📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!
📢本文作者:由webmote 原创
📢作者格言:新的征程,我们面对的不仅仅是技术还有人心,人心不可测,海水不可量,唯有技术,才是深沉黑夜中的一座闪烁的灯塔
序言
上2篇海康SDK使用以及常见的坑受到了许多网友的喜爱,这也说明了在工控领域内,使用.net开发还是非常便捷省事的。针对海康的SDK进行进一步封装,第一版Net Framework版本代码发在github上,供大家测试和使用。
这次主要讲解在.net core /6/7/8下进行跨平台调用时怎么封装海康的跨平台库,毕竟很多的研发类库已经都迁移到.net core 跨平台的系统上,以便适应时代的潮流,支持和兼容linux系统,国产操作系统或者华为鸿蒙系统等。
声明下 ,海康威视没有给赞助费,希望厂家能够看到,给点打赏,哈哈~~~
1. 跨平台类库支持
目前.net Core 支持两种模式对类库进行加载,一种是传统方式,使用
DllImport
属性模式定义;另外一种是新的方式,采用
NativeLibrary
类库进行高级解析和加载,这种方式需要你确认你的.net 类库版本,需要在支持范围内(.net core 3.1 以及.net 5+)。
2. 采用DllImport默认方式加载
如果你使用这种模式,那么大部分情形需要限定dll的路径,因此我们先看下默认采用的规则是什么?
[DllImport("HCNetSDK")]
publicstaticexternboolNET_DVR_Init();
上面的代码,就隐含了下列规则:
在 Windows 上运行时,将按以下顺序搜索 DLL:
HCNetSDK
HCNetSDK.dll(如果库名称尚未以 .dll 或 .exe 结尾)
在 Linux 或 macOS 上运行时,运行时将尝试在前添加
lib
,并追加扩展名。在这些 OS 上,按以下顺序尝试库名:
HCNetSDK.so / - HCNetSDK.dylib
libHCNetSDK.so / libHCNetSDK.dylib1
HCNetSDK
libHCNetSDK1
注意,在这些系统上,名称是区分大小写的。
当然,如果类库名称以
.so
结尾或包含
.so.
,则搜索顺序会有所不同。
HCNetSDK.so.6
libHCNetSDK.so.61
HCNetSDK.so.6.so
libHCNetSDK.so.6.so1
3.采用NativeLibrary进行高级解析
在新版本的.net框架中,其提供了一系列函数对库加载的支持:
voidFree(IntPtr handle)
IntPtrGetExport(IntPtr handle,String name)
IntPtrLoad(String libraryPath)
IntPtrLoad(String libraryName, Assembly, DllImportSearchPath?)
voidSetDllImportResolver(Assembly, DllImportResolver)
IntPtrTryGetExport(IntPtr handle,String name,outIntPtr address)
IntPtrTryLoad(String libraryPath,outIntPtr handle)
IntPtrTryLoad(String libraryName, Assembly, DllImportSearchPath?,outIntPtr handle)
其中仍然利用
DllImport
界定类库名称,然后再利用
DllImportResolver
进行高级解析。
参数
assembly
:已为其注册解析程序的程序集。
参数
resolver
:要注册的解析程序回调。
此回调函数是第一次尝试解析程序集时启动的本机库加载函数。此方法的调用方应仅为自己的程序集注册解析程序。每个程序集只能注册一个解析程序。尝试注册第二个解析程序失败,并显示
InvalidOperationException
。
以下是封装海康SDK的跨平台核心代码:
public classHcNetSdk
{
privateconststring HCNetSDK ="HCNetSDK";
//静态构造,保调用时,一次加载。
staticHcNetSdk()
{
NativeLibrary.SetDllImportResolver(typeof(HcNetSdk).Assembly, DllImportResolver);
}
privatestaticIntPtrDllImportResolver(string libraryName,Assembly assembly,DllImportSearchPath? searchPath)
{
// windows下加载dll
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if(Environment.Is64BitProcess)
{
if(libraryName == HCNetSDK)
{
return NativeLibrary.Load("./HCNetSDK/x64/HCNetSDK.dll", assembly, searchPath);
}
elseif(libraryName == AnalyzeData)
{
return NativeLibrary.Load("./HCNetSDK/x64/HCNetSDKCom/AnalyzeData.dll", assembly, searchPath);
}
}
else
{
if(libraryName == HCNetSDK)
{
return NativeLibrary.Load("./HCNetSDK/x86/HCNetSDK.dll", assembly, searchPath);
}
elseif(libraryName == AnalyzeData)
{
return NativeLibrary.Load("./HCNetSDK/x86/HCNetSDKCom/AnalyzeData.dll", assembly, searchPath);
}
}
}
else//linux操作系统下,此处没有细分,如果有更多系统需求,可以自行增加
{
if(libraryName == HCNetSDK)
{
return NativeLibrary.Load("./HCNetSDK/linux/libhcnetsdk.so", assembly, searchPath);
}
elseif(libraryName == AnalyzeData)
{
return NativeLibrary.Load("./HCNetSDK/linux/HCNetSDKCom/libanalyzedata.so", assembly, searchPath);
}
}
// Otherwise, fallback to default import resolver.
return IntPtr.Zero;
}
publicHcNetSdk()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
[DllImport(HCNetSDK)]
publicstaticexternintNET_DVR_SendWithRecvRemoteConfig(int lHandle,IntPtr lpInBuff,uint dwInBuffSize,IntPtr lpOutBuff,uint dwOutBuffSize,refuint dwOutDataLen);
[DllImport(HCNetSDK)]
publicstaticexternintNET_DVR_SendWithRecvRemoteConfig(int lHandle,refHcNetSdk.NET_DVR_FACE_RECORD lpInBuff,int dwInBuffSize,refHcNetSdk.NET_DVR_FACE_STATUS lpOutBuff,int dwOutBuffSize,IntPtr dwOutDataLen);
[DllImport(HCNetSDK)]
publicstaticexternintNET_DVR_SendWithRecvRemoteConfig(int lHandle,refHcNetSdk.NET_DVR_FINGERPRINT_RECORD lpInBuff,int dwInBuffSize,refHcNetSdk.NET_DVR_FINGERPRINT_STATUS lpOutBuff,int dwOutBuffSize,IntPtr dwOutDataLen);
...
}
4. 海康dll的路径组织
按照上面的解析定义,我们自定义了路径进行海康dll的加载,因此需要按照代码内的内容对dll及放好,放置方式如下所示。
类库的项目文件中,需要增加对这些类库的处理定义:
<ItemGroup>
<NoneUpdate="HCNetSDK\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
编译的dll 和海康的dll目录和文件不要搞丢了。
5. 总结
这里以海康sdk的dll加载为例,介绍了两种方案进行跨平台的封装方式,如果你加载的dll文件比较少,可以使用第一种方案简单的进行标记和部署即可;如果涉及的dll比较复杂,需要放在不同的目录下进行调用支撑,那么采用第二种方式自定义控制更方便灵活。
据我查看微软文档,还有一种方式是DllMap方式,再Mono下用的非常多,采用XML方式对dll的映射进行定义,即可实现类似2的方案,xml类似如下定义,这种方式我没有试过,有兴趣的朋友可以试一试。
<configuration>
<dllmapdll="OldLib"target="NewLib"/>
</configuration>
希望这些介绍能帮助到大家。
你学废了吗?
👓都看到这了,还在乎点个赞吗?
👓都点赞了,还在乎一个收藏吗?
👓都收藏了,还在乎一个评论吗?