Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C Union in C# Error incorrectly aligned or overlapped by a non-object field

I'm working on a C# WPF application and trying to use an unmanaged dll (don't have access to source). The structure I need is 'NET_DVR_IPPARACFG_V40' which contains a bunch of other structs/unions. Here is the info the documentation gives us:

struct{
  DWORD                   dwSize;
  DWORD                   dwGroupNum;
  DWORD                   dwAChanNum;
  DWORD                   dwDChanNum;
  DWORD                   dwStartDChan;
  BYTE                    byAnalogChanEnable[MAX_CHANNUM_V30];
  NET_DVR_IPDEVINFO_V31   struIPDevInfo[MAX_IP_DEVICE_V40];
  NET_DVR_STREAM_MODE     struStreamMode[MAX_CHANNUM_V30];
  BYTE                    byRes2[20];
}NET_DVR_IPPARACFG_V40

struct{
  BYTE               byEnable;
  BYTE               byProType;
  BYTE               byEnableQuickAdd;
  BYTE               byRes1;
  BYTE               sUserName[NAME_LEN];
  BYTE               sPassword[PASSWD_LEN];
  BYTE               byDomain[MAX_DOMAIN_NAME];
  NET_DVR_IPADDR     struIP;
  WORD               wDVRPort;
  BYTE               byRes2[34];
}NET_DVR_IPDEVINFO_V31

struct{
  char    sIpV4[16];
  BYTE    sIpV6[128];
}NET_DVR_IPADDR

struct{
  BYTE                      byGetStreamType;
  BYTE                      byRes[3];
  NET_DVR_GET_STREAM_UNION  uGetStream;
}NET_DVR_STREAM_MODE

union{
  NET_DVR_IPCHANINFO          struChanInfo;
  NET_DVR_IPSERVER_STREAM     struIPServerStream;
  NET_DVR_PU_STREAM_CFG       struPUStream;
  NET_DVR_DDNS_STREAM_CFG     struDDNSStream;
  NET_DVR_PU_STREAM_URL       struStreamUrl;
  NET_DVR_HKDDNS_STREAM       struHkDDNSStream;
}NET_DVR_GET_STREAM_UNION

struct{
  BYTE     byEnable;
  BYTE     byIPID;
  BYTE     byChannel;
  BYTE     byIPIDHigh;
  BYTE     byRes[32];
}NET_DVR_IPCHANINFO

struct{
  BYTE               byEnable;
  BYTE               byRes[3];
  NET_DVR_IPADDR     struIPServer;
  WORD               wPort;
  WORD               wDvrNameLen;
  BYTE               byDVRName[NAME_LEN];
  WORD               wDVRSerialLen;
  WORD               byRes1[2];
  BYTE               byDVRSerialNumber[SERIALNO_LEN];
  BYTE               byUserName[NAME_LEN];
  BYTE               byPassWord[PASSWD_LEN];
  BYTE               byChannel;
  BYTE               byRes2[11];
}NET_DVR_IPSERVER_STREAM

struct{
  DWORD                             dwSize;
  NET_DVR_STREAM_MEDIA_SERVER_CFG   struStreamMediaSvrCfg;
  NET_DVR_DEV_CHAN_INFO             struDevChanInfo;
}NET_DVR_PU_STREAM_CFG

struct{
  NET_DVR_IPADDR   struIP;
  WORD             wDVRPort;
  BYTE             byChannel;
  BYTE             byTransProtocol;
  BYTE             byTransMode;
  BYTE             byFactoryType; 
  BYTE             byDeviceType;
  BYTE             byDispChan;
  BYTE             bySubDispChan; 
  BYTE             byRes[3];
  BYTE             byDomain[MAX_DOMAIN_NAME]; 
  BYTE             sUserName[NAME_LEN];
  BYTE             sPassword[PASSWD_LEN];
}NET_DVR_DEV_CHAN_INFO

struct{
  DWORD                             dwSize;
  NET_DVR_STREAM_MEDIA_SERVER_CFG   struStreamMediaSvrCfg;
  NET_DVR_DEV_CHAN_INFO             struDevChanInfo;
}NET_DVR_PU_STREAM_CFG

struct{
  BYTE             byValid;
  BYTE             byRes1[3];
  NET_DVR_IPADDR   struDevIP;
  WORD             wDevPort;
  BYTE             byTransmitType;
  BYTE             byRes2[69];
}NET_DVR_STREAM_MEDIA_SERVER_CFG

struct{
  BYTE               byEnable;
  BYTE               byRes1[3];
  NET_DVR_IPADDR     struStreamServer;
  WORD               wStreamServerPort;
  BYTE               byStreamServerTransmitType;
  BYTE               byRes2;
  NET_DVR_IPADDR     struIPServer;
  WORD               wIPServerPort;
  BYTE               byRes3[2];
  BYTE               sDVRName[NAME_LEN];
  WORD               wDVRNameLen;
  WORD               wDVRSerialLen;
  BYTE               sDVRSerialNumber[SERIALNO_LEN];
  BYTE               sUserName[NAME_LEN];
  BYTE               sPassWord[PASSWD_LEN];
  WORD               wDVRPort;
  BYTE               byRes4[2];
  BYTE               byChannel;
  BYTE               byTransProtocol;
  BYTE               byTransMode;
  BYTE               byFactoryType;
}NET_DVR_DDNS_STREAM_CFG

struct{
  BYTE    byEnable;
  BYTE    strURL[240];
  BYTE    byTransPortocol ;
  WORD    wIPID;
  BYTE    byChannel;
  BYTE    byRes[7];
}NET_DVR_PU_STREAM_URL

struct{
  BYTE    byEnable;
  BYTE    byRes[3];
  BYTE    byDDNSDomain[64];
  WORD    wPort;
  WORD    wAliasLen;
  BYTE    byAlias[NAME_LEN];
  WORD    wDVRSerialLen;
  BYTE    byRes1[2];
  BYTE    byDVRSerialNumber[SERIALNO_LEN];
  BYTE    byUserName[NAME_LEN];
  BYTE    byPassWord[PASSWD_LEN];
  BYTE    byChannel;
  BYTE    byRes2[11];
}NET_DVR_HKDDNS_STREAM

I've read tons of documentation online and still can't seem to get this 'NET_DVR_IPPARACFG_V40' Marshalled correctly. Here is what I have in C#:

/*[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_IPPARACFG_V40
{
    public uint dwSize;
    public uint dwGroupNum;
    public uint dwAChanNum;
    public uint dwDChanNum;
    public uint dwStartDChan;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = MAX_CHANNUM_V30, ArraySubType = UnmanagedType.I1)]
    public byte[] byAnalogChanEnable;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = MAX_IP_DEVICE_V40, ArraySubType = UnmanagedType.Struct)]
    public NET_DVR_IPDEVINFO_V31[] struIPDevInfo;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = MAX_CHANNUM_V30, ArraySubType = UnmanagedType.Struct)]
    public NET_DVR_STREAM_MODE[] struStreamMode;
    public byte[] byRes2;
}*/
[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public struct NET_DVR_IPPARACFG_V40
{
    public uint dwSize;
    public uint dwGroupNum;
    public uint dwAChanNum;
    public uint dwDChanNum;
    public uint dwStartDChan;
    unsafe public fixed byte byAnalogChanEnable[MAX_CHANNUM_V30];
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = MAX_IP_DEVICE_V40, ArraySubType = UnmanagedType.Struct)]
    public NET_DVR_IPDEVINFO_V31[] struIPDevInfo;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = MAX_CHANNUM_V30, ArraySubType = UnmanagedType.Struct)]
    public NET_DVR_STREAM_MODE[] struStreamMode;
    unsafe public fixed byte byRes2[20];
}

/*[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_IPDEVINFO_V31
{
    public byte byEnable;
    public byte byProType;
    public byte byEnableQuickAdd;
    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;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = MAX_DOMAIN_NAME, ArraySubType = UnmanagedType.I1)]
    public byte[] byDomain;
    public NET_DVR_IPADDR struIP;
    public ushort wDVRPort;
    public byte[] byRes;
}*/
[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public struct NET_DVR_IPDEVINFO_V31
{
    public byte byEnable;
    public byte byProType;
    public byte byEnableQuickAdd;
    public byte byRes1;
    unsafe public fixed byte sUserName[NAME_LEN];
    unsafe public fixed byte sPassword[PASSWD_LEN];
    unsafe public fixed byte byDomain[MAX_DOMAIN_NAME];
    public NET_DVR_IPADDR struIP;
    public ushort wDVRPort;
    unsafe public fixed byte byRes[34];
}

/*[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_STREAM_MODE
{
    public byte byGetStreamType;
    public byte[] byRes;
    public NET_DVR_GET_STREAM_UNION uGetStream;
}*/
[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public struct NET_DVR_STREAM_MODE
{
    public byte byGetStreamType;
    unsafe public fixed byte byRes[3];
    public NET_DVR_GET_STREAM_UNION uGetStream;
}

/*[StructLayout(LayoutKind.Explicit, Size = 528)]
public struct NET_DVR_GET_STREAM_UNION
{
    [FieldOffset(0)]
    public NET_DVR_IPCHANINFO struChanInfo;
    [FieldOffset(0)]
    public NET_DVR_IPSERVER_STREAM struIPServerStream;
    [FieldOffset(0)]
    public NET_DVR_PU_STREAM_CFG struPUStream;
    [FieldOffset(0)]
    public NET_DVR_DDNS_STREAM_CFG struDDNSStream;
    [FieldOffset(0)]
    public NET_DVR_PU_STREAM_URL struStreamUrl;
    [FieldOffset(0)]
    public NET_DVR_HKDDNS_STREAM struHkDDNSStream;
}*/
[StructLayout(LayoutKind.Explicit)]
public struct NET_DVR_GET_STREAM_UNION
{
    [FieldOffset(0)]
    public NET_DVR_IPCHANINFO struChanInfo;
    [FieldOffset(0)]
    public NET_DVR_IPSERVER_STREAM struIPServerStream;
    [FieldOffset(0)]
    public NET_DVR_PU_STREAM_CFG struPUStream;
    [FieldOffset(0)]
    public NET_DVR_DDNS_STREAM_CFG struDDNSStream;
    [FieldOffset(0)]
    public NET_DVR_PU_STREAM_URL struStreamUrl;
    [FieldOffset(0)]
    public NET_DVR_HKDDNS_STREAM struHkDDNSStream;
}

/*[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct NET_DVR_IPADDR
{

    /// char[16]
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 16)]
    public string sIpV4;

    /// BYTE[128]
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 128, ArraySubType = UnmanagedType.I1)]
    public byte[] byRes;

    public void Init()
    {
        byRes = new byte[128];
    }
}*/
[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public struct NET_DVR_IPADDR
{
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 16)]
    public string sIpV4;
    unsafe public fixed byte byRes[128];
}

/*[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_DEV_CHAN_INFO
{
    public NET_DVR_IPADDR struIP;
    public ushort wDVRPort;
    public byte byChannel;
    public byte byTransProtocol;
    public byte byTransMode;
    public byte byFactoryType;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 6, ArraySubType = UnmanagedType.I1)]
    public byte[] byRes;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = MAX_DOMAIN_NAME)]
    public string byDomain;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = NAME_LEN)]
    public string sUserName;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = PASSWD_LEN)]
    public string sPassword;
}*/
[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public struct NET_DVR_DEV_CHAN_INFO
{
    public NET_DVR_IPADDR struIP;
    public ushort wDVRPort;
    public byte byChannel;
    public byte byTransProtocol;
    public byte byTransMode;
    public byte byFactoryType;
    unsafe public fixed byte byRes[6];
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = MAX_DOMAIN_NAME)]
    public string byDomain;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = NAME_LEN)]
    public string sUserName;
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = PASSWD_LEN)]
    public string sPassword;
}

/*[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_STREAM_MEDIA_SERVER_CFG
{
    public byte byValid;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.I1)]
    public byte[] byRes1;
    public NET_DVR_IPADDR struDevIP;
    public ushort wDevPort;
    public byte byTransmitType;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 69, ArraySubType = UnmanagedType.I1)]
    public byte[] byRes2;
}*/
[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public struct NET_DVR_STREAM_MEDIA_SERVER_CFG
{
    public byte byValid;
    unsafe public fixed byte byRes1[3];
    public NET_DVR_IPADDR struDevIP;
    public ushort wDevPort;
    public byte byTransmitType;
    unsafe public fixed byte byRes2[69];
}



/*[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_IPCHANINFO
{
    public byte byEnable;
    public byte byIPID;
    public byte byChannel;
    public byte byProType;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 32, ArraySubType = UnmanagedType.I1)]
    public byte[] byRes;
    public void Init()
    {
        byRes = new byte[32];
    }
}*/
[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public struct NET_DVR_IPCHANINFO
{
    public byte byEnable;
    public byte byIPID;
    public byte byChannel;
    public byte byProType;
    unsafe public fixed byte byRes[32];
}

/*[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_IPSERVER_STREAM
{
    public byte byEnable;
    public byte[] byRes;
    public NET_DVR_IPADDR struIPServer;
    public ushort wPort;
    public ushort wDvrNameLen;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NAME_LEN, ArraySubType = UnmanagedType.I1)]
    public byte[] byDVRName;
    public ushort wDVRSerialLen;
    public ushort[] byRes1;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = SERIALNO_LEN, ArraySubType = UnmanagedType.I1)]
    public byte[] byDVRSerialNumber;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NAME_LEN, ArraySubType = UnmanagedType.I1)]
    public byte[] byUserName;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = PASSWD_LEN, ArraySubType = UnmanagedType.I1)]
    public byte[] byPassWord;
    public byte byChannel;
    public byte[] byRes2;
}*/
[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public struct NET_DVR_IPSERVER_STREAM
{
    public byte byEnable;
    unsafe public fixed byte byRes[3];
    public NET_DVR_IPADDR struIPServer;
    public ushort wPort;
    public ushort wDvrNameLen;
    unsafe public fixed byte byDVRName[NAME_LEN];
    public ushort wDVRSerialLen;
    unsafe public fixed ushort byRes1[2];
    unsafe public fixed byte byDVRSerialNumber[SERIALNO_LEN];
    unsafe public fixed byte byUserName[NAME_LEN];
    unsafe public fixed byte byPassWord[PASSWD_LEN];
    public byte byChannel;
    unsafe public fixed byte byRes2[11];
}

/*[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_PU_STREAM_CFG
{
    public uint dwSize;
    public NET_DVR_STREAM_MEDIA_SERVER_CFG struStreamMediaSvrCfg;
    public NET_DVR_DEV_CHAN_INFO struDevChanInfo;
}*/
[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public unsafe struct NET_DVR_PU_STREAM_CFG
{
    public uint dwSize;
    public NET_DVR_STREAM_MEDIA_SERVER_CFG struStreamMediaSvrCfg;
    public NET_DVR_DEV_CHAN_INFO struDevChanInfo;
}

/*[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_DDNS_STREAM_CFG
{
    public byte byEnable;
    public byte[] byRes1;
    public NET_DVR_IPADDR struStreamServer;
    public ushort wStreamServerPort;
    public byte byStreamServerTransmitType;
    public byte byRes2;
    public NET_DVR_IPADDR struIPServer;
    public byte wIPServerPort;
    public byte[] byRes3;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NAME_LEN, ArraySubType = UnmanagedType.I1)]
    public byte[] sDVRName;
    public ushort wDVRNameLen;
    public ushort wDVRSerialLen;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = SERIALNO_LEN, ArraySubType = UnmanagedType.I1)]
    public byte[] sDVRSerialNumber;
    [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 ushort wDVRPort;
    public byte[] byRes4;
    public byte byChannel;
    public byte byTransProtocol;
    public byte byTransMode;
    public byte byFactoryType;
}*/
[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public struct NET_DVR_DDNS_STREAM_CFG
{
    public byte byEnable;
    unsafe public fixed byte byRes1[3];
    public NET_DVR_IPADDR struStreamServer;
    public ushort wStreamServerPort;
    public byte byStreamServerTransmitType;
    public byte byRes2;
    public NET_DVR_IPADDR struIPServer;
    public byte wIPServerPort;
    unsafe public fixed byte byRes3[2];
    unsafe public fixed byte sDVRName[NAME_LEN];
    public ushort wDVRNameLen;
    public ushort wDVRSerialLen;
    unsafe public fixed byte sDVRSerialNumber[SERIALNO_LEN];
    unsafe public fixed byte sUserName[NAME_LEN];
    unsafe public fixed byte sPassWord[PASSWD_LEN];
    public ushort wDVRPort;
    unsafe public fixed byte byRes4[2];
    public byte byChannel;
    public byte byTransProtocol;
    public byte byTransMode;
    public byte byFactoryType;
}

/*[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_PU_STREAM_URL
{
    public byte byEnable;
    public byte[] strURL;
    public byte byTransPortocol;
    public ushort wIPID;
    public byte byChannel;
    public byte[] byRes;
}*/
[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public struct NET_DVR_PU_STREAM_URL
{
    public byte byEnable;
    unsafe public fixed byte strURL[240];
    public byte byTransPortocol;
    public ushort wIPID;
    public byte byChannel;
    unsafe public fixed byte byRes[7];
}

/*[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_HKDDNS_STREAM
{
    public byte byEnable;
    public byte[] byRes;
    public byte[] byDDNSDomain;
    public ushort wPort;
    public ushort wAliasLen;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NAME_LEN, ArraySubType = UnmanagedType.I1)]
    public byte[] byAlias;
    public ushort wDVRSerialLen;
    public byte[] byRes1;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = SERIALNO_LEN, ArraySubType = UnmanagedType.I1)]
    public byte[] byDVRSerialNumber;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NAME_LEN, ArraySubType = UnmanagedType.I1)]
    public byte[] byUserName;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = PASSWD_LEN, ArraySubType = UnmanagedType.I1)]
    public byte[] byPassWord;
    public byte byChannel;
    public byte[] byRes2;
}*/
[StructLayoutAttribute(LayoutKind.Sequential, Pack = 1)]
public struct NET_DVR_HKDDNS_STREAM
{
    public byte byEnable;
    unsafe public fixed byte byRes[3];
    unsafe public fixed byte byDDNSDomain[64];
    public ushort wPort;
    public ushort wAliasLen;
    unsafe public fixed byte byAlias[NAME_LEN];
    public ushort wDVRSerialLen;
    unsafe public fixed byte byRes1[2];
    unsafe public fixed byte byDVRSerialNumber[SERIALNO_LEN];
    unsafe public fixed byte byUserName[NAME_LEN];
    unsafe public fixed byte byPassWord[PASSWD_LEN];
    public byte byChannel;
    unsafe public fixed byte byRes2[11];
}

It compiles but when I make the call that uses this struct I get the error "Could not load type because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field." The structs in the union are all different sizes too, I'm not sure if that's an issue but figured its worth noting. The manufacturer actually gave me the C# structures above, but I don't think they really tested it since it isn't working. This is the first time I've had to deal with unions, so I'm not real sure how to handle it. The extent of my knowledge is from research within the past couple weeks.

If anyone could provide some insight, I'd greatly appreciate it.

like image 682
Brian Avatar asked Jun 07 '13 18:06

Brian


2 Answers

While marhalling we should pay attention to two things:

  1. Alignments (1, 2, 4 bytes)

  2. Sizes and offsets

    Whenever we run into values like BYTE, WORD, BYTE[69] that are not 4-Byte (32 bit) aligned we should put alignment explicitly:

[StructLayout(LayoutKind.Sequential, Pack = 1)] // <- Pack = 1, byte border alignment 

Whenever we have arrays such as BYTE[69] we should inform .Net about arrays' sizes, like that:

fixed byte byRes2[69]; // <- do not move (re-align) 69 bytes! And address them as array

Finally, we can check if we've done all right by means of sizeof() function. Let's, for instance, marshal one of the given structures

  struct{
    BYTE             byValid;
    BYTE             byRes1[3];
    NET_DVR_IPADDR   struDevIP;
    WORD             wDevPort;
    BYTE             byTransmitType;
    BYTE             byRes2[69];
  }NET_DVR_STREAM_MEDIA_SERVER_CFG

We can see, that it has non-trivial alignement (since structire contains single bytes, words, arrays that are not 4*Byte values) as well as arrays. So the C# wrap will be

  [StructLayout(LayoutKind.Sequential, Pack = 1)]
  public unsafe struct NET_DVR_STREAM_MEDIA_SERVER_CFG {
    byte       byValid;
    fixed byte byRes1[3];
    int        struDevIP; // <- I suggest IP v4 using here (Int32)
    UInt16     wDevPort;
    byte       byTransmitType;
    fixed byte byRes2[69];
  }

It's time to check: the initial structure size uses 1 + 3 + 4 + 2 + 1 + 69 = 80 bytes, actual size is

sizeof(NET_DVR_STREAM_MEDIA_SERVER_CFG) 

that returns 80.

like image 200
Dmitry Bychenko Avatar answered Oct 19 '22 23:10

Dmitry Bychenko


With the help of others, we have finally got the structures worked out. Here are the 2 structs dealing with the union:

[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_GET_STREAM_UNION
{
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 492, ArraySubType = UnmanagedType.I1)]
    public byte[] byUnion;
    public void Init()
    {
        byUnion = new byte[492];
    }
}

[StructLayoutAttribute(LayoutKind.Sequential)]
public struct NET_DVR_STREAM_MODE
{  
    public byte  byGetStreamType;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.I1)]
    public byte[]  byRes;
    public NET_DVR_GET_STREAM_UNION uGetStream;
    public void Init()
    {
        byGetStreamType = 0;
        byRes = new byte[3];
        uGetStream.Init();
    }
}

Basically, we just use a byte[] for the union for the anonymous data. Then when we do the call, we can use byGetStreamType in NET_DVR_STREAM_MODE as a switch to parse/cast the byte[] to the appropriate type.

Thanks for the input from everyone who helped.

like image 23
Brian Avatar answered Oct 20 '22 01:10

Brian