Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Både klasserna System.String och System.Text.StringBuilder har liknande hantering av data.
Strängar ordnas som en COM-typ BSTR eller som en null-avslutad sträng (en teckenmatris som slutar med ett null-tecken). Tecknen i strängen kan ordnas som Unicode (som är standard på Windows-system) eller ANSI.
Strängar som används i gränssnitt
I följande tabell visas marshallingsalternativen för strängdatatypen när de är ordnade som ett metodargument till ohanterad kod. Attributet MarshalAsAttribute innehåller flera UnmanagedType uppräkningsvärden för att konvertera strängar till COM-gränssnitt.
| Uppräkningstyp | Beskrivning av ohanterat format |
|---|---|
UnmanagedType.BStr (standardinställning) |
Ett COM-format BSTR med prefixlängd och Unicode-tecken. |
UnmanagedType.LPStr |
En pekare till en null-avslutad matris med ANSI-tecken. |
UnmanagedType.LPWStr |
En pekare till en null-avslutad matris med Unicode-tecken. |
Den här tabellen gäller för String. För StringBuilderär UnmanagedType.LPStr de enda tillåtna alternativen och UnmanagedType.LPWStr.
I följande exempel visas strängar som deklarerats i IStringWorker gränssnittet.
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
I följande exempel visas motsvarande gränssnitt som beskrivs i ett typbibliotek.
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);
};
Strängar som används i plattformsanrop
När CharSet är Unicode eller ett strängargument uttryckligen markeras som [MarshalAs(UnmanagedType.LPWSTR)] och strängen skickas med värde (inte ref eller out), fästs strängen och används direkt av den interna koden. Annars använder platform invoke för att kopiera strängargument och konvertera från .NET Framework-formatet (Unicode) till det ohanterade plattformsformatet. Strängar är oföränderliga och kopieras inte tillbaka från ohanterat minne till hanterat minne när anropet returneras.
Inbyggd kod ansvarar endast för att frigöra minnet när strängen skickas som en referens och när ett nytt värde tilldelas. Annars hanteras minnet av .NET-körtiden och frigörs efter anropet.
I följande tabell listas alternativen för strängmarshaling när dessa används som metodargument vid ett plattformsanrop. Attributet MarshalAsAttribute tillhandahåller flera UnmanagedType uppräkningsvärden för att överföra strängar.
| Uppräkningstyp | Beskrivning av ohanterat format |
|---|---|
UnmanagedType.AnsiBStr |
En COM-stil BSTR med en förprefixad längd och ANSI-tecken. |
UnmanagedType.BStr |
Ett COM-format BSTR med prefixlängd och Unicode-tecken. |
UnmanagedType.LPStr (standardinställning) |
En pekare till en null-avslutad matris med ANSI-tecken. |
UnmanagedType.LPTStr |
En pekare till en null-avslutad matris med plattformsberoende tecken. |
UnmanagedType.LPUTF8Str |
En pekare till en null-avslutad matris med UTF-8-kodade tecken. |
UnmanagedType.LPWStr |
En pekare till en null-avslutad matris med Unicode-tecken. |
UnmanagedType.TBStr |
Ett COM-format BSTR med prefixlängd och plattformsberoende tecken. |
VBByRefStr |
Ett värde som gör att Visual Basic kan ändra en sträng i ohanterad kod och få resultatet att återspeglas i hanterad kod. Det här värdet stöds endast för plattformsanrop. Det här är standardvärdet i Visual Basic för ByVal strängar. |
Den här tabellen gäller för String. För StringBuilderär LPStrde enda tillåtna alternativen , LPTStroch LPWStr.
Följande typdefinition visar korrekt användning av MarshalAsAttribute för plattformsanrop.
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
Strängar som används i strukturer
Strängar är giltiga medlemmar i strukturer. Buffertar är dock StringBuilder ogiltiga i strukturer. I följande tabell visas marshallingalternativen för datatypen String när typen hanteras som ett fält. Attributet MarshalAsAttribute innehåller flera UnmanagedType uppräkningsvärden för att konvertera strängar till ett fält.
| Uppräkningstyp | Beskrivning av ohanterat format |
|---|---|
UnmanagedType.BStr |
Ett COM-format BSTR med prefixlängd och Unicode-tecken. |
UnmanagedType.LPStr (standardinställning) |
En pekare till en null-avslutad matris med ANSI-tecken. |
UnmanagedType.LPTStr |
En pekare till en null-avslutad matris med plattformsberoende tecken. |
UnmanagedType.LPUTF8Str |
En pekare till en null-avslutad matris med UTF-8-kodade tecken. |
UnmanagedType.LPWStr |
En pekare till en null-avslutad matris med Unicode-tecken. |
UnmanagedType.ByValTStr |
En matris med fast längd med tecken. matrisens typ bestäms av teckenuppsättningen för den innehållande strukturen. |
Typen ByValTStr används för infogade teckenmatriser med fast längd som visas i en struktur. Andra typer gäller för strängreferenser som finns i strukturer som innehåller pekare till strängar.
Argumentet CharSet för det StructLayoutAttribute som tillämpas på den innehållande strukturen avgör teckenformatet för strängarna i strukturerna. Följande exempelstrukturer innehåller strängreferenser och infogade strängar, samt ANSI, Unicode och plattformsberoende tecken. Representationen av dessa strukturer i ett typbibliotek visas i följande C++-kod:
struct StringInfoA
{
char * f1;
char f2[256];
};
struct StringInfoW
{
WCHAR * f1;
WCHAR f2[256];
BSTR f3;
};
struct StringInfoT
{
TCHAR * f1;
TCHAR f2[256];
};
I följande exempel visas hur du använder MarshalAsAttribute för att definiera samma struktur i olika format.
[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
Strängbuffertar med fast längd
I vissa fall måste en buffert med fast längd skickas till ohanterad kod för att manipuleras. Att bara skicka en sträng fungerar inte i det här fallet eftersom anroparen inte kan ändra innehållet i den skickade bufferten. Även om strängen skickas som referens finns det inget sätt att initiera bufferten till en viss storlek.
Lösningen är att skicka en byte[] eller char[], beroende på förväntad kodning, som argument i stället för en String. Matrisen, när den är markerad med [Out], kan derefereras och ändras av anroparen, förutsatt att den inte överskrider kapaciteten för den allokerade matrisen.
Windows API-funktionen (definierad i GetWindowText) kräver till exempel att anroparen skickar en buffert med fast längd som funktionen skriver fönstrets text till. Argumentet lpString pekar på en anropare allokerad buffert av storlek nMaxCount. Anroparen förväntas allokera bufferten och ange nMaxCount argumentet till storleken på den allokerade bufferten. I följande exempel visas funktionsdeklarationen GetWindowText enligt definitionen i winuser.h.
int GetWindowText(
HWND hWnd, // Handle to window or control.
LPTStr lpString, // Text buffer.
int nMaxCount // Maximum number of characters to copy.
);
A char[] kan derefereras och ändras av anroparen. I följande kodexempel demonstreras hur ArrayPool<char> kan användas för att förallokera en 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
En annan lösning är att skicka ett StringBuilder som argument i stället för en String. Bufferten som skapas när StringBuilder marshallas kan derefereras och ändras av den anropade, förutsatt att den inte överskrider kapaciteten för StringBuilder. Den kan också initieras till en fast längd. Om du till exempel initierar en StringBuilder buffert med en kapacitet på N, ger marshalleren en buffert med storlek (N+1) tecken. +1 står för det faktum att den ohanterade strängen har en null-terminator medan StringBuilder inte har det.
Anmärkning
I allmänhet rekommenderas inte att skicka StringBuilder argument om du är orolig för prestanda. Mer information finns i Strängparametrar.