Прежде всего, +10000 при использовании реального типа взаимодействия P / Invoke, а не при сортировке данных вручную.Но так как вы спросили, вот что происходит с вашими строками.
Среда выполнения решает, как обрабатывать строки и символы в каждом конкретном случае, на основе атрибутов, которые вы применяете к декларациям взаимодействия, контекст, в которомвы используете взаимодействие, методы, которые вы вызываете, и т. д. Каждый тип объявления P / Invoke (метод extern, делегат или структура) позволяет вам указать размер символов по умолчанию для области действия этого определения.Существует три варианта:
- Использовать
CharSet.Ansi
, который преобразует управляемые строки Unicode в 8-битные символы - Использовать
CharSet.Unicode
, который передает данные строки как 16-битныесимволы - Используйте
CharSet.Auto
, который решает во время выполнения, в зависимости от операционной системы хоста, какую из них использовать.
В общем, я ненавижу CharSet.Auto
, потому что это в основном бессмысленно.Поскольку Framework даже не поддерживает Windows 95, единственное время, когда «Auto» не означает «Unicode», - это при работе в Windows 98. Но здесь есть более серьезная проблема, заключающаяся в том, что во время выполнения принимается решение о том, как выполнить маршалинг строкв «неподходящее время».
Неуправляемый код, который вы вызываете, принял это решение в время компиляции , поскольку компилятор должен был решить, означает ли TCHAR
char или wchar - это решениеоснован на присутствии макроса препроцессора _UNICODE
.Это означает, что для большинства библиотек он будет всегда использовать одну или другую, и нет смысла позволять CLR «выбирать одну».
Для системных компонентов Windows все немного лучше, потому чтоUnicode-ориентированные сборки на самом деле включают в себя две версии большинства системных функций.Например, API установки имеет два метода: SetupDiGetDeviceInterfaceDetailA
и SetupDiGetDeviceInterfaceDetailW
.Версия * A использует 8-битные строки "ANSI", а версия * W использует 16-битные строки "Unicode".Он также имеет ANSI и широкую версию любой структуры, которая имеет строку.
Это ситуация, когда светит CharSet.Auto
, если вы используете его правильно.Когда вы применяете DllImport
к функции, вы можете указать набор символов.Если вы укажете Ansi
для набора символов, если среда выполнения не найдет точное совпадение с именем вашей функции, она добавит A и попытается снова.(Как ни странно, если вы укажете Unicode
, он вызовет функцию * W first и попытается найти точное совпадение только в случае неудачи.)
Вот подвох: если вы неt укажите набор символов на вашем DllImport
, , по умолчанию это CharSet.Ansi
.Это означает, что вы получите ANSI-версию функции, если только вы не переопределите кодировку.Скорее всего, это происходит здесь: вы вызываете версию ANSI SetupDiGetDeviceInterfaceDetail
по умолчанию и, таким образом, получаете строку ANSI обратно, но PtrToStringAuto
хочет использовать Unicode, потому что вы, вероятно, используете хотя бы Windows XP.
Лучший вариант, при условии, что мы можем игнорировать Windows 98, будет указывать CharSet.Unicode
повсеместно, поскольку SetupAPI его поддерживает, но, по крайней мере, вам нужно указать то же самое CharSet
значение везде.