- 📢 Welcome to like: 👍 Collection ⭐ Message 📝 If there is a mistake, please correct, give people roses, and leave a lingering fragrance in your hands!
- 📢 This article was written by webmote
- 📢 Author's motto: The new journey, we are facing not only technology but also people's hearts, people's hearts are unpredictable, the sea water is immeasurable, only technology is a flickering beacon in the deep dark night
preface
The use of Hikvision SDK and common pits in the last 2 articles have been loved by many netizens, which also shows that in the field of industrial control, it is still very convenient to use .net development. The first version of the Net Framework version is published on github for testing and use.
This time I will mainly explain how to encapsulate Hikvision's cross-platform library when making cross-platform calls under .NET Core /6/7/8, after all, many R&D libraries have been migrated to .NET Core cross-platform systems in order to adapt to the trend of the times, support and compatibility with Linux systems, domestic operating systems or Huawei Hongmeng systems, etc.
Under the statement, Hikvision did not give a sponsorship fee, I hope the manufacturer can see it and give a reward, haha~~~
1. Cross-platform library support
Currently, .NET Core supports two modes for loading class libraries, one is the traditional way, used
DllImport
attribute schema definition; The other is a new way to adopt
NativeLibrary
Advanced parsing and loading of class libraries requires you to confirm your .NET library version, which needs to be supported (.NET Core 3.1 and .NET 5+).
2. Use the default DllImport mode to load
If you're using this pattern, you'll need to limit the path to the dll in most cases, so let's take a look at what is the default rule?
[DllImport("HCNetSDK")]
public static extern bool NET_DVR_Init();
The above code implies the following rules:
When running on Windows, DLLs are searched in the following order:
- HCNetSDK
- HCNetSDK.dll if the library name doesn't already end with .dll or .exe)
When running on Linux or macOS, the runtime will attempt to add first
lib
and append the extension. On these OSs, try the library names in the following order:
- HCNetSDK.so / - HCNetSDK.dylib
- libHCNetSDK.so / libHCNetSDK.dylib1
- HCNetSDK
- libHCNetSDK1
Note that on these systems, names are case-sensitive.
Of course, if the library name starts with
.so
End or contain
.so.
, the search order will be different.
- HCNetSDK.so.6
- libHCNetSDK.so.61
- HCNetSDK.so.6.so
- libHCNetSDK.so.6.so1
3. NativeLibrary is used for advanced parsing
In the new version of the .NET framework, it provides a series of functions to support library loading:
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)
which is still utilized
DllImport
Define the name of the class library and then utilize it
DllImportResolver
Advanced parsing.
- parameter
: The assembly for which the resolver has been registered.assembly
- parameter
: The resolver callback to be registered.resolver
This callback function is a native library load function that is started when you first try to resolve an assembly. The caller of this method should register the resolver only for its own assembly. Only one resolver can be registered per assembly. Attempts to register the second resolver fail and are displayed
InvalidOperationException
。
The following is the cross-platform core code that encapsulates the Hikvision 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. Path organization of Hikvision DLLs
According to the above definition of analysis, we have customized the path to load the Hikvision DLL, so we need to put the DLL according to the content in the code, and the placement method is as follows.
In the project file of the class libraries, you need to add the processing definitions for these class libraries:
<ItemGroup>
<None Update="HCNetSDK\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
Don't lose the compiled dll and Hikvision's dll directories and files.
5. Summary
If you load a small number of DLL files, you can use the first solution to simply mark and deploy; If the DLLs involved are complex and need to be placed in different directories for call support, then the second way is more convenient and flexible to customize the control.
According to my view of Microsoft documentation, there is another way is the DllMap method, and then Mono is used a lot, using XML to define the mapping of dll, you can achieve a scheme similar to 2, xml is similar to the following definition, I have not tried this way, interested friends can try it.
<configuration>
<dllmap dll="OldLib" target="NewLib"/>
</configuration>
I hope you find these presentations helpful.
Have you lost your studies?
👓 It's all favorited, do you still care about a comment?