Creating C# application using Hikvision SDK for DS-7116HVI-SL

Discussion in 'Cameras, NVR / DVR's, hardware & more' started by Srinivas Cheruku, Aug 3, 2017.

Share This Page

  1. ARJunior

    ARJunior n3wb

    Joined:
    Aug 24, 2015
    Messages:
    11
    Likes Received:
    0
    Hello,

    I've take a look at SDK manual but things aren't clear for me.

    Using NET_DVR_GetDeviceConfig() function with NET_DVR_GET_SIGNAL_SOURCE_INFO command (1654) means we have to define some values in instance of struct NET_DVR_DEVICEID_INFO like for example sDeviceID.
    But according to SDK manual, this value is returned by NET_DVR_AddNetSignal function which I don't use, so I don't know exactly how to set parameters correctly :(
    I think I have to define lpInBuffer as below to use in NET_DVR_GetDeviceConfig() function :
    Code:
    NET_DVR_DEVICEID_INFO deviceIdInfo = new NET_DVR_DEVICEID_INFO();
    deviceIdInfo.dwSize = (uint)Marshal.SizeOf(deviceIdInfo);
    deviceIdInfo.sDeviceID =               // ??
    deviceIdInfo.dwChan = lChannel;
    deviceIdInfo.dwInputSignalIndex =  // ??
    
    IntPtr lpInBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(deviceIdInfo));
    Marshal.StructureToPtr(deviceIdInfo, lpInBuffer, false);
    uint dwInBufferSize = Convert.ToUInt32(deviceIdInfo.dwSize);          
    
    This is how I've defined structure of NET_DVR_DEVICEID_INFO :
    Code:
    public struct NET_DVR_DEVICEID_INFO
    {
        public uint dwSize;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32, ArraySubType = UnmanagedType.I1)]
        public int[] sDeviceID;
        public uint dwChan;
        public uint dwInputSignalIndex;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 60, ArraySubType = UnmanagedType.I1)]
        public byte[] byRes;
    }
    
    Any help would be appreciated.
    Best regards
     
  2. curiousDev

    curiousDev Young grasshopper

    Joined:
    Aug 16, 2017
    Messages:
    35
    Likes Received:
    2
    Hi,

    Unfortunatelly my device doesnt support this funtionality.
    Here is what I have done, maybe it will help you somehow.


    structures definitions:

    Code:
    
    public struct NET_DVR_CHAN_INFO
        {
            public uint dwSize;                   // Structure size
            public byte byValid;                  // Whether this channel is valid or not: 0- invalid, 1- valid
            public byte byUsed;                   // Whether this channel is used or not: 0- not used, 1- in use
            [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.I1)]
            public byte[] byRes1;                 // Reserved, please set to 0
            [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = SDKConst.NAME_LEN, ArraySubType = UnmanagedType.I1)]  //SDKConst.NAME_LEN = 32
            public byte[] sChanName;              // Channel name
            public NET_DVR_COLOR struVideoColor;  // Signal source video color
            public ushort wResolutionX;
            public ushort wResolutionY;
            //[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 44, ArraySubType = UnmanagedType.I1)]
            [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 40, ArraySubType = UnmanagedType.I1)]
            public byte[] byRes2;                 // Reserved, please set to 0
        }
        
        public struct NET_DVR_COLOR
        {
            public byte byBrightness;
            public byte byContrast;
            public byte bySaturation;
            public byte byHue;
        }
    
    public struct NET_DVR_DEVICEID_INFO
        {
            public uint dwSize;
            public uint dwDeviceIndex;
            public byte byWallNo;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 27, ArraySubType = UnmanagedType.I1)]
            public byte[] byRes1;
            public uint dwChan;
            public uint dwInputSignalIndex;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 60, ArraySubType = UnmanagedType.I1)]
            public byte[] byRes;
        }
    call:

    Code:
     Hik_LoginID = SDKMethods.NET_DVR_Login_V30(ip, port, user, password, ref struDeviceInfo);
                if (Hik_LoginID < 0)
                {
                    //result.AddError(string.Format("Login failed, error code: {0}\n", SDKMethods.NET_DVR_GetLastError()));
                    //result.IsSuccessful = false;
    
                    SDKMethods.NET_DVR_Cleanup();
                    return;
                }
                
                NET_DVR_DEVICEID_INFO deviceIdInfo = new NET_DVR_DEVICEID_INFO();
                deviceIdInfo.dwSize = (uint)Marshal.SizeOf(deviceIdInfo);
                deviceIdInfo.dwDeviceIndex = 0;
                deviceIdInfo.dwChan = channel;  //I put here 36
                deviceIdInfo.dwInputSignalIndex = 0;
    
                IntPtr lpInBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(deviceIdInfo));
                Marshal.StructureToPtr(deviceIdInfo, lpInBuffer, false);
                uint dwInBufferSize = Convert.ToUInt32(deviceIdInfo.dwSize);
    
                NET_DVR_CHAN_INFO deviceChannelInfo = new NET_DVR_CHAN_INFO();
                deviceChannelInfo.struVideoColor = new NET_DVR_COLOR();
    
                IntPtr lpOutBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(deviceChannelInfo));
                Marshal.StructureToPtr(deviceChannelInfo, lpOutBuffer, false);
                uint dwOutBufferSize = Convert.ToUInt32(deviceIdInfo.dwSize);
    
                uint statusList = 555;
                IntPtr lpStatusList = Marshal.AllocHGlobal(Marshal.SizeOf(statusList));
                Marshal.StructureToPtr(statusList, lpStatusList, false);
                
    
                if (!SDKMethods.NET_DVR_GetDeviceConfig(Hik_LoginID, 1654, 1, lpInBuffer, dwInBufferSize, lpStatusList, lpOutBuffer, dwOutBufferSize))
                {
                    string message = string.Format("GetChannelInfoStatus failed, error code: {0}", SDKMethods.NET_DVR_GetLastError());
                    Console.WriteLine(message);
                }
    If you will look closer my structure definitions has some diffrent fields it's because I took them from header file. Don't know why but it's diffrent than programming manual.
    Noticable diffrence is in NET_DVR_DEVICEID_INFO where you can find dwDeviceIndex, byWallNo, byRes1 instead of yours int[] sDeviceID.

    As return value of calling NET_DVR_GetDeviceConfig I am getting false and GetLastError giving me value -> 23 - Device does not support this function.

    I havent check NET_DVR_AddNetSignal since the above function doesnt work for me. First of all I wanted to test NET_DVR_GetDeviceConfig with some 'standard' values for dwDeviceIndex like 0 or 1.

    I am curious if you will get diffrent results than me.

    Best regards.
     
  3. ARJunior

    ARJunior n3wb

    Joined:
    Aug 24, 2015
    Messages:
    11
    Likes Received:
    0
    Hey Curious,

    Yes, I've seen different structure from SDK manual and header file too ( NET_DVR_CHAN_INFO and NET_DVR_DEVICEID_INFO are concerned about this) !
    Don't know which ones we have to use but the two give me the same result, error code 23 like you.
    I've tried several values for dwDeviceIndex with no luck until now :(

    Thank you for your time.
    Best Regards
     
  4. ARJunior

    ARJunior n3wb

    Joined:
    Aug 24, 2015
    Messages:
    11
    Likes Received:
    0
    Oh...found one error in your NET_DVR_CHAN_INFO structure.
    If you look at header file, byte byEnabled doesn't exist anymore.
    By the way, my goal to detect if channel is used or not is reminding me to use this byte ! Don't you ?
     
  5. curiousDev

    curiousDev Young grasshopper

    Joined:
    Aug 16, 2017
    Messages:
    35
    Likes Received:
    2
    Hello again ARJunior,

    I am not sure if that is error since it's c++.
    Dll header definition has BYTE byRes1[3] while the one in programming manual has
    BYTE byUsed and BYTE byRes1[2] those two together is kinda BYTE byRes1[3]. If we use this structure as a pointer in call then that array [3] can be splitted at those two fields. The size will be the same.
    I have no idea why in manual they put something else than it is in header file. For me two splitted fields seems to be more readable without guessing what means first byte of array [3].

    I was counting you will get any other result than me. In this case we cannot be sure if we did something wrong or if it is a matter of our devices (still i believe if we screw up something we should get error '17 - Parameter error...').

    Best regards.
    curious
     
  6. ARJunior

    ARJunior n3wb

    Joined:
    Aug 24, 2015
    Messages:
    11
    Likes Received:
    0
    Hello Curious,

    You're right...didn't pay attention that size of byRes1 is 3 in SDK manual. Thanks for your thoughts.

    Yes, t's hard to know for sure whether our code is wrong or not but I'm wondering in this case how Hikvision client (ivms4200) can get this type of information Independently of the model.
    Maybe they used another function ?! Will try to find informations in SDK manual...

    Please keep me informed if you get better results ! Thank you.

    Best Regards.
     
  7. curiousDev

    curiousDev Young grasshopper

    Joined:
    Aug 16, 2017
    Messages:
    35
    Likes Received:
    2
    Can you write me steps which I need follow to get this info by from ivms4200? I wasnt using this software before so I want to be sure I will find the same functionality which you would like to achive.
    Then I will be able to take a look when find some spare time.

    Best regards.
     
  8. ARJunior

    ARJunior n3wb

    Joined:
    Aug 24, 2015
    Messages:
    11
    Likes Received:
    0
    Hi Curious,

    Don't know exactly if this is the same function used by from iVMS4200 but when connecting to one device, list of channels is displayed and depending if channel is used or not, they use different icon.
    [​IMG]

    Otherwise, I've found another function in SDK whick could probably be used for this purpose but didn't succeeded to return needed informations (output buffer is always null)

    Dll import
    Code:
    [DllImport(@"\Hikvision\CppDlls\HCNetSDK.dll", EntryPoint = "NET_DVR_GetDVRConfig")]
    public static extern bool NET_DVR_GetDVRConfig(int lUserID, uint dwCommand, int lChannel, IntPtr lpOutBuffer, uint dwOutBufferSize, uint lpBytesReturned);
    

    Structure definition

    Code:
    public struct NET_DVR_DIGITAL_CHANNEL_STATE
    {
        public uint dwSize;
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = SDKConst.MAX_CHANNUM_V30, ArraySubType = UnmanagedType.I1)]
        public byte[] byDigitalAudioChanTalkState;
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = SDKConst.MAX_CHANNUM_V30, ArraySubType = UnmanagedType.I1)]
        public byte[] byDigitalChanState;
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = SDKConst.MAX_CHANNUM_V30 * 3, ArraySubType = UnmanagedType.I1)]
        public byte[] byDigitalAudioChanTalkStateEx;
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = SDKConst.MAX_CHANNUM_V30 * 3, ArraySubType = UnmanagedType.I1)]
        public byte[] byDigitalChanStateEx;
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 64, ArraySubType = UnmanagedType.I1)]
        public byte[] byRes;
    }
    

    Call

    Code:
    NET_DVR_DIGITAL_CHANNEL_STATE struDigitalChannelState = new NET_DVR_DIGITAL_CHANNEL_STATE();
    
    uint dwOutBufferSize = (uint)Marshal.SizeOf(struDigitalChannelState);
    struDigitalChannelState.dwSize = dwOutBufferSize;
    
    IntPtr lpOutBuffer = Marshal.AllocHGlobal((int)dwOutBufferSize);
    Marshal.StructureToPtr(struDigitalChannelState, lpOutBuffer, false);
    
    uint dwCommand = 6126; // NET_DVR_GET_DIGITAL_CHANNEL_STATE
    uint lpBytesReturned = dwOutBufferSize;
    
    if (!SDKMethods.NET_DVR_GetDVRConfig(Hik_LoginID, dwCommand, 0, lpOutBuffer, dwOutBufferSize, lpBytesReturned))
    {
        Console.WriteLine("GetDVRConfig failed, error code: {0}\n", SDKMethods.NET_DVR_GetLastError());
    }
    else
    {
        Console.WriteLine("OK");
        var byDigitalChanState = new byte[32];
        byDigitalChanState = struDigitalChannelState.byDigitalChanState;
    
        for (int i = 0; i < 32; i++)
        {
            if (byDigitalChanState[i] == 1)
            Console.WriteLine("Channel : {0}", i);
        }
    }
    Marshal.FreeHGlobal(lpOutBuffer);
    
    Could you please try/verify this code on your device ?

    Best Regards.
     
  9. ARJunior

    ARJunior n3wb

    Joined:
    Aug 24, 2015
    Messages:
    11
    Likes Received:
    0
    Oopps...my fault ! Forget to copy values from lpOutBuffer in struDigitalChannelState structure !
    We have to replace
    Code:
       var byDigitalChanState = new byte[32];
       byDigitalChanState = struDigitalChannelState.byDigitalChanState;
    
       for (int i = 0; i < 32; i++)
       {
           if (byDigitalChanState[i] == 1)
           Console.WriteLine("Channel : {0}", i);
       }
    
    by
    Code:
    struDigitalChannelState = (NET_DVR_DIGITAL_CHANNEL_STATE)Marshal.PtrToStructure(lpOutBuffer, typeof(NET_DVR_DIGITAL_CHANNEL_STATE));
    
    for (int i = 0; i < 32; i++)
    {
        if (struDigitalChannelState.byDigitalChanState[i] == 1)
        Console.WriteLine("Channel : {0}", i);
    }
    
    ALL IS WORKING NOW !!

    Thank you for your time ;)
     
  10. petkoo

    petkoo n3wb

    Joined:
    Jan 3, 2019
    Messages:
    5
    Likes Received:
    0
    Location:
    Slovakia
    Hello,

    I also have problem with method NET_DVR_StartRemoteConfig, it is returning error 17. For command NET_DVR_GET_ONLINE_LOCAL_CONTROLLER 2177 there is no struct passed, and it is working.
    But for NET_DVR_GET_LOCAL_CONTROLLER_STATUS 2176 I have to pass NET_DVR_LOCAL_CONTROLLER_STATUS_COND

    Code:
    //*****My implementations:
    [StructLayout(LayoutKind.Sequential)]
    public struct NET_DVR_LOCAL_CONTROLLER_STATUS_COND
    {
           public uint dwSize;
           public ushort wLocalControllerID;
           [MarshalAs(UnmanagedType.ByValArray, SizeConst = 306, ArraySubType = UnmanagedType.I1)]
           public byte[] byRes;
    }
    
     public delegate void STATECALLBACK(uint dwType, IntPtr lpBuffer, uint dwBufLen, IntPtr pUserData);
    
     [DllImport(@"HCNetSDK.dll")]
     public static extern Int32 NET_DVR_StartRemoteConfig(int lUserID, uint dwCommand, ref IntPtr lpInBuffer, uint dwInBufferLen, STATECALLBACK cbStateCallback, ref IntPtr pUserData);
    
    //*******Main code:
    MyCHCNetSDK.NET_DVR_LOCAL_CONTROLLER_STATUS_COND lpInBuffer = new MyCHCNetSDK.NET_DVR_LOCAL_CONTROLLER_STATUS_COND()
    {
            wLocalControllerID = 0
    };
    lpInBuffer.dwSize = (uint)Marshal.SizeOf(lpInBuffer);
    
    MyCHCNetSDK.STATECALLBACK callback = new MyCHCNetSDK.STATECALLBACK((dwType, lpBuffer, dwBufLen, pUserData) => { });
    
    IntPtr lpInBufferPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lpInBuffer));
    Marshal.StructureToPtr(lpInBuffer, lpInBufferPtr, false);
    
    IntPtr pUserData1 = IntPtr.Zero;
    
    int iResult = MyCHCNetSDK.NET_DVR_StartRemoteConfig(userId, MyCHCNetSDK.NET_DVR_GET_CARD_CFG, ref lpInBufferPtr, lpInBuffer.dwSize, callback, ref pUserData1);
    iResult = iResult;
    I tried Login_V30, also V40, 32bit, 64 bit, but still same result.
     
  11. curiousDev

    curiousDev Young grasshopper

    Joined:
    Aug 16, 2017
    Messages:
    35
    Likes Received:
    2
    Hi petkoo and ARJunior,

    Good job with solving your problem ARJunior.

    I tried to implement it on my own. Unfortunately, I am getting the same result in both cases, like for problem which ARJunior presented few posts ago, error 23 (Device does not support this function.). I am unable to check it fully to help you.
    Despite that I was suspecting one thing that can cause issue in your code. I have on mind
    [DllImport(@"HCNetSDK.dll")]
    public static extern Int32 NET_DVR_StartRemoteConfig(int lUserID, uint dwCommand, ref IntPtr lpInBuffer, uint dwInBufferLen, STATECALLBACK cbStateCallback, ref IntPtr pUserData);

    When I changed my version to version with refs in first case I got again error 23 but with 2nd case I ended up with error 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.)

    Conclusion is to remove those ref in your code and try again.
    I am looking forward for news from you.

    Best regards.
     
  12. petkoo

    petkoo n3wb

    Joined:
    Jan 3, 2019
    Messages:
    5
    Likes Received:
    0
    Location:
    Slovakia
    Hello curiousDev,

    I tried it yesterday as many other options and now again, but same result 17. If you get 23, than it is working. I am getting 23 in case I run C++ demo from Hikvision. Could you please send me test project? If not can I send you mine and you will try to run it?

    I know there is problem with my code, but it is strange...

    Peter
     
  13. curiousDev

    curiousDev Young grasshopper

    Joined:
    Aug 16, 2017
    Messages:
    35
    Likes Received:
    2
    No problem for me. Take a look on my test solution.
     

    Attached Files:

  14. petkoo

    petkoo n3wb

    Joined:
    Jan 3, 2019
    Messages:
    5
    Likes Received:
    0
    Location:
    Slovakia
    It is working, and now surprisingly also mine is working. Currently I had wrong command number, but it was just result of my multiple options which I tried. So ref should not be there definitelly, you are right.

    Thank you so much, I appreciate your help ;)

    Peter
     
  15. petkoo

    petkoo n3wb

    Joined:
    Jan 3, 2019
    Messages:
    5
    Likes Received:
    0
    Location:
    Slovakia
    Hello curiousDev,

    Maybe you will be able to help me one more time...

    There is another method NET_DVR_SendRemoteConfig and I should pass structure to char * type, so it should be string. Have you had experience with struct to string conversion?

    I implemented it like this:
    [DllImport(@"HCNetSDK.dll", CharSet = CharSet.Ansi)]
    public static extern bool NET_DVR_SendRemoteConfig(int lHandle, uint dwDataType, [MarshalAs(UnmanagedType.LPStr)] string pSendBuf, uint dwBufSize);

    IntPtr dataPtr = Marshal.AllocHGlobal(Marshal.SizeOf(data)); //Data is struct NET_DVR_CARD_CFG_V50
    Marshal.StructureToPtr(data, dataPtr, false);
    byte[] byteData = new byte[Marshal.SizeOf(data)];
    Marshal.Copy(dataPtr, byteData, 0, Marshal.SizeOf(data));
    string buffer = Encoding.Unicode.GetString(byteData);
    Marshal.FreeHGlobal(dataPtr);

    res = MyCHCNetSDK.NET_DVR_SendRemoteConfig(iResult, 0x03, buffer, (uint)buffer.Length);

    It returrns true, but with callback I received error 9.
     
  16. curiousDev

    curiousDev Young grasshopper

    Joined:
    Aug 16, 2017
    Messages:
    35
    Likes Received:
    2
    Hi petkoo,

    I believe you should use byte[] instead of string. Convert the string to byte array then to IntPtr and NET_DVR_SendRemoteConfig(int lHandle, uint dwDataType, IntPtr pSendBuf, uint dwBufSize);
    Sorry but in this moment i dont have time to test it out on my own.

    Best regards.
     
  17. petkoo

    petkoo n3wb

    Joined:
    Jan 3, 2019
    Messages:
    5
    Likes Received:
    0
    Location:
    Slovakia
    Hello,

    Both approaches are correct, but I like more your suggestion.

    The problem was that if you are adding new card you have to set dwModifyParamType, so specify what you would like to save. It is not enough to set for instance byName value.

    Thank you curiousDev ;)
     
Tags: