天天看點

.net 調用海康SDK的跨平台解決方案

  • 📢歡迎點贊 :👍 收藏 ⭐留言 📝 如有錯誤敬請指正,賜人玫瑰,手留餘香!
  • 📢本文作者:由webmote 原創
  • 📢作者格言:新的征程,我們面對的不僅僅是技術還有人心,人心不可測,海水不可量,唯有技術,才是深沉黑夜中的一座閃爍的燈塔

序言

上2篇海康SDK使用以及常見的坑受到了許多網友的喜愛,這也說明了在工控領域内,使用.net開發還是非常便捷省事的。針對海康的SDK進行進一步封裝,第一版Net Framework版本代碼發在github上,供大家測試和使用。

這次主要講解在.net core /6/7/8下進行跨平台調用時怎麼封裝海康的跨平台庫,畢竟很多的研發類庫已經都遷移到.net core 跨平台的系統上,以便适應時代的潮流,支援和相容linux系統,國産作業系統或者華為鴻蒙系統等。

.net 調用海康SDK的跨平台解決方案

聲明下,海康威視沒有給贊助費,希望廠家能夠看到,給點打賞,哈哈~~~

1. 跨平台類庫支援

目前.net Core 支援兩種模式對類庫進行加載,一種是傳統方式,使用

DllImport

屬性模式定義;另外一種是新的方式,采用

NativeLibrary

類庫進行進階解析和加載,這種方式需要你确認你的.net 類庫版本,需要在支援範圍内(.net core 3.1 以及.net 5+)。

2. 采用DllImport預設方式加載

如果你使用這種模式,那麼大部分情形需要限定dll的路徑,是以我們先看下預設采用的規則是什麼?

[DllImport("HCNetSDK")]
public static extern bool NET_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架構中,其提供了一系列函數對庫加載的支援:

void Free(IntPtr handle)
IntPtr GetExport(IntPtr handle, String name)
IntPtr Load(String libraryPath)
IntPtr Load(String libraryName, Assembly, DllImportSearchPath?)
void SetDllImportResolver(Assembly, DllImportResolver)
IntPtr TryGetExport(IntPtr handle, String name, out IntPtr address)
IntPtr TryLoad(String libraryPath, out IntPtr handle)
IntPtr TryLoad(String libraryName, Assembly, DllImportSearchPath?, out IntPtr handle)
           

其中仍然利用

DllImport

界定類庫名稱,然後再利用

DllImportResolver

進行進階解析。

  • 參數

    assembly

    :已為其注冊解析程式的程式集。
  • 參數

    resolver

    :要注冊的解析程式回調。

此回調函數是第一次嘗試解析程式集時啟動的本機庫加載函數。此方法的調用方應僅為自己的程式集注冊解析程式。每個程式集隻能注冊一個解析程式。嘗試注冊第二個解析程式失敗,并顯示

InvalidOperationException

以下是封裝海康SDK的跨平台核心代碼:

public class HcNetSdk
{
private const string HCNetSDK = "HCNetSDK"; 
//靜态構造,保調用時,一次加載。
static HcNetSdk()
{
 NativeLibrary.SetDllImportResolver(typeof(HcNetSdk).Assembly, DllImportResolver);
}
private static IntPtr DllImportResolver(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);
}
else if(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);
}
else if (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);
}
else if (libraryName == AnalyzeData)
{
return NativeLibrary.Load("./HCNetSDK/linux/HCNetSDKCom/libanalyzedata.so", assembly, searchPath);
}
}


// Otherwise, fallback to default import resolver.
return IntPtr.Zero;
}

public HcNetSdk()
{
//
// TODO: 在此處添加構造函數邏輯
//
}
[DllImport(HCNetSDK)]
public static extern int NET_DVR_SendWithRecvRemoteConfig(int lHandle, IntPtr lpInBuff, uint dwInBuffSize, IntPtr lpOutBuff, uint dwOutBuffSize, ref uint dwOutDataLen);

[DllImport(HCNetSDK)]
public static extern int NET_DVR_SendWithRecvRemoteConfig(int lHandle, ref HcNetSdk.NET_DVR_FACE_RECORD lpInBuff, int dwInBuffSize, ref HcNetSdk.NET_DVR_FACE_STATUS lpOutBuff, int dwOutBuffSize, IntPtr dwOutDataLen);

[DllImport(HCNetSDK)]
public static extern int NET_DVR_SendWithRecvRemoteConfig(int lHandle, ref HcNetSdk.NET_DVR_FINGERPRINT_RECORD lpInBuff, int dwInBuffSize, ref HcNetSdk.NET_DVR_FINGERPRINT_STATUS lpOutBuff, int dwOutBuffSize, IntPtr dwOutDataLen);
...
}
           

4. 海康dll的路徑組織

按照上面的解析定義,我們自定義了路徑進行海康dll的加載,是以需要按照代碼内的内容對dll及放好,放置方式如下所示。

.net 調用海康SDK的跨平台解決方案
.net 調用海康SDK的跨平台解決方案

類庫的項目檔案中,需要增加對這些類庫的處理定義:

<ItemGroup>
<None Update="HCNetSDK\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
           

編譯的dll 和海康的dll目錄和檔案不要搞丢了。

5. 總結

這裡以海康sdk的dll加載為例,介紹了兩種方案進行跨平台的封裝方式,如果你加載的dll檔案比較少,可以使用第一種方案簡單的進行标記和部署即可;如果涉及的dll比較複雜,需要放在不同的目錄下進行調用支撐,那麼采用第二種方式自定義控制更友善靈活。

據我檢視微軟文檔,還有一種方式是DllMap方式,再Mono下用的非常多,采用XML方式對dll的映射進行定義,即可實作類似2的方案,xml類似如下定義,這種方式我沒有試過,有興趣的朋友可以試一試。

<configuration>
<dllmap dll="OldLib" target="NewLib"/>
</configuration>
           
.net 調用海康SDK的跨平台解決方案

希望這些介紹能幫助到大家。

你學廢了嗎?

👓都收藏了,還在乎一個評論嗎?