275 lines
9.5 KiB
C#
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);
|
|
}
|
|
}
|