📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!
📢本文作者:由webmote 原创
📢作者格言:新的征程,我们面对的不仅仅是技术还有人心,人心不可测,海水不可量,唯有技术,才是深沉黑夜中的一座闪烁的灯塔 !
序言
在工控领域,很多时候需要访问和控制海康相机,通过程序控制海康相机可以实现变倍变焦,拍照,抓取视频等不同的操作。海康的SDK是C++编写的Dll,因为没有很好的进行包装,使用起来还是比较麻烦的,并且随着海康SDK的版本不同,各类版本有许多差异性,不好的封装会导致有很多的问题,这里把踩过的坑列举下,以便后来者少踩坑。
1. 一个进程只能加在一个海康DLL
在许多的应用中,有时候会不小心有多个类库,如果重复引用了海康DLL,会导致C#在调用海康威视CHCNetSDK出现未能从程序集中加载类型“WIFI_AUTH_PARAM”,因为它在 0 偏移位置处包含一个对象字段,该字段已由一个非对象字段不正确地对齐或重叠。
很多的处理方案是把整个文件接口体头部的LayoutKind.Explicit改为LayoutKind.Auto,删除所有[FieldOffset(0)]
,这个从语言体系上来说是错误的,但方法又是可行的,为啥?
根本原因是你没有用到此结构体而已,一旦有引用,那么很可能带来不必要的麻烦。
因此,出现问题不要慌,仔细查找相关库,是不是有多次引用海康库的问题,就可以从根本上解决该问题。
2.监测海康相机是否还在线,或登录过期
很多同学采用ping
方式进行监测,不得不说,这是最初级的方案,它根本无法检测登录过期问题,正确的做法是利用SDK中的使用userid的函数,我这里挑了个简单的方法进行检测,非常好用,大家不妨拿来用:
public bool CheckDevice(int userId)
{
IntPtr addr = IntPtr.Zero;
uint nOutSize = 0;
try
{
int nInSize = Marshal.SizeOf<CHCNetSDK.NET_DVR_TIME>();
addr = Marshal.AllocHGlobal(nInSize);
var rtn = CHCNetSDK.NET_DVR_GetDVRConfig(userId, CHCNetSDK.NET_DVR_GET_TIMECFG, 0, addr, (uint)nInSize, ref nOutSize);
var dvrTime = Marshal.PtrToStructure<CHCNetSDK.NET_DVR_TIME>(addr);
return rtn;
}
catch
{
return false;
}
finally
{
if (addr != IntPtr.Zero)
{
try
{
Marshal.FreeHGlobal(addr);
}
catch { }
}
}
}
利用CheckDevice
函数,就可以对海康设备的通断情况进行直接检测,不但效率比ping
高,而且可靠易用。
3. 海康DLL引用
引用有几种方式,最简单的方式是直接使用 DllImportAttribute
属性进行,简单方便,只需要记得把海康的dll文件放在执行根目录的相对路径下即可。
[DllImport(@"\HkSdk\HCNetSDK.dll")]
public static extern bool NET_DVR_STDXMLConfig(int iUserID, ref NET_DVR_XML_CONFIG_INPUT lpInputParam, ref NET_DVR_XML_CONFIG_OUTPUT lpOutputParam);
...
//这个文件应该都有吧...
public class CHCNetSDK
{
public CHCNetSDK()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
//2019 3.1添加
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_XML_CONFIG_INPUT
{
public uint dwSize;//结构体大小
public IntPtr lpRequestUrl;//请求信令,字符串格式
public uint dwRequestUrlLen;
public IntPtr lpInBuffer;//输入参数缓冲区,XML格式
public uint dwInBufferSize;
public uint dwRecvTimeOut;//接收超时时间,单位:ms,填0则使用默认超时5s
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 32, ArraySubType = UnmanagedType.I1)]
public byte[] byRes;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_XML_CONFIG_OUTPUT
{
public uint dwSize;//结构体大小
public IntPtr lpOutBuffer;//输出参数缓冲区,XML格式
public uint dwOutBufferSize;
public uint dwReturnedXMLSize;//实际输出的XML内容大小
public IntPtr lpStatusBuffer;//返回的状态参数(XML格式:ResponseStatus),获取命令成功时不会赋值,如果不需要,可以置NULL
public uint dwStatusSize;//状态缓冲区大小(内存大小)
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 32, ArraySubType = UnmanagedType.I1)]
public byte[] byRes;
}
}
还有如果需要支持linux平台,以及windows的x86和x64,那么需要更多的封装,如果有需要可以留言。
4. SDK的初始化
海康SDK在使用的时候,需要进行SDK的初始化,在退出时,需要销毁资源,这里的资源属于非托管资源,因此请谨慎反复调用。
CHCNetSDK.NET_DVR_Cleanup();
if (!CHCNetSDK.NET_DVR_Init())
{
throw new Exception("海康相机初始化失败:调用NET_DVR_Init()方法返回false");
}
5. 登录登出
海康SDK支持限定并发连接到海康设备,因此频繁登入可能导致46错误,我们使用的时候,记得配对使用,避免引入bug。
var userID = CHCNetSDK.NET_DVR_Login_V40(ref struLogInfo, ref deviceInfo);
HCNetSDK.NET_DVR_Logout_V30(userID);
6.错误解析和输出
像大多数c++类库一样,它们都是采用一个特定函数获取错误码的。
public string GetErrorDetail()
{
var errorCode = CHCNetSDK.NET_DVR_GetLastError();
LastErrorCode = errorCode;
return string.Format("错误码:{0}", errorCode);
}
7.结论
我这里没有提供封装好的类库,这应该是有大量需求的,海康自己也没有很好的进行封装,我计划后面会提供一个,先发文章看看是否有需求了,大家可以评论给我。
你学废了吗?
👓都看到这了,还在乎点个赞吗?
👓都点赞了,还在乎一个收藏吗?
👓都收藏了,还在乎一个评论吗?