2012-04-23 13 views
1

COM Interopに登録されている.NETアセンブリとアセンブリで型を読み込むリフレクションコードを組み合わせると、奇妙な動作が発生します。私はデバッガで何が起こっているのか分析し、ネットを検索して解決策を見つけました。 私は助けを借りて多くの記事を見つけましたが、私は問題を完全に解決できませんでした。問題アセンブリがCOM相互運用機能によって読み込まれたときのAppDomainのパス

Aの

概要は、.NET(私の場合はVB6アプリケーション)ではないのexeファイルを持っています。それはフォルダAにあります。
私はフォルダBにいくつかの.NET dllを持っています。そのうちの1つはCOM dllです。
exeファイルは、COM .NETアセンブリの.NETオブジェクトのCOMインスタンスをインスタンス化します。 次に、AppDomainのメインパスはフォルダAですが、フォルダBにしたいと思います。フォルダAなので、.NETコード内の一部のリフレクトタイプロードが失敗します。ここで

の詳細は以下のとおりです。

私はVB6のアプリケーションを持っています。 exeファイルは、私はVB6の声明

Set DotNetE2 = CreateObject("MyDotNet.E2") 

これは、COM相互運用のためのregistredである私の.NETクラスのインスタンスを作成する必要があり、その中のフォルダA. に存在します。 .NETクラスのヘッダは次のようになります。

namespace MyDotNet.E2.COM 
{ 
    [ComVisible(true)] 
    [Guid("776FF4EA-2F40-4E61-8EF3-08250CB3712B")] 
    [ProgId("MyDotNet.E2")] 
    [ClassInterface(ClassInterfaceType.AutoDual)] 
    public class E2 
    { 

マイ.NETアセンブリ「「このアセンブリは、E3と呼ばれる2つの他の.NETアセンブリへの参照を持っているフォルダB. に常駐MyDotNet.E2.COM.dllと同じフォルダにあるE4 E3にはE4への参照がありません これらのアセンブリでは、期待通りにコードを実行することができますので、参照は問題ありません。 これまでのところとても役に立ちました 今、 E3のコードでE4の型を反映しようとしました これは失敗します。

string dotnetPath = Path.GetDirectoryName(
       Assembly.GetExecutingAssembly().Location); 
string mainDir = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; 
string otherDirs = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath; 

Assembly assembly = Assembly.LoadFrom(Path.Combine(dotnetPath, "E4.dll")); 
Type mytype = assembly.GetType("MyDotnet.E4.MyForm"); 

観察

dotnetPathがMAINDIR異なる:ここではコードです。
mytypeがnullです。期待される結果は型インスタンスです。
exeファイルをフォルダBに移動すると、.NETアセンブリと一緒に動作します。次に、dotnetPathとmainDirは同じです。
E4ではなくE2でリフレクションコードを実行すると、dotnetPath!= mainDirの場合でも動作します。
しかし、まさにシナリオで私はアウトラインを持っていますが、それはうまくいきません。

私は、設定ファイルにあるものを指定することによって、PrivateBinPathのAppDomainに他のフォルダを追加するためのヒントをいくつか見つけました。しかし、私はこれに成功していません。私は設定ファイルをCOM .NETファイルとVB6 exe-fileに追加しようとしましたが、私のPrivateBinPathプロパティに何も起こりませんでした。ここで私が追加しようとした設定ファイルは次のとおりです。

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <runtime> 
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
    <probing privatePath="..\..\FolderB"/> 
    </assemblyBinding> 
    </runtime> 
</configuration> 

私のアセンブリと型を再構築するために私に聞かないでください。このプロジェクトはかなり複雑で、これは最高のアーキテクチャです。

答えて

1

私はこれを自分自身で解決することができました。 システムがアセンブリの解決に失敗した場合に発生するキーはAssemblyResolveイベントでした。 それは、ここで説明されています http://msdn.microsoft.com/library/system.appdomain.assemblyresolve

それは私がこのイベントを使用する必要があり、.NETフレームワークのバグのように思えるが、この問題を回避するには、かなり素敵なことが判明しました。

string dotnetPath = Path.GetDirectoryName(
            Assembly.GetExecutingAssembly().Location); 
string mainDir = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; 

if (!mainDir.Equals(dotnetPath, StringComparison.CurrentCultureIgnoreCase)) 
{ 
    // This will happen if .NET process is fired 
    // from a COM call from another folder. 
    // Solution: an event is fired if assembly-resolving fails. 
    AppDomain.CurrentDomain.AssemblyResolve += 
         new ResolveEventHandler(CurrentDomain_AssemblyResolve); 
} 

イベントハンドラは非常に簡単です:

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
{ 
    foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) 
    { 
     if (assembly.FullName == args.Name) return assembly; 
    } 
    return null; 
} 
関連する問題