Share via


Einen Überblick über die verwaltete/nicht verwaltete Codeinteroperabilität

 

Sonja Keserovic, Programmmanagerin
David Mortenson, Leitender Software-Konstrukteur
Adam Nathan, Leitender Softwareentwurfstechniker im Test

Microsoft Corporation

Oktober 2003

Gilt für:
   Microsoft® .NET Framework
   COM-Interop

Zusammenfassung: Dieser Artikel enthält grundlegende Fakten zur Interoperabilität zwischen verwaltetem und nicht verwaltetem Code sowie Richtlinien und gängige Methoden für den Zugriff auf und das Umschließen nicht verwalteter API aus verwaltetem Code und zum Verfügbarmachen verwalteter APIs für nicht verwaltete Aufrufer. Sicherheits- und Zuverlässigkeitsüberlegungen, Leistungsdaten und allgemeine Methoden für Entwicklungsprozesse werden ebenfalls hervorgehoben. (14 gedruckte Seiten)

Voraussetzungen: Die Zielgruppe für dieses Dokument umfasst Entwickler und Manager, die allgemeine Entscheidungen darüber treffen müssen, wo verwalteter Code verwendet werden soll. Um dies zu tun, ist es hilfreich, zu verstehen, wie die Interaktion zwischen verwaltetem und nicht verwaltetem Code funktioniert und wie die aktuellen Richtlinien für bestimmte Szenarien gelten.

Inhalte

Einführung in die Interoperabilität
Interoperabilitätsrichtlinien
Sicherheit
Zuverlässigkeit
Leistung
Anhang 1: Überschreiten der Interoperabilitätsgrenze
Anhang 2: Ressourcen
Anhang 3: Glossar der Begriffe

Einführung in die Interoperabilität

Die Common Language Runtime (CLR) fördert die Interaktion von verwaltetem Code mit COM-Komponenten, COM+-Diensten, der Win32-API® und anderen Arten von nicht verwaltetem Code. Datentypen, Fehlerbehandlungsmechanismen, Erstellungs- und Zerstörungsregeln und Entwurfsrichtlinien variieren zwischen verwalteten und nicht verwalteten Objektmodellen. Um die Zusammenarbeit zwischen verwaltetem und nicht verwaltetem Code zu vereinfachen und den Migrationspfad zu vereinfachen, verdeckt die CLR-Interopschicht die Unterschiede zwischen diesen Objektmodellen sowohl auf Clients als auch auf Servern.

Die Interoperabilität ("interop") ist bidirektional und ermöglicht Folgendes:

  • Aufrufen nicht verwalteter APIs aus verwaltetem Code

    Dies kann sowohl für flache APIs (statische DLL-Exporte, z. B. die Win32-API, die über DLLs wie kernel32.dll und user32.dll verfügbar gemacht wird) als auch für COM-APIs (Objektmodelle, wie sie von Microsoft® Word, Excel, Internet Explorer, ActiveX® Data Objects (ADO) usw. verfügbar gemacht werden.

  • Verfügbarmachen von verwalteten APIs für nicht verwalteten Code

    Beispiele hierfür sind das Erstellen eines Add-Ins für eine COM-basierte Anwendung wie Windows Media® Player oder das Einbetten eines verwalteten Windows Forms-Steuerelements in einem MFC-Formular.

Drei sich ergänzende Technologien ermöglichen diese verwalteten/nicht verwalteten Interaktionen:

  • Platform Invoke (manchmal auch als P/Invoke bezeichnet) ermöglicht das Aufrufen einer Beliebigen Funktion in einer nicht verwalteten Sprache, solange ihre Signatur im verwalteten Quellcode neu deklariert wird. Dies ähnelt der Funktionalität, die von der Declare Anweisung in Visual Basic® 6.0 bereitgestellt wurde.
  • COM-Interop ermöglicht das Aufrufen von COM-Komponenten in einer beliebigen verwalteten Sprache ähnlich der Verwendung normaler verwalteter Komponenten und umgekehrt. COM-Interop besteht aus kernigen Diensten, die von der CLR bereitgestellt werden, sowie einigen Tools und APIs im System.Runtime.InteropServices-Namespace .
  • C++-Interop (manchmal auch als It Just Works (IJW) bezeichnet) ist ein C++-spezifisches Feature, mit dem flache APIs und COM-APIs direkt verwendet werden können, da sie immer verwendet wurden. Dies ist leistungsstärker als COM-Interop, erfordert aber viel mehr Sorgfalt. Überprüfen Sie die C++-Ressourcen, bevor Sie diese Technologie verwenden.

Interoperabilitätsrichtlinien

Aufrufen nicht verwalteter APIs aus verwaltetem Code

Es gibt verschiedene Arten von nicht verwalteten APIs und verschiedene Arten von Interop-Technologien, die für den Aufruf dieser APIs verfügbar sind. Vorschläge zur Verwendung dieser Technologien werden in diesem Abschnitt beschrieben. Bitte beachten Sie, dass diese Vorschläge sehr allgemein sind und nicht jedes Szenario abdecken. Sie sollten Ihre Szenarien sorgfältig auswerten und Entwicklungsmethoden und/oder Lösungen anwenden, die für Ihr Szenario sinnvoll sind.

Aufrufen nicht verwalteter flacher APIs

Es gibt zwei Mechanismen zum Aufrufen von nicht verwalteten flat-APIs aus verwaltetem Code: über Platform Invoke (verfügbar in allen verwalteten Sprachen) oder über C++-Interop (verfügbar in C++).

Bevor Sie sich entscheiden, eine flat-API mit einer dieser Interoptechnologien aufzurufen, sollten Sie bestimmen, ob im .NET Framework gleichwertige Funktionen verfügbar sind. Es wird empfohlen, nach Möglichkeit .NET Framework Funktionalität zu verwenden, anstatt nicht verwaltete APIs aufzurufen.

Wenn Sie nur einige nicht verwaltete Methoden aufrufen oder einfache flache APIs aufrufen möchten, empfiehlt es sich, anstelle von C++-Interop den Plattformaufruf zu verwenden. Das Schreiben von Plattformaufrufdeklarationen für einfache flache APIs ist einfach. Die CLR kümmert sich um das Laden der DLL und das gesamte Parameter marshaling. Selbst das Schreiben einiger Plattformaufrufdeklarationen für komplexe flache APIs ist vernachlässigbar im Vergleich zu den Kosten für die Verwendung von C++-Interop und der Einführung eines völlig neuen Moduls, das in C++ geschrieben wurde.

Zum Umschließen komplexer, nicht verwalteter flacher APIs oder zum Umschließen nicht verwalteter flacher APIs, die sich ändern, während verwalteter Code gerade entwickelt wird, empfiehlt es sich, C++-Interop anstelle des Plattformaufrufs zu verwenden. Die C++-Ebene kann sehr dünn sein, und der rest des verwalteten Codes kann in jeder anderen verwalteten Sprache ihrer Wahl geschrieben werden. Die Verwendung von Plattformaufrufen in diesen Szenarien erfordert viel Aufwand, um komplexe Teile der API in verwaltetem Code neu zu deklarieren und mit den nicht verwalteten APIs synchron zu halten. Die Verwendung von C++-Interop löst dieses Problem, indem der direkte Zugriff auf nicht verwaltete APIs gewährt wird. Dies erfordert keine Neuschreibung, nur die Aufnahme einer Headerdatei.

Aufrufen von COM-APIs

Es gibt zwei Möglichkeiten, COM-Komponenten aus verwaltetem Code aufzurufen: über COM-Interop (verfügbar in allen verwalteten Sprachen) oder über C++-Interop (verfügbar in C++).

Zum Aufrufen von OLE Automation-kompatiblen COM-Komponenten empfiehlt es sich, COM-Interop zu verwenden. Die CLR übernimmt die Aktivierung von COM-Komponenten und das Marshallen von Parametern.

Für das Aufrufen von COM-Komponenten, die auf IDL (Interface Definition Language) basieren, empfiehlt es sich, C++-Interop zu verwenden. Die C++-Ebene kann sehr dünn sein, und der Rest des verwalteten Codes kann in jeder verwalteten Sprache geschrieben werden. COM-Interop basiert auf Informationen aus Typbibliotheken, um korrekte Interopaufrufe auszuführen, aber Typbibliotheken enthalten in der Regel nicht alle Informationen, die in IDL-Dateien vorhanden sind. Die Verwendung von C++-Interop löst dieses Problem, indem der direkte Zugriff auf diese COM-APIs gewährt wird.

Für Unternehmen, die bereits ausgelieferte COM-APIs besitzen, ist es wichtig, den Versand primärer Interopassemblys (PIAs) für diese APIs in Erwägung zu ziehen, um sie einfach für verwaltete Clients zu nutzen.

Entscheidungsstruktur für das Aufrufen nicht verwalteter APIs

Abbildung 1. Aufrufen der Entscheidungsstruktur für nicht verwaltete APIs

Verfügbarmachen verwalteter APIs für nicht verwalteten Code

Es gibt zwei Standard Möglichkeiten, eine verwaltete API für rein nicht verwaltete Aufrufer verfügbar zu machen: als COM-API oder als flache API. Für nicht verwaltete C++-Clients, die bereit sind, ihren Code mit Visual Studio® .NET neu zu kompilieren, gibt es eine dritte Option: direkten Zugriff auf verwaltete Funktionen über C++-Interop. Vorschläge für die Verwendung dieser Optionen werden in diesem Abschnitt beschrieben.

Direkter Zugriff auf eine verwaltete API

Wenn ein nicht verwalteter Client in C++ geschrieben wird, kann er mit dem Visual Studio .NET C++-Compiler als "Image im gemischten Modus" kompiliert werden. Danach kann der nicht verwaltete Client direkt auf jede verwaltete API zugreifen. Einige Codierungsregeln gelten jedoch für den Zugriff auf verwaltete Objekte aus nicht verwaltetem Code. Weitere Informationen finden Sie in der C++-Dokumentation.

Der direkte Zugriff ist die bevorzugte Option, da sie keine besondere Berücksichtigung durch verwaltete API-Entwickler erfordert. Sie können ihre verwaltete API gemäß den Richtlinien für das Design der verwalteten API (DG) entwerfen und sicher sein, dass die API weiterhin für nicht verwaltete Aufrufer zugänglich sein wird.

Verfügbarmachen einer verwalteten API als COM-API

Jede öffentliche verwaltete Klasse kann über COM-Interop für nicht verwaltete Clients verfügbar gemacht werden. Dieser Prozess ist sehr einfach zu implementieren, da die COM-Interopschicht alle COM-Sanitäranlagen übernimmt. So scheint beispielsweise jede verwaltete Klasse IUnknown, IDispatch, ISupportErrorInfo und einige andere COM-Standardschnittstellen zu implementieren.

Obwohl die Offenlegung verwalteter APIs als COM-APIs einfach ist, unterscheiden sich verwaltete und COM-Objektmodelle sehr. Daher sollte die Offenlegung der verwalteten API für COM immer eine explizite Entwurfsentscheidung sein. Einige Features, die in der verwalteten Welt verfügbar sind, verfügen über keine Entsprechung in der COM-Welt und können von COM-Clients nicht verwendet werden. Aus diesem Grund gibt es häufig Spannungen zwischen den Richtlinien für den Entwurf verwalteter API (DG) und der Kompatibilität mit COM.

Wenn COM-Clients wichtig sind, schreiben Sie Ihre verwaltete API gemäß den Entwurfsrichtlinien für verwaltete API, und schreiben Sie dann einen schlanken COM-freundlichen verwalteten Wrapper um Ihre verwaltete API, der für COM verfügbar gemacht wird.

Verfügbarmachen einer verwalteten API als flat-API

Manchmal können nicht verwaltete Clients COM nicht verwenden. Sie können beispielsweise bereits für die Verwendung von flachen APIs geschrieben und nicht geändert oder neu kompiliert werden. C++ ist die einzige allgemeine Sprache, mit der Sie verwaltete APIs als flache APIs verfügbar machen können. Dies ist nicht so einfach wie das Verfügbarmachen einer verwalteten API als COM-API. Es handelt sich um eine sehr fortgeschrittene Technik, die erweiterte Kenntnisse der C++-Interop und der Unterschiede zwischen der verwalteten und nicht verwalteten Welt erfordert.

Machen Sie Ihre verwaltete API nur dann als flache API verfügbar, wenn dies unbedingt erforderlich ist. Wenn Sie keine Wahl haben, überprüfen Sie die C++-Dokumentation, und beachten Sie alle Einschränkungen.

Entscheidungsstruktur zum Verfügbarmachen verwalteter APIs

Abbildung 2. Entscheidungsstruktur für verwaltete APIs verfügbar

Sicherheit

Die Common Language Runtime wird mit dem Sicherheitssystem Code Access Security (CAS) ausgeliefert, das den Zugriff auf geschützte Ressourcen basierend auf Informationen über den Ursprung einer Assembly regelt. Das Aufrufen von nicht verwaltetem Code stellt ein großes Sicherheitsrisiko dar. Ohne entsprechende Sicherheitsüberprüfungen könnte nicht verwalteter Code jeden Zustand einer verwalteten Anwendung im CLR-Prozess ändern. Es ist auch möglich, Ressourcen im nicht verwalteten Code direkt aufzurufen, ohne dass diese Ressourcen cas-Berechtigungsprüfungen unterliegen. Aus diesem Grund wird jeder Übergang zu nicht verwaltetem Code als hochgradig geschützter Vorgang betrachtet und sollte eine Sicherheitsüberprüfung enthalten. Diese Sicherheitsüberprüfung sucht nach der nicht verwalteten Codeberechtigung, die die Assembly erfordert, die den nicht verwalteten Codeübergang enthält, sowie nach allen Assemblys, die in sie aufrufen, um das Recht zu haben, nicht verwalteten Code tatsächlich aufzurufen.

Es gibt einige begrenzte Interop-Szenarien, in denen vollständige Sicherheitsüberprüfungen nicht erforderlich sind und die Leistung oder den Umfang der Komponente übermäßig einschränken würden. Dies ist der Fall, wenn eine Ressource, die aus nicht verwaltetem Code verfügbar gemacht wird, keine Sicherheitsrelevanz aufweist (Systemzeit, Fensterkoordinaten usw.), oder wenn die Ressource nur intern in der Assembly verwendet wird und nicht öffentlich für beliebige Aufrufer verfügbar gemacht wird. In solchen Fällen können Sie die vollständige Sicherheitsüberprüfung für nicht verwaltete Codeberechtigungen für alle Aufrufer der relevanten APIs unterdrücken. Hierzu wenden Sie das benutzerdefinierte SuppressUnmanagedCodeSecurity-Attribut auf die jeweilige Interop-Methode oder -Klasse an. Beachten Sie, dass hierbei von einer sorgfältigen Sicherheitsüberprüfung ausgegangen wird, bei der Sie festgestellt haben, dass kein teilweise vertrauenswürdiger Code solche APIs ausnutzen könnte.

Zuverlässigkeit

Verwalteter Code ist zuverlässiger und robuster als nicht verwalteter Code. Ein Beispiel für ein CLR-Feature, das diese Qualitäten fördert, ist die Garbage Collection, die sich um das Freigeben von nicht genutztem Arbeitsspeicher kümmert, um Speicherverluste zu verhindern. Ein weiteres Beispiel ist die Sicherheit des verwalteten Typs, die verwendet wird, um Pufferüberlauffehler und andere typbezogene Fehler zu verhindern.

Wenn Sie eine beliebige Art von Interoptechnologie verwenden, ist Ihr Code möglicherweise nicht so zuverlässig oder robust wie reiner verwalteter Code. Beispielsweise müssen Sie nicht verwalteten Arbeitsspeicher manuell zuweisen und daran denken, ihn freizugeben, wenn Sie damit fertig sind.

Das Schreiben eines nicht trivialen Interopcodes erfordert die gleiche Aufmerksamkeit auf Zuverlässigkeit und Robustheit wie das Schreiben von nicht verwaltetem Code. Selbst wenn der gesamte Interopcode korrekt geschrieben wird, ist Ihr System nur so zuverlässig wie seine nicht verwalteten Teile.

Leistung

Bei jedem Übergang von verwaltetem Code zu nicht verwaltetem Code (und umgekehrt) entsteht ein gewisser Leistungsaufwand. Der Aufwand hängt von den verwendeten Parametertypen ab. Die CLR-Interop-Schicht verwendet drei Ebenen der Interop-Aufrufoptimierung basierend auf Übergangstyp und Parametertypen: JiT-Inlining( Just-in-Time- Inlining), kompilierte Assembly-Stubs und interpretierte Marshallstumbs (in der Reihenfolge der schnellsten bis langsamsten Aufrufart).

Ungefährer Mehraufwand für einen Plattformaufruf: 10 Computeranweisungen (auf einem x86-Prozessor)

Ungefährer Mehraufwand für einen COM-Interop-Aufruf: 50 Computeranweisungen (auf einem x86-Prozessor)

Die mit diesen Anweisungen ausgeführten Arbeiten werden in den Abschnitten Aufrufen einer Flat-API: Schritt für Schritt und Aufrufen einer COM-API: Schritt für Schritt gezeigt. Neben der Sicherstellung, dass der Garbage Collector nicht verwaltete Threads während des Aufrufs blockiert und Aufrufkonventionen und nicht verwaltete Ausnahmen behandelt, übernimmt COM-Interop zusätzliche Arbeit, um den Aufruf für den aktuellen Runtime-Aufruf wrapper (RCW) in einen COM-Schnittstellenzeiger zu konvertieren, der dem aktuellen Kontext entspricht.

Jeder Interop-Aufruf führt zu einem gewissen Mehraufwand. Je nachdem, wie oft diese Aufrufe auftreten und welche Bedeutung die Arbeit innerhalb der Methodenimplementierung hat, kann der Mehraufwand pro Aufruf vernachlässigbar bis sehr spürbar sein.

Basierend auf diesen Überlegungen enthält die folgende Liste einige allgemeine Leistungsvorschläge, die Sie nützlich finden könnten:

  • Wenn Sie die Schnittstelle zwischen verwaltetem und nicht verwaltetem Code steuern, stellen Sie sie "chunky" und nicht "chatty" fest, um die Gesamtzahl der durchgeführten Übergänge zu verringern.

    Chatte Schnittstellen sind Schnittstellen, die viele Übergänge machen, ohne auf der anderen Seite der Interop-Grenze erhebliche Arbeit zu leisten. Eigenschaftssetter und Getter sind z. B. chattend. Chunky-Schnittstellen sind Schnittstellen, die nur wenige Übergänge machen, und der Arbeitsaufwand auf der anderen Seite der Grenze ist erheblich. Beispielsweise ist eine Methode, die eine Datenbankverbindung öffnet und einige Daten abruft, blockig. Chunky-Schnittstellen erfordern weniger Interop-Übergänge, sodass Sie einen gewissen Leistungsaufwand vermeiden.

  • Vermeiden Sie nach Möglichkeit Unicode/ANSI-Konvertierungen.

    Das Konvertieren von Zeichenfolgen von Unicode in ANSI und umgekehrt ist ein teurer Vorgang. Wenn beispielsweise Zeichenfolgen übergeben werden müssen, deren Inhalt jedoch nicht wichtig ist, können Sie einen Zeichenfolgenparameter als IntPtr deklarieren, und der Interop-Marshaller führt keine Konvertierungen durch.

  • In Hochleistungsszenarien kann das Deklarieren von Parametern und Feldern als IntPtr die Leistung steigern, allerdings auf Kosten der Benutzerfreundlichkeit und Wartbarkeit.

    Manchmal ist es schneller, manuelles Marshalling mit Methoden zu durchführen, die für die Marshal-Klasse verfügbar sind, anstatt sich auf das standardmäßige Interop-Marshalling zu verlassen. Wenn beispielsweise große Arrays von Zeichenfolgen über eine Interopgrenze übergeben werden müssen, aber nur wenige Elemente benötigt werden, ist das Deklarieren des Arrays als IntPtr und der manuelle Zugriff nur auf diese wenigen Elemente viel schneller.

  • Verwenden Sie InAttribute und OutAttribute sinnvoll, um unnötiges Marshalling zu reduzieren.

    Der Interop-Marshaller verwendet Standardregeln, wenn er entscheidet, ob ein bestimmter Parameter vor dem Aufruf gemarst und nach dem Aufruf gemarst werden muss. Diese Regeln basieren auf der Indirektierungsebene und dem Parametertyp. Einige dieser Vorgänge sind abhängig von der Semantik der Methode möglicherweise nicht erforderlich.

  • Verwenden Sie SetLastError=false auf Plattformaufrufsignaturen nur, wenn Sie Marshal.GetLastWin32Error anschließend aufrufen.

    Das Festlegen von SetLastError=true für Plattformaufrufsignaturen erfordert zusätzliche Arbeit von der Interopebene, um den letzten Fehlercode beizubehalten. Verwenden Sie dieses Feature nur, wenn Sie sich auf diese Informationen verlassen und sie nach dem Aufruf verwenden.

  • Wenn und nur, wenn nicht verwaltete Aufrufe auf nicht verwertbare Weise verfügbar gemacht werden, verwenden Sie SuppressUnmanagedCodeSecurityAttribute , um die Anzahl der Sicherheitsprüfungen zu reduzieren.

    Sicherheitsüberprüfungen sind sehr wichtig. Wenn Ihre API keine geschützten Ressourcen oder vertraulichen Informationen verfügbar macht oder diese gut geschützt sind, können umfangreiche Sicherheitsüberprüfungen unnötigen Mehraufwand verursachen. Allerdings sind die Kosten für das Nicht-Durchführen einer Sicherheitsüberprüfung sehr hoch.

Anhang 1: Überschreiten der Interoperabilitätsgrenze

Aufrufen einer Flat-API: Schritt für Schritt

Abbildung 3. Aufrufen einer Flat-API

  1. Rufen Sie LoadLibrary und GetProcAddress ab.
  2. Erstellen Sie einen DllImport-Stub aus der Signatur, die die Zieladresse enthält.
  3. Pushen Von angerufenen gespeicherten Registern.
  4. Richten Sie einen DllImport-Frame ein, und pushen Sie ihn auf den Stapel der Frames.
  5. Wenn temporärer Arbeitsspeicher zugewiesen ist, initialisieren Sie eine sauber-Up-Liste, um nach Abschluss des Aufrufs schnell freizugeben.
  6. Marshallparameter. (Dadurch könnte Arbeitsspeicher zugewiesen werden.)
  7. Ändern Sie den Garbage Collection-Modus von kooperativ in präventiv, sodass eine Garbage Collection jederzeit auftreten kann.
  8. Laden Sie die Zieladresse, und rufen Sie sie auf.
  9. Wenn das SetLastError-Bit festgelegt ist, rufen Sie GetLastError auf, und speichern Sie das Ergebnis in einer Thread-Abstraktion, die im lokalen Threadspeicher gespeichert ist.
  10. Wechseln Sie zurück zum kooperativen Garbage Collection-Modus.
  11. Wenn PreserveSig=false und die Methode einen Fehler HRESULT zurückgegeben hat, lösen Sie eine Ausnahme aus.
  12. Wenn keine Ausnahme ausgelöst wurde, werden die Parameter "Back-Propagat out " und "by-ref" zurückgegeben.
  13. Stellen Sie den erweiterten Stapelzeiger auf seinen ursprünglichen Wert wieder her, um die Argumente des Aufrufers zu berücksichtigen.

Aufrufen einer COM-API: Schritt für Schritt

Abbildung 4. Aufrufen einer COM-API

  1. Erstellen Sie einen verwalteten zu nicht verwalteten Stub aus der Signatur.
  2. Pushen Von angerufenen gespeicherten Registern.
  3. Richten Sie einen verwalteten zu nicht verwalteten COM-Interop-Frame ein, und pushen Sie ihn auf den Stapel der Frames.
  4. Reservieren Sie Speicherplatz für temporäre Daten, die während des Übergangs verwendet werden.
  5. Wenn temporärer Arbeitsspeicher zugewiesen ist, initialisieren Sie eine sauber-Up-Liste, um nach Abschluss des Aufrufs schnell freizugeben.
  6. Löschen Sie Gleitkomma-Ausnahmeflags (nur x86).
  7. Marshallparameter. (Dadurch könnte Arbeitsspeicher zugewiesen werden.)
  8. Rufen Sie den richtigen Schnittstellenzeiger für den aktuellen Kontext im Runtime Callable Wrapper ab. Wenn der zwischengespeicherte Zeiger nicht verwendet werden kann, rufen Sie QueryInterface für die COM-Komponente auf, um ihn abzurufen.
  9. Ändern Sie den Garbage Collection-Modus von kooperativ in präventiv, sodass eine Garbage Collection jederzeit auftreten kann.
  10. Indizieren Sie über den vtable-Zeiger nach der Slotnummer, rufen Sie die Zieladresse ab, und rufen Sie sie auf.
  11. Rufen Sie Release auf dem Schnittstellenzeiger auf, wenn QueryInterface zuvor aufgerufen wurde.
  12. Wechseln Sie zurück zum kooperativen Garbage Collection-Modus.
  13. Wenn die Signatur nicht als PreserveSig markiert ist, überprüfen Sie, ob HRESULT-Fehler auftritt, und lösen Sie eine Ausnahme aus (möglicherweise mit IErrorInfo-Informationen gefüllt).
  14. Wenn keine Ausnahme ausgelöst wurde, werden die Parameter "Back-Propagat out " und "by-ref" zurückgegeben.
  15. Stellen Sie den erweiterten Stapelzeiger auf den ursprünglichen Wert wieder her, um aufruferbasierte Argumente zu berücksichtigen.

Aufrufen einer verwalteten API aus COM: Schritt für Schritt

Abbildung 5. Aufrufen einer verwalteten API aus COM

  1. Erstellen Sie einen nicht verwalteten Stub aus der Signatur.
  2. Pushen Von angerufenen gespeicherten Registern.
  3. Richten Sie einen nicht verwalteten COM-Interopframe ein, und pushen Sie ihn auf den Stapel der Frames.
  4. Reservieren Sie Speicherplatz für temporäre Daten, die während des Übergangs verwendet werden.
  5. Ändern Sie den Garbage Collection-Modus vom kooperativen in den präventiven Modus, damit eine Garbage Collection jederzeit auftreten kann.
  6. Rufen Sie den COM Callable Wrapper (CCW) aus dem Schnittstellenzeiger ab.
  7. Rufen Sie das verwaltete Objekt innerhalb des CCW ab.
  8. Übergangs-Appdomänen, falls erforderlich.
  9. Wenn eine App-Domäne nicht vollständig vertrauenswürdig ist, führen Sie alle Linkanforderungen aus, die die Methode möglicherweise für die Ziel-App-Domäne hat.
  10. Wenn temporärer Arbeitsspeicher zugewiesen ist, initialisieren Sie eine sauber-Up-Liste, um nach Abschluss des Anrufs schnell freizugeben.
  11. Marshallparameter. (Dadurch kann Arbeitsspeicher zugeordnet werden.)
  12. Suchen Sie die aufzurufende zielverwaltete Methode. (Dies umfasst die Zuordnung von Schnittstellenaufrufen zur Zielimplementierung.)
  13. Den Rückgabewert zwischenspeichern. (Wenn es sich um einen Gleitkommarückgabewert handelt, rufen Sie ihn aus dem Gleitkommaregister ab.)
  14. Wechseln Sie zurück zum kooperativen Garbage Collection-Modus.
  15. Wenn eine Ausnahme ausgelöst wurde, extrahieren Sie deren HRESULT, um zurückzugeben, und rufen Sie SetErrorInfo auf.
  16. Wenn keine Ausnahme ausgelöst wurde, geben Sie die Parameter "out" und "by ref" zurück.
  17. Stellen Sie den erweiterten Stapelzeiger auf den ursprünglichen Wert wieder her, um Argumente mit Aufrufer-Pop zu berücksichtigen.

Anhang 2: Ressourcen

Muss lesen!.NET und COM: Der vollständige Interoperabilitätsleitfaden von Adam Nathan

Zusammenarbeit mit nicht verwaltetem Code, Microsoft .NET Framework Entwicklerhandbuch

Interop-Beispiele, Microsoft .NET Framework

Adam Nathans Blog

Blog von Chris Brumme

Anhang 3: Glossar der Begriffe

AppDomain (Anwendungsdomäne) Eine Anwendungsdomäne kann als vergleichbar mit einem einfachen Betriebssystemprozess angesehen werden und wird von der Common Language Runtime verwaltet.
CCW (COM callable wrapper) Eine spezielle Art von Wrapper, der von der CLR-Interopebene um verwaltete Objekte erstellt wird, die aus COM-Code aktiviert werden. Ein CCW blendet Unterschiede zwischen verwalteten und COM-Objektmodellen aus, indem Datenmarshalling, Lebensdauerverwaltung, Identitätsverwaltung, Fehlerbehandlung, richtige Apartment- und Threadingübergänge usw. bereitgestellt werden. CCWs machen verwaltete Objektfunktionen COM-freundlich verfügbar, ohne dass der Verwaltete Codeimplementierer etwas über COM-Plumbing wissen muss.
CLR Die Common Language Runtime.
COM-Interop Der Dienst, der von der CLR-Interopebene bereitgestellt wird, um COM-APIs aus verwaltetem Code zu verwenden oder verwaltete APIs als COM-APIs für nicht verwaltete Clients verfügbar zu machen. COM-Interop ist in allen verwalteten Sprachen verfügbar.
C++-Interop Der vom C++-Sprachcompiler und der CLR bereitgestellte Dienst wird zum direkten Mischen von verwaltetem und nicht verwaltetem Code in derselben ausführbaren Datei verwendet. C++-Interop umfasst in der Regel das Einschließen von Headerdateien in nicht verwalteten APIs und das Einhalten bestimmter Codierungsregeln.
Komplexe flache API APIs mit Signaturen, die in verwalteter Sprache schwer deklariert werden können. Beispielsweise sind Methoden mit Variablengrößenstrukturparametern schwierig zu deklarieren, da es kein gleichwertiges Konzept im verwalteten Typsystem gibt.
Interop Der allgemeine Begriff, der jede Art von Interoperabilität zwischen verwaltetem und nicht verwaltetem Code (auch als "systemeigener Code" bezeichnet) abdeckt. Interop ist einer von vielen Diensten, die von der CLR bereitgestellt werden.
Interopassembly Ein spezieller Typ verwalteter Assembly, der verwaltete Typäquivalente für COM-Typen enthält, die in einer Typbibliothek enthalten sind. Wird in der Regel durch Ausführen des Type Library Importer-Tools (Tlbimp.exe) für eine Typbibliothek erstellt.
Verwalteter Code Code, der unter der Kontrolle der CLR ausgeführt wird, wird als verwalteter Code bezeichnet. Beispielsweise ist jeder in C# oder Visual Basic .NET geschriebene Code verwalteter Code.
Plattformaufruf Der Dienst, der von der CLR-Interopebene zum Aufrufen nicht verwalteter flacher APIs aus verwaltetem Code bereitgestellt wird. Der Plattformaufruf ist in allen verwalteten Sprachen verfügbar.
RCW (runtime callable wapper) Eine spezielle Art von Wrapper, der von der CLR-Interopebene um COM-Objekte erstellt wird, die aus verwaltetem Code aktiviert werden. Ein RCW blendet Unterschiede zwischen verwalteten und COM-Objektmodellen aus, indem Datenmarshalling, Lebensdauerverwaltung, Identitätsverwaltung, Fehlerbehandlung, richtige Apartment- und Threadingübergänge usw. bereitgestellt werden.
Nicht verwalteter Code Code, der außerhalb der CLR ausgeführt wird, wird als "nicht verwalteter Code" bezeichnet. COM-Komponenten, ActiveX-Komponenten und Win32-API-Funktionen sind Beispiele für nicht verwalteten Code.