📢歡迎點贊 :👍 收藏 ⭐留言 📝 如有錯誤敬請指正,賜人玫瑰,手留余香!
📢本文作者:由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>
希望這些介紹能幫助到大家。
你學廢了嗎?
👓都看到這了,還在乎點個贊嗎?
👓都點贊了,還在乎一個收藏嗎?
👓都收藏了,還在乎一個評論嗎?