指定字符集Specifying a Character Set

DllImportAttribute.CharSet 字段控制字符串封送,并确定平台调用在 DLL 中查找函数名的方式。The DllImportAttribute.CharSet field controls string marshaling and determines how platform invoke finds function names in a DLL. 本主题将介绍这两种行为。This topic describes both behaviors.

某些 API 导出采用字符串自变量的函数的两个版本:窄版 (ANSI) 和宽版 (Unicode)。Some APIs export two versions of functions that take string arguments: narrow (ANSI) and wide (Unicode). 例如,Windows API 包含 MessageBox 函数的以下入口点名称:The Windows API, for instance, includes the following entry-point names for the MessageBox function:

  • MessageBoxAMessageBoxA

    提供 ANSI 格式的 1 字节字符,由附加到入口点名称后的“A”区分。Provides 1-byte character ANSI formatting, distinguished by an "A" appended to the entry-point name. 调用 MessageBoxA 始终以 ANSI 格式封送字符串。Calls to MessageBoxA always marshal strings in ANSI format.

  • MessageBoxWMessageBoxW

    提供 Unicode 格式的 2 字节字符,由附加到入口点名称后的“W”区分。Provides 2-byte character Unicode formatting, distinguished by a "W" appended to the entry-point name. 调用 MessageBoxW 始终以 Unicode 格式封送字符串。Calls to MessageBoxW always marshal strings in Unicode format.

字符串封送和名称匹配String Marshaling and Name Matching

CharSet 字段接受以下值:The CharSet field accepts the following values:

Ansi(默认值)Ansi (default value)

  • 字符串封送String marshaling

    平台调用将字符串从托管格式 (Unicode) 封送为 ANSI 格式。Platform invoke marshals strings from their managed format (Unicode) to ANSI format.

  • 名称匹配Name matching

    如果 DllImportAttribute.ExactSpelling 字段为 true(Visual Basic 中默认为此值),平台调用仅搜索指定的名称。When the DllImportAttribute.ExactSpelling field is true, as it is by default in Visual Basic, platform invoke searches only for the name you specify. 例如,如果指定“MessageBox”,则平台调用搜索“MessageBox”,如果无法找到精确拼写,则将失败。For example, if you specify MessageBox, platform invoke searches for MessageBox and fails when it cannot locate the exact spelling.

    如果 ExactSpelling 字段为 false(C++ 和 C# 中默认为此值),平台调用先搜索未修饰的别名 (MessageBox),如果找不到未修饰的别名,再搜索修饰后的名称 (MessageBoxA)。When the ExactSpelling field is false, as it is by default in C++ and C#, platform invoke searches for the unmangled alias first (MessageBox), then the mangled name (MessageBoxA) if the unmangled alias is not found. 请注意,ANSI 名称匹配行为与 Unicode 名称匹配行为不同。Notice that ANSI name-matching behavior differs from Unicode name-matching behavior.

Unicode

  • 字符串封送String marshaling

    平台调用将字符串从托管格式 (Unicode) 复制为 Unicode 格式。Platform invoke copies strings from their managed format (Unicode) to Unicode format.

  • 名称匹配Name matching

    如果 ExactSpelling 字段为 true(Visual Basic 中默认为此值),平台调用仅搜索指定的名称。When the ExactSpelling field is true, as it is by default in Visual Basic, platform invoke searches only for the name you specify. 例如,如果指定“MessageBox”,则平台调用搜索“MessageBox”,如果无法找到精确拼写,则将失败。For example, if you specify MessageBox, platform invoke searches for MessageBox and fails if it cannot locate the exact spelling.

    如果 ExactSpelling 字段为 false(C++ 和 C# 中默认为此值),平台调用先搜索修饰的名称 (MessageBoxW),如果找不到修饰的名称,再搜索未修饰的别名 (MessageBox)。When the ExactSpelling field is false, as it is by default in C++ and C#, platform invoke searches for the mangled name first (MessageBoxW), then the unmangled alias (MessageBox) if the mangled name is not found. 请注意,Unicode 名称匹配行为与 ANSI 名称匹配行为不同。Notice that Unicode name-matching behavior differs from ANSI name-matching behavior.

Auto

  • 平台调用在运行时根据目标平台在 ANSI 和 Unicode 格式之间进行选择。Platform invoke chooses between ANSI and Unicode formats at run time, based on the target platform.

在 Visual Basic 中指定字符集Specifying a Character Set in Visual Basic

以下示例声明“MessageBox”函数三次,每次使用不同的字符集行为。The following example declares the MessageBox function three times, each time with different character-set behavior. 通过将“Ansi”、“Unicode”或“Auto”关键字添加到声明语句中,就可以在 Visual Basic 中指定字符集行为。You can specify character-set behavior in Visual Basic by adding the Ansi, Unicode, or Auto keyword to the declaration statement.

如果省略字符集关键字,正如在第一个声明语句中那样,则 DllImportAttribute.CharSet 字段默认为 ANSI 字符集。If you omit the character-set keyword, as is done in the first declaration statement, the DllImportAttribute.CharSet field defaults to the ANSI character set. 示例中的第二个和第三个语句使用关键字显式指定字符集。The second and third statements in the example explicitly specify a character set with a keyword.

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++ 中指定字符集Specifying a Character Set in C# and C++

DllImportAttribute.CharSet 字段将基础字符集标识为 ANSI 或 Unicode。The DllImportAttribute.CharSet field identifies the underlying character set as ANSI or Unicode. 字符集控制应如何封送方法的字符串自变量。The character set controls how string arguments to a method should be marshaled. 使用以下形式之一来指示字符集:Use one of the following forms to indicate the character set:

[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”函数的三个托管定义,它们是指定字符集的结果。The following example shows three managed definitions of the MessageBox function attributed to specify a character set. 在第一个定义中,通过省略,CharSet 字段默认为 ANSI 字符集。In the first definition, by its omission, the CharSet field defaults to the ANSI character set.

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

请参阅See also