Как передать строки c # через p / invoke в параметры linux / glibc wchar_t *? - PullRequest
0 голосов
/ 14 февраля 2019

У меня есть приложение .NET Core 2.2 C #, которое использует DllImport для извлечения собственной разделяемой библиотеки на CentOS 7.5 (интерфейс C ++ extern "C", скомпилированный с gcc).Для функций в библиотеке C ++ требуются параметры wchar_t *, но эти параметры отображаются в виде строк UTF16, а не строк UTF32, как реализовано в gcc / glibc.Это (моя) ошибка программиста или она должна быть вызвана командой .NET Core?

Вот очень сложный метод, который я пытаюсь вызвать:

void wchar_tTest(const wchar_t *arg1, const wchar_t *arg2)
{
    std::wcout << L"wchar_tTest: arg1: " << arg1 << L", arg2: " << arg2 << std::endl;

    char *s = (char *)arg1;
    for (int i = 0; i < 12; i++)
    {
        printf("%d: %c\n", i, s[i]);
    }
}

Я пытался использоватьMarshalAs(UnmanagedType.LPWSTR) и / или CharSet.Unicode на DllImport на управляемой стороне безрезультатно.Они оба дают схожие результаты:

[DllImport("cover", EntryPoint = "wchar_tTest", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void LPWSTRStringTest([MarshalAs(UnmanagedType.LPWStr)] string arg1, [MarshalAs(UnmanagedType.LPWStr)] string arg2);

[DllImport("cover", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void wchar_tTest(string arg1, string arg2);

Вызовы выглядят следующим образом (с stringTest() - это аналогичный вызов, но для функции с char * аргументами):

string arg1 = "Hello!";
string arg2 = "Goodbye!";

stringTest(arg1, arg2);

wchar_tTest(arg1, arg2);

LPWSTRStringTest(arg1, arg2);

Когдапараметры сбрасываются через wcout, Hello! становится Hlo и Goodbye! становится Gobe.Вывод выглядит подозрительно, как UTF16, когда вы проходите символ за символом ... Похоже, wchar_t * пропускает все остальные символы UTF16 (обрабатывая его как строку UTF32, которую я предполагаю).

wchar_tTest: arg1: Hlo, arg2: Gobe
0: H
1: 
2: e
3: 
4: l
5: 
6: l
7: 
8: o
9: 
10: !
11: 

Есть лиспособ решить эту проблему, не делая пользовательских сортировки?После всего, что я прочитал, кажется, что это должно быть простым заданием, но я здесь.

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Учитывая количество трафика, которое я видел без хороших ответов, я опубликую кратковременный хак, который я использую, чтобы решить эту проблему, учитывая ограничение, что сторона мира C ++ / native-библиотеки не может быть изменена ...

Я изменил DllImport для объявления параметров байта []

[DllImport("cover", EntryPoint = "wchar_tTest", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void utf32Test(byte[] arg1, byte[] arg2);

и создал версию строк .NET в кодировке UTF32

string arg1 = "Hello!";
byte[] arg1UTF32 = Encoding.UTF32.GetBytes(arg1);
string arg2 = "Goodbye!";
byte[] arg2UTF32 = Encoding.UTF32.GetBytes(arg2);

utf32Test(arg1UTF32, arg2UTF32);

и вуаля вы получите ожидаемый результатстроки и содержимое массива

wchar_tTest: arg1: Hello!, arg2: Goodbye!
0: H
1: 
2: 
3: 
4: e
5: 
6: 
7: 
8: l
9: 
10: 
11: 

Это вряд ли очень переносимо, и, конечно, происходит сбой при запуске этого в системе Windows.Я надеюсь, что есть лучший ответ.

0 голосов
/ 14 февраля 2019

Текст обозначен как UTF16, как и ожидалось и как задумано.Вам необходимо либо:

  • Адаптировать код C ++ для работы с UTF16, либо
  • Пользовательский маршал, используя другую кодировку, например, UTF8 или UTF32.
...