Teilen über


Kopieren und Anpinnen

Beim Marshalling von Daten kann der Interop-Marshaller die gemarshallten Daten kopieren oder fixieren. Beim Kopieren der Daten wird eine Kopie der Daten von einem Speicherort zu einem anderen Speicherort übertragen. Die folgende Abbildung veranschaulicht die Unterschiede zwischen dem Kopieren eines Werttyps und dem Kopieren eines Typs, der als Verweis von einem verwalteten Speicher zu einem nicht verwalteten Speicher übergeben wird.

Diagramm, das zeigt, wie Wert- und Verweistypen kopiert werden.

Als Wert übergebene Methodenargumente werden in einen nicht verwalteten Code als Werte im Stapel gemarshallt. Der Kopiervorgang ist direkt. Als Verweis übergebene Argumente werden als Zeiger im Stapel übergeben. Auch Verweistypen werden als Wert und als Verweis übergebenen. Die folgende Abbildung zeigt, dass als Wert übergebene Verweistypen entweder kopiert oder fixiert werden:

Diagramm mit Verweistypen, die nach Wert und Verweis übergeben werden.

Durch das Festpinnen werden die Daten vorübergehend an ihrem aktuellen Speicherort fixiert, wodurch verhindert wird, dass die Daten vom Garbage Collector der Common Language Runtime verschoben werden. Der Marshaller fixiert die Daten, um den Aufwand beim Kopieren zu reduzieren und die Leistung zu verbessern. Ob Daten während des Marshallingvorgangs kopiert oder fixiert werden, wird durch den Datentyp bestimmt. Das Anheften wird während des Marshallings automatisch für Objekte wie String durchgeführt. Es besteht jedoch auch die Möglichkeit, den Arbeitsspeicher manuell mit der GCHandle Klasse anzupinnen.

Formatierte blitfähige Klassen

Formatierte blittbare Klassen weisen ein festes Layout (formatiert) und allgemeine Datendarstellungen sowohl im verwalteten als auch im nicht verwalteten Arbeitsspeicher auf. Wenn diese Typen gemarshallt werden müssen, wird ein Zeiger auf das Objekt im Heap direkt an den Aufgerufenen übergeben. Der Angerufene kann den Inhalt des Speicherorts ändern, auf den der Zeiger verweist.

Hinweis

Der Aufgerufene kann den Speicherinhalt ändern, wenn der Parameter als Ausgabe- oder Ein-/Ausgabeparameter markiert ist. Im Gegensatz dazu sollte der Aufgerufene den Inhalt nicht ändern, wenn der Parameter zum Marshallen als Eingabeparameter festgelegt ist. Dies ist die Standardeinstellung für formatierte blitfähige Typen. Das Ändern von Eingabeobjekten kann zu Problemen führen, wenn die gleiche Klasse in eine Typbibliothek exportiert und auch für apartmentübergreifende Aufrufe verwendet wird.

Formatierte nicht blitfähige Klassen

Formatierte nicht teilbare Klassen weisen ein festes Layout (formatiert) auf, die Datendarstellung unterscheidet sich jedoch im verwalteten und nicht verwalteten Speicher. Die Daten können eine Transformation unter den folgenden Bedingungen erfordern:

  • Wenn eine nicht blitfähige Klasse als Wert gemarshallt wird, erhält der Aufgerufene einen Zeiger auf eine Kopie der Datenstruktur.

  • Wenn eine nicht blitfähige Klasse als Verweis gemarshallt wird, erhält der Aufgerufene einen Zeiger auf einen Zeiger auf eine Kopie der Datenstruktur.

  • Wenn das InAttribute-Attribut festgelegt ist, wird diese Kopie immer mit dem Zustand der Instanz initialisiert. Das Marshalling erfolgt nach Bedarf.

  • Wenn das OutAttribute-Attribut festgelegt ist, wird der Zustand bei der Rückgabe immer zurück in die Instanz kopiert. Das Marshalling erfolgt nach Bedarf.

  • Wenn sowohl InAttribute als auch OutAttribute festgelegt sind, sind beide Kopien erforderlich. Wenn eines der Attribute ausgelassen wird, kann der Marshaller optimieren, indem beide Kopien eliminiert werden.

Verweistypen

Verweistypen können als Wert oder als Verweis übergeben werden. Werden sie als Wert übergeben, wird ein Zeiger auf den Typ im Stapel übergeben. Werden sie als Verweis übergeben, wird ein Zeiger auf einen Zeiger auf den Typ im Stapel übergeben.

Referenztypen weisen das folgende bedingte Verhalten auf:

  • Wird ein Verweistyp als Wert übergeben, und verfügt er über Member nicht blitfähiger Typen, werden die Typen zweimal konvertiert:

    • bei der Übergabe eines Arguments an die nicht verwaltete Seite

    • bei der Rückgabe aus dem Aufruf

    Um unnötiges Kopieren und Konvertieren zu vermeiden, werden diese Typen als In-Parameter gemarshallt. Sie müssen die Attribute InAttribute und OutAttribute explizit auf ein Argument anwenden, damit der Aufrufer Änderungen sehen kann, die vom aufgerufenen Code vorgenommen wurden.

  • Wird ein Verweistyp als Wert übergeben, und verfügt er nur über Member blitfähiger Typen, kann er während des Marshallings fixiert werden. Alle vom Aufgerufenen an den Membern des Typs vorgenommen Änderungen sind für den Aufrufer sichtbar. Wenden Sie InAttribute und OutAttribute explizit an, wenn Sie dieses Verhalten wünschen. Ohne diese direktionalen Attribute werden keine direktionalen Informationen vom Interop-Marshaller in die Typbibliothek exportiert (der Export erfolgt standardmäßig als Eingabeparameter). Dies kann zu Problemen beim apartmentübergreifenden COM-Marshalling führen.

  • Wird ein Verweistyp als Verweis übergeben, wird er standardmäßig als Ein-/Ausgabeparameter gemarshallt.

System.String und System.Text.StringBuilder

Wenn Daten als Wert oder als Verweis in einen nicht verwalteten Code gemarshallt werden, kopiert der Marshaller die Daten in der Regel in einen sekundären Puffer (wobei Zeichensätze während des Kopiervorgangs eventuell konvertiert werden) und übergibt an den Aufgerufenen einen Verweis auf den Puffer. Sofern der Verweis nicht mit BSTR zugeordnet ist, wird der Verweis immer mit CoTaskMemAlloc zugeordnet.

Wenn String oder StringBuilder als Wert gemarshallt werden (wie etwa bei einer Unicode-Zeichenfolge), übergibt der Marshaller dem Aufgerufenen einen direkten Zeiger auf die verwalteten Zeichenfolgen im internen Unicode-Puffer, anstatt sie in einen neuen Puffer zu kopieren.

Vorsicht

Wird eine Zeichenfolge als Wert übergeben, darf der Aufgerufene den vom Marshaller übergebenen Verweis nie ändern. Andernfalls kann der verwaltete Heap beschädigt werden.

Wenn ein System.String als Verweis übergeben wird, kopiert der Marshaller den Inhalt der Zeichenfolge vor dem Aufruf in einen sekundären Puffer. Anschließend kopiert er den Inhalt des Puffers bei der Rückgabe aus dem Aufruf in eine neue Zeichenfolge. So wird sichergestellt, dass die unveränderliche verwaltete Zeichenfolge unverändert bleibt.

Wenn ein System.Text.StringBuilder als Wert übergeben wird, gibt der Marshaller einen Verweis auf eine temporäre Kopie des internen Puffers des StringBuilder an den Aufrufer weiter. Der Aufrufer und der Angerufene müssen sich auf die Größe des Puffers einigen. Der Anrufer ist dafür verantwortlich, dass StringBuilder eine angemessene Länge hat. Der Aufgerufene muss die erforderlichen Vorsichtsmaßnahmen treffen, um einen Pufferüberlauf zu verhindern. StringBuilder ist eine Ausnahme von der Regel, dass Verweistypen, die standardmäßig als Wert übergeben werden, als In Parameter übergeben werden. StringBuilder wird immer als In/Out übergeben.

Siehe auch