Runtime: Load .netcore CLR into 3rd party native process

Created on 22 Feb 2020  路  10Comments  路  Source: dotnet/runtime

Not really a bug/issue but a very specialized question I hope you can help me with.

I am porting Full-Fx code that is loaded into a native process. The purpose of the project is to allow managed plugin development for a native (C/C++) plugin standard running inside a native process. The main player is a C++/CLI (Common Language Integration) interop project that takes care of the marshaling between the native and managed world. That dll has an exported entry point that the native host application calls.

Native Host => Interop Entry Point => Managed Plugin

I have managed to get the projects compiling with .netcore3.1 but the native host application does not load my interop assembly. I know the Full-Fx is wired into Windows and the CLR is automatically started when trying to load a managed assembly.

Does .netcore does something similar?
And if not, how can I make this scenario work?

area-Host question

All 10 comments

@jeffschwMSFT

We do enable native hosting, please take a look at these samples: https://github.com/dotnet/samples/tree/master/core/hosting

cc @elinor-fung @vitek-karas

We do enable native hosting, please take a look at these samples: https://github.com/dotnet/samples/tree/master/core/hosting

Yeah, seen those, but that are custom .exe's hosting the CLR. My scenario is that a 3rd party exe is loading my .netcore3.1 C++/CLI (mixed) assembly as a plugin.

I switched to x86 and got a bit further. It seems its not finding one of it's dependencies, but I can't figure out which one. BTW: it looks like the .netcore clr is auto-loading just as with the full Fx..? (ijwhost.dll)

vsthost is the 3rd party host that loads my Jacobi.Vst.Interop (C++/CLI) assembly as a plugin:

'vsthost.exe' (Win32): Loaded '[..]\vst.net\Source.Core_SharedAssemblies\Jacobi.Vst.Interop.dll'. Symbols loaded.
'vsthost.exe' (Win32): Loaded 'C:\Windows\SysWOW64\ucrtbased.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Windows\SysWOW64\vcruntime140d.dll'.
'vsthost.exe' (Win32): Unloaded 'C:\Windows\SysWOW64\ucrtbased.dll'
'vsthost.exe' (Win32): Loaded '[..]\vst.net\Source.Core_SharedAssemblies\Ijwhost.dll'.
'vsthost.exe' (Win32): Unloaded '[..]\vst.net\Source.Core_SharedAssemblies\Ijwhost.dll'
'vsthost.exe' (Win32): Loaded 'C:\Windows\SysWOW64\ucrtbased.dll'.
'vsthost.exe' (Win32): Loaded '[..]\vst.net\Source.Core_SharedAssemblies\Ijwhost.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\host\fxr\3.1.1\hostfxr.dll'.
'vsthost.exe' (Win32): Unloaded 'C:\Program Files (x86)\dotnet\host\fxr\3.1.1\hostfxr.dll'
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\host\fxr\3.1.1\hostfxr.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\hostpolicy.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\coreclr.dll'.
'vsthost.exe' (Win32): Unloaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\coreclr.dll'
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\coreclr.dll'.
Exception thrown at 0x76DB3DB2 (KernelBase.dll) in vsthost.exe: 0x04242420 (parameters: 0x31415927, 0x08FA0000, 0x0018F540).
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\System.Private.CoreLib.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\clrjit.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\System.Runtime.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\Microsoft.DiaSymReader.Native.x86.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\System.Threading.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\System.Runtime.Extensions.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\System.Runtime.CompilerServices.VisualC.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\System.Diagnostics.Debug.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\System.Runtime.InteropServices.dll'.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\System.Collections.NonGeneric.dll'.
Exception thrown at 0x76DB3DB2 in vsthost.exe: Microsoft C++ exception: EEFileLoadException at memory location 0x0018DE28.
Exception thrown at 0x76DB3DB2 in vsthost.exe: Microsoft C++ exception: [rethrow] at memory location 0x00000000.
Exception thrown at 0x76DB3DB2 in vsthost.exe: Microsoft C++ exception: [rethrow] at memory location 0x00000000.
Exception thrown at 0x76DB3DB2 (KernelBase.dll) in vsthost.exe: 0xE0434352 (parameters: 0x80070002, 0x00000000, 0x00000000, 0x00000000, 0x08FA0000).
Exception thrown at 0x76DB3DB2 in vsthost.exe: Microsoft C++ exception: [rethrow] at memory location 0x00000000.
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\mscordaccore.dll'.
'vsthost.exe' (Win32): Unloaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\mscordaccore.dll'
'vsthost.exe' (Win32): Loaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\mscordaccore.dll'.
'vsthost.exe' (Win32): Unloaded 'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\3.1.1\mscordaccore.dll'
Exception thrown at 0x76DB3DB2 in vsthost.exe: Microsoft C++ exception: CSEHException at memory location 0x0017F5C0.

Source Code for Jacobi.Vst.Interop is here.

.NET Core 3.1 does have support for C++/CLI on Windows. As you noticed, it goes through ijwhost.dll to load the .NET Core runtime. That host also expects a .runtimeconfig.json file with a name corresponding to that of your C++/CLI assembly. The IJW activation doc has more details.

Do you get a managed exception? If you debug with either mixed mode or managed only (CoreCLR), I would expect there to be a managed exception thrown (with more information about the specific file failing to load).

What version of Visual Studio are you using to build your the C++/CLI project?

Yes, I have Jacobi.Vst.Interop.runtimeconfig.json for the Jacobi.Vst.Interop.dll. I did not know what to put in it so I copied some default I found somewhere

{
    "runtimeOptions": {
        "tfm": "netcoreapp3.1",
        "framework": {
            "name": "Microsoft.NETCore.App",
            "version": "3.1.0"
        }
    }
}

Debugging with CoreCLR and Native loads the symbols and see the breakpoints 'solidify' (indicating the symbols are loaded and recognized) but I never hit any breakpoint at DllMain or in the entry point the vst host should call (VSTPluginMain)...

I see no exceptions or break into the debugger at any point.
The output did show a C++ exception:
Exception thrown at 0x76DB3DB2 in vsthost.exe: Microsoft C++ exception: EEFileLoadException at memory location 0x0018DE28.

VS: Enterprise 2019, Version 16.4.5

Edit: After reading the IJW activation doc I am unsure what is needed. The document assumes a great deal of knowledge I don't have and gives the impression some manual intervention is needed to load managed assemblies into the CLR - something that was automatic in the FullFx; just referencing the dependency for the first time loaded it automatically.

I work under the impression that I would at least be able to get a debugging session to break into the vst host entry point function -which is C/C++- without having to deal with any other managed/CLR business... Please let me know if this assumption is correct.

Please make sure that you have the debugger setup to stop on all managed exceptions (sometimes the default hides some of them - never understood the logic behind it myself). The EEFileLoadException should mean a managed exception, unless it happens in a really weird spot.

As an additional data point (not sure if it's going to help though): You can collect the native hosting trace - run the process with environment: COREHOST_TRACE=1 and COREHOST_TRACEFILE=t.txt. It should produce t.txt in the current directory with lot of info about the native hosting side. You can use that to double check that it ended up loading the right things for the right reasons.

By default, for most managed exceptions, the VS debugger will only break if they are unhandled, so as @vitek-karas mentioned, you likely need to enable breaking on all managed exceptions thrown to see the managed exception corresponding to the EEFileLoadException

In VS 16.4.*, C++/CLI did not automatically generate a .runtimeconfig.json (https://github.com/dotnet/sdk/issues/3889). This support should be in 16.5 (still in preview, but preview 3 has the support).

One thing I see in the Jacobi.Vst.Interop project is that there is a framework reference to Windows Forms. This means that in order to load/find that framework, Jacobi.Vst.Interop.runtimeconfig.json would need to point to Microsoft.WindowsDesktop.App instead of Microsoft.NETCore.App.

Microsoft.WindowsDesktop.App

That was it! Thanks! (Duh, makes perfect sense too!)

The debugger stops at the breakpoint in the vst host entry point - which means the assembly is loaded and its entry point is being called. Awesome.

I can probably remove the WinForms dependency -I think I only used it for MessageBox.

(I have so many other questions but I will continue by myself for now)
Thank you very much for helping me out.

Glad to hear it works!

(I have so many other questions but I will continue by myself for now)

Please feel free to open new issues on these - it helps us to understand what are the non-obvious things (or pain points), and it acts as a temporary documentation for others to solve the same problem.

Was this page helpful?
0 / 5 - 0 ratings