C# 封送 C++ 函数

C# marshaling C++ functions

我正在尝试使用海康威视SDK https://www.hikvision.com/en/support/download/sdk/ 我目前的目标是用对讲室外机开门(触发输出)

我成功登录(NET_DVR_LoginV40)并显示室外站的摄像头。

我的下一步是开门。为此,我需要调用 NET_DVR_RemoteControl 函数,传入 NET_DVR_Control_GateWay.

的结构。

现在这样做时它不起作用 returns 错误 17 显然是:

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.

所以我的 C# 代码中几乎 100% 有问题。但我不知道它是什么,据我所知,如果你不是这方面的专家(我不是),这是不可能轻易查明的

函数的dll导入:

[DllImport(@"..\bin\HCNetSDK.dll")]
public static extern bool NET_DVR_RemoteControl(int lUserID, uint dwCommand, IntPtr lpInBuffer, uint dwInBufferSize);

上一个函数的参数结构体:

 [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];
            }
        }

我的开门方法:

 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

据我所知,我已经正确地完成了定义和导入。

如果有人能为我指明正确的方向,我将不胜感激,因为我之前从未使用过 C#、C++ 互操作,此时我不知道如何前进,如何调试,如何确定我的代码中的问题。

我已尝试就此问题联系制造商,但他们无法直接帮助我的代码,从他们的角度来看,一切正常,因为我得到的错误是我造成的问题。

非常感谢您的帮助!

您使用 Marshal.AllocHGlobal 分配了一些内存,您没有将 gateWay 结构复制到该内存中,而是将指向已分配内存的指针传递给 NET_DVR_RemoteControl,以便它看到 random garbage,然后你不释放分配的内存,这样它就会泄漏。

您可以在通话后 copying gateWay into the allocated memory and then freeing 修复它。

然而,最好让编组器完成它的工作:

[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);