Определение кодировки

DllImportAttribute.CharSetПоле управляет упаковкой строк и определяет, как вызов неуправляемого кода находит имена функций в библиотеке DLL. В этом разделе описываются оба механизма.

Некоторые API экспортируют две версии функций, которые принимают строковые аргументы: обычные (ANSI) и двухбайтовые (Юникод). Например, API Windows включает следующие имена точек входа для функции MessageBox:

  • MessageBoxA

    Обеспечивает форматирование однобайтовых символов ANSI и имеет суффикс "A" в имени точки входа. При вызове MessageBoxA строки всегда маршалируются в формате ANSI.

  • MessageBoxW

    Обеспечивает форматирование двухбайтовых символов Юникода и имеет суффикс "W" в имени точки входа. При вызове MessageBoxW строки всегда маршалируются в формате Юникод.

Упаковка строк и сопоставление имен

Поле CharSet принимает следующие значения:

Ansi (значение по умолчанию)

  • Упаковка строк

    При вызове неуправляемого кода выполняется маршалинг строк из соответствующего управляемого формата (Юникод) в формат ANSI.

  • Сопоставление имен

    Если поле DllImportAttribute.ExactSpelling имеет значение true (значение по умолчанию в Visual Basic), при вызове неуправляемого кода осуществляется поиск только указанного имени. Например, если указать MessageBox, при вызове неуправляемого кода будет выполнен поиск MessageBox, который может завершиться сбоем из-за невозможности найти точное совпадение.

    ExactSpellingЕсли поле имеет false значение, как по умолчанию в C++ и C#, то при вызове неверного псевдонима сначала выполняется поиск, а затем искаженное имя (falseExactSpellingесли Неискаженный псевдоним не найден. Обратите внимание, что принципы сопоставления имен ANSI и Юникода различаются.

Unicode

  • Упаковка строк

    При вызове неуправляемого кода строки копируются из соответствующего управляемого формата (Юникод) в формат Юникода.

  • Сопоставление имен

    Если поле ExactSpelling имеет значение true (значение по умолчанию в Visual Basic), при вызове неуправляемого кода осуществляется поиск только указанного имени. Например, если указать MessageBox, при вызове неуправляемого кода будет выполнен поиск MessageBox, который может завершиться сбоем из-за невозможности найти точное совпадение.

    ExactSpellingЕсли поле имеет false значение, как по умолчанию в C++ и C#, при вызове неискаженного имени сначала ищется имя (ExactSpelling), а затем неповрежденный псевдоним (false), если искаженное имя не найдено. Обратите внимание, что принципы сопоставления имен Юникода и ANSI различаются.

Auto

  • При вызове неуправляемого кода во время выполнения осуществляется выбор между форматами ANSI и Юникода в соответствии с целевой платформой.

Определение кодировки в Visual Basic

В Visual Basic можно указать поведение кодировки, добавив ключевое слово Ansi, Unicode или Auto в операторе объявления. Если опустить ключевое слово кодировки, в поле 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 или Юникод. Кодировка определяет способ маршалирования строковых аргументов метода. Чтобы указать кодировку, используйте одну из следующих форм:

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

См. также