共用方式為


TN039: MFC/OLE 自動化實作

注意事項注意事項

由於它第一次線上文件中包含尚未更新下列技術提示。如此一來,某些程序和主題可能已經過期或不正確。如需最新資訊,建議您先搜尋線上文件索引中有興趣的主題。

OLE IDispatch 介面的概觀

IDispatch介面是應用程式公開方法與屬性,例如可讓其他的應用程式,例如 Visual BASIC 中或其他語言中,使用的應用程式的功能所用的方法。 這個介面中的最重要的一部分是 IDispatch::Invoke 函式。 MFC 會使用"分派對應] 來實作 IDispatch::Invoke。 分派對應的版面配置及 「 形狀 」 提供 MFC 實作有關您CCmdTarget-衍生的類別,如此可以直接操作物件的內容,或呼叫成員函式,以滿足您的物件內 IDispatch::Invoke 的要求。

大多數的情況下,類別精靈] 和 [MFC 互相合作隱藏多數的 OLE 自動化,從應用程式設計者的詳細資料。 程式設計人員專注於實際的功能,以公開 (expose) 應用程式中,而且不需要擔心基礎配管。

有些情形下,不過,就必須了解 MFC 會在幕後執行哪些動作。 這張便箋解決架構方式分派的 DISPIDs 轉換成成員函式和屬性。 MFC 用來指派之演算法的知識的 DISPIDs 時,才需要當您需要知道 Id,例如,當您建立 「 型別程式庫 」 應用程式的物件。

MFC 的 DISPID 指派

自動化儘管的自動化 (Visual Basic 使用者,例如),一般使用者所看到的實際名稱啟用它們 (例如物件的程式碼中屬性及方法顯示) 的實作 IDispatch::Invoke 不會收到的實際名稱。 基於最佳化因素,它會收到的 DISPID,也就是 32 位元 「 神奇 cookie 」 所描述的方法或屬性的存取。 這些的 DISPID 會傳回值,從IDispatch透過呼叫另一個方法的實作 IDispatch::GetIDsOfNames。 自動化用戶端應用程式會呼叫GetIDsOfNames想要存取及快取這些後續呼叫若要針對每個成員或屬性一旦 IDispatch::Invoke。 如此一來,昂貴的字串查閱才會這麼做一次每次物件使用,而不是一次每個 IDispatch::Invoke 呼叫。

MFC 會決定的 DISPIDs 為每個方法和屬性會根據下列兩件事:

  • 分派對應 (1 相對的) 的頂端之間的距離

  • 分派對應,從最高衍生類別 (相對的 0) 的距離

的 DISPID 分成兩部分。 LOWORD的 DISPID 包含第一個元件,也就是分派對應的頂端之間的距離。 HIWORD 包含最高衍生類別之間的距離。 例如:

class CDispPoint : public CCmdTarget
{
public:
    short m_x, m_y;
    ...
    DECLARE_DISPATCH_MAP()
    ...
};

class CDisp3DPoint : public CDispPoint
{
public:
    short m_z;
    ...
    DECLARE_DISPATCH_MAP()
    ...
};

BEGIN_DISPATCH_MAP(CDispPoint, CCmdTarget)
    DISP_PROPERTY(CDispPoint, "x", m_x, VT_I2)
    DISP_PROPERTY(CDispPoint, "y", m_y, VT_I2)
END_DISPATCH_MAP()

BEGIN_DISPATCH_MAP(CDisp3DPoint, CDispPoint)
    DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
END_DISPATCH_MAP()

如您所見,有兩個類別,這兩種 OLE 自動化介面公開 (expose)。 其中一個類別衍生自另,因此會使用基底類別的功能,包括 [OLE 自動化組件 ("x"和"y"在此案例的屬性)。

MFC 會產生的 DISPIDs 的類別 CDispPoint,如下所示:

property X    (DISPID)0x00000001
property Y    (DISPID)0x00000002

因為屬性不是在基底類別中, HIWORD的 DISPID 永遠都是的零 (CDispPoint 的最高衍生類別之間的距離為零)。

MFC 會產生的 DISPIDs 的類別 CDisp3DPoint,如下所示:

property Z    (DISPID)0x00000001
property X    (DISPID)0x00010001
property Y    (DISPID)0x00010002

Z 屬性指定 DISPIDHIWORD 因為其所定義之類別的公開的屬性,CDisp3DPoint。 因為 x 和 y 屬性會定義在基底類別中, HIWORD的 DISPID 為 1,因為這些屬性定義之類別是一個衍生自最高衍生類別的範圍。

注意事項注意事項

LOWORD 一律由的位置在地圖上,即使有明確的對應中的項目的 DISPID (請參閱有關資訊的下一個章節 _ID 新版程式碼DISP_PROPERTYDISP_FUNCTION巨集)。

進階的 MFC 分派對應的功能

有許多本版本的 Visual C++ 類別精靈不支援的其他功能。 類別精靈支援DISP_FUNCTIONDISP_PROPERTY,以及DISP_PROPERTY_EX而定義的方法、 成員變數的屬性,並取得或設定成員函式的屬性,分別。 這些功能通常是足以用來建立大部分的自動化伺服器。

類別精靈支援巨集並不足夠時,就可以使用下列額外的巨集: DISP_PROPERTY_NOTIFY,以及DISP_PROPERTY_PARAM

DISP_PROPERTY_NOTIFY--巨集說明

DISP_PROPERTY_NOTIFY( 
   theClass, 
   pszName, 
   memberName, 
   pfnAfterSet, 
   vtPropType 
)

備註

w7a36sdf.collapse_all(zh-tw,VS.110).gif參數

  • theClass
    類別的名稱。

  • pszName
    外部屬性的名稱。

  • memberName
    屬性儲存的成員變數的名稱。

  • pfnAfterSet
    當屬性變更時要呼叫成員函式的名稱。

  • vtPropType
    值,指定屬性的型別。

備註

此巨集十分類似DISP_PROPERTY,不同之處在於它所接受的額外引數。 額外的引數, pfnAfterSet, 應該就會傳 nothing 並不採用任何參數 'void OnPropertyNotify()' 的成員函式。 將會呼叫之後成員變數已被修改。

DISP_PROPERTY_PARAM--巨集說明

DISP_PROPERTY_PARAM( 
   theClass,
   pszName,
   pfnGet,
   pfnSet,
   vtPropType,
   vtsParams 
)

備註

w7a36sdf.collapse_all(zh-tw,VS.110).gif參數

  • theClass
    類別的名稱。

  • pszName
    外部屬性的名稱。

  • memberGet
    用來取得其屬性的成員函式的名稱。

  • memberSet
    用來設定屬性的成員函式的名稱。

  • vtPropType
    值,指定屬性的型別。

  • vtsParams
    空間的字串分隔為每個參數的 VTS_。

備註

就像是DISP_PROPERTY_EX巨集],此巨集會定義使用個別的 Get 和 Set 成員函式存取的屬性。 不過,這個巨集,可讓您指定屬性的參數清單。 這適用於以其他方法實作會編製索引或參數化的屬性。 參數會放置在第一次,後面接著屬性的新值。 例如:

DISP_PROPERTY_PARAM(CMyObject, "item", GetItem, SetItem, VT_DISPATCH,    VTS_I2 VTS_I2)

相當於 get 和 set 成員函式:

LPDISPATCH CMyObject::GetItem(short row, short col)
void CMyObject::SetItem(short row, short col, LPDISPATCH newValue)

DISP_XXXX_ID--巨集說明

DISP_FUNCTION_ID( 
   theClass,
   pszName,
   dispid,
   pfnMember,
   vtRetVal,
   vtsParams 
)
DISP_PROPERTY_ID( 
   theClass,
   pszName,
   dispid,
   memberName,
   vtPropType 
)
DISP_PROPERTY_NOTIFY_ID( 
   theClass,
   pszName,
   dispid,
   memberName,
   pfnAfterSet,
   vtPropType 
)
DISP_PROPERTY_EX_ID( 
   theClass,
   pszName,
   dispid,
   pfnGet,
   pfnSet,
   vtPropType 
)
DISP_PROPERTY_PARAM_ID( 
   theClass,
   pszName,
   dispid,
   pfnGet,
   pfnSet,
   vtPropType,
   vtsParams 
)

備註

w7a36sdf.collapse_all(zh-tw,VS.110).gif參數

  • theClass
    類別的名稱。

  • pszName
    外部屬性的名稱。

  • dispid
    屬性或方法固定的 DISPID。

  • pfnGet
    用來取得其屬性的成員函式的名稱。

  • pfnSet
    用來設定屬性的成員函式的名稱。

  • memberName
    若要對應至屬性的成員變數的名稱

  • vtPropType
    值,指定屬性的型別。

  • vtsParams
    空間的字串分隔為每個參數的 VTS_。

備註

這些巨集可讓您指定的 DISPID 而不是讓 MFC 會自動指派其中一個。 這些進階巨集具有相同的名稱,但該 ID 是巨集名稱加上 (例如: DISP_PROPERTY_ID) ID 由只在指定的參數,並pszName參數。 請參閱 AFXDISP。如需有關這些巨集的 H。 _ID 項目必須放在分派對應的結尾。 它們會影響自動 DISPID 產生相同的方式為非-_ID 巨集的版本嗎 ( 的 DISPIDs 取決於位置)。 例如:

BEGIN_DISPATCH_MAP(CDisp3DPoint, CCmdTarget)
    DISP_PROPERTY(CDisp3DPoint, "y", m_y, VT_I2)
    DISP_PROPERTY(CDisp3DPoint, "z", m_z, VT_I2)
    DISP_PROPERTY_ID(CDisp3DPoint, "x", 0x00020003, m_x, VT_I2)
END_DISPATCH_MAP()

MFC 會產生 Dispid CDisp3DPoint 類別,如下所示:

property X    (DISPID)0x00020003
property Y    (DISPID)0x00000002
property Z     (DISPID)0x00000001

指定固定的 DISPID 有助於維護先前已存在的分派介面,為符合回溯相容性,或實作特定的系統定義的方法或屬性 (通常是由負數表示的 DISPID,例如 DISPID_NEWENUM 集合)。

w7a36sdf.collapse_all(zh-tw,VS.110).gif正在擷取 COleClientItem IDispatch 介面

多伺服器將支援自動化它們一起 OLE 伺服器功能的文件物件內。 若要存取這個自動化介面,則必須直接存取 COleClientItem::m_lpObject 成員變數。 下列程式碼會擷取IDispatch介面的物件衍生自COleClientItem。 如果您發現這項功能所需,您可以在應用程式中包含下列程式碼:

LPDISPATCH CMyClientItem::GetIDispatch()
{
    ASSERT_VALID(this);
    ASSERT(m_lpObject != NULL);

    LPUNKNOWN lpUnk = m_lpObject;

    Run();    // must be running

    LPOLELINK lpOleLink = NULL;
    if (m_lpObject->QueryInterface(IID_IOleLink, 
        (LPVOID FAR*)&lpOleLink) == NOERROR)
    {
        ASSERT(lpOleLink != NULL);
        lpUnk = NULL;
        if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR)
        {
            TRACE0("Warning: Link is not connected!\n");
            lpOleLink->Release();
            return NULL;
        }
        ASSERT(lpUnk != NULL);
    }

    LPDISPATCH lpDispatch = NULL;
    if (lpUnk->QueryInterface(IID_IDispatch, &lpDispatch) 
        != NOERROR)
    {
        TRACE0("Warning: does not support IDispatch!\n");
        return NULL;
    }

    ASSERT(lpDispatch != NULL);
    return lpDispatch;
}

從傳回的分派介面這項功能無法再直接使用或附加至COleDispatchDriver為型別安全存取。 如果您直接使用它,請確定您呼叫其發行成員何時透過指標 ( COleDispatchDriver解構函式的運作方式是預設值)。

請參閱

其他資源

技術的備忘稿編號

依類別的技術注意事項