出于部署原因,我试图使用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没有关于该错误的信息。
答案 0 :(得分:32)
问题在于DLL的位置。
我通过将managed.dll复制到c:\ exe来确认这一点,并且它没有问题。显然,CLR不会在非托管DLL的路径中查找托管DLL,只会查找可执行文件所在的DLL。 (或在GAC中)。
由于不值得进入的原因,这是我需要的结构,这意味着我需要让CLR找到托管dll。请参阅以下代码:
AssemblyResolver.h:
/// <summary>
/// Summary for AssemblyResolver
/// </summary>
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;
}
}
答案 1 :(得分:9)
第一个问题是确保Debugger类型设置为mixed。然后你会得到有用的例外。
答案 2 :(得分:4)
对于使用混合模式dll(您的EXE)的本机应用程序,更改**&#34;调试器类型&#34;到&#34;混合&#34;模式。 (转到项目属性 - &gt;配置属性 - &gt;调试)
还有一些其他要点(可能与您无关)但根据我的经验,它们可能会导致问题。 - 在Windows 8(安全性更高)上,请尝试以管理员身份启动VS. - 确保对于x86配置,您使用的是x86二进制文件。 - 注意StrongName验证,如果您在Managed C ++中使用的C#程序集已签名,请考虑签署混合模式dll。
希望这会有所帮助。
答案 3 :(得分:1)
如果其他人偶然发现了这个问题,并且您正在使用动态程序集名称:请确保您正在删除程序集名称,它可能包含您可能不使用的版本,区域性和其他内容。
即,您的MyResolveEventHandler应采用以下形式:
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;
}
答案 4 :(得分:0)
在调试ASP.NET MVC应用程序期间,我在iisexpress.exe中抛出了很多C ++ EEFileLoadException。调用堆栈和C ++异常本身并没有帮助我解决问题。
直接查看C ++异常中给出的指针地址后,我最终发现了一个指向不再使用的旧版本的库字符串。这反过来是由于我的web.config文件中的过期条目:
IsObjectMenu()
我已经通过NuGet将各种Microsoft.Own安全库升级到版本4.0.30319但配置中的这一行指示服务器将调用重定向到版本3.0.1.0,现在它已不再是我的项目的一部分。更新配置重新解决了我的问题。
答案 5 :(得分:-5)
当您在使用C ++托管dll的调试器C ++本机项目中运行时,您可能会遇到此异常。当VS2010捕获它并且您的应用程序在一些链异常将被中止后,您可以尝试在异常过滤器(Menu | Debug | Excpetion)中禁用所有C ++异常。您仍会在输出中看到此异常,但您的应用程序不会中止