Маршалинг по умолчанию для строкDefault Marshaling for Strings

Классы System.String и System.Text.StringBuilder ведут себя при маршалинге одинаково.Both the System.String and System.Text.StringBuilder classes have similar marshaling behavior.

Строки маршалируются как тип BSTR стиля COM или как строка (массив символов), заканчивающаяся символом null.Strings are marshaled as a COM-style BSTR type or as a null-terminated string (a character array that ends with a null character). Символы в строке могут маршалироваться как символы Юникода (по умолчанию в системах Windows) или символы в кодировке ANSI.The characters within the string can be marshaled as Unicode (the default on Windows systems) or ANSI.

Строки, используемые в интерфейсахStrings Used in Interfaces

В таблице ниже показаны варианты маршалинга данных строкового типа в неуправляемый код в качестве аргумента метода.The following table shows the marshaling options for the string data type when marshaled as a method argument to unmanaged code. Атрибут MarshalAsAttribute предоставляет несколько значений перечисления UnmanagedType для маршалинга строк в COM-интерфейсы.The MarshalAsAttribute attribute provides several UnmanagedType enumeration values to marshal strings to COM interfaces.

Тип перечисленияEnumeration type Описание неуправляемого форматаDescription of unmanaged format
UnmanagedType.BStr (по умолчанию)UnmanagedType.BStr (default) Тип BSTR стиля COM с фиксированной длиной и символами Юникода.A COM-style BSTR with a prefixed length and Unicode characters.
UnmanagedType.LPStr Указатель на массив символов в кодировке ANSI, завершающийся значением null.A pointer to a null-terminated array of ANSI characters.
UnmanagedType.LPWStr Указатель на строку знаков в кодировке Юникод, завершающуюся нулевым значением.A pointer to a null-terminated array of Unicode characters.

Эта таблица применяется к String.This table applies to String. Для StringBuilder единственными допустимыми вариантами являются UnmanagedType.LPStr и UnmanagedType.LPWStr.For StringBuilder, the only options allowed are UnmanagedType.LPStr and UnmanagedType.LPWStr.

В примере ниже показаны строки, объявленные в интерфейсе IStringWorker.The following example shows strings declared in the IStringWorker interface.

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

В примере ниже показан соответствующий интерфейс, описанный в библиотеке типов.The following example shows the corresponding interface described in a type library.

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

Строки, используемые в вызовах неуправляемого кодаStrings Used in Platform Invoke

Вызов неуправляемого кода копирует строковые аргументы, выполняя преобразование из формата .NET Framework (Юникод) в неуправляемый формат платформы.Platform invoke copies string arguments, converting from the .NET Framework format (Unicode) to the platform unmanaged format. При возврате из вызова строки не изменяются и не копируются обратно из неуправляемой памяти в управляемую.Strings are immutable and are not copied back from unmanaged memory to managed memory when the call returns.

В таблице ниже перечислены варианты маршалинга для строк, маршалируемых в качестве аргумента метода при вызове неуправляемого кода.The following table lists the marshaling options for strings when marshaled as a method argument of a platform invoke call. Атрибут MarshalAsAttribute предоставляет несколько значений перечисления UnmanagedType для маршалинга строк.The MarshalAsAttribute attribute provides several UnmanagedType enumeration values to marshal strings.

Тип перечисленияEnumeration type Описание неуправляемого форматаDescription of unmanaged format
UnmanagedType.AnsiBStr Тип BSTR стиля COM с фиксированной длиной и символами в кодировке ANSI.A COM-style BSTR with a prefixed length and ANSI characters.
UnmanagedType.BStr Тип BSTR стиля COM с фиксированной длиной и символами Юникода.A COM-style BSTR with a prefixed length and Unicode characters.
UnmanagedType.LPStr (по умолчанию)UnmanagedType.LPStr (default) Указатель на массив символов в кодировке ANSI, завершающийся значением null.A pointer to a null-terminated array of ANSI characters.
UnmanagedType.LPTStr Указатель на массив символов, завершающийся значением null, в зависящей от платформы кодировке.A pointer to a null-terminated array of platform-dependent characters.
UnmanagedType.LPUTF8Str Указатель на строку знаков в кодировке UTF-8, завершающуюся нулевым значением.A pointer to a null-terminated array of UTF-8 encoded characters.
UnmanagedType.LPWStr Указатель на строку знаков в кодировке Юникод, завершающуюся нулевым значением.A pointer to a null-terminated array of Unicode characters.
UnmanagedType.TBStr Тип BSTR стиля COM с фиксированной длиной и символами в кодировке, зависящей от платформы.A COM-style BSTR with a prefixed length and platform-dependent characters.
VBByRefStr Значение, позволяющее Visual Basic .NET изменять строку в неуправляемом коде и получать результаты, отраженные в управляемом коде.A value that enables Visual Basic .NET to change a string in unmanaged code and have the results reflected in managed code. Это значение поддерживается только для вызова неуправляемого кода.This value is supported only for platform invoke. Это значение по умолчанию для строк ByVal в Visual Basic.This is the default value in Visual Basic for ByVal strings.

Эта таблица применяется к String.This table applies to String. Для StringBuilder единственными допустимыми вариантами являются LPStr, LPTStr и LPWStr.For StringBuilder, the only options allowed are LPStr, LPTStr, and LPWStr.

В определении типа ниже показано правильное использование атрибута MarshalAsAttribute для вызовов неуправляемого кода.The following type definition shows the correct use of MarshalAsAttribute for platform invoke calls.

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

Строки, используемые в структурахStrings Used in Structures

Строки являются допустимыми элементами структур, но буферы StringBuilder недопустимы в структурах.Strings are valid members of structures; however, StringBuilder buffers are invalid in structures. В таблице ниже показаны варианты маршалинга для типа данных String при маршалинге типа как поля.The following table shows the marshaling options for the String data type when the type is marshaled as a field. Атрибут MarshalAsAttribute предоставляет несколько значений перечисления UnmanagedType для маршалинга строк в поле.The MarshalAsAttribute attribute provides several UnmanagedType enumeration values to marshal strings to a field.

Тип перечисленияEnumeration type Описание неуправляемого форматаDescription of unmanaged format
UnmanagedType.BStr Тип BSTR стиля COM с фиксированной длиной и символами Юникода.A COM-style BSTR with a prefixed length and Unicode characters.
UnmanagedType.LPStr (по умолчанию)UnmanagedType.LPStr (default) Указатель на массив символов в кодировке ANSI, завершающийся значением null.A pointer to a null-terminated array of ANSI characters.
UnmanagedType.LPTStr Указатель на массив символов, завершающийся значением null, в зависящей от платформы кодировке.A pointer to a null-terminated array of platform-dependent characters.
UnmanagedType.LPUTF8Str Указатель на строку знаков в кодировке UTF-8, завершающуюся нулевым значением.A pointer to a null-terminated array of UTF-8 encoded characters.
UnmanagedType.LPWStr Указатель на строку знаков в кодировке Юникод, завершающуюся нулевым значением.A pointer to a null-terminated array of Unicode characters.
UnmanagedType.ByValTStr Массив символов фиксированной длины; тип массива определяется кодировкой содержащей его структуры.A fixed-length array of characters; the array's type is determined by the character set of the containing structure.

Тип ByValTStr используется для встроенных массивов символов фиксированной длины, расположенных в структуре.The ByValTStr type is used for inline, fixed-length character arrays that appear within a structure. Другие типы применяются к ссылкам на строки, включенным в структуры, содержащие указатели на строки.Other types apply to string references contained within structures that contain pointers to strings.

Аргумент CharSet класса StructLayoutAttribute, применяемый к содержащей указатели структуре, определяет формат символов строк в структурах.The CharSet argument of the StructLayoutAttribute that is applied to the containing structure determines the character format of strings in structures. Ниже приведены примеры структур, содержащих ссылки на строки и встроенные строки, а также символы в кодировках ANSI, Юникод и кодировке, зависящей от платформы.The following example structures contain string references and inline strings, as well as ANSI, Unicode, and platform-dependent characters. Представление этих структур в библиотеке типов показано в следующем коде C++:The representation of these structures in a type library is shown in the following C++ code:

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

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

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

В примере ниже показано, как с помощью класса MarshalAsAttribute определить одну и ту же структуру в различных форматах.The following example shows how to use the MarshalAsAttribute to define the same structure in different formats.

[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

Буферы строк фиксированной длиныFixed-Length String Buffers

При некоторых обстоятельствах необходимо передавать в неуправляемый код для обработки символьные буферы фиксированной длины.In some circumstances, a fixed-length character buffer must be passed into unmanaged code to be manipulated. Простая передача строки в этом случае не работает, так как вызываемый объект не может изменять содержимое переданного буфера.Simply passing a string does not work in this case because the callee cannot modify the contents of the passed buffer. Даже если строка передается по ссылке, не существует способа инициализации буфера заданного размера.Even if the string is passed by reference, there is no way to initialize the buffer to a given size.

Решением является передача в качестве аргумента буфера StringBuilder вместо String.The solution is to pass a StringBuilder buffer as the argument instead of a String. Буфер StringBuilder может быть разыменован и изменен вызываемым объектом при условии, что он не превышает емкость StringBuilder.A StringBuilder can be dereferenced and modified by the callee, provided it does not exceed the capacity of the StringBuilder. Его также можно инициализировать с фиксированной длиной.It can also be initialized to a fixed length. Например, если вы инициализируете буфер StringBuilder емкостью N, упаковщик предоставляет буфер размером (N+1) символов.For example, if you initialize a StringBuilder buffer to a capacity of N, the marshaler provides a buffer of size (N+1) characters. Дополнительный символ объясняется тем, что неуправляемая строка заканчивается символом null, а буфер StringBuilder нет.The +1 accounts for the fact that the unmanaged string has a null terminator while StringBuilder does not.

Например, функция API GetWindowText Windows (определенная в файле winuser.h) требует, чтобы вызывающий объект передавал буфер символов фиксированной длины, в который эта функция записывает текст окна.For example, the Windows GetWindowText API function (defined in winuser.h) requires that the caller pass a fixed-length character buffer to which the function writes the window's text. LpString указывает на выделенный вызывающим объектом буфер размером nMaxCount.LpString points to a caller-allocated buffer of size nMaxCount. Предполагается, что вызывающий объект выделяет буфер и задает аргумент nMaxCount равным размеру выделяемого буфера.The caller is expected to allocate the buffer and set the nMaxCount argument to the size of the allocated buffer. В приведенном ниже примере показано объявление функции GetWindowText, определенное в файле winuser.h.The following example shows the GetWindowText function declaration as defined in winuser.h.

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

Буфер StringBuilder может быть разыменован и изменен вызываемым объектом при условии, что он не превышает емкость StringBuilder.A StringBuilder can be dereferenced and modified by the callee, provided it does not exceed the capacity of the StringBuilder. В примере кода ниже показана инициализация буфера StringBuilder с фиксированной длиной.The following code example demonstrates how StringBuilder can be initialized to a fixed length.

using System;
using System.Runtime.InteropServices;
using System.Text;

internal static class NativeMethods
{
    [DllImport("User32.dll")]
    internal static extern void GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
}

public class Window
{
    internal IntPtr h;        // Internal handle to Window.
    public String GetText()
    {
        StringBuilder sb = new StringBuilder(256);
        NativeMethods.GetWindowText(h, sb, sb.Capacity + 1);
        return sb.ToString();
    }
}
Imports System.Text

Friend Class NativeMethods
    Friend Declare Auto Sub GetWindowText Lib "User32.dll" _
        (hWnd As IntPtr, lpString As StringBuilder, nMaxCount As Integer)
End Class

Public Class Window
    Friend h As IntPtr ' Friend handle to Window.
    Public Function GetText() As String
        Dim sb As New StringBuilder(256)
        NativeMethods.GetWindowText(h, sb, sb.Capacity + 1)
        Return sb.ToString()
   End Function
End Class

См. такжеSee also