Структура маршалинга со строками на WinRT - PullRequest
0 голосов
/ 25 июня 2018

Я разрабатываю урезанный порт Windows IoT Core ARM для настольного приложения в качестве доказательства концепции для большего количества вариантов распространения с одноплатными компьютерами (в настоящее время используется Raspberry Pi3 B +). Нам нужно упорядочить неуправляемый массив C пар строк строк с нулевым символом в конце, например:

// The C struct
typedef struct {
const char *key;
char* value;
} Pair;

// Its managed counterpart
[StructLayout(LayoutKind.Sequential)]
public struct Pair
{
    [MarshalAs(UnmanagedType.LPStr)]
    public string Key;
    [MarshalAs(UnmanagedType.LPStr)]
    public string Value;
}

Следующий PInvoke, в настоящее время работающий с нашими приложениями WPF и Forms, оставляет указатель на данные в информации и количество элементов в infoLength:

[DllImport("path/to.dll", EntryPoint = "unmanagedfunction", CallingConvention = CallingConvention.Cdecl)]
public static extern OperationResultEnum GetDeviceInfo(IntPtr session, out IntPtr info, out int infoLength);

который мы затем маршалируем, используя следующую обобщенную функцию:

public static T[] GetArray(IntPtr ptr, int length)
    {
        T[] array = new T[length];
        Type type = typeof(T);
        IntPtr offsetPtr = ptr;
        int size = Marshal.SizeOf(type);
        for (int i = 0; i < length; i++)
        {
            array[i] = (T)Marshal.PtrToStructure(offsetPtr, type);
            offsetPtr = new IntPtr(offsetPtr.ToInt64() + size);
        }

        return array;
    }

Похоже, что это работает в нашем приложении UWP IoT Core, но для некоторых выходных данных происходит сбой где-то в середине массива с System.ArgumentOutOfRangeException: «В целевой многобайтовой кодовой странице не существует сопоставления для символа Unicode» , Мы сузили это до проблемы кодирования: нарушающая пара. Ключ - это имя, содержащее диакритический знак (í). Кодировка по умолчанию для Pi выглядит как UTF-8, а кодировка по умолчанию для устройства, с которым взаимодействует библиотека C, - это ANSI.

Как мы можем это исправить? C-половина более или менее неизменна, так как она уже широко используется. Мы попробовали несколько вариантов маршалинга без успеха. Я попытался написать собственный маршалер, который выдает во время выполнения, потому что, очевидно, пользовательские маршалеры не поддерживаются в WinRT. Другой теоретический вариант - реализация DecoderFallback, но я не вижу способа заставить Marshal.PtrToStructure использовать любую кодировку, отличную от Encoding.Default, которая доступна только для чтения.

...