Error loading bootloader with managed C ++ dll statically linked to native C ++ lib

I have a managed C ++ dll with several managed classes, which in turn call native C ++ code in a library that I statically linked to dll. However, if I try to run RegAsm.exe in the dll, the tool correctly says "there are no types that we registered", but then freezes . I am very sure that this is a bootloader lock problem , and my dll freezes when RegAsm tries to load it. I am using Visual Studio 2008 Express Edition.

Which makes me think that everything works fine when placing your own code in the dll, but not when statically linking it from the library. I know this post is similar to this question , but I do not have DllMain in my dll, there is no risk for me MSIL code from DllMain. In addition, on the recommendation, setting / clr for individual files did not help.

Compiling the dll with / NOENTRY fixes the lock problem, but causes the application to crash with a Type initializer for <Module> threw exception and is apparently only recommended with .NET 2003.

I suspect that initializing static members may be a possible culprit, but why would this be compiled for MSIL in my static lib outside of me.

Just to clarify: although I do not need to run RegAsm.exe in the dll, I use it as a check for the bootloader lock problem. I actually consume a dll in a C # assembly that implements several classes visible in COM, so I need to record COM on this. At the end of the C # IDE crashes during registration for COM interaction, reports β€œR6033 C ++ runtime error: try to use the MSIL code from this assembly while initializing your own code. This indicates an error in your application. Most likely, this is the result calling an MSIL-compiled (/ clr) function from a native constructor or from DllMain.

I solved the problem, but little is unclear, and I'm curious:

I noticed that two static variables were added to the header file in a statically linked library at the time when everything stopped working, it looked like this:

 // The whole header is forced to compile as native #pragma managed(push, off) .... static const std::locale commaSeparator(std::locale::classic(), new DecimalSeparator<char>(','));; .... #pragma managed(pop) 

Moving the initialization to the .cpp file (and changing the static to extern ) removes the bootloader lock. Can anyone indicate why the initializer will be compiled into MSIL?

Before the fix, if I only # included the header file from the managed dll, everything worked fine. But if I included the AND header, also associated with lib, it did not work. Since lib also uses a header inside itself, did I end up with two instances of a static variable? In any case, why complain about running MSIL code?

Despite the fact that now everything works, any understanding will be welcome.

+4
source share
2 answers

next page (especially for initializing static objects and implementing in header sections):

Since the same header can be included using both CPP files with / clr enabled and disabled, and C # include, you can wrap inside an unmanaged #pragma block, it is possible to have both MSIL and native versions of functions that provide implementations in headlines.

and

In Visual C ++ 2005, as a convenience for users involved in locking the bootloader, the linker will choose its own implementation over the managed one when both are presented .... However, in this release there are two exceptions to this rule due to two unsolved problems with the compiler:
...
- the call of the built-in function is carried out using the pointer of the global static function. This scenario is particularly notable in that virtual functions are called using global function pointers.

When placing a static variable directly inside a managed dll (or compiling with \ clr, for that matter), loader lock is excluded, since in DllMain only the initialization of its own static variables occurs. However, any static variable compiled as a native will be inhibited if the MSIL code is executed. In our case, MSIL is generated for the STL part that is used by the constructor of the static object due to the amazing behavior of the linker when presenting both the source and MSIL implementations.

The solution would be:

  • Compile everything with /clr (this is not possible for us, since we need to use static lib)
  • Make sure # all included third-party headers (STLs) are preceded by #pragma unmanaged (too complex)
  • Remove static variable initialization from headers (via external link)

     // Solved by replacing initialization in header file static const std::locale commaSeparator(...); // with extern const std::locale commaSeparator; // and doing initialization in a cpp file 
+1
source

Compiiler wraps the user-defined DllMain with its own code, which is used to initialize the runtime library and global variables (so that the custom DllMain can work with already created global objects and can use the standard library). Even if you do not have DllMain, a compiler will still be created. With / NOENTRY, you instruct the linker to ignore it.

So, something does in the constructor of the static variable, in fact the same as in the case of DllMain, and it seems to be the case here.

+1
source

All Articles