Übersicht über verwaltete/nicht verwaltete Codeinteroperabilität
Sonja Keserovic, Programmmanager
David Mortenson, Lead Software Design Engineer
Adam Prüfstand, Lead Software Design Engineer in Test
Microsoft Corporation
Oktober 2003
Gilt für:
Microsoft® .NET Framework
COM-Interoperabilität
Zusammenfassung: Dieser Artikel enthält grundlegende Fakten zur Interoperabilität zwischen verwaltetem und nicht verwaltetem Code sowie Richtlinien und allgemeinen Methoden für den Zugriff auf und umbrochene 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 auf bestimmte Szenarien angewendet werden.
Inhalt
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 Typen von nicht verwaltetem Code. Datentypen, Fehlerbehandlungsmechanismen, Erstellungs- und Zerstörungsregeln sowie Entwurfsrichtlinien variieren zwischen verwalteten und nicht verwalteten Objektmodellen. Um die Interoperabilität zwischen verwaltetem und nicht verwaltetem Code zu vereinfachen und den Migrationspfad zu vereinfachen, verdeckt die CLR-Interoperabilitätsebene die Unterschiede zwischen diesen Objektmodellen sowohl von Clients als auch von Servern.
Die Interoperabilität ("Interop") ist bidirektional, was folgende Möglichkeiten ermöglicht:
Aufrufen von nicht verwalteten APIs aus verwaltetem Code
Dies kann sowohl für flache APIs (statische DLL-Exporte wie die Win32-API, die von DLLs wie kernel32.dll und user32.dll) verfügbar gemacht wird, als auch für COM-APIs (Objektmodelle wie z. B. von Microsoft® Word, Excel, Internet Explorer, ActiveX® Data Objects (ADO) und so weiter).
verfügbar machen verwaltete 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 ein MFC-Formular.
Drei ergänzende Technologien ermöglichen diese verwalteten/nicht verwalteten Interaktionen:
- Der Plattformaufruf (manchmal als P/Invoke bezeichnet) ermöglicht das Aufrufen einer beliebigen Funktion in einer nicht verwalteten Sprache, solange die 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-Interoperabilität ermöglicht das Aufrufen von COM-Komponenten in jeder verwalteten Sprache in einer Weise, die der Verwendung normal verwalteter Komponenten ähnelt, und umgekehrt. COM-Interop besteht aus kernigen Diensten, die von der CLR bereitgestellt werden, sowie aus einigen Tools und APIs im System.Runtime.InteropServices Namespace.
- C++-Interoperabilität (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-Interoperabilität, erfordert aber viel mehr Sorgfalt. Stellen Sie sicher, dass Sie die C++-Ressourcen überprüfen, bevor Sie diese Technologie verwenden.
Interoperabilitätsrichtlinien
Aufrufen nicht verwalteter APIs aus verwaltetem Code
Es gibt mehrere Arten von nicht verwalteten APIs und verschiedene Arten von Interoperabilitätstechnologien, die für den Aufruf in diese technologien verfügbar sind. Vorschläge dazu, wie und wann diese Technologien verwendet werden, 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 Entwicklungspraktiken und/oder Lösungen anwenden, die für Ihr Szenario sinnvoll sind.
Aufrufen nicht verwalteter flacher APIs
Es gibt zwei Mechanismen zum Aufrufen nicht verwalteter flacher APIs aus verwaltetem Code: über Den Plattformaufruf (verfügbar in allen verwalteten Sprachen) oder über C++-Interoperabilität (verfügbar in C++).
Bevor Sie sich für den Aufruf einer flachen API mit einer dieser Interoperabilitätstechnologien entscheiden, sollten Sie ermitteln, ob in .NET Framework entsprechende Funktionen verfügbar sind. Es wird empfohlen, dass Sie nach Möglichkeit .NET Framework-Funktionen verwenden, anstatt nicht verwaltete APIs aufzurufen.
Zum Aufrufen nur einiger nicht verwalteter Methoden oder zum Aufrufen einfacher flacher APIs besteht der Vorschlag darin, den Plattformaufruf anstelle der C++-Interoperabilität zu verwenden. Das Schreiben von Plattform-Aufrufdeklarationen für einfache flache APIs ist einfach. Die CLR kümmert sich um das Laden von DLL und alle Parametermarsing. Selbst das Schreiben einiger Plattform-Aufrufdeklarationen für komplexe flache APIs ist im Vergleich zu den Kosten für die Verwendung von C++-Interoperabilität und der Einführung eines ganz neuen Moduls in C++ gering.
Zum Umschließen komplexer nicht verwalteter flacher APIs oder zum Umschließen nicht verwalteter flacher APIs, die sich ändern, während verwalteter Code entwickelt wird, empfiehlt es sich, die C++-Interoperabilität 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 geschrieben werden. Die Verwendung des Plattform-Aufrufs in diesen Szenarien erfordert viel Aufwand, komplexe TEILE der API in verwaltetem Code neu zu deklarieren und sie mit den nicht verwalteten APIs synchron zu halten. Durch die Verwendung von C++-Interop wird dieses Problem gelöst, indem der direkte Zugriff auf nicht verwaltete APIs ermöglicht wird, was keine Neuschreibung erfordert, nur die Einbindung einer Headerdatei.
Aufrufen von COM-APIs
Es gibt zwei Möglichkeiten, COM-Komponenten aus verwaltetem Code aufzurufen: über COM-Interoperabilität (verfügbar in allen verwalteten Sprachen) oder über C++-Interoperabilität (verfügbar in C++).
Für den Aufruf von OLE Automation-kompatiblen COM-Komponenten empfiehlt es sich, COM-Interoperabilität zu verwenden. Die CLR kümmert sich um die AKTIVIERUNG von COM-Komponenten und die Parametermarsing.
Für den Aufruf von COM-Komponenten basierend auf der Schnittstellendefinitionssprache (IDL) besteht der Vorschlag darin, die C++-Interoperabilität zu verwenden. Die C++-Ebene kann sehr dünn sein, und der Rest des verwalteten Codes kann in jeder verwalteten Sprache geschrieben werden. COM-Interoperabilität basiert auf Informationen aus Typbibliotheken, um korrekte Interoperabilitätsaufrufe vorzunehmen, aber Typbibliotheken enthalten in der Regel nicht alle Informationen, die in IDL-Dateien vorhanden sind. Die Verwendung der C++-Interoperabilität löst dieses Problem durch direktes Zugreifen auf diese COM-APIs.
Für Unternehmen, die bereits ausgelieferte COM-APIs besitzen, ist es wichtig, den Versand primärer Interopassemblys (PIAs) für diese APIs zu berücksichtigen, wodurch sie für verwaltete Clients einfach zu nutzen sind.
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 Hauptmethoden zum Verfügbarmachen einer verwalteten API für rein nicht verwaltete Aufrufer: 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: direkt auf verwaltete Funktionen über die C++-Interoperabilität zugreifen. Vorschläge dazu, wie und wann diese Optionen verwendet werden, 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 "Mixed Mode Image" 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 Details finden Sie in der C++-Dokumentation.
Der direkte Zugriff ist die bevorzugte Option, da es keine besondere Berücksichtigung von verwalteten API-Entwicklern erfordert. Sie können ihre verwaltete API gemäß den Richtlinien für verwaltete API-Design (DG) entwerfen und sicher sein, dass die API weiterhin für nicht verwaltete Aufrufer zugänglich ist.
Verfügbarmachen einer verwalteten API als COM-API
Jede öffentliche verwaltete Klasse kann über die COM-Interoperabilität 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, ISupportErrorInfound einige andere Standard-COM-Schnittstellen zu implementieren.
Trotz der Tatsache, dass das Verfügbarmachen verwalteter APIs als COM-APIs einfach ist, sind verwaltete und COM-Objektmodelle sehr unterschiedlich. Daher sollte das Verfügbarmachen der verwalteten API für COM immer eine explizite Entwurfsentscheidung sein. Einige features, die in der verwalteten Welt verfügbar sind, haben keine Entsprechung in der COM-Welt und können nicht von COM-Clients verwendet werden. Aus diesem Grund gibt es häufig Spannungen zwischen verwalteten API-Entwurfsrichtlinien (DG) und Kompatibilität mit COM.
Wenn COM-Clients wichtig sind, schreiben Sie Ihre verwaltete API gemäß den Entwurfsrichtlinien der verwalteten API, und schreiben Sie dann einen dünnen COM-freundlichen verwalteten Wrapper um Ihre verwaltete API, die für COM verfügbar gemacht wird.
Verfügbarmachen einer verwalteten API als flache API
Manchmal können nicht verwaltete Clients COM nicht verwenden. Beispielsweise können sie bereits geschrieben werden, um flache APIs zu verwenden und können 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 ist eine sehr fortgeschrittene Technik, die erweiterte Kenntnisse der C++-Interoperabilität und die Unterschiede zwischen den verwalteten und nicht verwalteten Welten erfordert.
Machen Sie Ihre verwaltete API nur dann als flache API verfügbar, wenn sie unbedingt erforderlich ist. Wenn Sie keine Wahl haben, überprüfen Sie unbedingt die C++-Dokumentation, und beachten Sie alle Einschränkungen.
Entscheidungsstruktur für die Bereitstellung verwalteter APIs
Abbildung 2. Bereitstellen der Entscheidungsstruktur für verwaltete APIs
Sicherheit
Die Common Language Runtime wird mit einem Sicherheitssystem, Code Access Security (CAS) ausgeliefert, das den Zugriff auf geschützte Ressourcen basierend auf Informationen zum Ursprung einer Assembly regelt. Das Aufrufen von nicht verwaltetem Code stellt ein großes Sicherheitsrisiko dar. Ohne geeignete Sicherheitsüberprüfungen kann nicht verwalteter Code jeden Status jeder verwalteten Anwendung im CLR-Prozess bearbeiten. Es ist auch möglich, Ressourcen direkt im nicht verwalteten Code aufzurufen, ohne dass diese Ressourcen cas-Berechtigungsprüfungen unterliegen. Aus diesem Grund gilt jeder Übergang in nicht verwalteten Code als hochgeschützter Vorgang und sollte eine Sicherheitsüberprüfung enthalten. Bei dieser Sicherheitsüberprüfung wird nach der Nicht verwalteten Codeberechtigung gesucht, die die Assembly mit dem nicht verwalteten Codeübergang sowie alle assemblys erfordert, die sie aufrufen, um das Recht zu haben, tatsächlich nicht verwalteten Code aufzurufen.
Es gibt einige eingeschränkte Interoperabilitätsszenarien, in denen vollständige Sicherheitsüberprüfungen unnötig sind und die Leistung oder den Umfang der Komponente unuell einschränken würden. Dies ist der Fall, wenn eine Ressource, die aus nicht verwaltetem Code verfügbar gemacht wird, keine Sicherheitsrelevanz hat (Systemzeit, Fensterkoordinaten usw.), oder die Ressource wird nur intern in der Assembly verwendet und nicht öffentlich für beliebige Aufrufer verfügbar gemacht. In solchen Fällen können Sie die vollständige Sicherheitsüberprüfung auf nicht verwaltete Codeberechtigungen für alle Aufrufer der relevanten APIs unterdrücken. Dazu wenden Sie das SuppressUnmanagedCodeSecurity benutzerdefiniertes Attribut auf die jeweilige Interopmethode oder -klasse an. Beachten Sie, dass dies eine sorgfältige Sicherheitsüberprüfung vorausgeht, 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 das Freigeben nicht verwendeter Arbeitsspeicher übernimmt, 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 rein verwalteter Code. Beispielsweise müssen Sie nicht verwalteten Arbeitsspeicher manuell zuweisen und sich daran erinnern, sie freizugeben, wenn Sie damit fertig sind.
Das Schreiben von nicht trivialen Interop-Code erfordert die gleiche Aufmerksamkeit auf Zuverlässigkeit und Robustheit wie das Schreiben von nicht verwalteten Code. Auch wenn der gesamte Interoperabilitätscode richtig 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) gibt es einen Leistungsaufwand. Der Aufwand hängt von den verwendeten Parametertypen ab. Die CLR-Interopebene verwendet drei Ebenen der Interopaufrufoptimierung basierend auf Übergangstyp und Parametertypen: just-in-time (JIT) Inlining, kompilierte Assemblystumbs und interpretierte Marshalling-Stubs (in Der Reihenfolge der schnellsten bis langsamsten Art des Anrufs).
Ungefährer Aufwand für einen Plattformaufruf: 10 Computeranweisungen (auf einem x86-Prozessor)
Ungefährer Aufwand für einen COM-Interoperabilitätsaufruf: 50 Computeranweisungen (auf einem x86-Prozessor)
Die Arbeit dieser Anweisungen wird in den Abschnitten "Aufrufen einer flachen API: Schritt für Schritt und Aufrufen einer COM-API: Schritt für Schritt" und "Aufrufen einer COM-API: Schritt für Schritt" gezeigt. Neben der Sicherstellung, dass der Garbage Collector während des Aufrufs keine nicht verwalteten Threads blockiert und Aufrufkonventionen und nicht verwaltete Ausnahmen verarbeitet, führt COM-Interop zusätzliche Arbeit aus, um den Aufruf für den aktuellen Laufzeit-aufrufbaren Wrapper (RCW) in einen COM-Schnittstellenzeiger zu konvertieren, der für den aktuellen Kontext geeignet ist.
Jeder Interop-Aufruf führt zu einem gewissen Mehraufwand. Je nachdem, wie oft diese Aufrufe auftreten und wie wichtig die Arbeit innerhalb der Methodenimplementierung ist, kann der Pro-Call-Overhead von vernachlässigbar bis sehr spürbar reichen.
Basierend auf diesen Überlegungen bietet die folgende Liste einige allgemeine Leistungsvorschläge, die Sie möglicherweise hilfreich finden:
Wenn Sie die Schnittstelle zwischen verwaltetem und nicht verwaltetem Code steuern, machen Sie sie "blockig" statt "chatty", um die Gesamtanzahl der vorgenommenen Übergänge zu verringern.
Chatty interfaces are interfaces that make a lot of transitions without perform any significant work on the other side of the interop boundary. Beispielsweise sind Eigenschaftensetter und Getter chatty. Blocky-Schnittstellen sind Schnittstellen, die nur wenige Übergänge machen, und die Menge der Arbeit auf der anderen Seite der Grenze ist signifikant. Beispielsweise ist eine Methode, die eine Datenbankverbindung öffnet und einige Daten abruft, blöckeweise. Blockierungsschnittstellen umfassen weniger Interopübergänge, sodass Sie einen Leistungsaufwand vermeiden.
Vermeiden Sie nach Möglichkeit Unicode-/ANSI-Konvertierungen.
Das Konvertieren von Zeichenfolgen aus 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-Marshaler führt keine Konvertierungen durch.
Für Hochleistungsszenarien kann das Deklarieren von Parametern und Feldern als IntPtr- die Leistung steigern, wenn auch auf Kosten der benutzerfreundlichen und wartungsfreundlichen Leistung.
Manchmal ist es schneller, manuelle Marshaling mithilfe von Methoden zu erledigen, die für die Marshal Klasse verfügbar sind, anstatt sich auf die standardmäßige Interopmarsing zu verlassen. Wenn beispielsweise große Arrays von Zeichenfolgen über eine Interopgrenze übergeben werden müssen, aber nur einige Elemente erforderlich sind, wird das Array als IntPtr deklarieren und nur die wenigen Elemente manuell zugreifen, viel schneller.
Verwenden Sie InAttribute- und OutAttribute- weise, um unnötige Marshaling zu reduzieren.
Der Interop marshaler verwendet Standardregeln, wenn sie entscheiden, ob ein bestimmter Parameter vor dem Aufruf gemarstet und nach dem Aufruf gemarstet werden muss. Diese Regeln basieren auf der Ebene der Dereferenzierung und des Parametertyps. Einige dieser Vorgänge sind je nach Semantik der Methode möglicherweise nicht erforderlich.
Verwenden Sie SetLastError=false auf der Plattform nur, wenn Sie Marshal.GetLastWin32Error- danach aufrufen.
Das Festlegen SetLastError=true auf plattform aufrufenden Signaturen 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 diese verwenden, nachdem Sie den Anruf ausgeführt haben.
Wenn und nur, wenn nicht verwaltete Aufrufe nicht ausnutzbar verfügbar gemacht werden, verwenden Sie SuppressUnmanagedCodeSecurityAttribute, um die Anzahl der Sicherheitsprüfungen zu verringern.
Sicherheitskontrollen sind sehr wichtig. Wenn Ihre API keine geschützten Ressourcen oder vertraulichen Informationen verfügbar macht oder sie gut geschützt sind, können umfangreiche Sicherheitsprüfungen unnötigen Aufwand verursachen. Die Kosten für keine Sicherheitsüberprüfung sind jedoch sehr hoch.
Anhang 1: Überschreiten der Interoperabilitätsgrenze
Aufrufen einer flachen API: Schritt für Schritt
Abbildung 3. Aufrufen einer flachen API
- Rufen Sie LoadLibrary und GetProcAddress-ab.
- Erstellen Sie einen DllImport- Stub aus der Signatur, die die Zieladresse enthält.
- Gespeicherte Register per Push übertragen.
- Richten Sie einen DllImport-Frame ein, und drücken Sie ihn auf den Stapel von Frames.
- Wenn temporärer Speicher zugewiesen wird, initialisieren Sie eine Bereinigungsliste für schnelles Freigeben, wenn der Anruf abgeschlossen ist.
- Marshal-Parameter. (Dies könnte Speicher zuordnen.)
- Ändern Sie den Garbage Collection-Modus von kooperativ in präemptive, sodass eine Garbage Collection jederzeit erfolgen kann.
- Laden Sie die Zieladresse, und rufen Sie sie auf.
- Wenn SetLastError Bit festgelegt ist, rufen Sie GetLastError- auf, und speichern Sie das Ergebnis in einer Threadstraktion, die im lokalen Threadspeicher gespeichert ist.
- Wechseln Sie zurück zum kooperativen Garbage Collection-Modus.
- Wenn PreserveSig=false und die Methode ein HRESULT-Fehler zurückgegeben hat, wird eine Ausnahme ausgelöst.
- Wenn keine Ausnahme ausgelöst wurde,
und parameter by-ref . - Stellen Sie den erweiterten Stapelzeiger auf seinen ursprünglichen Wert zurück, um Aufruferargumente zu berücksichtigen.
Aufrufen einer COM-API: Schritt für Schritt
Abbildung 4. Aufrufen einer COM-API
- Erstellen Sie einen verwalteten und nicht verwalteten Stub aus der Signatur.
- Gespeicherte Register per Push übertragen.
- Richten Sie einen verwalteten und nicht verwalteten COM-Interopframe ein, und verschieben Sie ihn auf den Stapel von Frames.
- Reservieren Sie Speicherplatz für temporäre Daten, die während des Übergangs verwendet werden.
- Wenn temporärer Speicher zugewiesen wird, initialisieren Sie eine Bereinigungsliste für schnelles Freigeben, wenn der Anruf abgeschlossen ist.
- Löschen von Gleitkomma-Ausnahmekennzeichnungen (nur x86).
- Marshal-Parameter. (Dies könnte Speicher zuordnen.)
- Rufen Sie den richtigen Schnittstellenzeiger für den aktuellen Kontext innerhalb des aufrufbaren Wrappers der Laufzeit ab. Wenn der zwischengespeicherte Zeiger nicht verwendet werden kann, rufen Sie QueryInterface für die COM-Komponente auf, um ihn abzurufen.
- Ändern Sie den Garbage Collection-Modus von kooperativ in präemptive, sodass eine Garbage Collection jederzeit erfolgen kann.
- Rufen Sie vom vtable-Zeiger die Zieladresse nach der Steckplatznummer indiziert, und rufen Sie ihn auf.
- Rufen Sie Release- auf dem Schnittstellenzeiger auf, wenn QueryInterface- zuvor aufgerufen wurde.
- Wechseln Sie zurück zum kooperativen Garbage Collection-Modus.
- Wenn die Signatur nicht PreserveSiggekennzeichnet ist, überprüfen Sie auf HRESULT-Fehler, und lösen Sie eine Ausnahme aus (möglicherweise mit IErrorInfo Informationen gefüllt).
- Wenn keine Ausnahme ausgelöst wurde,
und parameter by-ref . - Stellen Sie den erweiterten Stapelzeiger auf den ursprünglichen Wert zurück, um aufruferseitige Argumente zu berücksichtigen.
Aufrufen einer verwalteten API über COM: Schritt für Schritt
Abbildung 5. Aufrufen einer verwalteten API von COM
- Erstellen Sie einen nicht verwalteten Stub aus der Signatur.
- Gespeicherte Register per Push übertragen.
- Richten Sie einen nicht verwalteten COM-Interopframe ein, und verschieben Sie ihn auf den Stapel von Frames.
- Reservieren Sie Speicherplatz für temporäre Daten, die während des Übergangs verwendet werden.
- Ändern Sie den Garbage Collection-Modus von "Kooperativ" in "Preemptive", damit eine Garbage Collection jederzeit erfolgen kann.
- Rufen Sie den COM-aufrufbaren Wrapper (CCW) vom Schnittstellenzeiger ab.
- Rufen Sie das verwaltete Objekt innerhalb des CCW ab.
- Transition appdomains, if required.
- Wenn eine App-Domäne ohne volle Vertrauenswürdigstellung ist, führen Sie alle Verknüpfungsanforderungen aus, die die Methode möglicherweise für die Ziel-App-Domäne hat.
- Wenn temporärer Speicher zugewiesen wird, initialisieren Sie eine Bereinigungsliste für schnelles Freigeben, wenn der Anruf abgeschlossen ist.
- Marshal-Parameter. (Dies könnte Speicher zuordnen.)
- Suchen Sie die zielverwaltete Methode, die aufgerufen werden soll. (Dies umfasst das Zuordnen von Schnittstellenaufrufen zur Zielimplementierung.)
- Zwischenspeichern des Rückgabewerts. (Wenn es sich um einen Gleitkommarückwert handelt, rufen Sie ihn aus dem Gleitkommaregister ab.)
- Wechseln Sie zurück zum kooperativen Garbage Collection-Modus.
- Wenn eine Ausnahme ausgelöst wurde, extrahieren Sie das HRESULT, um es zurückzugeben, und rufen Sie SetErrorInfoauf.
- Wenn keine Ausnahme ausgelöst wurde,
und parameter by-ref . - Stellen Sie den erweiterten Stapelzeiger auf den ursprünglichen Wert zurück, um aufruferseitige Argumente zu berücksichtigen.
Anhang 2: Ressourcen
Muss lesen!.NET und COM: Der vollständige Interoperabilitätsleitfaden von AdamVervollständigen
Interoperabilität mit nicht verwalteten Code-, Microsoft .NET Framework-Entwicklerhandbuch
Interop-Beispiele, Microsoft .NET Framework
Adam Gardes Blog
Chris Brummes Blog
Anhang 3: Glossar der Begriffe
AppDomain (Anwendungsdomäne) | Eine Anwendungsdomäne kann ähnlich wie ein einfacher Betriebssystemprozess betrachtet 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 wurde, die aus COM-Code aktiviert werden. Ein CCW blendet Unterschiede zwischen verwalteten und COM-Objektmodellen aus, indem Datenmarsing, Lebensdauerverwaltung, Identitätsverwaltung, Fehlerbehandlung, korrekte Apartment- und Threadingübergänge usw. bereitgestellt werden. CCWs machen verwaltete Objektfunktionen auf COM-freundliche Weise verfügbar, ohne dass die Implementierung von verwaltetem Code etwas über die COM-Sanitärinstallation wissen muss. |
CLR | Die Common Language Runtime. |
COM-Interoperabilität | Der Dienst, der von der CLR-Interoperabilitätsebene für die Verwendung von COM-APIs aus verwaltetem Code bereitgestellt wird, oder das Verfügbarmachen verwalteter APIs als COM-APIs für nicht verwaltete Clients. COM-Interoperabilität ist in allen verwalteten Sprachen verfügbar. |
C++-Interoperabilität | Der vom C++-Sprachcompiler und der CLR bereitgestellte Dienst wird verwendet, um verwalteten und nicht verwalteten Code in derselben ausführbaren Datei direkt zu mischen. C++-Interoperabilität umfasst in der Regel Headerdateien in nicht verwalteten APIs und das Folgen bestimmter Codierungsregeln. |
komplexe flache API | APIs mit Signaturen, die schwer in verwalteter Sprache deklariert werden können. Methoden mit Parametern für variable Größenstrukturen sind z. B. schwer zu deklarieren, da im verwalteten Typsystem kein entsprechendes Konzept vorhanden ist. |
Interop | Der allgemeine Begriff, der alle Arten von Interoperabilität zwischen verwaltetem und nicht verwaltetem Code (auch als "systemeigener" bezeichnet) behandelt. Interop ist einer von vielen Diensten, die von der CLR bereitgestellt werden. |
Interopassembly | Ein spezieller Typ von verwalteter Assembly, der Entsprechungen vom verwalteten Typ für COM-Typen enthält, die in einer Typbibliothek enthalten sind. In der Regel wird das Tool "Type Library Importer" (Tlbimp.exe) in einer Typbibliothek erstellt. |
verwalteter Code | Code, der unter dem Steuerelement der CLR ausgeführt wird, wird als verwalteter Code bezeichnet. Beispielsweise wird jeder in C# oder Visual Basic .NET geschriebene Code verwaltet. |
Plattform-Aufruf | Der dienst, der von der CLR-Interopebene zum Aufrufen nicht verwalteter flacher APIs aus verwaltetem Code bereitgestellt wird. Der Plattform-Aufruf 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 Datenmarsing, Lebensdauerverwaltung, Identitätsverwaltung, Fehlerbehandlung, korrekte Apartment- und Threadingübergänge usw. bereitgestellt werden. |
nicht verwalteten 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. |