共用方式為


字串的預設封送處理

更新:2007 年 11 月

System.StringSystem.Text.StringBuilder 這兩個類別擁有類似的封送處理行為。

字串會當做 COM-Style BSTR 型別,或當做 Null 參考中的字元陣列結尾 (在 Visual Basic 中為 Nothing) 封送處理。字串內的字元可以封送處理為 Unicode 或 ANSI,或者以平台依存方式 (Unicode 於 Microsoft Windows NT、Windows 2000 和 Windows XP;ANSI 於 Windows 98 和 Windows Millennium Edition (Windows Me)) 封送處理字元。

這個主題提供以下有關封送處理字串型別的資訊:

  • 在介面中使用的字串

  • 在平台叫用中使用的字串

  • 在結構中使用的字串

  • 固定長度字串緩衝區

在介面中使用的字串

下表顯示當封送處理為 Unmanaged 程式碼的方法引數時,字串資料型別的封送處理選項。MarshalAsAttribute 屬性提供多個 UnmanagedType 列舉值將字串封送處理為 COM 介面。

列舉型別

Unmanaged 格式的說明

UnmanagedType.BStr (預設值)

具有前置長度和 Unicode 字元的 COM-Style BSTR。

UnmanagedType.LPStr

ANSI 字元之 Null 終端陣列的指標

UnmanagedType.LPWStr

Unicode 字元之 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 格式 (Unicode) 轉換為平台 Unmanaged 格式的方式複製字串引數。當呼叫傳回時,字串是不變的,而且不會從 Unmanaged 記憶體複製回 Managed 記憶體。

下表列出當封送處理為平台叫用呼叫的方法引數時,字串的封送處理選項。MarshalAsAttribute 屬性提供多個 UnmanagedType 列舉值封送處理字串。

列舉型別

Unmanaged 格式的說明

UnmanagedType.AnsiBStr

具有前置長度和 ANSI 字元的 COM-Style BSTR

UnmanagedType.BStr

具有前置長度和 Unicode 字元的 COM-Style BSTR。

UnmanagedType.LPStr

ANSI 字元之 Null 終端陣列的指標

UnmanagedType.LPTStr (預設值)

平台依存字元之 Null 終端陣列的指標

UnmanagedType.LPWStr

Unicode 字元之 Null 終端陣列的指標

UnmanagedType.TBStr

具有前置長度和平台依存字元的 COM-Style BSTR

VBByRefStr

一個值,可讓 Visual Basic .NET 變更 Unmanaged 程式碼中的字串,並且讓結果反映在 Managed 程式碼中。只有平台叫用支援這個值。

本表會套用至字串。不過,StringBuilder 所允許的選項為 LPStr、LPTStr 和 LPWStr。

下列型別定義顯示平台叫用呼叫的 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 列舉值將字串封送處理為欄位。

列舉型別

Unmanaged 格式的說明

UnmanagedType.BStr

具有前置長度和 Unicode 字元的 COM-Style 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;
}

固定長度字串緩衝區

在某些情況下,必須將固定長度字串緩衝區傳遞到要被操作的 Unmanaged 程式碼中。在這種情況下只傳遞字串並不可行,因為被呼叫端無法修改傳遞的緩衝區內容。即使字串是以傳址方式傳遞,還是無法將緩衝區初始化為指定的大小。

解決方式是將 StringBuilder 緩衝區做為引數而非字串傳遞。只要不超過 StringBuilder 的容量,被呼叫端可以將 StringBuilder 解除參考並加以修改。它也可以初始化為固定長度。例如,如果您將 StringBuilder 緩衝區初始化為 N 的容量,封送處理器會提供大小為 (N+1) 字元的緩衝區。+1 說明 Unmanaged 字串有 null 結束字元而 StringBuilder 卻沒有的事實。

例如,Microsoft Win32 API GetWindowText 函式 (定義於 Windows.h) 是固定長度的字元緩衝區,必須傳遞至要管理的 Unmanaged 程式碼。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 型別

方向屬性

複製和 Pin

其他資源

預設的封送處理行為