다음을 통해 공유


문자열에 대한 기본 마샬링

System.String 클래스와 System.Text.StringBuilder 클래스는 마샬링 동작이 유사합니다.

문자열은 COM 스타일의 BSTR 형식 또는 null 참조(Visual Basic의 경우 Nothing)로 종결되는 문자 배열로 마샬링됩니다. 문자열 내의 문자는 유니코드 또는 ANSI로 마샬링되거나 플랫폼별 방식으로 마샬링될 수 있습니다. 즉, Microsoft Windows NT, Windows 2000 및 Windows XP에서는 유니코드로 마샬링되고, Windows 98 및 Windows Me(Windows Millennium Edition)에서는 ANSI로 마샬링될 수 있습니다.

이 항목에서는 문자열 형식의 마샬링에 대한 다음 내용을 다룹니다.

  • 인터페이스에 사용되는 문자열

  • 플랫폼 호출에 사용되는 문자열

  • 구조체에 사용되는 문자열

  • 고정 길이 문자열 버퍼

인터페이스에 사용되는 문자열

다음 표에서는 문자열 데이터 형식을 비관리 코드에 메서드 인수로 마샬링할 때의 마샬링 옵션을 보여 줍니다. MarshalAsAttribute 특성은 문자열을 COM 인터페이스로 마샬링하기 위한 몇 개의 UnmanagedType 열거형 값을 제공합니다.

열거형

관리되지 않는 형식의 설명

UnmanagedType.BStr(기본값)

미리 고정된 길이 및 유니코드 문자를 사용하는 COM 스타일의 BSTR입니다.

UnmanagedType.LPStr

null로 끝나는 ANSI 문자 배열에 대한 포인터입니다.

UnmanagedType.LPWStr

null로 끝나는 유니코드 문자 배열에 대한 포인터입니다.

이 표의 내용은 문자열에 적용됩니다. 그러나 StringBuilder의 경우에는 UnmanagedType.LPStr 및 UnmanagedType.LPWStr 옵션만 사용할 수 있습니다.

다음 예제에서는 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);
);

다음 예제에서는 형식 라이브러리에 선언된 해당 인터페이스를 보여 줍니다.

[…]
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);
);

플랫폼 호출에 사용되는 문자열

플랫폼 호출에서는 문자열 인수를 .NET Framework 형식인 유니코드에서 플랫폼의 관리되지 않는 형식으로 변환하여 복사합니다. 문자열은 변경할 수 없으며 호출이 반환될 때 관리되지 않는 메모리에서 관리되는 메모리로 다시 복사되지 않습니다.

다음 표에서는 문자열을 P/Invoke 호출의 메서드 인수로 마샬링할 때의 마샬링 옵션을 보여 줍니다. MarshalAsAttribute 특성은 문자열을 마샬링하기 위한 몇 개의 UnmanagedType 열거형 값을 제공합니다.

열거형

관리되지 않는 형식의 설명

UnmanagedType.AnsiBStr

미리 고정된 길이 및 ANSI 문자를 사용하는 COM 스타일의 BSTR입니다.

UnmanagedType.BStr

미리 고정된 길이 및 유니코드 문자를 사용하는 COM 스타일의 BSTR입니다.

UnmanagedType.LPStr

null로 끝나는 ANSI 문자 배열에 대한 포인터입니다.

UnmanagedType.LPTStr(기본값)

null로 끝나는 플랫폼별 문자 배열에 대한 포인터입니다.

UnmanagedType.LPWStr

null로 끝나는 유니코드 문자 배열에 대한 포인터입니다.

UnmanagedType.TBStr

미리 고정된 길이 및 플랫폼별 문자를 사용하는 COM 스타일의 BSTR입니다.

VBByRefStr

Visual Basic .NET에서 비관리 코드의 문자열을 변경하고 결과를 관리 코드에 반영되도록 하는 데 사용할 수 있는 값입니다. 이 값은 플랫폼 호출에만 지원됩니다.

이 표의 내용은 문자열에 적용됩니다. 그러나 StringBuilder의 경우에는 LPStr, LPTStr 및 LPWStr 옵션만 사용할 수 있습니다.

다음 형식 정의에서는 P/Invoke 호출에 MarshalAsAttribute를 올바르게 사용하는 방법을 보여 줍니다.

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

구조체에 사용되는 문자열

문자열은 구조체의 유효한 멤버이지만 StringBuilder 버퍼는 구조체에서 유효하지 않습니다. 다음 표에서는 문자열 데이터 형식을 필드로 마샬링할 때의 마샬링 옵션을 보여 줍니다. MarshalAsAttribute 특성은 문자열을 필드로 마샬링하기 위한 몇 개의 UnmanagedType 열거형 값을 제공합니다.

열거형

관리되지 않는 형식의 설명

UnmanagedType.BStr

미리 고정된 길이 및 유니코드 문자를 사용하는 COM 스타일의 BSTR입니다.

UnmanagedType.LPStr

null로 끝나는 ANSI 문자 배열에 대한 포인터입니다.

UnmanagedType.LPTStr

null로 끝나는 플랫폼별 문자 배열에 대한 포인터입니다.

UnmanagedType.LPWStr

null로 끝나는 유니코드 문자 배열에 대한 포인터입니다.

UnmanagedType.ByValTStr

고정 길이의 문자 배열. 배열 형식은 포함하는 구조체의 문자 집합에 따라 결정됩니다.

ByValTStr 형식은 구조체 내에 나타나는 고정 길이의 인라인 문자 배열에 사용됩니다. 다른 형식은 문자열에 대한 포인터를 포함하는 구조체 내에 포함된 문자열 참조에 적용됩니다.

포함하는 구조체에 적용되는 StructLayoutAttribute 특성의 CharSet 인수는 구조체에서 문자열의 문자 형식을 결정합니다. 다음 예제 구조체에는 문자열 참조 및 인라인 문자열과, ANSI, 유니코드 및 플랫폼별 문자가 포함되어 있습니다.

형식 라이브러리 표현

struct StringInfoA {
   char *    f1;
   char      f2[256];
};
struct StringInfoW {
   WCHAR *   f1;
   WCHAR     f2[256];
   BSTR      f3;
};
struct StringInfoT {
   TCHAR *   f1;
   TCHAR     f2[256];
};

다음 코드 예제에서는 MarshalAsAttribute 특성을 사용하여 동일한 구조체를 다른 형식으로 정의하는 방법을 보여 줍니다.

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

고정 길이 문자열 버퍼

일부 경우에는 조작을 위해 고정 길이 문자 버퍼를 비관리 코드에 전달해야 합니다. 이 경우 호출 수신자는 전달된 버퍼의 내용을 수정할 수 없으므로 단순히 문자열을 전달하는 것으로는 충분하지 않습니다. 문자열이 참조로 전달되는 경우에도 버퍼를 지정된 크기로 초기화할 수는 없습니다.

해결 방법은 StringBuilder 버퍼를 문자열 대신 인수로 전달하는 것입니다. StringBuilder는 StringBuilder의 용량을 초과하지 않는 경우 호출 수신자에 의해 역참조 및 수정될 수 있습니다. 또한 고정 길이로 초기화될 수도 있습니다. 예를 들어 StringBuilder 버퍼를 N 용량으로 초기화하는 경우 마샬러에서는 N+1개의 문자를 포함할 수 있는 크기의 버퍼를 제공합니다. +1은 StringBuilder에 null 종결자가 없어도 관리되지 않는 문자열에는 null 종결자가 있음을 고려한 것입니다.

예를 들어 Windows.h에 정의된 Microsoft Win32 API GetWindowText 함수는 조작할 비관리 코드에 전달해야 하는 고정 길이 문자 버퍼입니다. LpString은 호출자가 할당한 nMaxCount 크기의 버퍼를 가리킵니다. 호출자는 버퍼를 할당하고 nMaxCount 인수를 할당된 버퍼의 크기로 설정해야 합니다. 다음 코드에서는 Windows.h에 정의되어 있는 GetWindowText 함수 선언을 보여 줍니다.

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

StringBuilder는 StringBuilder의 용량을 초과하지 않는 경우 호출 수신자에 의해 역참조 및 수정될 수 있습니다. 다음 코드 예제에서는 StringBuilder를 고정 길이로 초기화하는 방법을 보여 줍니다.

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

참고 항목

개념

Blittable 형식 및 비 Blittable 형식

방향 특성

복사 및 고정

기타 리소스

기본 마샬링 동작