Determining when .NET is about to load (unmanaged) C ++

[this gets TL; DR ... sorry ...]

I am working on a huge (mostly) C ++ / MFC application with hundreds of DLLs; it supports the dynamically loaded "add" mechanism through COM, so add-ons can be developed in .NET using COM interoperability. Some limited new features are developed in .NET without using this add-in mechanism (although they are still dynamically loaded); however, the end user may decide not to use this feature. Therefore, .NET cannot be loaded at startup.

But when does .NET load , I need to do some specific .NET initialization (in particular, set CurrentUICulture to match my own / unmanaged user interface).

One solution is to simply punt and do this .NET initialization when the code starts loading either the new .NET function modules or COM. Given the nature of this application, this is probably a 95% solution (most users will use the new functionality).

But this is not perfect. Someone can โ€œeasilyโ€ add new .NET functionality at any time by creating a module with the / clr flag (remember that this is a huge application).

Another reliable (and obvious) solution simply causes .NET to load when launched through C ++ / CLI. But some of the smart C ++ developers for whom every byte and clock cycle do not want to do this; somewhat understandable since there is no need to set CurrentUICulture if / before loading .NET.

Another possibility that I was thinking about is to hook the LoadLibrary and look for mscorlib . Now I know that .NET for some reason loads, loads it in normal mode and initializes before other code does something. But the LoadLibrary binding (or something else, for that matter) is really not what I want to do.

So, is there a simple (ier) / best way to tell if .NET should load?

Edit: The LockClrVersion read response is pretty close. The only hiccup is that it will not work if you connect to a DLL / mixed-mode assembly.

 // ClrAboutToLoad.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <MSCorEE.h> // http://community.bartdesmet.net/blogs/bart/archive/2005/07/22/2882.aspx FLockClrVersionCallback begin_init, end_init; STDAPI hostCallback() { printf("hostCallback()\n"); // we're in control; notify the shim to grant us the exclusive initialization right begin_init(); ICLRRuntimeHost *pHost = NULL; HRESULT hr = CorBindToRuntimeEx(NULL, L"wks", STARTUP_SERVER_GC, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (PVOID*) &pHost); hr = pHost->Start(); // mission completed; tell the shim we're ready end_init(); return S_OK; } int _tmain(int argc, _TCHAR* argv[]) { LockClrVersion(&hostCallback, &begin_init, &end_init); //fnTheDLL(); HMODULE hModule = LoadLibrary(L"TheDLL"); FARPROC fp = GetProcAddress(hModule, "fnTheDLL"); typedef void (*fnTheDLL_t)(); fnTheDLL_t fnTheDLL = reinterpret_cast<fnTheDLL_t>(fp); fnTheDLL(); FreeLibrary(hModule); return 0; } 
+7
c ++
source share
5 answers

I believe that you can do this by asking your process to call the unmanaged LockClrVersion function before using any managed APIs. This function allows you to specify two FLOCKClrVersion callback methods.

The first method (pBeginHostSetup) is called before the CLR is initialized for the first time for the hosting process. The second method (pEndHostSetup) is called when CLR initialization is complete.

This should allow you to specify unmanaged code that runs just before and immediately after the initialization of the CLR. In your case, you probably need to connect to pEndHostSetup to call your managed API installation routines (you will need to wait for the CLR to complete successfully).

+6
source share

You can run your own CLR host to load assemblies . Then you can make more specific decisions about which version of the runtime (1.1? 2.0? 4.0?) To load and separate managed code from your code so that when the plugin crashes, your code will not work with it .

+1
source share

There are two things that can help you: performance counters and the WMI..NET CLR integrates with both, and you should be able to interact with them (maybe WMI will be better) to keep track of the launch of AppDomain. However, none of these tools is particularly ideal, and in terms of overhead, doing what Sheng Jiang suggested, offering your own CLR is likely to be more efficient (and therefore more enjoyable for your "byte counters". )

In a slightly different note ... if you have any measure of influence and control over the development team, I would go into "byte counters" a bit. One of the biggest misconceptions regarding .NET is that it is less efficient than C ++. This old mistake should be buried, since .NET can be surprisingly efficient and, when used correctly, is more efficient than C ++. In addition to the basic effectiveness of any platform, you should ask the question: how much can I really gain by spending an unknown amount of hours, optimizing the best grain, when statistically, its more ambitious things that usually kill performance: cross calls (i.e. calling COM objects from C ++ and calling .NET objects from .NET), calling remote processes (e.g. web services, RPC, etc.), calling to a database, etc.

You can try to solve your problem with running .NET AppDomain to calm the erroneous representations of byte counters, or you can correctly implement the .NET system and avoid marshaling and interoperational shock, which will be significantly more exhausted than any number of byte-level performance tuning can counteract.

+1
source share

Instead of trying to connect to the assembly, can you connect when the AppDomain boots up? To do this, go to System.AppDomainManager.

After loading your subclass of System.AppDomainManager into the GAC, you just need to set some environment variables (APPDOMAIN_MANAGER_TYPE, APPDOMAIN_MANAGER_ASM) before running your C ++ program.

0
source share

You should probably initialize the .NET platform when starting the application. I worked on an application with a similar background, and sometimes it came to a standstill, because 2 dlls tried to initialize the .NET infrastructure at the same time, indirectly accessing .net DLL files. To fix this, we made a call to CorBindToRuntimeEx in the first few lines of the entry point of the executable.

I do not think the OS will tell you whether to boot .NET.

-one
source share

All Articles