如何获得USB闪存驱动器的制造商序列号? [英] How to get manufacturer serial number of an USB flash drive?

查看:147
本文介绍了如何获得USB闪存驱动器的制造商序列号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我如何在Delphi中检索USB闪存驱动器的制造商序列号?



我已经尝试过:

 函数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);
结果:= VolumeSerialNumber;
结束

但它没有返回正确的结果!

解决方案

opc0de,根据您的意见,我将给您一个使用WMI的示例。



首先,您发布的代码(使用 GetVolumeInformation 功能)返回格式化磁盘时Windows分配的序列号。



好消息是存在两个wmi类,它们公开了一个名为 SerialNumber 的属性,存储制造商分配的号码来标识物理媒体。这些类是 Win32_DiskDrive Win32_PhysicalMedia



不幸的是,这个类不直接与字母相关联(C, D,E,F ...),因为您必须调用另一个wmi类来找到逻辑驱动程序字母和物理驱动器之间的链接。



所以您必须先找到此链接才能获得序列号。找到这个关联的顺序是这样的。



Win32_DiskPartition - > Win32_LogicalDiskToPartition - > Win32_DiskDrive



这是获取的代码使用 Win32_DiskDrive 类。

 程序GetWMI_Info; 

{$ APPTYPE CONSOLE}

使用
SysUtils,
StrUtils,
ActiveX,
ComObj,
变种

函数VarArrayToStr(const vArray:variant):string;

函数_VarToStr(const V:variant):string;
var
Vt:integer;
begin
Vt:= VarType(V);
case Vt
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:结果:= VarArrayToStr(Variant(V));
结束
结束

var
i:integer;
begin
结果:='[';
if(VarType(vArray)和VarArray)= 0然后
结果:= _VarToStr(vArray)
else
for i:= VarArrayLowBound(vArray,1)到VarArrayHighBound(vArray ,1)do
if i = VarArrayLowBound(vArray,1)then
Result:= Result + _VarToStr(vArray [i])
else
结果:= Result +'|' + _VarToStr(vArray [i]);

结果:= Result +']';
结束

函数VarStrNull(const V:OleVariant):string; //避免使用空字符串的问题
begin
结果:='';
如果不是VarIsNull(V)然后
begin
如果VarIsArray(V)then
结果:= VarArrayToStr(V)
else
结果:= VarToStr (V);
结束
结束


函数GetWMIObject(const objectName:String):IDispatch; //创建Wmi实例
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));
结束



函数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;
开始;
结果:='';
objWMIService:= GetWMIObject('winmgmts:\\localhost\root\CIMV2'); //连接到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]); //在DeviceID值中删除`\`个字符,因为'\'是WMI中的保留字符。
colPartitions:= objWMIService.ExecQuery(Format('ASSOCIATORS OF {Win32_DiskDrive.DeviceID =%s} WHERE AssocClass = Win32_DiskDriveToDiskPartition',[DeviceID])); //将Win32_DiskDrive类与Win32_DiskDriveToDiskPartition类$ b链接$ b 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'); //将Win32_DiskPartition类与Win32_LogicalDiskToPartition类链接。
oEnumLogical:= IUnknown(colLogicalDisks.NewEnum)as IEnumVariant;
while oEnumLogical.Next(1,objLogicalDisk,iValue)= 0 do
如果VarStrNull(objLogicalDisk.DeviceID)=(Drive +':')然后//比较设备ID
begin
结果:= VarStrNull(objDiskDrive.SerialNumber);
退出;
结束
结束
结束
结束

begin
try
CoInitialize(nil);
try
Writeln(GetUsbDriveSerial('F'));
Readln;
finally
CoUninitialize;
结束
除了
在E上:异常do
begin
Writeln(E.Classname,':',E.Message);
Readln;
结束
结束
结束。

之前我写了一个名为

>

更新



USB磁盘的某些驱动程序不会在制造商序列号Win32_DiskDrive.SerialNumber属性,所以在这种情况下,您可以从 PnPDeviceID 属性中提取序列号。



检查此示例代码

  {$ APPTYPE CONSOLE} 

使用
SysUtils,
StrUtils,
ActiveX,
ComObj,
变体;


函数VarStrNull(const V:OleVariant):string; //避免空变量的问题
begin
结果:='';
如果不是VarIsNull(V)then
结果:= VarToStr(V);
结束


函数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;
开始;
结果:='';
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]); //在DeviceID值中删除`\`个字符,因为'\'是WMI中的保留字符。
colPartitions:= objWMIService.ExecQuery(Format('ASSOCIATORS OF {Win32_DiskDrive.DeviceID =%s} WHERE AssocClass = Win32_DiskDriveToDiskPartition',[DeviceID])); //将Win32_DiskDrive类与Win32_DiskDriveToDiskPartition类$ b链接$ b 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'); //将Win32_DiskPartition类与Win32_LogicalDiskToPartition类链接。
oEnumLogical:= IUnknown(colLogicalDisks.NewEnum)as IEnumVariant;
while oEnumLogical.Next(1,objLogicalDisk,iValue)= 0 do
begin
如果SameText(VarStrNull(objLogicalDisk.DeviceID),Drive +':')则//比较设备ID
begin
结果:= VarStrNull(objDiskDrive.PnPDeviceID);
如果AnsiStartsText('USBSTOR',结果)然后
开始
iValue:= LastDelimiter('\',Result);
结果:=复制(结果,iValue + 1,长度(结果));
结束
objLogicalDisk:=未分配;
退出;
结束
objLogicalDisk:=未分配;
结束
objPartition:=未分配;
结束
objDiskDrive:=未分配;
结束
结束

begin
try
CoInitialize(nil);
try
Writeln(GetUsbDriveSerial('F'));
Readln;
finally
CoUninitialize;
结束
除了
在E上:异常do
begin
Writeln(E.Classname,':',E.Message);
Readln;
结束
结束
结束。


How can I retrieve the manufacturer serial number of an USB flash drive in Delphi ?

I have tried this:

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;

But it doesn't return correct result!

解决方案

opc0de, according to your comments i will give you a sample using the WMI.

First, the code which you posted (using the GetVolumeInformation function) return the serial number assigned by windows when you format a disk.

The good news are which exist two wmi classes wich exposes a property called SerialNumber which store the Number allocated by the manufacturer to identify the physical media. these classes are Win32_DiskDrive and Win32_PhysicalMedia.

Now the bad news, unfortunately this classes is not associated directly with the letter (C,D,E,F...) of the logical disk, because that you must call to another wmi classes to find the link between the logical driver letter and the Physical drive.

so you must find this link previous to obtain the serial number. the sequence to find this association is like this.

Win32_DiskPartition -> Win32_LogicalDiskToPartition -> Win32_DiskDrive

this is the code to obtain the serial number of a usb using the Win32_DiskDrive class.

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.

By the way some time ago i wrote an application called WMI Delphi Code Creator which can help you to generate delphi code to access the system info using the WMI.

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.

Check this sample code.

{$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.

这篇关于如何获得USB闪存驱动器的制造商序列号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆