2010-09-15 9 views
12

W mojej aplikacji (Delphi), muszę wyświetlić listę wszystkich urządzeń pamięci masowej USB. Mogą to być dyski flash z pamięcią flash lub Zewnętrzne dyski do przechowywania danych.Delphi - Jak uzyskać listę przenośnych dysków twardych USB i kart pamięci?

Jest Jvcl komponent JvDriveCombo i ma właściwość DriveType - problem jest, jeśli wybiorę DriveType := Fixed wtedy oprócz dysku zewnętrznym, ale także listę napędów wewnętrznych (C:\, D:\ etc). Jednak chcę tylko wymienić dyski zewnętrzne.

Wierzę, że istnieje funkcja DeviceIoControl (widziałem to na MSDN), ale nie mam pojęcia, jak z niego korzystać.

Zastanawiam się, czy ktoś może mi pomóc w prawidłowy sposób/kod do listy urządzeń pamięci USB?

Dzięki.

EDIT:

Właśnie znalazłem przykładowy kod i zamieszczam go tutaj:

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; 

Teraz chciałbym tylko wiedzieć, w jaki sposób wyliczyć wszystkie litery dysków. Która funkcja jest najbardziej wydajna?

Odpowiedz

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

Działa! dzięki za twój kłopot! –

+1

idealny, ale czy "{MINNEUZMIANIE 4}" jest naprawdę potrzebny? – Peter

+1

@Peter Cóż, pole 'BusType' powinno zajmować 4 bajty. Zwykle Delphi przydzieliłby tylko tyle bajtów, ile potrzeba, aby zapisać dowolną wartość wyliczenia (w tym przypadku 1 bajt), chyba że podasz minimalny rozmiar wyliczenia za pomocą dyrektywy '$ MINENUMSIZE'. Możesz także zadeklarować 'BusType' jako' DWORD' i typować go na 'STORAGE_BUS_TYPE'. –

3

Nie jestem pewien, czy chcesz tylko wyliczyć litery dysków? Poniższa pętla for wykonuje to, przechodząc przez wszystkie litery, niezależnie od tego, czy istnieje napęd dla tej litery.

Jeśli szukasz innego sposobu na znalezienie dysków wymiennych, możesz skorzystać z poniższej funkcji. (Twój może być lepszy ...) Zaskakująco, na moim teście, Windows.GetDriveType NIE uważa dysków CD jako wymiennych. Napędy USB są oznaczane jako wymienne, jak można się spodziewać.

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

Nie działa, jeśli jest to zewnętrzny dysk twardy USB, który zgodnie z systemem Windows jest dyskiem stałym. Więc teraz widzisz powód, dla którego napisałem moje oryginalne pytanie :) –

4

Można uzyskać dostęp do tej informacji za pomocą WMI. Jeśli używasz tego kodu SQL, możesz uzyskać dostęp do informacji o zainstalowanych dyskach.

select * from Win32_diskdrive where size<>NULL 

Kod ten przekazuje informacje o napędach.

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; 

Należy dodać ActiveX i WbemScripting_TLB (musi to być importowane) w swoich zastosowaniach. Dzięki temu można uzyskać dostęp do wszystkich informacji na temat dysków.

Aby sprowadzaniu list wszystkich dysku można połączyć (pobrać można zrobić z tego samego kodu) dostępu do klas Win32_LogicalDiskToPartition i Win32_DiskDrive.

select * from Win32_LogicalDiskToPartition 
select * from Win32_DiskDrive 

W przypadku wyszukiwania w usłudze WMI można znaleźć więcej powiązanych kodów.

Pozdrawiam.

+0

To świetne rozwiązanie, ponieważ pozwala przechwytywać całe właściwości, takie jak odpowiednik cmd. – user2858981

Powiązane problemy