C# 如何使用dbcc_名称从DEV_BROADCAST_DEVICEINTERFACE检索可读的USB VID/PID

C# 如何使用dbcc_名称从DEV_BROADCAST_DEVICEINTERFACE检索可读的USB VID/PID,c#,visual-studio,usb,C#,Visual Studio,Usb,我正在尝试从USB设备捕获VIP和PID: public const int WM_DEVICECHANGE = 0x219; public const int DBT_DEVTYP_VOLUME = 0x00000002; public const int DBT_DEVICEARRIVAL = 0x8000; [StructLayout(LayoutKind.Sequential)] internal class DEV_BROADCAST_HDR

我正在尝试从USB设备捕获VIP和PID:

    public const int WM_DEVICECHANGE = 0x219;
    public const int DBT_DEVTYP_VOLUME = 0x00000002;
    public const int DBT_DEVICEARRIVAL = 0x8000;

    [StructLayout(LayoutKind.Sequential)]
    internal class DEV_BROADCAST_HDR
    {
        public int dbch_size;
        public int dbch_devicetype;
        public int dbch_reserved;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct DEV_BROADCAST_DEVICEINTERFACE
    {
        public int dbcc_size;
        public int dbcc_devicetype;
        public int dbcc_reserved;
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 16)]
        public byte[] dbcc_classguid;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
        public char[] dbcc_name;
    }

    public void WndProc(ref Message m)
    {
        if (m.Msg == WM_DEVICECHANGE) //Device state has changed
        {
           switch (m.WParam.ToInt32())
           {
               case DBT_DEVICEARRIVAL: //New device arrives
               DEV_BROADCAST_HDR hdr;
               hdr = (DEV_BROADCAST_HDR)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_HDR));
               if (hdr.dbch_devicetype == DBT_DEVTYP_VOLUME) //If it is a USB Mass Storage or Hard Drive
               {
                    //Save Device name
                    DEV_BROADCAST_DEVICEINTERFACE deviceInterface;
                    string deviceName = "";
                    deviceInterface = (DEV_BROADCAST_DEVICEINTERFACE)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_DEVICEINTERFACE));
                    deviceName = new string(deviceInterface.dbcc_name).Trim();
                }
           }
        }
    }
但是
deviceName
总是返回一个带有非意义字符的字符串。我在
DEV\u BROADCAST\u DEVICEINTERFACE
结构中更改了
CharSet
,并将
dbcc.name
声明为字符串,但结果相同


我希望避免从注册表中读取,并且在我读到的所有内容中,只有在
dbch\u设备类型==DBT\u DEVTYP\u设备接口
的情况下,才有可能将
DEV\u BROADCAST\u头
投射到
DEV\u BROADCAST\u设备接口
。在我的例子中,dbch_设备类型是2,而不是5,我正在使用一些常见的USB大容量存储设备。我做错了什么?提前谢谢

也许有一种更优雅的方法来解决这个问题,但至少,经过长时间的搜索,这似乎是可行的

一方面,我注册应用程序以接收正确的信息,将其转换为
DEV\u BROADCAST\u DEVICEINTERFACE
结构(本例中
DEV\u BROADCAST\u HEADER.dbch\u devicetype
为5)。因此,我能够检索视频和PID信息。另一方面,我保留了WndProc收到的第一条Windows消息,以检索连接USB设备时Windows分配的卷(
DEV\u BROADCAST\u HEADER.dbch\u devicetype
为2)。然后,我收到两条信息

代码:

public const int WM_DEVICECHANGE = 0x219;
public const int DBT_DEVTYP_VOLUME = 0x00000002;
public const int DBT_DEVICEARRIVAL = 0x8000;
public const int DBT_DEVTYP_DEVICEINTERFACE = 0x00000005;

private IntPtr notificationHandle;

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr RegisterDeviceNotification(IntPtr recipient, IntPtr notificationFilter, int flags);

[StructLayout(LayoutKind.Sequential)]
internal class DEV_BROADCAST_HDR
{
    public int dbch_size;
    public int dbch_devicetype;
    public int dbch_reserved;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DEV_BROADCAST_DEVICEINTERFACE
{
    public int dbcc_size;
    public int dbcc_devicetype;
    public int dbcc_reserved;
    public Guid dbcc_classguid;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
    public char[] dbcc_name;
}

public void WndProc(ref Message m)
{
    if (m.Msg == WM_DEVICECHANGE) //Device state has changed
    {
       switch (m.WParam.ToInt32())
       {
           case DBT_DEVICEARRIVAL: //New device arrives
           DEV_BROADCAST_HDR hdr;
           hdr = (DEV_BROADCAST_HDR)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_HDR));
                        if (hdr.dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) //If it is a USB Mass Storage or Hard Drive
                        {
                            //Save Device name
                            DEV_BROADCAST_DEVICEINTERFACE deviceInterface = (DEV_BROADCAST_DEVICEINTERFACE)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_DEVICEINTERFACE));
                            deviceName = new string(deviceInterface.dbcc_name);
                            deviceNameFiltered = deviceName.Substring(0, deviceName.IndexOf('{'));
                            vid = GetVid(deviceName);
                            pid = GetPid(deviceName);
                        }
                        if (hdr.dbch_devicetype == DBT_DEVTYP_VOLUME)
                        { 
                            DEV_BROADCAST_VOLUME volume;
                            volume = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(m.LParam, typeof(DEV_BROADCAST_VOLUME));
                            //Translate mask to device letter
                            driveLetter = DriveMaskToLetter(volume.dbcv_unitmask);
       }
    }
}
要注册应用程序以接收正确的信息,将其转换为
DEV_BROADCAST\u DEVICEINTERFACE
结构,必须从窗体类中调用最后一个
registerusbdevisionification
方法,并将其窗口处理程序作为参数

    public void RegisterUsbDeviceNotification(IntPtr windowHandle)
    {
        DEV_BROADCAST_DEVICEINTERFACE deviceInterface = new DEV_BROADCAST_DEVICEINTERFACE
        {
            dbcc_classguid = GuidDevinterfaceUSBDevice,
            dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE,
            dbcc_reserved = 0,
        };

        deviceInterface.dbcc_size = Marshal.SizeOf(deviceInterface);
        IntPtr buffer = Marshal.AllocHGlobal(deviceInterface.dbcc_size);
        Marshal.StructureToPtr(deviceInterface, buffer, true);

        notificationHandle = RegisterDeviceNotification(windowHandle, buffer, 0);
    }