Das Herzstück von OLE 2 ist das "OLE Component Object Model" oder com COM definiert einen Standard für wie kooperierenden Objekte miteinander kommunizieren. Dazu gehören die Details welche ein "Objekt" aussieht, einschließlich wie Methoden auf einem Objekt gesendet werden. COM definiert auch eine Basisklasse, von der alle COM-kompatible Klassen abgeleitet werden. Diese Basisklasse wird IUnknown. Obwohl die IUnknown -Schnittstelle als eine C++-Klasse bezeichnet wird, COM ist nicht spezifisch für jede Sprache ein — es kann implementiert werden, in C, PASCAL oder jede andere Sprache, die das binäre Layout eines COM-Objekts unterstützen kann.
OLE bezieht sich auf alle Klassen abgeleitet von IUnknown als "Schnittstellen". Dies ist eine wichtige Unterscheidung, da eine "Schnittstelle", z. B. IUnknown mit ihm keine Implementierung führt. Es definiert lediglich das Protokoll durch die Objekte zu kommunizieren, nicht die Besonderheiten der was tun diese Implementierungen. Dies ist sinnvoll für ein System, das maximale Flexibilität ermöglicht. Es ist Aufgabe der MFC ein Standardverhalten für MFC/C++-Programme zu implementieren.
Die MFC-Implementierung von IUnknown verstehen müssen Sie zuerst verstehen, was diese Schnittstelle ist. Eine vereinfachte Version von IUnknown, wird unten definiert.:
iUnknown-Klasse
{
Öffentliche:
&Nbsp; virtuelle HRESULT QueryInterface(REFIID iid, void** ppvObj) = 0;
virtuelle ULONG AddRef() = 0;
virtuelle ULONG Release() = 0;
}
Hinweis&Nbsp; Bestimmte notwendig aufrufende Konvention Details, wie z. B. __stdcall sind für diese Abbildung ausgelassen.
Die Memberfunktionen AddRef und Release Steuern Speicherverwaltung des Objekts. COM nutzt eine Zählung Referenzschema zu behalten Objekte. Ein Objekt wird nie verwiesen direkt wie in C++. Stattdessen sind COM-Objekte immer über einen Zeiger verwiesen. Um das Objekt freizugeben, wenn der Eigentümer erfolgt mit es, das Objekt freigeben Mitglied wird (im Gegensatz zur Verwendung von Operator löschen, wie bei einem herkömmlichen C++-Objekt durchgeführt werden würde) bezeichnet. Die Verweiszählung Mechanismus ermöglicht mehrere Verweise auf ein einzelnes Objekt verwaltet werden. Eine Implementierung der AddRef und Release behält einen Verweiszähler des Objekts — das Objekt wird nicht gelöscht, bis der Verweiszähler 0 erreicht.
AddRef und Release sind relativ einfach aus der Sicht einer Implementierung. Hier ist eine triviale Implementierung:
ULO&NG CMyObj::AddRef() {Nbsp; zurück ++ M_dwRef;
}
ULONG CMyObj::Release() {Wenn (--M_dwRef == 0) {}
delete this;
return 0;
}
Rückkehr M_dwRef;
}
Die QueryInterface -Memberfunktion ist ein wenig interessanter. Wie Sie sich vorstellen können, ist es nicht sehr interessant, die ein Objekt haben, deren einzige Memberfunktionen AddRef und Release sind — es würdet sein fein zu sagen, das Objekt zu tun, mehr Dinge als IUnknown enthält. Dies ist, wo QueryInterface nützlich ist. Sie können eine andere "Schnittstelle" auf das gleiche Objekt zu erhalten. Diese Schnittstellen sind in der Regel von IUnknown abgeleitet und zusätzliche Funktionen hinzufügen, indem Sie neue Member-Funktionen. COM-Schnittstellen haben nie in der Schnittstelle deklarierten Member-Variablen, und alle Member-Funktionen werden als rein virtual deklariert. Zum Beispiel,
iPrintInterface-Klasse: public IUnknown
{
Öffentliche:
&Nbsp; virtual void PrintObject() = 0;
}
Rufen Sie ein IPrintInterface erhalten, wenn Sie nur eine IUnknown, IUnknown:: QueryInterface mit der IID die IPrintInterface. Eine IID ist eine 128-Bit-Zahl, die die Schnittstelle eindeutig identifiziert. Es gibt eine IID für jede Schnittstelle, die entweder von Ihnen oder OLE definieren. Wenn pUnk ein Zeiger auf ein IUnknown -Objekt ist, möglicherweise der Code zum Abrufen eines IPrintInterface von ihm
IPrintInterface * pPrint = NULL;
Wenn (pUnk-Gt;QueryInterface(IID_IPrintInterface, (void**) & pPrint) == NOERROR)
{
pPrint - > PrintObject();
pPrint - > Release();
/ / Version Zeiger abgerufen über QueryInterface
}
Scheint das ziemlich einfach, aber wie würden Sie ein Objekt unterstützt sowohl die IPrintInterface als auch die IUnknown -Schnittstelle implementieren? In diesem Fall ist es einfach, da die IPrintInterface direkt von IUnknown abgeleitet ist — durch die Implementierung von IPrintInterface, IUnknown wird automatisch unterstützt. Zum Beispiel:
klasse CPrintObj: öffentliche CPrintInterface
{
&Nbsp; virtuelle HRESULT QueryInterface(REFIID iid, void** ppvObj);
virtuelle ULONG AddRef();
virtuelle ULONG Release();
virtual void PrintObject();
}
Die Implementierungen der AddRef und Release wäre genau die gleichen wie oben implementiert. CPrintObj::QueryInterface würde wie folgt aussehen
HRESULT CPrintObj::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
{
&Nbsp; Wenn (Iid == IID_IUnknown || Iid == IID_IPrintInterface)
{
* PpvObj =;
AddRef();
NOERROR zurück;
}
Rückkehr ResultFromScode(E_NOINTERFACE);
}
Wie Sie sehen können, wenn der Interface Identifier (IID) erkannt wird, wird ein Zeiger auf das Objekt zurückgegeben; Andernfalls tritt ein Fehler auf. Beachten Sie außerdem, dass eine erfolgreiche QueryInterface eine stillschweigende AddRefführt. Natürlich müssten Sie auch CEditObj::Printimplementieren. Das ist einfach, denn die IPrintInterface direkt von der Schnittstelle IUnknown abgeleitet wurde. Jedoch wenn Sie zwei verschiedene Schnittstellen unterstützen wollten, beide abgeleitet von IUnknown, Folgendes
klasse IEditInterface: öffentliche IUnkown
{
Öffentliche:
&Nbsp; virtual void EditObject() = 0;
}
Zwar gibt es eine Reihe von Möglichkeiten zum Implementieren einer Klasse, die Unterstützung von IEditInterface und IPrintInterface, einschließlich der Verwendung von C++ Mehrfachvererbung, wird dieser Hinweis auf die Verwendung von geschachtelten Klassen zum Implementieren dieser Funktionen konzentrieren.
klasse CEditPrintObj
{
Öffentliche:
&Nbsp; CEditPrintObj();
HRESULT QueryInterface(REFIID iid, void**);
ULONG AddRef();
ULONG Release();
DWORD M_dwRef;
Klasse CPrintObj: öffentliche IPrintInterface
{
Öffentliche:
CEditPrintObj * M_pParent;
virtuelle HRESULT QueryInterface(REFIID iid, void** ppvObj);
virtuelle ULONG AddRef();
virtuelle ULONG Release();
} M_printObj;
Klasse CEditObj: öffentliche IEditInterface
{
Öffentliche:
CEditPrintObj * M_pParent;
virtuelle ULONG QueryInterface(REFIID iid, void** ppvObj);
virtuelle ULONG AddRef();
virtuelle ULONG Release();
} M_editObj;
}
Die gesamte Implementierung ist unten enthalten.:
CEditPrintObj::CEditPrintObj()
{
Nbsp; m_editObj.m_pParent = diese;
m_printObj.m_pParent = diese;
}
ULONG CEditPrintObj::AddRef() {zurück ++ M_dwRef;
}
CEditPrintObj::Release()
{
Wenn (--M_dwRef == 0)
{
delete this;
return 0;
}
Rückkehr M_dwRef;
}
HRESULT CEditPrintObj::QueryInterface(REFIID iid, void** ppvObj)
{
Wenn (Iid == IID_IUnknown || Iid == IID_IPrintInterface)
{
* PpvObj = & M_printObj;
AddRef();
NOERROR zurück;
}
elseif (Iid == IID_IEditInterface)
{
* PpvObj = & M_editObj;
AddRef();
NOERROR zurück;
}
Rückkehr ResultFromScode(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);
}
Beachten Sie, dass die meisten der IUnknown -Implementierung befindet sich in der CEditPrintObj -Klasse, anstatt den Code in CEditPrintObj::CEditObj und CEditPrintObj::CPrintObj zu duplizieren. Dies reduziert die Menge an Code und vermeidet Fehler. Der wichtige Punkt hier ist, dass die IUnknown-Schnittstelle es möglich ist, rufen Sie QueryInterface für eine Schnittstelle abzurufen, die das Objekt möglicherweise unterstützt, und aus jeder der diese Schnittstellen ist es möglich, das gleiche zu tun. Dies bedeutet, dass alle QueryInterface Funktionen in den einzelnen Schnittstellen müssen genauso Verhalten. Damit diese eingebetteten Objekte aufrufen, die Umsetzung in das "äußere Objekt" ist ein zurück-Zeiger verwendet (M_pParent). Der M_pParent-Zeiger wird während der CEditPrintObj-Konstruktor initialisiert. Dann würde Sie CEditPrintObj::CPrintObj::PrintObject und CEditPrintObj::CEditObj::EditObject sowie implementieren. Einiges an Code wurde hinzugefügt, um ein Feature hinzuzufügen – die Möglichkeit, das Objekt zu bearbeiten. Glücklicherweise ist es recht ungewöhnlich für Schnittstellen auf nur eine einzelnen Member-Funktion haben (obwohl es geschieht) und in diesem Fall, EditObject und PrintObject würde in der Regel werden kombiniert in einer einzigen Schnittstelle.
Das ist eine Menge Erklärung und eine Menge Code für solch ein einfaches Szenario. Die MFC/OLE-Klassen bieten eine einfachere Alternative. Die MFC-Implementierung verwendet eine Technik ähnlich wie die Windows-Meldungen eingewickelt werden mit Meldungszuordnungen. Diese Anlage heißt Interface Karten und wird im nächsten Abschnitt erläutert.
MFC-Interface-Karten
MFC/OLE enthält eine Implementierung des "Interface Karten" MFC "Meldungszuordnungen" und "Dispatchzuordnungen" ähnlich im Konzept und Ausführung. Die Kernfeatures von MFC Interface Karten sind wie folgt:
Darüber hinaus unterstützen Schnittstellen-Karten die folgenden erweiterten Funktionen:
Weitere Informationen über Aggregation finden Sie in der OLE Programmer's Reference.
MFC Schnittstelle Karte Unterstützung wurzelt in der CCmdTarget -Klasse. CCmdTarget "hat ein" verweisen Graf sowie alle Member-Funktionen, die die IUnknown -Implementierung (die Anzahl ist zum Beispiel in CCmdTarget) zugeordnet. Wenn Sie eine Klasse erstellen, die OLE-COM unterstützt, Sie leiten Sie eine Klasse von CCmdTarget und verwenden verschiedene Makros sowie Memberfunktionen von CCmdTarget die gewünschten Schnittstellen implementiert. MFC Implementierung verwendet geschachtelte Klassen jedes Schnittstellenimplementierung ähnlich wie das obige Beispiel zu definieren. Dies ist mit einer standard-Implementierung von IUnknown sowie eine Reihe von Makros, die einige der sich wiederholenden Code beseitigen leichter gemacht.
Schnittstelle Karte Grundlagen
Implementieren eine Klasse mithilfe von MFC-Benutzeroberfläche folgendermaßen Karten:
CPrintEditObj obigen Beispiel könnte wie folgt implementiert werden:
klasse CPrintEditObj: öffentliche CCmdTarget
{
Öffentliche:
&Nbsp; / / Hier gehen Memberdaten und Memberfunktionen für CPrintEditObj
/ / Interface Karten
geschützt:
DECLARE_INTERFACE_MAP()
BEGIN_INTERFACE_PART EditObj (IEditInterface)
STDMETHOD_ (leere, EditObject)();
END_INTERFACE_PART(EditObj)
BEGIN_INTERFACE_PART (PrintObj, IPrintInterface)
STDMETHOD_ (leere, PrintObject)();
END_INTERFACE_PART(PrintObj)
}
Die obige Deklaration erstellt eine von CCmdTargetabgeleitete Klasse. Das DECLARE_INTERFACE_MAP -Makro sagt Rahmen, dass diese Klasse eine benutzerdefinierte Schnittstelle-Karte haben wird. Darüber hinaus definieren die Makros BEGIN_INTERFACE_PART und END_INTERFACE_PART geschachtelte Klassen, in diesem Fall mit Namen CEditObj und CPrintObj (das x dient nur zum unterscheiden der geschachtelten Klassen von globalen Klassen, die mit "C" beginnen und Schnittstellenklassen, die beginnen mit "I"). Werden zwei verschachtelte Mitglieder dieser Klassen erstellt: M_CEditObj, und M_CPrintObj, beziehungsweise. Die Makros deklarieren automatisch die AddRef, Releaseund QueryInterface Funktionen; damit Sie nur die Funktionen deklarieren für diese Schnittstelle spezifisch: EditObject und PrintObject (das STDMETHOD ist OLE-Makro verwendet wie so dass _stdcall und virtuelle Schlüsselwörter für die Zielplattform entsprechend bereitgestellt werden).
Die Schnittstellenzuordnung für diese Klasse implementieren:
BEGI&N_INTERFACE_MAP (CPrintEditObj, CCmdTarget)
Nbsp; INTERFACE_PART (CPrintEditObj, IID_IPrintInterface, PrintObj)
INTERFACE_PART (CPrintEditObj, IID_IEditInterface, EditObj)
END_INTERFACE_MAP()
Dadurch die IID_IPrintInterface IID mit M_CPrintObj und IID_IEditInterface mit M_CEditObj bzw.. Die CCmdTarget -Implementierung von QueryInterface (CCmdTarget::ExternalQueryInterface) wird diese Karte Zeiger auf M_CPrintObj und M_CEditObj bei der Anforderung zurückgegeben. Es ist nicht notwendig, einen Eintrag für IID_IUnknownenthalten; das Framework verwendet die erste Schnittstelle in der Karte (in diesem Fall M_CPrintObj) Wenn IID_IUnknown angefordert wird,.
Obwohl das BEGIN_INTERFACE_PART -Makro automatisch die AddRef, Release und QueryInterface Funktionen für Sie deklariert, müssen Sie immer noch, sie umzusetzen:
ULONG weit EXPORT CEditPrintObj::XEditObj::AddRef()
{
Nbsp; METHOD_PROLOGUE (CEditPrintObj, EditObj)
zurück pThis - > ExternalAddRef();
}
ULONG weit EXPORT CEditPrintObj::XEditObj::Release()
{
METHOD_PROLOGUE (CEditPrintObj, EditObj)
zurück pThis - > ExternalRelease();
}
HRESULT weit exportieren () CEditPrintObj::XEditObj::QueryInterface
REFIID Iid, void FAR FAR ** PpvObj)
{
METHOD_PROLOGUE (CEditPrintObj, EditObj)
zurück (HRESULT) pThis - > ExternalQueryInterface (& Iid, PpvObj);
}
void weit exportieren CEditPrintObj::XEditObj::EditObject()
{
METHOD_PROLOGUE (CEditPrintObj, EditObj)
/ / code auf "Bearbeiten" dem Objekt, was auch immer das bedeutet...
}
Die Implementierung für CEditPrintObj::CPrintObj, wäre ähnlich wie die oben genannten Definitionen für CEditPrintObj::CEditObj. Obwohl es möglich wäre, ein Makro zu erstellen, die verwendet werden könnte, um automatisch generieren diese Funktionen (in der Tat, früher in die MFC/OLE-Entwicklung war dies der Fall), wird es schwierig, Haltepunkte festlegen, wenn ein Makro mehr als eine Zeile Code generiert. Aus diesem Grund wird dieser Code manuell erweitert.
Mithilfe der Framework-Implementierung der Nachricht sind Karten gibt eine Reihe von Dingen, die nicht notwendig waren:
Darüber hinaus verwendet das Framework intern Meldungszuordnungen. Sagen Sie dies ermöglicht, ein Framework-Klasse ableiten, COleServerDoc abgeleitet ist, die bereits bestimmte Schnittstellen unterstützt und stellt Ersatz oder Ergänzung der vom Framework bereitgestellten Schnittstellen. Dies wird durch die Tatsache, dass das Framework vollständig unterstützt eine Schnittstelle Karte von einer Basisklasse erben aktiviert – das ist der Grund, warum BEGIN_INTERFACE_MAP als zweiten Parameter den Namen der Basisklasse nimmt,.
Hinweis&Nbsp; Es ist generell nicht möglich, die Umsetzung des MFC integrierten Implementierungen von OLE-Schnittstellen durch Vererbung von der eingebetteten Spezialisierung dieser Schnittstelle von der MFC-Version wiederverwenden. Ist dies nicht möglich weil die Verwendung des Makros METHOD_PROLOGUE erhalten Sie Zugriff auf das enthaltende CCmdTarget-abgeleiteten Objekt impliziert ein fester Versatz des eingebetteten Objekts von der CCmdTarget-abgeleiteten Objekts. Das bedeutet zum Beispiel, Sie eine eingebettete XMyAdviseSink von MFC Implementierung in COleClientItem::XAdviseSink, ableiten können nicht, da XAdviseSink beruht darauf, an einem bestimmten Offset vom Anfang der die COleClientItem -Objekt.
Sie können, jedoch an die MFC-Implementierung für alle Funktionen delegieren möchten MFC Standardverhalten. Dies geschieht in der MFC-Implementierung von IOleInPlaceFrame (XOleInPlaceFrame) in der COleFrameHook -Klasse (delegiert an M_xOleInPlaceUIWindow für viele Funktionen). Dieses Design wurde gewählt, um die Common Language Runtime-Größe der Objekte zu verringern, die viele Schnittstellen implementieren; Es entfällt die Notwendigkeit für einen Back-Zeiger (z. B. die Art und Weise M_pParent im vorherigen Abschnitt verwendet wurde).
Aggregation und Interface-Karten
Zusätzlich zur Unterstützung von eigenständigen COM-Objekte, unterstützt MFC auch Aggregation. Aggregation selbst ist zu Komplex ein Thema hier zu diskutieren; finden Sie in der OLE Programmer's Reference für weitere Informationen über Aggregation. Dieser Hinweis wird die Unterstützung für die Aggregation in den Rahmen und Interface-Karten integriert einfach beschreiben.
Es gibt zwei Möglichkeiten, Aggregation verwendet werden: (1) mithilfe eines COM-Objekts, die Aggregation unterstützt, und (2) Implementierung eines Objekts, das von einem anderen aggregiert werden kann. Diese Funktionen können als "mit einer aggregate-Objekt" und "ein Objekt aggregiert werden" bezeichnet werden. MFC unterstützt sowohl.
Mithilfe einer Aggregate-Objekt
Eine aggregate-Objekt, es muss irgendwie binden das Aggregat in der QueryInterface-Mechanismus verwenden. Mit anderen Worten muss das zusammengesetzte Objekt verhält, als ob es ein systemeigener Bestandteil Ihres Objekts ist. So wie diese Krawatte in MFC Schnittstelle Karte Mechanismus funktioniert? Zusätzlich zu den INTERFACE_PART -Makro, wobei eine geschachtelte Objekt eine IID zugeordnet ist, können Sie auch eine aggregate-Objekt als Teil Ihrer CCmdTarget abgeleitete Klasse deklarieren. Dazu wird das INTERFACE_AGGREGATE -Makro verwendet. Dadurch können Sie eine Membervariable (das muss ein Zeiger auf ein IUnknown oder abgeleitete Klasse) angeben, die in der Schnittstelle-Karte-Mechanismus integriert werden. Wenn der Zeiger nicht NULL ist, wenn CCmdTarget::ExternalQueryInterface aufgerufen wird, der Rahmen wird automatisch das zusammengesetzte Objekt QueryInterface -Memberfunktion aufrufen, wenn die IID angefordert ist nicht eine native IIDs unterstützt durch die CCmdTarget -Objekt selbst.
Gehen folgendermaßen Sie vor um das Makro INTERFACE_AGGREGATE verwenden,:
Zum Beispiel,
klasse CAggrExample: öffentliche CCmdTarget
{
Öffentliche:
Nbsp; CAggrExample();
geschützt:
LPUNKNOWN M_lpAggrInner;
Virtual BOOL OnCreateAggregates();
DECLARE_INTERFACE_MAP()
/ / "native" Schnittstelle Teil Makros können hier verwendet werden
};
CAggrExample::CAggrExample()
{
M_lpAggrInner = NULL;
}
BOOL CAggrExample::OnCreateAggregates()
{
/ / Draht bis Aggregat mit richtigen Steuerung unbekannt
M_lpAggrInner = CoCreateInstance (CLSID_Example,
GetControllingUnknown(), CLSCTX_INPROC_SERVER,
IID_IUnknown, (LPVOID **) & M_lpAggrInner);
Wenn (M_lpAggrInner == NULL)
Return FALSE;
/ / Erstellen Sie optional andere aggregierte Objekte hier
TRUE zurück;
}
BEGIN_INTERFACE_MAP (CAggrExample, CCmdTarget)
/ / native "INTERFACE_PART" Einträge gehen hier
INTERFACE_AGGREGATE (CAggrExample, M_lpAggrInner)
END_INTERFACE_MAP()
Die m_lpAggrInner wird im Konstruktor auf NULL initialisiert. Der Rahmen wird eine NULL-Member-Variable in der Standardimplementierung von QueryInterfaceignorieren. OnCreateAggregates ist ein guter Ort um die aggregierten Objekte zu erstellen. Du musst es explizit aufrufen, wenn Sie das Objekt außerhalb der die MFC-Implementierung von COleObjectFactoryerstellen. Der Grund für die Erstellung von Aggregaten in CCmdTarget::OnCreateAggregates sowie die Verwendung von CCmdTarget::GetControllingUnknown wird offensichtlich werden, beim Erstellen von aggregierbare Objekten behandelt wird.
Diese Technik wird Ihr Objekt alle Schnittstellen geben, die das zusammengesetzte Objekt plus die nativen Schnittstellen unterstützt. Wenn Sie nur eine Teilmenge der Schnittstellen, die das Aggregat unterstützt, können Sie CCmdTarget::GetInterfaceHooküberschreiben. Dadurch können Sie sehr niedrigen Niveau Hookability, ähnlich dem QueryInterface. In der Regel möchten Sie alle Schnittstellen, die das Aggregat unterstützt.
Machen eine Objekt-Implementierung aggregierbaren
Für ein Objekt aggregiert werden sollen muss die Implementierung von QueryInterface , AddRefund Releasean eine "Steuerung unbekannt." delegieren. Es mit anderen Worten, muss dass es als Teil des Objekts, QueryInterface , AddRefund Releaseauf ein anderes Objekt, auch abgeleitet von IUnknowndelegieren. Diese "Kontrolle unbekannt" wird auf das Objekt wenn es erstellt wird, das heißt, es auf die Umsetzung von COleObjectFactorybereitgestellt wird. Umsetzung führt eine kleine Menge an Aufwand, und in einigen Fällen ist nicht wünschenswert, so dass MFC das optional macht. Um ein Objekt aggregiert werden zu aktivieren, rufen Sie CCmdTarget::EnableAggregation aus der Konstruktor des Objekts.
Wenn das Objekt auch Aggregate verwendet, Sie müssen auch sicher sein, den richtigen pass "Kontrolle unbekannt" auf die aggregierten Objekte. In der Regel wird dieser IUnknown -Zeiger auf das Objekt übergeben, wenn das Aggregat erstellt wird. Beispielsweise ist der pUnkOuter-Parameter der "Steuerung unbekannt" für Objekte mit CoCreateInstanceerstellt. Der richtige "Steuern unbekannt" Zeiger kann durch Aufrufen von CCmdTarget::GetControllingUnknownabgerufen werden. Der Rückgabewert von der Funktion an, ist jedoch nicht gültig während der Konstruktor. Aus diesem Grund wird empfohlen, dass Sie nur in einer Überschreibung der CCmdTarget::OnCreateAggregates, Ihre Aggregate wo der Rückgabewert von GetControllingUnknown zuverlässig erstellen, ist auch wenn von der COleObjectFactory -Implementierung erstellt.
Es ist auch wichtig, dass das Objekt den richtigen Verweiszähler beim Hinzufügen oder Freigeben von künstlichen Referenzzähler zu bearbeiten. Um sicherzustellen, dass dies der Fall ist, rufen Sie immer ExternalAddRef und ExternalRelease anstelle von InternalRelease und InternalAddRef. Es ist selten, InternalRelease oder InternalAddRef auf einer Klasse aufrufen, die Aggregation unterstützt.
Referenzmaterial
Fortgeschrittene Verwendung von OLE, wie Ihre eigenen Schnittstellen definieren oder überschreiben die Framework-Implementierung der OLE-Schnittstellen erfordert die Verwendung des zugrunde liegenden Schnittstelle Karte Mechanismus.
Dieser Abschnitt beschreibt jedes Makro und die APIs, die verwendet wird, um diese erweiterten Features zu implementieren.
CCmdTarget::EnableAggregation — Funktionsbeschreibung
privatevoid EnableAggregation();
Hinweis&Nbsp; Rufen Sie diese Funktion in den Konstruktor der abgeleiteten Klasse, wenn Sie OLE-Aggregation für Objekte dieses Typs unterstützen möchten. Dies bereitet eine spezielle IUnknown-Implementierung, die für aggregierbaren Objekte erforderlich ist.
CCmdTarget::ExternalQueryInterface — Funktionsbeschreibung
DWORD ExternalQueryInterface (Const void FAR * LpIID, LPVOID FAR * PpvObj);
lpIID
Ein weit Zeiger auf eine IID (das erste Argument von QueryInterface)
ppvObj
Ein Zeiger an eine IUnknown (zweite Argument QueryInterface)
Hinweis&Nbsp; Rufen Sie diese Funktion in Ihrer Implementierung der IUnknown für jede Schnittstelle der Klasse implementiert. Diese Funktion bietet datengesteuerter Standardimplementierung von QueryInterface auf der Grundlage des Objekts Schnittstelle anzeigen. Es ist notwendig, den Rückgabewert in ein HRESULT umgewandelt. Wenn das Objekt aggregiert ist, wird diese Funktion "Steuernde IUnknown" aufrufen, anstatt mit Hilfe der lokalen Schnittstelle-Karte.
CCmdTarget::ExternalAddRef — Funktionsbeschreibung
DWORD ExternalAddRef();
Hinweis&Nbsp; Rufen Sie diese Funktion in der Implementierung von AddRef für jede Schnittstelle der Klasse implementiert. Der Rückgabewert ist der neue Verweiszähler für die CCmdTarget-Objekt. Wenn das Objekt aggregiert ist, wird diese Funktion "Steuernde IUnknown" aufrufen, anstatt bearbeiten den lokalen Verweiszähler.
CCmdTarget::ExternalRelease — Funktionsbeschreibung
DWORD ExternalRelease();
Hinweis&Nbsp; Rufen Sie diese Funktion in Ihrer Implementierung der IUnknown:: Release für jede Schnittstelle der Klasse implementiert. Der Rückgabewert gibt den neue Verweiszähler des Objekts. Wenn das Objekt aggregiert ist, wird diese Funktion "Steuernde IUnknown" aufrufen, anstatt bearbeiten den lokalen Verweiszähler.
DECLARE_INTERFACE_MAP — Makrobeschreibung
DECLARE_INTERFACE_MAP
Hinweis&Nbsp; Verwenden Sie dieses Makro in einer Klasse, abgeleitet von CCmdTarget , die eine Schnittstelle-Karte haben. Verwendet in viel die gleiche Weise wie DECLARE_MESSAGE_MAP. Dieser Makroaufruf in der Klassendefinition, in der Regel in einem Header platziert werden sollte (.H) Datei. Eine Klasse mit DECLARE_INTERFACE_MAP muss die Schnittstellenzuordnung in der Implementierungsdatei definieren (.CPP) mit den Makros BEGIN_INTERFACE_MAP und END_INTERFACE_MAP.
BEGIN_INTERFACE_PART und END_INTERFACE_PART — Makro Beschreibungen
BEGIN_INTERFACE_PART (LocalClass, Iface);
END_INTERFACE_PART (LocalClass)
localClass
Der Name der Klasse, die die Schnittstelle implementiert
iface
Der Name der Schnittstelle, die diese Klasse implementiert
Hinweis&Nbsp; Für jede Schnittstelle, die Ihre Klasse implementiert wird, müssen Sie ein paar BEGIN_INTERFACE_PART und END_INTERFACE_PART haben. Diese Makros definieren eine lokale Klasse abgeleitet der OLE-Schnittstelle, die Sie als auch eine eingebettete Member-Variable der Klasse definieren. Die QueryInterface , AddRefund Releasesind automatisch deklarierten Member. Sie müssen die Deklarationen für die andere Memberfunktionen, die Teil der implementierten Schnittstelle sind enthalten (diese Erklärungen befinden sich zwischen den Makros BEGIN_INTERFACE_PART und END_INTERFACE_PART ).
Das Iface -Argument ist die OLE-Schnittstelle, die Sie wünschen zu implementieren, z. B. IAdviseSink, oder IPersistStorage (oder Ihre eigene benutzerdefinierte Schnittstelle).
Das Argument LocalClass ist der Name der lokalen Klasse, die definiert wird. Ein ' X' wird automatisch der Name vorangestellt werden. Diese Benennungskonvention wird verwendet, um Kollisionen mit globaler Klassen mit demselben Namen zu vermeiden. Darüber hinaus ist der Name der eingebetteten Members, identisch mit den LocalClass Namen außer es 'M_x' vorangestellt.
Zum Beispiel:
BEGI&N_INTERFACE_PART (MyAdviseSink, IAdviseSink)
Nbsp; STDMETHOD_(void,OnDataChange) (LPFORMATETC, LPSTGMEDIUM);
STDMETHOD_(void,OnViewChange) (DWORD, lange);
STDMETHOD_(void,OnRename)(LPMONIKER);
STDMETHOD_(void,OnSave)();
STDMETHOD_(void,OnClose)();
END_INTERFACE_PART(MyAdviseSink)
eine lokale Klasse namens XMyAdviseSink abgeleitet IAdviseSink definieren würde, und ein Member der Klasse, in der es deklariert ist, aufgerufen m_xMyAdviseSink.Note:
Hinweis&Nbsp; Die Linien beginnen mit STDMETHOD_ werden im Wesentlichen von OLE2 kopiert.H und leicht geändert. Kopieren von OLE2.H kann Fehler zu reduzieren, die schwer zu beheben sind.
BEGIN_INTERFACE_MAP und END_INTERFACE_MAP — Makro Beschreibungen
BEGIN_INTERFACE_MAP (TheClass, BaseClass)
END_INTERFACE_MAP
theClass
Die Klasse, in dem die Schnittstellenzuordnung definiert werden
baseClass
Die Klasse von der TheClass abgeleitet.
Hinweise: Die Makros BEGIN_INTERFACE_MAP und END_INTERFACE_MAP werden in der Implementierungsdatei tatsächlich definieren Sie die Schnittstelle-Karte verwendet. Für jede Schnittstelle, die implementiert wird gibt es ein oder mehrere Aufrufe der INTERFACE_PART -Makro. Für jede Summe, die die Klasse verwendet, gibt es ein INTERFACE_AGGREGATE Makroaufruf.
INTERFACE_PART — Makrobeschreibung
INTERFACE_PART (TheClass, Iid, LocalClass)
theClass
Der Name der Klasse, die die Schnittstellenzuordnung enthält.
iid
Die IID der eingebetteten Klasse zugeordnet werden soll.
localClass
Der Name der lokalen Klasse (weniger das ' X')
Hinweis&Nbsp; Dieses Makro ist für jede Schnittstelle zwischen das BEGIN_INTERFACE_MAP -Makro und das END_INTERFACE_MAP -Makro verwendet, die Ihr Objekt unterstützt werden. Es erlaubt Ihnen, eine IID auf einen Member der Klasse TheClass und LocalClassabzubilden. Die 'M_x' wird der LocalClass automatisch hinzugefügt werden. Beachten Sie, dass mehr als eine IID ein einzelnes Mitglied zugeordnet werden kann. Dies ist sehr nützlich, wenn Sie nur eine "am meisten abgeleitete" Schnittstelle implementieren und alle fortgeschrittene Schnittstellen sowie bereitstellen möchten. Ein gutes Beispiel hierfür ist die IOleInPlaceFrameWindow -Schnittstelle. Die Hierarchie sieht folgendermaßen aus.:
IUnknown
&Nbsp; IOleWindow
IOleUIWindow
IOleInPlaceFrameWindow
Wenn ein Objekt IOleInPlaceFrameWindowimplementiert, kann ein Client QueryInterface auf eine dieser Schnittstellen: IOleUIWindow, IOleWindowoder IUnknown, neben der "am meisten abgeleiteten" Schnittstelle IOleInPlaceFrameWindow (die ein, die Sie tatsächlich implementieren). Um zu handhaben können mehr als ein INTERFACE_PART -Makro Sie die IOleInPlaceFrameWindow -Schnittstelle jeder Basisschnittstelle zuordnen
in der klasse-definitionsdatei:
BEGIN_INTERFACE_PART (CMyFrameWindow, IOleInPlaceFrameWindow)
in der implementierungsdatei der klasse:
BEGI&N_INTERFACE_MAP (CMyWnd, CFrameWnd)
Nbsp; INTERFACE_PART (CMyWnd, IID_IOleWindow, MyFrameWindow)
INTERFACE_PART (CMyWnd, IID_IOleUIWindow, MyFrameWindow)
INTERFACE_PART (CMyWnd, IID_IOleInPlaceFrameWindow, MyFrameWindow)
END_INTERFACE_MAP
Das Framework übernimmt IUnknown da es immer notwendig ist.
INTERFACE_PART — Makrobeschreibung
INTERFACE_AGGREGATE (TheClass, TheAggr)
theClass
Der Name der Klasse, die die Schnittstellenzuordnung enthält,
theAggr
Der Name der Membervariablen aggregiert werden soll.
Hinweis&Nbsp; Dieses Makro wird verwendet, um dem Rahmen sagen, dass die Klasse eine aggregate-Objekt verwendet. Es muss zwischen den Makros BEGIN_INTERFACE_PART und END_INTERFACE_PART angezeigt werden. Eine aggregate-Objekt ist ein separates Objekt, abgeleitet von IUnknown. Aggregat und das INTERFACE_AGGREGATE -Makro verwenden, stellen Sie alle Schnittstellen, die das Aggregieren unterstützt angezeigt werden direkt von dem Objekt unterstützt werden sollen. Das TheAggr -Argument ist der Name des eine Member-Variable der Klasse das (direkt oder indirekt) von IUnknown abgeleitet wird. Alle INTERFACE_AGGREGATE -Makros müssen die INTERFACE_PART Makros in einer Schnittstelle Karte platziert folgen.
Technische Hinweise von &Nummer |nbsp; Technische Hinweise nach Kategorie