我有一个托管 c++ dll,其中包含几个托管类,这些托管类反过来调用我静态链接到 dll 的库中的本机 c++ 代码。但是,如果我尝试在 dll 上运行 RegAsm.exe,该工具会正确报告“没有我们注册的类型”,但随后会挂起。我很确定这是一个加载程序锁定问题,当 RegAsm 尝试加载它时,我的 dll 挂起。我正在使用 Visual Studio 2008,速成版。
令我困惑的是,将本机代码放入 dll 时一切正常,但从库中静态链接时却不行。我知道这篇文章与这个问题类似,但我的 dll 中没有 DllMain,我没有从 DllMain 运行 MSIL 代码的风险。此外,遵循在单个文件上设置 /clr 的建议也无济于事。
使用 /NOENTRY 编译 dll 可修复锁定问题,但会导致应用程序因Type initializer for <Module> threw exception
异常而中断,并且显然仅在 .NET 2003 中推荐使用。
我怀疑静态成员的初始化可能是罪魁祸首,但为什么在我的静态库中将其编译为 MSIL 超出了我的范围。
澄清一下:虽然我不需要在 dll 上运行 RegAsm.exe,但我使用它来检查加载程序锁定问题。实际上,我正在使用 ac# 程序集中的 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?
在修复之前,如果我只 #included 托管 dll 中的头文件,则一切正常。但是,如果我包含标题并且还链接到库,那么事情就不起作用了。由于 lib 也在内部使用了标头,所以我最终得到了静态变量的两个实例吗?无论如何,为什么要抱怨运行 MSIL 代码?
尽管现在一切正常,但欢迎任何见解。