TN038: Implementace IUnknown MFC/OLE
[!POZNÁMKA]
Následující technické poznámce nebyly aktualizovány od byla poprvé zahrnuta v dokumentaci online.Proto některé postupy a témata mohou být nesprávné nebo zastaralé.Nejnovější informace je vhodné vyhledat téma zájmu v dokumentaci online index.
Srdce OLE 2 je "OLE Component Object Model" nebo COM.COM definuje standard jak spolupracující objekty komunikovat mezi sebou.To zahrnuje podrobnosti o jaké "objekt" vypadá, včetně způsobu odeslání metody objektu.COM definuje základní třídy, ze které jsou odvozeny všechny třídy COM kompatibilní.Tato základní třída je IUnknown.Přestože IUnknown rozhraní je označována jako třídy jazyka C++, COM není specifický pro jakékoli jeden jazyk – lze implementovat v C, PASCAL nebo jiný jazyk podporující binární rozložení objektu COM.
OLE se týká všech tříd odvozených od IUnknown jako "rozhraní". To je důležité rozlišovat, od "rozhraní" jako IUnknown s ním nese žádné implementace.Pouze definuje protokol, kterým objekty komunikovat, nejsou specifické proveďte tyto implementace.Toto je přiměřené pro systém, který umožňuje maximální flexibilitu.Je úloha MFC a implementují výchozí chování pro programy MFC/C++.
Pochopit jeho MFC provádění IUnknown musíte nejprve porozumět, je toto rozhraní.Zjednodušené verze IUnknown je definována níže:
class IUnknown
{
public:
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj) = 0;
virtual ULONG AddRef() = 0;
virtual ULONG Release() = 0;
};
[!POZNÁMKA]
Podrobnosti určité nezbytné konvence volání, například __stdcall vynecháno pro tento obrázek.
AddRef a vydání funkce členů řízení správy paměti objektu.COM používá ke sledování objektů inventur schéma odkazu.Objekt se odkazuje nikdy přímo, stejně jako v jazyce C++.Objekty COM místo toho vždy odkazovat pomocí ukazatele.Uvolnit objekt po vlastníka s použitím objektu na vydání (jako protiklad k pomocí operátoru delete, jako by v tradiční objektu C++) se nazývá členské.Referenční počítání mechanismus umožňuje spravovat více odkazů do jednoho objektu.Implementace AddRef a vydání udržuje počet odkazů na objektu, objekt není odstraněn, dokud se jeho počet odkazů dosáhne nuly.
AddRefa vydání jsou z hlediska implementace přímočará.Zde je trivial implementace:
ULONG CMyObj::AddRef()
{
return ++m_dwRef;
}
ULONG CMyObj::Release()
{
if (--m_dwRef == 0)
{
delete this;
return 0;
}
return m_dwRef;
}
QueryInterface Je něco zajímavějšího členské funkce.Není velmi zajímavé objektu, jehož jedinou funkcí členů jsou AddRef a vydání – bylo příjemné zjistit objekt provádět více než IUnknown poskytuje.Kde je QueryInterface je užitečné.Umožňuje získat jiné "rozhraní" na stejný objekt.Tato rozhraní jsou obvykle odvozeny z IUnknown a přidáním nové funkce členů přidat další funkce.Rozhraní COM nikdy mít členské proměnné deklarované v rozhraní a funkce všech členů jsou deklarovány jako čistý virtuální.Příklad:
class IPrintInterface : public IUnknown
{
public:
virtual void PrintObject() = 0;
};
Získat IPrintInterface Pokud máte pouze IUnknown, volání IUnknown::QueryInterface použití IID z IPrintInterface.IID je 128bitové číslo jedinečně identifikující rozhraní.Došlo IID pro každé rozhraní definující nebo OLE.Pokud pUnk je ukazatel na IUnknown objektu, načíst kód IPrintInterface z může být:
IPrintInterface* pPrint = NULL;
if (pUnk->QueryInterface(IID_IPrintInterface,
(void**)&pPrint) == NOERROR)
{
pPrint->PrintObject();
pPrint->Release();
// release pointer obtained via QueryInterface
}
Který se zdá být poměrně snadno, ale jak by implementaci objekt podporující oba IPrintInterface a IUnknown rozhraní?V tomto případě je jednoduché od IPrintInterface odvozuje přímo z IUnknown – implementací IPrintInterface, IUnknown automaticky podporovány.Příklad:
class CPrintObj : public CPrintInterface
{
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
virtual void PrintObject();
};
Implementacích AddRef a vydání by být přesně stejné jako ty implementované výše.CPrintObj::QueryInterface by vypadat přibližně takto:
HRESULT CPrintObj::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
{
if (iid == IID_IUnknown || iid == IID_IPrintInterface)
{
*ppvObj = this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
Jak můžete vidět, pokud identifikátor rozhraní (IID) je rozpoznán, ukazatel je vrácena do objektu; v opačném případě dojde k chybě.Také úspěšně QueryInterface vede předpokládané AddRef.Samozřejmě je také třeba implementovat CEditObj::Print.Je jednoduché, protože IPrintInterface byla odvozena z IUnknown rozhraní.Ale pokud jste chtěli podporu dvou různých rozhraní i odvozené z IUnknown, zvažte následující:
class IEditInterface : public IUnkown
{
public:
virtual void EditObject() = 0;
};
Přestože existuje řada způsobů, jak implementovat podporu obě třídy IEditInterface a IPrintInterface, včetně C++ pomocí více dědičnosti, tato poznámka se soustředí na používání vnořené třídy implementují.
class CEditPrintObj
{
public:
CEditPrintObj();
HRESULT QueryInterface(REFIID iid, void**);
ULONG AddRef();
ULONG Release();
DWORD m_dwRef;
class CPrintObj : public IPrintInterface
{
public:
CEditPrintObj* m_pParent;
virtual HRESULT QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
} m_printObj;
class CEditObj : public IEditInterface
{
public:
CEditPrintObj* m_pParent;
virtual ULONG QueryInterface(REFIID iid, void** ppvObj);
virtual ULONG AddRef();
virtual ULONG Release();
} m_editObj;
};
Níže je zahrnuta celá implementace:
CEditPrintObj::CEditPrintObj()
{
m_editObj.m_pParent = this;
m_printObj.m_pParent = this;
}
ULONG CEditPrintObj::AddRef()
{
return ++m_dwRef;
}
CEditPrintObj::Release()
{
if (--m_dwRef == 0)
{
delete this;
return 0;
}
return m_dwRef;
}
HRESULT CEditPrintObj::QueryInterface(REFIID iid, void** ppvObj)
{
if (iid == IID_IUnknown || iid == IID_IPrintInterface)
{
*ppvObj = &m_printObj;
AddRef();
return NOERROR;
}
else if (iid == IID_IEditInterface)
{
*ppvObj = &m_editObj;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
ULONG CEditPrintObj::CEditObj::AddRef()
{
return m_pParent->AddRef();
}
ULONG CEditPrintObj::CEditObj::Release()
{
return m_pParent->Release();
}
HRESULT CEditPrintObj::CEditObj::QueryInterface(
REFIID iid, void** ppvObj)
{
return m_pParent->QueryInterface(iid, ppvObj);
}
ULONG CEditPrintObj::CPrintObj::AddRef()
{
return m_pParent->AddRef();
}
ULONG CEditPrintObj::CPrintObj::Release()
{
return m_pParent->Release();
}
HRESULT CEditPrintObj::CPrintObj::QueryInterface(
REFIID iid, void** ppvObj)
{
return m_pParent->QueryInterface(iid, ppvObj);
}
Všimněte si, že většina IUnknown implementace je umístěn do CEditPrintObj třídy namísto duplikování kód v CEditPrintObj::CEditObj a CEditPrintObj::CPrintObj.To snižuje množství kódu a předchází chyby.Důležitým faktem je z rozhraní IUnknown je možné volat QueryInterface načíst libovolné rozhraní může podporovat objekt a z každého z těchto rozhraní je možné provést.To znamená, že všechny QueryInterface funkce z každé rozhraní musí chovat stejným způsobem.Aby tyto vložené objekty k provádění volání v "vnější objekt" je ukazatel myši zpět použité (m_pParent).Ukazatel m_pParent je inicializován během konstruktoru CEditPrintObj.Potom by implementovat CEditPrintObj::CPrintObj::PrintObject a také CEditPrintObj::CEditObj::EditObject.Byl přidán poměrně bit kódu přidat jednu funkci – možnost objekt upravovat.Naštěstí je poměrně běžné rozhraní mít pouze jediné členské funkce (ačkoli dojít) a v případě EditObject a PrintObject by obvykle kombinovat do jednoho rozhraní.
Je mnoho kód pro jednoduché použití a mnoho vysvětlení.Třídy MFC/OLE poskytují jednodušší alternativu.Implementace MFC používá podobný způsob, jakým systém Windows zalamovány technika s mapami zprávy.Toto zařízení se nazývá Mapy rozhraní , který je popsán v následující části.
Mapy rozhraní MFC
MFC/OLE obsahuje implementaci "Rozhraní mapy" "Mapy zprávy" a "Odeslání mapy" MFC a podobné koncepce a provádění.Základní funkce mapy a MFC rozhraní jsou:
Standardní implementaci IUnknown, vestavěná CCmdTarget třídy.
Údržba počet odkazů, upravil AddRef a vydání
Provádění na datechQueryInterface
Rozhraní mapy navíc podporují následující funkce:
Podpora pro vytváření agregovatelné objektů modelu COM
Podpora pro provádění objektu COM pomocí agregačních objektů
Je hookable a rozšiřitelné
Další informace o agregaci naleznete OLE Programmer's Reference.
Podpora mapování MFC na rozhraní se zobrazuje v CCmdTarget třídy.CCmdTarget"má v" referenční počet stejně jako všechny přidružené funkce členů IUnknown provedení (počet odkazů je například v CCmdTarget).Chcete-li vytvořit třídu, která podporuje OLE COM odvození třídy z CCmdTarget a používat různé makra jako členské funkce CCmdTarget k provedení požadované rozhraní.Implementace a MFC používá vnořené třídy definovat každou implementaci rozhraní podobně jako v příkladu výše.To je usnadněno s standardní implementace IUnknown, jakož i počet vyloučit některé opakované kód makra.
K implementaci třídy MFC daného rozhraní pomocí mapy
Odvození třídy přímo nebo nepřímo z CCmdTarget.
Použití DECLARE_INTERFACE_MAP funkce v definici odvozené třídy.
U každého chtějí podporovat rozhraní použít BEGIN_INTERFACE_PART a END_INTERFACE_PART makra v definici třídy.
V provádění souboru použít BEGIN_INTERFACE_MAP a END_INTERFACE_MAP makra definovat mapování třídy rozhraní.
Každý IID podporovány, použijte INTERFACE_PART mezi maker BEGIN_INTERFACE_MAP a END_INTERFACE_MAP mapování na konkrétní třídy "části" IID tohoto makra.
Každý vnořený tříd, které představují rozhraní, které budete provádět.
Použití METHOD_PROLOGUE přístupu k nadřazenému makro CCmdTarget-odvozené objekt.
AddRef, Verze, a QueryInterface můžete delegovat CCmdTarget provádění těchto funkcí (ExternalAddRef, ExternalRelease, a ExternalQueryInterface).
Výše uvedený příklad CPrintEditObj se provádí takto:
class CPrintEditObj : public CCmdTarget
{
public:
// member data and member functions for CPrintEditObj go here
// Interface Maps
protected:
DECLARE_INTERFACE_MAP()
BEGIN_INTERFACE_PART(EditObj, IEditInterface)
STDMETHOD_(void, EditObject)();
END_INTERFACE_PART(EditObj)
BEGIN_INTERFACE_PART(PrintObj, IPrintInterface)
STDMETHOD_(void, PrintObject)();
END_INTERFACE_PART(PrintObj)
};
Výše uvedené prohlášení vytvoří třídy odvozené od CCmdTarget.DECLARE_INTERFACE_MAP makro říká rámci, že tato třída bude mít vlastní rozhraní mapy.Kromě toho BEGIN_INTERFACE_PART a END_INTERFACE_PART makra v tomto případě definovat vnořené třídy s názvy CEditObj a CPrintObj (X je používán pouze k odlišení vnořené třídy od globální třídy, které začínají třídy "C" a rozhraní, které začínají "I").Jsou vytvořeny dva vnořené členy těchto tříd: m_CEditObj a m_CPrintObj, resp..Makra automaticky deklarovat AddRef, verze, a QueryInterface funkce; proto pouze deklarování funkce specifické pro toto rozhraní: EditObject a PrintObject (makro OLE STDMETHOD je například tak, aby _stdcall a virtuální klíčová slova jsou k dispozici pro cílové platformě).
Implementovat rozhraní mapy pro tuto třídu:
BEGIN_INTERFACE_MAP(CPrintEditObj, CCmdTarget)
INTERFACE_PART(CPrintEditObj, IID_IPrintInterface, PrintObj)
INTERFACE_PART(CPrintEditObj, IID_IEditInterface, EditObj)
END_INTERFACE_MAP()
Toto připojení IID_IPrintInterface IID s m_CPrintObj a IID_IEditInterface s m_CEditObj resp..CCmdTarget Provádění QueryInterface (CCmdTarget::ExternalQueryInterface) mapa používá k vrácení ukazatele m_CPrintObj a m_CEditObj požadována.Není nutné zahrnout položku pro IID_IUnknown; rámci bude používat při první rozhraní v mapování (v tomto případě m_CPrintObj) IID_IUnknown je požadováno.
Přestože BEGIN_INTERFACE_PART makra automaticky deklarován AddRef, vydání a QueryInterface funkce můžete stále potřebujete implementovat je:
ULONG FAR EXPORT CEditPrintObj::XEditObj::AddRef()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return pThis->ExternalAddRef();
}
ULONG FAR EXPORT CEditPrintObj::XEditObj::Release()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return pThis->ExternalRelease();
}
HRESULT FAR EXPORT CEditPrintObj::XEditObj::QueryInterface(
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}
void FAR EXPORT CEditPrintObj::XEditObj::EditObject()
{
METHOD_PROLOGUE(CEditPrintObj, EditObj)
// code to "Edit" the object, whatever that means...
}
Provádění CEditPrintObj::CPrintObj, by podobné výše uvedené definice pro CEditPrintObj::CEditObj.Ačkoli by bylo možné vytvořit makro, které by bylo možné tyto funkce automaticky generovat (ale bylo dříve v rozvoji MFC/OLE případ), bude obtížné nastavit body přerušení při více než jeden řádek kódu vytváří makra.Z tohoto důvodu je tento kód rozbalen ručně.
Pomocí implementace rozhraní mapy zprávy existuje několik věcí, které nebyly nutné provést:
Provádění funkce QueryInterface
AddRef implementace a uvolnění
Kterékoli z těchto vestavěných metod deklarovat i vaše rozhraní
Kromě toho rámci používá mapování zpráva interně.To umožňuje odvodit z rámce třídy, vyslovte příkaz COleServerDoc, který již podporuje určité rozhraní a poskytuje náhrady nebo dodatky k rozhraní poskytované v rámci.Je standardně skutečnost, že plně podporuje dědění mapování rozhraní ze základní třídy – to je důvod proč BEGIN_INTERFACE_MAP bere jako svůj druhý parametr název základní třídy.
[!POZNÁMKA]
Obecně není možné znovu použít provádění jeho MFC vestavěné implementace rozhraní OLE podle dědění vložený specializace MFC verze rozhraní.Není možné protože použití METHOD_PROLOGUE přístup na obsahující makra CCmdTarget-odvozený objekt implikuje pevné odsazení z vloženého objektu CCmdTarget-odvozené objekt.To znamená například není možné odvodit vloženého XMyAdviseSink z implementace MFC a v COleClientItem::XAdviseSink, protože využívá právě na konkrétní posunu od začátku XAdviseSink COleClientItem objektu.
[!POZNÁMKA]
Můžete však delegovat provádění MFC pro všechny funkce má výchozí chování prvku MFC.Důvodem je implementace MFC v IOleInPlaceFrame (XOleInPlaceFrame) v COleFrameHook třídy (jej deleguje na m_xOleInPlaceUIWindow pro mnoho funkcí).Tento návrh byl vybrán pro zmenšení velikosti runtime objektů, které implementují rozhraní mnoho; odstraňuje potřebu ukazatel zpět (například m_pParent způsobem byl použit v předchozí části).
Agregace a mapy rozhraní
Vedle podpora samostatné objekty COM, MFC také podporuje agregaci.Agregace sám je příliš složité téma diskutovat zde; odkaz OLE Programmer's Reference Další informace o agregaci.Tato poznámka jednoduše popisuje podporu pro agregaci vestavěné rozhraní framework a mapy.
Agregace použít dvěma způsoby: (1) pomocí objektu COM, který podporuje agregaci a (2) objektu, který lze agregovat jinou implementaci.Tyto možnosti můžete být označovány jako "použití agregační objekt" a "vytvoření objektu agregovatelné".MFC podporuje oba.
Použití agregačních objektu
Použití agregačních objektu, pak musí být nějakým způsobem agregační funkce QueryInterface mechanismus do propojení.Jinými slovy agregovanému objektu musí chovat jako by je nativní součástí vašeho objektu.Jak tedy této rovnosti do rozhraní prvku MFC namapovat mechanismus?Kromě INTERFACE_PART makro, kde je mapován IID vnořený objekt můžete také deklarovat agregovanému objektu jako součást vašeho CCmdTarget odvozené třídy.Tak učinit, INTERFACE_AGGREGATE makro.Umožňuje určit členské proměnné (které musí být ukazatel k IUnknown nebo odvozené třídy), která je integrována do mapy mechanismus rozhraní.Pokud ukazatel není NULL při CCmdTarget::ExternalQueryInterface je volána, rámci automaticky zavolá agregovanému objektu QueryInterface členské funkce IID požadované není nativním IIDs podporován CCmdTarget sám.
Použití maker INTERFACE_AGGREGATE
Deklarování proměnné členů ( IUnknown *) obsahující ukazatel na objekt agregační.
Patří INTERFACE_AGGREGATE na mapě rozhraní členské proměnné odkazuje název makra.
V některých případech (obvykle během CCmdTarget::OnCreateAggregates), inicializovat členské proměnné na jinou hodnotu než NULL.
Příklad:
class CAggrExample : public CCmdTarget
{
public:
CAggrExample();
protected:
LPUNKNOWN m_lpAggrInner;
virtual BOOL OnCreateAggregates();
DECLARE_INTERFACE_MAP()
// "native" interface part macros may be used here
};
CAggrExample::CAggrExample()
{
m_lpAggrInner = NULL;
}
BOOL CAggrExample::OnCreateAggregates()
{
// wire up aggregate with correct controlling unknown
m_lpAggrInner = CoCreateInstance(CLSID_Example,
GetControllingUnknown(), CLSCTX_INPROC_SERVER,
IID_IUnknown, (LPVOID*)&m_lpAggrInner);
if (m_lpAggrInner == NULL)
return FALSE;
// optionally, create other aggregate objects here
return TRUE;
}
BEGIN_INTERFACE_MAP(CAggrExample, CCmdTarget)
// native "INTERFACE_PART" entries go here
INTERFACE_AGGREGATE(CAggrExample, m_lpAggrInner)
END_INTERFACE_MAP()
m_lpAggrInner Je inicializován v konstruktoru na hodnotu NULL.Rámci bude ignorovat NULL členské proměnné v provádění výchozí QueryInterface.OnCreateAggregates je vhodná skutečně vytvořit agregační objekty.Budete muset explicitně volat při vytváření objektu mimo provádění MFC COleObjectFactory.Důvod vytvoření souhrnných ukazatelů v CCmdTarget::OnCreateAggregates stejně jako použití CCmdTarget::GetControllingUnknown se stanou zjevnými při vytváření objektů agregovatelné je popsána.
Tato technika vám nabídne objekt všechna rozhraní, které podporuje agregovanému objektu a jeho nativní rozhraní.Pokud chcete pouze podmnožinu rozhraní, které podporuje agregační funkci, můžete přepsat CCmdTarget::GetInterfaceHook.To umožňuje velmi nízké úrovně hookability, podobný QueryInterface.Obvykle má rozhraní, které podporuje agregační funkci.
Vytváření objektů implementace agregovatelné
Pro objekt se agregovatelných, provádění AddRef, verze, a QueryInterface musí delegovat "řízení neznámý". Jinými slovy, jeho část objektu se musí delegovat AddRef, verze, a QueryInterface jiný objekt také odvozena IUnknown.Tento "řízení neznámý" je k dispozici v objektu při jeho vytvoření, je poskytován na provádění COleObjectFactory.Tato implementace nese malou režie a v některých případech není žádoucí, aby MFC je volitelné.Chcete-li objekt, který má být agregovatelné volání CCmdTarget::EnableAggregation z konstruktoru objektu.
Pokud objekt používá také agregáty, musíte také dbát předat správné "řízení" Neznámé"agregační objektů.Obvykle to IUnknown ukazatel předaný objekt při vytvoření agregační funkci.Parametr pUnkOuter je například "řízení neznámý" pro objekty vytvořené pomocí CoCreateInstance.Správné "Neznámý řízení" ukazatele lze získat voláním CCmdTarget::GetControllingUnknown.Hodnota vrácená z této funkce však není platné během konstruktoru.Z tohoto důvodu je doporučeno vytvořit vaše agregáty pouze v lokální změna z CCmdTarget::OnCreateAggregates, kde hodnota návrat z GetControllingUnknown je spolehlivý, přestože vytvořené z COleObjectFactory provedení.
Je také důležité, že objekt manipulovat správné referenční počet při přidávání nebo uvolnění počty umělých odkazů.Aby případě volání ExternalAddRef a ExternalRelease namísto InternalRelease a InternalAddRef.Nedochází k volání InternalRelease nebo InternalAddRef na třídu, která podporuje agregaci.
Referenční materiál
Rozšířené použití OLE, například definovat vlastní rozhraní nebo přepsání rámci provádění rozhraní OLE vyžaduje použití základní mechanismus rozhraní mapy.
Tato část popisuje jednotlivá makra a rozhraní API, které slouží k implementaci těchto rozšířených funkcí.
CCmdTarget::EnableAggregation – Popis funkce
void EnableAggregation();
Poznámky
Volání této funkce v konstruktoru třídy odvozené, pokud si přejete agregace OLE objekty tohoto typu.Připraví zvláštní IUnknown implementace, která je požadována pro agregovatelné objekty.
CCmdTarget::ExternalQueryInterface – Popis funkce
DWORD ExternalQueryInterface(
const void FAR* lpIID,
LPVOID FAR* ppvObj
);
Poznámky
Parametry
lpIID
Daleko ukazatele myši IID (první argument QueryInterface)ppvObj
Ukazatel na IUnknown * (druhá argument QueryInterface)
Poznámky
Volání této funkce v implementace IUnknown pro každé rozhraní třídy implementuje.Tato funkce poskytuje standardní řízené daty provádění funkce QueryInterface založené na mapě rozhraní daného objektu.Je nezbytné odevzdaných vrácenou hodnotu na popisovač HRESULT.Objekt je agregované, tato funkce zavolá "IUnknown řízení" namísto použití mapy místní rozhraní.
CCmdTarget::ExternalAddRef – Popis funkce
DWORD ExternalAddRef();
Poznámky
Volání této funkce v IUnknown::AddRef implementace pro každé rozhraní třídy implementuje.Vrácená hodnota je nový počet odkazů na objektu CCmdTarget.Objekt je agregované, tato funkce zavolá "IUnknown řízení" namísto místní referenční počet manipulace.
CCmdTarget::ExternalRelease – Popis funkce
DWORD ExternalRelease();
Poznámky
Volání této funkce v IUnknown::Release implementace pro každé rozhraní třídy implementuje.Vrácená hodnota označuje počet nových odkazů na objektu.Objekt je agregované, tato funkce zavolá "IUnknown řízení" namísto místní referenční počet manipulace.
DECLARE_INTERFACE_MAP – Popis makra
DECLARE_INTERFACE_MAP
Poznámky
Toto makro použít v libovolné třídy odvozené z CCmdTarget , bude mít mapování rozhraní.Podobným způsobem jako v DECLARE_MESSAGE_MAP.Toto makro vyvolání uvádět v definici třídy, obvykle v záhlaví (.H) soubor.Třída s DECLARE_INTERFACE_MAP v provádění souboru musíte definovat mapování rozhraní (.CPP) se BEGIN_INTERFACE_MAP a END_INTERFACE_MAP makra.
BEGIN_INTERFACE_PART a END_INTERFACE_PART – popis makra
BEGIN_INTERFACE_PART(
localClass,
iface
);
END_INTERFACE_PART(
localClass
)
Poznámky
Parametry
localClass
Název třídy, která implementuje rozhraníiface
Název této třídy implementuje rozhraní
Poznámky
Pro každé rozhraní třídy provede, musíte mít BEGIN_INTERFACE_PART a END_INTERFACE_PART páru.Tato makra definovat místní třídy odvozené od definovat jako proměnnou vložený člen třídy rozhraní OLE.AddRef, Verze, a QueryInterface členy jsou deklarovány automaticky.Musí obsahovat prohlášení pro jiné členské funkce, které jsou součástí rozhraní prováděna (Tato prohlášení jsou umístěny mezi BEGIN_INTERFACE_PART a END_INTERFACE_PART makra).
Iface argument je rozhraní OLE, které chcete implementovat jako IAdviseSink, nebo IPersistStorage (nebo vlastní rozhraní).
LocalClass argument je název místní třídu, která bude definována."X" bude automaticky před název.Toto pojmenování se používá k zabránění kolizím s globální třídy se stejným názvem.Kromě název vloženého členů, stejně jako localClass název kromě předchází "m_x".
Příklad:
BEGIN_INTERFACE_PART(MyAdviseSink, IAdviseSink)
STDMETHOD_(void,OnDataChange)(LPFORMATETC, LPSTGMEDIUM);
STDMETHOD_(void,OnViewChange)(DWORD, LONG);
STDMETHOD_(void,OnRename)(LPMONIKER);
STDMETHOD_(void,OnSave)();
STDMETHOD_(void,OnClose)();
END_INTERFACE_PART(MyAdviseSink)
by definovat místní třídy nazvané XMyAdviseSink z IAdviseSink a členem třídy, která je deklarována nazývá m_xMyAdviseSink.Note:
[!POZNÁMKA]
Řádky začínající STDMETHOD_ v podstatě zkopírována z OLE2.H a mírně upravené.Kopírování z OLE2.H zmenšit chyby, které je obtížné vyřešit.
BEGIN_INTERFACE_MAP a END_INTERFACE_MAP – popis makra
BEGIN_INTERFACE_MAP(
theClass,
baseClass
)
END_INTERFACE_MAP
Poznámky
Parametry
theClass
Mapa rozhraní je nutné definovat třídybaseClass
Třídy, ze které theClass odvozen od.
Poznámky
BEGIN_INTERFACE_MAP a END_INTERFACE_MAP makra jsou při provádění soubor skutečně definovat mapování rozhraní.Pro každé rozhraní implementované je jeden nebo více INTERFACE_PART makro vyvolání.Pro každý souhrn, který používá třída je INTERFACE_AGGREGATE makro vyvolání.
INTERFACE_PART – Popis makra
INTERFACE_PART(
theClass,
iid,
localClass
)
Poznámky
Parametry
theClass
Název třídy, která obsahuje mapu rozhraní.iid
IID která je mapována na vložený třídy.localClass
Název třídy místní (menší "X").
Poznámky
Toto makro se používá mezi BEGIN_INTERFACE_MAP makro a END_INTERFACE_MAP podporu bude objekt maker pro každé rozhraní.Umožňuje mapovat IID členem třídy podle theClass a localClass."m_x" bude přidán do localClass automaticky.Všimněte si, že více než jeden IID může být spojena s jeden člen.To je velmi užitečné, když jsou pouze "nejvíce odvozené" rozhraní na implementaci a chtějí zajistit také všechny mezilehlé rozhraní.Dobrým příkladem tohoto je IOleInPlaceFrameWindow rozhraní.Jeho hierarchie vypadá takto:
IUnknown
IOleWindow
IOleUIWindow
IOleInPlaceFrameWindow
Pokud objekt implementuje IOleInPlaceFrameWindow, může klient QueryInterface na některý z těchto rozhraní: IOleUIWindow, IOleWindow, nebo IUnknown, kromě rozhraní "nejvíce odvozené" IOleInPlaceFrameWindow (jedna skutečně provedli).Toto zpracování lze použít více než jeden INTERFACE_PART makro mapovat každý základní rozhraní IOleInPlaceFrameWindow rozhraní:
v souboru definice třídy:
BEGIN_INTERFACE_PART(CMyFrameWindow, IOleInPlaceFrameWindow)
v souboru implementace třídy:
BEGIN_INTERFACE_MAP(CMyWnd, CFrameWnd)
INTERFACE_PART(CMyWnd, IID_IOleWindow, MyFrameWindow)
INTERFACE_PART(CMyWnd, IID_IOleUIWindow, MyFrameWindow)
INTERFACE_PART(CMyWnd, IID_IOleInPlaceFrameWindow, MyFrameWindow)
END_INTERFACE_MAP
Protože je vždy požadována rámci stará o IUnknown.
INTERFACE_PART – Popis makra
INTERFACE_AGGREGATE(
theClass,
theAggr
)
Poznámky
Parametry
theClass
Název třídy, která obsahuje mapu rozhranítheAggr
Název členské proměnné, která se sečtou.
Poznámky
Toto makro lze zjistit rámci třídy pomocí agregačních objektu.Musí být mezi BEGIN_INTERFACE_PART a END_INTERFACE_PART makra.Agregační objekt je samostatný objekt, odvozené z IUnknown.Pomocí agregační a INTERFACE_AGGREGATE makra, můžete vytvořit rozhraní, které podporuje agregační přímo podporována objektem.TheAggr argument je jednoduše název proměnné členů třídy, který je odvozen z IUnknown (přímo nebo nepřímo).Všechny INTERFACE_AGGREGATE musí následovat makra INTERFACE_PART makra při umístění v mapě rozhraní.