You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
No way to set the .NET entry assembly from unmanaged host? Also, documentation seems to be wrong/unclear. #94139
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:
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.
I can confirm that there's no way to do this currently. The only way to set the entry assembly from native host is to use the hostfxr_run_app API, but that is not usable in some cases.
That said I think this issue and what @davidfowl and I were discussing is somewhat different. This scenario seems to need a way to effectively modify the value returned from GetEntryAssembly when there's already managed code running. The other scenario is if the managed code is executed via a different way than hostfxr_run_app, where it would be set just once on runtime start.
I think that adding ability to set the entry point assembly at runtime start is something we can design/implement relatively easily. The only interesting questions would be:
How/where is it specified - for this I would probably go with a runtime property and just the simple name of the assembly.
How is the assembly resolved - for consistency I think this would require the assembly to be in the TPA, or otherwise immediately resolvable at runtime start.
What is the interaction with hostfxr_run_app - what happens if the property is specified in this case - should the property win or the "run app" call win.
Adding the ability to change this value later on - basically from managed code (as this scenario loads the assembly from memory), is something I would be a bit more nervous about. Whether specified or not, the runtime currently effectively guarantees that the value will never change - allowing it could break things in subtle ways.
Adding the ability to change this value later on - basically from managed code (as this scenario loads the assembly from memory), is something I would be a bit more nervous about.
My preference is to add a managed API to let people set it to whatever they want anytime to solve this problem once for all. I agree that it would be somewhat dangerous API. It is similar to AppDomain.CurrentDomain.SetData when used on keys owned by the runtime.
Activity
davidfowl commentedon Oct 28, 2023
+1 @vitek-karas we spoke about this recently.
vitek-karas commentedon Oct 30, 2023
I can confirm that there's no way to do this currently. The only way to set the entry assembly from native host is to use the
hostfxr_run_appAPI, but that is not usable in some cases.That said I think this issue and what @davidfowl and I were discussing is somewhat different. This scenario seems to need a way to effectively modify the value returned from
GetEntryAssemblywhen there's already managed code running. The other scenario is if the managed code is executed via a different way thanhostfxr_run_app, where it would be set just once on runtime start.I think that adding ability to set the entry point assembly at runtime start is something we can design/implement relatively easily. The only interesting questions would be:
hostfxr_run_app- what happens if the property is specified in this case - should the property win or the "run app" call win.Adding the ability to change this value later on - basically from managed code (as this scenario loads the assembly from memory), is something I would be a bit more nervous about. Whether specified or not, the runtime currently effectively guarantees that the value will never change - allowing it could break things in subtle ways.
@elinor-fung - any ideas, opinions?
jkotas commentedon Oct 30, 2023
My preference is to add a managed API to let people set it to whatever they want anytime to solve this problem once for all. I agree that it would be somewhat dangerous API. It is similar to
AppDomain.CurrentDomain.SetDatawhen used on keys owned by the runtime.jkotas commentedon Oct 30, 2023
This managed API would allow us to get rid of the
s_forceNullEntryPointinternal testing hook.elinor-fung commentedon Jun 7, 2024
The new
Assembly.SetEntryAssemblyAPI allows setting the entry assembly:SetEntryAssembly()API toSystem.Reflection#102271With this, you should be able to set the entry assembly once your first .NET assembly is loaded / before running the other assembly's entry point.
Docs are also updated to clarify that the comments about
AppDomain.ExecuteAssemblyare only for .NET Framework (dotnet/dotnet-api-docs#10004).