<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,导致内存中有脏数据,最终转换出来的字符串变成了乱码。