マネージド コードとネイティブ コードを組み合わせた MSTest シナリオで EEFileLoadException を解決しようとしています。
私のアプリケーションは、いくつかのネイティブ (アンマネージ) C++、いくつかの C++/CLI、およびいくつかの C# など、数十個の DLL で構成されています。すべての DLL は同じディレクトリにあります。通常の操作では、メインの実行可能ファイルはネイティブ C++ です。ネイティブ DLL の 1 つ (Native.DLL と呼びましょう) が C++/CLI DLL にリンクし、C# アセンブリの 1 つを参照すると、すべて正常に動作します。
現在、MSTest でテストを作成しようとしています。コード構造は、前述の Native.DLL を呼び出す C++/CLI アセンブリを参照する C# 単体テストで構成されています。ただし、テストを実行しようとすると、Native.DLL が使用する最初の C++/CLI アセンブリを呼び出すポイントで EEFileLoadException が発生します。
Fusion ログ ビューアーを使用して、アセンブリの読み込みの問題をデバッグしようとしました。ログからの抜粋を次に示します。
*** Assembly Binder Log Entry (9/12/2012 @ 2:51:14 PM) ***
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\VS2010\Common7\IDE\QTAgent32.exe
LOG: Appbase = file:///C:/VS2010/Common7/IDE/
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\VS2010\Common7\IDE\QTAgent32.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/VS2010/Common7/IDE/My.Managed.Assembly.DLL
(...)
LOG: All probing URLs attempted and failed.
そのため、AppBase が QTAgent32.exe の場所に設定されており、すべての DLL が実際に配置されているディレクトリではなく、そこでマネージド アセンブリを検索していることは明らかです。アセンブリは単体テストによって直接参照され、アンマネージド DLL を見つけるのに問題はありませんが、アンマネージド DLL が追加のマネージド アセンブリを読み込もうとすると失敗します (ユニット テストへの参照の移動は、これが赤いニシンであることを示唆しています。私のメモを参照してください)。以下の「私が試したこと」の下)。
私はこれらすべてを Visual Studio 2010 で行っています。単体テストの大部分は生成されたコードです。実際には、SpecFlow で書かれた受け入れテストです。
まだ明確でない場合の私の質問は、次のとおりです。アセンブリの読み込みに失敗するのはなぜですか?どうすれば修正できますか?
これが私がすでに試したことです:
- 無効化された展開 (これがないと、ここまではできませんでした)
- アプリケーションへのパスを LocalTestRun.testrunconfig に追加しました (「アセンブリをロードするためのルート フォルダー」と「テストの実行時に使用するフォルダー」の両方として)
AppDomain.CurrentDomain.SetData("APPBASE", TheDirectoryThatMyDLLsAreIn);
単体テストに追加- 単体テスト コードからマネージ アセンブリを参照し、ネイティブ C++ を呼び出す前にダミー呼び出しを追加して、C++ が必要なときにアセンブリが既に存在するようにアセンブリをプリロードしようとしました。これには驚くべき結果がありました。C++/CLI アセンブリを呼び出すメソッドを JIT でコンパイルすると、同じ EEFileLoadException が発生します。
- 問題のあるアセンブリに厳密な名前を追加しました。これは効果がありませんでした。
- GAC への読み込みに失敗していたアセンブリを追加しました。これを行った後もアセンブリの読み込みは失敗しましたが、その理由を説明する Fusion ログはなく、テスト結果にはメッセージ「
The same bind was seen before, and was failed with hr = 0x80070002.
」が含まれていました。とにかく、GAC を使用することは、このプロジェクトの長期的な解決策として受け入れられるとは思いません。
テストの実行時に MSTest が与えるエラーは次のとおりです。
Test method MyTestAssembly.MyTestMethod threw exception:
System.TypeInitializationException: The type initializer for '<Module>' threw an exception. ---> <CrtImplementationDetails>.ModuleLoadExceptionHandlerException: A nested exception occurred after the primary exception that caused the C++ module to fail to load.
---> System.TypeInitializationException: The type initializer for '<Module>' threw an exception. ---> <CrtImplementationDetails>.ModuleLoadException: The C++ module failed to load during process initialization.
---> System.IO.FileNotFoundException: Could not load file or assembly 'MyNamespace.MyCPlusPlusCLIModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1478252538103a9d' or one of its dependencies. The system cannot find the file specified.Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\VS2010\Common7\IDE\QTAgent32.exe