首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >来自C# C++:SetupDiGetDeviceInterfaceDetail的USB驱动程序

来自C# C++:SetupDiGetDeviceInterfaceDetail的USB驱动程序
EN

Stack Overflow用户
提问于 2015-06-22 13:26:45
回答 2查看 6.6K关注 0票数 4

我想从C#打电话给C#是有问题的。它总是返回1784错误代码(“提供的用户缓冲区对请求的操作无效”)。这是我的C#代码:

代码语言:javascript
运行
复制
Guid GUID_DEVINTERFACE_DFU = new Guid(0x3fe809ab, 0xfb91, 0x4cb5, 0xa6, 0x43, 0x69, 0x67, 0x0d, 0x52,0x36,0x6e);

        Guid classGuid = GUID_DEVINTERFACE_DFU;

        IntPtr hDevInfo = Win32.SetupDiGetClassDevs(ref classGuid, IntPtr.Zero, IntPtr.Zero, Win32.DIGCF_DEVICEINTERFACE | Win32.DIGCF_PRESENT);
        if (hDevInfo.ToInt32() == Win32.INVALID_HANDLE_VALUE)
        {
            Console.WriteLine("read hardware information error");
        }
        else
        {
            SP_DEVINFO_DATA devInfoData = new SP_DEVINFO_DATA();
            devInfoData.cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
            devInfoData.classGuid = Guid.Empty;
            devInfoData.devInst = 0;
            devInfoData.reserved = IntPtr.Zero;
            bool result = Win32.SetupDiEnumDeviceInfo(hDevInfo, i, devInfoData);
            if (false == result)
            {
                int error = Marshal.GetLastWin32Error();
                if (error != Win32.ERROR_NO_MORE_ITEMS)
                    throw new Win32Exception(error);
            }

            SP_DEVICE_INTERFACE_DATA ifData = new SP_DEVICE_INTERFACE_DATA();
            ifData.cbSize = (uint)Marshal.SizeOf(ifData);
            ifData.Flags = 0;
            ifData.InterfaceClassGuid = Guid.Empty;
            ifData.Reserved = IntPtr.Zero;

            bool result2 = Win32.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref classGuid, i, ifData);
            if(result2 == false)
            {
                int error = Marshal.GetLastWin32Error();
                if (error != Win32.ERROR_NO_MORE_ITEMS)
                    throw new Win32Exception(error);
            }

            uint needed;

            // This returns: needed=160, result3=false and error=122 ("The data area passed to a system call is too small")
            bool result3 = Win32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ifData, null, 0, out needed, null);
            if(result3 == false)
            {
                int error = Marshal.GetLastWin32Error();
            }

            IntPtr detailDataBuffer = IntPtr.Zero;
            SP_DEVICE_INTERFACE_DETAIL_DATA ifDetailsData = new SP_DEVICE_INTERFACE_DETAIL_DATA();
            ifDetailsData.devicePath = new byte[needed - 4];   
            ifDetailsData.cbSize = (uint)Marshal.SizeOf(ifDetailsData);

            uint nBytes = needed;

            // This returns always: error = 1784
            bool result4 = Win32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ifData, ifDetailsData, nBytes, out needed, null);
            if (result4 == false)
            {
                int error = Marshal.GetLastWin32Error();
                if (error != Win32.ERROR_NO_MORE_ITEMS)
                    throw new Win32Exception(error);
            }
        }

Classe Win32:

代码语言:javascript
运行
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace USB_test
{
[StructLayout(LayoutKind.Sequential)]
public class SP_DEVINFO_DATA
{
    public uint cbSize;
    public Guid classGuid;
    public uint devInst;
    public IntPtr reserved;
};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class SP_DEVICE_INTERFACE_DETAIL_DATA
{
    public uint cbSize;
    public byte[] devicePath;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public class SP_DEVICE_INTERFACE_DATA
{
    public uint cbSize;
    public Guid InterfaceClassGuid;
    public uint Flags;
    public IntPtr Reserved;
}

public class Win32
{
    public static uint ANYSIZE_ARRAY = 1000;

    [DllImport("setupapi.dll", SetLastError = true)]
    public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, uint Flags);   

    [DllImport("setupapi.dll", SetLastError = true)]
    public static extern Boolean SetupDiEnumDeviceInfo(IntPtr lpInfoSet, UInt32 dwIndex, SP_DEVINFO_DATA devInfoData);

    [DllImport(@"setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr hDevInfo, IntPtr devInfo, ref Guid interfaceClassGuid, uint memberIndex, SP_DEVICE_INTERFACE_DATA deviceInterfaceData);

    [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr hDevInfo, SP_DEVICE_INTERFACE_DATA deviceInterfaceData, SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData, uint deviceInterfaceDetailDataSize, out uint requiredSize, SP_DEVINFO_DATA deviceInfoData);

    public const int DIGCF_PRESENT = 0x02;
    public const int DIGCF_DEVICEINTERFACE = 0x10;
    public const int SPDRP_DEVICEDESC = (0x00000000);
    public const long ERROR_NO_MORE_ITEMS = 259L;
    }
}

如果它能帮助某人,这就是解决办法:

代码语言:javascript
运行
复制
IntPtr detailDataBuffer = Marshal.AllocHGlobal((int)needed);
Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8);
uint nBytes = needed;

bool result4 = Win32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ifData, detailDataBuffer, nBytes, out needed, null);
if (result4 == false)
{
    int error = Marshal.GetLastWin32Error();
    if (error != Win32.ERROR_NO_MORE_ITEMS)
        throw new Win32Exception(error);
}

IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt32() + 4);
String devicePathName = Marshal.PtrToStringAuto(pDevicePathName);

附加注意:如果在64位机器上运行,或者强制64位模式运行,指向pDevicePathName的指针的上面一行将引用64位指针,而不是32。

IntPtr pDevicePathName =新IntPtr(detailDataBuffer.ToInt64() + 8);

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-06-22 13:37:49

该结构是一个可变大小的结构,不能自动编组。你得自己动手。

您需要删除SP_DEVICE_INTERFACE_DETAIL_DATA类型。对你没用。将SetupDiGetDeviceInterfaceDetail的声明更改为:

代码语言:javascript
运行
复制
[DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean SetupDiGetDeviceInterfaceDetail(
    IntPtr hDevInfo, 
    SP_DEVICE_INTERFACE_DATA deviceInterfaceData, 
    IntPtr deviceInterfaceDetailData, 
    uint deviceInterfaceDetailDataSize, 
    out uint requiredSize, 
    SP_DEVINFO_DATA deviceInfoData
);

在对IntPtr.Zero的第一个调用中传递SetupDiGetDeviceInterfaceDetail。然后通过调用Marshal.AllocHGlobal来分配所需大小的缓冲区。然后将大小写入该缓冲区的前4个字节。然后再打电话给SetupDiGetDeviceInterfaceDetail

类似于这样的东西:

代码语言:javascript
运行
复制
bool result3 = Win32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ifData, IntPtr.Zero, 0, 
    out needed, null);
if(!result3)
{
    int error = Marshal.GetLastWin32Error();
}
// expect that result3 is false and that error is ERROR_INSUFFICIENT_BUFFER = 122, 
// and needed is the required size

IntPtr DeviceInterfaceDetailData = Marshal.AllocHGlobal((int)needed);
try
{
    uint size = needed;
    Marshal.WriteInt32(DeviceInterfaceDetailData, (int)size);
    bool result4 = Win32.SetupDiGetDeviceInterfaceDetail(hDevInfo, ifData, 
        DeviceInterfaceDetailData, size, out needed, null);
    if(!result4)
    {
        int error = Marshal.GetLastWin32Error();
    }
    // do whatever you need with DeviceInterfaceDetailData
}
finally
{
    Marshal.FreeHGlobal(DeviceInterfaceDetailData);
}
票数 6
EN

Stack Overflow用户

发布于 2022-11-02 08:42:11

对我来说,answer of David Hoffmann不起作用。但他激励了我这个解决方案:

代码语言:javascript
运行
复制
IntPtr buffer = Marshal.AllocHGlobal((int)requiredSize);
int cbSize = sizeof(DWORD) + 2 * sizeof(CHAR); // cbSize + empty DevicePath
Marshal.WriteInt32(buffer, cbSize);
deviceInterfaceInfoData.cbSize = (DWORD)Marshal.SizeOf(deviceInterfaceInfoData);

if (!SetupDiGetDeviceInterfaceDetail(
    deviceInfoSet,
    ref deviceInterfaceData,
    buffer,
    requiredSize,
    out requiredSize,
    ref deviceInterfaceInfoData))
    throw new Win32Exception(error);

int devicePathSize = (int)requiredSize - sizeof(DWORD); // cbSize
char[] devicePathChars = new char[devicePathSize / sizeof(char)];
int offset = sizeof(DWORD); // cbSize
Marshal.Copy(IntPtr.Add(buffer, offset), devicePathChars, 0, devicePathChars.Length);
string devicePath = new(devicePathChars, 0, devicePathChars.Length - 1); // Remove NULL terminator
Marshal.FreeHGlobal(buffer);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30981181

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档