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 屬性指定 DISPID , HIWORD 因為其所定義之類別的公開的屬性,CDisp3DPoint。 因為 x 和 y 屬性會定義在基底類別中, HIWORD 的的 DISPID 為 1,因為這些屬性定義之類別是一個衍生自最高衍生類別的範圍。
注意事項 |
---|
LOWORD 一律由的位置在地圖上,即使有明確的對應中的項目的 DISPID (請參閱有關資訊的下一個章節 _ID 新版程式碼DISP_PROPERTY和DISP_FUNCTION巨集)。 |
進階的 MFC 分派對應的功能
有許多本版本的 Visual C++ 類別精靈不支援的其他功能。 類別精靈支援DISP_FUNCTION, DISP_PROPERTY,以及DISP_PROPERTY_EX而定義的方法、 成員變數的屬性,並取得或設定成員函式的屬性,分別。 這些功能通常是足以用來建立大部分的自動化伺服器。
類別精靈支援巨集並不足夠時,就可以使用下列額外的巨集: DISP_PROPERTY_NOTIFY,以及DISP_PROPERTY_PARAM。
DISP_PROPERTY_NOTIFY--巨集說明
DISP_PROPERTY_NOTIFY(
theClass,
pszName,
memberName,
pfnAfterSet,
vtPropType
)
備註
參數
theClass
類別的名稱。pszName
外部屬性的名稱。memberName
屬性儲存的成員變數的名稱。pfnAfterSet
當屬性變更時要呼叫成員函式的名稱。vtPropType
值,指定屬性的型別。
備註
此巨集十分類似DISP_PROPERTY,不同之處在於它所接受的額外引數。 額外的引數, pfnAfterSet, 應該就會傳 nothing 並不採用任何參數 'void OnPropertyNotify()' 的成員函式。 將會呼叫之後成員變數已被修改。
DISP_PROPERTY_PARAM--巨集說明
DISP_PROPERTY_PARAM(
theClass,
pszName,
pfnGet,
pfnSet,
vtPropType,
vtsParams
)
備註
參數
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
)
備註
參數
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 集合)。
正在擷取 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解構函式的運作方式是預設值)。