我有一个托管c++ dll,其中有几个托管类,这些托管类反过来调用库中的本机c++代码,我有静态链接到dll。但是,如果我尝试在dll上运行RegAsm.exe,该工具会正确报告"没有我们注册的类型",但随后挂起。我很确定这是一个加载器锁定问题,当RegAsm试图加载它时,我的dll会挂起。我用的是Visual Studio 2008, express版。
让我困惑的是,当将本机代码放入dll中时,一切都很好,但当从库静态链接它时却不行。我知道这篇文章类似于这个问题,但我做没有DllMain在我的dll中,没有我从DllMain运行MSIL代码的风险。此外,按照建议在单个文件上设置/clr也没有帮助。
使用/NOENTRY编译dll修复了锁问题,但导致应用程序因Type initializer for <Module> threw exception
异常而中断,显然只推荐使用。net 2003。
我怀疑静态成员的初始化可能是一个可能的罪魁祸首,但为什么要在我的静态库中编译成MSIL ?
只是为了澄清:虽然我不需要在dll上运行RegAsm.exe,但我正在使用它来检查加载程序锁定问题。在现实中,我正在使用c#程序集中的dll,该程序集确实实现了一些COM可见类-所以我需要在该程序集上进行COM注册。最后,c# IDE在注册COM互操作期间崩溃,报告'R6033 c++运行时错误:试图在本机代码初始化期间使用此程序集的MSIL代码。这表明应用程序中存在错误。这很可能是从本机构造函数或从DllMain调用msil编译(/clr)函数的结果。
解决了问题,但有些事情不清楚,我很好奇:
我注意到,当事情停止工作时,静态链接库中的头文件中添加了两个静态变量,看起来像这样:
// 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)
将初始化移动到.cpp文件(并将static
更改为extern
)修复加载器锁定。有人能指出为什么初始化器会被编译成MSIL吗?
在修复之前,如果我只从托管dll中包含头文件,事情就会正常工作。但是,如果我包括头和也链接到lib,事情没有工作。由于lib也在内部使用头文件,我是否最终得到了静态变量的两个实例?在任何情况下,为什么抱怨运行MSIL代码呢?
虽然现在一切正常,但任何见解都是受欢迎的。
编译器用自己的代码包装用户定义的DllMain,用于初始化运行时库和全局变量(以便用户定义的DllMain可以与已经创建的全局对象一起运行,并且可以使用标准库)。即使没有dlmain,也会有编译器生成的。使用/NOENTRY命令链接器忽略它。
所以,在静态变量的构造函数中做一些事情实际上与在DllMain中做的事情是一样的,这里的情况似乎是这样的。
下面的页面,(特别是初始化静态对象和在header 部分中的实现)有如下说明:
因为相同的头文件可以被/clr启用和禁用的CPP文件包含,或者#include可以包装在#pragma unmanaged块中,所以可以同时使用MSIL和本机版本的函数在头文件中提供实现。
和
在Visual c++ 2005中,为了方便用户处理加载器锁,链接器将选择本机实现而不是托管实现. ...然而,由于编译器的两个未解决的问题,在这个版本中有两个例外:
…-通过全局静态函数指针调用内联函数。这个场景特别值得注意,因为虚函数是通过全局函数指针调用的。
当将静态变量直接放置在托管dll中时(或者在使用clr进行编译时),将避免加载器锁定,因为只有在dll main中才会初始化本机静态变量。但是,任何作为本机编译的静态变量在执行MSIL代码时都会死锁。在我们的例子中,MSIL是为静态对象的构造函数使用的STL的一部分生成的,因为在本机和MSIL实现同时出现时,链接器的行为令人惊讶。
一个解决方案是:
- 用
/clr
编译所有内容(因为我们需要使用静态库,所以不可能) - 确保所有#包含的第三方标头(STL)前面都有
#pragma unmanaged
(太复杂了) -
从头文件中删除静态变量初始化(通过外部链接)
// 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