テクニカル ノート 65: OLE オートメーション サーバー デュアル インターフェイス サポート

このノートでは、MFC ベースの OLE オートメーション サーバー アプリケーションにデュアル インターフェイス サポートを追加する方法について説明します。 ACDUALサンプルにデュアル インターフェイス サポートを示していて、このコード例は ACDUAL からとられています。このノートでは、ようマクロ DECLARE_DUAL_ERRORINFODUAL_ERRORINFO_PART 、および IMPLEMENT_DUAL_ERRORINFO 、ACDUAL のサンプルの一部であるし、MFCDUAL で見つけることができます。H。

デュアル インターフェイス

OLE オートメーションIDispatchインターフェイス、VTBL インターフェイス、または (両方を包含する) は、デュアル インターフェイスを実装することができますが、Microsoft は強く露出のすべての OLE オートメーション オブジェクトに対してデュアル インターフェイスを実装することを推奨します。デュアル インターフェイスのIDispatchの重要な利点がある-唯一のまたは VTBL のみのインターフェイス:

CCmdTarget に基づいたクラスへのデュアル インターフェイス サポートを追加

デュアル インターフェイスはIDispatchから派生したカスタム インターフェイスは本当にだけです。CCmdTargetにデュアル インターフェイス サポートを実装する最も簡単な方法-ベース クラスは通常のディスパッチ インターフェイスの MFC と ClassWizard を使用して、クラスにし、カスタム インターフェイスを後で追加の最初の実装をします。ほとんどの部分については、カスタム インターフェイスの実装は単に、MFC のIDispatch実装に戻る委任します。

最初に、オブジェクトはデュアル インターフェイスを定義するのには、サーバー用の ODL ファイルを変更します。デュアル インターフェイスを定義するのには、インターフェイス ステートメントの代わりに使用する必要があります、 DISPINTERFACE 、Visual C のウィザードを生成するステートメント。既存を削除するのではなく DISPINTERFACE ステートメントは、新しいインターフェイス ステートメントを追加します。保持によって、 DISPINTERFACE 、できますフォーム、引き続き ClassWizard を使用してプロパティとメソッドをオブジェクトに追加するには、同等のプロパティ、メソッド、インターフェイス ステートメントを追加する必要があります。

Ole オートメーションデュアル属性、インターフェイス ステートメントは、デュアル インターフェイスの必要があり、インターフェイスはIDispatchから派生する必要があります。使用して、 、デュアル インターフェイスのIIDを作成するには、 GUIDGENサンプル

[uuid(0BDD0E81-0DD7-11cf-BBA8-444553540000)、・ ・ IID_IDualAClick特価;ole オートメーション、デュアル]IDualAClick インタ フェース: IDispatch{}(&N)

場所で、インターフェイス ステートメントとは、メソッドとプロパティのエントリを追加を開始します。デュアル インターフェイスは、プロパティ アクセサー関数はデュアル インターフェイスで、メソッドがHRESULTを返すし、戻り値、属性をパラメーターとして渡すパラメーターの一覧に配置する必要があります [retval,out] 。プロパティの両方を追加する必要があります覚えて ( propget ) と書き込み ( propput )、同じ id を持つ関数にアクセスします。たとえば:

[propput、id(1)]HRESULT テキスト ([in] BSTR newText);propget [id(1)]HRESULT テキスト ([out, retval] BSTR ※ retval)

メソッドとプロパティを定義したら、コクラス ステートメントでインターフェイス ステートメントへの参照を追加する必要があります。たとえば:

[uuid(4B115281-32F0-11cf-AC85-444553540000)]コクラス ドキュメント{特価;ディスパッチ インターフェイス IAClick;[既定] のインターフェイス IDualAClick;}(&N)

ODL ファイルを更新すると、MFC のインターフェイス マップ機構を使用してデュアル インターフェイス用実装クラス、オブジェクト クラスの定義し、MFC のQueryInterface機構内の対応するエントリを確認します。1 つのエントリ必要があります、 INTERFACE_PART 、ODL のインターフェイス ステートメント内の各エントリ エントリに加え、ディスパッチ インターフェイスのブロック。各 ODL エントリpropput属性を持つ必要があるという名前の関数 put_propertyname 。各エントリpropget属性を持つ必要があるという名前の関数get_propertyname

デュアル インターフェイス用実装クラスを定義するには、追加、 DUAL_INTERFACE_PART ブロックをオブジェクトのクラス定義に。たとえば:

BEGIN_DUAL_INTERFACE_PART (DualAClick, IDualAClick)STDMETHOD(put_text) (THIS_ BSTR newText);STDMETHOD(get_text) (THIS_ BSTR まで ※ retval);STDMETHOD(put_x) (THIS_ 短い newX);STDMETHOD(get_x) (retval THIS_ 短いまで ※);STDMETHOD(put_y) (THIS_ 短い newY);STDMETHOD(get_y) (retval THIS_ 短いまで ※);STDMETHOD(put_Position) (THIS_ IDualAutoClickPoint まで ※ newPosition);STDMETHOD(get_Position) (THIS_ IDualAutoClickPoint まで ※ まで ※ retval);STDMETHOD(RefreshWindow)(THIS);STDMETHOD(SetAllProps) (THIS_ ショート x、短い y、BSTR 本文);STDMETHOD(ShowWindow)(THIS);END_DUAL_INTERFACE_PART(DualAClick)

MFC のデュアル インターフェイスを接続する の QueryInterface機構、追加、 INTERFACE_PART エントリのインターフェイス マップに

BEGIN_INTERFACE_MAP (CAutoClickDoc、CDocument)INTERFACE_PART (CAutoClickDoc、DIID_IAClick、ディスパッチ)INTERFACE_PART (CAutoClickDoc、IID_IDualAClick、DualAClick)END_INTERFACE_MAP()

次に、インターフェイスの実装では、入力する必要があります。ほとんどの部分については、既存の MFC のIDispatchの実装に委任できます。たとえば:

STDMETHODIMP_(ULONG) CAutoClickDoc::XDualAClick::AddRef()
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) CAutoClickDoc::XDualAClick::Release()
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   return pThis->ExternalRelease();
}
STDMETHODIMP CAutoClickDoc::XDualAClick::QueryInterface(
             REFIID iid, LPVOID* ppvObj)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   return pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetTypeInfoCount(
            UINT FAR* pctinfo)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
   ASSERT(lpDispatch != NULL);
   return lpDispatch->GetTypeInfoCount(pctinfo);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetTypeInfo(
          UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
   ASSERT(lpDispatch != NULL);
   return lpDispatch->GetTypeInfo(itinfo, lcid, pptinfo);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::GetIDsOfNames(
       REFIID riid, OLECHAR FAR* FAR* rgszNames, UINT cNames,
       LCID lcid, DISPID FAR* rgdispid) 
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
   ASSERT(lpDispatch != NULL);
   return lpDispatch->GetIDsOfNames(riid, rgszNames, cNames, 
                                    lcid, rgdispid);
}
STDMETHODIMP CAutoClickDoc::XDualAClick::Invoke(
    DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
    DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult,
    EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr)
{
   METHOD_PROLOGUE(CAutoClickDoc, DualAClick)
   LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE);
   ASSERT(lpDispatch != NULL);
   return lpDispatch->Invoke(dispidMember, riid, lcid,
                             wFlags, pdispparams, pvarResult,
                             pexcepinfo, puArgErr);
}

オブジェクトのメソッド、プロパティ アクセサー関数を実装する必要があります。あなたのメソッドとプロパティの機能は、一般的に ClassWizard を使用して生成したメソッドに委任できます。ただし、プロパティを変数に直接アクセスする場合は、値を変数に取得するコードを記述する必要があります。たとえば:

STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText){特価;METHOD_PROLOGUE (CAutoClickDoc, DualAClick)//MFC を自動的に変換 Unicode BSTR から・ ・ Ansi CString、必要に応じて.pThis - > m_str newText; =NOERROR を返す;}STDMETHODIMP CAutoClickDoc::XDualAClick::get_text(BSTR* retval){METHOD_PROLOGUE (CAutoClickDoc, DualAClick)//MFC を自動的に変換する Ansi CString から//Unicode BSTR、必要に応じて.pThis - > m_str。SetSysString(retval);NOERROR を返す;}

デュアル インターフェイスのポインターを渡します

デュアル インターフェイス ポインターを渡すは特にCCmdTarget::FromIDispatchを呼び出す必要がある場合に、簡単ではありません。FromIDispatchは、MFC のIDispatchポインターにのみ動作します。この問題を回避する 1 つの方法は、元のIDispatchポインター セット MFC でし、ポインターが必要な関数に渡すをクエリします。たとえば

 STDMETHODIMP CAutoClickDoc::XDualAClick::put_Position (特価;IDualAutoClickPoint まで ※ newPosition){METHOD_PROLOGUE (CAutoClickDoc, DualAClick)LPDISPATCH lpDisp = NULL;newPosition - > QueryInterface (IID_IDispatch、(LPVOID ※) & lpDisp);pThis - > SetPosition(lpDisp);lpDisp - > Release();NOERROR を返す;}

デュアル インターフェイス メソッドから戻るポインターを渡す前に、MFC のIDispatchポインターからデュアル インターフェイス ポインターに変換する必要があります。たとえば:

STDMETHODIMP CAutoClickDoc::XDualAClick::get_Position (特価;IDualAutoClickPoint まで ※ まで ※ retval){METHOD_PROLOGUE (CAutoClickDoc, DualAClick)LPDISPATCH lpDisp;lpDisp = pThis - > GetPosition();lpDisp - > QueryInterface (IID_IDualAutoClickPoint、(LPVOID ※) retval);NOERROR を返す;}

アプリケーションのタイプ ライブラリの登録

AppWizard では、OLE オートメーション サーバー アプリケーションのタイプ ライブラリをシステムに登録するコードは生成されません。タイプ ライブラリを登録する他の方法がありますが、スタンドアロン アプリケーションを実行するたびに、その OLE の種類の情報は、更新しているときに、タイプ ライブラリを登録アプリケーションに便利です。

アプリケーションがスタンドアロンで実行されるたびに、アプリケーションのタイプ ライブラリを登録するには:

タイプ ライブラリの変更に対応するプロジェクトのビルド設定を変更します。

UUID定義を含むヘッダー ファイルが生成されるように変更するには、プロジェクトのビルド設定 タイプ ライブラリが再構築されるたびにMkTypLib

  1. [ビルド] メニューの [から設定をクリックし、ファイルの一覧から ODL ファイルを選択。

  2. [OLE タイプ] タブをクリックし、[出力ヘッダー ファイル名] フィールドにファイル名を指定します。MkTypLib が既存のファイルを上書きするので、あなたのプロジェクトでは、まだ使用されていないファイル名を使用します。[ビルド設定] ダイアログ ボックスを閉じるには、[ok] をクリックします。

UUID定義から MkTypLib によって生成されたヘッダー ファイルをプロジェクトに追加するには:

  1. MkTypLib 生成が含まれます、標準のヘッダー ファイルには、ヘッダー ファイル、STDAFX が含まれています。H。

  2. 新しいファイル、INITIIDS を作成します。CPP、それをプロジェクトに追加します。このファイルには、OLE2 を含む後に、MkTypLib によって生成されたヘッダー ファイルが含まれます。H と INITGUID。H:
    //initIIDs.c: デュアル インターフェイスの Iid を定義します//このプリコンパイル済みヘッダーを構築する必要がありません。#include lt;ole2.h >#include <initguid.h>#include"acdual.h"
    
  3. ビルド] メニューの [設定] をクリックし、INITIIDS を選択します。CPP ファイル リストの各構成から。

  4. [C++] タブをクリックし、カテゴリ「プリコンパイル済みヘッダー」と選択"を使用していないヘッダー プリコンパイル」ラジオ ボタン。[ビルド設定] ダイアログ ボックスを閉じるには、[ok] をクリックします。

タイプ ライブラリに、正しいオブジェクト クラス名を指定します。

Visual C での出荷されていないウィザードでは、実装クラス名を使用してサーバーの ODL ファイル内の OLE createable クラス、コクラスを指定します。動作はしますが、実装クラス名を使用するユーザー オブジェクトのクラス名はありません。正しい名前を指定するには、ODL ファイルを開く各コクラス ステートメントを見つけます、実装クラス名を正しい外部名を置き換える。

Coclass ステートメントが変更されたときに、 CLSIDの MkTypLib によって生成されたヘッダー ファイルでの変数の名前に応じて変わります。新しい変数名を使用するようにコードを更新する必要があります。

例外とオートメーション エラー インターフェイスの処理

オートメーション オブジェクトのメソッドとプロパティ アクセサー関数例外をスロー可能性があります。場合は、それらは、デュアル インターフェイスの実装で処理し、OLE オートメーション エラー処理インターフェイスIErrorInfoを通じてコント ローラーに戻る、例外に関する情報を渡す必要があります。このインターフェイスは、 idispatch インターフェイスと VTBL インターフェイスを介しての詳細は、文脈上のエラー情報を提供します。エラー ハンドラーが利用可能であることを示すには、 ISupportErrorInfoインターフェイスを実装する必要があります。

エラー処理機構を説明するには、標準のディスパッチのサポートを実装するために使用、ClassWizard で生成された関数例外をスローすることを想定しています。MFC の実装idispatch::invokeは通常これらの例外をキャッチし、EXCEPTINFO には構造変換呼び出しを通じて返されます。ただし、VTBL インターフェイスを使用すると、例外をキャッチするの責任があります。たとえば、デュアル インターフェイスのメソッドを保護します。

STDMETHODIMP CAutoClickDoc::XDualAClick::put_text(BSTR newText){特価;METHOD_PROLOGUE (CAutoClickDoc, DualAClick)TRY_DUAL(IID_IDualAClick){//MFC を自動的に変換 Unicode BSTR から・ ・ Ansi CString、必要に応じて.pThis - > m_str newText; =NOERROR を返す;}CATCH_ALL_DUAL}

CATCH_ALL_DUAL例外が発生した場合、正しいエラー コードを返すの世話します。CATCH_ALL_DUALMFC 例外ICreateErrorInfoインターフェイスを使用して OLE オートメーション エラー処理情報に変換します。(例 CATCH_ALL_DUAL マクロは、ファイルに MFCDUAL。H で、 ACDUALサンプル。関数が例外を処理する呼び出し DualHandleException 、MFCDUAL ファイルであります。CPP。)CATCH_ALL_DUALに発生した例外の種類に基づいて返すエラー コードを指定します

OLE オートメーションのエラー ハンドラーを使用することを示すには、また、 ISupportErrorInfoインターフェイスを実装する必要があります。

まず、 ISupportErrorInfoサポートを表示するには、オートメーション クラス定義にコードを追加します。

第二に、コードは MFC のQueryInterface機構ISupportErrorInfo実装クラスを関連付けるには、オートメーション クラスのインターフェイス マップに追加します。INTERFACE_PARTステートメントISupportErrorInfoは定義クラスと一致します。

最後に、 ISupportErrorInfoをサポートするために定義されているクラスを実装します。

(、 ACDUALサンプルには、これら 3 つの手順を実行する 3 つのマクロが含まれている DECLARE_DUAL_ERRORINFODUAL_ERRORINFO_PART 、および IMPLEMENT_DUAL_ERRORINFO 、すべて MFCDUAL に含まれています。H.)

次の例は、 ISupportErrorInfoをサポートするために定義されたクラスを実装します。CAutoClickDocオートメーション クラスの名前を指定し、 IID_IDualAClick エラーのソース インターフェイスのIID OLE オートメーション エラー オブジェクトを介して報告されています。:

STDMETHODIMP_(ULONG) CAutoClickDoc::XSupportErrorInfo::AddRef() (特価;METHOD_PROLOGUE (CAutoClickDoc, SupportErrorInfo) pThis - 戻る > ExternalAddRef();} STDMETHODIMP_(ULONG) CAutoClickDoc::XSupportErrorInfo::Release() {METHOD_PROLOGUE (CAutoClickDoc、SupportErrorInfo) を返す pThis - > ExternalRelease();} STDMETHODIMP CAutoClickDoc::XSupportErrorInfo::QueryInterface (REFIID iid、LPVOID ※ ppvObj) {METHOD_PROLOGUE (CAutoClickDoc、SupportErrorInfo) を返す pThis - > ExternalQueryInterface (& iid、ppvObj);} STDMETHODIMP CAutoClickDoc::XSupportErrorInfo::InterfaceSupportsErrorInfo (REFIID iid) {METHOD_PROLOGUE (CAutoClickDoc、SupportErrorInfo) 戻り (iid IID_IDualAClick = =) か。S_OK: S_FALSE;}

番号順テクニカル ノート|nbsp;カテゴリ別テクニカル ノート(&N)

Index