Skip to content

No way to set the .NET entry assembly from unmanaged host? Also, documentation seems to be wrong/unclear. #94139

@Sebtous

Description

@Sebtous

Description

I have a rather complex scenario where I have to launch a WPF (.NET 7) application from another .NET application (let's call that one the .NET host application), in the same process as the .NET host application, which in turn is hosted in an unmanaged application using hostfxr's hdt_load_assembly_and_get_function_pointer.

In the .NET host application, I load the WPF application assembly from bytes in memory, then invoke the Assembly.EntryPoint to launch it. It is here that the problem manifests itself. WPF depends on Assembly.GetEntryAssembly () returning the main WPF assembly for resource management.
In my case however, Assembly.GetEntryAssembly () returns null, with no apparent way to set it to anything else, making the WPF app crash.

The documentation for Assembly.GetEntryAssembly states it returns:

The assembly that is the process executable in the default application domain, or the first executable that was executed by AppDomain.ExecuteAssembly(String). Can return null when called from unmanaged code.

However, when I look at the runtime source code, all AppDomain.ExecuteAssembly(String) seems to do is call a private method that invokes the assembly entrypoint, just like I am doing:

private static int ExecuteAssembly(Assembly assembly, string?[]? args)
{
    MethodInfo? entry = assembly.EntryPoint;
    if (entry == null)
    {
        throw new MissingMethodException(SR.Arg_EntryPointNotFoundException);
    }

    object? result = entry.Invoke(
        obj: null,
        invokeAttr: BindingFlags.DoNotWrapExceptions,
        binder: null,
        parameters: entry.GetParameters().Length > 0 ? new object?[] { args } : null,
        culture: null);

    return result != null ? (int)result : 0;
}

Needless to say, this does not make Assembly.GetEntryAssembly () return a different value.

As far as I can tell, there's no way to change the behavior of Assembly.GetEntryAssembly (), as all this function does is call GetEntryAssemblyInternal: github

So how do I make this work? (assuming I can't modify the WPF application as it is not mine).

Reproduction Steps

Create an unmanaged .NET host, use that to load a .NET assembly that loads another .NET assembly that is the main assembly of a WPF application.
Start the WPF application by invoking its Assembly.EntryPoint.

The application crashes on exceptions caused by Assembly.GetEntryAssembly () returning null.

Expected behavior

I expect there should be a way for an unmanaged host (or even another .NET assembly) to set the value returned by Assembly.GetEntryAssembly() to a specific assembly so that it does not return null.

Actual behavior

Assembly.GetEntryAssembly() always returns null

Regression?

No response

Known Workarounds

None as far as I can tell

Configuration

.NET 7, Windows 11, x64. Not relevant, I suspect.

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions