Solved

USB non HID device name

Posted on 2006-11-21
10
3,091 Views
Last Modified: 2012-06-21
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
Comment
Question by:JacekH
  • 4
  • 3
  • 2
  • +1
10 Comments
 
LVL 4

Expert Comment

by:Meldrachaun
Comment Utility
It looks like the TJclSCManager (JEDI) component may be what you need.
0
 

Author Comment

by:JacekH
Comment Utility
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
 
LVL 9

Expert Comment

by:bernani
Comment Utility
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
 
LVL 9

Expert Comment

by:bernani
Comment Utility
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
 

Author Comment

by:JacekH
Comment Utility
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
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 11

Assisted Solution

by:robert_marquardt
robert_marquardt earned 200 total points
Comment Utility
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
 

Author Comment

by:JacekH
Comment Utility
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
 
LVL 9

Accepted Solution

by:
bernani earned 100 total points
Comment Utility
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
 
LVL 11

Expert Comment

by:robert_marquardt
Comment Utility
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
 

Author Comment

by:JacekH
Comment Utility
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

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
ADO Memory leak with DELPHI 2007 37 153
IExtractImage Delphi 14 159
code issue 8 84
How to define IfThen functions in one common unit? 4 33
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now