5

これは一種の複雑な質問であり、COM、CLR、および reg-free COM に関連するやや難解な領域に当てはまります。

まず、私のメイン アプリケーションは Python で書かれています。そのため、(開発中の) コードベースは、たとえば C:\mainapp\main.py にあります。

もちろん、Windows では、プログラムを実行するのは C:\Python27\python.exe です。

C:\mainapp\ManagedCOMObject.dll にある、私が制御する C# で記述された COM オブジェクトと通信する (IDispatch を使用して) python から reg-free COM を (win32com を使用して) 使用したいと考えています。


注: python / pythoncom を話せない場合は、Dispatch() の呼び出しが最終的に CoCreateInstance() になることに注意してください。


試行 1

#main.py:

import win32com.client
CLSID_ManagedComObject_MyClass = "{zzzzz....}" #This is correct
myclass = win32com.client.Dispatch(CLSID_ManagedComObject_MyClass)

結果

オブジェクトがレジストリにないため (予想どおり)、マニフェスト ファイルについては何も言及していませんでした。また、python.exe のマニフェストは明らかにオブジェクトについて認識していません。


試行 2

#main.py:

ac = ActivationContext("C:\mainapp\myapp.manifest", asm_dir="C:\mainapp")
with ac.activate():
    #The above two lines fill in a ACTCTX structure, call CreateActCtx, and call ActivateActCtx 
    import win32com.client
    CLSID_ManagedComObject_MyClass = "{zzzzz....}" #This is correct
    myclass = win32com.client.Dispatch(CLSID_ManagedComObject_MyClass)

-

#myapp.manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity type="win32" 
                name="My.Main.App" 
                version="1.0.0.0" 
                processorArchitecture="x86" 
    />
    <dependency>
        <dependentAssembly>
            <assemblyIdentity
                        name="ManagedComObject" 
                        version="1.0.0.0" 
                        processorArchitecture="msil" 
            />
        </dependentAssembly>
    </dependency>
</assembly>

ManagedCOMObject には、clrClass タグを使用して COM オブジェクトを宣言するマニフェストが埋め込まれていることに注意してください。

結果

ActicateActCtx 呼び出しは成功し、myapp.manifest と ManagedComObject.dll のマニフェストを正しく解析します。sxstrace.exe を使用してこれを確認しました。

C:\Python27\ManagedComObject.dll をプローブした後、CoCreateInstance の呼び出しが FileNotFound で失敗します。Fusion のログは、PrivatePath が設定されていないと主張しており (python.exe.config が存在しないためと考えられます)、単純に C:\mainapp で C# オブジェクトを探しません。

質問

  1. なぜこれが失敗するのですか?CLR COM ローダー スタブが C# アセンブリをインポートできないためだと思います。このステップの前に失敗した場合、CLR は読み込まれません。そのため、CLR が ManagedCOMObject.dll を見つけられないことが原因であると信じてしまいます。

  2. CLR が読み込まれていることに注意してください。これは、COM が現在のアクティベーション コンテキストを正常に調べて登録を見つけたことを意味すると思います。マニフェストで clrClass が何をするのか正確にはわかりませんが、おそらく CLR が正常に読み込まれました。

  3. 問題は、アセンブリをロードするときに CLR が ActCtx に注意を払っていないことだと思います。マネージ コードを作成している場合は、AppDomain.CurrentDomain.AssemblyResolve イベントにフックして、自分で DLL を見つけることができます。代わりに、アンマネージ コードを作成し、CLR を暗黙的にのみホストしているため、アプリケーションの PrivatePath やアセンブリのプローブ方法を何らかの方法で変更できますか?

4

1 に答える 1

3

問題は、アセンブリをロードするときにCLRがActCtxに注意を払っていないことだと思います

それは正解です。CLR には、Windows アクティベーション コンテキストの影響を受けないアセンブリを見つけるための独自の戦略があります。デフォルトでは、GAC のみを検索し、次に EXE のプライベート ビン パスを検索します。Fuslogvw.exe ユーティリティを使用すると、これを確認できます。

ここには多くの優れたオプションはありません。アセンブリを GAC にインストールすることは明白な解決策であり、COM DLL Hell 問題の解決に役立つため、一般的に [ComVisible] アセンブリに適しています。他にできることは、それを C:\Python27 ディレクトリにコピーするか、同じディレクトリに python.exe.config ファイルを書き込んで、プローブ パスを C:\Python27 のサブディレクトリに変更することだけです。どちらもうまくスケーリングしません。自分で CLR をホストしたり、AppDomain.AssemblyResolve イベント ハンドラーを作成したりすることは、検討の余地がありません。

Regasm.exe /codebase を回避したい場合は、GAC を使用するのが適切な解決策です。

于 2012-11-27T19:21:32.003 に答える