Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX (https://www.delphipraxis.net/186877-partition-auslesen-mit-deviceiocontrol-und-ioctl_disk_get_partition_info_ex.html)

Captnemo 8. Okt 2015 11:11

Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX
 
Liste der Anhänge anzeigen (Anzahl: 1)
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
Delphi-Quellcode:
PartitionInfoEx: array[0..10] of _PARTITION_INFORMATION_EX
. Ich habe in diversen Posts gelesen, dass es
Delphi-Quellcode:
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.

BUG 8. Okt 2015 12:01

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX
 
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
Delphi-Quellcode:
DRIVE_LAYOUT_INFORMATION_EX
castest.

Delphi-Quellcode:
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.

Captnemo 8. Okt 2015 12:02

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX
 
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.

Captnemo 8. Okt 2015 12:03

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX
 
Zitat:

Zitat von BUG (Beitrag 1318039)
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
Delphi-Quellcode:
DRIVE_LAYOUT_INFORMATION_EX
castest.

Delphi-Quellcode:
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.

Captnemo 9. Okt 2015 09:50

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX
 
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.dll' name 'FindFirstVolumeW';
  function FindNextVolume(hFindVolume: THandle; lpszVolumeName: LPTSTR; cchBufferLength: DWORD): BOOL; stdcall; external 'kernel32.dll' name 'FindNextVolumeW';
  function FindVolumeClose(hFindVolume: THandle): BOOL; stdcall; external 'kernel32.dll' name 'FindVolumeClose';
  function GetVolumePathNames(lpszVolumeName: LPCTSTR; lpszVolumePathName: LPTSTR; cchBufferLength: DWORD; lpcchReturnLength: PDWORD): BOOL; stdcall; external 'kernel32.dll' name '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.

Captnemo 9. Okt 2015 12:19

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX
 
Gibt es denn keinen hier, der das schon mal gemacht hat? Vielleicht muss ich in DRIVE_LAYOUT_INFORMATION_EX das Array anders initialisieren?

p80286 9. Okt 2015 12:40

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX
 
Zitat:

Zitat von Captnemo (Beitrag 1318149)
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

Captnemo 9. Okt 2015 15:20

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX
 
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
Delphi-Quellcode:
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
Delphi-Quellcode:
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.

Zacherl 9. Okt 2015 17:36

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX
 
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;

HolgerX 9. Okt 2015 17:37

AW: Partition auslesen mit DeviceIoControl und IOCTL_DISK_GET_PARTITION_INFO_EX
 
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


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:10 Uhr.
Seite 1 von 2  1 2      

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