EEFileLoadException lors de l'utilisation de classes C # en C ++ (application win32)

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

  •  01-07-2019
  •  | 
  •  

Question

Pour des raisons de déploiement, j'essaie d'utiliser IJW pour envelopper un assembly C # en C ++ au lieu d'utiliser un encapsulable COM Callable Wrapper.

Je l'ai fait sur d'autres projets, mais sur celui-ci, je reçois une exception EEFileLoadException. Toute aide serait la bienvenue!

Code wrapper C ++ géré (il s'agit d'une 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);
}

Code de test (il s'agit d'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;
}

Pour ce que cela vaut, le journal des événements contient les informations suivantes: .NET Runtime version 2.0.50727.143 - Erreur fatale du moteur d'exécution (79F97075) (80131506)

Malheureusement, Microsoft ne dispose d'aucune information sur cette erreur.

Était-ce utile?

La solution

Le problème concernait l'emplacement des DLL.

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

Je l’ai confirmé en copiant managed.dll dans c: \ exe et cela a fonctionné sans problème. Apparemment, le CLR ne recherchera pas les DLL gérées dans le chemin de la DLL non gérée et le recherchera uniquement à l'emplacement de l'exécutable. (ou dans le GAC).

Pour des raisons qui ne valent pas la peine d’entrer, c’est la structure dont j’ai besoin, ce qui signifie que je devais donner un coup de main au CLR pour localiser la dll gérée. Voir le code ci-dessous:

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

Autres conseils

Le premier problème consiste à vérifier que le type de débogueur est défini sur mixte. Ensuite, vous obtenez des exceptions utiles.

Pour votre application native utilisant la dll en mode mixte (Votre EXE), modifiez le type de ** " type de débogage " vers " Mixed " mode. (Accédez à Propriétés du projet - > Propriétés de configuration - > Débogage)

Il existe d’autres points (qui pourraient ne pas vous intéresser) mais, d’après mon expérience, ils pourraient poser problème.  - Sous Windows 8 (avec une sécurité renforcée), essayez de lancer votre VS en tant qu’administrateur.  - Assurez-vous que pour la configuration x86, vous utilisez des fichiers binaires x86.  - Surveillez la vérification StrongName, si les assemblys C # que vous consommez en C ++ géré en tant que signés, pensez également à signer la dll en mode mixte.

J'espère que cela aiderait.

Si quelqu'un d'autre tombe sur cette question et que vous utilisez un nom d'assembly dynamique: veillez à supprimer le nom de l'assembly, celui-ci peut contenir une version, une culture et tout autre contenu que vous ne pouvez pas utiliser.

I.e., votre MyResolveEventHandler devrait se présenter sous la forme suivante:

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

Je me faisais beaucoup jeter par iisexpress.exe lors du débogage d’une application ASP.NET MVC. La pile d'appels et l'exception C ++ en soi ne m'ont pas beaucoup aidé à cerner le problème.

Après avoir examiné directement l'adresse du pointeur indiquée dans l'exception C ++, j'ai finalement découvert une chaîne de bibliothèque pointant vers une ancienne version qui n'était plus utilisée. Cela était dû à une entrée périmée dans mon fichier 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>

J'avais mis à niveau plusieurs bibliothèques de sécurité Microsoft.Own via NuGet vers la version 4.0.30319, mais cette ligne de la configuration demandait au serveur de rediriger les appels vers la version 3.0.1.0, qui ne faisait plus partie de mon projet. La mise à jour de la configuration a résolu mes problèmes.

Lorsque vous exécutez dans le projet natif C ++ du débogueur qui utilise une dll gérée C ++, vous pouvez obtenir cette exception. Lorsque VS2010 le détecte et que votre application après l'abandon de certaines exceptions en chaîne est abandonnée, vous pouvez essayer de filtrer les exceptions (Menu | Debug | Excpetion), désactivez toutes les exceptions C ++. Vous verrez toujours cette exception en sortie mais votre application n'abandonnera pas

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top