工作中遇到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; }