By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,974 Members | 1,206 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,974 IT Pros & Developers. It's quick & easy.

C# 1 - PInvoke - Pinning structures via GCHandle

P: n/a
Hi all,

I want to understand more about how the pinvoke pinning process works.

I'm writing some code that calls DeviceIoControl.
DeviceIoControl provides a generic interface to device drivers.
Its signature is deliberately open-ended so that it can be highly generic.
Refer SDK for more.

I want to access the drive geommetry of an SD-Card via
IOCTL_DISK_GET_DRIVE_GEOMETRY.

I've tried three different methods for calling DeviceIoControl.
Two work, but the third doesn't. I want to know why?

The three methods are presented below,
And are delimited by "//////////////////"

Cheers Steve

//////////////////
//
// Passing an appropriately defined DISK_GEOMETRY structure by ref works..

ie.

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

....

DISK_GEOMETRY DiskGeometry = new DISK_GEOMETRY();

....

// This works

DeviceIoControl(
...,
ref DiskGeometry, // StructLayout sequential, packing = 1
(uint) Marshal.SizeOf(typeof(DISK_GEOMETRY), // 24 bytes
...);

//////////////////
//
// Pinning an allocated byte[] and passing via an IntPtr through lpOutBuffer
works
// yes i know you can just pass a byte array by ref

ie.

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

....

byte[] DiskGeometry = new byte[24];
GCHandle PinnedDiskGeometry = GCHandle.Alloc(DiskGeometry,
GCHandleType.Pinned);
IntPtr pDiskGeometry = PinnedDiskGeometry.AddrOfPinnedObject();

....

// This works

DeviceIoControl(
...,
pDiskGeometry,
(uint) DiskGeometry.Length,
...);

....

PinnedDiskGeometry.Free();

//////////////////
//
// Pinning an allocated DISK_GEOMETRY structure
// and passing via an IntPtr through lpOutBuffer DOES NOT WORK
//
// Why? Is it because structs are allocated on the stack?
//

ie.

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

....

DISK_GEOMETRY DiskGeometry = new DISK_GEOMETRY();
GCHandle PinnedDiskGeometry = GCHandle.Alloc(DiskGeometry,
GCHandleType.Pinned);
IntPtr pDiskGeometry = PinnedDiskGeometry.AddrOfPinnedObject();

....

DeviceIoControl(
...,
pDiskGeometry, // StructLayout sequential, packing = 1
(uint) Marshal.SizeOf(typeof(DISK_GEOMETRY), // 24 bytes
...);

// Call succeeds but DiskGeometry is not updated. WHY???

....

PinnedDiskGeometry.Free();

Cheers,

Steve

May 15 '06 #1
Share this Question
Share on Google+
2 Replies


P: n/a
> // Call succeeds but DiskGeometry is not updated. WHY???

If DISK_GEOMETRY is declared as a struct, you'll end up pinning a
boxed copy in the GCHandle.Alloc call. That copy will get modified,
not the original DiskGeometry instance.
Mattias

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
May 15 '06 #2

P: n/a
Ahhhh.. caught by value sematics again

Thanks,

Steve

"Mattias Sjögren" wrote:
// Call succeeds but DiskGeometry is not updated. WHY???


If DISK_GEOMETRY is declared as a struct, you'll end up pinning a
boxed copy in the GCHandle.Alloc call. That copy will get modified,
not the original DiskGeometry instance.
Mattias

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.

May 15 '06 #3

This discussion thread is closed

Replies have been disabled for this discussion.