草庐IT

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

coder 2023-11-12 原文

如何在 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/

有关windows - 如何获取U盘的制造商序列号?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  4. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  9. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  10. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

随机推荐