1

COMインタープロセスオブジェクトを扱う場合、 を使用せずに をにキャストIDispatch*しても安全ですか?IUnknown*QueryInterface

ここで、IDispatchオブジェクトは他のプロセスから取得されますOtherProcess.exe。そして、私の同僚は、 を得るために に電話QueryInterfaceするべきだと言っています。IDispatchIUnknown

現在、私はやっています:

void CComThrowDispatch::CheckCOMAvailabilty() const
{
    IUnknown * pIUnknown = m_spDispatchDriver.p;   
    // is this line above a problem ? 
    // m_spDispatchDriver is an ATL CComDispatchDriver 
    // it handles an object instanciated in another process.
    // m_spDispatchDriver.p is of type IDispatch*

    if (pIUnknown == nullptr) return;
    bool bComObjectReachable = ::CoIsHandlerConnected(pIUnknown) == TRUE;
    if (bComObjectReachable == false)
    {
        throw MyException;
    }
}

彼の提案に関する私の問題: 私は、OtherProcess.exe がクラッシュしたか強制終了された場合 (アクセス違反) に対処しています。この存在しない OtherProcess.exe からオブジェクトをカプセル化するInvokeon のような関数を呼び出すと、これらのアクセス違反が引き起こされるようです (編集:コメントと回答は、この最新の仮定が完全に誤りであったことを示しています!)。IDispatch

そのため、 as パラメーター::CoIsHandlerConnected(pIUnknown);を取るアプリケーションのテストを保護しようとしています。IUnknown

しかし、同僚が私にアドバイスするように、QueryInterfaceを呼び出すことによって、私が解決しようとしている同じ問題に戻ることを 恐れています: これは、もはや存在しないオブジェクトを処理します。 (もう一度編集します。この仮定も誤りです)。IDispatchIDispatchQueryInterfaceIUnknown

キャストをするだけで本当に間違っていますか?死んだプロセス間COMオブジェクトを処理する一般的な方法は何ですか?

これは、OAIdl.h 内の の定義の始まりであり、IDispatchから派生したものとして宣言されていIUnknownます。

MIDL_INTERFACE("00020400-0000-0000-C000-000000000046")
IDispatch : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
        /* [out] */ __RPC__out UINT *pctinfo) = 0;
4

3 に答える 3

2

C++ で ( のように) にキャストIDispatchすると、 が から派生するため、まったく同じポインター値が生成されます。OTOH、for onを実行すると、別のポインター返される場合がありますが、それでも正当な操作です。実際、これは COM オブジェクトの ID を取得する方法です。たとえば、2 つのインターフェイスが同じ COM オブジェクトによって実装されているかどうかを確認する方法です (同じ COM アパートメント内で常に機能するハード COM ルール)。IUnknownstatic_cast<IUnknown*>(pDispatch)IDispatchIUnknownQueryInterfaceIID_IUnknownpDispatch

つまり、COM マーシャラーによって実装されたプロキシ COM オブジェクトはインターフェイスをキャッシュしている可能性があるため、リモート サーバーが既にダウンしているにもかかわらず、への呼び出し返され、プロキシの有効な IDIDispatch::QueryInterfaceが返さS_OKれる場合があります。IUnknownつまり、そのような操作は即時の IPC 呼び出しを引き起こさない可能性があります。

あなたの場合、COM サーバーがまだ正常に動作しているかどうかをテストするには、IDispatch::GetTypeInfoCount既に持っているプロキシ オブジェクトを呼び出すだけです。これにより、実際には IPC 呼び出しが発生します (または、サーバーが別のホストで実行されている場合は、ワイヤを介した往復)。

リモート サーバーがクラッシュしたか、使用できない場合、エラーが発生する可能性がありCO_E_OBJNOTCONNECTEDます (別のエラー コードである可能性がありますが、そうではないことは確かS_OKです)。

ただし、シナリオによっては、サーバーが使用可能かどうかを確認するためだけに追加の IPC 呼び出しを行うと、コストのかかる操作になる可能性があることに注意してください。

于 2015-06-10T18:06:39.503 に答える
2

オブジェクトがリモートであるかどうかを検出するにはCoIsHandlerConnectedQueryInterfaceとにかく引数を取得します( forIProxyManagerなど)。したがって、既に持っているポインターを提供するか、追加でクエリを実行するかは関係ありませんIUnknown。呼び出しは、リモート オブジェクトのステータスに影響しませQueryInterfaceん。オブジェクトがリモートであるかどうか、リモート オブジェクトが死んでいるかどうかCoIsHandlerConnectedに関係なく、追加のQueryInterface. したがって、それを行う必要はありません。

IDispatch::Invoke次に、リモート オブジェクトが停止している場合 (プロセス外のサーバーがクラッシュした場合など)に呼び出しても安全であることに注意してください。プロキシは、未定義の動作なしで単にエラー コードを返します。つまり、まったく必要ないように見えます。CoIsHandlerConnectedクライアント プロセスのコンテキストでアクセス違反が発生した場合は、最初に解決する必要がある他の問題がある可能性があります。

于 2015-06-10T14:44:33.357 に答える
1

いいえ、常にする必要がありますQueryInterface

インターフェイスを com にしたからといって、IUnknownそれを に直接キャストできるわけではありませんIDispatch。COM は、基になるオブジェクトへのプロキシを提供している可能性があります。つまり、ポインタは とは何の関係もありませんIDispatch

同様に、実装は、実装するオブジェクトをラップする場合がIDispatchあり、呼び出すQueryInterfaceと、このオブジェクトに委任されます。または、outer にデリゲートする COM オブジェクトへのポインターがある場合もありますIUnknown

したがって、時間の経過とともに変化する可能性があるため、基本的には、うまくいくと思っても直接キャストしないでください。呼び出しQueryInterfaceがパフォーマンスのボトルネックになることはめったにないため、避ける価値はありません。

于 2015-06-10T14:05:49.387 に答える