EEFileLoadException quando usando classes C # em C ++ (win32 app)
-
01-07-2019 - |
Pergunta
Por razões de implantação, eu estou tentando usar IJW para embrulhar um C # montagem em C ++ em vez de usar um Callable Wrapper COM.
Já fiz isso em outros projetos, mas em um presente, eu estou recebendo um EEFileLoadException. Qualquer ajuda seria apreciada!
C ++ invólucro código Controlados (isto é, em uma 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 Test (este é um 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 que vale a pena, o log de eventos informa o seguinte: .NET Runtime versão 2.0.50727.143 - Erro do motor Execução Fatal (79F97075) (80131506)
Infelizmente, a Microsoft não tem informações sobre esse erro.
Solução
O problema era onde as DLLs foram localizados.
- c: \ DLLs \ managed.dll
- c: \ DLLs \ wrapper.dll
- c: \ exe \ my.exe
Eu confirmei isso copiando managed.dll em c: \ exe e ele funcionou sem problema. Aparentemente, o CLR não vai olhar para DLLs geridos no caminho da DLL não gerenciado e só vai olhar para ele, onde o executável é. (Ou no GAC).
Por razões não vale a pena indo para, este é o que eu preciso estrutura, o que significava que eu precisava para dar o CLR uma mão na localizado a dll gerido. Ver código abaixo:
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;
}
}
Outras dicas
A primeira questão é se certificar que o tipo depurador está definido para misto. Então você começa exceções úteis.
Para você aplicativo nativo consumindo o dll modo misto (seu EXE), altere o ** "Debugger Type" para o modo "misto". (Vá para Propriedades do projeto -> Propriedades de configuração -> Depuração)
Há alguns outros pontos (que pode não ser relevante para você), mas na minha experiência, eles poderiam causar problemas. - No Windows 8 (com maior segurança) por favor tente lançar o seu VS como admin. - Certifique-se de que para a configuração x86 você estiver usando binários x86. -. Relógio para verificação StrongName, se seus # montagens C que você está consumindo em Managed C ++ como assinado, por favor considere assinar o modo dll mista demasiado
Espero que isso ajudaria.
Em caso de alguém se depara com esta questão, e você estiver usando um nome conjunto dinâmico:. Verifique se você está tirando o nome do assembly, pode conter versão, cultura e outros conteúdos que você não pode usar
.ou seja, o seu MyResolveEventHandler deve ser na 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;
}
Eu estava recebendo o ++ EEFileLoadException C jogado um monte de iisexpress.exe durante a depuração de uma aplicação ASP.NET MVC. A pilha de chamadas e da própria exceção C ++ não eram terrivelmente útil para ajudar me fixar para baixo o problema.
Depois de olhar diretamente para o endereço ponteiro dada no C ++ exceção que eu finalmente descobri uma corda biblioteca que estava apontando para uma versão antiga não está mais em uso. Este por sua vez foi devido a uma entrada out-of-date no meu arquivo 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>
Eu tinha atualizado várias bibliotecas de segurança Microsoft.Own via NuGet para a versão 4.0.30319 mas esta linha na configuração estava instruindo o servidor para redirecionar as chamadas para a versão 3.0.1.0, que agora já não faz parte do meu projeto. Atualizando a configuração resovled meus problemas.
Quando você executa no depurador C ++ projeto nativa que uso C ++ gerenciado dll você pode obter essa exceção. Quando VS2010 pegá-lo e sua aplicação depois de algumas exceções cadeia será abortado você pode tentar no filtro de exceção (Menu | Debug | excpetion) desativar todas as exceções C ++. Você ainda verá essa exceção na saída, mas a sua aplicação não vai abortar