C++(win32 앱)에서 C# 클래스를 사용할 때 EEFileLoadException이 발생합니다.

StackOverflow https://stackoverflow.com/questions/93770

  •  01-07-2019
  •  | 
  •  

문제

배포상의 이유로 COM 호출 가능 래퍼를 사용하는 대신 IJW를 사용하여 C++에서 C# 어셈블리를 래핑하려고 합니다.

다른 프로젝트에서도 이 작업을 수행했지만 이 프로젝트에서는 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:\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;
}

};

래퍼.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;
    }
}

다른 팁

첫 번째 문제는 디버거 유형이 혼합으로 설정되어 있는지 확인하는 것입니다.그러면 유용한 예외가 발생합니다.

혼합 모드 dll(EXE)을 사용하는 기본 애플리케이션의 경우 **"디버거 유형"을 "혼합" 모드로 변경합니다.(프로젝트 속성 -> 구성 속성 -> 디버깅으로 이동)

(귀하와 관련이 없을 수도 있는) 몇 가지 다른 사항이 있지만 제 경험상 문제가 발생할 수 있습니다.- 보안이 강화된 Windows 8에서는 관리자 권한으로 VS를 시작해 보세요.- x86 구성의 경우 x86 바이너리를 사용하고 있는지 확인하세요.- StrongName 확인을 주의 깊게 살펴보세요. Managed C++에서 서명된 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;
}

ASP.NET MVC 응용 프로그램을 디버깅하는 동안 iisexpress.exe에서 C++ EEFileLoadException이 많이 발생했습니다.호출 스택과 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>

NuGet을 통해 다양한 Microsoft.Own 보안 라이브러리를 버전 4.0.30319로 업그레이드했지만 구성의 이 줄은 서버에 호출을 버전 3.0.1.0으로 리디렉션하도록 지시하고 있었으며 이는 이제 더 이상 내 프로젝트의 일부가 아닙니다.구성을 업데이트하면 문제가 해결되었습니다.

C++ 관리 dll을 사용하는 디버거 C++ 네이티브 프로젝트에서 실행하면 이 예외가 발생할 수 있습니다.VS2010이 이를 포착하고 일부 체인 예외 이후 애플리케이션이 중단되면 예외 필터(Menu|Debug|Excpetion)에서 모든 C++ 예외를 비활성화해 볼 수 있습니다.출력에는 이 예외가 계속 표시되지만 애플리케이션은 중단되지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top