C#调用C++dll文件获取数据得到乱码的解决方法

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



发布了20 篇原创文章 · 获赞 5 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/mt122/article/details/50260403
今日推荐