2008-09-18 3 views
23

배포상의 이유로 IXW를 사용하여 COM 호출 가능 래퍼 대신 C++에서 C# 어셈블리를 래핑하려고합니다.C++ (win32 응용 프로그램)에서 C# 클래스를 사용하는 경우 EEFileLoadException

다른 프로젝트에서도이 작업을 수행했지만이 작업에서는 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 - 치명적인 실행 엔진 오류 (79137050)

불행히도 Microsoft에는 정보가 없습니다. 그 오류에 대한 설명.

+0

어셈블리가 동일한 디렉토리에서로드되는지 확인하는 테스트가 있습니까? –

+0

수동으로 관리되는 DLL을 exe의 디렉터리에 복사하면이 추가 코드없이 작동합니다. –

답변

28

문제는 DLL의 위치입니다.

  • C : \ DLL을 \ managed.dll
  • C : \ DLL을 \ 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 : C++를 사용하는 네이티브 프로젝트는 DLL을 관리

#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

나는 단지 그것이'EEFileLoadException'을 던지고 있다는 것을 알아 차리기 위해 혼성 DLL에 무엇이 잘못되었는지 알아 내려고 노력했다. 이걸 주셔서 감사합니다, 그것은 도왔습니다 :) – porges

+0

너무 간단 .... 감사합니다! – Spidy

6

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

+0

Managed C++로 작성된 Excel 추가 기능으로 문제가 발생했습니다. 실제로 혼합 디버깅을 사용하면 유용한 예외가 _ _ _ 발생합니다. 특히 나는 EEFileLoadException 자체를 보지 못했다. 단지 몇 번의 연속적인 rethrows이다. –

+0

이 조언은 아마도 저에게 한 시간의 디버깅을 저장했습니다. –

-5

당신이 디버거 C에서 실행 ++이 예외를받을 수 있습니다. VS2010이 일부 체인 예외가 중단 된 후 응용 프로그램과 응용 프로그램을 catch하면 예외 필터 (Menu | Debug | Excpetion)에서 모든 C++ 예외를 비활성화 할 수 있습니다. 출력에서이 예외가 계속 표시되지만 응용 프로그램이 중단되지 않습니다.

+2

-1 : 문제를 해결하지 못하는 잘못된 조언처럼 보입니다. –

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; 
} 
2

위한 혼합 모드 DLL (귀하의 EXE)에 "혼합"모드를 ** "디버거 유형을"변경을 소비 네이티브 응용 프로그램입니다.(프로젝트 속성 -> 구성 속성 -> 디버깅으로 이동)

다른 점 (관련이 없을 수도 있음)이 있지만 내 경험상 문제가 될 수 있습니다. - Windows 8 (보안 강화)에서 VS를 관리자로 시작하십시오. - x86 구성의 경우 x86 바이너리를 사용하고 있는지 확인하십시오. - StrongName 확인을 위해 Managed C++에서 서명 한 C# 어셈블리를 사용하는 경우 혼합 모드 dll 서명도 고려하십시오.

희망이 도움이 될 것입니다.

0

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> 
나는 버전 4.0.30319에 NuGet을 통해 다양한 Microsoft.Own 보안 라이브러리를 업그레이드했다하지만 설정이 줄을이었다

서버가 더 이상 내 프로젝트에 포함되지 않은 버전 3.0.1.0으로 호출을 리디렉션하도록 지시합니다. 구성을 업데이트하면 내 문제가 재발되었습니다.

관련 문제