在C ++中使用C#类时的EEFileLoadException(win32 app)

出于部署原因,我试图使用IJW在C ++中包装C#程序集,而不是使用COM Callable Wrapper。

我已经在其他项目上完成了,但是在这个项目上,我得到了一个EEFileLoadException。 任何帮助,将不胜感激!

托管C ++包装器代码(这是在DLL中):

extern "C" __declspec(dllexport) IMyObject* CreateMyObject(void) { //this class references c# in the constructor return new CMyWrapper( ); } extern "C" __declspec(dllexport) void DeleteMyObject(IMyObject* pConfigFile) { delete pConfigFile; } extern "C" __declspec(dllexport) void TestFunction(void) { ::MessageBox(NULL, _T("My Message Box"), _T("Test"), MB_OK); } 

测试代码(这是一个EXE):

 typedef void* (*CreateObjectPtr)(); typedef void (*TestFunctionPtr)(); int _tmain testwrapper(int argc, TCHAR* argv[], TCHAR* envp[]) { HMODULE hModule = ::LoadLibrary(_T("MyWrapper")); _ASSERT(hModule != NULL); PVOID pFunc1 = ::GetProcAddress(hModule, "TestFunction"); _ASSERT(pFunc1 != NULL); TestFunctionPtr pTest = (TestFunctionPtr)pFunc1; PVOID pFunc2 = ::GetProcAddress(hModule, "CreateMyObject"); _ASSERT(pFunc2 != NULL); CreateObjectPtr pCreateObjectFunc = (CreateObjectPtr)pFunc2; (*pTest)(); //this successfully pops up a message box (*pCreateObjectFunc)(); //this tosses an EEFileLoadException return 0; } 

对于它的价值,事件日志报告以下内容:.NET运行时版本2.0.50727.143 – 致命执行引擎错误(79F97075)(80131506)

不幸的是,Microsoft没有关于该错误的信息。

问题在于DLL的位置。

  • C:\ dll文件\ managed.dll
  • C:\ dll文件\ wrapper.dll
  • C:\ EXE \ my.exe

我通过将managed.dll复制到c:\ exe来确认这一点,它没有问题。 显然,CLR不会在非托管DLL的路径中查找托管DLL,只会查找可执行文件所在的DLL。 (或在GAC中)。

由于不值得进入的原因,这是我需要的结构,这意味着我需要让CLR找到托管的dll。 见下面的代码:

AssemblyResolver.h:

 ///  /// Summary for AssemblyResolver ///  public ref class AssemblyResolver { public: static Assembly^ MyResolveEventHandler( Object^ sender, ResolveEventArgs^ args ) { Console::WriteLine( "Resolving..." ); Assembly^ thisAssembly = Assembly::GetExecutingAssembly(); String^ thisPath = thisAssembly->Location; String^ directory = Path::GetDirectoryName(thisPath); String^ pathToManagedAssembly = Path::Combine(directory, "managed.dll"); Assembly^ newAssembly = Assembly::LoadFile(pathToManagedAssembly); return newAssembly; } }; 

Wrapper.cpp:

 #include "AssemblyResolver.h" extern "C" __declspec(dllexport) IMyObject* CreateMyObject(void) { try { AppDomain^ currentDomain = AppDomain::CurrentDomain; currentDomain->AssemblyResolve += gcnew ResolveEventHandler( AssemblyResolver::MyResolveEventHandler ); return new CMyWrapper( ); } catch(System::Exception^ e) { System::Console::WriteLine(e->Message); return NULL; } } 

第一个问题是确保将Debugger类型设置为mixed。 然后你得到有用的例外。

对于使用混合模式dll(您的EXE)的本机应用程序,将**“调试器类型”更改为“混合”模式。 (转到项目属性 – >配置属性 – >调试)

还有一些其他要点(可能与您无关),但根据我的经验,它们可能会导致问题。 – 在Windows 8(安全性更高)上,请尝试以管理员身份启动VS. – 确保对于x86配置,您使用的是x86二进制文件。 – 注意StrongNamevalidation,如果您在Managed C ++中使用的C#程序集已签名,请考虑签署混合模式dll。

希望这会有所帮助。

如果其他人偶然发现了这个问题,并且您正在使用动态程序集名称:确保您正在剥离程序集名称,它可能包含您可能不使用的版本,文化和其他内容。

即,您的MyResolveEventHandler应采用以下forms:

 static Assembly^ MyResolveEventHandler( Object^ sender, ResolveEventArgs^ args ) { Console::WriteLine( "Resolving..." ); String^ assemblyName = args->Name; // Strip irrelevant information, such as assembly, version etc. // Example: "Acme.Foobar, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" if( assemblyName->Contains(",") ) { assemblyName = assemblyName->Substring(0, assemblyName->IndexOf(",")); } Assembly^ thisAssembly = Assembly::GetExecutingAssembly(); String^ thisPath = thisAssembly->Location; String^ directory = Path::GetDirectoryName(thisPath); String^ pathToManagedAssembly = Path::Combine(directory, assemblyName ); Assembly^ newAssembly = Assembly::LoadFile(pathToManagedAssembly); return newAssembly; } 

在调试ASP.NET MVC应用程序期间,我在iisexpress.exe中抛出了很多C ++ EEFileLoadException。 调用堆栈和C ++exception本身对帮助我解决问题并没有太大帮助。

在直接查看C ++exception中给出的指针地址后,我最终发现了一个指向不再使用的旧版本的库字符串。 这反过来是由于我的web.config文件中的过期条目:

         

我已经通过NuGet将各种Microsoft.Own安全库升级到版本4.0.30319,但配置中的这一行指示服务器将调用重定向到版本3.0.1.0,现在不再是我的项目的一部分。 更新配置重新解决了我的问题。

当您在使用C ++托管DLL的调试器C ++本机项目中运行时,您可能会遇到此exception。 当VS2010捕获它并且您的应用程序在一些链exception将被中止后,您可以尝试在exceptionfilter(Menu | Debug | Excpetion)中禁用所有C ++exception。 您仍会在输出中看到此exception,但您的应用程序不会中止