TN039: MFC/OLE-Automatisierungsimplementierung
Hinweis
Der folgende technische Hinweis wurde seit dem ersten Erscheinen in der Onlinedokumentation nicht aktualisiert. Daher können einige Verfahren und Themen veraltet oder falsch sein. Um aktuelle Informationen zu erhalten, wird empfohlen, das gewünschte Thema im Index der Onlinedokumentation zu suchen.
Übersicht über die OLE IDispatch-Schnittstelle
Die IDispatch
Schnittstelle ist die Methode, mit der Anwendungen Methoden und Eigenschaften verfügbar machen, sodass andere Anwendungen wie Visual BASIC oder andere Sprachen die Features der Anwendung nutzen können. Der wichtigste Teil dieser Schnittstelle ist die IDispatch::Invoke
Funktion. MFC verwendet "Dispatch maps" zum Implementieren IDispatch::Invoke
. Die Verteilerzuordnung stellt die MFC-Implementierungsinformationen zum Layout oder "Shape" Ihrer CCmdTarget
abgeleiteten Klassen bereit, sodass sie die Eigenschaften des Objekts direkt bearbeiten oder Memberfunktionen innerhalb Des Objekts aufrufen kann, um Anforderungen zu erfüllen IDispatch::Invoke
.
Zum größten Teil arbeiten ClassWizard und MFC zusammen, um die meisten Details der OLE-Automatisierung aus dem Anwendungsprogrammierer auszublenden. Der Programmierer konzentriert sich auf die tatsächliche Funktionalität, die in der Anwendung verfügbar gemacht werden soll, und muss sich keine Gedanken über die zugrunde liegende Sanitärinstallation machen.
Es gibt jedoch Fälle, in denen es notwendig ist zu verstehen, was MFC hinter den Kulissen tut. In diesem Hinweis wird erläutert, wie das Framework DISPIDsMemberfunktionen und -eigenschaften zuweist. Kenntnisse des Algorithmus, den MFC zum Zuweisen von DISPIDs verwendet, sind nur erforderlich, wenn Sie die IDs kennen müssen, z. B. wenn Sie eine "Typbibliothek" für die Objekte Ihrer Anwendung erstellen.
MFC DISPID-Zuordnung
Obwohl der Endbenutzer der Automatisierung (z. B. ein Visual Basic-Benutzer) die tatsächlichen Namen der automatisierungsfähigen Eigenschaften und Methoden in ihrem Code (z. B. obj) sieht. ShowWindow), die Implementierung von IDispatch::Invoke
erhält nicht die tatsächlichen Namen. Aus Optimierungsgründen erhält es eine DISPID, die ein 32-Bit-"Magisches Cookie" ist, das die Methode oder Eigenschaft beschreibt, auf die zugegriffen werden soll. Diese DISPID-Werte werden von der IDispatch
Implementierung über eine andere Methode zurückgegeben, die aufgerufen wird IDispatch::GetIDsOfNames
. Eine Automatisierungsclientanwendung ruft GetIDsOfNames
einmal für jedes Element oder jede Eigenschaft auf, auf das bzw. die sie zugreifen möchten, und speichert sie für spätere Aufrufe zwischen IDispatch::Invoke
. Auf diese Weise erfolgt die teure Zeichenfolgensuche nur einmal pro Objektverwendung statt einmal pro IDispatch::Invoke
Aufruf.
MFC bestimmt die DISPIDfür jede Methode und Eigenschaft basierend auf zwei Dingen:
Der Abstand vom oberen Rand der Verteilerkarte (1 relativ)
Der Abstand der Verteilerzuordnung von der abgeleiteten Klasse (0 relativ)
Die DISPID ist in zwei Teile unterteilt. Die LOWORD der DISPID enthält die erste Komponente, den Abstand vom oberen Rand der Verteilerkarte. Das HIWORD enthält den Abstand von der am häufigsten abgeleiteten Klasse. Beispiel:
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()
Wie Sie sehen können, gibt es zwei Klassen, die beide OLE-Automatisierungsschnittstellen verfügbar machen. Eine dieser Klassen wird von der anderen abgeleitet und nutzt somit die Funktionalität der Basisklasse, einschließlich der OLE-Automatisierungskomponente ("x" und "y"-Eigenschaften in diesem Fall).
MFC generiert DISPIDs für die Klasse CDispPoint wie folgt:
property X (DISPID)0x00000001
property Y (DISPID)0x00000002
Da sich die Eigenschaften nicht in einer Basisklasse befinden, ist das HIWORD der DISPID immer null (der Abstand von der am häufigsten abgeleiteten Klasse für CDispPoint ist Null).
MFC generiert DISPIDs für die Klasse CDisp3DPoint wie folgt:
property Z (DISPID)0x00000001
property X (DISPID)0x00010001
property Y (DISPID)0x00010002
Die Z-Eigenschaft erhält eine DISPID mit null HIWORD , da sie in der Klasse definiert ist, die die Eigenschaften verfügbar macht, CDisp3DPoint. Da die X- und Y-Eigenschaften in einer Basisklasse definiert sind, ist das HIWORD der DISPID 1, da die Klasse, in der diese Eigenschaften definiert werden, in einem Abstand von einer Ableitung von der abgeleiteten Klasse liegt.
Hinweis
Der LOWORD wird immer durch die Position in der Karte bestimmt, auch wenn einträge in der Karte mit expliziter DISPID vorhanden sind (informationen zu den _ID Versionen und DISP_PROPERTY
DISP_FUNCTION
Makros finden Sie im nächsten Abschnitt).
Erweiterte MFC Dispatch Map-Features
Es gibt eine Reihe zusätzlicher Features, die ClassWizard mit dieser Version von Visual C++ nicht unterstützt. ClassWizard unterstützt DISP_FUNCTION
, DISP_PROPERTY
und DISP_PROPERTY_EX
definiert eine Methode, Membervariablen-Eigenschaft bzw. get/set Member-Funktionseigenschaft. Diese Funktionen sind in der Regel alle, die zum Erstellen der meisten Automatisierungsserver erforderlich sind.
Die folgenden zusätzlichen Makros können verwendet werden, wenn die von ClassWizard unterstützten Makros nicht ausreichend sind: DISP_PROPERTY_NOTIFY
und DISP_PROPERTY_PARAM
.
DISP_PROPERTY_NOTIFY – Makrobeschreibung
DISP_PROPERTY_NOTIFY(
theClass,
pszName,
memberName,
pfnAfterSet,
vtPropType)
Parameter
theClass
Name der Klasse.
pszName
Externer Name der Eigenschaft.
Membername
Name der Membervariable, in der die Eigenschaft gespeichert wird.
pfnAfterSet
Name der Memberfunktion, die aufgerufen werden soll, wenn die Eigenschaft geändert wird.
vtPropType
Ein Wert, der den Typ der Eigenschaft angibt.
Hinweise
Dieses Makro ähnelt DISP_PROPERTY, außer dass es ein zusätzliches Argument akzeptiert. Das zusätzliche Argument pfnAfterSet sollte eine Memberfunktion sein, die nichts zurückgibt und keine Parameter akzeptiert, 'void OnPropertyNotify()'. Sie wird aufgerufen , nachdem die Membervariable geändert wurde.
DISP_PROPERTY_PARAM – Makrobeschreibung
DISP_PROPERTY_PARAM(
theClass,
pszName,
pfnGet,
pfnSet,
vtPropType,
vtsParams)
Parameter
theClass
Name der Klasse.
pszName
Externer Name der Eigenschaft.
memberGet
Name der Memberfunktion, die zum Abrufen der Eigenschaft verwendet wird.
memberSet
Name der Memberfunktion, die zum Festlegen der Eigenschaft verwendet wird.
vtPropType
Ein Wert, der den Typ der Eigenschaft angibt.
vtsParams
Eine Zeichenfolge mit leerer VTS_ für jeden Parameter.
Hinweise
Ähnlich wie das DISP_PROPERTY_EX Makro definiert dieses Makro eine Eigenschaft, auf die mit separaten Funktionen "Abrufen" und "Festlegen" zugegriffen wird. Mit diesem Makro können Sie jedoch eine Parameterliste für die Eigenschaft angeben. Dies ist nützlich für die Implementierung von Eigenschaften, die auf andere Weise indiziert oder parametrisiert werden. Die Parameter werden immer zuerst platziert, gefolgt vom neuen Wert für die Eigenschaft. Beispiel:
DISP_PROPERTY_PARAM(CMyObject, "item", GetItem, SetItem, VT_DISPATCH, VTS_I2 VTS_I2)
entspricht dem Abrufen und Festlegen von Memberfunktionen:
LPDISPATCH CMyObject::GetItem(short row, short col)
void CMyObject::SetItem(short row, short col, LPDISPATCH newValue)
DISP_XXXX_ID – Makrobeschreibungen
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)
Parameter
theClass
Name der Klasse.
pszName
Externer Name der Eigenschaft.
Dispid
Die feste DISPID für die Eigenschaft oder Methode.
pfnGet
Name der Memberfunktion, die zum Abrufen der Eigenschaft verwendet wird.
pfnSet
Name der Memberfunktion, die zum Festlegen der Eigenschaft verwendet wird.
Membername
Der Name der Membervariable, die der Eigenschaft zugeordnet werden soll
vtPropType
Ein Wert, der den Typ der Eigenschaft angibt.
vtsParams
Eine Zeichenfolge mit leerer VTS_ für jeden Parameter.
Hinweise
Mit diesen Makros können Sie eine DISPID angeben, anstatt MFC automatisch zuweisen zu lassen. Diese erweiterten Makros haben dieselben Namen, mit der Ausnahme, dass die ID an den Makronamen angefügt wird (z. B. DISP_PROPERTY_ID), und die ID wird durch den Parameter bestimmt, der direkt nach dem pszName-Parameter angegeben wurde. Siehe AFXDISP. H für weitere Informationen zu diesen Makros. Die _ID Einträge müssen am Ende der Verteilerkarte platziert werden. Sie wirken sich auf die automatische DISPID-Generierung auf die gleiche Weise wie eine nicht _ID Version des Makros aus (die DISPID-Elementewerden durch Position bestimmt). Beispiel:
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 generiert DISPIDs für die Klasse CDisp3DPoint wie folgt:
property X (DISPID)0x00020003
property Y (DISPID)0x00000002
property Z (DISPID)0x00000001
Das Angeben einer festen DISPID ist nützlich, um die Abwärtskompatibilität mit einer zuvor vorhandenen Verteilerschnittstelle zu Standard oder bestimmte systemdefinierte Methoden oder Eigenschaften zu implementieren (in der Regel durch eine negative DISPID angegeben, z. B. die DISPID_NEWENUM-Auflistung).
Abrufen der IDispatch-Schnittstelle für ein COleClientItem
Viele Server unterstützen die Automatisierung innerhalb ihrer Dokumentobjekte sowie die OLE-Serverfunktionalität. Um Zugriff auf diese Automatisierungsschnittstelle zu erhalten, ist es notwendig, direkt auf die COleClientItem::m_lpObject
Membervariable zuzugreifen. Der folgende Code ruft die IDispatch
Schnittstelle für ein objekt ab, das von COleClientItem
. Sie können den folgenden Code in Ihre Anwendung einschließen, wenn Sie diese Funktionalität benötigen:
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;
}
Die von dieser Funktion zurückgegebene Verteilerschnittstelle kann dann direkt verwendet oder an einen COleDispatchDriver
typsicheren Zugriff angefügt werden. Wenn Sie es direkt verwenden, stellen Sie sicher, dass Sie das Release
Element beim Durchlaufen mit dem Zeiger aufrufen (der COleDispatchDriver
Destruktor führt dies standardmäßig aus).
Siehe auch
Technische Hinweise – nach Nummern geordnet
Technische Hinweise – nach Kategorien geordnet