Solved

USB Flash Drive Serial Numbers

Posted on 2013-05-28
9
4,181 Views
Last Modified: 2013-06-30
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
Comment
Question by:axp275
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
9 Comments
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 39202658
0
 

Author Comment

by:axp275
ID: 39202822
That link will get me the volume s/n.  That changes with each format so it won't work.  Thanks.
0
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 39203105
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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:axp275
ID: 39203803
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
 

Author Comment

by:axp275
ID: 39204817
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
 
LVL 27

Accepted Solution

by:
Sinisa Vuk earned 500 total points
ID: 39203817
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
 
LVL 8

Expert Comment

by:lomo74
ID: 39204036
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
 

Author Closing Comment

by:axp275
ID: 39204818
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
 

Expert Comment

by:johnnyex
ID: 39288514
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

[Webinar] Code, Load, and Grow

Managing multiple websites, servers, applications, and security on a daily basis? Join us for a webinar on May 25th to learn how to simplify administration and management of virtual hosts for IT admins, create a secure environment, and deploy code more effectively and frequently.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Developing a front end to SPLUNK 1 111
Programming Language for Wordpress 7 88
Broadcast a message using ICS 2 51
Cannot locate cell 15 43
This article is meant to give a basic understanding of how to use R Sweave as a way to merge LaTeX and R code seamlessly into one presentable document.
A short article about a problem I had getting the GPS LocationListener working.

710 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