Marshaling par défaut pour les chaînes
Mise à jour : novembre 2007
Les classes System.String et System.Text.StringBuilder ont un comportement de marshaling semblable.
Les chaînes sont marshalées en tant que type BSTR de style COM ou comme tableau de caractères se terminant par une référence null (Nothing en Visual Basic). Les caractères à l'intérieur de la chaîne peuvent être marshalés en tant qu'Unicode ou ANSI, ou en fonction de la plateforme (Unicode sous Microsoft Windows NT, Windows 2000 et Windows XP ; ANSI sous Windows 98 et Windows Millennium Edition (Windows Me).
Cette rubrique fournit les informations suivantes sur le marshaling de types de chaînes :
Chaînes utilisées dans les interfaces
Chaînes utilisées dans l'appel de code non managé
Chaînes utilisées dans les structures
Mémoires tampons de chaînes de longueur fixe
Chaînes utilisées dans les interfaces
Le tableau suivant montre les options de marshaling pour les types de données de chaîne qui sont marshalés en tant qu'argument de méthode vers du code non managé. L'attribut MarshalAsAttribute fournit plusieurs valeurs d'énumération UnmanagedType pour marshaler des chaînes vers des interfaces COM.
Type énumération |
Description de format non managé |
---|---|
UnmanagedType.BStr (par défaut) |
BSTR de style COM d'une longueur préfixée et constitué de caractères Unicode. |
UnmanagedType.LPStr |
Pointeur vers un tableau de caractères ANSI se terminant par null. |
UnmanagedType.LPWStr |
Pointeur vers un tableau de caractères Unicode se terminant par null. |
Ce tableau s'applique aux chaînes. Toutefois, pour StringBuilder , les seules options autorisées sont UnmanagedType.LPStr et UnmanagedType.LPWStr.
L'exemple suivant montre des chaînes déclarées dans l'interface IStringWorker.
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);
);
Le code suivant montre l'interface correspondante décrite dans une bibliothèque de types.
[…]
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);
);
Chaînes utilisées dans l'appel de code non managé
L'appel de code non managé copie des arguments de chaînes, en convertissant du format .NET Framework (Unicode) au format non managé de la plateforme. Les chaînes sont immuables et ne sont pas recopiées à partir de la mémoire non managée vers la mémoire managée au retour d'appel.
Le tableau suivant répertorie les options de marshaling pour les chaînes lorsque celles-ci sont marshalées comme argument de méthode d'un appel de code non managé. L'attribut MarshalAsAttribute fournit plusieurs valeurs d'énumération UnmanagedType pour marshaler des chaînes.
Type énumération |
Description de format non managé |
---|---|
UnmanagedType.AnsiBStr |
BSTR de style COM d'une longueur préfixée et constitué de caractères ANSI. |
UnmanagedType.BStr |
BSTR de style COM d'une longueur préfixée et constitué de caractères Unicode. |
UnmanagedType.LPStr |
Pointeur vers un tableau de caractères ANSI se terminant par null. |
UnmanagedType.LPTStr (par défaut) |
Pointeur vers un tableau de caractères dépendants de la plateforme et se terminant par null. |
UnmanagedType.LPWStr |
Pointeur vers un tableau de caractères Unicode se terminant par null. |
UnmanagedType.TBStr |
BSTR de style COM d'une longueur préfixée et constitué de caractères dépendants de la plateforme. |
VBByRefStr |
Valeur qui permet à Visual Basic .NET de changer une chaîne en code non managé et de répercuter les résultats dans du code managé. Cette valeur est prise en charge uniquement pour l'appel de code non managé. |
Ce tableau s'applique aux chaînes. Toutefois, pour StringBuilder , les seules options autorisées sont LPStr, LPTStr et LPWStr.
La définition de type suivante illustre l'utilisation correcte de MarshalAsAttribute pour les appels de code non managé.
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);
}
Chaînes utilisées dans les structures
Les chaînes sont des membres valides de structures ; cependant, les mémoires tampons StringBuilder sont non valides dans les structures. Le tableau suivant montre les options de marshaling pour les types de données de chaîne lorsque le type est marshalé en tant que champ. L'attribut MarshalAsAttribute fournit plusieurs valeurs d'énumération UnmanagedType pour marshaler des chaînes vers un champ.
Type énumération |
Description de format non managé |
---|---|
UnmanagedType.BStr |
BSTR de style COM d'une longueur préfixée et constitué de caractères Unicode. |
UnmanagedType.LPStr |
Pointeur vers un tableau de caractères ANSI se terminant par null. |
UnmanagedType.LPTStr |
Pointeur vers un tableau de caractères dépendants de la plateforme et se terminant par null. |
UnmanagedType.LPWStr |
Pointeur vers un tableau de caractères Unicode se terminant par null. |
UnmanagedType.ByValTStr |
Tableau de caractères de longueur fixe ; le type du tableau est déterminé par le jeu de caractères de la structure contenante. |
Le type ByValTStr est utilisé pour les tableaux de caractères de longueur fixe, inline qui apparaissent au sein d'une structure. Les autres types s'appliquent aux références de chaîne contenues au sein de structures qui contiennent des pointeurs vers des chaînes.
L'argument CharSet de l'attribut StructLayoutAttribute qui est appliqué à la structure contenante détermine le format de caractères des chaînes dans des structures. Les structures d'exemple suivantes contiennent des références de chaînes et des chaînes inline ainsi que des caractères ANSI, UNICODE et dépendants de la plateforme.
Représentation de la bibliothèque de types
struct StringInfoA {
char * f1;
char f2[256];
};
struct StringInfoW {
WCHAR * f1;
WCHAR f2[256];
BSTR f3;
};
struct StringInfoT {
TCHAR * f1;
TCHAR f2[256];
};
L'exemple de code suivant montre comment utiliser l'attribut MarshalAsAttribute pour définir la même structure dans des formats différents.
<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;
}
Mémoires tampons de chaînes de longueur fixe
Dans certaines circonstances, une mémoire tampon de caractères de longueur fixe doit être passée dans le code non managé afin d'être manipulée. Le simple fait de passer une chaîne ne fonctionne pas dans ce cas car l'appelé ne peut pas modifier le contenu de la mémoire tampon passée. Même si la chaîne est passée par référence, il est impossible d'initialiser la mémoire tampon avec une taille donnée.
La solution consiste à passer une mémoire tampon StringBuilder comme argument plutôt qu'une chaîne. Un StringBuilder peut être déréférencé et modifié par l'appelé à condition qu'il n'excède pas la capacité du StringBuilder. Il peut être également initialisé avec une longueur fixe. Par exemple, si vous initialisez une mémoire tampon StringBuilder avec une capacité de N, le marshaleur fournit une mémoire tampon d'une taille de (N+1) caractères. Le +1 tient compte du fait que la chaîne non managée possède un terminateur null, ce qui n'est pas le cas de StringBuilder.
Par exemple, la fonction GetWindowText de l'API Win32 de Microsoft (définie dans Windows.h) est une mémoire tampon de caractères de longueur fixe qui doit être passée dans le code non managé pour être manipulée. LpString pointe vers une mémoire tampon allouée par l'appelant de taille nMaxCount L'appelant est censé allouer la mémoire tampon et définir l'argument nMaxCount à la taille de la mémoire tampon allouée. Le code suivant illustre la déclaration de fonction GetWindowText telle qu'elle est définie dans Windows.h.
int GetWindowText(
HWND hWnd, // Handle to window or control.
LPTStr lpString, // Text buffer.
int nMaxCount // Maximum number of characters to copy.
);
Un StringBuilder peut être déréférencé et modifié par l'appelé à condition qu'il n'excède pas la capacité du StringBuilder. L'exemple de code suivant démontre comment StringBuilder peut être initialisé à une longueur fixe.
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();
}
}
Voir aussi
Concepts
Types blittables et non blittables