Marshalling predefinito per le stringhe
Entrambe le classi System.String e System.Text.StringBuilder presentano un comportamento di marshalling simile.
Il marshalling delle stringhe viene eseguito come tipo BSTR COM o matrice di caratteri terminante in un riferimento null (Nothing in Visual Basic). È possibile eseguire il marshalling dei caratteri interni alla stringa come caratteri Unicode o ANSI oppure in un modo dipendente dalla piattaforma (Unicode su Microsoft Windows NT, Windows 2000 e Windows XP; ANSI su Windows 98 e Windows Millennium Edition).
In questo argomento sono disponibili le informazioni elencate di seguito sul marshalling dei tipi di stringhe:
Stringhe utilizzate nelle interfacce
Stringhe utilizzate in platform invoke
Stringhe utilizzate nelle strutture
Buffer di stringhe a lunghezza fissa
Stringhe utilizzate nelle interfacce
Nella tabella riportata di seguito vengono mostrate le opzioni per il marshalling del tipo di dati stringa come argomento di metodo sul codice non gestito. L'attributo MarshalAsAttribute fornisce diversi valori dell'enumerazione UnmanagedType per il marshalling di stringhe in interfacce COM.
Tipo di enumerazione |
Descrizione del formato non gestito |
---|---|
UnmanagedType.BStr (impostazione predefinita) |
BSTR di tipo COM con lunghezza prefissata e caratteri Unicode. |
UnmanagedType.LPStr |
Puntatore a matrice con terminazione null di caratteri ANSI. |
UnmanagedType.LPWStr |
Puntatore a matrice con terminazione null di caratteri Unicode. |
Questa tabella si applica alle stringhe. Tuttavia, le uniche opzioni consentite per StringBuilder sono UnmanagedType.LPStr e UnmanagedType.LPWStr.
Nell'esempio riportato di seguito vengono mostrate le stringhe dichiarate nell'interfaccia 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);
);
Nell'esempio seguente viene mostrata l'interfaccia corrispondente descritta in una libreria dei tipi.
[…]
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);
);
Stringhe utilizzate in platform invoke
Gli argomenti di stringa vengono copiati da platform invoke mediante la conversione del formato di .NET Framework (Unicode) in quello non gestito della piattaforma. Le stringhe sono immutabili e non vengono ricopiate dalla memoria non gestita a quella gestita al termine della chiamata.
Nella tabella riportata di seguito sono elencate le opzioni per il marshalling delle stringhe come argomento del metodo di platform invoke. L'attributo MarshalAsAttribute fornisce diversi valori dell'enumerazione UnmanagedType per il marshalling di stringhe.
Tipo di enumerazione |
Descrizione del formato non gestito |
---|---|
UnmanagedType.AnsiBStr |
BSTR di tipo COM con lunghezza prefissata e caratteri ANSI. |
UnmanagedType.BStr |
BSTR di tipo COM con lunghezza prefissata e caratteri Unicode. |
UnmanagedType.LPStr |
Puntatore a matrice con terminazione null di caratteri ANSI. |
UnmanagedType.LPTStr (impostazione predefinita) |
Puntatore a matrice con terminazione null di caratteri dipendenti dalla piattaforma. |
UnmanagedType.LPWStr |
Puntatore a matrice con terminazione null di caratteri Unicode. |
UnmanagedType.TBStr |
BSTR di tipo COM con lunghezza prefissata e caratteri dipendenti dalla piattaforma. |
VBByRefStr |
Valore che consente a Visual Basic .NET di modificare una stringa in codice non gestito e riflettere i risultati in codice gestito. Questo valore è supportato solo per platform invoke. |
Questa tabella si applica alle stringhe. Tuttavia, le uniche opzioni consentite per StringBuilder sono LPStr, LPTStr e LPWStr.
Nella definizione di tipo riportata di seguito viene mostrato l'uso corretto di MarshalAsAttribute per le chiamate platform invoke.
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);
}
Stringhe utilizzate nelle strutture
Le stringhe sono membri validi di strutture, a differenza dei buffer StringBuilder. Nella tabella riportata di seguito vengono elencate le opzioni per il marshalling del tipo di dati stringa come campo. L'attributo MarshalAsAttribute fornisce diversi valori dell'enumerazione UnmanagedType per il marshalling di stringhe in un campo.
Tipo di enumerazione |
Descrizione del formato non gestito |
---|---|
UnmanagedType.BStr |
BSTR di tipo COM con lunghezza prefissata e caratteri Unicode. |
UnmanagedType.LPStr |
Puntatore a matrice con terminazione null di caratteri ANSI. |
UnmanagedType.LPTStr |
Puntatore a matrice con terminazione null di caratteri dipendenti dalla piattaforma. |
UnmanagedType.LPWStr |
Puntatore a matrice con terminazione null di caratteri Unicode. |
UnmanagedType.ByValTStr |
Matrice di caratteri a lunghezza fissa. Il tipo della matrice viene determinato dal set di caratteri della struttura contenitore. |
Il tipo ByValTStr viene utilizzato per matrici di caratteri a lunghezza fissa inline presenti all'interno di una struttura. Gli altri tipi vengono applicati a riferimenti a stringhe all'interno di strutture contenenti puntatori a stringhe.
Il formato carattere delle stringhe nelle strutture è determinato dall'argomento CharSet dell'attributo StructLayoutAttribute applicato alla struttura contenitore. Nelle strutture di esempio riportate di seguito sono contenuti riferimenti a stringhe e stringhe inline, nonché caratteri ANSI, Unicode e dipendenti dalla piattaforma.
Rappresentazione di libreria dei tipi
struct StringInfoA {
char * f1;
char f2[256];
};
struct StringInfoW {
WCHAR * f1;
WCHAR f2[256];
BSTR f3;
};
struct StringInfoT {
TCHAR * f1;
TCHAR f2[256];
};
Nell'esempio di codice riportato di seguito viene illustrato come utilizzare l'attributo MarshalAsAttribute per definire la stessa struttura in diversi formati.
<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;
}
Buffer di stringhe a lunghezza fissa
In alcuni casi, è necessario passare un buffer di caratteri a lunghezza fissa nel codice non gestito da modificare. Il semplice passaggio di una stringa non funziona in questo caso perché il chiamato non può modificare il contenuto del buffer passato. Anche se la stringa viene passata per riferimento, non è possibile inizializzare il buffer su una dimensione specifica.
La soluzione consiste nel passare come argomento un buffer StringBuilder anziché una stringa. Il chiamato può annullare i riferimenti e modificare un oggetto StringBuilder, purché non venga superata la capacità dell'oggetto StringBuilder stesso. È anche possibile inizializzare questo oggetto in base a una lunghezza fissa. Se, ad esempio, si inizializza un buffer StringBuilder per una capacità pari a N, un buffer di caratteri di dimensione (N+1) viene fornito dal gestore di marshalling. Il valore +1 tiene conto del fatto che, a differenza di StringBuilder, la stringa non gestita ha una terminazione null.
La funzione GetWindowText dell'API Microsoft Win32 (definita in Windows.h) rappresenta ad esempio un buffer di caratteri a lunghezza fissa che deve essere passato nel codice non gestito per essere modificato. LpString punta a un buffer allocato dal chiamante di dimensione nMaxCount. Il chiamante deve allocare il buffer e impostare l'argomento nMaxCount sulla dimensione del buffer allocato. Nel codice riportato di seguito viene illustrata la dichiarazione della funzione GetWindowText come definita in Windows.h.
int GetWindowText(
HWND hWnd, // Handle to window or control.
LPTStr lpString, // Text buffer.
int nMaxCount // Maximum number of characters to copy.
);
Il chiamato può annullare i riferimenti e modificare un oggetto StringBuilder, purché non venga superata la capacità dell'oggetto StringBuilder stesso. Nell'esempio di codice riportato di seguito viene mostrato come inizializzare StringBuilder in base a una lunghezza fissa.
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();
}
}
Vedere anche
Concetti
tipi copiabili e non copiabili