C# 到 C++/CLI 到 C DLL System.IO.FileNotFoundException
当运行调用 C++/CLI 程序集的 C# 代码(该程序集又调用纯 C DLL)时,我收到 System.IO.FileNotFoundException:找不到指定的模块
。 一旦调用纯 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 代码的项目的测试,我将这些代码保存在 DLL 中,并使用 C++/CLI 实现的 ViewModel。
编辑 检查目录后,我可以确认 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 复制到该目录并没有修复错误。
CPPDemoViewModel 具有属性 Copy Local 设置,我认为该属性负责在引用 if 时复制其 DLL。 我无法将 C# 项目的引用添加到纯 C DLL - 它只是说无法添加对后备存储的引用。
我不确定我是否只有一两个问题。
我可以使用老式的复制构建步骤将 BackingStore.dll 复制到任何给定的 C# 项目的目录中,尽管我希望新的 .net 模型不需要这样做。
DependencyWalker 告诉我缺少的文件是 GPSVC.dll,已建议 表明安全设置问题。 我怀疑这是一条红鲱鱼。
编辑2 通过将 BackingStore.dll 的手动副本与可执行文件相邻,GUI 现在可以正常工作。 C# 测试项目仍然存在问题,我怀疑这些问题是由于测试项目的运行时环境造成的,但我现在可以没有这个问题。
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.
BackingStore is pure C.
CPPDemoViewModel is C++/CLI calling BackingStore it has a reference to 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 .
A C++/CLI test project works fine with just the added ref to CPPDemoViewModel so it's something about going between the languages.
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.
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.
edit
After checking directories, I can confirm that the BackingStore.dll has not been copied.
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.
WPFViewModelInCPP\Debug contains BackingStore.dll, CPPDemoViewModel.dll, CPPViewModelTest.dll and their associated .ilk and .pdb files
WPFViewModelInCPP\CPPViewModelTestInCS\bin\Debug 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.
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.
DependencyWalker is telling me that the missing file is GPSVC.dll which has been suggested indicates security setting issues. I suspect this is a red herring.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
C 和 C++ DLL 是否与正在执行的 C# 程序集位于同一目录中?
您可能必须更改项目输出设置,以便 C# 程序集和其他 DLL 最终都位于同一文件夹中。
在这种情况下,我经常使用Dependency Walker; 这是一个健全性检查,表明实际上可以找到所有依赖项。
应用运行后,您可能还想尝试进程监视器在您正在运行的代码上,查看正在引用哪些 DLL 以及它们所在的位置。
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.
GUI 的答案除了更改输出设置之外,还包括添加预构建步骤
。测试项目的答案是将缺少的 DLL 添加到 testrunconfig 的“部署”选项卡中。 您可以通过直接编辑默认的 LocalTestRun.testrunconfig (显示在解决方案项下的解决方案中)或右键单击解决方案并添加新的测试运行配置来实现此目的,该配置随后将显示在主测试下菜单。
感谢您对这个关于测试配置的问题的回答引导我到答案。
The answer for the GUI, other than changing output settings, was the addition of a Pre-Build Step
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.
Thanks for the answers on this SO question on test configurations for leading me to the answer.
发生这种情况的原因是您在 CRT 有机会初始化之前从托管代码加载 DLLMAIN。 您可能没有任何受 DllMain 通知影响直接或间接执行的托管代码。 (请参阅:专家 C++/CLI:面向 Visual C++ 程序员的 .Net,第 11++ 章)。
或者您没有定义任何本机入口点,但您已链接到 MSVCRT。 CLR 会使用 /clr 自动为您初始化,这个细节会造成很多混乱,必须予以考虑。 混合模式 DLL 实际上通过使用热修补类中的所有托管入口点 vtable 来延迟加载 CLR。
许多类初始化问题都围绕着这个主题,加载器锁和延迟加载 CLR 有时有点棘手。 尝试声明全局静态并且不要使用#pragma托管/非托管,使用每个文件的/clr隔离您的代码。
如果您无法将代码与托管代码隔离,并且遇到麻烦(在采取其中一些步骤之后),您还可以考虑自己托管 CLR,并且可能需要创建一个域管理器,这将确保您完全处于运行时事件和引导的“循环内”。
这就是为什么,它与您的搜索路径或初始化无关。 不幸的是,Fusion 日志查看器并没有多大帮助(这是查找 .NET CLR 程序集绑定问题而不是依赖项遍历器的通常位置)。
静态链接也与此无关。 您不能静态链接混合模式的 C++/CLI 应用程序。
祝你好运,也检查一下那本书,非常好。
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.
Good luck, also check that book it's very good.
确保目标系统具有正确的 MS Visual C 运行时,并且您不会意外地使用调试运行时构建 C dll。
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.
这是一个有趣的困境。 我以前从未听说过从 C# 调用本机 .DLL 后从 C++/CLI 加载本机 .DLL 时出现问题。 我只能假设问题是 @Daniel L 建议,并且您的 .DLL 根本不在程序集加载器可以找到的路径中。
如果 Daniel 的建议不起作用,我建议您尝试将本机 C 代码静态链接到 C++/CLI 程序(如果可以的话)。 这肯定会解决问题,因为 .DLL 将被完全吸收到 C++/CLI .DLL 中。
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.
切换到 64 位 Vista 时遇到同样的问题。 我们的应用程序正在调用 Win32 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:
When I re-ran the application it worked.