字段 DllImportAttribute.CharSet 控制字符串封送并确定平台调用如何在 DLL 中查找函数名称。 本主题介绍这两种行为。
某些 API 导出采用字符串参数的两个版本的函数:窄(ANSI)和宽(Unicode)。 例如,Windows API 包括 MessageBox 函数的以下入口点名称:
MessageBoxA
提供单字节字符的 ANSI 格式,通过在入口点名称后附加一个 "A" 来区分。 对 MessageBoxA 的调用始终以 ANSI 格式封送字符串。
MessageBoxW
提供 Unicode 格式的 2 字节字符,由附加到入口点名称后的“W”区分。 对 MessageBoxW 的调用始终以 Unicode 格式封送字符串。
字符串封送处理和名称匹配
该 CharSet
字段接受以下值:
Ansi(默认值)
字符串封送处理
平台调用将字符串从托管格式 (Unicode) 封送为 ANSI 格式。
名称匹配
如果 DllImportAttribute.ExactSpelling 字段为
true
(Visual Basic 中默认为此值),平台调用仅搜索指定的名称。 例如,如果指定 MessageBox,平台调用将搜索 MessageBox ,并在找不到确切的拼写时失败。ExactSpelling
字段为false
时,平台调用默认在 C++ 和 C# 中首先搜索未改变的别名(MessageBox),如果未找到未改变的别名,则搜索经过改变的名称(MessageBoxA)。 请注意,ANSI 名称匹配行为不同于 Unicode 名称匹配行为。
字符串封送处理
平台调用将字符串从其托管格式(Unicode)复制到 Unicode 格式。
名称匹配
如果
ExactSpelling
字段为true
(Visual Basic 中默认为此值),平台调用仅搜索指定的名称。 例如,如果指定 MessageBox,平台调用将搜索 MessageBox ,如果找不到确切的拼写,则失败。如果
ExactSpelling
字段为false
(C++ 和 C# 中默认为此值),平台调用先搜索修饰的名称 (MessageBoxW),如果找不到修饰的名称,再搜索未修饰的别名 (MessageBox)。 请注意,Unicode 名称匹配行为不同于 ANSI 名称匹配行为。
- 平台调用在运行时根据目标平台在 ANSI 和 Unicode 格式之间进行选择。
在 Visual Basic 中指定字符集
可以通过向声明语句添加Ansi
或Unicode
Auto
关键字,在 Visual Basic 中指定字符集行为。 如果省略字符集关键字,则 DllImportAttribute.CharSet 字段默认为 ANSI 字符集。
以下示例声明 MessageBox 函数三次,每次使用不同的字符集行为。 第一个语句省略字符集关键字,因此字符集默认为 ANSI。 第二个和第三个语句显式指定具有关键字的字符集。
Friend Class NativeMethods
Friend Declare Function MessageBoxA Lib "user32.dll" (
ByVal hWnd As IntPtr,
ByVal lpText As String,
ByVal lpCaption As String,
ByVal uType As UInteger) As Integer
Friend Declare Unicode Function MessageBoxW Lib "user32.dll" (
ByVal hWnd As IntPtr,
ByVal lpText As String,
ByVal lpCaption As String,
ByVal uType As UInteger) As Integer
Friend Declare Auto Function MessageBox Lib "user32.dll" (
ByVal hWnd As IntPtr,
ByVal lpText As String,
ByVal lpCaption As String,
ByVal uType As UInteger) As Integer
End Class
在 C# 和 C++ 中指定字符集
该 DllImportAttribute.CharSet 字段将基础字符集标识为 ANSI 或 Unicode。 字符集控制应如何封送方法的字符串参数。 使用以下形式之一来指示字符集:
[DllImport("DllName", CharSet = CharSet.Ansi)]
[DllImport("DllName", CharSet = CharSet.Unicode)]
[DllImport("DllName", CharSet = CharSet.Auto)]
[DllImport("DllName", CharSet = CharSet::Ansi)]
[DllImport("DllName", CharSet = CharSet::Unicode)]
[DllImport("DllName", CharSet = CharSet::Auto)]
以下示例显示了用于指定字符集的 MessageBox 函数的三个托管定义。 在第一个定义中,由于省略,它的 CharSet
字段默认使用 ANSI 字符集。
using System;
using System.Runtime.InteropServices;
internal static class NativeMethods
{
[DllImport("user32.dll")]
internal static extern int MessageBoxA(
IntPtr hWnd, string lpText, string lpCaption, uint uType);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern int MessageBoxW(
IntPtr hWnd, string lpText, string lpCaption, uint uType);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern int MessageBox(
IntPtr hWnd, string lpText, string lpCaption, uint uType);
}
typedef void* HWND;
// Can use MessageBox or MessageBoxA.
[DllImport("user32")]
extern "C" int MessageBox(
HWND hWnd, String* lpText, String* lpCaption, unsigned int uType);
// Can use MessageBox or MessageBoxW.
[DllImport("user32", CharSet = CharSet::Unicode)]
extern "C" int MessageBoxW(
HWND hWnd, String* lpText, String* lpCaption, unsigned int uType);
// Must use MessageBox.
[DllImport("user32", CharSet = CharSet::Auto)]
extern "C" int MessageBox(
HWND hWnd, String* lpText, String* lpCaption, unsigned int uType);