C#到C ++ / CLI到C DLL System.IO.FileNotFoundException

时间:2009-03-15 04:39:12

标签: c# build-process c++-cli unmanaged

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

BackingStore是纯粹的C. CPPDemoViewModel是调用BackingStore的C ++ / CLI,它引用了BackingStore。

我尝试了最简单的案例 - 添加一个新的C#单元测试项目,该项目只是尝试创建CPPDemoViewModel中定义的对象。我在C#项目中添加了一个引用到CPPDemoViewModel。

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

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

这感觉就像是一些愚蠢而且显而易见的我不知道但是我浪费时间试图私下解决这个问题会更加愚蠢,所以我在这里让自己感到尴尬!

这是对一个移植大量遗留C代码的项目的测试,我将其保存在一个带有在C ++ / CLI中实现的ViewModel的DLL中。

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

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

WPFViewModelInCPP
  BackingStore
  CPPViewModel
  CPPViewModelTestInCS
    bin
      Debug
  Debug

更高级别的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具有属性复制本地设置,我假设它负责在引用if时复制其DLL。我无法将C#项目的引用添加到纯C DLL中 - 只是说无法添加对Backing Store的引用。

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

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

DependencyWalker告诉我丢失的文件是GPSVC.dll has been suggested表示安全设置问题。我怀疑这是一只红鲱鱼。

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

6 个答案:

答案 0 :(得分:11)

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

您可能需要更改项目输出设置,以便C#程序集和其他DLL都在同一文件夹中。

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

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

答案 1 :(得分:4)

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

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

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

感谢this SO question关于测试配置的答案,以便我找到答案。

答案 2 :(得分:4)

之所以发生这种情况,是因为您要么在CRT有机会初始化之前从托管代码加载DLLMAIN。您可能没有任何托管代码,可以从DllMain通知的效果中执行 DIRECTLY INDERECTLY 。 (参见:Expert C ++ / CLI:.Net for Visual C ++ Programmers,chapter 11 ++)。

或者您没有定义本地入口点,但您已链接到MSVCRT。使用/ clr为您自动初始化CLR,此详细信息会引起很多混淆,必须予以考虑。混合模式DLL实际上延迟加载 CLR,方法是使用热修补类中所有托管入口点vtable。

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

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

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

静态链接对此也没有任何意义。您可以 NOT 静态链接混合模式的C ++ / CLI应用程序。

  1. 将您的DLLMAIN功能单独放入文件中。
  2. 确保此文件 NOT 在构建选项(文件构建选项)中设置了 / CLR
  3. 确保您与/ MD或/ MDd的链接以及您链接的所有依赖项使用完全相同的CRT。
  4. 评估/ DEFAULTLIB和/ INCLUDE的链接器设置以识别任何可能的参考问题,您可以在代码中声明原型并使用/ INCLUDE覆盖默认的库链接解析。
  5. 祝你好运,也检查一下这本书非常好。

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

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

答案 5 :(得分:0)

有同样的问题切换到64位Vista。我们的应用程序调用Win32 DLLs,这使应用程序的目标构建混乱。为解决这个问题,我们做了以下工作:

  1. 转到项目属性;
  2. 选择“构建”选项卡;
  3. 将“平台目标:”选项更改为x86;
  4. 重建应用程序。
  5. 当我重新运行应用程序时,它有效。