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

ARJunior

n3wb
Joined
Aug 24, 2015
Messages
11
Reaction score
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 :(
This API is used to add a network signal source on the client and the device will return the allocated deviceID. The different channel of one device is as different source and please input the transmission protocol type(byTransProtocol) and stream type(byTransMode).
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
 

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
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.
 

ARJunior

n3wb
Joined
Aug 24, 2015
Messages
11
Reaction score
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
 

ARJunior

n3wb
Joined
Aug 24, 2015
Messages
11
Reaction score
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 ?
 

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
2
Hello again ARJunior,

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 ?
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
 

ARJunior

n3wb
Joined
Aug 24, 2015
Messages
11
Reaction score
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.
 

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
2
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.
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.
 

ARJunior

n3wb
Joined
Aug 24, 2015
Messages
11
Reaction score
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.


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.
 

ARJunior

n3wb
Joined
Aug 24, 2015
Messages
11
Reaction score
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 ;)
 

petkoo

n3wb
Joined
Jan 3, 2019
Messages
5
Reaction score
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.
 

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
2
Hi petkoo and ARJunior,

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 ;)
Good job with solving your problem ARJunior.

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.
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.
 

petkoo

n3wb
Joined
Jan 3, 2019
Messages
5
Reaction score
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
 

petkoo

n3wb
Joined
Jan 3, 2019
Messages
5
Reaction score
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
 

petkoo

n3wb
Joined
Jan 3, 2019
Messages
5
Reaction score
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.
 

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
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.
 

petkoo

n3wb
Joined
Jan 3, 2019
Messages
5
Reaction score
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 ;)
 
Joined
Jan 18, 2019
Messages
5
Reaction score
0
Location
UK
Hi all.

I've inherited a Winforms app that functions as DVR client for Hikvision, the former developer used the HCNetSDK.cs file for pinvoke and structs definitions. I've noticed that some structs in this file will cause the CLR type loader to throw an exception when touse types are used. the problem is with structs with a union.
I've created a small console app to illustrate this issue.

I don't know how to fix those structs, probably need to change the MarsalAsAttribute.

Maybe there is a fixed version on this HCNetSDK.cs file out there...


Code:
namespace ClassLibrary1
{
    public class Class1
    {
        public const int MAX_DOMAIN_NAME = 64;
        public const int NAME_LEN = 32;
        public const int PASSWD_LEN = 16;

        [StructLayoutAttribute(LayoutKind.Sequential)]
        public struct NET_DVR_CHANNEL
        {
            [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = MAX_DOMAIN_NAME, ArraySubType = UnmanagedType.I1)]
            public byte[] byAddress;
            public ushort wDVRPort;
            [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType = UnmanagedType.I1)]
            public byte[] byRes1;
            [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NAME_LEN, ArraySubType = UnmanagedType.I1)]
            public byte[] sUserName;
            [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = PASSWD_LEN, ArraySubType = UnmanagedType.I1)]
            public byte[] sPassword;
            public uint dwChannel;
            [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 32, ArraySubType = UnmanagedType.I1)]
            public byte[] byRes2;
        }

        [StructLayout(LayoutKind.Explicit)]
        public struct NET_DVR_SLAVE_CHANNEL_UNION
        {
            [FieldOffsetAttribute(0)]
            [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 152, ArraySubType = UnmanagedType.I1)]
            public byte[] byRes;
            [FieldOffsetAttribute(0)]
            public uint dwLocalChannel;
            [FieldOffsetAttribute(0)]
            public NET_DVR_CHANNEL struRemoteChannel;
        }
    }
}

Code:
using static ClassLibrary1.Class1;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            NET_DVR_CHANNEL instance_NET_DVR_CHANNEL;
            NET_DVR_SLAVE_CHANNEL_UNION instance_NET_DVR_SLAVE_CHANNEL_UNION;
        }
    }
}
This code will cause the following exception:

An unhandled exception of type 'System.TypeLoadException' occurred in mscorlib.dll

Additional information: Could not load type 'NET_DVR_SLAVE_CHANNEL_UNION' from assembly 'ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field.
Any suggestion on how to fix this will be greatly appreciated.
 

curiousDev

Young grasshopper
Joined
Aug 16, 2017
Messages
38
Reaction score
2
Hey Adam Guttman.

I didnt check it on my own yet but from an exception which you posted I can suspect that [FieldOffsetAttribute(0)] for dwLocalChannel is wrongly calculated.
Since both of 'structures' (NET_DVR_CHANNEL and byRes[152]) have the same size it seems that dwLocalChannel causing this problem.
Please try to change it into:
[FieldOffsetAttribute(152)]
public uint dwLocalChannel;

I should be able to take a closer look into it tomorrow if it won't solve your problem.

Best regards
curiousDev
 
Joined
Jan 18, 2019
Messages
5
Reaction score
0
Location
UK
Please try to change it into:
[FieldOffsetAttribute(152)]
public uint dwLocalChannel;
Thanks for the replay, curiousDev.
I've applied your suggestion and the exception is gone.
However, In my understanding, this will result in the struct not being a union anymore, as the filed of dwLocalChannel will be stored in the memory after the fields byRes and struRemoteChannel.

From the Help file of Hikvision:

NET_DVR_SLAVE_CHANNEL_UNION
Affiliated Channel Parameters Union.

union{
BYTE byRes[152];
DWORD dwLocalChannel;
NET_DVR_CHANNEL struRemoteChannel;
}NET_DVR_SLAVE_CHANNEL_UNION, *LPNET_DVR_SLAVE_CHANNEL_UNION;
Members
byRes
The size of the union, 152 bytes
dwLocalChannel
Local channel, valid when channel type is the local channel.
struRemoteChannel
Remote channel, valid when channel type is the remote channel.

And from Demo app of Hikvision written in C++:

//Slave channel union
typedef union tagNET_DVR_SLAVE_CHANNEL_UNION
{
BYTE byRes[152]; //Reserved
DWORD dwLocalChannel; //Local channel
NET_DVR_CHANNEL struRemoteChannel; //Remote channel
}NET_DVR_SLAVE_CHANNEL_UNION, *LPNET_DVR_SLAVE_CHANNEL_UNION;
So, do you think that there is a solution that preserves the union of the struct but helps the C# CLR understand how to handle this struct?
 
Top