1

これを可能にする API があるかどうか、または自分で作成する必要があるかどうかはわかりません。これが私が達成しようとしていることです。

NT サービスに接続して別の COM サーバーとのセッションを開始するアプリケーションがあります。

  • アプリケーション、クライアント。
  • ブローカー NT サービス; (システム アカウント コンテキスト)。
  • セッション COM サービス。(システム アカウント コンテキスト、必要に応じてユーザーを偽装します)。

セッション サーバーには、NT サービスに接続するすべてのアプリケーション インスタンスに対して実行中のインスタンスがあります。アプリケーションは、セッション サーバーが COM ライブラリ DLL をロードし、セッション サーバー内のそれらの DLL からオブジェクトとサービスをホストするように要求できます。DLL は、登録不要のアクティベーションによって登録されます。

セッション サーバーからオブジェクトを作成し、それらをアプリケーションに戻すことは、それらが IDispatch から派生している限り正常に機能します。これは、スクリプト言語がこれを使用することが予想されるため、システム全体の要件であり、それが要求されたインターフェイスです。C++ アプリケーションは、セッション サーバーでホストされているオブジェクトを使用することもできます。しかし IDispatch は、C++ で扱うには非常に冗長なインターフェイスです。

私の質問はこれです:

ホストされている DLL には、アプリケーションが認識しているデュアル カスタム インターフェイスがあり、それらのインターフェイスに関する型情報は、ITypeInfo を介してアプリケーションで読み取ることができるとします。ITypeInfo 情報も含む IDispatch インターフェイスを提供できる場合、実行時に元のカスタム インターフェイスを模倣するプロキシを作成する API はありますか。プロキシに必要なのは IDispatch インターフェイスを呼び出すことだけですが、C++ にはカスタム インターフェイスとして表示されます。より最適なソリューションは、DLL がそのマニフェストに登録したのと同じプロキシ (既定の OLE オートメーション プロキシ) を使用することです。

複数のアプリケーションが同じモジュールを持っていてもバージョンが異なる可能性があるため、DLL のプロキシ/スタブを登録できません。したがって、登録不要のアクティベーションを使用します。

4

2 に答える 2

2

1 つのオプションは、ハード型付けされたデュアル インターフェイスをIDispatchあきらめ、コンパイル時に生成されたハード型付けされたスマート ポインター ラッパーを介して -only ディスパッチ インターフェイスを使用することです。これらを生成するには、および/またはオプションを指定してVC++#importを使用します。raw_dispinterfacesno_dual_interfaces

IDispatch::InvokeCOM マーシャラーは、呼び出しをマーシャリングするためにタイプ ライブラリを必要としません。ただし、並行して実行するタイプ ライブラリ/DLL のバージョンに対してコンパイルする必要があります。または、少なくとも DISPID とメソッド シグネチャが COM DLL のすべてのバージョンで同じであることを確認してください。AFAIR、生成されたスマートポインターは使用しないためIDispatch::GetIdsOfNames、DISPID はハードコードされています。

パフォーマンスは、直接のデュアル インターフェイス呼び出しと比較してオプションではIDispatch::Invokeないかもしれませんが、説明したプロセス間呼び出しのシナリオを考えれば、問題ではないと思います。マーシャリングされたアウトプロセス COM 呼び出しは、インプロセス呼び出しよりもはるかにコストがかかりIDispatch::Invokeます。

于 2015-08-05T04:15:55.830 に答える
2

タイプ ライブラリに記述されているすべて[oleautomation]のインターフェイス (およびすべての[dual]インターフェイス) は、タイプ ライブラリ マーシャラーを使用できます。

ここでは、プロキシ スタブ DLL を見つける手間を、タイプ ライブラリを見つける手間と交換します。assemblyしたがって、次のように、アセンブリのマニフェスト (要素の直下) でインターフェイスとタイプ ライブラリを宣言します。

<comInterfaceExternalProxyStub name="IFooBar"
                               iid="{IIIIIIII-IIII-IIII-IIII-IIIIIIIIIIII}"
                               proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
                               tlbid="{TTTTTTTT-TTTT-TTTT-TTTT-TTTTTTTTTTTT}" />

<!-- This also works for a type library embedded in a DLL -->
<file name="FooBar.tlb">
    <!-- If you have multiple embedded type libraries, use the resourceid attribute -->
    <typelib tlbid="{TTTTTTTT-TTTT-TTTT-TTTT-TTTTTTTTTTTT}"
             version="1.0" />
</file>

インターフェイスがインターフェイスではなく[oleautomation]、プロキシ スタブ DLL を分離したい場合は、次のようなものを使用します。

<file name="FooBarPS.dll">
    <comInterfaceProxyStub name="IFooBar"
                           iid="{IIIIIIII-IIII-IIII-IIII-IIIIIIIIIIII}"
                           proxyStubClsid32="{PPPPPPPP-PPPP-PPPP-PPPP-PPPPPPPPPPPP}"
                           threadingModel="Both" />
</file>

AcomInterfaceProxyStubは によく似ていますcomClassが、プロキシ/スタブに重点を置いており、インターフェイスに関連付けられています。

分離されたプロキシ/スタブ DLL の有無にかかわらずテストする場合は、プロキシ/スタブセクションのコメントを (解除) することにより、(要素レベルcomInterfaceExternalProxyStubの下で) と(要素の下で)のペアで同じ効果を実現できます。assemblycomClassfilefile

<comInterfaceExternalProxyStub name="IFooBar"
                               iid="{IIIIIIII-IIII-IIII-IIII-IIIIIIIIIIII}"
                               proxyStubClsid32="{PPPPPPPP-PPPP-PPPP-PPPP-PPPPPPPPPPPP}" />

<file name="FooBarPS.dll">
    <comClass description="PSFactoryBuffer"
              clsid="{PPPPPPPP-PPPP-PPPP-PPPP-PPPPPPPPPPPP}"
              threadingModel="Both" />
</file>

確かではありませんが、標準のプロキシ/スタブ DLL が複数のインターフェイスに使用されている場合は、このアプローチも使用する必要があります。


編集:これはあなたにとって新しいものではないようです。あなたの問題は、動的にロードされたライブラリのマニフェストをアクティブにしても、セッション サービスでは、その状態が現在のスレッドにのみ残ることです。そのため、COM ワーカー スレッド (RPC スレッドなど) は、インターフェイス、コクラス、およびプロキシ/スタブについて認識しません。

ブローカ サービス ( REGDB_E_IIDNOTREG) に表示されるエラーは、セッション サービスからのマーシャリングが原因である可能性があります。メソッドが戻ったに発生するため、セッションサービスではそのエラーは発生しません。

ただし、当然のことながら、ブローカ サービスで発生している可能性があります。ライブラリはロードされず、ましてやマニフェストはロードされません。

私がお勧めするアプローチは、セッション サービスとブローカー サービスに、登録不要の COM 情報を宣言するアセンブリに依存するマニフェストを持たせることです。このように、すべてがデフォルトのアクティベーション コンテキストの一部となり、アクティベーション コンテキストに関して何もする必要はありません。

デフォルトのアクティベーション コンテキストに事前に必要なものを含める以外に、所有していないスレッドのアクティベーション コンテキストを制御することはできないことに注意してください。

あなたの質問のこの部分について:

複数のアプリケーションが同じモジュールを持っていてもバージョンが異なる可能性があるため、DLL のプロキシ/スタブを登録できません。したがって、登録不要のアクティベーションを使用します。

あなたが何を言おうとしているのか、私にははっきりしません。モジュールに下位互換性がある場合は、心配する必要はありません。そうでない場合は、別の CLSID/ProgID を使用してください。

COM に違反しているため、実際には異なるインターフェイスで同じ IID を使用しているという意味ではないことを願っています。この問題を解決する最善の方法は、やらないことです。もう 1 つの方法は、セッション サービスとブローカー サービスの両方で、専用のアクティベーション コンテキストを持つ専用のスレッドを使用することです。これは、おそらくセッション サービスだけで見てきたように、非常に脆弱なアプローチです。

私が見ているように、COM 分離はまったく必要ないかもしれません。ただし、それでも必要な場合は、ブローカーとセッションの両方のサービスに対して実行する必要があり、実行時ではなくマニフェストから実行する必要があります。

于 2015-08-03T15:10:00.760 に答える