展開上の理由から、COM Callable Wrapperを使用する代わりに、IJWを使用してC#アセンブリをC++でラップしようとしています。
他のプロジェクトでも実行しましたが、このプロジェクトでは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-致命的な実行エンジンエラー(79F97075)(80131506)
残念ながら、Microsoftはそのエラーに関する情報を持っていません。
問題は、DLLがどこにあるかでした。
Managed.dllをc:\ exeにコピーしてこれを確認しましたが、問題なく動作しました。どうやら、CLRはアンマネージDLLのパスでマネージDLLを検索せず、実行可能ファイルがある場所(またはGAC)でのみ検索します。
立ち入る価値のない理由で、これは私が必要とする構造です。つまり、管理されたdllを見つけてCLRに手を差し伸べる必要がありました。以下のコードを参照してください。
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;
}
}
最初の問題は、デバッガタイプが混合に設定されていることを確認することです。次に、有用な例外が発生します。
混合モードdll(EXE)を使用するネイティブアプリケーションの場合は、**「デバッガタイプ」を「混合」モードに変更します。 ([プロジェクトのプロパティ]-> [構成のプロパティ]-> [デバッグ]に移動します)
他にもいくつかの点がありますが(あなたには関係がないかもしれません)、私の経験では、それらは問題を引き起こす可能性があります。 -Windows 8(セキュリティが強化されている)では、管理者としてVSを起動してみてください。 -x86構成では、x86バイナリを使用していることを確認してください。 -StrongNameの検証に注意してください。マネージC++で使用しているC#アセンブリが署名されている場合は、混合モードdllにも署名することを検討してください。
これがお役に立てば幸いです。
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>
NuGetを介してさまざまなMicrosoft.Ownセキュリティライブラリをバージョン4.0.30319にアップグレードしましたが、構成のこの行は、呼び出しをバージョン3.0.1.0にリダイレクトするようにサーバーに指示していました。これは、現在はプロジェクトの一部ではありません。設定を更新すると、問題が解決しました。
他の誰かがこの質問に遭遇し、動的なアセンブリ名を使用している場合:アセンブリ名を削除していることを確認してください。アセンブリ名には、使用できないバージョン、カルチャ、およびその他のコンテンツが含まれている可能性があります。
つまり、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;
}