2009-12-18 15 views
4

J'ai trouvé plusieurs extraits et fichiers .pas qui peuvent détecter quand des clés USB sont insérées et retirées. Certains donnent toutes sortes de bonnes informations, mais ce dont j'ai besoin, c'est le numéro de série unique des appareils, pas le numéro de série des volumes. Mon fichier .pas actuel (que je ne me souviens pas où j'ai trouvé) semble également détecter les cartes SD (que j'aime). Si vous voulez un coup d'oeil, vous pouvez le trouver ici (il ne renvoie que le numéro de lecteur et inséré/retiré):Comment trouver le numéro de série unique d'un périphérique flash?

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. Le surlignage de code est échouer.

Dans l'ensemble; Lorsqu'un disque amovible est inséré/retiré, obtenez la lettre de lecteur et son numéro de série unique. Peut-être combiner le code déjà donné avec un appel WMI "où Index = found_index".

**** EDIT! **** J'ai supprimé la clause "where" dans le code donné par RRUZ. J'ai finalement découvert comment gérer les tableaux, donc je l'utilise pour trouver Capabilities [i] = 7 pour obtenir tous les médias amovibles. Maintenant, j'ai juste besoin de connecter ce code avec le code ci-dessus. Je pense en utilisant Index, mais je ne sais pas comment utiliser GetDrive MapInfo. Si vous pouviez me donner un exemple sur l'obtention de la lettre de lecteur, ma question est résolue.

+1

@Daniel, vérifiez cette question http://stackoverflow.com/questions/1687239/getting-connected-usb-info-with-delphi-on-vista – RRUZ

+0

Je l'ai fait, mais j'ai oublié de dire que j'espérais un manière standard (si tel existe). Je suppose que je peux l'utiliser s'il n'y a pas d'alternatives. –

+0

Très bien, ça marche. Mais il ne détecte que les clés USB. Et il n'y a aucun moyen que je puisse connecter celui-là avec mon unité déjà existante. –

Répondre

4

Vous pouvez utiliser la bibliothèque WMI par Magenta Systems ce qui prend le plus de mal à utiliser les requêtes WMI. Le téléchargement gratuit comprend la source et un exemple de projet qui vous permet de jouer avec l'API et les requêtes à votre contenu de cœur. Vous voudrez garder un lien vers le Microsoft officiel API documentation qui vous aidera avec quelle requête à exécuter pour obtenir quelles informations ... votre intéressé à interroger les classes en utilisant des requêtes de syntaxe comme SQL.

Par exemple, l'exécution de la requête

SELECT * FROM Win32_DiskDrive Where InterfaceType = 'USB' 

renvoie une mine d'informations sur tous les périphériques USB actuellement connectés à la machine. Vous pouvez ensuite utiliser le PNPDeviceID en tant qu'identificateur unique.

EDIT vérifier le seul périphérique USB à portée de main que j'avais retourné un numéro de série matériel de « u », mais une très longue et valable à la recherche PNPDeviceID qui semble inclure un numéro de série, ce qui est la raison pour laquelle je l'ai suggéré ce domaine.

EDIT Vous pouvez obtenir la lettre de lecteur en effectuant une requête sur Win32_LogicalDisk vous pouvez également interroger Win32_DiskDriveToDiskPartition qui contient une correspondance entre Win32_DiskDrive et Win32_DiskPartition. Enfin, Win32_LogicalDiskToPartition mappe ensuite un disque logique sur une partition, ce qui vous permet à son tour de lier un lecteur USB physique à une lettre de lecteur spécifique.

+0

Oui, c'est quelque chose dans ce sens, mais j'aimerais que vous jetiez un coup d'oeil aux commentaires à la question; Je veux tout type de périphériques amovibles (y compris les cartes SD).En outre, il devrait être possible d'obtenir cette information quand un tel périphérique est inséré (et supprimé), peut-être le combiner avec le code dans la question? –

+0

vous n'avez rien à ajouter dans la clause where et il retournera un enregistrement pour TOUS les périphériques de disque connectés à la machine. – skamradt

+0

Je sais. C'est ce que je fais. Mais tout ce dont j'ai besoin est la lettre de lecteur. –