<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> 很久沒寫博客了,最近空閒下來,有空整理了下最近幾個項目,把遇到的一些問題記錄下來。</span>
做一個視頻二次開發的項目,是與大華的dss平臺進行對接。在獲取攝像頭名稱的時候經常出現亂碼,剛開始以爲是編碼問題,測試了各種編碼方式,最後都沒有解決。
最終沒辦法,最後諮詢大華研發,因爲對方只會C++,而我們的項目是C#開發,雙方在代碼上面溝通了很久,才發現是因爲結構體初始化後,要給字段內存賦一個空值。
因爲C#的習慣,每次new過後,就默認會賦值。所有也沒考慮到這麼多。先將解決代碼貼出來,大家也可以借鑑。
C++結構體原型:
//獲取組織請求信息
typedef struct tagGetDepInfo
{
IN char szCoding[DPSDK_CORE_DGROUP_DGPCODE_LEN]; // 節點code
IN uint32_t nDepCount; // 組織個數
OUT Dep_Info_t* pDepInfo; // 組織信息,在外部創建,如果爲NULL則只返回個數
IN uint32_t nDeviceCount; // 設備個數
OUT Device_Info_Ex_t* pDeviceInfo; // 設備信息
}Get_Dep_Info_t;
注意:其中Dep_Info_t*是一個集合,類似與C#的List<Dep_Info_t>,我們在C#中定義爲IntPtr指針地址。
下面是C#的定義(C#如何訪問C++的dll接口,請大家自行百度。一般是DllImport):
/// <summary>
/// 組織結構信息結構體
/// </summary>
//[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct Get_Dep_Info_t
{
/// <summary>
/// IN char szCoding[DPSDK_CORE_DGROUP_DGPCODE_LEN]; // 節點code
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DPSDK_CORE_DGROUP_DGPCODE_LEN)]
public byte[] szCoding;
/// <summary>
/// IN uint32_t nDepCount; // 組織個數
/// </summary>
public UInt32 nDepCount;
/// <summary>
/// OUT Dep_Info_t* pDepInfo; // 組織信息,在外部創建,如果爲NULL則只返回個數
/// </summary>
public IntPtr pDepInfo;
//public List<Dep_Info_t> pDepInfo;
/// <summary>
/// IN uint32_t nDeviceCount; // 設備個數
/// </summary>
public UInt32 nDeviceCount;
/// <summary>
/// OUT Device_Info_Ex_t* pDeviceInfo; // 設備信息
/// </summary>
public IntPtr pDeviceInfo;
//public List<Device_Info_Ex_t> pDeviceInfo;
}
注意:剛開始我們也是定義爲List集合,但是全部是亂碼,遇到這種數據類型不知道如何轉換的,大家都可以定義爲指針地址,然後再去轉換。因爲數據都是存放在內存中。
上面貼出了C++與C#的結構體定義,下面就來說說C++與C#如何初始化結構體。也許大家都會說直接new就可以了,對這樣是沒錯的,但是並沒有這麼簡單。
C++結構體初始化代碼
Get_Dep_Info_t* pGetDepInfo = new Get_Dep_Info_t;
memset(pGetDepInfo, 0 , sizeof(Get_Dep_Info_t));
memcpy(pGetDepInfo->szCoding, szDepId, strlen(szDepId));
pGetDepInfo->nDepCount = pGetCountInfo->nDepCount;
pGetDepInfo->nDeviceCount = pGetCountInfo->nDeviceCount;
if (pGetDepInfo->nDepCount > 0)
{
pGetDepInfo->pDepInfo = new Dep_Info_t[pGetCountInfo->nDepCount];
memset(pGetDepInfo->pDepInfo, 0, sizeof(Dep_Info_t)*pGetCountInfo->nDepCount);
}
if (pGetDepInfo->nDeviceCount > 0)
{
pGetDepInfo->pDeviceInfo = new Device_Info_Ex_t[pGetCountInfo->nDeviceCount];
memset(pGetDepInfo->pDeviceInfo, 0, sizeof(Device_Info_Ex_t)*pGetCountInfo->nDeviceCount);
}
pGetDepInfo->pDepInfo = new Dep_Info_t[pGetCountInfo->nDepCount];
memset(pGetDepInfo->pDepInfo, 0, sizeof(Dep_Info_t)*pGetCountInfo->nDepCount);
memset給結構體賦一個0的空值。關鍵就是這個,當初轉換層C#時,就是唄這個地方整瘋掉了。
下面是C#的初始化代碼:
//組織和設備獲取接口調用順序:
//0、DPSDK_LoadDGroupInfo
//1、DPSDK_GetDGroupCount
//2、DPSDK_GetDGroupInfo
//3、DPSDK_GetChannelInfo
//0、加載組織信息DPSDK_LoadDGroupInfo
//1、獲取組織下子組織和子設備的個數,加載組織結構完成後才能使用
DaHuaNetSdk_DSS_Szdjq_PInvoke.Get_Dep_Count_Info_t stuGetDepCountInfo = new DaHuaNetSdk_DSS_Szdjq_PInvoke.Get_Dep_Count_Info_t();
stuGetDepCountInfo.szCoding = szDepId;
stuGetDepCountInfo.nDepCount = 0;
stuGetDepCountInfo.nDeviceCount = 0;
lError = DaHuaNetSdk_DSS_Szdjq_PInvoke.DPSDK_GetDGroupCount(m_nPDLLHandle, ref stuGetDepCountInfo);
//2、獲取組織下子組織和子設備的信息,加載組織結構完成後才能使用
if (lError == (Int32)DaHuaNetSdk_DSS_Szdjq_PInvoke.dpsdk_ErrorCode_DaHua.DPSDK_RET_SUCCESS)
{
DaHuaNetSdk_DSS_Szdjq_PInvoke.Get_Dep_Info_t stuGetDepInfo = new DaHuaNetSdk_DSS_Szdjq_PInvoke.Get_Dep_Info_t();
stuGetDepInfo.szCoding = szDepId;
//獲取部門個數,並初始化數組
stuGetDepInfo.nDepCount = stuGetDepCountInfo.nDepCount;
int tagDepInfotSize = Marshal.SizeOf(typeof(DaHuaNetSdk_DSS_Szdjq_PInvoke.Dep_Info_t));/* 獲取Dep_Info_t結構體長度 */
IntPtr ptrDepInfoList = Marshal.AllocHGlobal(Convert.ToInt32(tagDepInfotSize * stuGetDepCountInfo.nDepCount));
//Marshal.WriteInt32(ptrDepInfoList, 0);
#region 初始化取值,組織機構指針
for (int idx = 0; idx < stuGetDepInfo.nDepCount; idx++)
{
IntPtr pBufferFlag = new IntPtr(ptrDepInfoList.ToInt32() + idx * tagDepInfotSize);
DaHuaNetSdk_DSS_Szdjq_PInvoke.Dep_Info_t pstDepInfoItem = new DaHuaNetSdk_DSS_Szdjq_PInvoke.Dep_Info_t();
pstDepInfoItem.szCoding = new byte[DaHuaNetSdk_DSS_Szdjq_PInvoke.DPSDK_CORE_DGROUP_DGPCODE_LEN];
pstDepInfoItem.szDepName = new byte[DaHuaNetSdk_DSS_Szdjq_PInvoke.DPSDK_CORE_DGROUP_DGPNAME_LEN];
Marshal.StructureToPtr(pstDepInfoItem, pBufferFlag, true);
}
#endregion
stuGetDepInfo.pDepInfo = ptrDepInfoList;
//獲取設備個數,並初始化數組
stuGetDepInfo.nDeviceCount = stuGetDepCountInfo.nDeviceCount;
}
我們將Dep_Info_t*定義爲指針地址,然後將指針轉換成結構體,然後將結構體new,並將結構體中的byte數組賦0的初始值,當初就因爲byte沒有賦值0,導致內存中有髒數據,最終轉換出來的字符串變成了亂碼。