如何获取 USB 闪存驱动器的制造商序列号?
Posted
技术标签:
【中文标题】如何获取 USB 闪存驱动器的制造商序列号?【英文标题】:How to get manufacturer serial number of an USB flash drive? 【发布时间】:2011-05-16 14:20:22 【问题描述】:如何在 Delphi 中检索 USB 闪存驱动器的制造商序列号?
我试过这个:
function GetDiskVolSerialID(ADriveName: Char): Cardinal;
var
DiskDrive: string;
FileSystemFlags: DWORD;
VolumeSerialNumber: DWORD;
MaximumComponentLength: DWORD;
begin
DiskDrive := ADriveName + ':\';
GetVolumeInformation(PChar(DiskDrive),
nil,
0,
@VolumeSerialNumber,
MaximumComponentLength,
FileSystemFlags,
nil,
0);
Result := VolumeSerialNumber;
end;
但它没有返回正确的结果!
【问题讨论】:
硬盘格式化时要windows分配的序列号还是厂家的序列号? 厂商的序列号! WMI 的创建是为了方便访问包括硬件在内的信息系统,WMI 是完成此类任务的完美工具,因为使用起来非常简单。我不知道您不使用 WMI 的动机是什么。你能解释一下吗? 在delphi中很难实现我试过但如果你有一些代码失败了我会很感激;) 我也同意 RRUZ。您同意删除 WMI 约束吗?如果不是,还有其他原因吗?你请求帮助解决一个人为的要求,这可能会使它变得更难,只是因为你认为它应该更容易。 【参考方案1】:opc0de,根据你的 cmets,我会给你一个使用 WMI 的示例。
首先,您发布的代码(使用GetVolumeInformation
函数)返回格式化磁盘时Windows分配的序列号。
好消息是存在两个 wmi 类,它们公开了一个名为 SerialNumber
的属性,其中存储了 the Number allocated by the manufacturer to identify the physical media.
这些类是 Win32_DiskDrive
和 Win32_PhysicalMedia
。
现在有个坏消息,不幸的是这个类与逻辑磁盘的字母(C,D,E,F...)没有直接关联,因为你必须调用另一个 wmi 类来找到它们之间的链接逻辑驱动器号和物理驱动器。
因此您必须先找到此链接才能获取序列号。找到这个关联的顺序是这样的。
Win32_DiskPartition
-> Win32_LogicalDiskToPartition
-> Win32_DiskDrive
这是使用Win32_DiskDrive
类获取USB 序列号的代码。
program GetWMI_Info;
$APPTYPE CONSOLE
uses
SysUtils,
StrUtils,
ActiveX,
ComObj,
Variants;
function VarArrayToStr(const vArray: variant): string;
function _VarToStr(const V: variant): string;
var
Vt: integer;
begin
Vt := VarType(V);
case Vt of
varSmallint,
varInteger : Result := IntToStr(integer(V));
varSingle,
varDouble,
varCurrency : Result := FloatToStr(Double(V));
varDate : Result := VarToStr(V);
varOleStr : Result := WideString(V);
varBoolean : Result := VarToStr(V);
varVariant : Result := VarToStr(Variant(V));
varByte : Result := char(byte(V));
varString : Result := String(V);
varArray : Result := VarArrayToStr(Variant(V));
end;
end;
var
i : integer;
begin
Result := '[';
if (VarType(vArray) and VarArray)=0 then
Result := _VarToStr(vArray)
else
for i := VarArrayLowBound(vArray, 1) to VarArrayHighBound(vArray, 1) do
if i=VarArrayLowBound(vArray, 1) then
Result := Result+_VarToStr(vArray[i])
else
Result := Result+'|'+_VarToStr(vArray[i]);
Result:=Result+']';
end;
function VarStrNull(const V:OleVariant):string; //avoid problems with null strings
begin
Result:='';
if not VarIsNull(V) then
begin
if VarIsArray(V) then
Result:=VarArrayToStr(V)
else
Result:=VarToStr(V);
end;
end;
function GetWMIObject(const objectName: String): IDispatch; //create the Wmi instance
var
chEaten: Integer;
BindCtx: IBindCtx;
Moniker: IMoniker;
begin
OleCheck(CreateBindCtx(0, bindCtx));
OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker));
OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));
end;
function GetUsbDriveSerial(const Drive:AnsiChar):string;
var
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:='';
objWMIService := GetWMIObject('winmgmts:\\localhost\root\CIMV2'); //Connect to the WMI
//colDiskDrives := objWMIService.ExecQuery('SELECT DeviceID,SerialNumber FROM Win32_DiskDrive WHERE InterfaceType="USB"','WQL',0);
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
if VarStrNull(objLogicalDisk.DeviceID)=(Drive+':') then //compare the device id
begin
Result:=VarStrNull(objDiskDrive.SerialNumber);
Exit;
end;
end;
end;
end;
begin
try
CoInitialize(nil);
try
Writeln(GetUsbDriveSerial('F'));
Readln;
finally
CoUninitialize;
end;
except
on E:Exception do
begin
Writeln(E.Classname, ':', E.Message);
Readln;
end;
end;
end.
顺便说一下,前段时间我写了一个名为WMI Delphi Code Creator 的应用程序,它可以帮助您生成delphi 代码以使用WMI 访问系统信息。
更新
某些 USB 磁盘驱动程序不会在 Win32_DiskDrive.SerialNumber 属性中公开制造商序列号,因此在这种情况下,您可以从 PnPDeviceID
属性中提取序列号。
检查此示例代码。
$APPTYPE CONSOLE
uses
SysUtils,
StrUtils,
ActiveX,
ComObj,
Variants;
function VarStrNull(const V:OleVariant):string; //avoid issues with null variants
begin
Result:='';
if not VarIsNull(V) then
Result:=VarToStr(V);
end;
function GetUsbDriveSerial(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;
objLogicalDisk:=Unassigned;
Exit;
end;
objLogicalDisk:=Unassigned;
end;
objPartition:=Unassigned;
end;
objDiskDrive:=Unassigned;
end;
end;
begin
try
CoInitialize(nil);
try
Writeln(GetUsbDriveSerial('F'));
Readln;
finally
CoUninitialize;
end;
except
on E:Exception do
begin
Writeln(E.Classname, ':', E.Message);
Readln;
end;
end;
end.
【讨论】:
在运行代码时出现以下异常:Invalid Query any ideea why? ok , 那是由于你的 WMI 版本将这一行colDiskDrives := objWMIService.ExecQuery('SELECT DeviceID,SerialNumber FROM Win32_DiskDrive WHERE InterfaceType="USB"','WQL',0);
更改为 colDiskDrives := objWMIService.ExecQuery('SELECT * FROM Win32_DiskDrive WHERE InterfaceType="USB"','WQL',0);
代码被编辑为兼容旧版本的 WMI。
这是因为某些U盘驱动没有在Win32_DiskDrive.SerialNumber
属性上暴露厂商序列号。
@JustMarc, 1.) 是的,您可以在代码中使用此示例,2) 从技术上讲可以伪造序列号,为避免这种情况,您可以尝试使用处理器等硬件信息的组合,以 Bios、RAM 等为例,试试这个链接theroadtodelphi.wordpress.com/2010/12/02/…【参考方案2】:
您可以尝试使用组件TDiskInfo from GLib 来获取序列号。 它不使用 WMI,但在某些系统(磁盘类型)中无法检索数字。 试试吧。免费。
问候。
【讨论】:
以上是关于如何获取 USB 闪存驱动器的制造商序列号?的主要内容,如果未能解决你的问题,请参考以下文章
UDEV - 在 USB 闪存驱动器插入上运行程序 [关闭]