none
Как хранить строку в кодировке, отличной от Unicode?

    Вопрос

  • Функция во внешней библиотеке COM может принимать только текст в кодировке 1251. 

    textBase do_smth(string text) //textBase - класс описанный внутри этой библиотеки.
    
    Главная проблема что функция может работать только с текстом в 1251 кодировке, но в c# строки хранятся в кодировке Unicode


    Каким образом можно передать функции строку в нужно кодировке?

Ответы

  • Это ваш вопрос https://ru.stackoverflow.com/questions/829259/Как-добавить-маршалинг-строки-в-функцию-библиотеки-которая-добавлена-через-refe?noredirect=1#829259 ?

    Я там написал. Для COM-интерфейсов по умолчанию string маршалит в BSTR, который использует UTF-16 и поддерживает все языки. Ищите в чем-то другом проблему.

    • Помечено в качестве ответа BadThings 18 мая 2018 г. 14:15
  • Оба варианта примерно одинаковы не требуют каких либо изменений в самой библиотеке. Хотя если у вас есть исходники к ней то это самый оптимальный вариант.

    Оба варианта требуют полной декларации всех методов, типов и интерфейсов из библиотеки в коде C#. Их можно создать в ручную или декомпилировать библиотеку созданную для вашей COM DLL утилитой TLBIMP:

    https://docs.microsoft.com/en-us/dotnet/framework/interop/how-to-generate-primary-interop-assemblies-using-tlbimp-exe

    Далее полученный код исправляется как надо (добавляются атрибуты, меняется сигнатура) и компилируется как обычно.

    This posting is provided "AS IS" with no warranties, and confers no rights.

    Модератор

Все ответы

  • Для того чтоб передать строку в текущей кодировке ANSI (в том числе 1251) надо добавить нужный атрибут в декларацию функции, например:

    [MarshalAs(UnmanagedType.LPStr)]

    https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshalasattribute(v=vs.110).aspx

    Другой вариант - изменить тип параметра в декларации на массив байтов и преобразовывать строку в байты в нужной кодировке используя Encoding.GetBytes.

    https://msdn.microsoft.com/en-us/library/system.text.encoding.getbytes%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396



    This posting is provided "AS IS" with no warranties, and confers no rights.

    Модератор
  • Очень благодарю за ответ, теперь хотя бы знаю где искать

    По поводу первого варианта. Я библиотеку добавляю через ссылки (reference), DLLImport не использовал (с этим сложности, т.к. внутри этой библиотеки есть сложный в реализации класс и у меня не получается его достать). Вытащить только do_smth:

    [DLLImport("TPLib.dll")]

    textBase do_smth([MarshalAs(UnmanagedType.LPStr)] string text)


    у меня получается, но он к сожалению привязан к внутреннему классу, так что в одиночке он бесполезен
    Если делать и то, и то, то вместо метода вытащенного с помощью DLLImport вызывается метод, вытащенный из reference


    Про второй вариант - я так понимаю что из за того что код неуправляемый, это нельзя реализовать? Вручную у меня не получилось хоть как то изменить неуправляемый код библиотеки, что в целом логично. Или есть какой то способ поменять входные параметры функции и добавить как-то две строки?

  • Оба варианта примерно одинаковы не требуют каких либо изменений в самой библиотеке. Хотя если у вас есть исходники к ней то это самый оптимальный вариант.

    Оба варианта требуют полной декларации всех методов, типов и интерфейсов из библиотеки в коде C#. Их можно создать в ручную или декомпилировать библиотеку созданную для вашей COM DLL утилитой TLBIMP:

    https://docs.microsoft.com/en-us/dotnet/framework/interop/how-to-generate-primary-interop-assemblies-using-tlbimp-exe

    Далее полученный код исправляется как надо (добавляются атрибуты, меняется сигнатура) и компилируется как обычно.

    This posting is provided "AS IS" with no warranties, and confers no rights.

    Модератор
  • Чтобы достать объявление какого-то отдельного класса или интерфейса из Interop-сборки, можно просто в студии нажать правой кнопкой по его имени и выбрать "Перейти к определению". Тогда студия откроет cs-файл, сгенерированный из метаданных, из которого можно код скопировать к себе и поменять что нужно.

  • Vadim: К сожалению в данном случае это похоже не реализуемо. Присутствует только названия и функций и нужные аргументы

    Ilya: но если библиотека  добавлена через reference, вроде происходит автоматической декларации функций?



  • Это ваш вопрос https://ru.stackoverflow.com/questions/829259/Как-добавить-маршалинг-строки-в-функцию-библиотеки-которая-добавлена-через-refe?noredirect=1#829259 ?

    Я там написал. Для COM-интерфейсов по умолчанию string маршалит в BSTR, который использует UTF-16 и поддерживает все языки. Ищите в чем-то другом проблему.

    • Помечено в качестве ответа BadThings 18 мая 2018 г. 14:15
  • Если COM добавлен через ссылку, то просто автоматом создается primary interop library (PIL). На картинках показан ее декомпилированный код. Он включает в себя только названия классов, функций и т.п, а фактическая реализации находится в COM объекте и написана на C++. 

    Как я сказал вам следует декомпилилировать всю PIL (созданную автоматически или в ручную через TLBIMP), исправить в ней что надо, собрать ее в отдельную DLL и использовать ссылку на нее в проекте. 

    Удобнее всего декомпилировать через ILSpy, но можно и по одному файлу как показано выше.


    This posting is provided "AS IS" with no warranties, and confers no rights.

    Модератор

  • Я там написал. Для COM-интерфейсов по умолчанию string маршалит в BSTR, который использует UTF-16 и поддерживает все языки. Ищите в чем-то другом проблему.

    Не факт что этот COM правильно реализован и не факт что манифест правильный. Лучше всего смотреть на C++ декларацию метода чтоб определить правильный тип параметра.

    This posting is provided "AS IS" with no warranties, and confers no rights.

    Модератор