Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Verfügbarmachen von .NET-Typen für COM
Wenn Sie Typen in einer Assembly für COM-Anwendungen verfügbar machen möchten, berücksichtigen Sie die Anforderungen der COM-Interoperabilität zur Entwurfszeit. Verwaltete Typen (Klasse, Schnittstelle, Struktur und Enumeration) lassen sich nahtlos in COM-Typen integrieren, wenn Sie die folgenden Richtlinien einhalten:
Klassen sollten Schnittstellen explizit implementieren.
Obwohl COM-Interop einen Mechanismus zum automatischen Generieren einer Schnittstelle mit allen Membern der Klasse und den Membern der Basisklasse bereitstellt, ist es wesentlich besser, explizite Schnittstellen bereitzustellen. Die automatisch generierte Schnittstelle wird als Klassenschnittstelle bezeichnet. Richtlinien finden Sie unter Einführung in die Klassenschnittstelle.
Sie können Visual Basic, C# und C++ verwenden, um Schnittstellendefinitionen in Ihren Code zu integrieren, anstatt die Schnittstellendefinitionssprache (Interface Definition Language, IDL) oder dessen Entsprechung zu verwenden. Ausführliche Informationen zur Syntax finden Sie in der Sprachdokumentation.
Verwaltete Typen müssen öffentlich sein.
Nur öffentliche Typen in einer Assembly werden registriert und in die Typbibliothek exportiert. Daher sind nur öffentliche Typen für COM sichtbar.
Verwaltete Typen machen Features für anderen verwalteten Code verfügbar, der möglicherweise nicht für COM verfügbar gemacht wird. Parameterisierte Konstruktoren, statische Methoden und Konstantenfelder werden beispielsweise nicht für COM-Clients verfügbar gemacht. Wenn die Laufzeit Daten in und außerhalb eines Typs marshallt, werden die Daten möglicherweise kopiert oder transformiert.
Methoden, Eigenschaften, Felder und Ereignisse müssen öffentlich sein.
Elemente öffentlicher Typen müssen auch öffentlich sein, wenn sie für COM sichtbar sein sollen. Sie können die Sichtbarkeit einer Assembly, eines öffentlichen Typs oder öffentlicher Member eines öffentlichen Typs einschränken, indem Sie die ComVisibleAttribute Standardmäßig sind alle öffentlichen Typen und Member sichtbar.
Typen müssen über einen öffentlichen parameterlosen Konstruktor verfügen, der von COM aktiviert werden soll.
Verwaltete, öffentliche Typen sind für COM sichtbar. Ohne einen öffentlichen parameterlosen Konstruktor (ein Konstruktor ohne Argumente) können COM-Clients den Typ jedoch nicht erstellen. COM-Clients können den Typ weiterhin verwenden, wenn er auf andere Arten aktiviert wird.
Typen können nicht abstrakt sein.
Weder COM-Clients noch .NET-Clients können abstrakte Typen erstellen.
Beim Export in COM wird die Vererbungshierarchie eines verwalteten Typs vereinfacht. Die Versionsverwaltung unterscheidet sich auch zwischen verwalteten und nicht verwalteten Umgebungen. Für COM verfügbar gemachte Typen weisen nicht dieselben Versionsverwaltungsmerkmale wie andere verwaltete Typen auf.
Verwenden von COM-Typen aus .NET
Wenn Sie COM-Typen von .NET verwenden möchten und keine Tools wie Tlbimp.exe (Type Library Importer) verwenden möchten, müssen Sie die folgenden Richtlinien befolgen:
- Schnittstellen müssen angewendet werden ComImportAttribute .
- Schnittstellen müssen mit der Schnittstellen-ID für die COM-Schnittstelle angewendet werden GuidAttribute .
- Schnittstellen sollten angewendet werden InterfaceTypeAttribute , um den Basisschnittstellentyp dieser Schnittstelle (
IUnknown,IDispatchoderIInspectable) anzugeben.- Die Standardoption besteht darin, den Basistyp der
IDispatchdeklarierten Methoden an die erwartete virtuelle Funktionstabelle für die Schnittstelle anzufügen. - Nur .NET Framework unterstützt die Angabe eines Basistyps von
IInspectable.
- Die Standardoption besteht darin, den Basistyp der
Diese Richtlinien enthalten die Mindestanforderungen für allgemeine Szenarien. Viele weitere Anpassungsoptionen sind vorhanden und werden unter Anwenden von Interopattributen beschrieben.
Definieren von COM-Schnittstellen in .NET
Wenn .NET-Code versucht, eine Methode für ein COM-Objekt über eine Schnittstelle mit dem ComImportAttribute Attribut aufzurufen, muss eine virtuelle Funktionstabelle (auch als vtable oder vftable bezeichnet) erstellt werden, um die .NET-Definition der Schnittstelle zu bilden, um den systemeigenen Code zu bestimmen, der aufgerufen werden soll. Dieser Prozess ist komplex. Die folgenden Beispiele zeigen einige einfache Fälle.
Betrachten Sie eine COM-Schnittstelle mit einigen Methoden:
struct IComInterface : public IUnknown
{
STDMETHOD(Method)() = 0;
STDMETHOD(Method2)() = 0;
};
Für diese Schnittstelle beschreibt die folgende Tabelle das Layout der Virtuellen Funktionstabelle:
IComInterface Tabellenplatz für virtuelle Funktionen |
Methodenname |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface::Method |
| 4 | IComInterface::Method2 |
Jede Methode wird der virtuellen Funktionstabelle in der Reihenfolge hinzugefügt, in der sie deklariert wurde. Die bestimmte Reihenfolge wird vom C++-Compiler definiert, aber für einfache Fälle ohne Überladungen definiert die Deklarationsreihenfolge die Reihenfolge in der Tabelle.
Deklarieren Sie eine .NET-Schnittstelle, die dieser Schnittstelle wie folgt entspricht:
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid(/* The IID for IComInterface */)]
interface IComInterface
{
void Method();
void Method2();
}
Die InterfaceTypeAttribute Basisschnittstelle wird angegeben. Es bietet einige Optionen:
| ComInterfaceType-Wert | Basisschnittstellentyp | Verhalten für Elemente auf der zugeordneten Schnittstelle |
|---|---|---|
InterfaceIsIUnknown |
IUnknown |
Die Virtuelle Funktionstabelle verfügt zuerst über die Member von IUnknown, dann die Member dieser Schnittstelle in Deklarationsreihenfolge. |
InterfaceIsIDispatch |
IDispatch |
Elemente werden der Virtuellen Funktionstabelle nicht hinzugefügt. Sie sind nur über IDispatchdie App zugänglich. |
InterfaceIsDual |
IDispatch |
Die Virtuelle Funktionstabelle verfügt zuerst über die Member von IDispatch, dann die Member dieser Schnittstelle in Deklarationsreihenfolge. |
InterfaceIsIInspectable |
IInspectable |
Die Virtuelle Funktionstabelle verfügt zuerst über die Member von IInspectable, dann die Member dieser Schnittstelle in Deklarationsreihenfolge. Wird nur in .NET Framework unterstützt. |
COM-Schnittstellenvererbung und .NET
Das COM-Interoperabilitätssystem, das die ComImportAttribute Schnittstellevererbung verwendet, interop, kann daher unerwartetes Verhalten verursachen, es sei denn, einige Milderungsschritte werden ausgeführt.
Der COM-Quellgenerator, der das System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute Attribut verwendet, interagiert mit der Schnittstellenvererbung, sodass es sich besser wie erwartet verhält.
COM-Schnittstellenvererbung in C++
In C++ können Entwickler COM-Schnittstellen deklarieren, die von anderen COM-Schnittstellen wie folgt abgeleitet werden:
struct IComInterface : public IUnknown
{
STDMETHOD(Method)() = 0;
STDMETHOD(Method2)() = 0;
};
struct IComInterface2 : public IComInterface
{
STDMETHOD(Method3)() = 0;
};
Dieser Deklarationsstil wird regelmäßig als Mechanismus zum Hinzufügen von Methoden zu COM-Objekten verwendet, ohne vorhandene Schnittstellen zu ändern. Dies wäre eine bedeutende Änderung. Dieser Vererbungsmechanismus führt zu den folgenden Layouts der virtuellen Funktionstabelle:
IComInterface Tabellenplatz für virtuelle Funktionen |
Methodenname |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface::Method |
| 4 | IComInterface::Method2 |
IComInterface2 Tabellenplatz für virtuelle Funktionen |
Methodenname |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface::Method |
| 4 | IComInterface::Method2 |
| 5 | IComInterface2::Method3 |
Daher ist es einfach, eine IComInterface methode aufzurufen, die aus einer .IComInterface2* Insbesondere das Aufrufen einer Methode auf einer Basisschnittstelle erfordert keinen Aufruf, um QueryInterface einen Zeiger auf die Basisschnittstelle abzurufen. Darüber hinaus ermöglicht C++ eine implizite Konvertierung von IComInterface2* zu IComInterface*, die gut definiert ist, und ermöglicht es Ihnen, einen QueryInterface erneuten Aufruf zu vermeiden. Daher müssen Sie in C oder C++ niemals aufrufen QueryInterface , um zum Basistyp zu gelangen, wenn Sie nicht möchten, was einige Leistungsverbesserungen ermöglichen kann.
Hinweis
WinRT-Schnittstellen folgen diesem Vererbungsmodell nicht. Sie sind so definiert, dass sie demselben Modell entsprechen wie das [ComImport]-basierte COM-Interoperabilitätsmodell in .NET.
Schnittstellenvererbung mit ComImportAttribute
In .NET ist C#-Code, der wie die Schnittstellenvererbung aussieht, eigentlich keine Schnittstellenvererbung. Beachten Sie den folgenden Code:
interface I
{
void Method1();
}
interface J : I
{
void Method2();
}
Dieser Code sagt nicht, "J implementiert I." Der Code sagt tatsächlich, "jeder Typ, der implementiert J , muss auch implementiert werden I." Dieser Unterschied führt zu der grundlegenden Entwurfsentscheidung, die die Schnittstellenvererbung in ComImportAttribute-basierten Interop unergonomisch macht. Schnittstellen werden immer allein betrachtet; Die Basisschnittstellenliste einer Schnittstelle hat keine Auswirkungen auf Berechnungen, um eine virtuelle Funktionstabelle für eine bestimmte .NET-Schnittstelle zu ermitteln.
Daher führt das natürliche Äquivalent des vorherigen C++-COM-Schnittstellenbeispiels zu einem anderen Layout einer virtuellen Funktionstabelle.
C#-Code:
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface
{
void Method();
void Method2();
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface2 : IComInterface
{
void Method3();
}
Layouts für virtuelle Funktionstabellen:
IComInterface Tabellenplatz für virtuelle Funktionen |
Methodenname |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface::Method |
| 4 | IComInterface::Method2 |
IComInterface2 Tabellenplatz für virtuelle Funktionen |
Methodenname |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface2::Method3 |
Da sich diese virtuellen Funktionstabellen vom C++-Beispiel unterscheiden, führt dies zur Laufzeit zu schwerwiegenden Problemen. Die richtige Definition dieser Schnittstellen in .NET lautet ComImportAttribute wie folgt:
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface
{
void Method();
void Method2();
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface2 : IComInterface
{
new void Method();
new void Method2();
void Method3();
}
Auf Metadatenebene wird nicht implementiertIComInterface2, sondern nur angegeben, IComInterface dass Implementierungen IComInterface2 auch implementiert IComInterfacewerden müssen. Daher muss jede Methode aus den Basisschnittstellentypen neu deklariert werden.
Schnittstellenvererbung mit GeneratedComInterfaceAttribute (.NET 8 und höher)
Der COM-Quellgenerator, der durch die Implementierung der GeneratedComInterfaceAttribute C#-Schnittstellenvererbung als COM-Schnittstellenvererbung ausgelöst wird, sodass die virtuellen Funktionstabellen erwartungsgemäß angeordnet sind. Wenn Sie das vorherige Beispiel verwenden, lautet die richtige Definition dieser Schnittstellen in .NET System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute wie folgt:
[GeneratedComInterface]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface
{
void Method();
void Method2();
}
[GeneratedComInterface]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IComInterface2 : IComInterface
{
void Method3();
}
Die Methoden der Basisschnittstellen müssen nicht neu deklariert werden und sollten nicht neu deklariert werden. In der folgenden Tabelle werden die resultierenden Tabellen für virtuelle Funktionen beschrieben:
IComInterface Tabellenplatz für virtuelle Funktionen |
Methodenname |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface::Method |
| 4 | IComInterface::Method2 |
IComInterface2 Tabellenplatz für virtuelle Funktionen |
Methodenname |
|---|---|
| 0 | IUnknown::QueryInterface |
| 1 | IUnknown::AddRef |
| 2 | IUnknown::Release |
| 3 | IComInterface::Method |
| 4 | IComInterface::Method2 |
| 5 | IComInterface2::Method3 |
Wie Sie sehen können, stimmen diese Tabellen mit dem C++-Beispiel überein, sodass diese Schnittstellen ordnungsgemäß funktionieren.