将非托管 EXE 作为资源合并到托管 C# 代码中
Posted
技术标签:
【中文标题】将非托管 EXE 作为资源合并到托管 C# 代码中【英文标题】:Incorporate an unmanaged EXE as resource in a managed C# code 【发布时间】:2012-03-05 16:43:36 【问题描述】:我有一个用非托管 C++ 编写的给定代码,我将其作为资源添加到 C# 程序中。
当尝试使用 Assembly.Load
加载非托管 EXE 时,我得到一个 BadImageFormatException
,其 InnerException 显示“IL 格式不正确”(显然)。
我怎样才能做到这一点?
我知道将代码用作 DLL 会更好,但由于某种原因,dll 调用的行为与我使用 System.Diagnostics.Process.Start
运行非托管 exe 时的行为不同。
而且我不想有两个单独的 EXE 文件。有什么想法吗?
编辑:好的,我不再需要这样做了。我的 dll 表现不同,因为我在不同的上下文中使用它(winform 而不是控制台);因此导致问题的函数SetThreadDesktop
无法按预期工作。现在要关闭帖子了,感谢所有回答的人。
【问题讨论】:
你想用这个非托管的可执行文件做什么?运行?您必须保存嵌入式 EXE,可能保存到 %TEMP% 路径,并使用Process.Start
来启动它。然后使用WaitForExit
,并删除EXE进行清理。
这确实是个好主意,但我宁愿在不生成嵌入式 EXE 的情况下完成这项工作
您应该能够使用 C++/CLI 编译器将 C++ 编译为混合模式程序集,并将其与您的 C# 代码链接到单个文件中。
【参考方案1】:
您不能使用Assembly.Load()
加载非托管的 exe/dll,它仅适用于托管的。如果您需要在该非托管文件上 PInvoke,并且您想要单个 exe 的原因只是部署,您可以将其打包为嵌入式资源(如您当前所做的那样)并在目标计算机上解压到一个文件中,并将其用作通常。
【讨论】:
好的,但也许有人可以给我一个提示,让我在没有 Assembly.Load 的情况下完成这项工作 @GianT971 我想你在尝试打包单个 exe 之前已经尝试过游戏。按照 Alexei (+1) 的建议遵循一些 PInvoke 教程 看看这个,明天给反馈【参考方案2】:如果您将非托管 DLL 作为资源 - 基本步骤:
Save resource to disk 在运行时 使用 LoadLibrary(Win32 调用 LoadLibrary using PInvoke) 通过调用方法annotated for PInvoke 或manually via GetProcAddress 使用此库中的方法。【讨论】:
“在运行时将资源保存到磁盘”是什么意思?我该怎么做?* 我们有搜索引擎 :) - bing.com/search?q=Save+resource+to+disk+at+run-time ,但这里有一个 ***.com/questions/864140/… 好的,您认为这样的结果可能与仅将 dll 导入项目不同? 不确定“不同”是什么意思 - 您不能将本机 DLL“导入”到托管项目。 @AlexeiLevenkov 正如 Ramhound 所发现的,可以使用 dllimport,这就是我正在做的,因此“不同”【参考方案3】:可以自动化的稍微不同的方法是使用所谓的“组装编织” Costura.Fody - https://github.com/Fody/Costura - 是“织布工”之一。嵌入过程(带有测试自动化)用于合并非托管资源并在运行时透明地加载它们而无需太多努力 -
Install-Package Fody.Costura
然后默认情况下,所有嵌入、解包、程序集定位和加载都是自动化的,并通过添加到您的项目中的“FodyWeavers.xml”配置来控制。
<Costura> <Unmanaged32Assemblies> Foo32 Bar32 </Unmanaged32Assemblies> <Unmanaged64Assemblies> Foo64 Bar64 </Unmanaged64Assemblies> </Costura>
方法背后的概念是静态<Module>
类加载器,即在项目程序集成功构建后由 Fody 项目任务更改的二进制文件。在内部,Mono.Cecil 用于静态 '<Module>'
加载程序注入,它自动解包资源,将它们保存到临时目录,告诉在程序集加载事件中从该位置加载 dll 等等。
【讨论】:
以上是关于将非托管 EXE 作为资源合并到托管 C# 代码中的主要内容,如果未能解决你的问题,请参考以下文章