如果结构中的字符串长于或短于所使用的p / Invoked签名会发生什么?

问题描述 投票:1回答:1

举例来说,我想使用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”。)但是可以我确定这就是它的工作方式,还是取决于在这种特定情况下恰好可以解决的问题?

c# c++ c .net pinvoke
1个回答
0
投票

您无法完全声明结构,您可以执行以下操作:

[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结合使用

© www.soinside.com 2019 - 2024. All rights reserved.