I am trying to use the Hikvision SDK https://www.hikvision.com/en/support/download/sdk/ My current goal is to open the door (trigger an output) with the intercom outdoor station.
I managed to do the login (NET_DVR_LoginV40) and display the outdoor station's camera feed.
My next step would be to open the door. For this I need to call the NET_DVR_RemoteControl function passing in among others the struct of NET_DVR_Control_GateWay.
Now when doing this it does not work it returns error 17 which is apparently:
Parameter error. Input or output parameters in the SDK API is NULL, or the value or format of the parameters does not match with the requirement.
So it is practically 100% that something is iffy in my C# code. But I have no idea what it is and as far as I know this is quite impossible to pinpoint easily if you are not an expert at this (I am not)
The dll import for the function:
[DllImport(@"..\bin\HCNetSDK.dll")]
public static extern bool NET_DVR_RemoteControl(int lUserID, uint dwCommand, IntPtr lpInBuffer, uint dwInBufferSize);
The struct for the parameter of the previous function:
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_Control_GateWay
{
public uint dwSize;
public uint dwGatewayIndex;
public byte byCommand;
public byte byLockType;
public UInt16 wLockID;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 32, ArraySubType = UnmanagedType.I1)]
public byte[] byControlSrc;
public byte byControlType;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.I1)]
public byte[] byRes3;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 16, ArraySubType = UnmanagedType.I1)]
public byte[] byPassword;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 108, ArraySubType = UnmanagedType.I1)]
public byte[] byRes2;
public void Init()
{
byRes3 = new byte[64];
byRes2 = new byte[108];
}
}
My method for the door opening:
private void button_Door1_Click(object sender, EventArgs e)
{
CHCNetSDK.NET_DVR_Control_GateWay gateWay = new CHCNetSDK.NET_DVR_Control_GateWay();
gateWay.Init();
gateWay.dwSize = (uint)Marshal.SizeOf(gateWay);
gateWay.dwGatewayIndex = 1;
gateWay.byCommand =1; //opening command
gateWay.byLockType = 0 ; //this is a normal lock not a smart lock
gateWay.wLockID = 0; //this is 0 because I want to use the door station's output
gateWay.byControlSrc = new byte[] {123} ; // this needs to be something, but doesn't matter what
gateWay.byControlType = 1 ; //this needs to be 1 or 2 but does not matter which
//gateWay.byPassword = ; this is not needed because the LockType is 0
IntPtr ptrStruData = Marshal.AllocHGlobal((int)gateWay.dwSize);
var dd = CHCNetSDK.NET_DVR_RemoteControl(lUserID, 16009, ptrStruData, gateWay.dwSize);
MessageBox.Show(dd.ToString() + CHCNetSDK.NET_DVR_GetLastError().ToString() + "\n" + gateWay.dwSize.ToString() + "\n" + "ptrStruData:" + ptrStruData.ToString());
}
According to the documentation the function looks like this
And the struct is defined as such
So according to my knowledge I have done the definition and import correctly.
I would appreciate if someone could set me in the right direction as I have never worked with C#, c++ interoperation before and at this point I have no idea how to go forward, how could I debug, how could I determine the problem in my code.
I have tried contacting the manufacturer about this issue, but they cannot help directly with my code, and from their perspective everything is working as it should as I get back the error that it is me who is the cause for the issue.
Your help is much appreciated!
You allocate some memory with Marshal.AllocHGlobal
, you do not copy your gateWay
structure into that memory, you pass the pointer to the allocated memory to NET_DVR_RemoteControl
so that it sees random garbage, and then you do not free the allocated memory so that it leaks.
You could have fixed it by copying gateWay
into the allocated memory and then freeing it after the call.
Instead, however, it is better to let the marshaller do its job:
[DllImport(HIKVISION_LIBRARY, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = false)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool NET_DVR_RemoteControl(int lUserID, int dwCommand, [In] ref NET_DVR_CONTROL_GATEWAY lpInBuffer, int dwInBufferSize);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct NET_DVR_CONTROL_GATEWAY
{
public int dwSize;
public int dwGatewayIndex;
public byte byCommand;
public byte byLockType;
public short wLockID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAME_LEN)]
public string byControlSrc;
public byte byControlType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] byRes3;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = PASSWD_LEN)]
public string byPassword;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 108)]
public byte[] byRes2;
}
var gateWay = new NET_DVR_CONTROL_GATEWAY()
{
dwSize = Marshal.SizeOf<NET_DVR_CONTROL_GATEWAY>(),
dwGatewayIndex = 1,
byCommand = 1,
byLockType = 0,
wLockID = 0,
byControlType = 1
};
var dd = NET_DVR_RemoteControl(lUserID, 16009, ref gateWay, gateWay.dwSize);