C# 到 C++/CLI 到 C DLL System.IO.FileNotFoundException
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/647310/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# to C++/CLI to C DLL System.IO.FileNotFoundException
提问by Andy Dent
I'm getting System.IO.FileNotFoundException: The specified module could not be found
when running C# code that calls a C++/CLI assembly which in turn calls a pure C DLL. It happens as soon as an object is instantiated that calls the pure C DLL functions.
我System.IO.FileNotFoundException: The specified module could not be found
在运行 C# 代码时遇到了调用 C++/CLI 程序集的 C# 代码,而后者又调用了纯 C DLL。一旦一个对象被实例化,调用纯 C DLL 函数,它就会发生。
BackingStore is pure C. CPPDemoViewModel is C++/CLI calling BackingStore it has a reference to BackingStore.
BackingStore 是纯 C. CPPDemoViewModel 是 C++/CLI 调用 BackingStore 它有一个对 BackingStore 的引用。
I tried the simplest possible case - add a new C# unit test project that just tries to create an object defined in CPPDemoViewModel . I added a reference from the C# project to CPPDemoViewModel .
我尝试了最简单的可能情况 - 添加一个新的 C# 单元测试项目,该项目只是尝试创建在 CPPDemoViewModel 中定义的对象。我从 C# 项目中添加了一个对 CPPDemoViewModel 的引用。
A C++/CLI test project works fine with just the added ref to CPPDemoViewModel so it's something about going between the languages.
C++/CLI 测试项目只需添加对 CPPDemoViewModel 的引用即可正常工作,因此它是在语言之间进行转换的事情。
I'm using Visual Studio 2008 SP1 with .Net 3.5 SP1. I'm building on Vista x64 but have been careful to make sure my Platform target is set to x86.
我正在使用带有 .Net 3.5 SP1 的 Visual Studio 2008 SP1。我在 Vista x64 上构建,但一直小心地确保我的平台目标设置为 x86。
This feels like something stupid and obvious I'm missing but it would be even more stupid of me to waste time trying to solve it in private so I'm out here embarrassing myself!
这感觉就像我错过了一些愚蠢而明显的事情,但浪费时间试图私下解决它会更愚蠢,所以我在这里让自己尴尬!
This is a test for a project porting a huge amount of legacy C code which I'm keeping in a DLL with a ViewModel implemented in C++/CLI.
这是对移植大量遗留 C 代码的项目的测试,我将这些代码保存在带有在 C++/CLI 中实现的 ViewModel 的 DLL 中。
editAfter checking directories, I can confirm that the BackingStore.dll has not been copied.
编辑检查目录后,我可以确认没有复制BackingStore.dll。
I have the standard unique project folders created with a typical multi-project solution.
我使用典型的多项目解决方案创建了标准的唯一项目文件夹。
WPFViewModelInCPP BackingStore CPPViewModel CPPViewModelTestInCS bin Debug Debug
The higher-level Debug appears to be a common folder used by the C and C++/CLI projects, to my surprise.
令我惊讶的是,更高级别的 Debug 似乎是 C 和 C++/CLI 项目使用的公共文件夹。
WPFViewModelInCPP\Debug contains BackingStore.dll, CPPDemoViewModel.dll, CPPViewModelTest.dll and their associated .ilk and .pdb files
WPFViewModelInCPP\Debug 包含 BackingStore.dll、CPPDemoViewModel.dll、CPPViewModelTest.dll 及其关联的 .ilk 和 .pdb 文件
WPFViewModelInCPP\CPPViewModelTestInCS\bin\Debug contains CPPDemoViewModel and CPPViewModelTestInCS .dll and .pdb files but notBackingStore. However, manually copying BackingStore into that directory did not fix the error.
WPFViewModelInCPP\CPPViewModelTestInCS\bin\Debug 包含 CPPDemoViewModel 和 CPPViewModelTestInCS .dll 和 .pdb 文件,但不包含 BackingStore。但是,手动将 BackingStore 复制到该目录并没有修复错误。
CPPDemoViewModel has the property Copy Localset 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.
CPPDemoViewModel 具有属性Copy Local集,我认为它负责在引用 if 时复制其 DLL。我无法将来自 C# 项目的引用添加到纯 C DLL - 它只是说无法添加对后备存储的引用。
I'm not sure if I have just one problem or two.
我不确定我是否只有一两个问题。
I can use an old-fashioned copying build step to copy the BackingStore.dll into any given C# project's directories, although I'd hoped the new .net model didn't require that.
我可以使用老式的复制构建步骤将 BackingStore.dll 复制到任何给定的 C# 项目目录中,尽管我希望新的 .net 模型不需要这样做。
DependencyWalker is telling me that the missing file is GPSVC.dll which has been suggestedindicates security setting issues. I suspect this is a red herring.
DependencyWalker 告诉我丢失的文件是 GPSVC.dll,有人建议它表示安全设置问题。我怀疑这是一个红鲱鱼。
edit2With 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.
edit2将 BackingStore.dll 的手动副本与可执行文件相邻,GUI 现在可以正常工作。C# 测试项目仍然存在问题,我怀疑这是由于测试项目的运行时环境造成的,但我现在可以没有它。
采纳答案by Andy Dent
The answer for the GUI, other than changing output settings, was the addition of a Pre-Build Step
除了更改输出设置之外,GUI 的答案是添加预构建步骤
copy $(ProjectDir)..\Debug\BackingStore.* $(TargetDir)
The answer for the Test projects was to add the missing DLL to the Deployment tab of the testrunconfig. You can either do so by directly editing the default LocalTestRun.testrunconfig(appears in Solution under Solution Items) or right-click the Solution and Add a new test run config, which will then appear under the main Test menu.
测试项目的答案是将缺少的 DLL 添加到 testrunconfig 的部署选项卡。您可以通过直接编辑默认的LocalTestRun.testrunconfig(出现在解决方案项下的解决方案中)或右键单击解决方案并添加新的测试运行配置来实现,该配置将出现在主测试菜单下。
Thanks for the answers on this SO questionon test configurations for leading me to the answer.
回答by Daniel LeCheminant
Are the C and C++ DLLs in the same directory as the C# assembly that's executing?
C 和 C++ DLL 是否与正在执行的 C# 程序集位于同一目录中?
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.
您可能需要更改项目输出设置,以便 C# 程序集和其他 DLL 都位于同一文件夹中。
I've often used the Dependency Walkerin cases like this; it's a sanity check that shows that all the dependencies can actually be found.
在这种情况下,我经常使用Dependency Walker;这是一个健全性检查,表明实际上可以找到所有依赖项。
Once your app is running, you may also want to try out Process Monitoron the code you are running, to see which DLLs are being referenced, and where they are located.
一旦您的应用程序运行,您可能还想在您正在运行的代码上试用Process Monitor,以查看正在引用哪些 DLL 以及它们位于何处。
回答by Randolpho
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 Lsuggested, and that your .DLL simply isn't in a path the assembly loader can find.
这是一个有趣的困境。我从来没有听说过在从 C# 调用本机 .DLL 之后从 C++/CLI 加载它的问题。我只能假设问题是@Daniel L建议的,并且您的 .DLL 根本不在程序集加载程序可以找到的路径中。
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.
如果 Daniel 的建议行不通,我建议您尝试将本机 C 代码静态链接到 C++/CLI 程序,如果可以的话。那肯定会解决问题,因为 .DLL 将被完全吸收到 C++/CLI .DLL 中。
回答by leppie
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.
确保目标系统具有正确的 MS Visual C 运行时,并且您不会意外地使用调试运行时构建 C dll。
回答by RandomNickName42
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 DIRECTLYor INDERECTLYfrom an effect of DllMain notifications. (See: Expert C++/CLI: .Net for Visual C++ Programmers, chapter 11++).
发生这种情况的原因是因为您要么在 CRT 有机会被初始化之前从托管代码加载 DLLMAIN。您可能没有任何托管代码,会因DllMain 通知的影响直接或间接执行。(请参阅:Expert C++/CLI:.Net for Visual C++ Programmers,第 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 loadsthe CLR through the use of hot-patching all of the managed entry point vtables in your classes.
或者您没有定义任何本地入口点,但您已链接到 MSVCRT。CLR 会使用 /clr 自动为您初始化,这个细节会引起很多混乱,必须加以考虑。混合模式 DLL 实际上通过使用热修补类中的所有托管入口点 vtable 来延迟加载CLR。
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.
许多类初始化问题围绕着这个主题,加载器锁定和延迟加载 CLR 有时有点棘手。尝试声明全局的静态并且不要使用#pragma managed/unmanaged,用 /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.
如果您无法将代码与托管代码隔离,并且遇到了问题(在执行了其中一些步骤之后),您还可以考虑自己托管 CLR,并可能通过创建域管理器的努力来确保运行时事件和引导的完全“循环”。
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).
这正是为什么它与您的搜索路径或初始化无关。不幸的是,Fusion 日志查看器并没有太大帮助(这是查找 .NET CLR 程序集绑定问题而不是依赖项walker 的常用位置)。
Linking statically has nothing todo with this either. You can NOTstatically link a C++/CLI application which is mixed mode.
静态链接也与此无关。您不能静态链接混合模式的 C++/CLI 应用程序。
- Place your DLLMAIN function into a file by itself.
- Ensure that this file does NOThave /CLRset in the build options (filebuild options)
- Make sure your linking with /MD or /MDd, and all your dependencies which you LINK use the exact same CRT.
- 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.
- 将您的 DLLMAIN 函数单独放入一个文件中。
- 确保该文件确实不具备/ CLR在构建选项集(文件生成选项)
- 确保您使用 /MD 或 /MDd 进行链接,并且您链接的所有依赖项都使用完全相同的 CRT。
- 评估 /DEFAULTLIB 和 /INCLUDE 的链接器设置以识别任何可能的引用问题,您可以在代码中声明原型并使用 /INCLUDE 覆盖默认库链接解析。
Good luck, also check that book it's very good.
祝你好运,也检查那本书,它非常好。
回答by RandomNickName42
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:
切换到 64 位 Vista 时遇到同样的问题。我们的应用程序正在调用 Win32 DLL,这混淆了应用程序的目标构建。为了解决它,我们做了以下事情:
- Go to project properties;
- Select Build tab;
- Change 'Platform target:' option to x86;
- Rebuild the application.
- 转到项目属性;
- 选择构建选项卡;
- 将“平台目标:”选项更改为 x86;
- 重建应用程序。
When I re-ran the application it worked.
当我重新运行应用程序时,它起作用了。