Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Entrambe le classi System.String e System.Text.StringBuilder hanno un simile comportamento di marshalling.
Le stringhe sono marshallate come tipo BSTR in stile COM o come stringa terminata da null (un array di caratteri che termina con un carattere null). I caratteri all'interno della stringa possono essere distribuiti come Unicode (impostazione predefinita nei sistemi Windows) o ANSI.
Stringhe usate nelle interfacce
Nella tabella seguente vengono illustrate le opzioni di marshalling per il tipo di dati stringa quando viene eseguito il marshalling come argomento del metodo al codice non gestito. L'attributo MarshalAsAttribute fornisce diversi UnmanagedType valori di enumerazione per effettuare il marshalling delle stringhe alle interfacce COM.
| Tipo di enumerazione | Descrizione del formato non gestito |
|---|---|
UnmanagedType.BStr (impostazione predefinita) |
Uno stile COM BSTR con lunghezza prefissata e caratteri Unicode. |
UnmanagedType.LPStr |
Puntatore a una matrice con terminazione Null di caratteri ANSI. |
UnmanagedType.LPWStr |
Puntatore a una matrice con terminazione Null di caratteri Unicode. |
Questa tabella si applica a String. Per StringBuilder, le uniche opzioni consentite sono UnmanagedType.LPStr e UnmanagedType.LPWStr.
Nell'esempio seguente vengono illustrate 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);
}
Public Interface IStringWorker
Sub PassString1(s As String)
Sub PassString2(<MarshalAs(UnmanagedType.BStr)> s As String)
Sub PassString3(<MarshalAs(UnmanagedType.LPStr)> s As String)
Sub PassString4(<MarshalAs(UnmanagedType.LPWStr)> s As String)
Sub PassStringRef1(ByRef s As String)
Sub PassStringRef2(<MarshalAs(UnmanagedType.BStr)> ByRef s As String)
Sub PassStringRef3(<MarshalAs(UnmanagedType.LPStr)> ByRef s As String)
Sub PassStringRef4(<MarshalAs(UnmanagedType.LPWStr)> ByRef s As String)
End Interface
Nell'esempio seguente viene illustrata 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 usate in P/Invoke
Quando il CharSet è impostato su Unicode o un argomento stringa viene contrassegnato in modo esplicito come [MarshalAs(UnmanagedType.LPWSTR)] e la stringa viene passata come valore (non ref o out), la stringa viene bloccata e utilizzata direttamente dal codice nativo. In caso contrario, platform invoke copia gli argomenti stringa, convertendo dal formato .NET Framework (Unicode) al formato non gestito della piattaforma. Le stringhe non sono modificabili e non vengono copiate dalla memoria non gestita alla memoria gestita quando la chiamata viene restituita.
Il codice nativo è responsabile solo del rilascio della memoria quando la stringa viene passata per riferimento e assegna un nuovo valore. In caso contrario, il runtime .NET possiede la memoria e la rilascia dopo la chiamata.
Nella tabella seguente sono elencate le opzioni di marshalling per le stringhe quando vengono eseguite come argomento del metodo di una chiamata di invocazione della piattaforma. L'attributo MarshalAsAttribute fornisce diversi UnmanagedType valori di enumerazione per effettuare il marshalling delle stringhe.
| Tipo di enumerazione | Descrizione del formato non gestito |
|---|---|
UnmanagedType.AnsiBStr |
Stile COM BSTR con lunghezza prefissata e caratteri ANSI. |
UnmanagedType.BStr |
Uno stile COM BSTR con lunghezza prefissata e caratteri Unicode. |
UnmanagedType.LPStr (impostazione predefinita) |
Puntatore a una matrice con terminazione Null di caratteri ANSI. |
UnmanagedType.LPTStr |
Puntatore a una matrice con terminazione Null di caratteri dipendenti dalla piattaforma. |
UnmanagedType.LPUTF8Str |
Puntatore a una matrice di caratteri codificati in UTF-8 terminata da un valore zero. |
UnmanagedType.LPWStr |
Puntatore a una matrice con terminazione Null di caratteri Unicode. |
UnmanagedType.TBStr |
Stile COM BSTR con una lunghezza prefissata e caratteri dipendenti dalla piattaforma. |
VBByRefStr |
Valore che consente a Visual Basic di modificare una stringa nel codice non gestito e di riflettere i risultati nel codice gestito. Questo valore è supportato solo per platform invoke. Questo è il valore predefinito in Visual Basic per ByVal le stringhe. |
Questa tabella si applica a String. Per StringBuilder, le uniche opzioni consentite sono LPStr, LPTStre LPWStr.
La definizione di tipo seguente mostra l'uso corretto di MarshalAsAttribute per le chiamate platform invoke.
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 PassLPUTF8Str([MarshalAs(UnmanagedType.LPUTF8Str)] 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);
}
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 PassLPUTF8Str Lib "StringLib.dll" (
<MarshalAs(UnmanagedType.LPUTF8Str)> 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
Stringhe usate nelle strutture
Le stringhe sono membri validi di strutture; Tuttavia, StringBuilder i buffer non sono validi nelle strutture. Nella tabella seguente vengono illustrate le opzioni di marshalling per il String tipo di dati quando il tipo viene sottoposto a marshalling come campo. L'attributo MarshalAsAttribute fornisce diversi UnmanagedType valori di enumerazione per effettuare il marshalling delle stringhe in un campo.
| Tipo di enumerazione | Descrizione del formato non gestito |
|---|---|
UnmanagedType.BStr |
Uno stile COM BSTR con lunghezza prefissata e caratteri Unicode. |
UnmanagedType.LPStr (impostazione predefinita) |
Puntatore a una matrice con terminazione Null di caratteri ANSI. |
UnmanagedType.LPTStr |
Puntatore a una matrice con terminazione Null di caratteri dipendenti dalla piattaforma. |
UnmanagedType.LPUTF8Str |
Puntatore a una matrice di caratteri codificati in UTF-8 terminata da un valore zero. |
UnmanagedType.LPWStr |
Puntatore a una matrice con terminazione Null di caratteri Unicode. |
UnmanagedType.ByValTStr |
Matrice a lunghezza fissa di caratteri; il tipo della matrice è determinato dal set di caratteri della struttura contenitore. |
Il ByValTStr tipo viene usato per matrici di caratteri a lunghezza fissa inline visualizzate all'interno di una struttura. Altri tipi si applicano ai riferimenti stringa contenuti all'interno di strutture che contengono puntatori alle stringhe.
L'argomento CharSet della funzione StructLayoutAttribute applicata alla struttura contenitore determina il formato dei caratteri delle stringhe nelle strutture. Le strutture di esempio seguenti contengono riferimenti a stringhe e stringhe inline, nonché caratteri ANSI, Unicode e dipendenti dalla piattaforma. La rappresentazione di queste strutture in una libreria dei tipi è illustrata nel codice C++ seguente:
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 seguente viene illustrato come usare MarshalAsAttribute per definire la stessa struttura in formati diversi.
[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;
}
<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
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 in una determinata dimensione.
La soluzione consiste nel passare un byte[] o un char[], a seconda della codifica prevista, come argomento anziché un String. La matrice, se contrassegnata con [Out], può essere dereferenziata e modificata dal chiamato, purché non superi la capacità della matrice allocata.
Ad esempio, la funzione API Windows GetWindowText (definita in winuser.h) richiede che il chiamante passi un buffer di caratteri a lunghezza fissa a cui la funzione scrive il testo della finestra. L'argomento lpString punta a un buffer allocato dal chiamante di dimensioni nMaxCount. Il chiamante deve allocare il buffer e impostare l'argomento nMaxCount alla dimensione del buffer allocato. L'esempio seguente mostra la dichiarazione di GetWindowText funzione come definita in winuser.h.
int GetWindowText(
HWND hWnd, // Handle to window or control.
LPTStr lpString, // Text buffer.
int nMaxCount // Maximum number of characters to copy.
);
Un char[] oggetto può essere dereferenziato e modificato dal chiamato. Nell'esempio di codice seguente viene illustrato come ArrayPool<char> possa essere usato per pre-allocare un char[].
using System;
using System.Buffers;
using System.Runtime.InteropServices;
internal static class NativeMethods
{
[DllImport("User32.dll", CharSet = CharSet.Unicode)]
public static extern void GetWindowText(IntPtr hWnd, [Out] char[] lpString, int nMaxCount);
}
public class Window
{
internal IntPtr h; // Internal handle to Window.
public string GetText()
{
char[] buffer = ArrayPool<char>.Shared.Rent(256 + 1);
NativeMethods.GetWindowText(h, buffer, buffer.Length);
return new string(buffer);
}
}
Imports System
Imports System.Buffers
Imports System.Runtime.InteropServices
Friend Class NativeMethods
Public Declare Auto Sub GetWindowText Lib "User32.dll" _
(hWnd As IntPtr, <Out> lpString() As Char, nMaxCount As Integer)
End Class
Public Class Window
Friend h As IntPtr ' Friend handle to Window.
Public Function GetText() As String
Dim buffer() As Char = ArrayPool(Of Char).Shared.Rent(256 + 1)
NativeMethods.GetWindowText(h, buffer, buffer.Length)
Return New String(buffer)
End Function
End Class
Un'altra soluzione consiste nel passare un StringBuilder come argomento anziché un String. Il buffer creato durante il marshalling di un StringBuilder può essere dereferenziato e modificato dal chiamato, purché non superi la capacità di StringBuilder. Può anche essere inizializzato a lunghezza fissa. Ad esempio, se si inizializza un StringBuilder buffer con una capacità di N, il marshaller fornisce un buffer di caratteri con dimensione (N+1). +1 indica il fatto che la stringa non gestita ha un carattere di terminazione Null mentre StringBuilder non lo è.
Annotazioni
In generale, il passaggio di StringBuilder argomenti non è consigliato se si è preoccupati per le prestazioni. Per altre informazioni, vedere Parametri stringa.
Vedere anche
- Comportamento di marshalling predefinito
- Gestione delle stringhe
- Blittable and Non-Blittable Types (Tipi copiabili da BLT e non copiabili da BLT)
- attributi direzionali
- Copia e fissaggio