English 中文(简体)
C# 转 C++/CLI 转 C DLL System.IO.FileNotFoundException
原标题:
  • 时间:2009-03-15 04:39:12
  •  标签:

当运行调用C++/CLI程序集的C#代码,该程序集又调用纯C DLL时,如果实例化调用纯C DLL函数的对象,就会出现“System.IO.FileNotFoundException:找不到指定的模块”的错误。

BackingStore is pure C. CPPDemoViewModel is C++/CLI calling BackingStore it has a reference to BackingStore.

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

一个C++/CLI测试项目只添加了对CPPDemoViewModel的引用就可以正常工作,所以这与语言之间的差异有关。

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

这感觉像是我忽略了某些愚蠢而显而易见的东西,但如果我浪费时间尝试私下解决它,那将更加愚蠢,所以我在这里出丑!

这是一个测试项目,用于移植大量旧版 C 代码,我将其保存在 DLL 中,并在 C++/CLI 中实现 ViewModel。

edit After checking directories, I can confirm that the BackingStore.dll has not been copied.

我已经创建了标准的独特项目文件夹,并使用典型的多项目解决方案。

WPFViewModelInCPP
  BackingStore
  CPPViewModel
  CPPViewModelTestInCS
    bin
      Debug
  Debug

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

WPFViewModelInCPPDebug包含BackingStore.dll、CPPDemoViewModel.dll、CPPViewModelTest.dll及其关联的.ilk和.pdb文件。

WPFViewModelInCPPCPPViewModelTestInCSinDebug contains CPPDemoViewModel and CPPViewModelTestInCS .dll and .pdb files but not BackingStore. However, manually copying BackingStore into that directory did not fix the error.

CPPDemoViewModel has the property Copy Local set which I assume is responsible for copying its DLL when if is referenced. I can t add a reference from a C# project to a pure C DLL - it just says A Reference to Backing Store could not be added.

I m not sure if I have just one problem or two.

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

DependencyWalker 告诉我缺失的文件是 GPSVC.dll,这可能表明有安全设置问题,但我怀疑这是一个误导。

edit2 With a manual copy of BackingStore.dll to be adjacent to the executable, the GUI now works fine. The C# Test Project still has problems which I suspect is due to the runtime environment of a test project but I can live without that for now.

最佳回答

The answer for the GUI, other than changing output settings, was the addition of a Pre-Build Step

copy $(ProjectDir)..DebugBackingStore.* $(TargetDir)

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

感谢关于这个SO问题有关测试配置的答案,帮我找到了答案。

问题回答

Are the C and C++ DLLs in the same directory as the C# assembly that s executing?

You may have to change your project output settings so that the C# assembly and the other DLLs all end up in the same folder.

I ve often used the Dependency Walker in cases like this; it s a sanity check that shows that all the dependencies can actually be found.

Once your app is running, you may also want to try out Process Monitor on the code you are running, to see which DLLs are being referenced, and where they are located.

The reason why this happens is because you either are loading DLLMAIN from managed code, before the CRT has an opportunity to be initialized. You may not have any managed code, be executed DIRECTLY or INDERECTLY from an effect of DllMain notifications. (See: Expert C++/CLI: .Net for Visual C++ Programmers, chapter 11++).

Or you have no native entrypoint defined wahtsoever, yet you have linked to MSVCRT. The CLR is automatically initialized for you with /clr, this detail causes a lot of confusion and must be taken into account. A mixed mode DLL actually delay loads the CLR through the use of hot-patching all of the managed entry point vtables in your classes.

A number of class initialization issues surround this topic, loader lock and delay loading CLR are a bit trickey sometimes. Try to declare global s static and do not use #pragma managed/unmanaged, isolate your code with /clr per-file.

If you can not isolate your code from the managed code, and are having trouble, (after taking some of these steps), you can also look towards hosting the CLR yourself and perhaps going through the effort of creating a domain manager, that would ensure your fully "in-the-loop" of runtime events and bootstrapping.

This is exactally why, it has nothting todo with your search path, or initialization. Unfortunately the Fusion log viewer does not help that much (which is the usual place to look for .NET CLR assembly binding issues not dependency walker).

Linking statically has nothing todo with this either. You can NOT statically link a C++/CLI application which is mixed mode.

  1. Place your DLLMAIN function into a file by itself.
  2. Ensure that this file does NOT have /CLR set in the build options (file build options)
  3. Make sure your linking with /MD or /MDd, and all your dependencies which you LINK use the exact same CRT.
  4. Evaluate your linker s settings for /DEFAULTLIB and /INCLUDE to identify any possiable reference issues, you can declare a prototype in your code and use /INCLUDE to override default library link resolution.

Good luck, also check that book it s very good.

Make sure the target system has the correct MS Visual C runtime, and that you are not accidentally building the C dll with a debug runtime.

This is an interesting dilemma. I ve never heard of a problem loading native .DLLs from C++/CLI after a call into it from C# before. I can only assume the problem is as @Daniel L suggested, and that your .DLL simply isn t in a path the assembly loader can find.

If Daniel s suggestion doesn t work out, I suggest you try statically linking the native C code to the C++/CLI program, if you can. That would certainly solve the problem, as the .DLL would then be entirely absorbed into the C++/CLI .DLL.

Had the same problem switching to 64-bit Vista. Our application was calling Win32 DLLs which was confusing the target build for the application. To resolve it we did the following:

  1. Go to project properties;
  2. Select Build tab;
  3. Change Platform target: option to x86;
  4. Rebuild the application.

When I re-ran the application it worked.





相关问题
热门标签