.net字符串的默认封送处理
字符串作为 COM 样式的 BSTR 类型封送,或者作为以空引用(在 Visual Basic 中为 Nothing)终止的字符数组封送。字符串内的字符可以作为 Unicode 或 ANSI 封送,或以平台相关的方式封送(在 Microsoft Windows NT、Windows 2000 和 Windows XP 上为 Unicode;在 Windows 98 和 Windows Millennium Edition 即 Windows Me 上为 ANSI)。
本主题提供下列有关封送字符串类型的信息:
接口中使用的字符串
下表显示字符串数据类型被作为方法参数封送到非托管代码时的封送处理选项。
枚举类型 | 非托管格式的说明 |
---|---|
UnmanagedType.BStr(默认) |
具有预设长度和 Unicode 字符的 COM 样式的 BSTR。 |
UnmanagedType.LPStr |
指向 ANSI 字符的空终止数组的指针。 |
UnmanagedType.LPWStr |
指向 Unicode 字符的空终止数组的指针。 |
下面的示例显示 IStringWorker
接口中声明的字符串。
下面的示例显示在类型库中描述的对应接口。
复制代码 | |
---|---|
[…] 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) 转换为平台非托管格式。字符串是不可变的,在调用返回时不会从非托管内存复制回托管内存。
下表列出了在字符串被作为对平台调用进行的调用的方法参数封送时的封送处理选项。
枚举类型 | 非托管格式的说明 |
---|---|
UnmanagedType.AnsiBStr |
具有预设长度并包含 ANSI 字符的 COM 样式 BSTR。 |
UnmanagedType.BStr(默认) |
具有预设长度和 Unicode 字符的 COM 样式的 BSTR。 |
UnmanagedType.LPStr |
指向 ANSI 字符的空终止数组的指针。 |
UnmanagedType.LPTStr |
指向平台相关的字符的空终止数组的指针。 |
UnmanagedType.LPWStr |
指向 Unicode 字符的空终止数组的指针。 |
UnmanagedType.TBStr |
具有预设长度并包含平台相关字符的 COM 样式 BSTR。 |
下面的类型定义针对平台调用的调用显示 MarshalAsAttribute 的正确用法。
C# | 复制代码 |
---|---|
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); } |
结构中使用的字符串
字符串是结构的有效成员;但是,
枚举类型 | 非托管格式的说明 |
---|---|
UnmanagedType.BStr |
具有预设长度和 Unicode 字符的 COM 样式的 BSTR。 |
UnmanagedType.LPStr |
指向 ANSI 字符的空终止数组的指针。 |
UnmanagedType.LPTStr |
指向平台相关的字符的空终止数组的指针。 |
UnmanagedType.LPWStr |
指向 Unicode 字符的空终止数组的指针。 |
UnmanagedType.ByValTStr |
定长的字符数组;数组的类型由包含数组的结构的字符集确定。 |
ByValTStr 类型用于出现在结构内的内联的定长字符数组。其他类型应用于包含指向字符串的指针的结构内所包含的字符串引用。
应用于包含结构的
类型库表示形式
复制代码 | |
---|---|
struct StringInfoA { char * f1; char f2[256]; }; struct StringInfoW { WCHAR * f1; WCHAR f2[256]; BSTR f3; }; struct StringInfoT { TCHAR * f1; TCHAR f2[256]; }; |
下面的代码示例显示如何使用
C# | 复制代码 |
---|---|
[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; } |
定长字符串缓冲区
在某些环境中,必须将定长的字符缓冲区传递到非托管代码中以进行操作。在这种情况下,只传递字符串不起作用,原因是被调用方无法修改传递的缓冲区的内容。即使字符串是通过引用传递的,仍然无法将缓冲区初始化为给定的大小。
解决方案是将
例如,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 初始化为固定长度。
C# | 复制代码 |
---|---|
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(); } } |