windows - 如何获取U盘的制造商序列号?

标签 windows delphi usb

如何在 Delphi 中检索 U 盘的制造商序列号?

我试过这个:

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;

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

最佳答案

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

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

好消息是存在两个 wmi 类,它们公开了一个名为 SerialNumber 的属性,该属性存储 制造商分配的编号以识别物理媒体。 这些类是 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 访问系统信息。

更新

某些 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.

关于windows - 如何获取U盘的制造商序列号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4292395/

相关文章:

仅在第二次打开应用程序时才建立 Android USB 连接

c# - 如何通过C++或C或C#在Windows中创建指定大小的空文件?

Windows VBScript - 使用 Eval 执行代码

python - 我应该如何将 Python 嵌入到 C++ Builder/Delphi 2010 应用程序中?

delphi - XE2 和 Delphi 2009 之间的 unicode 文本文件输出不同吗?

delphi - 限制 DBGrid 中的小数位数

windows - 如何使用 Delphi 在 Windows 中从 USB 驱动器挂载分区?

c - 输出不显示

windows - 如何让批处理文件等到另一个批处理文件完成执行?

python - 连接到设备时更改 pySerial 中的波特率?