473,396 Members | 2,011 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Marshalling Question: Array of Complex Structs?

Hi all,

I'm taking my first steps into C# <--C++ DLL Interop and
unfortunately I've run into (what seems to be) a very complicated case
as my first task. Perhaps someone here can help me.

I need to pass an array of RADIO_INFO2 structures to be filled by a
function in the DLL. This is how the structure is defined in the C++
example that comes with the DLL:

#pragma pack(1) // set byte packing
typedef struct {
unsigned __int32 bLength;
char szSerNum[9];
char szProdName[9];
unsigned __int64 MinFreq;
unsigned __int64 MaxFreq;
struct {
unsigned __int32 ExtRef:1;
unsigned __int32 FMWEnabled:1;
unsigned __int32 Reserved:30;
} Features;
} RADIO_INFO2;
#pragma pack() // set back the default packing

As you can see, there are a few obvious difficulties. First, the
nested Features struct. I think I've solved this by just defining
Features as a UInt32 and I'll handle the bit masking manually if I
need to. The second are the two char arrays. The DLL wants two 9
byte buffers to fill with character data while the marshalling code
wants to pass references. This brings me to the third problem, the
size of the structure. In C++ it's 42 bytes long: 32bits + 9bytes +
9bytes + 64bits + 64bits + 32bits = 42bytes. However, due to the
reference vs. value array problem the Marshalling code is coming up
with 32bytes: 32bits + 32bit (ref) + 32bit (ref) + 64bits + 64bits +
32bits = 32 bytes. The following is my best shot at describing this
structure in C#.

[StructLayout(LayoutKind.Sequential, Pack = 1,
CharSet = CharSet.Ansi)]
public struct RADIO_INFO2
{
public UInt32 bLength;
public Byte[] szSerNum;
public Byte[] szProdName;
public UInt64 MinFreq;
public UInt64 MaxFreq;
public UInt32 Features;
};

As stated above, this is the struct that gives me a
Marshalling.SizeOf() of 32 bytes. If, instead of the two Byte arrays,
I provide 18 individual Bytes, I get a matching size of 42 bytes, but
that seems like a heavy-handed work-around. Surely there's a Right
Way to do this.

Additionally, if instead of Byte arrays I define them as Char arrays,
I get an error from the Marshalling code complaining that the array
types don't match.

Just for reference, the actual call that consumes this struct looks
like:

[DllImport("WRG315API.DLL")]
public static extern UInt32 GetRadioList(ref RADIO_INFO2[]
lpRadioInfo,
UInt32 BufferSize,
ref UInt32 InfoSize);

Thanks in advance for any help that is offered.
Todd Pafford
ca******@gmail.com
Jan 14 '08 #1
2 3309
Todd,

You can just tell the marshalling layer to embed the string into the
struct by value:
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct RADIO_INFO2
{
public UInt32 bLength;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=9)]
public string szSerNum;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=9)]
public string szProdName;
public UInt64 MinFreq;
public UInt64 MaxFreq;
public UInt32 Features;
};

If you are using unsafe code, then you could use the fixed keyword as
well to fix the character array to a certain size, but what's above should
work just fine.

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com
<ca******@gmail.comwrote in message
news:27**********************************@j78g2000 hsd.googlegroups.com...
Hi all,

I'm taking my first steps into C# <--C++ DLL Interop and
unfortunately I've run into (what seems to be) a very complicated case
as my first task. Perhaps someone here can help me.

I need to pass an array of RADIO_INFO2 structures to be filled by a
function in the DLL. This is how the structure is defined in the C++
example that comes with the DLL:

#pragma pack(1) // set byte packing
typedef struct {
unsigned __int32 bLength;
char szSerNum[9];
char szProdName[9];
unsigned __int64 MinFreq;
unsigned __int64 MaxFreq;
struct {
unsigned __int32 ExtRef:1;
unsigned __int32 FMWEnabled:1;
unsigned __int32 Reserved:30;
} Features;
} RADIO_INFO2;
#pragma pack() // set back the default packing

As you can see, there are a few obvious difficulties. First, the
nested Features struct. I think I've solved this by just defining
Features as a UInt32 and I'll handle the bit masking manually if I
need to. The second are the two char arrays. The DLL wants two 9
byte buffers to fill with character data while the marshalling code
wants to pass references. This brings me to the third problem, the
size of the structure. In C++ it's 42 bytes long: 32bits + 9bytes +
9bytes + 64bits + 64bits + 32bits = 42bytes. However, due to the
reference vs. value array problem the Marshalling code is coming up
with 32bytes: 32bits + 32bit (ref) + 32bit (ref) + 64bits + 64bits +
32bits = 32 bytes. The following is my best shot at describing this
structure in C#.

[StructLayout(LayoutKind.Sequential, Pack = 1,
CharSet = CharSet.Ansi)]
public struct RADIO_INFO2
{
public UInt32 bLength;
public Byte[] szSerNum;
public Byte[] szProdName;
public UInt64 MinFreq;
public UInt64 MaxFreq;
public UInt32 Features;
};

As stated above, this is the struct that gives me a
Marshalling.SizeOf() of 32 bytes. If, instead of the two Byte arrays,
I provide 18 individual Bytes, I get a matching size of 42 bytes, but
that seems like a heavy-handed work-around. Surely there's a Right
Way to do this.

Additionally, if instead of Byte arrays I define them as Char arrays,
I get an error from the Marshalling code complaining that the array
types don't match.

Just for reference, the actual call that consumes this struct looks
like:

[DllImport("WRG315API.DLL")]
public static extern UInt32 GetRadioList(ref RADIO_INFO2[]
lpRadioInfo,
UInt32 BufferSize,
ref UInt32 InfoSize);

Thanks in advance for any help that is offered.
Todd Pafford
ca******@gmail.com

Jan 14 '08 #2
Thanks for the quick response, Nicholas. Indeed, the MarshalAs()
directive fixes the string sizing and typing issue. This is a great
help.

Oddly, when I pass an array of ten of these structs as refs to the
DLL, I get back an array of length 1 (I've only got one radio so this
is ok), but that one struct contains only the initialization values I
assigned all the elements in my original array. It's as if the array
was passed by reference and so could be modified, but each element of
the array cannot be modified. Does this make sense according to the
marshalling rules? Certainly, the problem could be in the DLL in
which case I can take it up with the manufacturers, but could this
behavior be a result of a problem with my definitions?

Thanks,
Todd
On Jan 14, 2:06 pm, "Nicholas Paldino [.NET/C# MVP]"
<m...@spam.guard.caspershouse.comwrote:
Todd,

You can just tell the marshalling layer to embed the string into the
struct by value:

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct RADIO_INFO2
{
public UInt32 bLength;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=9)]
public string szSerNum;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=9)]
public string szProdName;
public UInt64 MinFreq;
public UInt64 MaxFreq;
public UInt32 Features;

};

If you are using unsafe code, then you could use the fixed keyword as
well to fix the character array to a certain size, but what's above should
work just fine.

--
- Nicholas Paldino [.NET/C# MVP]
- m...@spam.guard.caspershouse.com

<calen...@gmail.comwrote in message

news:27**********************************@j78g2000 hsd.googlegroups.com...
Hi all,
I'm taking my first steps into C# <--C++ DLL Interop and
unfortunately I've run into (what seems to be) a very complicated case
as my first task. Perhaps someone here can help me.
I need to pass an array of RADIO_INFO2 structures to be filled by a
function in the DLL. This is how the structure is defined in the C++
example that comes with the DLL:
#pragma pack(1) // set byte packing
typedef struct {
unsigned __int32 bLength;
char szSerNum[9];
char szProdName[9];
unsigned __int64 MinFreq;
unsigned __int64 MaxFreq;
struct {
unsigned __int32 ExtRef:1;
unsigned __int32 FMWEnabled:1;
unsigned __int32 Reserved:30;
} Features;
} RADIO_INFO2;
#pragma pack() // set back the default packing
As you can see, there are a few obvious difficulties. First, the
nested Features struct. I think I've solved this by just defining
Features as a UInt32 and I'll handle the bit masking manually if I
need to. The second are the two char arrays. The DLL wants two 9
byte buffers to fill with character data while the marshalling code
wants to pass references. This brings me to the third problem, the
size of the structure. In C++ it's 42 bytes long: 32bits + 9bytes +
9bytes + 64bits + 64bits + 32bits = 42bytes. However, due to the
reference vs. value array problem the Marshalling code is coming up
with 32bytes: 32bits + 32bit (ref) + 32bit (ref) + 64bits + 64bits +
32bits = 32 bytes. The following is my best shot at describing this
structure in C#.
[StructLayout(LayoutKind.Sequential, Pack = 1,
CharSet = CharSet.Ansi)]
public struct RADIO_INFO2
{
public UInt32 bLength;
public Byte[] szSerNum;
public Byte[] szProdName;
public UInt64 MinFreq;
public UInt64 MaxFreq;
public UInt32 Features;
};
As stated above, this is the struct that gives me a
Marshalling.SizeOf() of 32 bytes. If, instead of the two Byte arrays,
I provide 18 individual Bytes, I get a matching size of 42 bytes, but
that seems like a heavy-handed work-around. Surely there's a Right
Way to do this.
Additionally, if instead of Byte arrays I define them as Char arrays,
I get an error from the Marshalling code complaining that the array
types don't match.
Just for reference, the actual call that consumes this struct looks
like:
[DllImport("WRG315API.DLL")]
public static extern UInt32 GetRadioList(ref RADIO_INFO2[]
lpRadioInfo,
UInt32 BufferSize,
ref UInt32 InfoSize);
Thanks in advance for any help that is offered.
Todd Pafford
calen...@gmail.com
Jan 14 '08 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: PHil Coveney | last post by:
Hello, I am having difficulty marshalling structures when calling DeviceIoControl. I am importing this Win32 function as static extern int DeviceIoControl (int hDevice, int...
10
by: Kieran Simkin | last post by:
Hi, I wonder if anyone can help me, I've been headscratching for a few hours over this. Basically, I've defined a struct called cache_object: struct cache_object { char hostname; char ipaddr;...
4
by: Animesh | last post by:
Hi All, I don't know whethher this is possible or not. This is the result of a bad design problem. Here I go; I have a structure like this: typedef struct _s_index_entry { char *doc_id;...
5
by: Paminu | last post by:
Why make an array of pointers to structs, when it is possible to just make an array of structs? I have this struct: struct test { int a; int b;
7
by: Kevin | last post by:
Hi al I have an interesting question.... I am working witha Win API this is the Function Public Declare Function EnumJobs Lib "winspool.drv" Alias "EnumJobsA" (ByVal hPrinter As Long, ByVal...
5
by: Zach | last post by:
When it is being said that, "value types are created on the stack or inline as part of an object". If a value type is created in an object, and that object is being called, the value type in that...
0
by: chijazz | last post by:
I have the following unmanaged code: typedef struct sicCrdPgInfo { short bProg; short wAA1Limit; short bFree; short wPad3; BYTE ucPCB; } tsicCrdPgInfo;
2
by: MyAlias | last post by:
Private Structure WCRANGE Dim wcLow As Short Dim cGlyphs As Short End Structure Private Structure GLYPHSET Dim cbThis As Integer Dim flAccel As Integer Dim cGlyphsSupported As Integer Dim...
7
by: heddy | last post by:
I have an array of objects. When I use Array.Resize<T>(ref Object,int Newsize); and the newsize is smaller then what the array was previously, are the resources allocated to the objects that are...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.