ekw*_*ekw 2 c++-cli visual-c++
我有本机(非托管)C++ DLL,它们由单个 C++/CLI dll 包装(通过 .lib 文件链接)。这些非托管 C++ DLL 有相当多的类,其中包含大量方法和大量常量数据(例如字符串、十六进制值等),这些数据在包含的标头中定义。
但对于 C++/CLI 包装器 DLL,它只是本机 dll 的包装和编组层。然而,它的二进制大小与本机 dll 一样大。我相信这导致我达到了硬编码限制,当 C# 应用程序加载它时会引发异常: System.TypeLoadException: Internal limit: Too much fields
C# 应用程序永远不会使用本机 DLL 标头中定义的字段。
它能够通过启用字符串池(减少几MB)来缓解这个问题,但这看起来像是一种黑客行为。
为什么 DLL 的简单包装器与该 DLL 的大小相同?有没有办法可以标记 const 数据,以便 C# 应用程序不会加载它们?
您陷入了一个非常常见的陷阱,C++/CLI 编译器工作得太好了。当 #pragma Managed 或 /clr 有效时,它能够将任何 C++03 兼容的本机 C++ 代码编译为 IL。在运行时也能很好地工作,它可以通过抖动及时编译为机器代码,就像常规托管程序一样。
这是个好消息。坏消息是该代码不像托管代码那样执行。它没有得到验证,也没有得到垃圾收集器的喜爱。它的运行效率也不如常规编译的 C++ 代码,您会错过C++ 代码优化器获得绝对最佳机器代码的额外时间。
还有一个限制导致你的程序失败。任何全局变量和自由函数都被编译为隐藏<Module>类的成员。必需的,因为 CLR 不支持全局变量。托管类的成员获得一个元数据令牌,这是一个在元数据表中唯一标识它们的数字。令牌是一个 32 位值,低 16 位用于对其进行编号。Kaboom 当您创建了一个<Module>拥有超过 65535 名成员的班级时。
显然,这都是非常不可取的。您需要更加注意哪些代码被编译为 IL 以及哪些代码被编译为机器代码。您的本机 C++ 源代码应该在 /clr 选项不生效的情况下进行编译。按住 Shift 键并单击选择这些文件并设置选项。如有必要,请使用#pragma un/managed 在一个源代码文件内来回切换编译器。