I'm trying to write good P/Invoke signatures for some Windows setupapi calls, and I've encountered the following problem with the packing of setupapi's structures:
// Excerpt from setupapi.h
#if defined(_WIN64)
#include <pshpack8.h> // Assume 8-byte (64-bit) packing throughout
#else
#include <pshpack1.h> // Assume byte packing throughout (32-bit processor)
#endif
Now, what that means is that I can't just set the StructLayoutAttribute.Pack property to a constant value.
I tried doing the following:
[StructLayout(LayoutKind.Sequential, Pack = Environment.Is64BitProcess ? 8 : 1)]
public struct SP_DEVINFO_DATA
{
public uint cbSize;
public Guid ClassGuid;
public uint DevInst;
public IntPtr Reserved;
}
As expected, this fails with the following compilation error:
An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
I'd really like to avoid #if and setting up different compilation platforms, as opposed to Any CPU. Can I determine the packing of a C# structure at run-time?
No, packing is a compile-time concept, because it determines (among other things) the overall size of the type. That can't change at run-time.
In this case, if you're not willing to have separate builds for x86 and x64, you'll have to do the marshalling yourself. Thanks for @Hans Passant for a clean way to achieve this:
SP_DEVINFO_DATA32 and SP_DEVINFO_DATA64, It would look something like this:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SP_DEVINFO_DATA32 { /* stuff */ }
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct SP_DEVINFO_DATA64 { /* stuff */ }
[DllImport("setupapi.dll")]
public static extern void Function(ref SP_DEVINFO_DATA32 data);
[DllImport("setupapi.dll")]
public static extern void Function(ref SP_DEVINFO_DATA64 data);
public void DoStuff()
{
if (Environment.Is64BitProcess)
{
var data = new SP_DEVINFO_DATA64
{
cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA64))
};
Function(ref data);
}
else
{
var data = new SP_DEVINFO_DATA32
{
cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA32))
};
Function(ref data);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With