Как найти уникальный серийный номер флеш-устройства? - PullRequest
4 голосов
/ 18 декабря 2009

Я нашел несколько фрагментов и файлов .pas, которые могут определять, когда USB-накопители вставлены и извлечены. Некоторые дают всевозможную полезную информацию, однако мне нужен уникальный серийный номер устройства, а не серийный номер тома.

Мой текущий файл .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.

P.S. Подсветка кода не удалась.

В целом; Когда съемный вставлен / удален, получите букву диска и его уникальный серийный номер. Может быть, объединить уже приведенный код с вызовом WMI "где Index = found_index".

**** EDIT! **** Я удалил фразу "где" в коде, заданном RRUZ. Я наконец узнал, как обращаться с массивами, поэтому я использую это, чтобы найти Capabilities [i] = 7, чтобы получить все съемные носители. Теперь мне просто нужно связать этот код с приведенным выше кодом. Я думаю об использовании индекса, но я не знаю, как использовать GetDrive MapInfo. Если бы вы могли привести пример получения буквы диска, мой вопрос решен.

1 Ответ

4 голосов
/ 19 декабря 2009

Вы можете использовать библиотеку WMI Magenta Systems , которая берет на себя большую часть трудностей при использовании запросов WMI. Бесплатная загрузка включает в себя исходный код и пример проекта, который позволяет вам играть с API и выполнять запросы к содержанию вашего сердца. Вы захотите сохранить ссылку на официальную документацию по Microsoft API , которая поможет вам с каким запросом выполнить, чтобы получить какую информацию ... вы заинтересованы в запросах классов с использованием запросов, подобных синтаксису SQL.

Например, выполнение запроса

SELECT * FROM Win32_DiskDrive Where InterfaceType = 'USB'

возвращает обширную информацию обо всех USB-устройствах, подключенных к машине в данный момент. Затем вы можете использовать PNPDeviceID в качестве уникального идентификатора.

РЕДАКТИРОВАТЬ проверка единственного удобного USB-устройства вернула мне аппаратный серийный номер "u", но очень длинный и корректно выглядящий PNPDeviceID, который, по-видимому, содержит серийный номер, поэтому я предложил это поле .

РЕДАКТИРОВАТЬ Букву диска можно получить, выполнив запрос к Win32_LogicalDisk, вы также можете запросить Win32_DiskDriveToDiskPartition, который содержит сопоставление между Win32_DiskDrive и Win32_DiskPartition. Наконец, Win32_LogicalDiskToPartition затем сопоставляет логический диск с разделом, который, в свою очередь, дает вам возможность связать физический USB-диск с определенной буквой диска.

...