举例来说,我想使用C#中的DEV_BROADCAST_DEVICEINTERFACE_A。但是,由于dbcc_name
的大小取决于dbcc_size
(正式声明为char dbcc_name[1]
),因此我不确定如何声明该结构。
根据this question,看来我需要添加
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
dbcc_name
之上。
但是为什么要使用SizeConst=255
?我们不知道大小。 (从我看到的其他答案中看来,there is no simple way to declare it such that it will know the correct size或一种视情况指定大小的方法。)
因此,如果我按照链接的答案设置静态长度,会发生什么情况。如果字符串较短或较长,会发生什么?
[测试表明,如果更长,我将得到正确的字符串,如果更短,我将得到截断的字符串(例如,如果我将SizeConst设置为2,而实际字符串是“ abc”,则我会得到“ ab”。)但是可以我确定这就是它的工作方式,还是取决于在这种特定情况下恰好可以解决的问题?
您无法完全声明结构,您可以执行以下操作:
[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!
}
并像这样使用它:
// 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);
注意,如果名称中可以包含零,则应将Marshal.PtrToStringAnsi(namePtr, len)
与len = dbcc_size - offset of dbcc_name
结合使用