TN039: MFC/OLE – implementace automatizace
Poznámka
Následující technická poznámka se od prvního zahrnutí do online dokumentace neaktualizovala. V důsledku toho můžou být některé postupy a témata zastaralé nebo nesprávné. Nejnovější informace doporučujeme vyhledat v online indexu dokumentace, které vás zajímá.
Přehled rozhraní OLE IDispatch
Rozhraní IDispatch
je způsob, jakým aplikace zpřístupňují metody a vlastnosti, jako jsou jiné aplikace, jako je Visual BASIC nebo jiné jazyky, mohou využívat funkce aplikace. Nejdůležitější součástí tohoto rozhraní je IDispatch::Invoke
funkce. MFC používá k implementaci IDispatch::Invoke
"dispatch maps" . Mapa odeslání poskytuje informace o implementaci MFC v rozložení nebo "tvaru" vašich CCmdTarget
-odvozených tříd, aby mohl přímo manipulovat s vlastnostmi objektu nebo volat členské funkce v rámci objektu, aby uspokojily IDispatch::Invoke
požadavky.
Ve většině případů spolupracuje ClassWizard a MFC na skrytí většiny podrobností automatizace OLE od programátora aplikace. Programátor se soustředí na skutečnou funkčnost, aby se v aplikaci zpřístupnil a nemusí se starat o základní instalatérské prostředí.
Existují však případy, kdy je nutné pochopit, co mfc dělá na pozadí. Tato poznámka se bude zabývat tím, jak architektura přiřazuje IDENTIFIKÁTORy DISPIDk členským funkcím a vlastnostem. Znalost algoritmu, který mfc používá k přiřazování identifikátorů DISPID, je nutná pouze v případě, že potřebujete znát ID, například při vytváření "knihovny typů" pro objekty vaší aplikace.
MFC DISPID – přiřazení
I když koncový uživatel automatizace (například uživatel jazyka Visual Basic), uvidí ve svém kódu skutečné názvy povolených vlastností a metod automatizace (například obj. ShowWindow), implementace IDispatch::Invoke
neobdrží skutečné názvy. Z důvodů optimalizace obdrží IDENTIFIKÁTOR DISPID, což je 32bitová "magic cookie", která popisuje metodu nebo vlastnost, ke které se má přistupovat. Tyto hodnoty DISPID jsou vráceny z IDispatch
implementace prostřednictvím jiné metody, která se nazývá IDispatch::GetIDsOfNames
. Klientská aplikace automatizace bude volat GetIDsOfNames
jednou pro každého člena nebo vlastnost, ke které hodlá přistupovat, a uložit je do mezipaměti pro pozdější volání IDispatch::Invoke
. Tímto způsobem se nákladné vyhledávání řetězců provádí pouze jednou za použití objektu, nikoli jednou za IDispatch::Invoke
volání.
MFC určuje identifikátory DISPIDpro každou metodu a vlastnost na základě dvou věcí:
Vzdálenost od horní části mapy dispečera (1 relativní)
Vzdálenost mapy odeslání od nejvíce odvozené třídy (0 relativní)
DISPID je rozdělený na dvě části. LOWORD dispid obsahuje první komponentu, vzdálenost od horní části mapy dispečeru. HIWORD obsahuje vzdálenost od nejvíce odvozené třídy. Příklad:
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()
Jak vidíte, existují dvě třídy, z nichž obě zpřístupňují automatizační rozhraní OLE. Jedna z těchto tříd je odvozena od druhé, a proto využívá funkce základní třídy, včetně části automatizace OLE ("x" a "y" vlastnosti v tomto případě).
MFC vygeneruje DISPIDpro třídu CDispPoint následujícím způsobem:
property X (DISPID)0x00000001
property Y (DISPID)0x00000002
Vzhledem k tomu, že vlastnosti nejsou v základní třídě, HIWORD dispID je vždy nula (vzdálenost od nejvíce odvozené třídy pro CDispPoint je nula).
MFC vygeneruje DISPIDs pro třídu CDisp3DPoint následujícím způsobem:
property Z (DISPID)0x00000001
property X (DISPID)0x00010001
property Y (DISPID)0x00010002
Vlastnost Z má hodnotu DISPID s nulovou hodnotou HIWORD , protože je definována ve třídě, která zobrazuje vlastnosti CDisp3DPoint. Vzhledem k tomu, X a Y vlastnosti jsou definovány v základní třídě, HIWORD DISPID je 1, protože třída, ve které jsou tyto vlastnosti definovány, je na vzdálenost od jedné odvozené třídy.
Poznámka
LOWORD je vždy určeno umístěním v mapě, i když v mapě existují položky s explicitním DISPID (informace o _ID verzích DISP_PROPERTY
a DISP_FUNCTION
makrech najdete v další části).
Pokročilé funkce mapy dispečerské knihovny MFC
Existuje řada dalších funkcí, které ClassWizard v této verzi jazyka Visual C++ nepodporuje. ClassWizard podporuje DISP_FUNCTION
, DISP_PROPERTY
a DISP_PROPERTY_EX
které definují metodu, vlastnost členské proměnné a get/set členské funkce vlastnost, v uvedeném pořadí. Tyto funkce jsou obvykle potřeba k vytvoření většiny automatizačních serverů.
Následující další makra lze použít v případě, že podporovaná makra ClassWizard nejsou adekvátní: DISP_PROPERTY_NOTIFY
a DISP_PROPERTY_PARAM
.
DISP_PROPERTY_NOTIFY – popis makra
DISP_PROPERTY_NOTIFY(
theClass,
pszName,
memberName,
pfnAfterSet,
vtPropType)
Parametry
theClass
Název třídy.
pszName
Externí název vlastnosti.
memberName
Název členské proměnné, ve které je vlastnost uložena.
pfnAfterSet
Název členské funkce, která se má volat při změně vlastnosti.
vtPropType
Hodnota určující typ vlastnosti.
Poznámky
Toto makro se podobá DISP_PROPERTY s tím rozdílem, že přijímá další argument. Další argument pfnAfterSet by měl být členská funkce, která vrací nic a nepřijímá žádné parametry, 'void OnPropertyNotify()'. Bude volána po změně členské proměnné.
DISP_PROPERTY_PARAM – popis makra
DISP_PROPERTY_PARAM(
theClass,
pszName,
pfnGet,
pfnSet,
vtPropType,
vtsParams)
Parametry
theClass
Název třídy.
pszName
Externí název vlastnosti.
memberGet
Název členské funkce použité k získání vlastnosti.
Memberset
Název členské funkce použité k nastavení vlastnosti.
vtPropType
Hodnota určující typ vlastnosti.
vtsParams
Řetězec mezery oddělené VTS_ pro každý parametr.
Poznámky
Podobně jako DISP_PROPERTY_EX makro definuje toto makro vlastnost, ke které se přistupuje pomocí samostatných funkcí Get a Set. Toto makro však umožňuje zadat seznam parametrů pro vlastnost. To je užitečné pro implementaci vlastností, které jsou indexovány nebo parametrizovány jiným způsobem. Parametry budou vždy umístěny jako první, následované novou hodnotou vlastnosti. Příklad:
DISP_PROPERTY_PARAM(CMyObject, "item", GetItem, SetItem, VT_DISPATCH, VTS_I2 VTS_I2)
by odpovídalo získání a nastavení členských funkcí:
LPDISPATCH CMyObject::GetItem(short row, short col)
void CMyObject::SetItem(short row, short col, LPDISPATCH newValue)
DISP_XXXX_ID – popisy maker
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)
Parametry
theClass
Název třídy.
pszName
Externí název vlastnosti.
Dispid
Pevný IDENTIFIKÁTOR DISPID pro vlastnost nebo metodu.
pfnGet
Název členské funkce použité k získání vlastnosti.
pfnSet
Název členské funkce použité k nastavení vlastnosti.
memberName
Název členské proměnné, která se má mapovat na vlastnost
vtPropType
Hodnota určující typ vlastnosti.
vtsParams
Řetězec mezery oddělené VTS_ pro každý parametr.
Poznámky
Tato makra umožňují místo automatického přiřazení identifikátoru DISPID určit IDENTIFIKÁTOR DISPID . Tato pokročilá makra mají stejné názvy s tím rozdílem, že ID je připojeno k názvu makra (např. DISP_PROPERTY_ID) a ID je určeno parametrem zadaným hned za parametrem pszName . Viz AFXDISP. Další informace o těchto makrech najdete v H. Položky _ID musí být umístěny na konci mapy odeslání. Ovlivní automatické generování DISPID stejným způsobem jako verze makra, která není _ID (DISPID jsou určeny podle pozice). Příklad:
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 vygeneruje identifikátory DISPID pro třídu CDisp3DPoint následujícím způsobem:
property X (DISPID)0x00020003
property Y (DISPID)0x00000002
property Z (DISPID)0x00000001
Zadání pevného DISPID je užitečné k zachování zpětné kompatibility s dříve existujícím rozhraním dispečera nebo k implementaci určitých systémově definovaných metod nebo vlastností (obvykle označených záporným identifikátorem DISPID, jako je například kolekce DISPID_NEWENUM).
Načtení rozhraní IDispatch pro COleClientItem
Mnoho serverů bude podporovat automatizaci v rámci svých objektů dokumentů spolu s funkcemi serveru OLE. Aby bylo možné získat přístup k tomuto rozhraní automatizace, je nutné přímo přistupovat k COleClientItem::m_lpObject
členské proměnné. Následující kód načte IDispatch
rozhraní pro objekt odvozený z COleClientItem
. Pokud zjistíte, že je tato funkce nezbytná, můžete do své aplikace zahrnout následující kód:
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;
}
Rozhraní dispečera vrácené z této funkce by se pak mohlo použít přímo nebo připojit k COleDispatchDriver
typu bezpečnému přístupu. Pokud ho použijete přímo, ujistěte se, že při použití ukazatele zavoláte jeho Release
člena ( COleDispatchDriver
destruktor to dělá ve výchozím nastavení).
Viz také
Technické poznámky podle čísel
Technické poznámky podle kategorií