【问题标题】:How to find the unique serial number of a flash device?如何找到闪存设备的唯一序列号?
【发布时间】:2023-03-24 20:49:01
【问题描述】:

我发现了几个可以检测 USB 闪存驱动器何时插入和移除的 sn-ps 和 .pas 文件。有些提供了各种好的信息,但我需要的是设备的唯一序列号,而不是卷的序列号。

我当前的 .pas 文件(我不记得我在哪里找到的)似乎也检测到了 SD 卡(我喜欢)。如果你想看,你可以在这里找到它(它只返回驱动器号和插入/删除):

unit UsbDetector;

interface

uses Classes;

type
  TUsbDriveChanged = procedure (Sender: TObject; Drive: string; Attached: boolean) of object;

procedure StartUsbDetector(NotifyProc: TUsbDriveChanged);
procedure StopUsbDetector;

implementation

uses Windows, Messages, Forms, SysUtils;

type
  TUSBDetector = class(TObject)
  private
    fUsbDriveChanged: TUsbDriveChanged;
  protected
    procedure DeviceChanged(Msg: UINT; wParam, lParam: Longint);
    procedure DoUsbDriveChanged(Drive: string; Attached: Boolean); dynamic;
  public
    constructor Create(NotifyProc: TUsbDriveChanged);
    destructor Destroy; override;
    property OnUsbDriveChanged: TUsbDriveChanged read fUsbDriveChanged;
  end;

var mUSBDetector: TUSBDetector;

procedure StartUsbDetector(NotifyProc: TUsbDriveChanged);
begin
  if not Assigned(mUsbDetector) then
    mUsbDetector := TUsbDetector.Create(NotifyProc);
end;

procedure StopUsbDetector;
begin
  FreeAndNil(mUsbDetector);
end;

{----------------------------------------------------------------------------}
// Device constants
const
  DBT_DEVICEARRIVAL          =  $00008000;
  DBT_DEVICEREMOVECOMPLETE   =  $00008004;
  DBT_DEVTYP_VOLUME          =  $00000002;

// Device structs
type
  _DEV_BROADCAST_HDR         =  packed record
     dbch_size:              DWORD;
     dbch_devicetype:        DWORD;
     dbch_reserved:          DWORD;
  end;
  DEV_BROADCAST_HDR          =  _DEV_BROADCAST_HDR;
  TDevBroadcastHeader        =  DEV_BROADCAST_HDR;
  PDevBroadcastHeader        =  ^TDevBroadcastHeader;

type
  _DEV_BROADCAST_VOLUME      =  packed record
     dbch_size:              DWORD;
     dbch_devicetype:        DWORD;
     dbch_reserved:          DWORD;
     dbcv_unitmask:          DWORD;
     dbcv_flags:             WORD;
  end;
  DEV_BROADCAST_VOLUME       =  _DEV_BROADCAST_VOLUME;
  TDevBroadcastVolume        =  DEV_BROADCAST_VOLUME;
  PDevBroadcastVolume        =  ^TDevBroadcastVolume;

var
  fPrevWndProc: TFNWndProc = nil;

function UsbWndProc(hWnd: HWND; Msg: UINT; wParam, lParam: Longint): Longint; stdcall;
begin
  Result := CallWindowProc(fPrevWndProc, hWnd, Msg, wParam, lParam);
  if (Msg = WM_DEVICECHANGE) and (mUsbDetector <> nil) then
    mUsbDetector.DeviceChanged(Msg, wParam, lParam);
end;

constructor TUSBDetector.Create(NotifyProc: TUsbDriveChanged);
begin
  inherited Create;
  fUsbDriveChanged := NotifyProc;
  if not Assigned(fPrevWndProc) then 
  begin
    fPrevWndProc := TFNWndProc(GetWindowLong(Application.Handle, GWL_WNDPROC));
    SetWindowLong(Application.Handle, GWL_WNDPROC, LongInt(@UsbWndProc));
  end;
end;

destructor TUSBDetector.Destroy;
begin
  //SetWindowLong(Application.Handle, GWL_WNDPROC, LongInt(@fPrevWndProc));
  inherited Destroy;
end;

procedure TUSBDetector.DeviceChanged(Msg: UINT; wParam, lParam: LongInt);
var
  lpdbhHeader: PDevBroadcastHeader;
  lpdbvData: PDevBroadcastVolume;
  dwIndex: Integer;
  lpszDrive: string;
begin
  // Get the device notification header
  lpdbhHeader := PDevBroadcastHeader(lParam);
  // Handle the message
  lpszDrive := '';
  case WParam of
    DBT_DEVICEARRIVAL:    {a USB drive was connected}
    begin
      if lpdbhHeader^.dbch_devicetype = DBT_DEVTYP_VOLUME then
      begin
        lpdbvData := PDevBroadcastVolume(lParam);
        for dwIndex := 0 to 25 do
        begin
          if (lpdbvData^.dbcv_unitmask shr dwIndex) = 1 then
          begin
            lpszDrive := lpszDrive + Chr(65 + dwIndex) + ':\';
            break;
          end;
        end;
        DoUsbDriveChanged(lpszDrive, True);
      end;
    end;
    DBT_DEVICEREMOVECOMPLETE:    {a USB drive was removed}
    begin
      if lpdbhHeader^.dbch_devicetype = DBT_DEVTYP_VOLUME then
      begin
        lpdbvData := PDevBroadcastVolume(lParam);
        for dwIndex := 0 to 25 do
        begin
          if (lpdbvData^.dbcv_unitmask shr dwIndex) = 1 then
          begin
            lpszDrive := lpszDrive + Chr(65 + dwIndex) + ':\';
            break;
          end;
        end;
        DoUsbDriveChanged(lpszDrive, False);
      end;
    end;
  end;
end;

procedure TUSBDetector.DoUsbDriveChanged(Drive: string; Attached: Boolean);
begin
  if Assigned(fUsbDriveChanged) then
    fUsbDriveChanged(Self, Drive, Attached);
end;

end.

附:代码高亮失败。

总之; 插入/移除可移动设备时,获取驱动器号及其唯一序列号。也许将已经给出的代码与 WMI 调用“where Index=found_index”结合起来。

****编辑!**** 我删除了 RRUZ 给出的代码中的“where”子句。我终于找到了如何处理数组,所以我用它来查找 Capabilities[i]=7 来获取所有可移动媒体。现在我只需要将这段代码与上面的代码连接起来。我正在考虑使用 Index,但我不知道如何使用 GetDrive MapInfo。如果你能给我提供一个获取驱动器号的例子,我的问题就解决了。

【问题讨论】:

  • @Daniel,检查这个问题stackoverflow.com/questions/1687239/…
  • 我做到了,但我忘了告诉我希望有一个标准的方式(如果存在的话)。如果没有其他选择,我想我可以使用它。
  • 好的,它有效。但它只检测 U 盘。而且我无法将它与我现有的设备连接起来。
  • 我发现我可以使用 Capabilities[7] 来获取所有可移动驱动器(USB 笔 + SD 卡等),但我不知道如何在 WMI 查询中使用数组。此外,如果我能得到驱动器号,那就太棒了。有一个索引,但我找不到 GetDriveMapInfo。

标签: delphi delphi-2007 removable-storage removable


【解决方案1】:

您可以通过Magenta Systems 使用 WMI 库,这可以消除使用 WMI 查询的大部分痛苦。免费下载包括源代码和示例项目,可让您使用 API 并查询您心中的内容。您需要保留指向官方 Microsoft API documentation 的链接,这将帮助您执行哪些查询以获取哪些信息...您有兴趣使用类似 SQL 的语法查询来查询类。

例如执行查询

SELECT * FROM Win32_DiskDrive Where InterfaceType = 'USB'

返回有关当前连接到机器的所有 USB 设备的大量信息。然后,您可以使用 PNPDeviceID 作为唯一标识符。

EDIT 检查我手边唯一的 USB 设备返回了硬件序列号“u”,但看起来很长且有效的 PNPDeviceID 似乎包含序列号,这就是我建议的原因字段。

编辑您可以通过对Win32_LogicalDisk 执行查询来获取驱动器号,也可以查询包含Win32_DiskDriveWin32_DiskPartition 之间映射的Win32_DiskDriveToDiskPartition。最后Win32_LogicalDiskToPartition 然后将逻辑磁盘映射到一个分区,从而使您能够将物理 USB 驱动器链接到特定驱动器号。

【讨论】:

  • 是的,它是这样的,但我希望你看看问题的 cmets;我想要各种可移动设备(包括 SD 卡)。此外,应该可以在插入(和移除)此类设备时获取此信息,也许将其与问题中的代码结合起来?
  • 您不必在 where 子句中添加任何内容,它将返回连接到机器的所有磁盘驱动器设备的记录。
  • 我知道。这就是我正在做的事情。但我只需要驱动器号。
  • 好的。感谢您的编辑。我是否应该担心 U 盘上可能有多个分区?
  • 很可能不是,但操作系统确实支持它,所以它是可能的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-10
  • 2022-06-16
相关资源
最近更新 更多