Pregunta

En mi aplicación (Delphi), necesito a la lista de todos los dispositivos de almacenamiento USB. Estas pueden ser las tarjetas de memoria o unidades de almacenamiento externas.

Hay un componente Jvcl JvDriveCombo, y tiene la propiedad DriveType - el problema es si selecciono DriveType := Fixed entonces, además de la unidad externa, que también enumera las unidades internas (C:\, D:\ etc). Sin embargo, sólo quiero enumerar las unidades externas.

Creo que no es función de DeviceIoControl (lo vi en MSDN) pero no tengo ni idea de cómo usarlo.

Me pregunto si alguien me puede ayudar con el buen camino / código para dispositivos de almacenamiento USB lista?

Gracias.

EDIT:

acabo de encontrar algunos ejemplos de código y estoy publicando aquí:

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;

Ahora me gustaría simplemente saber cómo enumerar todas las letras de unidad. ¿Cuál es la función más eficiente?

¿Fue útil?

Solución

{$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;

Otros consejos

Se puede acceder a esta información mediante WMI. Si utiliza este SQL puede acceder a información acerca de los discos instalados.

select * from Win32_diskdrive where size<>NULL

Este código de información acerca de las unidades retrive.

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;

Debe añadir ActiveX y WbemScripting_TLB (esto debe ser importado) en sus usos. Con esto se puede acceder a toda la información de los discos.

Para retrive la carta de todos los discos se pueden combinar (recuperar puede hacer con el mismo código) el acceso a las clases Win32_LogicalDiskToPartition y Win32_DiskDrive .

select * from Win32_LogicalDiskToPartition
select * from Win32_DiskDrive

Si usted busca WMI puede encontrar más códigos relacionados.

Saludos.

No estoy seguro de si lo que buscas para enumerar las letras de unidad? El ciclo for a continuación hace que, pasando por todas las letras, independientemente de si hay una unidad de esa letra.

O, si usted está buscando una manera diferente de encontrar las unidades extraíbles, hay una función para la que a continuación, también. (El suyo puede ser mejor ...) Sorprendentemente, en mi prueba, Windows.GetDriveType NO considera como unidades de CD extraíble. unidades USB se marcan como extraíble, como era de esperar.

  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;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top