Я работаю над оболочкой PInvoke для библиотеки, которая не поддерживает строки Unicode, но поддерживает многобайтовые строки ANSI. Исследуя отчеты FxCop по библиотеке, я заметил, что используемый маршалинг строк имел некоторые интересные побочные эффекты. Метод PInvoke использовал отображение «наилучшее соответствие» для создания однобайтовой строки ANSI. Для иллюстрации, вот как выглядел один метод:
[DllImport("thedll.dll", CharSet=CharSet.Ansi)]
public static extern int CreateNewResource(string resourceName);
Результатом вызова этой функции со строкой, содержащей символы, не входящие в ASCII, является то, что Windows находит «закрывающий» символ, обычно это выглядит так, как будто это «???». Если мы притворимся, что «a» не является символом ASCII, то передача «cat» в качестве параметра создаст ресурс с именем «c? T».
Если я буду следовать указаниям правила FxCop, я получу что-то вроде этого:
[DllImport("thedll.dll", CharSet=CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern int CreateNewResource([MarshalAs(UnmanagedType.LPStr)] string resourceName);
Это вводит изменение в поведение; теперь, когда персонаж не может быть отображен, генерируется исключение. Это касается меня, потому что это серьезное изменение, поэтому я хотел бы попытаться упорядочить строки как многобайтовые ANSI, но я не могу найти способ сделать это. UnmanagedType.LPStr
указано как однобайтовая строка ANSI, LPTStr will be Unicode or ANSI depending on the system, and LPWStr is not what the library expects.</p>
<p>How would I tell PInvoke to marshal the string as a multibyte string? I see there's a <code>WideCharToMultiByte()
API-функция. Могу ли я изменить сигнатуру, чтобы ожидать IntPtr на строку, которую я создаю в неуправляемой памяти? Кажется, что это все еще имеет много проблем, с которыми сталкивается текущая реализация (возможно, придется отбрасывать или заменять символы), поэтому я не уверен, является ли это улучшением. Есть ли другой метод маршалинга, который мне не хватает?