0

I'm trying to catch VIP and PID from USB device:

    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();
                }
           }
        }
    }

But deviceName always returns a string with non sense characters. I have change CharSet in DEV_BROADCAST_DEVICEINTERFACE structure and declare dbcc.name as string but the result is the same.

I would like to avoid reading from registry, and among all I have read, I have seen that it is possible to cast a DEV_BROADCAST_HEADER to a DEV_BROADCAST_DEVICEINTERFACE only if dbch_devicetype==DBT_DEVTYP_DEVICEINTERFACE. In my case, dbch_devicetype is 2, not 5, and I am using some common USB Mass Storage devices. What am I doing wrong? Thanks in advance!

Community
  • 1
  • 1
AdSsa
  • 268
  • 1
  • 6
  • 21

1 Answers1

0

Maybe, there is a more elegant way to resolve this question, but at least, and after a long search, this seems to be working.

On one hand, I register the app in order to receive the correct info to cast it as DEV_BROADCAST_DEVICEINTERFACE structure (DEV_BROADCAST_HEADER.dbch_devicetype is 5 in this case). So, I am able to retrieve VID and PID info. On the other hand, I keep first Windows message WndProc receives to retrieve the volume that Windows assings when I connect USB devices (DEV_BROADCAST_HEADER.dbch_devicetype is 2). Then, I receive two messages.

In code:

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);
       }
    }
}

To register app in order to receive the correct info to cast it as DEV_BROADCAST_DEVICEINTERFACE structure, it is necessary to call to this last RegisterUsbDeviceNotification method from Form class with its window handler as argument.

    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);
    }
AdSsa
  • 268
  • 1
  • 6
  • 21