我正在开发桌面应用程序的简化的Windows IoT核心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;
}
当前正在WPF和Forms应用程序上运行的以下PInvoke留下了指向info中的数据和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字符的映射” 。我们将其范围缩小到编码问题:令人讨厌的Pair.Key是一个包含变音符号(í)的名称。 Pi的默认编码似乎是UTF-8,而C库与之交互的设备的默认编码是ANSI。
我们该如何解决?由于C一半已经被广泛使用,所以它几乎是不可变的。我们尝试了几种封送处理选项,但均未成功。我尝试编写一个自定义封送程序,该程序在运行时抛出,因为显然WinRT不支持自定义封送程序。另一个理论上的选择是实现DecoderFallback,但我看不到让Marshal.PtrToStructure使用任何不同于Encoding.Default(只读)的编码的方法。