Standardmäßiges Marshalling für Zeichenfolgen

Die System.String-Klasse und die System.Text.StringBuilder-Klasse verfügen über ein ähnliches Marshallingverhalten.

Zeichenfolgen werden als BSTR-Typ im COM-Format oder als Zeichenarray gemarshallt, das auf einen NULL-Verweis (Nothing in Visual Basic) endet. Die Zeichen in der Zeichenfolge können als Unicode, ANSI oder plattformabhängig (Unicode für Microsoft Windows NT, Windows 2000 und Windows XP; ANSI für Windows 98 und Windows Millennium Edition (Windows Me)) gemarshallt werden.

In diesem Thema erhalten Sie folgende Informationen zum Marshalling von Zeichenfolgentypen:

  • In Schnittstellen verwendete Zeichenfolgen

  • Im Plattformaufruf verwendete Zeichenfolgen

  • In Strukturen verwendete Zeichenfolgen

  • Zeichenfolgenpuffer mit fester Länge

In Schnittstellen verwendete Zeichenfolgen

In der folgenden Tabelle sind die Marshallingoptionen für den Datentyp String aufgelistet, wenn dieser als Methodenargument an nicht verwalteten Code gemarshallt wird. Das MarshalAsAttribute-Attribut stellt mehrere UnmanagedType-Enumerationswerte zum Marshallen von Zeichenfolgen an COM-Schnittstellen zur Verfügung.

Enumerationstyp

Beschreibung des nicht verwalteten Formats

UnmanagedType.BStr (Standardwert)

BSTR im COM-Format mit vorangestellter Länge und Unicode-Zeichen.

UnmanagedType.LPStr

Ein Zeiger auf ein mit Null endendes Array von ANSI-Zeichen.

UnmanagedType.LPWStr

Ein Zeiger auf ein mit Null endendes Array von Unicode-Zeichen.

Diese Tabelle gilt für Zeichenfolgen. Für StringBuilder sind nur die Optionen UnmanagedType.LPStr und UnmanagedType.LPWStr zulässig.

Im folgenden Beispiel werden in der IStringWorker-Schnittstelle deklarierte Zeichenfolgen gezeigt.

public interface IStringWorker {
void PassString1(String s);
void PassString2([MarshalAs(UnmanagedType.BStr)]String s);
void PassString3([MarshalAs(UnmanagedType.LPStr)]String s);
void PassString4([MarshalAs(UnmanagedType.LPWStr)]String s);
void PassStringRef1(ref String s);
void PassStringRef2([MarshalAs(UnmanagedType.BStr)]ref String s);
void PassStringRef3([MarshalAs(UnmanagedType.LPStr)]ref String s);
void PassStringRef4([MarshalAs(UnmanagedType.LPWStr)]ref String s);
);

Das folgende Beispiel zeigt die entsprechende Schnittstelle, die in einer Typbibliothek beschrieben wird.

[…]
interface IStringWorker : IDispatch {
HRESULT PassString1([in] BSTR s);
HRESULT PassString2([in] BSTR s);
HRESULT PassString3([in] LPStr s);
HRESULT PassString4([in] LPWStr s);
HRESULT PassStringRef1([in, out] BSTR *s);
HRESULT PassStringRef2([in, out] BSTR *s);
HRESULT PassStringRef3([in, out] LPStr *s);
HRESULT PassStringRef4([in, out] LPWStr *s);
);

Im Plattformaufruf verwendete Zeichenfolgen

Plattformaufruf kopiert Zeichenargumente, wobei diese gegebenenfalls aus dem .NET Framework-Format (Unicode) in das nicht verwaltete Plattformformat konvertiert werden. Zeichenfolgen sind unveränderlich und werden bei Rückgabe des Aufrufs nicht aus dem nicht verwalteten Speicher in den verwalteten Speicher zurückkopiert.

In der folgenden Tabelle sind die Marshallingoptionen für Zeichenfolgen aufgelistet, wenn die Zeichenfolgen als Methodenargumente eines Plattformaufrufs gemarshallt werden. Das MarshalAsAttribute-Attribut stellt mehrere UnmanagedType-Enumerationswerte zum Marshallen von Zeichenfolgen zur Verfügung.

Enumerationstyp

Beschreibung des nicht verwalteten Formats

UnmanagedType.AnsiBStr

BSTR im COM-Format mit vorangestellter Länge und ANSI-Zeichen.

UnmanagedType.BStr

BSTR im COM-Format mit vorangestellter Länge und Unicode-Zeichen.

UnmanagedType.LPStr

Ein Zeiger auf ein mit Null endendes Array von ANSI-Zeichen.

UnmanagedType.LPTStr (Standardwert)

Ein Zeiger auf ein mit Null endendes Array von plattformabhängigen Zeichen.

UnmanagedType.LPWStr

Ein Zeiger auf ein mit Null endendes Array von Unicode-Zeichen.

UnmanagedType.TBStr

BSTR im COM-Format mit vorangestellter Länge und plattformabhängigen Zeichen.

VBByRefStr

Ein Wert, der es Visual Basic .NET ermöglicht, eine Zeichenfolge in nicht verwaltetem Code zu ändern und die Ergebnisse in verwaltetem Code wiederzugeben. Dieser Wert wird nur für Plattformaufrufe unterstützt.

Diese Tabelle gilt für Zeichenfolgen. Für StringBuilder sind nur die Optionen LPStr, LPTStr und LPWStr zulässig.

In der folgenden Typdefinition ist die richtige Verwendung von MarshalAsAttribute für Plattformaufrufe dargestellt.

Class StringLibAPI    
Public Declare Auto Sub PassLPStr Lib "StringLib.Dll" _
(<MarshalAs(UnmanagedType.LPStr)> s As String)    
Public Declare Auto Sub PassLPWStr Lib "StringLib.Dll" _
(<MarshalAs(UnmanagedType.LPWStr)> s As String)    
Public Declare Auto Sub PassLPTStr Lib "StringLib.Dll" _
(<MarshalAs(UnmanagedType.LPTStr)> s As String)    
Public Declare Auto Sub PassBStr Lib "StringLib.Dll" _
(<MarshalAs(UnmanagedType.BStr)> s As String)    
Public Declare Auto Sub PassAnsiBStr Lib "StringLib.Dll" _
(<MarshalAs(UnmanagedType.AnsiBStr)> s As String)    
Public Declare Auto Sub PassTBStr Lib "StringLib.Dll" _
(<MarshalAs(UnmanagedType.TBStr)> s As String)
End Class
class StringLibAPI {
[DllImport("StringLib.Dll")]
public static extern void PassLPStr([MarshalAs(UnmanagedType.LPStr)]
String s);
[DllImport("StringLib.Dll")]
public static extern void 
PassLPWStr([MarshalAs(UnmanagedType.LPWStr)]String s);
[DllImport("StringLib.Dll")]
public static extern void 
PassLPTStr([MarshalAs(UnmanagedType.LPTStr)]String s);
[DllImport("StringLib.Dll")]
public static extern void PassBStr([MarshalAs(UnmanagedType.BStr)]
String s);
[DllImport("StringLib.Dll")]
public static extern void 
PassAnsiBStr([MarshalAs(UnmanagedType.AnsiBStr)]String s);
[DllImport("StringLib.Dll")]
public static extern void PassTBStr([MarshalAs(UnmanagedType.TBStr)]
String s);
}

In Strukturen verwendete Zeichenfolgen

Zeichenfolgen sind gültige Member von Strukturen. StringBuilder-Puffer sind in Strukturen jedoch ungültig. In der folgenden Tabelle sind die Marshallingoptionen für den Datentyp String aufgelistet, wobei der Typ als Feld gemarshallt wird. Das MarshalAsAttribute-Attribut stellt mehrere UnmanagedType-Enumerationswerte zum Marshallen von Zeichenfolgen an ein Feld zur Verfügung.

Enumerationstyp

Beschreibung des nicht verwalteten Formats

UnmanagedType.BStr

BSTR im COM-Format mit vorangestellter Länge und Unicode-Zeichen.

UnmanagedType.LPStr

Ein Zeiger auf ein mit Null endendes Array von ANSI-Zeichen.

UnmanagedType.LPTStr

Ein Zeiger auf ein mit Null endendes Array von plattformabhängigen Zeichen.

UnmanagedType.LPWStr

Ein Zeiger auf ein mit Null endendes Array von Unicode-Zeichen.

UnmanagedType.ByValTStr

Ein Zeichenarray mit fester Länge; der Typ des Arrays wird durch den Zeichensatz der enthaltenden Struktur bestimmt.

Der ByValTStr-Typ wird für Inlinearrays mit Zeichen fester Länge verwendet, die in einer Struktur erscheinen. Andere Typen gelten für Zeichenfolgenverweise, die in Strukturen enthalten sind, die Zeiger auf Zeichenfolgen enthalten.

Das CharSet-Argument des StructLayoutAttribute-Attributs, das auf die enthaltende Struktur angewendet wird, bestimmt das Zeichenformat von Zeichenfolgen in Strukturen. Die folgenden Beispielstrukturen enthalten Zeichenfolgenverweise und Inlinezeichenfolgen sowie ANSI-, Unicode- und plattformabhängige Zeichen.

Typbibliothekdarstellung

struct StringInfoA {
   char *    f1;
   char      f2[256];
};
struct StringInfoW {
   WCHAR *   f1;
   WCHAR     f2[256];
   BSTR      f3;
};
struct StringInfoT {
   TCHAR *   f1;
   TCHAR     f2[256];
};

Im folgenden Codebeispiel wird demonstriert, wie das MarshalAsAttribute-Attribut zum Definieren derselben Struktur in unterschiedlichen Formaten verwendet wird.

<StructLayout(LayoutKind.Sequential, CharSet := CharSet.Ansi)> _
Structure StringInfoA
<MarshalAs(UnmanagedType.LPStr)> Public f1 As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst := 256)> _
Public f2 As String
End Structure
<StructLayout(LayoutKind.Sequential, CharSet := CharSet.Unicode)> _
Structure StringInfoW
<MarshalAs(UnmanagedType.LPWStr)> Public f1 As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst := 256)> _
Public f2 As String
<MarshalAs(UnmanagedType.BStr)> Public f3 As String
End Structure
<StructLayout(LayoutKind.Sequential, CharSet := CharSet.Auto)> _
Structure StringInfoT
<MarshalAs(UnmanagedType.LPTStr)> Public f1 As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst := 256)> _
Public f2 As String
End Structure
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
struct StringInfoA {
   [MarshalAs(UnmanagedType.LPStr)] public String f1;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] public String f2;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
struct StringInfoW {
   [MarshalAs(UnmanagedType.LPWStr)] public String f1;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] public String f2;
   [MarshalAs(UnmanagedType.BStr)] public String f3;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
struct StringInfoT {
   [MarshalAs(UnmanagedType.LPTStr)] public String f1;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] public String f2;
}

Zeichenfolgenpuffer mit fester Länge

In bestimmten Situationen müssen Zeichenpuffer mit fester Länge zur Bearbeitung an nicht verwalteten Code übergeben werden. In diesem Fall ist es nicht möglich, die Zeichenfolge einfach zu übergeben, da der Aufgerufene den Inhalt des übergebenen Puffers nicht ändern kann. Selbst wenn die Zeichenfolge durch einen Verweis übergeben wird, kann der Puffer nicht für eine gegebene Größe initialisiert werden.

Die Lösung besteht darin, anstelle einer Zeichenfolge einen StringBuilder-Puffer als Argument zu übergeben. Ein StringBuilder kann durch den Aufrufer dereferenziert und geändert werden, sofern die Kapazität von StringBuilder nicht überschritten wird. Sie können auch für eine feste Länge initialisiert werden. Wenn Sie beispielsweise einen StringBuilder-Puffer mit einer Kapazität N initialisieren, stellt der Marshaller einen Puffer mit einer Größe von (N+1) Zeichen zur Verfügung. Durch +1 wird der Tatsache Rechnung getragen, dass die nicht verwaltete Zeichenfolge, im Gegensatz zu StringBuilder, über einen Nullterminator verfügt.

Die GetWindowText-Funktion der Microsoft Win32-API (in Windows.h definiert) ist beispielsweise ein Zeichenpuffer mit fester Länge, der zur Bearbeitung an nicht verwalteten Code übergeben werden muss. LpString zeigt auf einen vom Aufrufer reservierten Puffer von der Größe nMaxCount. Es wird erwartet, dass der Aufrufer den Puffer reserviert und das nMaxCount-Argument auf die Größe des reservierten Puffers festlegt. Der folgende Code stellt die Deklaration der GetWindowText-Funktion entsprechend der Definition in Windows.h dar.

int GetWindowText(
HWND hWnd,        // Handle to window or control.
LPTStr lpString,  // Text buffer.
int nMaxCount     // Maximum number of characters to copy.
);

Ein StringBuilder kann durch den Aufrufer dereferenziert und geändert werden, sofern die Kapazität von StringBuilder nicht überschritten wird. Im folgenden Codebeispiel wird dargestellt, wie StringBuilder mit einer festen Länge initialisiert werden kann.

Public Class Win32API
Public Declare Auto Sub GetWindowText Lib "User32.Dll" _
(h As Integer, s As StringBuilder, nMaxCount As Integer)
End Class
Public Class Window
   Friend h As Integer ' Friend handle to Window.
   Public Function GetText() As String
      Dim sb As New StringBuilder(256)
      Win32API.GetWindowText(h, sb, sb.Capacity + 1)
   Return sb.ToString()
   End Function
End Class
public class Win32API {
[DllImport("User32.Dll")]
public static extern void GetWindowText(int h, StringBuilder s, 
int nMaxCount);
}
public class Window {
   internal int h;        // Internal handle to Window.
   public String GetText() {
      StringBuilder sb = new StringBuilder(256);
      Win32API.GetWindowText(h, sb, sb.Capacity + 1);
   return sb.ToString();
   }
}

Siehe auch

Konzepte

Blitfähige und nicht blitfähige Typen

Direktionale Attribute

Kopieren und Fixieren

Weitere Ressourcen

Standardmarshallingverhalten