DeviceIO and Array of structs

This has been confusing me for over a day now, and straddles user mode (c#) and kernel mode code.

I am trying to return an array of structs from my driver using buffered IO.

I think I have the driver code written ok, but am having problems from the C# end.

Has anyone done this? Can you post some code?

> I think I have the driver code written ok, but am having problems from the C# end.

Use unmanaged code for this. Possibly in the form of yet another DLL, which exposes something C# style, and internally having these structures.

C# is too high a level to do such low-level operations. As was told by Tim on this very forum, even Python is more low level language then C#.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

Sure, but I have managed to send “a” struct across the divide, so it should be possible. The marshalling provided by C# may be slow, but to mitigate this I want to send more information in one go hence increasing from 1 struct to an array of 50 structs to keep the amount of chatter to a minimum.

Being really specific this is the current problem. The output buffer supplied to the driver is only 4 bytes. It needs to be 200 bytes.

An illustration of the C# code follows

uint inputBufferSize = 0;  
uint outputBufferSize = 200;  
IntPtr ptrInput;  
IntPtr ptrOutput;  
ptrOutput = Marshal.AllocHGlobal(200);  
retVal = DeviceIoControl(hDriver, ioctlCode, ptrInput, inputBufferSize, ptrOutput, outputBufferSize, ref bytesReturned, IntPtr.Zero);  

Yet a DbgPrint of the AssociatedIrp->SystemBuffer size yields only 4 bytes!

This is what is confusing the heck out of me. This worked like a charm when I was only retrieving one struct.

So the theory is this.

I need a buffer off 200 bytes (which will return an array of 50 ptrs - each ptr points to a struct in the array. Then I can walk the buffer pulling out my structs.

As I say I’m not asking for help with how to unpack the buffer, rather why or how is the driver only getting 4 bytes?

The definition of the api call has not changed.

I had this same problem. I had complicated kernel mode structures that I tried to define in C# and just ran into to many issues trying to get marshaling to work correctly. In the end I wrote a DLL in C++ and had my C# app use the DLL so that I could simplify the data exchange. It wasn’t pretty, but it worked. I remember going to a C# forum for help with defining my structure in C# and the advice I got was don’t do it… My app by the way was a c# application talking to a virtual miniport driver and acting like a disk in user mode… don’t try this at home…

My 2 cents worth…

Mark Cariddi
OSR Open Systems Resources, Inc.

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@yahoo.co.uk
Sent: Friday, September 03, 2010 8:44 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] DeviceIO and Array of structs

This has been confusing me for over a day now, and straddles user mode (c#) and kernel mode code.

I am trying to return an array of structs from my driver using buffered IO.

I think I have the driver code written ok, but am having problems from the C# end.

Has anyone done this? Can you post some code?


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer


don’t try this at home…

Nomination for best advice of the week :slight_smile:

Dave Cattley

I know. I understand what you are telling me.

What is driving me nuts is, if I have a simple struct, say 40 bytes, it works like a charm.
Forget the complex structs bit, I am going to handle that I’m sure. The question he is, why after I have allocated 200 bytes does the driver only get 4?

As you say your solution aint pretty, and I wouldn’t no where to start (writing the external hooks for c# I mean) and I just feel like there is something obvious here I am missing.

Random thought for the day (I haven’t read this read) - you’re passing
something like sizeof(pointer) v. sizeof(structure).

mm

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@yahoo.co.uk
Sent: Friday, September 03, 2010 9:31 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] DeviceIO and Array of structs

I know. I understand what you are telling me.

What is driving me nuts is, if I have a simple struct, say 40 bytes, it
works like a charm.
Forget the complex structs bit, I am going to handle that I’m sure. The
question he is, why after I have allocated 200 bytes does the driver only
get 4?

As you say your solution aint pretty, and I wouldn’t no where to start
(writing the external hooks for c# I mean) and I just feel like there is
something obvious here I am missing.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Nonsense.

This should be solvable – It’s all about getting the signature correct.

I think we need some more information:

  1. Please post the definition of the control code that you’re using (the CTL_CODE macro, please)

  2. Please post the C# signature [DllImport] that you’re using for DeviceIoControl

  3. Please post the contents of Parameters.DeviceIoControl.InputBufferLength and Paramters.DeviceIoControl.OutputBufferLength

Peter
OSR

Thanks Peter

>1) Please post the definition of the control code that you’re using (the
CTL_CODE macro, please)

internal static uint METHOD_BUFFERED = 0;  
internal static uint FILE_ANY_ACCESS = 0;   
internal static uint SIOCTL_TYPE = 40000;  
internal static uint IOCTL_REGISTER_EVENT = ((SIOCTL_TYPE) \<\< 16) | ((FILE_ANY_ACCESS) \<\< 14) | ((0x906) \<\< 2) | (METHOD_BUFFERED);  

>2) Please post the C# signature [DllImport] that you’re using for
DeviceIoControl

[DllImport("kernel32.dll", SetLastError = true)]  
 static extern bool DeviceIoControl(  
 Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,  
 uint dwIoControlCode,  
 IntPtr lpInBuffer,  
 uint nInBufferSize,  
 [Out] IntPtr lpOutBuffer,  
 uint nOutBufferSize,  
 ref uint lpBytesReturned,  
 IntPtr lpOverlapped);  

>3) Please post the contents of Parameters.DeviceIoControl.InputBufferLength and
Paramters.DeviceIoControl.OutputBufferLength

Parameters.DeviceIoControl.InputBufferLength is 0
Paramters.DeviceIoControl.OutputBufferLength is 200

As I say, the api call and CTL_CODE works like a charm with one structure. Very confusing.

OK, then… I’ve apparently lost the plot.

What exactly is the problem? You’re using METHOD_BUFFERED without any INPUT buffer, and the OUTPUT buffer size is being set to exactly what you asked (200).

Your driver should expect to receive a buffer in non-paged pool (the pointer will be at Irp->AssociatedIrp.SystemBuffer) that has random contents and which is at least 200 bytes long. That seems to be exactly what you’re getting.

???

Peter
OSR

If you have not discovered it, here is a link I have found helpful:

http://pinvoke.net/index.aspx

Gary G. Little
H (952) 223-1349
C (952) 454-4629
xxxxx@comcast.net

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@yahoo.co.uk
Sent: Friday, September 03, 2010 9:15 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] DeviceIO and Array of structs

Thanks Peter

>1) Please post the definition of the control code that you’re using
>(the
CTL_CODE macro, please)

internal static uint METHOD_BUFFERED = 0;  
internal static uint FILE_ANY_ACCESS = 0;   
internal static uint SIOCTL_TYPE = 40000; internal static uint  
IOCTL_REGISTER_EVENT = ((SIOCTL_TYPE) \<\< 16) | ((FILE_ANY_ACCESS) \<\< 14) |  
((0x906) \<\< 2) | (METHOD_BUFFERED); ```  
  
>\>2) Please post the C# signature [DllImport] that you're using for  
DeviceIoControl  
  

[DllImport(“kernel32.dll”, SetLastError = true)]
static extern bool DeviceIoControl(
Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
[Out] IntPtr lpOutBuffer,
uint nOutBufferSize,
ref uint lpBytesReturned,
IntPtr lpOverlapped);

  
>\>3) Please post the contents of  
Parameters.DeviceIoControl.InputBufferLength and   
Paramters.DeviceIoControl.OutputBufferLength  
  
Parameters.DeviceIoControl.InputBufferLength is 0  
Paramters.DeviceIoControl.OutputBufferLength is 200  
  
As I say, the api call and CTL_CODE works like a charm with one structure.  
Very confusing.   
  
---  
NTDEV is sponsored by OSR  
  
For our schedule of WDF, WDM, debugging and other seminars visit:   
http://www.osr.com/seminars  
  
To unsubscribe, visit the List Server section of OSR Online at  
http://www.osronline.com/page.cfm?name=ListServer

Nope. sizeof(Irp->AssociatedIrp.SystemBuffer) gives 4 bytes.

@Gary. Yes I have. This is where I got the api call from. It works like a charm for a single structure.

You are taking the sizeof a pointer what do you expect. You need to
access:

irpSp->Parameters.DeviceIoControl.OutputBufferLength

where irpSp is the stack pointer for the IRP for the size.

Don Burn (MVP, Windows DKD)
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

xxxxx@yahoo.co.uk” wrote in message
news:xxxxx@ntdev:

> Nope. sizeof(Irp->AssociatedIrp.SystemBuffer) gives 4 bytes.

That’s because you are taking the size of a pointer.

Gary G. Little
H (952) 223-1349
C (952) 454-4629
xxxxx@comcast.net

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@yahoo.co.uk
Sent: Friday, September 03, 2010 9:27 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] DeviceIO and Array of structs

Nope. sizeof(Irp->AssociatedIrp.SystemBuffer) gives 4 bytes.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

But 4 is what it is supposed to return. You get the length from the parameters field of the irp stack…

Mark Cariddi
OSR Open Systems Resources, Inc
Associate Fellha… (to keep up with MM… ;:slight_smile:

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@yahoo.co.uk
Sent: Friday, September 03, 2010 10:27 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] DeviceIO and Array of structs

Nope. sizeof(Irp->AssociatedIrp.SystemBuffer) gives 4 bytes.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Firstly, yes I do feel stupid.
Secondly, yes I do feel incredibly stupid.
Thirdly this is what happens when some code eats you up and you start at the screen until 3am then get up again 3 hours later, start at the screen all day long (with a screaming teething toddler in the background for good measure)

I will track back in the code versions and see how the heck it ever worked for one structure. Should be interesting.

Thanks

While this CAN be a helpful site, the contents vary widely in terms of the qualify of what’s posted. MUCH if it is not best practice, and some of it is just plain wrong.

I’m not saying never go to pinvoke.net – I’m merely saying use your judgement and verify whatever you find there.

Peter
OSR

Good advice Peter. Thanks.

And once again, sorry for missing the obvious and wasting your time.