Проблема маршалинга с символом ** при доступе к функции библиотеки - PullRequest
0 голосов
/ 10 июня 2019

Я портирую существующую библиотеку / DLL, написанную на C ++ / VisualStudio, на кодовые блоки / GCC.DLL в Windows была протестирована на C #, C, C ++, Python, Delphi, Java, VB.NET, LabVIEW и т. Д. И работает нормально и стабильно.Однако при портировании его на Linux у меня возникают проблемы при тестировании его из Mono / C #, в то время как он работает нормально с FreePascal и Python.

Корень проблемы - это функция, которая обнаруживает некоторые устройства и возвращает их.целое число с количеством обнаруженных устройств и списком путей (массив строк символов ASCII), в которых расположены устройства, через параметры:

int DetectDevices(char ** DevicePaths);

Они копируют результаты вбиблиотека:

i=0;
for (vector<string>::iterator it=lstDetected.begin(); it!=lstDetected.end(); ++it)
    strcpy(DevicePaths[i++], (*it).c_str());

В C # я объявляю внешнюю функцию, используя следующий код:

[DllImport(LIBRARY_PATH)]
public static extern int DetectDevices([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] DevicePaths);

Я хотел бы отметить, что я на самом деле резервирую некоторое пространство памятив C # перед вызовом функции и получением возвращенного значения:

string[] DevicePaths = new string[50];
for (int i=0; i<DevicePaths.Length; i++)
    DevicePaths[i] = new string('\0', 255);

Это нормально работает в Windows / VisualStudio, но не в Linux / Mono.

Замена LPStr на LPWStr и выполнениеотладка, показывает, что символы предположительно прибывают, но эквивалентный полученный код ASCII равен 0 для всех символов в LPStr и 63 в LPWStr.

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

Кто-нибудь знает, что здесь может быть не так?Помощь будет высоко ценится!

Ответы [ 2 ]

1 голос
/ 13 июня 2019

Мне наконец-то удалось найти решение проблемы Маршалинга.

В Windows (.NET Framework) и Visual Studio допускается возврат параметра C массив строк (array of char array) следующим образом:

[DllImport(LIBRARY_PATH)]
public static extern int DetectDevices([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] DevicePaths);

по какой-то причине это не работает в Linux / Mono, и мне пришлось использовать следующий метод:

public static extern int DetectDevices(IntPtr[] pDevicePaths);

, а затем в коде извлекаем каждую строку, используя следующий метод:

const int VCOUNT = 50;
const int MAXSTRINGSIZE = 255;
string[] MyValues = new string[VCOUNT];

IntPtr[] ptr = new IntPtr[VCOUNT];
for (int i = 0; i < ptr.Length; i++) ptr[i] = Marshal.AllocCoTaskMem(MAXSTRINGSIZE);

int n = DetectDevices(ptr);
if (n > 0) {
    for (int i = 0; i < n; i++) {
        StringBuilder sb = new StringBuilder(Marshal.PtrToStringAnsi(ptr[i]));
        MyValues[i] = sb.ToString();
    }
}

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

Если у кого-то есть лучшее решение, я буду очень признателен.

0 голосов
/ 10 июня 2019

Попробуйте с LPTStr, который преобразует строку в кодировку строки платформы по умолчанию.Для моно это UTF-8.

  • UnmanagedType.LPStr => ansi
  • UnmanagedType.LPWStr => Юникод
  • UnmanagedType.LPTStr => платформа по умолчанию

Тамдругие UnmanagedType, которые также могут помочь ... BStr возможно ...?

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

документация довольно хорошая.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...