problem marshalling structures

G

Guest

Hello,

I am having difficulty marshalling structures when calling DeviceIoControl.

I am importing this Win32 function as

[DllImport("kernel32.dll", SetLastError=true)]
static extern int DeviceIoControl (int hDevice,
int dwIoControlCode,
ref int[] lpInBuffer,
int nInBufferSize,
ref int lpOutBuffer,
int nOutBufferSize,
out int lpBytesReturned,
IntPtr lpOverlapped);

For most commands, the device I am communicating with expects an array of
6 integers as command data.
I try to invoke this like so
int Reply, int BytesReturned;
int[] CmdData = new int[6];
int nResult = DeviceIoControl(m_DriverHandle, ASTROPCI_COMMAND,
ref CmdData, Marshal.SizeOf(CmdData),
ref Reply, Marshal.SizeOf(Reply),
out BytesReturned, IntPtr.Zero);
Using this syntax, I get a runtime error when I perform this
DeviceIoControl invoke:

"Type System.Int32[] can not be marshaled as an unmanaged structure;
no meaningful size or offset can be computed." string

I am confused by why this is a marshalling problem. Since the size of
CmdData is easily obtainable, and
the error message clearly says the marshaller can't figure it out, I'm
assuming there's an issue here I
don't understand.

Question #1: How do I use C# to pass an array of 6 ints in this call?
Question #2: (Less important, but I'd like to understand, if someone has
a quick explanation)
Why is the marshaller unable to figure out the size?
 
M

Mattias Sjögren

[DllImport("kernel32.dll", SetLastError=true)]
static extern int DeviceIoControl (int hDevice,
int dwIoControlCode,
ref int[] lpInBuffer,
int nInBufferSize,
ref int lpOutBuffer,
int nOutBufferSize,
out int lpBytesReturned,
IntPtr lpOverlapped);

Yuo should probably remove the ref keyword on the lpInBuffer
parameter.

As for calculating the array size, just do

CmdData.Length * 4

or if you don't want to hardcode the size of an int

CmdData.Length * Marshal.SizeOf(typeof(int))



Mattias
 
G

Guest

Hi Mattias,
The presence or absence of ref does not have an effect.

There is a MarshalAs attribute that contains a SizeConst field, apparently
instructions to the marshaler as to how many bytes to copy. However, this
only applies to fields, not to arguments to a function. what I'm looking for
(I think) is a way to tell the marshaller, "Here's how many bytes this
pointer is pointing at." This will vary from call to call, as this is the
nature of DeviceIoControl.
Yes, I think I mentioned that obtaining the array size is simple. I was
wondering why the marshaller was unable to do so.

PC

Mattias Sjögren said:
[DllImport("kernel32.dll", SetLastError=true)]
static extern int DeviceIoControl (int hDevice,
int dwIoControlCode,
ref int[] lpInBuffer,
int nInBufferSize,
ref int lpOutBuffer,
int nOutBufferSize,
out int lpBytesReturned,
IntPtr lpOverlapped);

Yuo should probably remove the ref keyword on the lpInBuffer
parameter.

As for calculating the array size, just do

CmdData.Length * 4

or if you don't want to hardcode the size of an int

CmdData.Length * Marshal.SizeOf(typeof(int))



Mattias
 
M

Mattias Sjögren

The presence or absence of ref does not have an effect.

It should.

There is a MarshalAs attribute that contains a SizeConst field, apparently
instructions to the marshaler as to how many bytes to copy. However, this
only applies to fields, not to arguments to a function. what I'm looking for
(I think) is a way to tell the marshaller, "Here's how many bytes this
pointer is pointing at." This will vary from call to call, as this is the
nature of DeviceIoControl.

It's not needed, since the runtime already knows how much to copy. It
knows the size of each array element, and it knows the length of the
array.

Keep in mind that the nInBufferSize parameter is only information
needed by the callee, not the CLR marshaler.



Mattias
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top