8

System.IO.FileNotFoundException: The specified module could not be found在运行调用 C++/CLI 程序集的 C# 代码时得到,该程序集又调用纯 C DLL。只要实例化调用纯 C DLL 函数的对象,就会发生这种情况。

BackingStore 是纯 C。CPPDemoViewModel 是调用 BackingStore 的 C++/CLI,它具有对 BackingStore 的引用。

我尝试了最简单的情况——添加一个新的 C# 单元测试项目,它只是试图创建一个在 CPPDemoViewModel 中定义的对象。我从 C# 项目中添加了对 CPPDemoViewModel 的引用。

只需添加对 CPPDemoViewModel 的引用,C++/CLI 测试项目就可以正常工作,因此它是在语言之间进行切换。

我正在使用带有 .Net 3.5 SP1 的 Visual Studio 2008 SP1。我在 Vista x64 上构建,但一直小心确保我的平台目标设置为 x86。

这感觉就像我错过了一些愚蠢和明显的事情,但浪费时间试图私下解决它会更愚蠢,所以我在这里让自己尴尬!

这是对移植大量遗留 C 代码的项目的测试,我将这些代码保存在 DLL 中,并使用 C++/CLI 实现的 ViewModel。

编辑 检查目录后,我可以确认没有复制BackingStore.dll。

我有使用典型的多项目解决方案创建的标准唯一项目文件夹。

WPFViewModelInCPP
  后台存储
  CPPViewModel
  CPPViewModelTestInCS
    斌
      调试
  调试

令我惊讶的是,更高级别的 Debug 似乎是 C 和 C++/CLI 项目使用的公共文件夹。

WPFViewModelInCPP\Debug 包含 BackingStore.dll、CPPDemoViewModel.dll、CPPViewModelTest.dll 及其关联的 .ilk 和 .pdb 文件

WPFViewModelInCPP\CPPViewModelTestInCS\bin\Debug 包含 CPPDemoViewModel 和 CPPViewModelTestInCS .dll 和 .pdb 文件,但包含 BackingStore。但是,手动将 BackingStore 复制到该目录并不能修复该错误。

CPPDemoViewModel 具有属性Copy Local set,我假设它负责在引用 if 时复制其 DLL。我无法将 C# 项目的引用添加到纯 C DLL - 它只是说无法添加对备份存储的引用。

我不确定我是否只有一两个问题。

我可以使用老式的复制构建步骤将 BackingStore.dll 复制到任何给定的 C# 项目的目录中,尽管我希望新的 .net 模型不需要这样做。

DependencyWalker 告诉我丢失的文件是 GPSVC.dll,这表明存在安全设置问题。我怀疑这是一个红鲱鱼。

edit2 将BackingStore.dll 的手动副本与可执行文件相邻,GUI 现在可以正常工作。C# 测试项目仍然存在问题,我怀疑这是由于测试项目的运行时环境造成的,但我现在可以不用它。

4

6 回答 6

12

C 和 C++ DLL 是否与正在执行的 C# 程序集位于同一目录中?

您可能必须更改项目输出设置,以便 C# 程序集和其他 DLL 最终都位于同一文件夹中。

在这种情况下,我经常使用Dependency Walker;这是一个健全性检查,表明实际上可以找到所有依赖项。

一旦您的应用程序运行,您可能还想在您正在运行的代码上试用Process Monitor,以查看正在引用哪些 DLL 以及它们的位置。

于 2009-03-15T04:42:55.050 回答
4

除了更改输出设置外,GUI 的答案是添加了预构建步骤

copy $(ProjectDir)..\Debug\BackingStore.* $(TargetDir)

测试项目的答案是将缺少的 DLL 添加到 testrunco​​nfig 的部署选项卡中。您可以通过直接编辑默认的LocalTestRun.testrunco​​nfig(出现在解决方案项下的解决方案中)来执行此操作,或者右键单击解决方案并添加新的测试运行配置,然后该配置将出现在主测试菜单下。

感谢您对这个关于测试配置的SO 问题的回答,以引导我找到答案。

于 2009-03-17T07:46:24.890 回答
4

发生这种情况的原因是因为您要么在 CRT 有机会初始化之前从托管代码加载 DLLMAIN。您可能没有任何托管代码,可以根据 DllMain 通知的效果直接间接执行。(请参阅:Expert C++/CLI:面向 Visual C++ 程序员的 .Net,第 11 章++)。

或者您没有定义任何本地入口点,但您已链接到 MSVCRT。CLR 会使用 /clr 自动为您初始化,这个细节会引起很多混乱,必须考虑在内。混合模式 DLL 实际上通过使用热修补类中的所有托管入口点 vtable 来 延迟加载CLR。

许多类初始化问题围绕着这个主题,加载器锁定和延迟加载 CLR 有时有点棘手。尝试声明全局的静态并且不要使用#pragma managed/unmanaged,使用/clr per-file 隔离你的代码。

如果您无法将您的代码与托管代码隔离开来,并且遇到了问题(在采取了其中一些步骤之后),您还可以考虑自己托管 CLR,也许还可以通过创建域管理器来确保您完全“在环”运行时事件和引导。

这正是为什么它与您的搜索路径或初始化无关的原因。不幸的是,Fusion 日志查看器并没有太大帮助(这是查找 .NET CLR 程序集绑定问题而不是依赖walker 的常用位置)。

静态链接也与此无关。您不能静态链接混合模式的 C++/CLI 应用程序。

  1. 将您的 DLLMAIN 函数单独放入一个文件中。
  2. 确保此文件在构建选项中设置/CLR文件构建选项)
  3. 确保您与 /MD 或 /MDd 的链接,以及您链接的所有依赖项都使用完全相同的 CRT。
  4. 评估 /DEFAULTLIB 和 /INCLUDE 的链接器设置以识别任何可能的引用问题,您可以在代码中声明原型并使用 /INCLUDE 覆盖默认库链接解析。

祝你好运,还检查了那本书,它非常好。

于 2009-05-19T05:33:20.110 回答
2

确保目标系统具有正确的 MS Visual C 运行时,并且您不会意外地使用调试运行时构建 C dll。

于 2009-03-15T06:10:15.713 回答
1

这是一个有趣的困境。在从 C# 调用本地 .DLL 之后,我从未听说过从 C++/CLI 加载本机 .DLL 的问题。我只能假设问题出在@Daniel L建议的范围内,并且您的 .DLL 根本不在程序集加载器可以找到的路径中。

如果 Daniel 的建议不起作用,我建议您尝试将本机 C 代码静态链接到 C++/CLI 程序,如果可以的话。这肯定会解决问题,因为 .DLL 将被完全吸收到 C++/CLI .DLL 中。

于 2009-03-15T05:03:40.117 回答
0

切换到 64 位 Vista 时遇到同样的问题。我们的应用程序正在调用 Win32 DLL,这混淆了应用程序的目标构建。为了解决它,我们做了以下事情:

  1. 转到项目属性;
  2. 选择构建选项卡;
  3. 将“平台目标:”选项更改为 x86;
  4. 重建应用程序。

当我重新运行应用程序时,它起作用了。

于 2009-07-14T15:47:10.823 回答