C#で記述された(長時間実行されている)コンソールアプリケーションがあり、COMを介して操作できるようにします(したがって、InProc DLLとregasm.exeはありません)。IDispatch
必要なのはこれだけです。つまり、従来のOLEオートメーションオブジェクトです。
ここでは、私がやろうとしていることの最小限のバージョンを紹介します。私は次のようなCOMクラスを定義しました:
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("9009311a-c0b2-42a4-8e7c-f42091d71594")]
public interface ITestEvents {
void OnEvent();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
[ComSourceInterfaces(typeof(ITestEvents))]
public class ComClass {
public event Action OnEvent;
public int Test() {
return 100;
}
}
ではMain()
、Running Object Table(ROT)のオブジェクトを"comTestApp"
Monikerに登録し、アプリケーションをスリープ状態にします。あなたはここで完全なソースを見ることができます。
これは、オブジェクトのメソッドを呼び出そうとすると問題なく機能します。たとえば、このVBScriptは正常に機能します。
Set obj = GetObject("comTestApp")
WScript.Echo obj.Test() Rem prints 100
しかし、私がイベントを接続しようとすると:
Set obj = GetObject("comTestApp")
WScript.Echo obj.Test() Rem Works
WScript.ConnectObject obj, "obj_" Rem Fails
Sub obj_OnEvent
WScript.Echo "Wish it worked"
End Sub
呼び出し時にエラーが発生しますConnectObject
(エラー0x80020009「オブジェクトを接続できませんでした」)。
アセンブリをInProcオブジェクトとしてregasm.exeに登録すると、同じコード(クラスGUID / ProgIDのみを追加する必要があります)が機能しますが、それは必要ありません。実行中のアプリケーションにアクセスする必要があるため、ROTを使用します。
簡単なC ++テストを作成して、問題についてもっと知ることができるかどうかを確認しました。ソースはこちらです。IDispatch
イベントシンクとして機能するインターフェイスを実装する最小限のCOMオブジェクトを作成しました。最初にROTからオブジェクトを取得し、をクエリしてから、のIIDをIConnectionPointContainer
取得IConnectionPoint
しITestEvents
、最後にそのAdvise()
メソッドを呼び出します。VBScriptと同様に、失敗します(ただし、別のエラー-0x80040202が発生します)。QueryInterface
イベントシンクのメソッドにブレークポイントを設定して、Advise()
が呼び出されたときに何が起こるかを確認しました。これはQueryInterface
さまざまなインターフェイスで呼び出され、最後に要求されITestEvents
、それを返してステータスを設定していることがわかりますS_OK
。それでも、Advise()
メソッドは上記のエラーを返します。
私はまた別のものを試してみました:私は、GUIDの設定したITestEvents
に{00020400-0000-0000-C000-000000000046}
いるのIIDですIDispatch
。そして今、Advise()
戻りますS_OK
!イベントをシミュレートしたところInvoke()
、イベントシンクのメソッドが呼び出されました。残念ながら、これは一般的に問題を解決しません。IConnectionPointContainer
IIDから直接リクエストすると、取得できますが、によって正しく列挙されていないようでITypeInfo
、VBScriptはまだ機能しません。
COMの経験がほとんどないので、ここからどこに行けばいいのかわかりません。IDispatch
IIDを使用すると機能するので、ITestEvents
インターフェイスにカスタムマーシャリングが必要かどうか疑問IDispatch
に思いますが、純粋なので、ランタイムで適切に処理する必要があると思います。
ありがとうございました!
私の結論は、インターフェイスIIDがレジストリに登録されていない接続シンクを(プロセス外オブジェクトに)提供することはできないということです。
シンクインターフェイスをサーバーに送信するには、マーシャリング情報が必須のようです。C#クラスが完全に提供するITypeInfo
ので、COMランタイムがインターフェイスがIDispatch
型であると認識し、デフォルトのプロキシを使用することを期待していました。残念ながら、これは当てはまらないように思われるので、唯一のオプションはレジストリです。
最低限、これが必要であることがわかりました。
[HKEY_CLASSES_ROOT\Interface\{9009311a-c0b2-42a4-8e7c-f42091d71594}\ProxyStubClsid32]
@="{00020424-0000-0000-C000-000000000046}"
これはイベントインターフェイスを定義し、プロキシに標準のIDispatchプロキシを使用することを示しています。
私はこれをWindows7と10でテストしましたが、動作します。--VBScriptは可能でConnectObject
あり、すべてが正常に機能します。
偶然、これが機能しないWin7インストールを見つけました(win ver6.1ビルド7601sp1)。タイプライブラリ(regasm.exe /tlb
)を登録した後にのみ機能しました。問題のインストールではWindowsUpdateが無効になっている(他のWin7は完全に更新されている)ので、デフォルトのIDispatchプロキシを指定していることに基づいて、ある時点で何かが変更され、タイプライブラリがなくてもインターフェイスをマーシャリングできるようになると思います。
最後に、アプリを移植可能でレジストリから独立させたいので、手動のイベント実装に頼りました。似たようなものがここに見られます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加