• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3203
  • Last Modified:

USB non HID device name

I need to know a device and driver name of a connected USB-storage stick/card. For HID class devices I can use TJvHIDController (JEDI) but for non-HID devices I haven't found no help. I use WM_DEVICECHANGE message for DBT_DeviceArrival/DBT_DeviceRemoveComplete to get a driver letter but I need the name...
0
JacekH
Asked:
JacekH
  • 4
  • 3
  • 2
  • +1
2 Solutions
 
MeldrachaunCommented:
It looks like the TJclSCManager (JEDI) component may be what you need.
0
 
JacekHAuthor Commented:
Well, it looks that JclSCManager controls windows services and has no info about DBT devices.... If I'm wrong please give a short example how can I use it to read a USB device name.
0
 
bernaniCommented:
Hi,

Maybe sth like this (found on a french group)

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type

 PDEV_BROADCAST_HDR = ^TDEV_BROADCAST_HDR;
 TDEV_BROADCAST_HDR = packed record
   dbch_size : DWORD;
   dbch_devicetype : DWORD;
   dbch_reserved : DWORD;
  end;

  PDEV_BROADCAST_VOLUME = ^TDEV_BROADCAST_VOLUME;
  TDEV_BROADCAST_VOLUME = packed record
   dbcv_size : DWORD;
   dbcv_devicetype : DWORD;
   dbcv_reserved : DWORD;
   dbcv_unitmask : DWORD;
   dbcv_flags : WORD;
  end;

type
  TForm1 = class(TForm)
   Memo1: TMemo;

  private
    { Déclarations privées }
  procedure WMDeviceChange(var Msg: TMessage);     message WM_DEVICECHANGE;
  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;
  GetDriveLetter : string;
implementation

{$R *.dfm}

// Capture Event Wind WMDeviceChange
procedure TForm1.WMDeviceChange(var Msg: TMessage);
var
    VolName, FileSysName : Array[0..Max_Path]Of Char;
    VolSerial, FileMaxLen, FileFlags : DWord;
    S : string;
begin

// Check ifi DBT_DEVICEARRIVAL = $8000
// If yes, only to handle storage divices of type 0=DeviceTypeOEM

  if Msg.wParam =$8000 then begin
          if PDEV_BROADCAST_HDR( Msg.LParam )^.dbch_devicetype <>2 then exit;
          if PDEV_BROADCAST_VOLUME( Msg.LParam )^.dbcv_flags <>0 then exit;

 S := 'Device connected' +#13+#10+#13+#10;
// Letter Device
 str(ln(PDEV_BROADCAST_VOLUME( Msg.LParam )^.dbcv_unitmask)/ln(2)+Ord('A'):2:0,GetDriveLetter);
 S := S + 'DeviceID :'+#9+#9+ char(strtoint(GetDriveLetter)) + ':\' + #13+#10;
// VolumeName + FileSystem + Device Serial Number
 If GetVolumeInformation(pchar(char(strtoint(GetDriveLetter))+':\'),VolName,Max_Path,@VolSerial, FileMaxLen, FileFlags,FileSysName,Max_Path) then
S := S +
       'Volume Name :' +#9+#9+ VolName +#13+#10
       'Filesystem :' +#9+ FileSysName +#13+#10
       'Serial Number :' +#9+#9+ IntToStr(VolSerial)+#13+#10;
// Size and free device space
 S := S +
'Total Sie :' +#9+#9+ FloatToStrF(DiskSize(strtoint(GetDriveLetter)-64)div 1024, ffNumber, 18, 0) + ' Ko' + #13+#10;
S :=
S + 'Available :' +#9+#9+ FloatToStrF(DiskFree(strtoint(GetDriveLetter)-64) div 1024, ffNumber, 18, 0) + ' Ko';

Memo1.text:=S;
Beep;             // When connecting
end;

// Check if DBT_DEVICEREMOVECOMPLETE = $8004
// Yes, handle only device of type 0=DeviceTypeOEM

  if Msg.wParam =$8004 then begin
          if PDEV_BROADCAST_HDR( Msg.LParam )^.dbch_devicetype <>2 then exit;
          if PDEV_BROADCAST_VOLUME( Msg.LParam )^.dbcv_flags <>0 then exit;

// Disconnect
S := 'Device disconnected.' +#13+#10+#13+#10;
// Letter device "DeviceID"
str(ln(PDEV_BROADCAST_VOLUME( Msg.LParam )^.dbcv_unitmask)/ln(2)+Ord('A'):2:0,GetDriveLetter);
 S := S + 'DeviceID :' +#9+#9+ char(strtoint(GetDriveLetter)) + ':\' + #13+#10;
 Memo1.text:=S;
 Beep; // Disconnected
end;

end;

end.

// Could be improved but it's functionnal and the report in the memo looks sth like this:


Device connected

DeviceID :            I:\
VolumeName :Maxtor-III  -----> to get a driver letter but I need the name...
FileSystem : NTFS
Serial Number :      2430142829
Total Size       : 26.973.134 Ko
Available        : 5.290.909 Ko

Hope this help.
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
bernaniCommented:
Hi

Forgot to say:

To use, compile the code above (it's only a form with a TMemo) and launch you app. When this one is open, connect and disconnect a USB device to see the messages displayed in the memo.

0
 
JacekHAuthor Commented:
Bernani,

That's not a solution. I can get a volume name. But I need a DEVICE name, not volume. When you connect a memory stick you can see a device name (as a New hardware found notification in a system tray) and that's what I need. I need a device name for __non_HID__ devices. HID devices are covered by JvHIDController component from JEDI project.

Jacek
0
 
robert_marquardtCommented:
This is problematic because i am not sure if this is stored in the registry.
The name comes either from the device itself or from the INF file of the driver and is probably only accessed by the New Hardware Wizard on first plug.

Getting the string from the INF file is possible with the Setup API (the conversion is part of TJvHIDController), but i never used the functions.
Getting the string from the device is hard because the only way is the USBVIEW way which is an example of the Windows DDK.
I have an example available. Get the modules scapi and win32api from http://jedi-apilib.sf.net
In scapi there is the example USBVIEW which should help you along.

Unfortunately it may not possible to completel solve your problem because the functions of the Setup API and the Config Manager API are badly designed and buggy.
Even New Hardware Wizards of the different Windows versions do not show the same string from the device.
0
 
JacekHAuthor Commented:
Robert,
It looks that's very close to what I need. With SafeRemoval demo I get GUIDs I can use to read from registry CurrentControlSet - USBSTOR. I'll check tonight. Thank you, I'll let you know.

Jacek
0
 
bernaniCommented:
Hi,

Sorry, I misunderstood your question

The values of the string returned by the HardwareID key in the Registry under

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USBSTOR\Disk&Ven_Maxtor&Prod_6Y160P0&Rev_YAR4\10000E0009572FC4&0

USBSTOR\DiskMaxtor__6Y160P0_________YAR4
USBSTOR\DiskMaxtor__6Y160P0_________
USBSTOR\DiskMaxtor__
USBSTOR\Maxtor__6Y160P0_________Y
Maxtor__6Y160P0_________Y
USBSTOR\GenDisk
GenDisk

or the value returned by FriendlyName wich gives in the example Maxtor 6Y160P0 USB Device      

are HID Class device name. OK.

What are the values returned in the subkeys of  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\PerHwIdStorage ? HID class device related too ?

Thanks



0
 
robert_marquardtCommented:
I doubt it. It seems at least partly prefilled. I have Iomega entries there and i never connected an Iomega device to my computer.
It is bus related. All entries under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum are called bus (even if they are virtual like USBSTOR).
I have no HID entries there.
0
 
JacekHAuthor Commented:
Solved. I splitted points:

1. robert - thanks for your link for API lib and USB View. It gave me the main idea.
2. bernani - thanks for "FriendlyName" key name. I forgot about it.

For now I can read a device name. It's a mixed solution. From API Lib (robert info) I can read USB buses and GUIDs to build a tree like a "Safely remove device" (Windows Tray). This is an idea - I haven't coded it yet. Now I use reading registry to get a device name - just a simple procedure (pasted belowe) without BUS name. Using WMDeviceChange message I read a drive letter (PDevBroadcastVolume). A drive letter is used in my function to get a Device name. Now it's for USB drives only. Thanks to all.

Jacek

Here's my solution:

function ReadFriendlyName(const  ADriveLetter: Char): String;
var
  Reg: TRegistry;
  MountedDevices, USBKeys, USBSubKeys: TStrings;
  Index, HashPos: Integer;
  BuffSize: Integer;
  BinValue: String;
  ParentID: String;
  i, j: Integer;
begin
  Result := '';
  Reg := TRegistry.Create;
  try // 0
    Reg.RootKey := HKEY_LOCAL_MACHINE;
    // Read mounted devices IDs
    if Reg.OpenKeyReadOnly('SYSTEM\MountedDevices') then
    begin // 1
      MountedDevices := TStringList.Create;
      try // 2
        Reg.GetValueNames(MountedDevices);
        Index := MountedDevices.IndexOf('\DosDevices\' + ADriveLetter + ':');
        if Index >= 0 then
        begin //3
          BuffSize := Reg.GetDataSize(MountedDevices.Strings[Index]);
          SetLength(BinValue, BuffSize);
          Reg.ReadBinaryData(MountedDevices.Strings[Index], BinValue[1], BuffSize);
          ParentID := '';
          for i := 1 to Length(BinValue) do
            if BinValue[i] <> #0 then
              ParentID := ParentID + BinValue[i];
          HashPos := Pos('#', ParentID);
          ParentID := Copy(ParentID, HashPos + 1, Length(ParentID) - HashPos);
          HashPos := Pos('#', ParentID);
          ParentID := Copy(ParentID, HashPos + 1, Length(ParentID) - HashPos);
          HashPos := Pos('RM#', ParentID);
          ParentID := Copy(ParentID, 1, HashPos - 2); // final Parent ID Prefix
          Reg.CloseKey;
          // Read USBSTOR Device Keys
          if Reg.OpenKeyReadOnly('SYSTEM\CurrentControlSet\Enum\USBSTOR') then
          begin // 4
            USBKeys := TStringList.Create;
            try // 5
              Reg.GetKeyNames(USBKeys);
              for i := 0 to USBKeys.Count - 1 do
              begin //6
                if Result <> '' then Break;
                Reg.CloseKey;
                // Read Device subkeys (serials)
                if Reg.OpenKeyReadOnly('SYSTEM\CurrentControlSet\Enum\USBSTOR' +
                      '\' + USBKeys[i]) then
                begin // 7
                  USBSubKeys := TStringList.Create;
                  try // 8
                    Reg.GetKeyNames(USBSubKeys);
                    for j := 0 to USBSubKeys.Count - 1 do
                    begin // 9
                      Reg.CloseKey;
                      // Read Device (serial) ParentIDPrefix
                      if Reg.OpenKeyReadOnly('SYSTEM\CurrentControlSet\Enum\USBSTOR' +
                        '\' + USBKeys[i] + '\' + USBSubKeys[j]) then
                      begin // 10
                        if Reg.ReadString('ParentIdPrefix') = ParentID then
                        begin
                          Result := Reg.ReadString('FriendlyName');
                          Break;
                        end;
                      end; // end 10
                    end; // end 9
                  finally // try 8
                    Reg.CloseKey;
                    USBSubKeys.Free;
                  end; // try 8
                end; // end 7
              end; // end 6
            finally // try 5
              USBKeys.Free;
              Reg.CloseKey;
            end; // try 5
          end; // end 4
        end; // end 3
      finally // try 2
        MountedDevices.Free;
        Reg.CloseKey;
      end; // try 2
    end; // end 1
  finally // try 0
     Reg.Free;
  end; // try 0
end;
0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

  • 4
  • 3
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now