Case in point, I want to use DEV_BROADCAST_DEVICEINTERFACE_A from C#. However, I'm not sure how to declare the struct since the size of dbcc_name
is dependent on dbcc_size
(It's officially declared as char dbcc_name[1]
).
According to this question it seems like I need to add
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
over dbcc_name
.
But why use SizeConst=255
? We don't know the size. (And it seems from other answers I've seen, that there is no simple way to declare it such that it will know the correct size or a way to specify the size case by case.)
So what happens if I set a static length as in the linked answer. What would happen if the string is shorter or longer?
Testing has shown that if it's longer I get the correct string, and if shorter - I get a truncated string (e.g. if I set SizeConst to 2 and the real string is "abc", I get "ab".) But can I be sure that that's how it works, or is it dependent on something that just happens to be fine in this specific case?
You can't declare completely the structure, what you can do is something like this:
[StructLayout(LayoutKind.Sequential)]
private struct _DEV_BROADCAST_DEVICEINTERFACE_A
{
public int dbcc_size;
public uint dbcc_devicetype;
public uint dbcc_reserved;
public Guid dbcc_classguid;
public char dbcc_name; // just for offset; don't use!
}
And use it like this:
// get ptr to structure from somewhere (lParam from WM_DEVICECHANGE ...)
IntPtr ptr = ...
// read structure
var iface = Marshal.PtrToStructure<_DEV_BROADCAST_DEVICEINTERFACE_A>(ptr);
// get name pointer
var namePtr = ptr + Marshal.OffsetOf<_DEV_BROADCAST_DEVICEINTERFACE_A>(nameof(_DEV_BROADCAST_DEVICEINTERFACE_A.dbcc_name)).ToInt32();
// get name
var name = Marshal.PtrToStringAnsi(namePtr);
Note if the name can contain zeros, you should instead use Marshal.PtrToStringAnsi(namePtr, len)
with len = dbcc_size - offset of dbcc_name