hikvision-sync-service/Interop/HikvisionTemplateInterop.cs

275 lines
9.5 KiB
C#

using System;
using System.Runtime.InteropServices;
using System.Text;
namespace HikvisionAttendanceService.Interop;
internal static class HikvisionTemplateInterop
{
// These wrappers allow template query/delete/sync with direct HCNetSDK.dll calls.
[DllImport("HCNetSDK.dll", CallingConvention = CallingConvention.StdCall)]
private static extern bool NET_DVR_SetDeviceConfig(
int lUserID,
uint dwCommand,
int lChannel,
IntPtr lpInBuffer,
uint dwInBufferSize,
IntPtr lpStatusList,
IntPtr lpInParamBuffer,
uint dwInParamBufferSize);
[DllImport("HCNetSDK.dll", CallingConvention = CallingConvention.StdCall)]
private static extern bool NET_DVR_GetDeviceConfig(
int lUserID,
uint dwCommand,
int lChannel,
IntPtr lpOutBuffer,
uint dwOutBufferSize,
ref uint lpBytesReturned,
IntPtr lpStatusList,
IntPtr lpInParamBuffer,
uint dwInParamBufferSize);
// Command IDs are the official ACS face/fingerprint config commands.
private const uint NET_DVR_SET_FACE_PARAM_CFG = 2568;
private const uint NET_DVR_GET_FACE_PARAM_CFG = 2569;
private const uint NET_DVR_DEL_FACE_PARAM_CFG = 2570;
private const uint NET_DVR_SET_FINGERPRINT_PARAM = 2573;
private const uint NET_DVR_GET_FINGERPRINT_PARAM = 2574;
private const uint NET_DVR_DEL_FINGERPRINT_PARAM = 2575;
[StructLayout(LayoutKind.Sequential)]
internal struct NET_DVR_FACE_PARAM_CFG
{
public uint dwSize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] byCardNo;
public uint dwFaceLen;
public IntPtr pFaceBuffer;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public byte[] byRes;
}
[StructLayout(LayoutKind.Sequential)]
internal struct NET_DVR_FINGERPRINT_PARAM
{
public uint dwSize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] byCardNo;
public byte byFingerPrintID;
public byte byEnableCardReader;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] byRes1;
public uint dwFingerPrintLen;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2048)]
public byte[] byFingerData;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] byRes2;
}
internal static bool SetFaceParam(int userId, int channel, string cardNo, byte[] faceData, out string error)
{
error = "";
var cfg = new NET_DVR_FACE_PARAM_CFG
{
dwSize = (uint)Marshal.SizeOf(typeof(NET_DVR_FACE_PARAM_CFG)),
byCardNo = new byte[32],
byRes = new byte[128],
dwFaceLen = (uint)(faceData?.Length ?? 0),
pFaceBuffer = IntPtr.Zero
};
CopyAscii(cardNo, cfg.byCardNo);
IntPtr cfgPtr = IntPtr.Zero;
IntPtr facePtr = IntPtr.Zero;
try
{
if (faceData == null || faceData.Length == 0)
{
error = "faceData is empty";
return false;
}
facePtr = Marshal.AllocHGlobal(faceData.Length);
Marshal.Copy(faceData, 0, facePtr, faceData.Length);
cfg.pFaceBuffer = facePtr;
cfgPtr = Marshal.AllocHGlobal((int)cfg.dwSize);
Marshal.StructureToPtr(cfg, cfgPtr, false);
return NET_DVR_SetDeviceConfig(userId, NET_DVR_SET_FACE_PARAM_CFG, channel, cfgPtr, cfg.dwSize, IntPtr.Zero, IntPtr.Zero, 0);
}
finally
{
if (cfgPtr != IntPtr.Zero) Marshal.FreeHGlobal(cfgPtr);
if (facePtr != IntPtr.Zero) Marshal.FreeHGlobal(facePtr);
}
}
internal static bool GetFaceParam(int userId, int channel, string cardNo, out byte[] faceData)
{
faceData = Array.Empty<byte>();
var cfg = new NET_DVR_FACE_PARAM_CFG
{
dwSize = (uint)Marshal.SizeOf(typeof(NET_DVR_FACE_PARAM_CFG)),
byCardNo = new byte[32],
byRes = new byte[128]
};
CopyAscii(cardNo, cfg.byCardNo);
uint returned = 0;
IntPtr cfgPtr = IntPtr.Zero;
try
{
cfgPtr = Marshal.AllocHGlobal((int)cfg.dwSize);
Marshal.StructureToPtr(cfg, cfgPtr, false);
if (!NET_DVR_GetDeviceConfig(userId, NET_DVR_GET_FACE_PARAM_CFG, channel, cfgPtr, cfg.dwSize, ref returned, IntPtr.Zero, IntPtr.Zero, 0))
return false;
var outCfg = Marshal.PtrToStructure<NET_DVR_FACE_PARAM_CFG>(cfgPtr);
if (outCfg.dwFaceLen == 0 || outCfg.pFaceBuffer == IntPtr.Zero)
return true;
faceData = new byte[outCfg.dwFaceLen];
Marshal.Copy(outCfg.pFaceBuffer, faceData, 0, (int)outCfg.dwFaceLen);
return true;
}
finally
{
if (cfgPtr != IntPtr.Zero) Marshal.FreeHGlobal(cfgPtr);
}
}
internal static bool DeleteFaceParam(int userId, int channel, string cardNo)
{
var cfg = new NET_DVR_FACE_PARAM_CFG
{
dwSize = (uint)Marshal.SizeOf(typeof(NET_DVR_FACE_PARAM_CFG)),
byCardNo = new byte[32],
byRes = new byte[128]
};
CopyAscii(cardNo, cfg.byCardNo);
IntPtr cfgPtr = IntPtr.Zero;
try
{
cfgPtr = Marshal.AllocHGlobal((int)cfg.dwSize);
Marshal.StructureToPtr(cfg, cfgPtr, false);
return NET_DVR_SetDeviceConfig(userId, NET_DVR_DEL_FACE_PARAM_CFG, channel, cfgPtr, cfg.dwSize, IntPtr.Zero, IntPtr.Zero, 0);
}
finally
{
if (cfgPtr != IntPtr.Zero) Marshal.FreeHGlobal(cfgPtr);
}
}
internal static bool SetFingerprintParam(int userId, int channel, string cardNo, byte fingerId, byte[] fpData)
{
var cfg = new NET_DVR_FINGERPRINT_PARAM
{
dwSize = (uint)Marshal.SizeOf(typeof(NET_DVR_FINGERPRINT_PARAM)),
byCardNo = new byte[32],
byRes1 = new byte[2],
byFingerData = new byte[2048],
byRes2 = new byte[64],
byFingerPrintID = fingerId,
byEnableCardReader = 1,
dwFingerPrintLen = (uint)Math.Min(fpData?.Length ?? 0, 2048)
};
CopyAscii(cardNo, cfg.byCardNo);
if (fpData != null && fpData.Length > 0)
Buffer.BlockCopy(fpData, 0, cfg.byFingerData, 0, (int)cfg.dwFingerPrintLen);
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal((int)cfg.dwSize);
Marshal.StructureToPtr(cfg, ptr, false);
return NET_DVR_SetDeviceConfig(userId, NET_DVR_SET_FINGERPRINT_PARAM, channel, ptr, cfg.dwSize, IntPtr.Zero, IntPtr.Zero, 0);
}
finally
{
if (ptr != IntPtr.Zero) Marshal.FreeHGlobal(ptr);
}
}
internal static bool GetFingerprintParam(int userId, int channel, string cardNo, byte fingerId, out byte[] fpData)
{
fpData = Array.Empty<byte>();
var cfg = new NET_DVR_FINGERPRINT_PARAM
{
dwSize = (uint)Marshal.SizeOf(typeof(NET_DVR_FINGERPRINT_PARAM)),
byCardNo = new byte[32],
byRes1 = new byte[2],
byFingerData = new byte[2048],
byRes2 = new byte[64],
byFingerPrintID = fingerId,
byEnableCardReader = 1
};
CopyAscii(cardNo, cfg.byCardNo);
uint returned = 0;
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal((int)cfg.dwSize);
Marshal.StructureToPtr(cfg, ptr, false);
if (!NET_DVR_GetDeviceConfig(userId, NET_DVR_GET_FINGERPRINT_PARAM, channel, ptr, cfg.dwSize, ref returned, IntPtr.Zero, IntPtr.Zero, 0))
return false;
var outCfg = Marshal.PtrToStructure<NET_DVR_FINGERPRINT_PARAM>(ptr);
if (outCfg.dwFingerPrintLen == 0)
return true;
fpData = new byte[outCfg.dwFingerPrintLen];
Buffer.BlockCopy(outCfg.byFingerData, 0, fpData, 0, (int)outCfg.dwFingerPrintLen);
return true;
}
finally
{
if (ptr != IntPtr.Zero) Marshal.FreeHGlobal(ptr);
}
}
internal static bool DeleteFingerprintParam(int userId, int channel, string cardNo, byte fingerId)
{
var cfg = new NET_DVR_FINGERPRINT_PARAM
{
dwSize = (uint)Marshal.SizeOf(typeof(NET_DVR_FINGERPRINT_PARAM)),
byCardNo = new byte[32],
byRes1 = new byte[2],
byFingerData = new byte[2048],
byRes2 = new byte[64],
byFingerPrintID = fingerId,
byEnableCardReader = 1
};
CopyAscii(cardNo, cfg.byCardNo);
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal((int)cfg.dwSize);
Marshal.StructureToPtr(cfg, ptr, false);
return NET_DVR_SetDeviceConfig(userId, NET_DVR_DEL_FINGERPRINT_PARAM, channel, ptr, cfg.dwSize, IntPtr.Zero, IntPtr.Zero, 0);
}
finally
{
if (ptr != IntPtr.Zero) Marshal.FreeHGlobal(ptr);
}
}
private static void CopyAscii(string text, byte[] target)
{
if (target == null || target.Length == 0)
return;
if (string.IsNullOrWhiteSpace(text))
return;
var bytes = Encoding.ASCII.GetBytes(text.Trim());
var len = Math.Min(bytes.Length, target.Length);
Buffer.BlockCopy(bytes, 0, target, 0, len);
}
}