Erstellen eines Objekts in COM

Nachdem ein Thread die COM-Bibliothek initialisiert hat, ist es sicher, dass der Thread COM-Schnittstellen verwendet. Um eine COM-Schnittstelle zu verwenden, erstellt Ihr Programm zunächst eine instance eines Objekts, das diese Schnittstelle implementiert.

Im Allgemeinen gibt es zwei Möglichkeiten, ein COM-Objekt zu erstellen:

  • Das Modul, das das -Objekt implementiert, kann eine Funktion bereitstellen, die speziell zum Erstellen von Instanzen dieses Objekts entwickelt wurde.
  • Alternativ stellt COM eine generische Erstellungsfunktion namens CoCreateInstance bereit.

Nehmen Sie beispielsweise das hypothetische Shape Objekt aus dem Thema Was ist eine COM-Schnittstelle?. In diesem Beispiel implementiert das Shape -Objekt eine Schnittstelle namens IDrawable. Die Grafikbibliothek, die das Shape -Objekt implementiert, kann eine Funktion mit der folgenden Signatur exportieren.

// Not an actual Windows function. 

HRESULT CreateShape(IDrawable** ppShape);

Mit dieser Funktion können Sie wie folgt ein neues Shape -Objekt erstellen.

IDrawable *pShape;

HRESULT hr = CreateShape(&pShape);
if (SUCCEEDED(hr))
{
    // Use the Shape object.
}
else
{
    // An error occurred.
}

Der ppShape-Parameter ist vom Typ zeiger-to-pointer-to-IDrawable. Wenn Sie dieses Muster noch nicht gesehen haben, ist die doppelte Dereferenzierung möglicherweise verwirrend.

Berücksichtigen Sie die Anforderungen der CreateShape Funktion. Die Funktion muss einen IDrawable Zeiger zurück auf den Aufrufer geben. Der Rückgabewert der Funktion wird jedoch bereits für den Fehler-/Erfolgscode verwendet. Daher muss der Zeiger über ein Argument an die Funktion zurückgegeben werden. Der Aufrufer übergibt eine Variable vom Typ IDrawable* an die Funktion, und die Funktion überschreibt diese Variable mit einem neuen IDrawable Zeiger. In C++ gibt es nur zwei Möglichkeiten für eine Funktion, einen Parameterwert zu überschreiben: pass by reference oder pass by address. COM verwendet letzteres, pass-by-address. Und die Adresse eines Zeigers ist ein Zeiger auf einen Zeiger, sodass der Parametertyp sein IDrawable**muss.

Im Folgenden finden Sie ein Diagramm, das Ihnen helfen soll, die Vorgänge zu visualisieren.

Diagramm, das die Dereferenzierung des doppelten Zeigers zeigt

Die CreateShape Funktion verwendet die Adresse von pShape (&pShape), um einen neuen Zeigerwert in pShape zu schreiben.

CoCreateInstance: Eine generische Methode zum Erstellen von Objekten

Die CoCreateInstance-Funktion stellt einen generischen Mechanismus zum Erstellen von Objekten bereit. Beachten Sie zum Verstehen von CoCreateInstance, dass zwei COM-Objekte dieselbe Schnittstelle implementieren können und ein Objekt zwei oder mehr Schnittstellen implementieren kann. Daher benötigt eine generische Funktion, die Objekte erstellt, zwei Informationselemente.

  • Welches Objekt erstellt werden soll.
  • Welche Schnittstelle aus dem -Objekt abgerufen werden soll.

Aber wie geben wir diese Informationen an, wenn wir die Funktion aufrufen? In COM wird ein Objekt oder eine Schnittstelle identifiziert, indem ihm eine 128-Bit-Zahl zugewiesen wird, die als GUID (Globally Unique Identifier ) bezeichnet wird. GUIDs werden so generiert, dass sie effektiv eindeutig sind. GUIDs sind eine Lösung für das Problem, wie eindeutige Bezeichner ohne zentrale Registrierungsstelle erstellt werden. GUIDs werden manchmal als universelle eindeutige Bezeichner (UUIDs ) bezeichnet. Vor COM wurden sie in DCE/RPC (Distributed Computing Environment/Remote Procedure Call) verwendet. Es gibt mehrere Algorithmen zum Erstellen neuer GUIDs. Nicht alle diese Algorithmen garantieren eindeutig, aber die Wahrscheinlichkeit, versehentlich denselben GUID-Wert zweimal zu erstellen, ist extrem klein – effektiv null. GUIDs können verwendet werden, um jede Art von Entität zu identifizieren, nicht nur Objekte und Schnittstellen. Dies ist jedoch die einzige Verwendung, die uns in diesem Modul betrifft.

Die Bibliothek kann beispielsweise Shapes zwei GUID-Konstanten deklarieren:

extern const GUID CLSID_Shape;
extern const GUID IID_IDrawable; 

(Sie können davon ausgehen, dass die tatsächlichen numerischen 128-Bit-Werte für diese Konstanten an anderer Stelle definiert sind.) Die Konstante CLSID_Shape identifiziert das Shape Objekt, während die Konstante IID_IDrawable die IDrawable Schnittstelle identifiziert. Das Präfix "CLSID" steht für Klassenbezeichner, und das Präfix IID steht für Schnittstellenbezeichner. Dies sind Standardbenennungskonventionen in COM.

Unter Berücksichtigung dieser Werte würden Sie wie folgt eine neue Shape instance erstellen:

IDrawable *pShape;
hr = CoCreateInstance(CLSID_Shape, NULL, CLSCTX_INPROC_SERVER, IID_IDrawable,
     reinterpret_cast<void**>(&pShape));

if (SUCCEEDED(hr))
{
    // Use the Shape object.
}
else
{
    // An error occurred.
}

Die CoCreateInstance-Funktion verfügt über fünf Parameter. Der erste und vierte Parameter sind der Klassenbezeichner und der Schnittstellenbezeichner. Tatsächlich weisen diese Parameter die Funktion an: "Erstellen Sie das Shape-Objekt, und geben Sie mir einen Zeiger auf die IDrawable-Schnittstelle."

Legen Sie den zweiten Parameter auf NULL fest. (Weitere Informationen zur Bedeutung dieses Parameters finden Sie im Thema Aggregation in der COM-Dokumentation.) Der dritte Parameter verwendet eine Reihe von Flags, deren Standard Zweck darin besteht, den Ausführungskontext für das Objekt anzugeben. Der Ausführungskontext gibt an, ob das Objekt im gleichen Prozess wie die Anwendung ausgeführt wird. in einem anderen Prozess auf demselben Computer; oder auf einem Remotecomputer. In der folgenden Tabelle sind die gängigsten Werte für diesen Parameter aufgeführt.

Flag Beschreibung
CLSCTX_INPROC_SERVER Der gleiche Prozess.
CLSCTX_LOCAL_SERVER Anderer Prozess, gleicher Computer.
CLSCTX_REMOTE_SERVER Anderer Computer.
CLSCTX_ALL Verwenden Sie die effizienteste Option, die das -Objekt unterstützt. (Die Rangfolge, von der effizientesten bis zur geringsten Effizienz, lautet: prozessintern, out-of-process und computerübergreifend.)

 

In der Dokumentation für eine bestimmte Komponente kann angegeben werden, welcher Ausführungskontext vom Objekt unterstützt wird. Andernfalls verwenden Sie CLSCTX_ALL. Wenn Sie einen Ausführungskontext anfordern, den das Objekt nicht unterstützt, gibt die CoCreateInstance-Funktion den Fehlercode REGDB_E_CLASSNOTREG zurück. Dieser Fehlercode kann auch angeben, dass die CLSID keiner Komponente entspricht, die auf dem Computer des Benutzers registriert ist.

Der fünfte Parameter für CoCreateInstance empfängt einen Zeiger auf die Schnittstelle. Da CoCreateInstance ein generischer Mechanismus ist, kann dieser Parameter nicht stark typisiert werden. Stattdessen ist der Datentyp void**, und der Aufrufer muss die Adresse des Zeigers in einen void** -Typ umwandeln. Dies ist der Zweck der reinterpret_cast im vorherigen Beispiel.

Es ist wichtig, den Rückgabewert von CoCreateInstance zu überprüfen. Wenn die Funktion einen Fehlercode zurückgibt, ist der COM-Schnittstellenzeiger ungültig, und der Versuch, ihn zu dereferenzieren, kann dazu führen, dass Ihr Programm abstürzt.

Intern verwendet die CoCreateInstance-Funktion verschiedene Techniken, um ein Objekt zu erstellen. Im einfachsten Fall wird der Klassenbezeichner in der Registrierung nachschlagen. Der Registrierungseintrag verweist auf eine DLL oder EXE, die das -Objekt implementiert. CoCreateInstance kann auch Informationen aus einem COM+-Katalog oder einem Parallelmanifest (SxS) verwenden. Unabhängig davon sind die Details für den Aufrufer transparent. Weitere Informationen zu den internen Details von CoCreateInstance finden Sie unter COM-Clients und -Server.

Das Shapes Beispiel, das wir verwendet haben, ist etwas erfunden, daher kommen wir nun zu einem realen Beispiel für COM in Aktion: Anzeigen des Dialogfelds "Öffnen ", in dem der Benutzer eine Datei auswählen kann.

Nächste

Beispiel: Das Dialogfeld "Öffnen"