[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 4942
  • Last Modified:

USB Flash Drive Serial Numbers

I am writing a program using Delphi 6 which I would like to run from a USB flash drive and I want to record the serial number of each flash drive when the software is copied to it for the first time.  When the program is opened I want to compare the serial number of the flash drive to the one I recorded when the flash drive software was created.  I don't want the serial number of the drive's volume when formatted.  This is the hardware serial number.  I have found a couple of methods that work but they fail when Vista/Windows 7/8 is used.
0
axp275
Asked:
axp275
1 Solution
 
axp275Author Commented:
That link will get me the volume s/n.  That changes with each format so it won't work.  Thanks.
0
 
Sinisa VukCommented:
This is serial number !! Best you can find.
http://www.codeproject.com/Articles/6077/How-to-Retrieve-the-REAL-Hard-Drive-Serial-Number
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_22787299.html
Did you try to format usb device? Volume number is changing and is 8 hex numbers.
Go download this tool and check by yourself:
http://www.popsoftdownload.com/usbphysic-unlimited-site-license-download-113467.html
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
axp275Author Commented:
None of those solutions work for me and I have seen them a very long time ago.  I have solved this puzzle.  see code below:


function GetFlashDriveSerialNumber(const Drive:AnsiChar):string;
var
      FSWbemLocator            :OleVariant;
  objWMIService            :OLEVariant;
  colDiskDrives            :OLEVariant;
  colLogicalDisks      :OLEVariant;
  colPartitions            :OLEVariant;
  objDiskDrive            :OLEVariant;
  objPartition            :OLEVariant;
  objLogicalDisk      :OLEVariant;
  oEnumDiskDrive      :IEnumvariant;
  oEnumPartition      :IEnumvariant;
  oEnumLogical            :IEnumvariant;
  iValue                              :LongWord;
  DeviceID                        :String;
begin;
  Result:='';
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  objWMIService := FSWbemLocator.ConnectServer('.', 'root\CIMV2', '', '');
  colDiskDrives := objWMIService.ExecQuery('SELECT * FROM Win32_DiskDrive WHERE InterfaceType="USB"','WQL',0);
  oEnumDiskDrive:= IUnknown(colDiskDrives._NewEnum) as IEnumVariant;
  while oEnumDiskDrive.Next(1, objDiskDrive, iValue) = 0 do
  begin
            DeviceID        := StringReplace(VarStrNull(objDiskDrive.DeviceID),'\','\\',[rfReplaceAll]); //Escape the `\` chars in the DeviceID value because the '\' is a reserved character in WMI.
            colPartitions   := objWMIService.ExecQuery(Format('ASSOCIATORS OF {Win32_DiskDrive.DeviceID="%s"} WHERE AssocClass = Win32_DiskDriveToDiskPartition',[DeviceID]));//link the Win32_DiskDrive class with the Win32_DiskDriveToDiskPartition class
            oEnumPartition  := IUnknown(colPartitions._NewEnum) as IEnumVariant;
            while oEnumPartition.Next(1, objPartition, iValue) = 0 do
            begin
                  colLogicalDisks := objWMIService.ExecQuery('ASSOCIATORS OF {Win32_DiskPartition.DeviceID="'+VarStrNull(objPartition.DeviceID)+'"} WHERE AssocClass = Win32_LogicalDiskToPartition'); //link the Win32_DiskPartition class with theWin32_LogicalDiskToPartition class.
                  oEnumLogical  := IUnknown(colLogicalDisks._NewEnum) as IEnumVariant;
                  while oEnumLogical.Next(1, objLogicalDisk, iValue) = 0 do
                  begin
                        if SameText(VarStrNull(objLogicalDisk.DeviceID),Drive+':')  then //compare the device id
                        begin
                              Result:=VarStrNull(objDiskDrive.PnPDeviceID);
                              if AnsiStartsText('USBSTOR', Result) then
                              begin
                                    iValue:=LastDelimiter('\', Result);
                                    Result:=Copy(Result, iValue+1, Length(Result));
                              end;//if
                              objLogicalDisk:=Unassigned;
                              Exit;
                        end;//if
                        objLogicalDisk:=Unassigned;
                  end;//while
                  objPartition:=Unassigned;
            end;//while
            objDiskDrive:=Unassigned;
  end;//while
end;
0
 
axp275Author Commented:
I've requested that this question be closed as follows:

Accepted answer: 0 points for axp275's comment #a39203803

for the following reason:

After I posted my problem I discovered a solution that did exactly what I needed it to do and I have posted the code above.  I don't deserve any points for this because I am using code from an example I found.  I have only adjusted it to compile properly and work for my project.  Thanks to all of those who assisted.
0
 
Sinisa VukCommented:
This code you provide is exact the same as is on page which I suggested:
http://stackoverflow.com/questions/4292395/how-to-get-manufacturer-serial-number-of-an-usb-flash-drive
0
 
lomo74Commented:
try the following code (translated from http://oroboro.com/usb-serial-number/).
you will need JVCL, Jcl and PerlRegEx libraries, too.
Jcl / JVCL : http://sourceforge.net/projects/jvcl/files/JVCL%203/JVCL%203.47/JVCL347CompleteJCL241-Build4571.zip/download
PerlRegEx : http://www.regular-expressions.info/delphi.html
program usbsn;

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows, JvSetupApi, PerlRegEx;

type
  DEVICE_TYPE = DWORD;
  STORAGE_DEVICE_NUMBER = record
    //
    // The FILE_DEVICE_XXX type for this device.
    //
    DeviceType: DEVICE_TYPE;
    //
    // The number of this device
    //
    DeviceNumber: DWORD;
    //
    // If the device is partitionable, the partition number of the device.
    // Otherwise -1
    //
    PartitionNumber: DWORD;
  end;

const
  FILE_ANY_ACCESS                     = 0;
  METHOD_BUFFERED                     = 0;
  FILE_DEVICE_MASS_STORAGE            = $0000002D;
  IOCTL_STORAGE_BASE                  = FILE_DEVICE_MASS_STORAGE;
  IOCTL_STORAGE_GET_DEVICE_NUMBER     = (IOCTL_STORAGE_BASE shl 16) or (FILE_ANY_ACCESS shl 14) or
                                        ($0420 shl 2) or METHOD_BUFFERED;
  GUID_DEVINTERFACE_USB_DISK: TGUID = (
    D1: $53f56307;
    D2: $b6bf;
    D3: $11d0;
    D4: ($94, $f2, $00, $a0, $c9, $1e, $fb, $8b);
  );

function getDeviceNumber(deviceHandle: THandle): DWORD;
var
  sdn: STORAGE_DEVICE_NUMBER;
  dwBytesReturned: DWORD;
begin
  sdn.DeviceNumber := MAXDWORD;
  dwBytesReturned := 0;
  if not DeviceIoControl(deviceHandle, IOCTL_STORAGE_GET_DEVICE_NUMBER,
  nil, 0, @sdn, SizeOf(sdn), dwBytesReturned, nil) then
   // handle error - like a bad handle.
    Result := MAXDWORD
  else
    Result := sdn.DeviceNumber;
end;

function getDeviceSerialNumber(vol: Char): string;
var
  devicePath: string;
  deviceHandle: THandle;
  volumeDeviceNumber: DWORD;
  hDev: HDEVINFO;
  Buf: array[0..1023] of Byte;
  pspdidd: PSPDeviceInterfaceDetailData;
  spdid: SP_DEVICE_INTERFACE_DATA;
  spdd: SP_DEVINFO_DATA;
  dwIndex, dwSize: DWORD;
  res: LongBool;
  hDrive: THandle;
  usbDeviceNumber: DWORD;
  re: TPerlRegEx;
begin
  // get the device handle
  devicePath := '\\.\' + vol + ':';

  deviceHandle := CreateFile(PChar(devicePath), 0,
    FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
    OPEN_EXISTING, 0, 0);
  if deviceHandle = INVALID_HANDLE_VALUE then
    Exit;

  // to get the device number
  volumeDeviceNumber := getDeviceNumber(deviceHandle);
  CloseHandle(deviceHandle);

  // Get device interface info set handle
  // for all devices attached to the system
  hDev := SetupDiGetClassDevs(
    @GUID_DEVINTERFACE_USB_DISK, nil, 0,
    DIGCF_PRESENT or DIGCF_DEVICEINTERFACE);

  if hDev = HDEVINFO(INVALID_HANDLE_VALUE) then
    Exit;

  // Get a context structure for the device interface
  // of a device information set.
  Cardinal(pspdidd) := Cardinal(@Buf);

  spdid.cbSize := SizeOf(spdid);

  dwIndex := 0;
  while True do begin
    if not SetupDiEnumDeviceInterfaces(hDev, nil,
    GUID_DEVINTERFACE_USB_DISK, dwIndex, spdid) then
       Break;

    dwSize := 0;
    SetupDiGetDeviceInterfaceDetail(hDev, @spdid, nil,
      0, dwSize, nil);

    if (dwSize <> 0) and (dwSize <= SizeOf(Buf)) then begin
      pspdidd^.cbSize := SizeOf(pspdidd^); // 5 Bytes!

      ZeroMemory(@spdd, SizeOf(spdd));
      spdd.cbSize := SizeOf(spdd);

      res := SetupDiGetDeviceInterfaceDetail(
        hDev, @spdid, pspdidd, dwSize, dwSize, @spdd);
      if res then begin
        hDrive := CreateFile(pspdidd^.DevicePath, 0,
          FILE_SHARE_READ or FILE_SHARE_WRITE,
          nil, OPEN_EXISTING, 0, 0);
        if hDrive <> INVALID_HANDLE_VALUE then begin
          usbDeviceNumber := getDeviceNumber(hDrive);

          if usbDeviceNumber = volumeDeviceNumber then begin
            re := TPerlRegEx.Create;
            re.RegEx := '&rev_[^#]+#([^&#]+)';
            re.Subject := PChar(@pspdidd^.DevicePath);
            if re.Match then begin
              Result := re.Groups[1];
              Exit;
            end;
          end;
        end;
        CloseHandle(hDrive);
      end;
    end;
    Inc(dwIndex);
  end;

  SetupDiDestroyDeviceInfoList(hDev);
end;

begin
  try
    LoadSetupApi;
    Writeln(getDeviceSerialNumber('N'));
    UnloadSetupApi;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Open in new window

0
 
axp275Author Commented:
This user did in fact send a link with the same code I used even though I discovered this on my own from a different link so they should get the points for the solution.
0
 
johnnyexCommented:
sorry again, confused so which solution is best?
here we can see:
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_28140731.html#a39203803

There we can see two methods:
http://stackoverflow.com/questions/4292395/how-to-get-manufacturer-serial-number-of-an-usb-flash-drive


Where author says: "UPDATE
Some drivers of the USB disks does not expose the manufacturer serial number on the Win32_DiskDrive.SerialNumber property, so on this cases you can extract the serial number from the PnPDeviceID property."


So which one is the best method which will work on all drives or maybe use two hybrid if one fail?

Would be good to have one solid solution which will just work is this from first link I posted or second method from stackoverflow link?
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now