11

私はExcel RTDサーバーの実装を書いていますIDispatch. ATL にはアクセスできませんが、ActiveQt を使用していますが、生の C または C++ でもこれを行う方法に興味があります。IDispatchCOM サーバーでメソッドを適切に実装するにはどうすればよいですか?

いつものように、ドキュメンテーションはパニックになるほどひどいものです。私がこれまでに読んだこと:

  • メソッド呼び出しを someに委譲するIDispatchITypeInfoことをお勧めします。これは正しいです?
  • もしそうなら、どうやっITypeInfoて自分自身を手に入れますか?LoadTypeLib()とファミリー (続いて をITypeLib::GetTypeInfo()参照)?
  • そうでない場合、どのように適切に実装されていますか? 質の高いドキュメントへのリンクと自己完結型の例は非常に役に立ちます。

このアプローチは、COMクライアントLoadTypeLib()が何らかのライブラリの型情報に到達するのに適しているように思われますが、COM サーバーがそれ自体をイントロスペクトしようとするのには適していないようです。私は正しいですか?

4

3 に答える 3

9

IDispatch の実装は、簡単な場合も難しい場合もあります。(ATL を使用できないと仮定します)。

簡単な方法は、TypeInfo をサポートしないことです (GetTypeInfoCountE_NOTIMPLから0 を返しGetTypeInfoます。誰も呼び出してはいけません)。

次に、サポートする必要があるのはGetIDsOfNamesとだけInvokeです。本質的には、単なる大きなルックアップ テーブルです。

の場合GetIDsOfNamesは、 を返しDISP_E_UNKNOWNNAMEますcNames != 1。引数名をサポートするつもりはありません。rgszNames[0]次に、名前から ID へのマッピングを検索するだけです。

最後に、Invoke を実装します。pDispParams と pVarResult 以外はすべて無視します。VariantChangeType を使用して、パラメーターを期待する型に強制し、実装に渡します。戻り値を設定して戻ります。終わり。

難しい方法は、ITypeInfo などを使用することです。私はそれをしたことはありませんし、するつもりもありません。ATL は簡単なので、ATL を使用するだけです。

難しい道を選ぶなら、頑張ってください。

于 2013-10-08T16:46:37.960 に答える
5

インターフェイスが IDL で適切に定義され、タイプ ライブラリにコンパイルされている場合、タイプ ライブラリIDispatchを介した実装は、ITypeInfoほとんどが委譲であるため、非常に実行可能です。興味深いのITypeInfo::Invokeは、正しい C++ v-table レイアウトに依存する部分です。

public class CComClass: public IDualInterface
{
    // ...

    // implementing IDualInterface

    ITypeInfo* m_pTypeInfo // can be obtained via ITypeLib::GetTypeInfoOfGuid for the GUID of IDualInterface

    // IDispatch
    STDMETHODIMP GetTypeInfoCount(UINT* pctinfo)
    {
        *pctinfo = 1;
        return S_OK;
    }

    STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
    {
        if (0 != itinfo)
            return E_INVALIDARG;
        (*pptinfo = m_pTypeInfo)->AddRef();
        return S_OK;
    }

    STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
    {
        return m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
    }

    STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
    {
        return m_pTypeInfo->Invoke(static_cast<IDualInterface*>(this), dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); 
    }
}

同様のアプローチを使用して、MSHTML DOM オブジェクトのスクリプト呼び出し可能なラッパーを作成し、スクリプトのセキュリティ制限を回避しました。

では、ITypeInfo はどこから取得するのでしょうか。基本的に、次の方法で取得します。

  1. インターフェイスをデュアルインターフェイスとして宣言する IDL ファイルを記述します。C++ にはリフレクションITypeInfoがなく、言語に中立であるため、クラスで C++ 関数を直接呼び出すことはできません。したがってInvoke、タイプ ライブラリで宣言されている別のメソッドへの呼び出しのみを委任できます。
  2. ビルド プロセスの一部として、IDL をヘッダー ファイルとタイプ ライブラリにコンパイルします。
  3. IDL から生成されたヘッダー ファイルは、実装クラスが継承する必要があるインターフェイスを定義します。すべてのメソッドを実装したら、準備完了です。(開発の場合は、それらをすべて返すことから始めて、E_NOTIMPLそれらを 1 つずつ実装します)
  4. タイプ ライブラリをインストール先ディレクトリにインストールするか、EXE/DLL のリソースとしてインストールします。を呼び出して登録する必要がありますRegisterTypeLib。リソースとして埋め込まれている場合は、DllRegisterServer実装からこれを呼び出す必要があります。
  5. を使用して、オブジェクトの最初のインスタンスが作成されたときにタイプ ライブラリを読み込みますLoadTypeLib。これにより、ITypeLib
  6. を使用して必要な ITypeInfo を取得しますGetTypeInfoOfGuid
于 2013-10-08T22:13:24.340 に答える
3

できることは、Type Libraryを使用することです。

持っている場合、それはあなたがする必要のないことの1つです。持っていない場合は、MIDL コンパイラを使用して作成できます。これは、プラットフォーム SDK に付属する無料のツールです。もちろん、この場合、IDL ファイルを作成する必要があることを意味します (これは大変な作業になる可能性がありますが、必要なものを定義するだけで済みます)。対象とする COM オブジェクトの種類によっては、SDK で IDL ファイルが既に利用できる場合があります。IDL の準備ができたら、それをコンパイルしてTLB ファイルを取得できます

その TLB ファイルを取得したら、LoadTypeLib 関数を使用してロードできます。ITypeLib参照を取得したら、必要な ITypeInfo をロードし(複数ある場合があります)、基本的に IDispatch 呼び出し (GetIDsOfNames など) を ITypeInfo 実装呼び出しにルーティングできます。これらは非常に似ているためです。

于 2013-10-08T17:19:13.543 に答える