封送至本机代码时缓冲区大小不正确

发布于 2024-12-16 12:55:18 字数 3901 浏览 1 评论 0原文

我正在尝试对 SetupApi 进行一些调用。我特别遇到 SetupDiGetDeviceInterfaceDetail()

这是我对本机方法的定义:

class NativeMethods {
    [DllImport("SetupApi.dll", SetLastError = true)]
    [return : MarshalAs(UnmanagedType.Bool)]
    public static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr hDevs,
                    ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
                    ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData,
                    uint deviceInterfaceDetailDataSize,
                    ref uint requiredSize,
                    ref SP_DEVINFO_DATA deviceInfoData);
}

这是所涉及结构的本机与托管定义:

[StructLayout(LayoutKind.Sequential, Size = 0x10)]
public struct GUID
{                    
    public Int32 Data1;
    public Int16 Data2;
    public Int16 Data3;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public byte[] Data4;

    public GUID(Int32 d1, Int16 d2, Int16 d3, byte[] d4)
    {
        Data1 = d1;
        Data2 = d2;
        Data3 = d3;
        Data4 = new byte[8];
        Array.Copy(d4, Data4, d4.Length);
    }
}

typedef struct _SP_DEVINFO_DATA {
    DWORD cbSize;
    GUID  ClassGuid;
    DWORD DevInst;    // DEVINST handle
    ULONG_PTR Reserved;
} SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;

[StructLayout(LayoutKind.Sequential)]
struct SP_DEVINFO_DATA
{
    public uint cbSize;
    public GUID  ClassGuid;
    public uint DevInst;
    public UIntPtr Reserved;
}

typedef struct _SP_DEVICE_INTERFACE_DATA {
    DWORD cbSize;
    GUID  InterfaceClassGuid;
    DWORD Flags;
    ULONG_PTR Reserved;
} SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;

[StructLayout(LayoutKind.Sequential)]
struct SP_DEVICE_INTERFACE_DATA
{
    public uint cbSize;
    public GUID  InterfaceClassGuid;
    public uint Flags;
    public UIntPtr Reserved;
}

typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA_A {
    DWORD  cbSize;
    CHAR   DevicePath[ANYSIZE_ARRAY];
} SP_DEVICE_INTERFACE_DETAIL_DATA_A, *PSP_DEVICE_INTERFACE_DETAIL_DATA_A;

[StructLayout(LayoutKind.Sequential)]
struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
    public uint cbSize;
    public IntPtr devicePath;
}

对于最后一个结构,我读过一篇文章,其中说结构,定义为 SP_DEVICE_INTERFACE_DETAIL_DATA 具有可变长度数组,C# 结构应该使用一个 IntPtr。为此,我通过 Marshal.AllocHGlobal() 分配内存,如下所示。以下是我使用SetupDiGetDeviceInterfaceDetail()的方式:

uint requiredSize = 0; // is ignored in this usage
byte[] foo = new byte[1024];

SP_DEVINFO_DATA spDevInfoData = new SP_DEVINFO_DATA();
spDevInfoData.cbSize = (uint)Marshal.SizeOf(spDevInfoData);

SP_DEVICE_INTERFACE_DATA spDevInfData = new SP_DEVICE_INTERFACE_DATA();
spDevInfData.cbSize = (uint)Marshal.SizeOf(spDevInfData);

SP_DEVICE_INTERFACE_DETAIL_DATA spDevInfDetailData = new SP_DEVICE_INTERFACE_DETAIL_DATA();
spDevInfDetailData.cbSize = 5; // the size needs to be 5
spDevInfDetailData.devicePath = Marshal.AllocHGlobal(foo.Length); 

NativeMethods.SetupDiGetDeviceInterfaceDetail(devList,
                                              ref spDevInfData,
                                              ref spDevInfDetailData, 
                                              spDevInfDetailData.cbSize,
                                              ref requiredSize,
                                              ref spDevInfoData);

在使用SetupDiGetDeviceInterfaceDetail()之前,我使用SetupDiGetClassDevs()和SetupDiEnumDeviceInterfaces()。在这两种情况下,这些方法都有效。我从第一个函数中获得了设备列表,并使用枚举调用迭代该列表。

但是,当我调用SetupDiGetDeviceInterfaceDetail()时,该函数失败并且Win32 GetLastError()返回错误122,我发现该错误是:ERROR_INSUFFICIENT_BUFFER。我不明白为什么我的缓冲区大小不足。我基本上是在 C++“测试应用程序”中做我正在做的事情,因为我无法在 C# 中让它工作。在该应用程序中,我使用分配给 SP_DEVICE_INTERFACE_DETAIL_DATA 结构的 char[] 数组 1024 个成员。这就是我在 C# 中使用 1024 个成员的字节数组的原因。

非常感谢任何帮助或见解。

I'm trying to make some calls into the SetupApi. I'm specifically having problems with SetupDiGetDeviceInterfaceDetail().

Here's my definition for the native method:

class NativeMethods {
    [DllImport("SetupApi.dll", SetLastError = true)]
    [return : MarshalAs(UnmanagedType.Bool)]
    public static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr hDevs,
                    ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
                    ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData,
                    uint deviceInterfaceDetailDataSize,
                    ref uint requiredSize,
                    ref SP_DEVINFO_DATA deviceInfoData);
}

Here's the native vs. managed definitions for the structures involved:

[StructLayout(LayoutKind.Sequential, Size = 0x10)]
public struct GUID
{                    
    public Int32 Data1;
    public Int16 Data2;
    public Int16 Data3;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public byte[] Data4;

    public GUID(Int32 d1, Int16 d2, Int16 d3, byte[] d4)
    {
        Data1 = d1;
        Data2 = d2;
        Data3 = d3;
        Data4 = new byte[8];
        Array.Copy(d4, Data4, d4.Length);
    }
}

typedef struct _SP_DEVINFO_DATA {
    DWORD cbSize;
    GUID  ClassGuid;
    DWORD DevInst;    // DEVINST handle
    ULONG_PTR Reserved;
} SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;

[StructLayout(LayoutKind.Sequential)]
struct SP_DEVINFO_DATA
{
    public uint cbSize;
    public GUID  ClassGuid;
    public uint DevInst;
    public UIntPtr Reserved;
}

typedef struct _SP_DEVICE_INTERFACE_DATA {
    DWORD cbSize;
    GUID  InterfaceClassGuid;
    DWORD Flags;
    ULONG_PTR Reserved;
} SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;

[StructLayout(LayoutKind.Sequential)]
struct SP_DEVICE_INTERFACE_DATA
{
    public uint cbSize;
    public GUID  InterfaceClassGuid;
    public uint Flags;
    public UIntPtr Reserved;
}

typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA_A {
    DWORD  cbSize;
    CHAR   DevicePath[ANYSIZE_ARRAY];
} SP_DEVICE_INTERFACE_DETAIL_DATA_A, *PSP_DEVICE_INTERFACE_DETAIL_DATA_A;

[StructLayout(LayoutKind.Sequential)]
struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
    public uint cbSize;
    public IntPtr devicePath;
}

For that last structure, I read a previous post here that says structures, defined as SP_DEVICE_INTERFACE_DETAIL_DATA is with a variable length array, the C# structure should use an IntPtr. To that end, I'm allocating memory through Marshal.AllocHGlobal() as is demonstrated below. Here's how I'm using the SetupDiGetDeviceInterfaceDetail():

uint requiredSize = 0; // is ignored in this usage
byte[] foo = new byte[1024];

SP_DEVINFO_DATA spDevInfoData = new SP_DEVINFO_DATA();
spDevInfoData.cbSize = (uint)Marshal.SizeOf(spDevInfoData);

SP_DEVICE_INTERFACE_DATA spDevInfData = new SP_DEVICE_INTERFACE_DATA();
spDevInfData.cbSize = (uint)Marshal.SizeOf(spDevInfData);

SP_DEVICE_INTERFACE_DETAIL_DATA spDevInfDetailData = new SP_DEVICE_INTERFACE_DETAIL_DATA();
spDevInfDetailData.cbSize = 5; // the size needs to be 5
spDevInfDetailData.devicePath = Marshal.AllocHGlobal(foo.Length); 

NativeMethods.SetupDiGetDeviceInterfaceDetail(devList,
                                              ref spDevInfData,
                                              ref spDevInfDetailData, 
                                              spDevInfDetailData.cbSize,
                                              ref requiredSize,
                                              ref spDevInfoData);

I'm using SetupDiGetClassDevs() and SetupDiEnumDeviceInterfaces() prior to my usage of SetupDiGetDeviceInterfaceDetail(). In both of those instances, the methods work. I'm provided the list of devices from the first function, and am iterating over the list with the enum call.

However, when I call SetupDiGetDeviceInterfaceDetail(), the function fails and the Win32 GetLastError() returns an error of 122 which I found is: ERROR_INSUFFICIENT_BUFFER. I'm not seeing why my buffer is of insufficient size. I'm basically doing what I'm doing in the C++ "test app" because I couldn't get this working in C#. In that app, I'm using a char[] array 1024 members that is assigned to the SP_DEVICE_INTERFACE_DETAIL_DATA structure. That's why I'm using a byte array 1024 members in C#.

Any help or insights are greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

╰◇生如夏花灿烂 2024-12-23 12:55:18

是的,您没有正确使用该功能。 SP_DEVICE_INTERFACE_DETAIL_DATA是一个可变大小的结构,ANYSIZE_ARRAY没有意义。您必须调用该函数两次。在第一个调用中,为 DeviceInterfaceDetailData 传递 IntPtr.Zero,为 DeviceInterfaceDetailDataSize 传递 0。返回的RequiredSize 告诉您要为该结构分配多少内存。再次分配并调用,现在传递指针和大小。

Yes, you are not using the function correctly. SP_DEVICE_INTERFACE_DETAIL_DATA is a variable sized structure, ANYSIZE_ARRAY has no meaning. You have to call the function twice. In the first call pass IntPtr.Zero for DeviceInterfaceDetailData and 0 for DeviceInterfaceDetailDataSize. The returned RequiredSize tells you how much memory to allocate for the structure. Allocate and call again, now passing the pointer and the size.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文