axp275
asked on
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.
ASKER
That link will get me the volume s/n. That changes with each format so it won't work. Thanks.
This is serial number !! Best you can find.
http://www.codeproject.com /Articles/ 6077/How-t o-Retrieve -the-REAL- Hard-Drive -Serial-Nu mber
http://www.experts-exchang e.com/Prog ramming/La nguages/Pa scal/Delph i/Q_227872 99.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/usbph ysic-unlim ited-site- license-do wnload-113 467.html
http://www.codeproject.com
http://www.experts-exchang
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
ASKER
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('WbemScrip ting.SWbem Locator');
objWMIService := FSWbemLocator.ConnectServe r('.', 'root\CIMV2', '', '');
colDiskDrives := objWMIService.ExecQuery('S ELECT * FROM Win32_DiskDrive WHERE InterfaceType="USB"','WQL' ,0);
oEnumDiskDrive:= IUnknown(colDiskDrives._Ne wEnum) as IEnumVariant;
while oEnumDiskDrive.Next(1, objDiskDrive, iValue) = 0 do
begin
DeviceID := StringReplace(VarStrNull(o bjDiskDriv e.DeviceID ),'\','\\' ,[rfReplac eAll]); //Escape the `\` chars in the DeviceID value because the '\' is a reserved character in WMI.
colPartitions := objWMIService.ExecQuery(Fo rmat('ASSO CIATORS OF {Win32_DiskDrive.DeviceID= "%s"} WHERE AssocClass = Win32_DiskDriveToDiskParti tion',[Dev iceID]));/ /link the Win32_DiskDrive class with the Win32_DiskDriveToDiskParti tion class
oEnumPartition := IUnknown(colPartitions._Ne wEnum) as IEnumVariant;
while oEnumPartition.Next(1, objPartition, iValue) = 0 do
begin
colLogicalDisks := objWMIService.ExecQuery('A SSOCIATORS OF {Win32_DiskPartition.Devic eID="'+Var StrNull(ob jPartition .DeviceID) +'"} WHERE AssocClass = Win32_LogicalDiskToPartiti on'); //link the Win32_DiskPartition class with theWin32_LogicalDiskToPart ition class.
oEnumLogical := IUnknown(colLogicalDisks._ NewEnum) as IEnumVariant;
while oEnumLogical.Next(1, objLogicalDisk, iValue) = 0 do
begin
if SameText(VarStrNull(objLog icalDisk.D eviceID),D rive+':') then //compare the device id
begin
Result:=VarStrNull(objDisk Drive.PnPD eviceID);
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;
function GetFlashDriveSerialNumber(
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('WbemScrip
objWMIService := FSWbemLocator.ConnectServe
colDiskDrives := objWMIService.ExecQuery('S
oEnumDiskDrive:= IUnknown(colDiskDrives._Ne
while oEnumDiskDrive.Next(1, objDiskDrive, iValue) = 0 do
begin
DeviceID := StringReplace(VarStrNull(o
colPartitions := objWMIService.ExecQuery(Fo
oEnumPartition := IUnknown(colPartitions._Ne
while oEnumPartition.Next(1, objPartition, iValue) = 0 do
begin
colLogicalDisks := objWMIService.ExecQuery('A
oEnumLogical := IUnknown(colLogicalDisks._
while oEnumLogical.Next(1, objLogicalDisk, iValue) = 0 do
begin
if SameText(VarStrNull(objLog
begin
Result:=VarStrNull(objDisk
if AnsiStartsText('USBSTOR', Result) then
begin
iValue:=LastDelimiter('\',
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;
ASKER
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.
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.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
try the following code (translated from http://oroboro.com/usb-ser ial-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
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.
ASKER
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.
sorry again, confused so which solution is best?
here we can see:
https://www.experts-exchange.com/questions/28140731/USB-Flash-Drive-Serial-Numbers.html?anchorAnswerId=39203803#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.SerialNumb er 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?
here we can see:
https://www.experts-exchange.com/questions/28140731/USB-Flash-Drive-Serial-Numbers.html?anchorAnswerId=39203803#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.SerialNumb
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?
http://stackoverflow.com/q