2008-09-18 22 views
23

Por razones de implementación, estoy tratando de usar IJW para envolver un ensamblado C# en C++ en lugar de utilizar un Contenedor COM invocable.EEFileLoadException al usar clases C# en C++ (aplicación win32)

Lo he hecho en otros proyectos, pero en este caso, recibo una EEFileLoadException. ¡Cualquier ayuda sería apreciada!

Gestionado código C++ envoltorio (esto es en un 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); 
} 

Código de prueba (este es un archivo 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; 
} 

Por lo que vale la pena, el registro de sucesos informa lo siguiente : .NET Runtime versión 2.0.50727.143 - Fatal Execution Engine Error (79F97075) (80131506)

Desafortunadamente, Microsoft no tiene información rmación sobre ese error.

+0

¿Ha realizado pruebas para verificar que el ensamblaje se carga desde el mismo directorio? –

+0

Cuando copié manualmente la DLL administrada en el directorio de exe, funcionó sin este código adicional. –

Respuesta

28

El problema era dónde estaban ubicados los archivos DLL.

  • c: \ dlls \ managed.dll
  • c: \ dlls \ wrapper.dll
  • c: \ exe \ my.exe

me confirmaron esto copiando managed.dll en c: \ exe y funcionó sin problemas. Aparentemente, el CLR no buscará archivos DLL administrados en la ruta del archivo DLL no administrado y solo lo buscará donde está el archivo ejecutable. (o en el GAC).

Por razones que no valen la pena, esta es la estructura que necesito, lo que significaba que tenía que darle una mano al CLR para ubicar el dll administrado. Ver código de abajo:

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

Acabo de pasar horas tratando de averiguar qué pasaba con mi DLL mixto solo para finalmente darme cuenta de que estaba lanzando una 'EEFileLoadException'. Gracias por esto, ayudó :) – porges

+0

Tan simple ... ¡gracias! – Spidy

6

El primer problema es asegurarse de que el tipo de depurador esté configurado en mixto. Entonces obtienes excepciones útiles.

+0

Tengo su problema con un complemento de Excel escrito en Managed C++ y realmente encontré una depuración mixta que me permite _less_ excepciones útiles; en particular, no veo la EEFileLoadException en sí, solo varios reestrenos posteriores. –

+0

Este consejo probablemente me ahorró una hora de depuración. –

-5

Cuando se ejecuta en el depurador proyecto de C++ nativo que utilizan C++ DLL administrado puede obtener esta excepción. Cuando VS2010 lo detecte y su aplicación después de que se cancelen algunas excepciones de la cadena, puede intentar con el filtro de excepciones (Menú | Depurar | Excluir) deshabilitar todas las excepciones de C++. Todavía verá esta excepción en el resultado, pero su aplicación no abortará

+2

-1: esto parece un mal consejo que no aborda el problema –

1

En caso de que alguien más tropiece con esta pregunta, y esté usando un nombre de ensamblado dinámico: asegúrese de quitar el nombre del ensamblado, puede contener una versión , cultura y otro contenido que no puedes usar.

es decir, su MyResolveEventHandler debe ser en forma de:

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

Para que la aplicación nativa de consumir la DLL de modo mixto (Su EXE), cambiar el ** "Tipo Depurador" a modo de "mixta".(Vaya a Propiedades del proyecto -> Propiedades de configuración -> Depuración)

Hay algunos otros puntos (que pueden no ser relevantes para usted) pero en mi experiencia podrían causar problemas. - En Windows 8 (con una mayor seguridad) intente iniciar su VS como administrador. - Asegúrese de que para la configuración x86 esté utilizando binarios x86. - Observe la verificación de StrongName, si sus ensamblajes de C# que está consumiendo en C++ administrado están firmados, considere firmar el dll de modo mixto también.

Espero que esto ayude.

0

Estaba obteniendo la C++ EEFileLoadException lanzada mucho por iisexpress.exe durante la depuración de una aplicación ASP.NET MVC. La pila de llamadas y la excepción de C++ no fueron terriblemente útiles para ayudarme a identificar el problema.

Después de mirar directamente la dirección del puntero dada en la excepción de C++ finalmente descubrí una cadena de biblioteca que apuntaba a una versión anterior que ya no se usa. Esto a su vez se debió a una entrada fuera de fecha en mi archivo 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> 

había mejorado diversas bibliotecas de seguridad a través de Microsoft.Own NuGet a la versión 4.0.30319 pero esta línea en la configuración era instruir al servidor para que redirija las llamadas a la versión 3.0.1.0, que ya no formaba parte de mi proyecto. La actualización de la configuración resolvió mis problemas.

Cuestiones relacionadas