如何连接C#和C++;将程序集转换为单个可执行文件?

如何连接C#和C++;将程序集转换为单个可执行文件?,c#,visual-c++,linker,c++-cli,C#,Visual C++,Linker,C++ Cli,我有一个VS2008解决方案,它生成一个C可执行文件,它引用一个生成包含C++和CLI和非托管C++的DLL的项目。 我想将这些合并成一个可执行文件,因为C++ DLL包含我要嵌入到主可执行文件中的安全代码。 我不能使用ILMerge,因为dll同时包含托管代码和非托管代码。建议的解决方案似乎是使用Link .EXE将C++组件与C++对象文件链接起来。这就是我想做的 我手动编辑了c可执行文件的项目文件,以生成netmodule。我在可执行项目中添加了一个生成后的步骤,运行Link .EXE,将

我有一个VS2008解决方案,它生成一个C可执行文件,它引用一个生成包含C++和CLI和非托管C++的DLL的项目。

我想将这些合并成一个可执行文件,因为C++ DLL包含我要嵌入到主可执行文件中的安全代码。 我不能使用ILMerge,因为dll同时包含托管代码和非托管代码。建议的解决方案似乎是使用Link .EXE将C++组件与C++对象文件链接起来。这就是我想做的

我手动编辑了c可执行文件的项目文件,以生成netmodule。我在可执行项目中添加了一个生成后的步骤,运行Link .EXE,将C*NETMAMP和编译的C++对象文件链接在一起,然后运行MT.EXE合并两个项目创建的程序集清单。这运行成功,但EXE仍然包含引用并使用C++程序中正常生成过程生成的DLL中定义的C++类型。

然后,我在C/C++ DLL的项目设置中指定/NoFunt,因此它也生成一个NETMULTLE。在C++项目中,我删除了C++项目的引用,但在解决方案中添加了项目依赖项。我手动编辑了C#项目文件,以包括类似的内容:

<ItemGroup>
    <AddModules Include="..\Debug\librarycode.netmodule" />
</ItemGroup>
这是完全可以理解的,因为我没有在LibraryCodeNetModule中链接;我正在链接用于生成NETMAMP的C++对象文件。 简而言之,我如何将C++可执行文件和C++对象文件合并成单个程序集?我错过了什么

到目前为止,我的参考来源(MSDN上link.exe命令link reference等的appart)是以下两篇文章:

  • 我有一个演示解决方案,可以显示我目前的工作情况,如果这有帮助的话
事先非常感谢


更新1 我在Steve Teixeira的博客中完全遵循了这个例子,并验证了它的有效性。使用reflector,我可以看到生成的可执行文件包含两个NetModule。c#netmodule包含对另一个netmodule的引用,但没有名称?!如果将程序集移动到新目录,则第二个netmodule将不被引用(显然),但可执行文件仍在运行,因为c#netmodule中存在具有正确定义的类型

注意到,原始的C.NETMead模块包含了C++ NETMAMP的命名引用,因此必须是删除名称的链接器步骤。 为了在示例项目中遵循此示例,我在构建后链接器步骤中添加了一个/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 我已经将我的项目简化为尽可能最简单的,并且正在尝试从命令行编译is。以下批处理文件在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

找出差异的时间:-(

您的业务案例与SQLite非常相似,因此同样的方法也适用于您。基本上,它们将托管程序集作为单独的数据节插入到非托管dll中。然后,它们能够以正常方式从托管dll p/调用非托管dll。还可以动态链接到托管dll中的非托管代码ll.

下面是一个Nant构建脚本,它完全满足了您(和我)的需求(如果我正确理解了您的需求,那就是xD)

其中有些是缺失的(比如一些不需要的变量),但事实证明这是相当容易实现的

这显示了合并混合程序集和托管程序集所需的cl/csc和链接器标志。此外,作为额外的“奖励”,所有内部类/方法/字段等在整个新程序集中可见,这意味着它们跨越了项目的边界

    <delete file="${tmp.cpp}" />
    <foreach item="File" property="filename">
        <in>
            <items basedir="${basedir}/SpotiFire.LibSpotify">
                <include name="**.h" />
            </items>
        </in>
        <do>
            <echo message="#include &quot;${filename}&quot;&#10;" append="true" file="${tmp.cpp}" />
        </do>
    </foreach>

    <cl outputdir="${build.obj}" options="/clr /LN">
        <sources basedir="${basedir}/SpotiFire.LibSpotify">
            <include name="*.cpp" />
            <include name="${tmp.cpp}" asis="true" />
            <exclude name="AssemblyInfo.cpp" />
        </sources>
    </cl>

    <csc target="module" output="${build.obj}/SpotiFire.netmodule">
        <modules basedir="${build.obj}">
            <include name="tmp.obj" />
        </modules>
        <references refid="all_refs" />
        <sources basedir="${basedir}/SpotiFire.SpotifyLib">
            <include name="**.cs" />
        </sources>
    </csc>

    <link output="${build.dir}/${name}.dll" options="/LTCG /FIXED /CLRIMAGETYPE:IJW /NOENTRY /DLL">
        <sources basedir="${build.obj}">
            <include name="*.obj" />
            <include name="*.netmodule" />
            <include name="${basedir}/libspotify.lib" asis="true" />
        </sources>
        <arg value="/DEBUG" if="${build.debug == 'true'}" />
    </link>

为了正确地合并到中,program.netmodule应该在链接器中指示两次,在输入列表中,并作为ASSEMBLYMODULE选项中的参数

因此,整个命令行将如下所示:

link /LTCG /CLRIMAGETYPE:IJW /ENTRY:MixedLanguageDemo.Program.Main /SUBSYSTEM:WINDOWS /ASSEMBLYMODULE:program.netmodule /OUT:MixedLanguageDemo.exe managedmessageprovider.obj messageprovider.obj program.netmodule
在此命令行之后,program.module类型应合并到MixedLanguageDemo.exe中。您始终可以使用.NET反射器(如或)检查结果程序集中的内容


快乐编码。

请参见此(重复)。问题72264的答案可能重复,包括嵌入dll,然后在运行时提取。这简化了安装,但没有提高安全性。第一次运行后,dll作为单独的程序集可用。但是,这让我考虑了嵌入dll并动态加载到内存中的选项,而不是e只是出于好奇,“业务用例”是什么为此?我们的客户要求我们使用第三方库实施软件保护和许可,因为他们已经使用该许可基础设施维护和管理了其他产品。第三方库提供了一个C API,但我们的产品是C。因此,我有我们的C可执行文件,以及一个包含此C API和C++/CLI int的dll我们已经编写了erop接口。如果我们可以将所有这些链接到一个可执行文件中,将会更加安全,否则您可以通过替换dll绕过安全性。希望这有帮助。
link /LTCG /CLRIMAGETYPE:IJW /ENTRY:MixedLanguageDemo.Program.Main /SUBSYSTEM:WINDOWS /ASSEMBLYMODULE:program.netmodule /OUT:MixedLanguageDemo.exe managedmessageprovider.obj messageprovider.obj program.netmodule