I'm working on a C# project using DeviceIoControl
. I've consulted the related Pinvoke.net page for my signature:
[DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
public static extern bool DeviceIoControl(
SafeFileHandle hDevice,
EIOControlCode IoControlCode,
[MarshalAs(UnmanagedType.AsAny)]
[In] object InBuffer,
uint nInBufferSize,
[MarshalAs(UnmanagedType.AsAny)]
[Out] object OutBuffer,
uint nOutBufferSize,
out uint pBytesReturned,
[In] IntPtr Overlapped
);
I'd never seen object
and [MarshalAs(
UnmanagedType.AsAny
)]
before, but the MSDN documentation sounded promising:
A dynamic type that determines the type of an object at run time and marshals the object as that type. This member is valid for platform invoke methods only.
My question is: What is the "best" and/or "proper" way of using this signature?
For example, IOCTL_STORAGE_QUERY_PROPERTY
expects InBuffer
to be a STORAGE_PROPERTY_QUERY
structure. It seems like I should be able to define that struct, create a new
instance, and pass it to my Pinvoke signature:
var query = new STORAGE_PROPERTY_QUERY { PropertyId = 0, QueryType = 0 };
DeviceIoControl(..., query, Marshal.SizeOf(query), ...);
However, I just got a System.ExecutionEngineException
doing that, so I changed to something like:
int cb = Marshal.SizeOf(typeof(...));
IntPtr query = Marshal.AllocHGlobal(cb);
...
Marshal.PtrToStructure(...);
Marshal.FreeHGlobal(query);
and it at least didn't throw any exceptions when I called it. That is just very ugly, and a huge pain in the butt though. Can't the marshaller handle copying data to/from my local structs like I was hoping?
The output data can sometimes be tricky, because they aren't fixed-size structures. I understand the marshaller can't possibly handle that automatically, and I'm okay with doing the HGlobal and copy business where I need to.
Additional:
This question looked helpful at first, but it ended up just being an incorrect constant.
I'm not against using unsafe
constructs. (The fixed
-size struct
members require this.)