C ++ / CLI Wrapper DLL TypeLoadException太多字段

时间:2013-06-14 21:21:37

标签: visual-c++ c++-cli

我有本机(非托管)C ++ DLL,它们由单个C ++ / CLI dll(通过.lib文件链接)包装。这些非托管C ++ DLL有很多类,包含大量方法和ton const数据(例如字符串,十六进制值等),这些数据在包含的头文件中定义。

但对于C ++ / CLI包装器DLL,它只是本机dll的包装和编组层。但是它的二进制大小和本机dll一样大。 我相信这会导致我达到硬编码的限制,当它被C#应用程序加载时抛出异常: System.TypeLoadException:内部限制:字段太多

C#应用程序永远不会使用本机DLL头文件中定义的字段。

它能够通过启用字符串池(削减几MB)来缓解这个问题,但它似乎是一个黑客攻击。

为什么DLL的简单包装器与DLL的大小相同?有没有办法可以标记const数据,以便C#应用程序不会加载它们?

2 个答案:

答案 0 :(得分:4)

你陷入了一个非常普遍的陷阱,C ++ / CLI编译器运行得很好。当#pragma managed或/ clr生效时,它能够将任何C ++ 03兼容的本机C ++代码编译到IL中。在运行时运行良好,它可以通过抖动到机器代码进行即时编译,就像常规托管程序一样。

这是个好消息。坏消息是,此代码执行托管代码。它没有得到验证,也没有得到垃圾收集器的喜爱。它也没有像定期编译的C ++代码那样高效运行,你错过了C ++代码优化器可用的额外时间,获得了绝对最好的机器代码。

使你的程序炸弹的一个限制。任何全局变量和自由函数都被编译为隐藏<Module>类的成员。必需,因为CLR不支持全局变量。托管类的成员获取元数据标记,该标记是在元数据表中唯一标识它们的编号。令牌是32位值,低16位用于对它们进行编号。 Kaboom,当您创建一个超过65535个成员的<Module>类时。

显然,这一切都是不可取的。您需要更加关注将哪些代码编译为IL以及将哪些代码编译为机器代码。您的本机C ++源代码应该编译为,而不是有效的/ clr选项。 Shift +单击选择这些文件并设置选项。必要时,使用#pragma un / managed在一个源代码文件中来回切换编译器。

答案 1 :(得分:1)

  

为什么DLL的简单包装器与DLL的大小相同?有没有办法可以标记const数据,以便C#应用程序不加载它们?

这通常是因为您使用/CLR编译整个项目。

如果您非常小心只将绝对最低要求包含在使用/ CLR编译的.cpp文件中,并且仅使用/ CLR编译作为托管类的.cpp文件,那么包装器项目往往是更简单,更小。主要问题是/ CLR编译的.cpp文件使用的任何头文件都会为所有C ++类型创建代理类型,这些类型可能会爆炸到程序集中的大量字段或类型。

使用PIMPL idiom“隐藏”后面的本机代码和opaque指针也可以显着缩小暴露给程序集的托管部分的类型数量,因为这允许您不包括主程序集中的主要标头托管代码。