Megosztás a következőn keresztül:


Sztringek alapértelmezett betöltése

Mind a System.String, mind a System.Text.StringBuilder osztályok hasonló rendezési viselkedést mutatnak.

A sztringek COM-stílusú BSTR típusként vagy null értékű karakterláncként vannak rendezve (null karakterrel végződő karaktertömb). A sztringen belüli karakterek Unicode -ként (windowsos rendszereken alapértelmezett) vagy ANSI-ként rendezhetők.

Interfészekben használt karakterláncok

Az alábbi táblázat bemutatja a sztring adattípusának átadási módszereit, amikor metódusargumentumként kerül átadásra a nem felügyelt kódhoz. Az MarshalAsAttribute attribútum több UnmanagedType felsorolt értéket kínál a karakterláncok COM-felületekhez való marshalolásához.

Számbavétel típusa A nem felügyelt formátum leírása
UnmanagedType.BStr (alapértelmezett) COM-stílusú BSTR , előtaggal ellátott hosszúságú és Unicode-karakterekkel.
UnmanagedType.LPStr Egy nullával lezárt ANSI karaktereket tartalmazó tömbre mutató mutató.
UnmanagedType.LPWStr Nullával lezárt Unicode karakterek tömbjének mutatója.

Ez a tábla a következőkre Stringvonatkozik: . Ebben StringBuilderaz esetben csak a következő lehetőségek engedélyezettek UnmanagedType.LPStr : és UnmanagedType.LPWStr.

Az alábbi példa a IStringWorker felületen deklarált sztringeket mutatja be.

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

Az alábbi példa egy típustárban leírt megfelelő felületet mutatja be.

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);
};

A platformhívásban használt karakterláncok

Ha a CharSet Unicode, vagy egy karakterlánc-argumentumot explicit módon [MarshalAs(UnmanagedType.LPWSTR)] jelöléssel láttak el, és a karakterláncot érték szerint adják át (nem ref és nem out), a karakterlánc rögzítve lesz, és közvetlenül a natív kód használja fel. Ellenkező esetben a Platform Invoke másolja a sztringargumentumokat, és a .NET-keretrendszer formátumából (Unicode) konvertálja a platform nem felügyelt formátumára. A sztringek nem módosíthatók, és nem lesznek visszamásolva a nem felügyelt memóriából a felügyelt memóriába a hívás visszatérésekor.

A natív kód csak akkor adja ki a memóriát, ha a sztringet hivatkozással adja át, és új értéket rendel hozzá. Ellenkező esetben a .NET-futtatókörnyezet a memória tulajdonosa, és a hívás után felszabadítja azt.

Az alábbi táblázat felsorolja a sztringek kiküldési opcióit, amikor platformhívás metódusargumentumaként kiküldésre kerülnek. Az MarshalAsAttribute attribútum számos UnmanagedType enumerálási értéket biztosít a marshal sztringekhez.

Számbavétel típusa A nem felügyelt formátum leírása
UnmanagedType.AnsiBStr COM-formátumú BSTR hosszelőtaggal és ANSI-karakterekkel.
UnmanagedType.BStr COM-stílusú BSTR , előtaggal ellátott hosszúságú és Unicode-karakterekkel.
UnmanagedType.LPStr (alapértelmezett) Egy nullával lezárt ANSI karaktereket tartalmazó tömbre mutató mutató.
UnmanagedType.LPTStr Egy mutató, amely egy platformfüggő karaktereket tartalmazó, nullával lezárt tömbre mutat.
UnmanagedType.LPUTF8Str Az UTF-8 kódolású karakterek nullával lezárt tömbjére mutató mutató.
UnmanagedType.LPWStr Nullával lezárt Unicode karakterek tömbjének mutatója.
UnmanagedType.TBStr COM-stílus BSTR előtaggal és platformfüggetlen karakterekkel.
VBByRefStr Olyan érték, amely lehetővé teszi, hogy a Visual Basic módosítson egy sztringet nem felügyelt kódban, és hogy az eredmények megjelenjenek a felügyelt kódban. Ez az érték csak platformhívás esetén támogatott. Ez az alapértelmezett érték a Visual Basicben a ByVal sztringekhez.

Ez a tábla a következőkre Stringvonatkozik: . Az StringBuilder esetében az egyetlen megengedett lehetőségek az LPStr, LPTStr és LPWStr.

Az alábbi típusdefiníció a platformhívási MarshalAsAttribute hívások helyes használatát mutatja.

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

Struktúrákban használt karakterláncok

A sztringek a struktúrák érvényes tagjai; a StringBuilder pufferek azonban érvénytelenek a struktúrákban. Az alábbi táblázat az String adattípus csatornázási lehetőségeit mutatja be, amikor a típus mezőként van csatornázva. Az MarshalAsAttribute attribútum számos UnmanagedType enumerálási értéket biztosít karakterláncok mezőhöz való csatolásához.

Számbavétel típusa A nem felügyelt formátum leírása
UnmanagedType.BStr COM-stílusú BSTR , előtaggal ellátott hosszúságú és Unicode-karakterekkel.
UnmanagedType.LPStr (alapértelmezett) Egy nullával lezárt ANSI karaktereket tartalmazó tömbre mutató mutató.
UnmanagedType.LPTStr Egy mutató, amely egy platformfüggő karaktereket tartalmazó, nullával lezárt tömbre mutat.
UnmanagedType.LPUTF8Str Az UTF-8 kódolású karakterek nullával lezárt tömbjére mutató mutató.
UnmanagedType.LPWStr Nullával lezárt Unicode karakterek tömbjének mutatója.
UnmanagedType.ByValTStr Rögzített hosszúságú karaktertömb; a tömb típusát az azt tartalmazó struktúra karakterkészlete határozza meg.

A ByValTStr típus beágyazott, rögzített hosszúságú karaktertömbökhöz használatos, amelyek egy struktúrában jelennek meg. Más típusok a sztringekre mutató mutatókat tartalmazó struktúrákban található sztringhivatkozásokra vonatkoznak.

A CharSet szerkezet alapján alkalmazott StructLayoutAttribute argumentum határozza meg a struktúrák sztringjeinek karakterformátumát. Az alábbi példastruktúrák sztringhivatkozásokat és beágyazott sztringeket, valamint ANSI-, Unicode- és platformfüggő karaktereket tartalmaznak. Ezeknek a struktúráknak a típustárban való ábrázolása a következő C++ kódban jelenik meg:

struct StringInfoA
{
    char *  f1;
    char    f2[256];
};

struct StringInfoW
{
    WCHAR * f1;
    WCHAR   f2[256];
    BSTR    f3;
};

struct StringInfoT
{
    TCHAR * f1;
    TCHAR   f2[256];
};

Az alábbi példa bemutatja, hogyan definiálhatja ugyanazt a MarshalAsAttribute struktúrát különböző formátumokban.

[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

Rögzített hosszúságú karakterláncpufferek

Bizonyos körülmények között a rögzített hosszúságú karakterpuffert nem felügyelt kódba kell továbbítani a manipuláláshoz. A sztringek egyszerű átadása ebben az esetben nem működik, mert a hívó nem tudja módosítani az átadott puffer tartalmát. Még akkor sem inicializálhatja a puffert egy adott méretre, ha a sztringet hivatkozással továbbítja.

A megoldás az, hogy a várt kódolástól függően egy byte[] vagy char[] argumentumot adunk át ahelyett, hogy egy String. A tömb, ha [Out]-val meg van jelölve, a hívott fél megtekintheti és módosíthatja, feltéve, hogy az nem haladja meg a lefoglalt tömb kapacitását.

A (GetWindowText nyelven definiált) Windows API-függvény például megköveteli, hogy a hívó egy rögzített hosszúságú karakterpuffert adjon át, amelybe a függvény az ablak szövegét írja. Az lpString argumentum egy hívó által lefoglalt méretű nMaxCountpufferre mutat. A hívó várhatóan lefoglalja a puffert, és az nMaxCount argumentumot a lefoglalt puffer méretére állítja. Az alábbi példa a GetWindowTextwinuser.h fájlban definiált függvénydeklarációt mutatja be.

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

Az A-t char[] a hívó elhalaszthatja és módosíthatja. Az alábbi példakód bemutatja, hogyan lehet egy ArrayPool<char>-t előre lefoglalni a char[] segítségével.

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

Egy másik megoldás az, hogy egy StringBuilder-t ad meg argumentumként, ahelyett, hogy egy String-t. A StringBuilder szerializáláskor létrehozott puffert a fogadó visszakeresheti és módosíthatja, feltéve, hogy az nem haladja meg a StringBuilder kapacitását. Rögzített hosszúságúra is inicializálható. Például, ha inicializál egy StringBuilder puffert N kapacitásra, a kiosztó egy (N+1) karakter hosszúságú puffert biztosít. A +1 azért van, mert a nem felügyelt karakterlánc null terminátort tartalmaz, miközben StringBuilder nem.

Megjegyzés:

Általában nem ajánlott StringBuilder argumentumok átadása, ha aggódik a teljesítmény miatt. További információ: Sztringparaméterek.

Lásd még