I'd normally not answer my own question, but meanwhile I did find an answer that hasn't come up here before, so here I go.
After some research, I happened on this post by Microsoft, which explains the problems of mixing managed and unmanaged code inside DllMain
and the solution, which came about with the 2nd version of the CLI, module initializers. Quote:
This initializer runs just after the
native DllMain (in other words,
outside of loader lock) but before any
managed code is run or managed data is
accessed from that module. The
semantics of the module .cctor are
very similar to those of class .cctors
and are defined in the ECMA C# and
Common Language Infrastructure
Standards.
While I wasn't able to find the term module initializer inside the current ECMA specification, it follows logically from type initializer and the global <Module>
special class (see section 22.26 on MethodDef, sub-point 40). This feature was implemented after .NET 1.1 (i.e., from 2.0 onwards). See also this semi-official description.
This question wasn't about C#, but because it is the lingua franca of .NET: C# doesn't know global methods, and you can't create a <Module>
, let alone its cctor. However, Einar Egilsson has recognized this apparent deficiency and created InjectModuleInitializer.exe that allows you to do this as a post/compile step from Visual Studio. In C++.NET, using this method is trivial and recommended practice in place of DllMain
. See also this SO answer by Ben Voigt (not the accepted answer) and this SO answer by yoyoyoyosef.
In short, the module initializer is the first method that is called after loading the module (not necessarily when loading assembly!) and before calling any class or instance method. It takes no parameters, returns no value, but can contain any managed code in its body.