如何将托管 c++ 库导入 C# 应用程序(目标 .net 版本 3.5)

Posted

技术标签:

【中文标题】如何将托管 c++ 库导入 C# 应用程序(目标 .net 版本 3.5)【英文标题】:How to import a managed c++ library to C# app (target .net version 3.5) 【发布时间】:2014-06-23 11:24:08 【问题描述】:

我在 Visual Studio 中创建了一个托管 c++ 库(包装器),它使用了一些非托管 c++ 库。此包装将由使用 .net 框架 3.5 的 c# 应用程序使用。

在 c++ 中,我向链接器添加了额外的依赖项,并将外部库的 .lib 文件和 .h 文件复制到源文件所在的文件夹中。我设置了 32 位平台并发布配置和构建解决方案。 DLL 已创建,因此我在 c# 应用程序的配置中引用它。

当我在 c# 和 c++ 中使用 .net 4.5 时一切正常,但 c# 必须使用 3.5 版本。我读到我需要在较旧的 Visual Studio 中构建 C++ 库(我在 2005 年和 2008 年尝试过)。我设置了 V90 构建工具和 3.5 .net 版本并构建了 dll。

当我构建 c# 项目时没有显示错误,但运行后我得到了这样的错误:

我检查了我的库的依赖项,这就是结果(我在每个项目旁边都写了版本,其中一些是 4.0.0.0,一些是 2.0.0.0)。我挣扎了几个小时,现在我只是不知道如何让它工作..

【问题讨论】:

试用/错误解决方案:您是否尝试过将“嵌入互操作类型”切换为 false/true ?喜欢here 您使用的是哪个版本的 VS?您使用相同的版本来构建 c++ 和 C# 代码,对吧? @isi 这样的选项在 .net 4.0 之前的版本中不存在。至少它不会出现在我的旧版本中。 嗯很奇怪,但这只是一个快速的猜测。前段时间使用该选项有奇怪的错误,这些错误很难检测到,并且具有相似的错误特征,甚至不同。但我可能记不太清了;) 【参考方案1】:

异常类FileNotFoundException 有点误导。但是错误代码(0x8007007E)说明了更多。这是一个代表 Win32 错误代码的 COM 错误代码。

我们怎么知道呢?好吧,structure of COM error codes is described on MSDN。 8 表示错误,7 是设施,FACILITY_WIN32。因此,0x8007xxxx 形式的 COM 错误代码只是 Win32 错误代码。包装的 Win32 错误代码位于最不重要的字中。这里是0x007E,即ERROR_MOD_NOT_FOUND。相关文字为:

找不到指定的模块。

当系统尝试加载非托管 DLL 并且找不到它时会发生该错误。托管程序集似乎依赖于一些非托管 DLL,并且至少找不到其中一个。通常这可能是:

    找不到托管程序集包装的主要非托管 DLL,或者, 找不到非托管 DLL 所需的 MSVC 运行时。

您需要深入研究托管程序集的文档才能找出问题所在。但希望这会为您指明正确的方向。我希望我已经为您提供了有关如何在未来解码此类错误代码的指示。

【讨论】:

【参考方案2】:

在我看来,你可能走错了路。

每个进程只能加载一个版本的 .NET(不记得我在哪里阅读此信息的资源。例如,您可以阅读 this)。你的错误只是正确的行为

这个问题的常见解决方案 - 为每个 .NET 版本编写程序集。如果您查看从 nuget 交付的包,您会发现这里使用了此解决方案

我认为在您当前的情况下,您可以用非托管代码重写包装器,并将其与 C# 代码中的 pinvoke 技术一起使用。这样的解决方案将使您的包装器 .net 版本独立

【讨论】:

如果这是唯一的方法,我可以做到这一点,不幸的是它不取决于我。在问题描述中我犯了一些错误。 c++ 包装器 64 位,c# app 64 位 - 工作(.net 4.5)是唯一有效的配置。即使在 .net 4.5 上,32 位这两个程序也无法运行。 也许我会尝试在仅安装 .net framework 3.5 的全新 windows xp 系统上编译 c++ 包装器,这样它就不会依赖于版本 4.0.0.0 中的某些 mscorlib 和其他? @Lukas 嗯,情况对我来说似乎还不清楚。我真的不知道为什么它在 64 位模式下工作而在 32 位模式下不工作。它应该工作。事实证明,从 4.0 版开始,您可以并排运行不同版本的程序集(不是全部,请查看此处的表格 msdn.microsoft.com/en-us/library/ee518876(v=vs.110).aspx),但对 32 位模式没有任何限制 我已经卸载了 .net framework 4.5 和 Visual Studio 2013。在 Visual Studio 2008 中创建了 C++ 库,然后 .net Reflector 显示所有引用的版本都是 2.0.0.0。我在 Visual Studio 2008 中创建了简单的 c# 应用程序并引用了我的 dll 并且仍然出现错误 System.BadImageFormatException(无法加载文件或程序集)。事实上,我的系统是 64 位的,应该不会影响它,对吧? !Error snapshot 作为变体,您可以创建新项目并在全新项目上测试库的简化版本,仅用于测试目的。可能是您当前项目的配置中的一些错误无法让您离开【参考方案3】:

我认为问题出在我这边,我的意思是我没有复制所有必需的依赖项(一个 dll)。我认为视觉出现了问题,因为 64 位版本在没有这个 dll 的情况下工作。

【讨论】:

以上是关于如何将托管 c++ 库导入 C# 应用程序(目标 .net 版本 3.5)的主要内容,如果未能解决你的问题,请参考以下文章

将非托管 c++ 类库暴露给 c#

托管 c++ 库,它是如何工作的?

将回调参数从 C# 传递到非托管 C++

从 c# 访问 C++ .lib 库

将 C# 类库导入 Visual C++

如何在 C# 应用程序中使用 C++ 库?