【发布时间】:2011-02-06 05:36:33
【问题描述】:
我的 VS2008 解决方案包含一个项目,该项目生成一个 C# 可执行文件,该可执行文件引用一个项目,该项目生成一个包含 C++/CLI 和非托管 C++ 的 dll。
我想将这些合并到一个可执行文件中,因为 C++ dll 包含我想嵌入到主可执行文件中的安全代码。
我不能使用 ILMerge,因为 dll 包含托管和非托管代码。建议的解决方案似乎是使用 link.exe 将 C# 程序集与 C++ 目标文件链接起来。这就是我想要做的。
我手动编辑了 c# 可执行文件的项目文件以生成网络模块。我在可执行项目中添加了一个构建后步骤来运行 link.exe 以将 c# 网络模块和已编译的 C++ 目标文件链接在一起,然后运行 mt.exe 以合并由两个项目创建的程序集清单。这运行成功,但 exe 仍然包含对 C++ 项目正常构建过程生成的 dll 中定义的 c++ 类型的引用和使用。
然后我在 C++ dll 的项目设置中指定了 /NOASSEMBLY,因此它也生成了一个网络模块。在C#项目中,我去掉了对C++项目的引用,但是在解决方案中增加了一个项目依赖。我手动编辑了 C# 项目文件以包含类似于:
<ItemGroup>
<AddModules Include="..\Debug\librarycode.netmodule" />
</ItemGroup>
即引用现在由 C++ 项目生成的 C++ 网络模块。
但是,现在我的构建后事件中的链接器步骤失败了:
error LNK2027: unresolved module reference 'librarycode.netmodule'
fatal error LNK1311: 1 unresolved module references:
这是完全可以理解的,因为我没有在 librarycode 网络模块中链接;我正在链接用于生成网络模块的 C++ 目标文件。
简而言之,如何将 c# 可执行文件和 C++ 目标文件合并到一个程序集中?我错过了什么?
到目前为止,我的参考来源(来自 MSDN 上的 link.exe 命令链接参考等)是以下两篇文章:
- http://blogs.msdn.com/texblog/archive/2007/04/05/linking-native-c-into-c-applications.aspx
- http://www.hanselman.com/blog/MixingLanguagesInASingleAssemblyInVisualStudioSeamlesslyWithILMergeAndMSBuild.aspx 如果有帮助,我有一个演示解决方案,可以展示我目前的工作情况。
非常感谢您。
更新1
我完全按照 Steve Teixeira 博客中的示例进行了操作,并验证了它是否有效。使用反射器,我可以看到生成的可执行文件包含两个网络模块。 c# netmodule 包含对另一个 netmodule 的引用,但没有名称?!如果将程序集移动到新目录,第二个网络模块将变为未引用(显然),但可执行文件仍会运行,因为 c# 网络模块中存在具有正确定义的类型。
请注意,原始 c# 网络模块确实包含对 c++ 网络模块的命名引用,因此删除该名称的必须是链接器步骤。
为了在我的示例项目中遵循此示例,我在构建后链接器步骤中添加了一个 /ASSEMBLYMODULE 参数。链接器现在因
而失败LNK2022: metadata operation failed (80040427) : Public type 'MixedLanguageLibrary.Class1' is defined in multiple places in this assembly: 'MixedLanguageDemo.exe' and 'mixedlanguagelibrary.netmodule'
LINK : fatal error LNK1255: link failed because of metadata errors
我猜是链接器魔术删除了我缺少的模块引用名称。
欢迎任何想法。
更新2
我已将我的项目简化为最简单的项目,并尝试从命令行编译。以下批处理文件成功构建了 Steve Teixeira 博客中的示例:
setlocal
call "C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
if errorlevel 1 goto End
cl /c /MD nativecode.cpp
if errorlevel 1 goto End
cl /clr /LN /MD clrcode.cpp nativecode.obj
if errorlevel 1 goto End
csc /target:module /addmodule:clrcode.netmodule Program.cs
if errorlevel 1 goto End
link /LTCG /CLRIMAGETYPE:IJW /ENTRY:ConsoleApplication1.Program.Main /SUBSYSTEM:CONSOLE /ASSEMBLYMODULE:clrcode.netmodule /OUT:MixedApp.exe clrcode.obj nativecode.obj program.netmodule
:End
以下批处理文件无法构建我的示例代码并出现链接器错误 LNK2022:
setlocal
call "C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
if errorlevel 1 goto End
cl /c /MD messageprovider.cpp
if errorlevel 1 goto End
cl /clr /LN /MD managedmessageprovider.cpp messageprovider.obj
if errorlevel 1 goto End
csc /target:module /addmodule:managedmessageprovider.netmodule Program.cs Form1.cs Form1.Designer.cs
if errorlevel 1 goto End
link /LTCG /CLRIMAGETYPE:IJW /ENTRY:MixedLanguageDemo.Program.Main /SUBSYSTEM:WINDOWS /ASSEMBLYMODULE:managedmessageprovider.netmodule /OUT:MixedLanguageDemo.exe managedmessageprovider.obj messageprovider.obj program.netmodule
:End
是时候发现差异了:-(
【问题讨论】:
-
查看post(重复)。
-
问题 72264 的答案涉及嵌入 dll,然后在运行时提取它。这简化了安装,但不会提高安全性。第一次运行后,dll 可作为单独的程序集使用。然而,这让我开始考虑嵌入 dll 并将其动态加载到内存中的选项,而不是将其提取到文件中。
-
只是出于好奇,这个“业务用例”是什么?
-
我们的客户要求我们使用第三方库实施软件保护和许可,因为他们已经使用该许可基础架构维护和管理其他产品。第三方库提供了 C API,但我们的产品是 C#。所以,我有我们的 C# 可执行文件,以及一个包含这个 C api 和我们编写的 C++/CLI 互操作接口的 dll。如果我们可以将所有这些链接到一个可执行文件中会更安全,否则您可以通过替换 dll 来绕过安全性。希望这会有所帮助。
标签: c# visual-c++ linker c++-cli