Исключение EEFileLoadException при использовании классов C # в C ++ (приложение win32)
-
01-07-2019 - |
Вопрос
По соображениям развертывания я пытаюсь использовать IJW для переноса сборки C # на C ++ вместо использования вызываемой оболочки COM.
Я делал это в других проектах, но в этом я получаю исключение 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);
}
Тестовый код (это исполняемый файл):
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)
К сожалению, корпорация Майкрософт не располагает информацией об этой ошибке.
Решение
Проблема заключалась в том, где находились библиотеки DLL.
- c:\dlls\managed.dll
- c:\dlls\wrapper.dll
- c:\exe\my.exe
Я подтвердил это, скопировав managed.dll в c:\exe, и это сработало без проблем.Очевидно, среда CLR не будет искать управляемые библиотеки 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;
}
}
Другие советы
Первая проблема заключается в том, чтобы убедиться, что для типа отладчика установлено значение mixed.Тогда вы получите полезные исключения.
Для вашего собственного приложения, использующего библиотеку DLL смешанного режима (ваш EXE-файл), измените ** "Тип отладчика" на "Смешанный" режим.(Перейдите в раздел Свойства проекта -> Свойства конфигурации -> Отладка)
Есть некоторые другие моменты (которые могут не иметь отношения к вам), но, по моему опыту, они могут вызвать проблемы.- В Windows 8 (с более строгой безопасностью), пожалуйста, попробуйте запустить свой VS от имени администратора.- Убедитесь, что для конфигурации x86 вы используете двоичные файлы x86.- Следите за проверкой StrongName, если ваши сборки C #, которые вы используете в Managed C ++, подписаны, пожалуйста, подумайте о подписании библиотеки DLL смешанного режима.
Надеюсь, это поможет.
На случай, если кто-нибудь еще наткнется на этот вопрос, и вы используете динамическое имя сборки:убедитесь, что вы удалили название сборки, оно может содержать версию, язык использования и другой контент, который вы, возможно, не используете.
Т.е. ваш 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;
}
Я часто получал исключение C ++ EEFileLoadException, вызванное iisexpress.exe во время отладки приложения ASP.NET MVC.Стек вызовов и само исключение C ++ не очень помогли мне определить проблему.
Посмотрев непосредственно на адрес указателя, указанный в исключении C ++, я в конце концов обнаружил строку библиотеки, которая указывала на старую версию, которая больше не используется.Это, в свою очередь, было связано с устаревшей записью в моем файле web.config:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly> </assemblyBinding> </runtime>
Я обновил различные версии Microsoft.Собственные библиотеки безопасности через NuGet до версии 4.0.30319, но эта строка в конфигурации предписывала серверу перенаправлять вызовы на версию 3.0.1.0, которая теперь больше не была частью моего проекта.Обновление конфигурации решило мои проблемы.
Когда вы запускаете в отладчике собственный проект C ++, который использует C ++ managed dll, вы можете получить это исключение.Когда VS2010 поймает это, и ваше приложение после некоторых цепных исключений будет прервано, вы можете попробовать в фильтре исключений (Меню | Debug | Excpetion) отключить все исключения C ++.Вы по-прежнему увидите это исключение в выходных данных, но ваше приложение не будет прервано