EEFileLoadException cuando se usan clases de C# en C++ (aplicación win32)

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

  •  01-07-2019
  •  | 
  •  

Pregunta

Por motivos de implementación, estoy intentando usar IJW para empaquetar un ensamblado de C# en C++ en lugar de usar un COM Callable Wrapper.

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

Código contenedor C++ administrado (esto está en una 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 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 si sirve de algo, el registro de eventos informa lo siguiente:.NET Runtime Versión 2.0.50727.143 - Error de motor de ejecución fatal (79F97075) (80131506)

Lamentablemente, Microsoft no tiene información sobre ese error.

¿Fue útil?

Solución

El problema era dónde estaban ubicadas las DLL.

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

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

Por razones que no vale la pena explicar, esta es la estructura que necesito, lo que significa que necesitaba echarle una mano al CLR para ubicar la DLL administrada.Ver código a continuación:

AsambleaResolver.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;
}

};

Envoltorio.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;
    }
}

Otros consejos

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

Para su aplicación nativa que consume el dll de modo mixto (su EXE), cambie el **"Tipo de depurador" al modo "Mixto".(Vaya a Propiedades del proyecto -> Propiedades de configuración -> Depuración)

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

Espero que esto ayude.

En caso de que alguien más se encuentre con esta pregunta y esté utilizando un nombre de ensamblaje dinámico:asegúrese de eliminar el nombre del ensamblado, ya que puede contener versión, cultura y otro contenido que no puede utilizar.

Es decir, su MyResolveEventHandler debe tener la 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;
}

Iiisexpress.exe lanzaba mucho la excepción C++ EEFileLoadException durante la depuración de una aplicación ASP.NET MVC.La pila de llamadas y la excepción de C++ en sí no fueron de gran ayuda para ayudarme a identificar el problema.

Después de mirar directamente la dirección del puntero proporcionada en la excepción de C++, finalmente descubrí una cadena de biblioteca que apuntaba a una versión anterior que ya no estaba en uso.Esto a su vez se debió a una entrada desactualizada 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 actualizado varias bibliotecas de seguridad de Microsoft.Own a través de NuGet a la versión 4.0.30319, pero esta línea en la configuración le indicaba al servidor que redirigiera las llamadas a la versión 3.0.1.0, que ahora ya no formaba parte de mi proyecto.La actualización de la configuración resolvió mis problemas.

Cuando ejecuta un proyecto nativo de C++ del depurador que utiliza una DLL administrada por C++, puede obtener esta excepción.Cuando VS2010 lo detecta y su aplicación después de algunas excepciones en cadena será cancelada, puede intentar en el filtro de excepciones (Menú|Depurar|Excpeción) deshabilitar todas las excepciones de C++.Seguirá viendo esta excepción en el resultado, pero su aplicación no se cancelará.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top