AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi IOCTL_STORAGE_GET_DEVICE_NUMBER, DRIVE_GEOMETRY und DRIVE_LAYOUT
Thema durchsuchen
Ansicht
Themen-Optionen

IOCTL_STORAGE_GET_DEVICE_NUMBER, DRIVE_GEOMETRY und DRIVE_LAYOUT

Ein Thema von Alter Mann · begonnen am 7. Sep 2010 · letzter Beitrag vom 8. Sep 2010
 
Alter Mann

Registriert seit: 15. Nov 2003
Ort: Berlin
937 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#1

IOCTL_STORAGE_GET_DEVICE_NUMBER, DRIVE_GEOMETRY und DRIVE_LAYOUT

  Alt 7. Sep 2010, 12:48
Hallo,

hier ein kleines Beispiel für die Verwendung von IOCTL_STORAGE_GET_DEVICE_NUMBER, IOCTL_DISK_GET_DRIVE_GEOMETRY und IOCTL_DISK_GET_DRIVE_LAYOUT.
Damit es läuft braucht man die jwaWinIOCTL bzw. die entsprechenden Deklaration(en).

Kernstück ist die Unit uDevice:
Delphi-Quellcode:
unit uDevice;

interface

uses
  Classes, Windows, jwaWindows;

type
  TDeviceRec = record
    DeviceNr : DWORD;
    DeviceStr : String;
    DriveStr : String;
    PartitionStr : String;
    PartitionNr : DWORD;
    DeviceTyp : DEVICE_TYPE;
    DiskGeometry : DISK_GEOMETRY;
    PartitionData : PARTITION_INFORMATION;
  end;

  TDynDeviceRec = record
    DeviceNr : DWORD;
    DeviceStr : String;
    DiskGeometry : DISK_GEOMETRY;
    PartitionData : Array of PARTITION_INFORMATION;
    MediaTypeStr : String;
  end;

  TDeviceRecList = Array of TDeviceRec;
  TDynDeviceRecList = Array of TDynDeviceRec;

function GetAllLogicalDevices(var aDeviceRecList : TDeviceRecList) : Boolean;
function GetAllPhysicalDevices(var aDynDeviceRecList : TDynDeviceRecList) : Boolean;

implementation

uses SysUtils;

function MediaTypeToStr(aMediaType : MEDIA_TYPE) : String;
begin
  case aMediatype of
    Unknown : Result := 'UNKNOWN';
    F5_1Pt2_512 : Result := '5.25" floppy, with 1.2MB and 512 bytes/sector';
    F3_1Pt44_512 : Result := '3.5" floppy, with 1.44MB and 512 bytes/sector';
    F3_2Pt88_512 : Result := '3.5" floppy, with 2.88MB and 512 bytes/sector';
    F3_20Pt8_512 : Result := '3.5" floppy, with 20MB and 512 bytes/sector';
    F3_720_512 : Result := '3.5" floppy, with 720KB and 512 bytes/sector';
    F5_360_512 : Result := '5.25" floppy, with 360KB and 512 bytes/sector';
    F5_320_512 : Result := '5.25" floppy, with 320KB and 512 bytes/sector';
    F5_320_1024 : Result := '5.25" floppy, with 360KB and 1024 bytes/sector';
    F5_180_512 : Result := '5.25" floppy, with 180KB and 512 bytes/sector';
    F5_160_512 : Result := '5.25" floppy, with 160KB and 512 bytes/sector';
    RemovableMedia : Result := 'Removable media other than floppy';
    FixedMedia : Result := 'Fixed hard disk media';
    F3_120M_512 : Result := '3.5" floppy, with 120MB and 512 bytes/sector';
    F3_640_512 : Result := '3.5" floppy, with 640MB and 512 bytes/sector';
    F5_640_512 : Result := '5.25" floppy, with 640KB and 512 bytes/sector';
    F5_720_512 : Result := '5.25" floppy, with 720KB and 512 bytes/sector';
    F3_1Pt2_512 : Result := '3.5" floppy, with 1.2MB and 512 bytes/sector';
    F3_1Pt23_1024 : Result := '3.5" floppy, with 1.23MB and 1024 bytes/sector';
    F5_1Pt23_1024 : Result := '5.25" floppy, with 1.23KB and 1024 bytes/sector';
    F3_128Mb_512 : Result := '3.5" floppy, with 128MB and 512 bytes/sector';
    F3_230Mb_512 : Result := '3.5" floppy, with 230MB and 512 bytes/sector';
    F8_256_128 : Result := '8" floppy, with 256KB and 128 bytes/sector';
    F3_200Mb_512 : Result := '3.5" floppy, with 200MB and 512 bytes/sector. (HiFD)';
    F3_240M_512 : Result := '3.5" floppy, with 240MB and 512 bytes/sector. (HiFD)';
    F3_32M_512 : Result := '3.5" floppy, with 32MB and 512 bytes/sector';
  end;
end;

function DeviceTypeToStr(aDeviceType : DEVICE_TYPE):String;
begin
  case aDeviceType of
    FILE_DEVICE_BEEP : Result :='BEEP';
    FILE_DEVICE_CD_ROM : Result :='CD-ROM';
    FILE_DEVICE_CD_ROM_FILE_SYSTEM : Result :='CD-ROM FILE-SYSTEM';
    FILE_DEVICE_CONTROLLER : Result :='CONTROLLER';
    FILE_DEVICE_DATALINK : Result :='DATALINK';
    FILE_DEVICE_DFS : Result :='DFS';
    FILE_DEVICE_DISK : Result :='DISK';
    FILE_DEVICE_DISK_FILE_SYSTEM : Result :='DISK FILE-SYSTEM';
    FILE_DEVICE_FILE_SYSTEM : Result :='FILE-SYSTEM';
    FILE_DEVICE_INPORT_PORT : Result :='INPORT-PORT';
    FILE_DEVICE_KEYBOARD : Result :='KEYBOARD';
    FILE_DEVICE_MAILSLOT : Result :='MAILSLOT';
    FILE_DEVICE_MIDI_IN : Result :='MIDI_IN';
    FILE_DEVICE_MIDI_OUT : Result :='MIDI_OUT';
    FILE_DEVICE_MOUSE : Result :='MOUSE';
    FILE_DEVICE_MULTI_UNC_PROVIDER : Result :='MULTI UNC-PROVIDER';
    FILE_DEVICE_NAMED_PIPE : Result :='NAMED-PIPE';
    FILE_DEVICE_NETWORK : Result :='NETWORK';
    FILE_DEVICE_NETWORK_BROWSER : Result :='NETWORK-BROWSER';
    FILE_DEVICE_NETWORK_FILE_SYSTEM : Result :='NETWORK FILE-SYSTEM';
    FILE_DEVICE_NULL : Result :='NULL';
    FILE_DEVICE_PARALLEL_PORT : Result :='PARALLEL-PORT';
    FILE_DEVICE_PHYSICAL_NETCARD : Result :='PHYSICAL-NETCARD';
    FILE_DEVICE_PRINTER : Result :='PRINTER';
    FILE_DEVICE_SCANNER : Result :='SCANNER';
    FILE_DEVICE_SERIAL_MOUSE_PORT : Result :='SERIAL MOUSE-PORT';
    FILE_DEVICE_SERIAL_PORT : Result :='SERIAL-PORT';
    FILE_DEVICE_SCREEN : Result :='SCREEN';
    FILE_DEVICE_SOUND : Result :='SOUND';
    FILE_DEVICE_STREAMS : Result :='STREAMS';
    FILE_DEVICE_TAPE : Result :='TAPE';
    FILE_DEVICE_TAPE_FILE_SYSTEM : Result :='TAPE FILE-SYSTEM';
    FILE_DEVICE_TRANSPORT : Result :='TRANSPORT';
    FILE_DEVICE_UNKNOWN : Result :='UNKNOWN';
    FILE_DEVICE_VIDEO : Result :='VIDEO';
    FILE_DEVICE_VIRTUAL_DISK : Result :='VIRTUAL-DISK';
    FILE_DEVICE_WAVE_IN : Result :='WAVE_IN';
    FILE_DEVICE_WAVE_OUT : Result :='WAVE_OUT';
    FILE_DEVICE_8042_PORT : Result :='8042-PORT';
    FILE_DEVICE_NETWORK_REDIRECTOR : Result :='NETWORK-REDIRECTOR';
    FILE_DEVICE_BATTERY : Result :='BATTERY';
    FILE_DEVICE_BUS_EXTENDER : Result :='BZS EXTENDER';
    FILE_DEVICE_MODEM : Result :='MODEM';
    FILE_DEVICE_VDM : Result :='VDM';
    FILE_DEVICE_MASS_STORAGE : Result :='MASS-STORAGE';
    FILE_DEVICE_SMB : Result :='SMB';
    FILE_DEVICE_KS : Result :='KS';
    FILE_DEVICE_CHANGER : Result :='CHANGER';
    FILE_DEVICE_SMARTCARD : Result :='SMARTCARD';
    FILE_DEVICE_ACPI : Result :='ACPI';
    FILE_DEVICE_DVD : Result :='DVD';
    FILE_DEVICE_FULLSCREEN_VIDEO : Result :='FULLSCREEN VIDEO';
    FILE_DEVICE_DFS_FILE_SYSTEM : Result :='DFS FILE-SYSTEM';
    FILE_DEVICE_DFS_VOLUME : Result :='DFS-VOLUME';
    FILE_DEVICE_SERENUM : Result :='SERENUM';
    FILE_DEVICE_TERMSRV : Result :='TERMINAL-SERVER';
    FILE_DEVICE_KSEC : Result :='KSEC';
    FILE_DEVICE_FIPS : Result :='FIPS';
    FILE_DEVICE_INFINIBAND : Result :='INFINIBAND';
    else Result := IntToStr(aDeviceType);
  end;
end;

function DeviceExists(aDeviceNumber : DWORD) : Boolean;
var
  hVolume : THandle;
begin
  hVolume := CreateFile(PChar(Format('\\.\PHYSICALDRIVE%d', [aDeviceNumber])),
                        GENERIC_READ,
                        FILE_SHARE_READ or FILE_SHARE_WRITE,
                        nil,
                        OPEN_EXISTING, 0, 0);
  CloseHandle(hVolume);
  Result := hVolume <> INVALID_HANDLE_VALUE;
end;

function GetDeviceNumber(const aDriveLetter : PChar;
                         var aDeviceRec : TDeviceRec) : Boolean; overload;
var
  pVolume : PChar;
  dwSize : DWORD;
  hVolume : THandle;
  SDN : STORAGE_DEVICE_NUMBER;
  DG : DISK_GEOMETRY;
  pDLI : PDRIVE_LAYOUT_INFORMATION;
  lpBytesReturned : DWORD;
  Ret,
  dliSize : Integer;
begin
  Ret := -1;
  dwSize := 6;
  pVolume := StrAlloc(dwSize);
  try
    StrPCopy(pVolume, Format('\\.\%s:', [Copy(aDriveLetter, 1, 1)]));
    hVolume := CreateFile(pVolume,
                          GENERIC_READ,
                          FILE_SHARE_READ or FILE_SHARE_WRITE,
                          nil,
                          OPEN_EXISTING, 0, 0);
    if hVolume <> INVALID_HANDLE_VALUE then
    begin
      if DeviceIOControl(hVolume,
                         IOCTL_STORAGE_GET_DEVICE_NUMBER,
                         nil,
                         0,
                         @SDN,
                         SizeOf(SDN),
                         @lpBytesReturned,
                         nil) then
      begin
        Ret := SDN.DeviceNumber;
        with aDeviceRec do
        begin
          DeviceNr := Ret;
          PartitionNr := SDN.PartitionNumber;
          DeviceTyp := SDN.DeviceType;
          DriveStr := Format('%s:\', [aDriveLetter]);
          case SDN.DeviceType of
            FILE_DEVICE_DISK : DeviceStr := Format('\\.\PHYSICALDRIVE%d', [DeviceNr]);
            else DeviceStr := Format('DEVICE: %s ', [DeviceTypeToStr(DeviceTyp)]);
          end;
          PartitionStr := Format('Partition%d', [PartitionNr]);
        end;
      end;

      if DeviceIOControl(hVolume,
                         IOCTL_DISK_GET_DRIVE_GEOMETRY,
                         nil,
                         0,
                         @DG,
                         SizeOf(DG),
                         @lpBytesReturned,
                         nil) then
        aDeviceRec.DiskGeometry := DG;

      // Für den folgenden Aufruf müssen wir ausreichend Speicher reserviren
      // Falls ich ein Fragt warum 16 Partitionen, sollte sich gesondert informieren;-)
      dliSize := SizeOf(DRIVE_LAYOUT_INFORMATION) + (15 * SizeOf(PARTITION_INFORMATION));
      // Wir nutzen GetMem da DRIVE_LAYOUT_INFORMATION.PartitionCount ein
      // statisches Array ist
      GetMem(pDLI, dliSize);

      if DeviceIOControl(hVolume,
                         IOCTL_DISK_GET_DRIVE_LAYOUT,
                         nil,
                         0,
                         pDLI,
                         dliSize,
                         @lpBytesReturned,
                         nil) then
      begin
        // Hier verkürzen wir das ganze, da wir ja wissen welche Partition
        // wir auslesen wollen
        aDeviceRec.PartitionData := pDLI^.PartitionEntry[aDeviceRec.PartitionNr-1];
        // Und geben den Speicher wieder frei
        FreeMem(pDLI, dliSize);
      end;

      CloseHandle(hVolume);
    end;
  finally
    StrDispose(pVolume);
  end;
  Result := Ret > -1;
end;

function GetDeviceNumber(const aPhysicalDrive : Byte;
                         var aDynDeviceRec : TDynDeviceRec) : Boolean; overload;
var
  pVolume : PChar;
  dwSize : DWORD;
  hVolume : THandle;
  DG : DISK_GEOMETRY;
  pDLI : PDRIVE_LAYOUT_INFORMATION;
  lpBytesReturned : DWORD;
  I, piCount,
  dliSize : Integer;
begin
  Result := false;
  dwSize := Length(Format('\\.\PHYSICALDRIVE%d', [aPhysicalDrive])) + 1;
  pVolume := StrAlloc(dwSize);
  try
    StrPCopy(pVolume, Format('\\.\PHYSICALDRIVE%d', [aPhysicalDrive]));
    hVolume := CreateFile(pVolume,
                          GENERIC_READ,
                          FILE_SHARE_READ or FILE_SHARE_WRITE,
                          nil,
                          OPEN_EXISTING, 0, 0);
    if hVolume <> INVALID_HANDLE_VALUE then
    begin
      aDynDeviceRec.DeviceNr := aPhysicalDrive;
      aDynDeviceRec.DeviceStr:= pVolume;
      if DeviceIOControl(hVolume,
                         IOCTL_DISK_GET_DRIVE_GEOMETRY,
                         nil,
                         0,
                         @DG,
                         SizeOf(DG),
                         @lpBytesReturned,
                         nil) then
        begin
          aDynDeviceRec.DiskGeometry := DG;
          aDynDeviceRec.MediaTypeStr := MediaTypeToStr(DG.MediaType);
        end;
        // Für den folgenden Aufruf müssen wir ausreichend Speicher reserviren
        // Falls sich ein Fragt warum 16 Partitionen, sollte er sich
        // gesondert informieren;-)
        dliSize := SizeOf(DRIVE_LAYOUT_INFORMATION) + (15 * SizeOf(PARTITION_INFORMATION));
        // Wir nutzen GetMem da DRIVE_LAYOUT_INFORMATION.PartitionCount ein
        // statisches Array ist
        GetMem(pDLI, dliSize);

        if DeviceIOControl(hVolume,
                           IOCTL_DISK_GET_DRIVE_LAYOUT,
                           nil,
                           0,
                           pDLI,
                           dliSize,
                           @lpBytesReturned,
                           nil) then
        begin
          // IOCTL_DISK_GET_DRIVE_LAYOUT bringt in
          // DRIVE_LAYOUT_INFORMATION.PartitionCount immer 4 zurück
          // egal ob 1, 2 oder mehr Primärepartitionen vorhanden sind.
          piCount := 0;
          for I := 0 to pDLI^.PartitionCount - 1 do
          begin
           if pDLI^.PartitionEntry[I].StartingOffset.LowPart = 0 then Break;
           Inc(piCount);
          end;
          SetLength(aDynDeviceRec.PartitionData, piCount);
          for I := 0 to piCount-1 do
           aDynDeviceRec.PartitionData[I] := pDLI^.PartitionEntry[I];
          // Speicher wieder freigeben
          FreeMem(pDLI, dliSize);
        end;
        CloseHandle(hVolume);
        Result := true;
    end;
  finally
    StrDispose(pVolume);
  end;
end;


function GetAllLogicalDevices(var aDeviceRecList : TDeviceRecList) : Boolean;
var
  drives : DWORD;
  letter : Char;
  SL : TStringList;
begin
  SL := TStringList.Create;
  try
     for letter := 'Cto 'Zdo
       case GetDriveType(PChar(letter + ':\')) of
        DRIVE_REMOVABLE : SL.Add(letter);
        DRIVE_FIXED : SL.Add(Letter);
       end;
     Result := SL.Count > 0;
     if Result then
     begin
       SetLength(aDeviceRecList, SL.Count);
       for drives := 0 to SL.Count - 1 do
        GetDeviceNumber(PChar(SL.Strings[drives]), aDeviceRecList[drives]);
     end;
  finally
    SL.Free;
  end;
end;

function GetAllPhysicalDevices(var aDynDeviceRecList : TDynDeviceRecList) : Boolean;
var
  I : Byte;
  J : Byte;
  C : Byte;
  DR : TDynDeviceRec;
begin
  C := 0;
  SetLength(aDynDeviceRecList, HIGH(Byte));
  for I := 0 to HIGH(BYTE) do
  begin
    if DeviceExists(I) then
    begin
      if GetDeviceNumber(I, DR) then
      begin
        try
          with aDynDeviceRecList[C] do
          begin
            DeviceNr := DR.DeviceNr;
            DeviceStr := DR.DeviceStr;
            DiskGeometry := DR.DiskGeometry;
            MediaTypeStr := DR.MediaTypeStr;
            SetLength(PartitionData, Length(DR.PartitionData));
            for J := 0 to Length(DR.PartitionData) - 1 do
            PartitionData[J] := DR.PartitionData[J];
          end;
          Inc(C);
        except
        end;
      end;
    end;
  end;
  SetLength(aDynDeviceRecList, C);
  Result := Length(aDynDeviceRecList) > 0;
end;

end.
Und das Formular:
Delphi-Quellcode:
unit frmMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ActnList, Menus, ComCtrls, uDevice;

type
  TMainForm = class(TForm)
    ActionList1: TActionList;
    MainMenu1: TMainMenu;
    mnuFile: TMenuItem;
    mnuDevice: TMenuItem;
    _aDummy: TAction;
    aFileExit: TAction;
    aDeviceLogical: TAction;
    aDevicePhysical: TAction;
    mnuFileExit: TMenuItem;
    mnuDeviceLogical: TMenuItem;
    N1: TMenuItem;
    mnuDevicePhysical: TMenuItem;
    tvDevices: TTreeView;
    procedure aFileExitExecute(Sender: TObject);
    procedure aDeviceLogicalExecute(Sender: TObject);
    procedure aDevicePhysicalExecute(Sender: TObject);
  private
    { Private-Deklarationen }
    DRL : TDeviceRecList;
    DDRL: TDynDeviceRecList;

    function FindRootNode(aName : String; aTreeView : TTreeView) : TTreeNode;
    procedure ClearList;
  public
    { Public-Deklarationen }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

procedure TMainForm.aDeviceLogicalExecute(Sender: TObject);
var
  I : Integer;
  R : TTreeNode;
begin
  tvDevices.Items.BeginUpdate;
  tvDevices.Items.Clear;
  ClearList;
  if GetAllLogicalDevices(DRL) then
  begin
    for I := 0 to Length(DRL) -1 do
    begin
      R := FindRootNode(DRL[I].DeviceStr, tvDevices);
      if R <> nil then
        tvDevices.Items.AddChild(R, Format('%s (%s)', [DRL[I].PartitionStr, DRL[I].DriveStr]))
      else
      begin
        R := tvDevices.Items.AddChild(nil, DRL[I].DeviceStr);
        tvDevices.Items.AddChild(R, Format('%s (%s)', [DRL[I].PartitionStr, DRL[I].DriveStr]));
      end;
    end;
    tvDevices.Items.AlphaSort();
  end;
  tvDevices.Items.EndUpdate;
end;

procedure TMainForm.aDevicePhysicalExecute(Sender: TObject);
var
  I,
  J : Integer;
  N,
  R : TTreeNode;
begin
  tvDevices.Items.BeginUpdate;
  tvDevices.Items.Clear;
  ClearList;
  if GetAllPhysicalDevices(DDRL) then
  begin
    for I := 0 to Length(DDRL) -1 do
    begin
      R := FindRootNode(DDRL[I].DeviceStr, tvDevices);
      if R <> nil then
        tvDevices.Items.AddChild(R, Format('%s ', [DDRL[I].MediaTypeStr]))
      else
      begin
        R := tvDevices.Items.AddChild(nil, DDRL[I].DeviceStr);
        N := tvDevices.Items.AddChild(R, Format('%s ', [DDRL[I].MediaTypeStr]));
        for J := 0 to Length(DDRL[I].PartitionData) -1 do
         tvDevices.Items.AddChild(N, Format('Partition%d', [J]));
      end;
    end;
    tvDevices.Items.AlphaSort();
  end;
  tvDevices.Items.EndUpdate;
end;

procedure TMainForm.aFileExitExecute(Sender: TObject);
begin
  ClearList;
  Close;
end;

function TMainForm.FindRootNode(aName : String; aTreeView : TTreeView) : TTreeNode;
var
  I : Integer;
begin
  Result := nil;
  aTreeView.Items.BeginUpdate;
  for I := 0 to aTreeView.Items.Count - 1 do
   if aTreeView.Items[I].Text = aName then
   begin
     Result := aTreeView.Items[I];
     Break;
   end;
  aTreeView.Items.EndUpdate;
end;

procedure TMainForm.ClearList;
var
  I : Integer;
begin
  if Length(DDRL) > 0 then
  begin
    for I := Length(DDRL) -1 downto 0 do
      if Length(DDRL[I].PartitionData) > 0 then
        SetLength(DDRL[I].PartitionData, 0);
    SetLength(DDRL, 0);
  end;
  if Length(DRL) > 0 then SetLength(DRL, 0);
end;

end.
Siehe auch Anhang. Ich gebe ja zu ein wenig Optimierung könnte das ganze vertragen

Falls es Fragen gibt, fragen.

Viele Grüße
Angehängte Dateien
Dateityp: zip DeviceInfo.zip (25,9 KB, 63x aufgerufen)

Geändert von Alter Mann ( 8. Sep 2010 um 10:20 Uhr)
  Mit Zitat antworten Zitat
 


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:27 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz