2010-09-15 9 views
12

Nella mia applicazione (Delphi), ho bisogno di elencare tutti i dispositivi di archiviazione USB. Questi possono essere sia unità di memoria flash o unità di archiviazione esterne.Delphi - Come ottenere l'elenco dei dischi rigidi e delle chiavette USB rimovibili?

C'è una componente JvclJvDriveCombo, e ha la proprietà DriveType - il problema è che se seleziono DriveType := Fixed poi oltre al disco esterno, elenca anche le unità interne (C:\, D:\ ecc). Tuttavia, voglio solo elencare le unità esterne.

Credo ci sia la funzione DeviceIoControl (l'ho vista su MSDN) ma non ho idea di come usarla.

Mi chiedo se qualcuno può aiutarmi con il modo corretto/codice per elencare i dispositivi di archiviazione USB?

Grazie.

EDIT:

ho appena trovato alcuni esempi di codice e sto postando qui:

uses .... jwawinbase, JwaWinIoctl; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    DriveCmdStr: string; 
    DriveHandle: THandle; 
    ADriveLetter: string; 
    hp: STORAGE_HOTPLUG_INFO; 
    rlen: DWORD; 
begin 

    ADriveLetter := 'H'; 
    DriveCmdStr := Format('\\.\%s:', [ADriveLetter]); 
    DriveHandle := CreateFile(PChar(DriveCmdStr), GENERIC_READ, FILE_SHARE_WRITE, 
    nil, OPEN_EXISTING, 0, 0); 

    if DriveHandle = INVALID_HANDLE_VALUE then 
    Exit; 

    DeviceIoControl(DriveHandle, IOCTL_STORAGE_GET_HOTPLUG_INFO, nil, 0, @hp, 
    SizeOf(hp), @rlen, nil); 

    CloseHandle(DriveHandle); 

    if hp.MediaRemovable then 
    showmessage('media removable'); 

end; 

Ora vorrei sapere solo come enumerare tutte le lettere di unità. Qual è la funzione più efficiente?

risposta

12
{$MINENUMSIZE 4} 
const 
    IOCTL_STORAGE_QUERY_PROPERTY = $002D1400; 

type 
    STORAGE_QUERY_TYPE = (PropertyStandardQuery = 0, PropertyExistsQuery, PropertyMaskQuery, PropertyQueryMaxDefined); 
    TStorageQueryType = STORAGE_QUERY_TYPE; 

    STORAGE_PROPERTY_ID = (StorageDeviceProperty = 0, StorageAdapterProperty); 
    TStoragePropertyID = STORAGE_PROPERTY_ID; 

    STORAGE_PROPERTY_QUERY = packed record 
    PropertyId: STORAGE_PROPERTY_ID; 
    QueryType: STORAGE_QUERY_TYPE; 
    AdditionalParameters: array [0..9] of AnsiChar; 
    end; 
    TStoragePropertyQuery = STORAGE_PROPERTY_QUERY; 

    STORAGE_BUS_TYPE = (BusTypeUnknown = 0, BusTypeScsi, BusTypeAtapi, BusTypeAta, BusType1394, BusTypeSsa, BusTypeFibre, 
    BusTypeUsb, BusTypeRAID, BusTypeiScsi, BusTypeSas, BusTypeSata, BusTypeMaxReserved = $7F); 
    TStorageBusType = STORAGE_BUS_TYPE; 

    STORAGE_DEVICE_DESCRIPTOR = packed record 
    Version: DWORD; 
    Size: DWORD; 
    DeviceType: Byte; 
    DeviceTypeModifier: Byte; 
    RemovableMedia: Boolean; 
    CommandQueueing: Boolean; 
    VendorIdOffset: DWORD; 
    ProductIdOffset: DWORD; 
    ProductRevisionOffset: DWORD; 
    SerialNumberOffset: DWORD; 
    BusType: STORAGE_BUS_TYPE; 
    RawPropertiesLength: DWORD; 
    RawDeviceProperties: array [0..0] of AnsiChar; 
    end; 
    TStorageDeviceDescriptor = STORAGE_DEVICE_DESCRIPTOR; 

function GetBusType(Drive: AnsiChar): TStorageBusType; 
var 
    H: THandle; 
    Query: TStoragePropertyQuery; 
    dwBytesReturned: DWORD; 
    Buffer: array [0..1023] of Byte; 
    sdd: TStorageDeviceDescriptor absolute Buffer; 
    OldMode: UINT; 
begin 
    Result := BusTypeUnknown; 

    OldMode := SetErrorMode(SEM_FAILCRITICALERRORS); 
    try 
    H := CreateFile(PChar(Format('\\.\%s:', [AnsiLowerCase(Drive)])), 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, 
     OPEN_EXISTING, 0, 0); 
    if H <> INVALID_HANDLE_VALUE then 
    begin 
     try 
     dwBytesReturned := 0; 
     FillChar(Query, SizeOf(Query), 0); 
     FillChar(Buffer, SizeOf(Buffer), 0); 
     sdd.Size := SizeOf(Buffer); 
     Query.PropertyId := StorageDeviceProperty; 
     Query.QueryType := PropertyStandardQuery; 
     if DeviceIoControl(H, IOCTL_STORAGE_QUERY_PROPERTY, @Query, SizeOf(Query), @Buffer, SizeOf(Buffer), dwBytesReturned, nil) then 
      Result := sdd.BusType; 
     finally 
     CloseHandle(H); 
     end; 
    end; 
    finally 
    SetErrorMode(OldMode); 
    end; 
end; 


procedure GetUsbDrives(List: TStrings); 
var 
    DriveBits: set of 0..25; 
    I: Integer; 
    Drive: AnsiChar; 
begin 
    List.BeginUpdate; 
    try 
    Cardinal(DriveBits) := GetLogicalDrives; 

    for I := 0 to 25 do 
     if I in DriveBits then 
     begin 
     Drive := Chr(Ord('a') + I); 
     if GetBusType(Drive) = BusTypeUsb then 
      List.Add(Drive); 
     end; 
    finally 
    List.EndUpdate; 
    end; 
end; 
+0

Works! grazie per il tuo disturbo! –

+1

perfetto, ma "{$ MINENUMSIZE 4}" è davvero necessario? – Peter

+1

@Peter Bene, il campo 'BusType' dovrebbe occupare 4 byte. Normalmente Delphi alloca solo il numero di byte necessario per memorizzare qualsiasi valore dell'enumerazione (in questo caso 1 byte), a meno che non si specifichi la dimensione minima enum con la direttiva '$ MINENUMSIZE'. Si potrebbe anche dichiarare 'BusType' come' DWORD' e convertirlo in 'STORAGE_BUS_TYPE'. –

3

Non sono sicuro se stai solo cercando di enumerare le lettere di unità? Il ciclo for di seguito lo fa, passando attraverso tutte le lettere, indipendentemente dal fatto che ci sia un disco per quella lettera.

Oppure, se stai cercando un modo diverso per trovare le unità rimovibili, c'è una funzione anche qui di seguito. (Il tuo potrebbe essere migliore ...) Sorprendentemente, sul mio test, Windows.GetDriveType NON considera le unità CD rimovibili. Le unità USB sono contrassegnate come rimovibili, come ci si aspetterebbe.

Function RemovableDrive(Drive: char): Boolean; 
    begin 
    Result := (Windows.GetDriveType(PChar(Drive + ':\')) = Windows.Drive_Removable); 
    end; 

    procedure TForm1.Button1Click(Sender: TObject); 
    var 
    Drive: Char; 
    begin 
    for Drive := 'A' to 'Z' do 
     Memo1.Lines.Add('Drive: ' + Drive + ' is ' + BoolToStr(RemovableDrive(Drive), TRUE)); 
    end; 
+0

Non funziona se si tratta di un disco rigido USB esterno, che secondo Windows è un disco fisso. Quindi ora vedi il motivo per cui ho postato la mia domanda originale :) –

4

È possibile accedere a queste informazioni tramite WMI. Se si utilizza questo SQL è possibile accedere alle informazioni sui dischi installati.

select * from Win32_diskdrive where size<>NULL 

Questo codice include informazioni sugli azionamenti.

procedure TForm1.DoInventario(aWSQL:string; var mmResult:TMemo); 
var 
    Locator:ISWbemLocator; 
    Services:ISWbemServices; 
    SObject:ISWbemObject; 
    ObjSet:ISWbemObjectSet; 
    Enum:IEnumVariant; 
    TempObj:OleVariant; 
    Value:Cardinal; 
    TS:TStrings; 
begin 

    try 
    Locator := CoSWbemLocator.Create(); 
    // Conectar con el Servicio de WMI 
    Services := Locator.ConnectServer(
     STR_LOCALHOST,  {ordenador local} 
     STR_CIM2_ROOT,  {root} 
     STR_EMPTY, STR_EMPTY, {usuario y password -en local no son necesarios-} 
     STR_EMPTY,STR_EMPTY, 0, nil); 
    // Acceder a los datos 
    ObjSet := Services.ExecQuery(aWSQL, 'WQL', 
       wbemFlagReturnImmediately and wbemFlagForwardOnly , nil); 
    Enum := (ObjSet._NewEnum) as IEnumVariant; 
    // Hemos encontrado algun objeto? 
    while (Enum.Next(1, TempObj, Value) = S_OK) do begin 
     SObject := IUnknown(TempObj) as ISWBemObject; 
     // encontrado? 
     if (SObject <> nil) then begin 
     // Acceder a la propiedad 
     SObject.Properties_; 
     // Cargamos las propiedades 
     TS := TStringList.Create(); 
     try 
      TS.Add(SObject.GetObjectText_(0)); 
      // lo pasamos al memo 
      mmResult.Lines.Text := mmResult.Lines.Text + TS.Text; 
     finally 
      FreeAndNil(TS); 
     end; 
     end; 
    end; 
    except 
    // Recuperar excepciones 
    end; 

end; 

È necessario aggiungere ActiveX e WbemScripting_TLB (questo deve essere importato) nei vostri usi. Con questo è possibile accedere a tutte le informazioni dei dischi.

Per retrive della lettera di tutti i dischi è possibile combinare (recuperare può fare con lo stesso codice) l'accesso alle classi Win32_LogicalDiskToPartition e Win32_DiskDrive.

select * from Win32_LogicalDiskToPartition 
select * from Win32_DiskDrive 

Se si cerca WMI è possibile trovare più codici correlati.

Saluti.

+0

Questa è un'ottima soluzione perché consente l'acquisizione di intere proprietà come la controparte cmd. – user2858981

Problemi correlati