AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX

Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX

Ein Thema von Captnemo · begonnen am 8. Okt 2015 · letzter Beitrag vom 11. Okt 2015
Antwort Antwort
Seite 1 von 2  1 2   
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#1

Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX

  Alt 8. Okt 2015, 12:11
Ich will meine Partitionen auslesen, und deren Zugehörigkeit zu den Harddisks.


Hier mal die Deklaration (das ist die von Hier)
Delphi-Quellcode:
  Type
    PARTITION_STYLE = type Integer;

    PARTITION_INFORMATION_MBR = record
      PartitionType: Byte;
      BootIndicator: BOOL;
      RecognizedPartition: BOOL;
      HiddenSecorts: DWORD;
    end;

    PARTITION_INFORMATION_GPT = record
      PartitonType: TGUID;
      PartitionId: TGUID;
      Attributes: DWORD64;
      Name: WCHAR;
    end;

    _PARTITION_INFORMATION_EX = record
      PartitionStyle: PARTITION_STYLE;
      StartingOffset: LARGE_INTEGER;
      PartitionLength: LARGE_INTEGER;
      PartitionNumber: ULONG;
      RewritePartition: Boolean;
      case Integer of
       0: (Mbr: PARTITION_INFORMATION_MBR);
       1: (Gpt: PARTITION_INFORMATION_GPT);
    end;

    DRIVE_LAYOUT_INFORMATION_MBR = record
      Signature: ULONG;
    end;

    DRIVE_LAYOUT_INFORMATION_GPT = record
      DiskID: TGUID;
      StartingusableOffset: LARGE_INTEGER;
      UsableLength: LARGE_INTEGER;
      MaxPartitionCount: ULONG;
    end;

    DRIVE_LAYOUT_INFORMATION_EX = record
      PartitionStyle: DWORD;
      PartitionCount: DWORD;
      DriveLayoutInfoType: record
        case Integer of
          0: (Mbr: DRIVE_LAYOUT_INFORMATION_MBR);
          1: (Gpt: DRIVE_LAYOUT_INFORMATION_GPT);
      end;
      PartitionInfoEx: array[0..10] of _PARTITION_INFORMATION_EX;
    end;

  const
    PARTITION_STYLE_MBR = PARTITION_STYLE(0);
    PARTITION_STYLE_GPT = PARTITION_STYLE(1);
    PARTITION_STYLE_RAW = PARTITION_STYLE(2);
Und es scheint auch soweit zu funktionieren. Allerdings habe ich noch Probleme mit PartitionInfoEx: array[0..10] of _PARTITION_INFORMATION_EX . Ich habe in diversen Posts gelesen, dass es PartitionInfoEx: array[0..0] of _PARTITION_INFORMATION_EX lauten soll. Aber dann erhalte ich gar keine Informationen.

Hier mal meine Procedure, mit der ich die Daten abfrage:
Delphi-Quellcode:
procedure TForm1.btn2Click(Sender: TObject);
var
  RetBytes: DWORD;
  hDevice: Cardinal;
  Status: LongBool;
  Drive: string;
  Layout: DRIVE_LAYOUT_INFORMATION_EX;
  I,p: Integer;
begin
  for I := 0 to 15 do
  begin
    Drive:='\\.\PhysicalDrive'+IntToStr(i);
    hDevice:=CreateFile(PChar(Drive), 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
    if hDevice<>INVALID_HANDLE_VALUE then
    begin
      Status:=DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, nil, 0, @Layout, SizeOf(DRIVE_LAYOUT_INFORMATION_EX), RetBytes, nil);
      if (Status=False) then
        mmo1.lines.Add(IntToStr(i)+'. Festplatte abfrage fehlgeschalten') else
      begin
        mmo1.Lines.Add(IntToStr(i)+'. Festplatte = '+inttostr(Layout.PartitionCount)+' Partitionen');
        for p := 0 to Layout.PartitionCount-1 do
        begin
          if (Layout.partitionInfoEx[p].StartingOffset.QuadPart<>0) and (Layout.partitionInfoEx[p].PartitionLength.QuadPart<>0) then
          begin
            mmo1.Lines.Add(' '+inttostr(p)+'. Partition: ');
            case Layout.partitionInfoEx[p].PartitionStyle of
              PARTITION_STYLE_MBR: mmo1.Lines.Add(' Part-Typ : MBR');
              PARTITION_STYLE_GPT: mmo1.Lines.Add(' Part-Typ : GPT');
              PARTITION_STYLE_RAW: mmo1.Lines.Add(' Part-Typ : RAW');
            end;
            mmo1.lines.Add(' PartitionNr: '+IntToStr(Layout.partitionInfoEx[p].PartitionNumber));
            mmo1.Lines.Add(' StartSektor: '+IntToStr(Layout.partitionInfoEx[p].StartingOffset.QuadPart));
            mmo1.lines.Add(' Länge : '+IntToStr(Layout.partitionInfoEx[p].PartitionLength.QuadPart));
            mmo1.Lines.Add(' Größe : '+GetSizeAsString(Layout.partitionInfoEx[p].PartitionLength.QuadPart));
          end;
        end;
      end;
      CloseHandle(hDevice);
    end else mmo1.lines.Add(IntToStr(i)+'. Festplatte hat kein hDeviceHandle');
  end;

end;

function TForm1.GetSizeAsString(Size: Int64): string;
var
  new: Extended;
  Sign: String;
  c: Integer;
begin
  c:=0;
  new:=Size;
  while new>1024 do
  begin
    new:=new/1024;
    Inc(c);
  end;
  case c of
    0: Sign:=' Byte';
    1: Sign:=' KB';
    2: Sign:=' MB';
    3: Sign:=' GB';
    4: Sign:=' TB';
    5: Sign:=' PB';
    6: Sign:=' EB';
    7: Sign:=' ZB';
    8: Sign:=' YB';
  else
    Sign:=' ('+intToStr(c)+')';
  end;
  Result:=FormatFloat('#,##0.00', new)+Sign;
end;
Ich wäre nach dem was ich gelesen habe mal davon ausgegangen, dass das Array partitionInfoEx hinterher der Partitionsanzahl entsprechende Elemente beinhaltet. Dem ist aber nicht so. Wenn ich es mit 0..0 deklariere, dann ist bleibt es eben auch leer, und wenn ich z.B. 0..10 deklariere, dann erhalte ich auch 11 Elemente, die dann aber eben zum Teil uninitialisierte Werte enthalten (ist klar).
Ich will ja hinterher in partitionInfoEx eben nur die Partitionen haben, die auf dem Datenträger auch existieren.

Gut, nun gibt es ja auch noch PartitionCount aus DRIVE_LAYOUT_INFORMATION_EX. Diese liefert mir aber entweder 0, 1 oder 4.

Meine Aufteilung sie in der Datenträgerverwaltung so aus:
1. HDD
1. Partition 350 MB System-reserved
2. Partition 931,17 GB c:
2. HDD
1. Partition 931,51 GB D:
3. HDD
Keine Partition. Ist der CardReader ohne Karte
4. HDD
1. Partition 1000,00 GB I: (ist tatsächlich iSCSi von meinem NAS, deswegen genau 1000 GB);

Wenn ich mein Testprogramm starte bekomme ich folgendes:

Code:
0. Festplatte = 4 Partitionen
  0. Partition:
    Part-Typ  : MBR
    PartitionNr: 1
    StartSektor: 1048576
    Länge     : 367001600
    Größe     : 350,00 MB
  2. Partition:
    PartitionNr: 0
    StartSektor: 2
    Länge     : 3087428650860807
    Größe     : 2,74 PB
1. Festplatte = 4 Partitionen
  0. Partition:
    Part-Typ  : MBR
    PartitionNr: 1
    StartSektor: 1048576
    Länge     : 1000202043392
    Größe     : 931,51 GB
  1. Partition:
    PartitionNr: 3429319
    StartSektor: 2421637
    Länge     : 4213862
    Größe     : 4,02 MB
  3. Partition:
    PartitionNr: 3654587
    StartSektor: 2787577
    Länge     : 2128090
    Größe     : 2,03 MB
2. Festplatte = 1 Partitionen
3. Festplatte = 4 Partitionen
  0. Partition:
    Part-Typ  : MBR
    PartitionNr: 1
    StartSektor: 1048576
    Länge     : 1073738678272
    Größe     : 1.000,00 GB

Die Partitionen mit Länge 0 oder StartSector 0 ignoriere ich mal.
Bei der letzten HDD und beim CardReader stimmt das ja auch soweit.
Aber bei meiner Bootplatte wird die 2. Partition mit Startsektor 0 oder Länge 0 ausgelese und eine 2. Partition mit einer wünschenswerten Größe angezeigt.
Und bei der 2. Platte, wird zwar die 1. Partition richtig ausgelesen, aber aufgrund des PartitiionCount, mütte ich von 4 Partitionen ausgehen.

Was mache ich noch falsch, bzw. wie kann man das besser lösen. Warum bekomme ich teilweise PartitionCount von 4?

Ich hab mal das Testprojekt angehängt.
Angehängte Dateien
Dateityp: rar PartitionTest.rar (652,6 KB, 37x aufgerufen)
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#2

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX

  Alt 8. Okt 2015, 13:01
Ich glaube hier ist dein Problem mit den Puffern:
Zitat:
If the output buffer is too small to hold all of the data but can hold some entries, some drivers will return as much data as fits. In this case, the call fails, GetLastError returns ERROR_MORE_DATA, and lpBytesReturned indicates the amount of data received.
Zum Glück kannst du den danach den Aufruf nochmal mit einem größerem dynamisch allozierten Puffer wiederholen, den du dann auf DRIVE_LAYOUT_INFORMATION_EX castest.

PartitionInfoEx: array[0..0] of _PARTITION_INFORMATION_EX ist quasi der Hinweis an den Compiler, das hinter dem Record/Header noch ein Array mit diesem Typ hängt. Um den Speicher dafür musst du dich selbst kümmern.
  Mit Zitat antworten Zitat
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#3

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX

  Alt 8. Okt 2015, 13:02
Bin je wieder einen Schritt weiter.
PartitionCount liefert bei MBR-Partitionen immer ein vielfaches von 4 zurück. Das erklärt schon mal, warum also immer 4 dort steht.

Also muss man anders an die Information, welche Partitionen denn nun wirklich exstieren.
Dabei hilft DRIVE_LAYOUT_INFORMATION_EX.PartitionInfoEx[p].Mbr.PartitionType, worin im Falle von MBR diese Information gefunden werden kann.

Delphi-Quellcode:
Const
    PARTITION_ENTRY_UNUSED = $00;
    PARTITION_EXTENDED = $05;
    PARTITION_FAT_12 = $01;
    PARTITION_FAT_16 = $04;
    PARTITION_FAT32 = $0B;
    PARTITION_IFS = $07;
    PARTITION_LDM = $42;
    PARTITION_NTFT = $80;
    VALID_NTFT = $C0;

.
.
.

            if Layout.PartitionInfoEx[p].PartitionStyle=PARTITION_STYLE_MBR then
            begin
              case Layout.PartitionInfoEx[p].Mbr.PartitionType of
                PARTITION_ENTRY_UNUSED: mmo1.lines.Add(' Part-Style : PARTITION_ENTRY_UNUSED');
                PARTITION_EXTENDED: mmo1.lines.Add(' Part-Style : PARTITION_EXTENDED');
                PARTITION_FAT_12: mmo1.lines.Add(' Part-Style : PARTITION_FAT_12');
                PARTITION_FAT_16: mmo1.lines.Add(' Part-Style : PARTITION_FAT_16');
                PARTITION_FAT32: mmo1.lines.Add(' Part-Style : PARTITION_FAT32');
                PARTITION_IFS: mmo1.lines.Add(' Part-Style : PARTITION_IFS');
                PARTITION_LDM: mmo1.lines.Add(' Part-Style : PARTITION_LDM');
                PARTITION_NTFT: mmo1.lines.Add(' Part-Style : PARTITION_NTFT');
                VALID_NTFT: mmo1.lines.Add(' Part-Style : VALID_NTFT');
              else
                mmo1.lines.Add(' Part-Style : Unbekannt');
              end;
            end;
das Ergebnis schaut jetzt so aus:
Code:
1. Festplatte = 4 Partitionen
  1. Partition:
    Part-Typ  : MBR
    Part-Style : PARTITION_IFS
    PartitionNr: 1
    StartSektor: 1048576
    Länge     : 367001600
    Größe     : 350,00 MB
  2. Partition:
    Part-Typ  : MBR
    Part-Style : PARTITION_ENTRY_UNUSED
    PartitionNr: 0
    StartSektor: 0
    Länge     : 0
    Größe     : 0,00 Byte
  3. Partition:
    PartitionNr: 0
    StartSektor: 2
    Länge     : 3087428650860807
    Größe     : 2,74 PB
  4. Partition:
    Part-Typ  : MBR
    Part-Style : PARTITION_ENTRY_UNUSED
    PartitionNr: 0
    StartSektor: 0
    Länge     : 0
    Größe     : 0,00 Byte
2. Festplatte = 4 Partitionen
  1. Partition:
    Part-Typ  : MBR
    Part-Style : PARTITION_IFS
    PartitionNr: 1
    StartSektor: 1048576
    Länge     : 1000202043392
    Größe     : 931,51 GB
  2. Partition:
    PartitionNr: 3429319
    StartSektor: 2421637
    Länge     : 4213862
    Größe     : 4,02 MB
  3. Partition:
    Part-Typ  : MBR
    Part-Style : Unbekannt
    PartitionNr: 1781809
    StartSektor: 0
    Länge     : 0
    Größe     : 0,00 Byte
  4. Partition:
    PartitionNr: 3654587
    StartSektor: 2787577
    Länge     : 2128090
    Größe     : 2,03 MB
3. Festplatte = 1 Partitionen
  1. Partition:
    Part-Typ  : MBR
    Part-Style : PARTITION_ENTRY_UNUSED
    PartitionNr: 0
    StartSektor: 0
    Länge     : 0
    Größe     : 0,00 Byte
4. Festplatte = 4 Partitionen
  1. Partition:
    Part-Typ  : MBR
    Part-Style : PARTITION_IFS
    PartitionNr: 1
    StartSektor: 1048576
    Länge     : 1073738678272
    Größe     : 1.000,00 GB
  2. Partition:
    PartitionNr: 8
    StartSektor: 0
    Länge     : -6047066961440
    Größe     : -6.047.066.961.440,00 Byte
  3. Partition:
    Part-Typ  : MBR
    Part-Style : PARTITION_ENTRY_UNUSED
    PartitionNr: 1
    StartSektor: 0
    Länge     : 0
    Größe     : 0,00 Byte
  4. Partition:
    Part-Typ  : MBR
    Part-Style : PARTITION_ENTRY_UNUSED
    PartitionNr: 0
    StartSektor: 0
    Länge     : 0
    Größe     : 0,00 Byte
Bis auf die Tatsache, dass mir bei meiner 1. Platte die 2. Partition als UNUSED angezeigt wird, was definitiv nicht so ist, kann ich damit schon mal arbeiten. Da die anderen Platten nur eine Partition haben, muss ich mir erst mal noch eine weitere einbauen, um mal zu testen, was bei mehreren Partitionen so passiert.
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo

Geändert von Captnemo ( 8. Okt 2015 um 13:05 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#4

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX

  Alt 8. Okt 2015, 13:03
Ich glaube hier ist dein Problem mit den Puffern:
Zitat:
If the output buffer is too small to hold all of the data but can hold some entries, some drivers will return as much data as fits. In this case, the call fails, GetLastError returns ERROR_MORE_DATA, and lpBytesReturned indicates the amount of data received.
Zum Glück kannst du den danach den Aufruf nochmal mit einem größerem dynamisch allozierten Puffer wiederholen, den du dann auf DRIVE_LAYOUT_INFORMATION_EX castest.

PartitionInfoEx: array[0..0] of _PARTITION_INFORMATION_EX ist quasi der Hinweis an den Compiler, das hinter dem Record/Header noch ein Array mit diesem Typ hängt. Um den Speicher dafür musst du dich selbst kümmern.
Okay, dann lasse ich es einfach bei [0..15], denn mehr Partitionen wird wohl keiner haben.
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#5

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX

  Alt 9. Okt 2015, 10:50
So, ich hab jetzt alles soweit, dass ich die Partitionen theoretisch auslesen könnte.
Leider liest er mir aber immer nur die erste Partition einer Festplatte aus. Woran könnte das noch liegen?

Hier mal mein Code:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    mmo1: TMemo;
    btn1: TButton;
    btn2: TButton;
    mmo2: TMemo;
    procedure btn1Click(Sender: TObject);
    procedure btn2Click(Sender: TObject);
  private
    function GetSizeAsString(Size: Int64): string;
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

  const
    PARTITION_BASIC_DATA_GUID = 'ebd0a0a2-b9e5-4433-87c0-68b6b72699c7';
    PARTITION_ENTRY_UNUSED_GUID = '00000000-0000-0000-0000-000000000000';
    PARTITION_SYSTEM_GUID = 'c12a7328-f81f-11d2-ba4b-00a0c93ec93b';
    PARTITION_MSFT_RESERVED_GUID = 'e3c9e316-0b5c-4db8-817d-f92df00215ae';
    PARTITION_LDM_METADATA_GUID = '5808c8aa-7e8f-42e0-85d2-e1e90434cfb3';
    PARTITION_LDM_DATA_GUID = 'af9b60a0-1431-4f62-bc68-3311714a69ad';
    PARTITION_MSFT_RECOVERY_GUID = 'de94bba4-06d1-4d40-a16a-bfd50179d6ac';

    GTP_ATTRIBUTE_PLATFORM_REQUIRED = $0000000000000001;
    GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER = $8000000000000000;
    GPT_BASIC_DATA_ATTRIBUTE_HIDDEN = $4000000000000000;
    GTP_BASIC_data_ATTRIBUTE_SHADOW_COPY = $2000000000000000;
    GTP_BASIC_DATA_ATTRIBUTE_READ_ONLY = $1000000000000000;

    PARTITION_ENTRY_UNUSED = $00;
    PARTITION_EXTENDED = $05;
    PARTITION_FAT_12 = $01;
    PARTITION_FAT_16 = $04;
    PARTITION_FAT32 = $0B;
    PARTITION_IFS = $07;
    PARTITION_LDM = $42;
    PARTITION_NTFT = $80;
    VALID_NTFT = $C0;



  Type
    PARTITION_STYLE = type Integer;

    PARTITION_INFORMATION_MBR = record
      PartitionType: Byte;
      BootIndicator: BOOL;
      RecognizedPartition: BOOL;
      HiddenSecorts: DWORD;
    end;

    PARTITION_INFORMATION_GPT = record
      PartitonType: TGUID;
      PartitionId: TGUID;
      Attributes: DWORD64;
      Name: WCHAR;
    end;

    _PARTITION_INFORMATION_EX = record
      PartitionStyle: PARTITION_STYLE;
      StartingOffset: LARGE_INTEGER;
      PartitionLength: LARGE_INTEGER;
      PartitionNumber: ULONG;
      RewritePartition: Boolean;
      case Integer of
       0: (Mbr: PARTITION_INFORMATION_MBR);
       1: (Gpt: PARTITION_INFORMATION_GPT);
    end;

    DRIVE_LAYOUT_INFORMATION_MBR = record
      Signature: ULONG;
    end;

    DRIVE_LAYOUT_INFORMATION_GPT = record
      DiskID: TGUID;
      StartingusableOffset: LARGE_INTEGER;
      UsableLength: LARGE_INTEGER;
      MaxPartitionCount: ULONG;
    end;

    DRIVE_LAYOUT_INFORMATION_EX = record
      PartitionStyle: DWORD;
      PartitionCount: DWORD;
      DriveLayoutInfoType: record
        case Integer of
          0: (Mbr: DRIVE_LAYOUT_INFORMATION_MBR);
          1: (Gpt: DRIVE_LAYOUT_INFORMATION_GPT);
      end;
      PartitionInfoEx: array[0..10] of _PARTITION_INFORMATION_EX;
    end;

  const
    PARTITION_STYLE_MBR = PARTITION_STYLE(0);
    PARTITION_STYLE_GPT = PARTITION_STYLE(1);
    PARTITION_STYLE_RAW = PARTITION_STYLE(2);

  function FindFirstVolume(lpszVolumeName: LPTSTR; cchBufferLength: DWord): THandle; stdcall; external 'kernel32.dllname 'FindFirstVolumeW';
  function FindNextVolume(hFindVolume: THandle; lpszVolumeName: LPTSTR; cchBufferLength: DWORD): BOOL; stdcall; external 'kernel32.dllname 'FindNextVolumeW';
  function FindVolumeClose(hFindVolume: THandle): BOOL; stdcall; external 'kernel32.dllname 'FindVolumeClose';
  function GetVolumePathNames(lpszVolumeName: LPCTSTR; lpszVolumePathName: LPTSTR; cchBufferLength: DWORD; lpcchReturnLength: PDWORD): BOOL; stdcall; external 'kernel32.dllname 'GetVolumePathNamesForVolumeNameW';


var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
var
  h, p: Integer;
  Device: string;
  hDevice: Cardinal;
  PARTITION_INFORMATION_EX: _PARTITION_INFORMATION_EX;
  Len: Cardinal;
  StartOffset, PartLength: Int64;
begin
  for h := 1 to 9 do
  begin
    Device:='\\.\Harddisk1'+IntToStr(h);
    hdevice:=CreateFile(PChar(Device), 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
    if hDevice <> INVALID_HANDLE_VALUE then
    begin
      ZeroMemory(@PARTITION_INFORMATION_EX, SizeOf(PARTITION_INFORMATION_EX));
      DeviceIoControl(hDevice, IOCTL_DISK_GET_PARTITION_INFO_EX, nil, 0, @PARTITION_INFORMATION_EX, SizeOf(PARTITION_INFORMATION_EX), Len, nil);
      StartOffset:=PARTITION_INFORMATION_EX.StartingOffset.QuadPart;
      PartLength:=PARTITION_INFORMATION_EX.PartitionLength.QuadPart;
      mmo1.Lines.Add(Device+' = '+IntToStr(StartOffset)+' - '+IntToStr(PartLength));
      CloseHandle(hDevice);
    end;
    //end;
  end;
end;

procedure TForm1.btn2Click(Sender: TObject);
var
  RetBytes: DWORD;
  hDevice: Cardinal;
  Status: LongBool;
  Drive: string;
  Layout: ^DRIVE_LAYOUT_INFORMATION_EX;
  I,p: Integer;
  PartCount: Integer;
begin
  mmo1.Lines.Clear;
  mmo2.Lines.Clear;
  for I := 0 to 15 do
  begin
    Drive:='\\.\PhysicalDrive'+IntToStr(i);
    hDevice:=CreateFile(PChar(Drive), 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
    if hDevice<>INVALID_HANDLE_VALUE then
    begin
      GetMem(Layout, SizeOf(DRIVE_LAYOUT_INFORMATION_EX) + (SizeOf(_PARTITION_INFORMATION_EX)*15));
      Status:=DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, nil, 0, Layout, SizeOf(DRIVE_LAYOUT_INFORMATION_EX), RetBytes, nil);
      if (Status=False) then
        mmo1.lines.Add(IntToStr(i+1)+'. Festplatte abfrage fehlgeschalten') else
      begin
        PartCount:=0;
        mmo1.Lines.Add(IntToStr(i+1)+'. Festplatte = '+inttostr(Layout.PartitionCount)+' Partitionen');
         for p := 0 to Layout.PartitionCount-1 do
        begin
// if (Layout.partitionInfoEx[p].StartingOffset.QuadPart<>0) and (Layout.partitionInfoEx[p].PartitionLength.QuadPart<>0) then
// begin
            mmo1.Lines.Add(' '+inttostr(p+1)+'. Partition: ');
            case Layout.partitionInfoEx[p].PartitionStyle of
              PARTITION_STYLE_MBR: mmo1.Lines.Add(' Part-Typ : MBR');
              PARTITION_STYLE_GPT: mmo1.Lines.Add(' Part-Typ : GPT');
              PARTITION_STYLE_RAW: mmo1.Lines.Add(' Part-Typ : RAW');
            end;
            if Layout.PartitionInfoEx[p].PartitionStyle=PARTITION_STYLE_MBR then
            begin
              case Layout.PartitionInfoEx[p].Mbr.PartitionType of
                PARTITION_ENTRY_UNUSED: mmo1.lines.Add(' Part-Style : PARTITION_ENTRY_UNUSED');
                PARTITION_EXTENDED: mmo1.lines.Add(' Part-Style : PARTITION_EXTENDED');
                PARTITION_FAT_12: mmo1.lines.Add(' Part-Style : PARTITION_FAT_12');
                PARTITION_FAT_16: mmo1.lines.Add(' Part-Style : PARTITION_FAT_16');
                PARTITION_FAT32: mmo1.lines.Add(' Part-Style : PARTITION_FAT32');
                PARTITION_IFS: mmo1.lines.Add(' Part-Style : PARTITION_IFS');
                PARTITION_LDM: mmo1.lines.Add(' Part-Style : PARTITION_LDM');
                PARTITION_NTFT: mmo1.lines.Add(' Part-Style : PARTITION_NTFT');
                VALID_NTFT: mmo1.lines.Add(' Part-Style : VALID_NTFT');
              else
                mmo1.lines.Add(' Part-Style : Unbekannt');
              end;
              if Layout.PartitionInfoEx[p].Mbr.PartitionType<>PARTITION_ENTRY_UNUSED then
                Inc(PartCount);
            end;
            mmo1.lines.Add(' PartitionNr: '+IntToStr(Layout.partitionInfoEx[p].PartitionNumber));
            mmo1.Lines.Add(' StartSektor: '+IntToStr(Layout.partitionInfoEx[p].StartingOffset.QuadPart));
            mmo1.lines.Add(' Länge : '+IntToStr(Layout.partitionInfoEx[p].PartitionLength.QuadPart));
            mmo1.Lines.Add(' Größe : '+GetSizeAsString(Layout.partitionInfoEx[p].PartitionLength.QuadPart));
// end;
          mmo2.Lines.Add(IntToStr(i+1)+'. Festplatte = '+inttostr(PartCount)+' Partitionen');
          if Layout.PartitionInfoEx[p].Mbr.PartitionType=PARTITION_IFS then
          begin
            mmo2.Lines.Add(#9+inttostr(p+1)+'.Partition:'+#9+GetSizeAsString(Layout.partitionInfoEx[p].PartitionLength.QuadPart));
          end;
        end;
      end;
      CloseHandle(hDevice);
    end;// else mmo1.lines.Add(IntToStr(i)+'. Festplatte hat kein hDeviceHandle');
  end;

end;

function TForm1.GetSizeAsString(Size: Int64): string;
var
  new: Extended;
  Sign: String;
  c: Integer;
begin
  c:=0;
  new:=Size;
  while new>1024 do
  begin
    new:=new/1024;
    Inc(c);
  end;
  case c of
    0: Sign:=' Byte';
    1: Sign:=' KB';
    2: Sign:=' MB';
    3: Sign:=' GB';
    4: Sign:=' TB';
    5: Sign:=' PB';
    6: Sign:=' EB';
    7: Sign:=' ZB';
    8: Sign:=' YB';
  else
    Sign:=' ('+intToStr(c)+')';
  end;
  Result:=FormatFloat('#,##0.00', new)+Sign;
end;

end.
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#6

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX

  Alt 9. Okt 2015, 13:19
Gibt es denn keinen hier, der das schon mal gemacht hat? Vielleicht muss ich in DRIVE_LAYOUT_INFORMATION_EX das Array anders initialisieren?
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#7

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX

  Alt 9. Okt 2015, 13:40
Gibt es denn keinen hier, der das schon mal gemacht hat? Vielleicht muss ich in DRIVE_LAYOUT_INFORMATION_EX das Array anders initialisieren?
Doch, doch aber das ist schon ewig lange her und da hat man die Platte noch mit den x13h ausgelesen. Ich glaube nicht das Dir das was bringt.
Liest Du denn die Adresse der FolgePartition richtig aus?
(so auf die schnelle hab' ich da nichts gefunden)

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#8

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX

  Alt 9. Okt 2015, 16:20
Naja, die ich lese ja nicht die Partitionen direkt.

Rufe die Funktion DeviceIoControl auf und übergebe diese den CommandString IOCTL_DISK_GET_DRIVE_LAYOUT_EX.
Die Funktion soll dann alle im Record DRIVE_LAYOUT_INFORMATION_EX deklarierten Daten auslesen und im Array PartitionInfoEx eben alle PartitonInformationen ablegen, also ParitionStyle, StartOffset, Länge usw.
Dieses Array muss mindestens so groß sein, wie die Funktion Partitionen darin speichern will. Heißt, will sie 1 Partition speichern würde ein Array[0..0] reichen. Will sie 2 Speichern, dann muss es mindestens ein Array[0..1] sein. Größer darf das Array aber wohl immer sein.

Wenn ich im Interface
PartitionInfoEx: array[0..0] of _PARTITION_INFORMATION_EX; angebe, wie ich es schon auf einigen Seiten gelesen habe, dann bekomme ich von DeviceIoControl ein False zurück.
Mit
PartitionInfoEx: array[0..15] of _PARTITION_INFORMATION_EX; bekomme ich zumindest mal mehr zurück.
Aber es kommen nur für die 1. Partition die richtigen Daten. Die Inhalte von den dahinterliegenden Array-Elementen sind eher willkürlich.
Da aber die Funktion DeviceIoControl True zurückmeldet, gehe ich mal davon aus, dass sie grundsätzlich mit dem zur Verfügung stehenden Speicher zufrieden ist.
Vielleicht habe ich ja auch den Record falsch deklariert (Mit den Übersetzungen aus C in Delphi habe ich gar keine Erfahrung).
Oder vielleicht berechne ich bei GetMem den Speicher falsch.

Da MS da ganz sicher keine Fehler macht, muss er ja bei mir liegen.

Aber ich habe so gar keine Idee mehr (mangels Erfahrung), woran das liegen kann.
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#9

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX

  Alt 9. Okt 2015, 18:36
Deine Structs waren an einigen Stellen falsch, deshalb hast du bei den späteren Einträgen an den falschen Offsets gelesen. So funktioniert es:
Delphi-Quellcode:
type
  PARTITION_INFORMATION_MBR = record
    PartitionType: Byte;
    BootIndicator: Boolean;
    RecognizedPartition: Boolean;
    HiddenSectors: DWord;
  end;

  PARTITION_INFORMATION_GPT = record
    PartitionType: TGUID;
    PartitionId: TGUID;
    Attributes: DWORD64;
    Name: array[0..35] of WCHAR;
  end;

  PARTITION_STYLE = type DWord;

  PARTITION_INFORMATION_EX = record
    PartitionStyle: PARTITION_STYLE;
    StartingOffset: LARGE_INTEGER;
    PartitionLength: LARGE_INTEGER;
    PartitionNumber: DWord;
    RewritePartition: Boolean;
    case Integer of
      0: (Mbr: PARTITION_INFORMATION_MBR);
      1: (Gpt: PARTITION_INFORMATION_GPT);
  end;
  TPartitionInformationEx = PARTITION_INFORMATION_EX;
  PPartitionInformationEx = ^TPartitionInformationEx;

  DRIVE_LAYOUT_INFORMATION_MBR = record
    Signature: DWord;
  end;

  DRIVE_LAYOUT_INFORMATION_GPT = record
    DiskId: TGUID;
    StartingUsableOffset: LARGE_INTEGER;
    UsableLength: LARGE_INTEGER;
    MaxPartitionCount: DWord;
  end;

  DRIVE_LAYOUT_INFORMATION_UNION = record
  case Integer of
    0: (Mbr: DRIVE_LAYOUT_INFORMATION_MBR);
    1: (Gpt: DRIVE_LAYOUT_INFORMATION_GPT);
  end;

  DRIVE_LAYOUT_INFORMATION_EX = record
    PartitionStyle: DWord;
    PartitionCount: DWord;
    DriveLayoutInformation: DRIVE_LAYOUT_INFORMATION_UNION;
    PartitionEntry: array[0..0] of PARTITION_INFORMATION_EX;
  end;
  TDriveLayoutInformationEx = DRIVE_LAYOUT_INFORMATION_EX;
  PDriveLayoutInformationEx = ^TDriveLayoutInformationEx;

procedure PrintVolumeInformation(PhysicalDriveId: Integer);
var
  hDevice: THandle;
  LayoutInfo: PDriveLayoutInformationEx;
  LayoutInfoSize,
  BytesReturned: DWord;
  I: Integer;
begin
  hDevice := CreateFile(PChar('\\.\PhysicalDrive' + IntToStr(PhysicalDriveId)), 0,
    FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
  if (hDevice = INVALID_HANDLE_VALUE) then RaiseLastOSError;
  try
    LayoutInfoSize := SizeOf(TDriveLayoutInformationEx) + SizeOf(TPartitionInformationEx) * 3;
    GetMem(LayoutInfo, LayoutInfoSize);
    try
      while (not DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, nil, 0, LayoutInfo,
        LayoutInfoSize, BytesReturned, nil)) do
      begin
        if (GetLastError <> ERROR_INSUFFICIENT_BUFFER) then RaiseLastOSError;
        LayoutInfoSize := LayoutInfoSize + SizeOf(TPartitionInformationEx) * 4;
        ReallocMem(LayoutInfo, LayoutInfoSize);
      end;
      for I := 0 to LayoutInfo^.PartitionCount - 1 do
      begin
        WriteLn(LayoutInfo^.PartitionEntry[I].PartitionNumber);
        // ..
      end;
    finally
      FreeMem(LayoutInfo);
    end;
  finally
    CloseHandle(hDevice);
  end;
end;
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
950 Beiträge
 
Delphi 6 Professional
 
#10

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX

  Alt 9. Okt 2015, 18:37
Delphi-Quellcode:
begin
  for h := 1 to 9 do
  begin
    Device:='\\.\Harddisk1'+IntToStr(h);
    hdevice:=CreateFile(PChar(Device), 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
    if hDevice <> INVALID_HANDLE_VALUE then
    begin
müsste das nicht so sein:

Delphi-Quellcode:
begin
  for h := 1 to 9 do
  begin
    Device:='\\.\Harddisk'+IntToStr(h); // ohne die 1
    hdevice:=CreateFile(PChar(Device), 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
    if hDevice <> INVALID_HANDLE_VALUE then
    begin
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 09:15 Uhr.
Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf