2010-11-27 80 views
3

如何在Delphi中检索USB闪存驱动器的制造商序列号?如何获取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; 

但它不返回正确的结果!

+0

当硬盘格式化或制造商的序列号是否需要由Windows分配的序列号? – RRUZ 2010-11-27 15:57:15

+0

从制造商的序列! – opc0de 2010-11-27 16:04:58

回答

12

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

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

好消息是存在两个wmi类将暴露属性SerialNumber存储the Number allocated by the manufacturer to identify the physical media.这些类是Win32_DiskDriveWin32_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的系统信息。

UPDATE

的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. 
2

您可以尝试组件TDiskInfo from GLib以获取SerialNumber。
它不使用WMI,但在某些系统(磁盘类型)不检索数字。
试试吧。免费。

问候。

相关问题