2

I have native (unmanaged) C++ DLLs that are being wrapped by a single C++/CLI dll (linking through the .lib files). These unmanaged C++ DLLs have quite a few classes with a ton of methods and a ton const data (e.g. strings, hex values, etc) which are defined in included headers.

But for the C++/CLI wrapper DLL its only a wrapping and marshalling layer for the native dll. However its binary size is as big as the native dll. I believe this is causing me to hit the hardcoded limit which throws the exception when it is being loaded by a C# application: System.TypeLoadException: Internal limitation: too many fields

The C# application will never use the fields defined in the headers for the native DLLs.

It was able to alleviate this issue through enabling of string pooling (shaving off a few MB), but it seems like a hack.

Why is a simple wrapper of a DLL the same size as that DLL? Is there a way where I can mark the const data such that the C# application won't load them?

4

2 回答 2

5

你掉进了一个很常见的陷阱,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 在一个源代码文件中来回切换编译器。

于 2013-06-14T21:35:44.890 回答
1

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

这通常是因为您正在使用/CLR.

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

使用PIMPL 习惯用法来“隐藏”本机代码和不透明指针还可以显着减少暴露给程序集托管部分的类型数量,因为这允许您不包括托管代码中的主标头。

于 2013-06-14T21:31:21.547 回答