工作中遇到C++写的程序将结构体存储到Redis中。然后使用C#读取。其中有几个需要注意的坑。
1.Struct上的StructLayout中的Pack
在C#中定义的struct一定要和C++中的对应上
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
其中pack 对应C++中De#program pack()
附结构体转换代码:
1 public StructType ConverBytesToStructure<StructType>(byte[] bytesBuffer) 2 { 3 // 检查长度。 4 if (bytesBuffer.Length != Marshal.SizeOf(typeof(StructType))) 5 { 6 throw new ArgumentException("bytesBuffer参数和structObject参数字节长度不一致。"); 7 } 8 9 IntPtr bufferHandler = Marshal.AllocHGlobal(bytesBuffer.Length); 10 for (int index = 0; index < bytesBuffer.Length; index++) 11 { 12 Marshal.WriteByte(bufferHandler, index, bytesBuffer[index]); 13 } 14 StructType structObject = (StructType)Marshal.PtrToStructure(bufferHandler, typeof(StructType)); 15 Marshal.FreeHGlobal(bufferHandler); 16 return structObject; 17 }
2.嵌套结构体数组的定义
当一个结构体中含有另一个结构体数组时,使用如下的定义
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 18)]
public StructB[] m_Info;
3.字符编码的转换(宽窄字符集的问题)
采用上述StructLayout中的编码方式和在C++中的一样
在C++中 我将Const char*为了将汉字转化成PB的UTF-8
inline string GBKToUTF8(const char* cchar) { std::string strs(cchar); string strOutUTF8 = ""; WCHAR * str1; int n = MultiByteToWideChar(CP_ACP, 0, strs.c_str(), -1, NULL, 0); str1 = new WCHAR[n]; MultiByteToWideChar(CP_ACP, 0, strs.c_str(), -1, str1, n); n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL); char * str2 = new char[n]; WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL); strOutUTF8 = str2; delete[]str1; str1 = NULL; delete[]str2; str2 = NULL; return strOutUTF8; }
在C#端将转化过的字符串无论使用哪个字符集转都显示乱码。最后调用了C++的方法。
[DllImport("kernel32.dll")] private static extern int MultiByteToWideChar(int CodePage, int dwFlags, string lpMultiByteStr, int cchMultiByte, [MarshalAs(UnmanagedType.LPWStr)]string lpWideCharStr, int cchWideChar); public string MByteToWChar(string content, int toEncode) { //字符编码转换 gb2312:936 utf-8:65001 big5:950 latin1:1252 int len = MultiByteToWideChar(toEncode, 0, content, -1, null, 0); char[] temp = new char[len]; string content1 = new string(temp); MultiByteToWideChar(toEncode, 0, content, -1, content1, len); return content1; }