文字列に対する既定のマーシャリング

System.String クラスと System.StringBuilder クラスのマーシャリングの動作は似ています。

文字列は COM スタイルの BTSR 型または null 参照 (Visual Basic では Nothing) で終わる文字配列としてマーシャリングされます。文字列に含まれる文字を、Unicode または ANSI として、またはプラットフォームに依存する方法 (Microsoft Windows NT、Windows 2000、および Windows XP の場合は Unicode、Windows 98 および Windows Millennium Edition (Windows Me) の場合は ANSI) でマーシャリングできます。

ここでは、文字列型のマーシャリングに関する、次の情報を示します。

  • インターフェイスで使用される文字列

  • プラットフォーム呼び出しで使用される文字列

  • 構造体で使用される文字列

  • 固定長の文字列バッファ

インターフェイスで使用される文字列

文字列データ型をメソッド引数としてアンマネージ コードにマーシャリングする場合のマーシャリング オプションを次の表に示します。MarshalAsAttribute 属性は、文字列を COM インターフェイスにマーシャリングするための UnmanagedType 列挙値をいくつか提供します。

列挙型 アンマネージ表現の説明

UnmanagedType.BStr
  (既定)

長さと Unicode 文字が前に付いた COM スタイルの BSTR

UnmanagedType.LPStr

ANSI 文字の null で終わる配列へのポインタ。

UnmanagedType.LPWStr

Unicode 文字の null で終わる配列へのポインタ。

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 形式 (Unicode) からプラットフォーム アンマネージ形式へと変換します。文字列は変更不可なので、呼び出しから制御が返されるときにアンマネージ メモリからマネージメモリにはコピーされません。

文字列をプラットフォーム呼び出しのメソッド引数としてマーシャリングする場合のマーシャリング オプションを次の表に列挙します。MarshalAsAttribute 属性は、文字列をマーシャリングするための UnmanagedType 列挙値をいくつか提供します。

列挙型 アンマネージ表現の説明

UnmanagedType.AnsiBStr

長さと ANSI 文字が前に付いた COM スタイルの BSTR

UnmanagedType.BStr 
(既定)

長さと Unicode 文字が前に付いた COM スタイルの BSTR

UnmanagedType.LPStr

ANSI 文字の null で終わる配列へのポインタ。

UnmanagedType.LPTStr

プラットフォーム依存の文字の null で終わる配列へのポインタ。

UnmanagedType.LPWStr

Unicode 文字の null で終わる配列へのポインタ。

UnmanagedType.TBStr

長さとプラットフォーム依存の文字が前に付いた COM スタイルの BSTR

プラットフォーム呼び出しに関する 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

長さと Unicode 文字が前に付いた COM スタイルの BSTR

UnmanagedType.LPStr

ANSI 文字の null で終わる配列へのポインタ。

UnmanagedType.LPTStr

プラットフォーム依存の文字の null で終わる配列へのポインタ。

UnmanagedType.LPWStr

Unicode 文字の null で終わる配列へのポインタ。

UnmanagedType.ByValTStr

固定長の文字配列。この配列の型は、配列を含む構造体の文字セットによって決定されます。

ByValTStr 型は、構造体の中のインラインの固定長文字配列用に使用されます。その他の型は、文字列へのポインタを含む構造体の中に含まれる文字列参照に対して適用されます。

構造体内の文字列の文字形式は、その文字列を含む構造体に適用される StructLayoutAttribute 属性の CharSet 引数によって決まります。ANSI、Unicode およびプラットフォーム依存の文字だけではなく、文字列参照とインライン文字列を含む構造体の例を次に示します。

タイプ ライブラリ表現

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 は、アンマネージ文字列には終端の null 文字があるが、StringBuilder にはないことを示しています。

たとえば、Microsoft Win32 API GetWindowText 関数 (Windows.h で定義) は固定長文字バッファであり、アンマネージ コードに渡して操作する必要があります。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 型
方向属性
コピーと固定

その他の技術情報

既定のマーシャリングの動作