如果结构中的字符串比使用的 p/Invoked 签名长或短,会发生什么情况?
What happens if a string in a struct is longer or shorter than the p/Invoked signature used?
例如,我想在 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
例如,我想在 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