I have a managed c++ dll with few managed classes that in turn call native c++ code in a library that I have statically linked to the dll. However, if I try to run RegAsm.exe on the dll, the tool correctly reports 'no types we registered' but then hangs. I'm very sure this is a loader lock problem and my dll hangs when RegAsm tries to load it. I'm using Visual Studio 2008, express edition.
What puzzles me that everything works fine when placing native code into the dll but not when statically linking it from the library. I'm aware that this post is similar to this question but I do not have DllMain in my dll, there is no risk of me running MSIL code from DllMain. Also, following the advice of setting /clr on individual files did not help.
Compiling the dll with /NOENTRY fixes the lock problem but causes the application to break with Type initializer for <Module> threw exception
exception and is apparently only reccommended with .NET 2003.
I'm suspecting that initialization of static members could be a possible culprit but why would that be compiled to MSIL in my static lib is beyond me.
Just to clarify: although I have no need of running RegAsm.exe on the dll, I'm using it as a check for the loader lock problem. In reality I'm consuming the dll in a c# assembly that does implement few COM-visible classes - so I need to do COM registration on that one. At the end C# IDE crashes during registering for COM interop, reporting 'R6033 c++ runtime error: Attempt to use MSIL code from this assembly during native code initialization. This indicates a bug in your application. It is most likely the result of calling an MSIL-compiled (/clr) function from a native constructor or from DllMain.
Solved the issue but few things are unclear and I'm curious:
I noticed that two static variables were added to a header file in the statically-linked lib at the time things stopped to work, that 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 a .cpp file (and changing static
to extern
) fixes the loader lock. Could anyone point to why would the initializer get compiled to MSIL at all?
Before the fix, if I only #included the header file from the managed dll, things worked fine. But if I includeed the header AND also linked to the lib, things didn't work. Since the lib also uses the header internally, did I end up with two instances of the static variable? In any case, why a complaint about running MSIL code?
Although things work now, any insight would be welcome.