Einzelnen Beitrag anzeigen

Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.613 Beiträge
 
#4
  Alt 8. Jul 2002, 15:36
Zitat von Mr_T:
[...] leider habe ich kei9ne ahnung, wie es genau funzt, da im source das ganze auf so unzähligviele prozeduren verteilt ist [...]
Tja, das nenn ich einfach strukturierte Programmierung

Also, mal im Schnelldurchgang durchsteppen:

Code:
TNTDisk = class(TBlockDevice)
  public
    constructor Create; override;
    destructor Destroy; override;

    procedure ReadPhysicalSector (Sector : DWORD; count : DWORD; Buffer : Pointer); override;
    procedure WritePhysicalSector(Sector : DWORD; count : DWORD; Buffer : Pointer); override;

    function Open : Boolean; override;
    function Close : Boolean; override;

    procedure SetFileName(Name : String);
    procedure SetMode(Writeable : Boolean);
    procedure SetPartition(Start : _Large_Integer; Length : _Large_Integer);
  private
    FileName  : String;
    h         : THandle;
    Writeable : Boolean;
    SectorSize : DWORD;
    Start      : _Large_Integer; //longlong; // start
    Length     : _Large_Integer; //longlong; // length
  end;
Was wir hier brauchen ist ein schreibfähiges OPEN, ein WritePhysicalSector, und ein Close.

Zuerst das Open:

Code:
function TNTDisk.Open : Boolean;
begin
   if Writeable then
   begin
      h := Windows.CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ , nil, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0);
   end
   else
   begin
      [...]
   end;

   if h <> INVALID_HANDLE_VALUE then
      Result := True
   else
      Result := False;
end;<
Ist eigentlich ganz einfach:
CreateFile gibt Dir einfach nur ein Handle zurück. Das hier ist allerdings hardcore-api. Ein F1 auf CreateFile sollte Dir hier schon sehr weit weiterhelfen.

Mit diesem Handle kannst Du dann Operationen auf dem angegebenen 'File' durchführen. Also zum Beispiel Deine Daten schreiben. Wir sind nun in WritePhysicalSector. Du übergibst den Sector, in den Du schreiben willst, die Länge der zu schreibenden Daten und die Daten als Pointer auf das erste Byte, das Du schreiben willst.

In der Prozedur sieht das dann so aus:

Code:
   begin
      Debug('Write sector ' + IntToStr(Sector) + ' count = ' + IntToStr(Count), DebugOff);
      // work out the start address (of partition/file)

      WriteStart.QuadPart := Start.QuadPart + (Sector * SectorSize);
      WriteLength := Count * SectorSize;
Hier wird erst berechnet, von welcher Position aus Du schreiben wirst.

Code:
      // seek to the correct pos
      Seek := SetFilePointer(h, WriteStart.LowPart, @WriteStart.HighPart, FILE_BEGIN);
      if Seek <> $FFFFFFFF then
      begin
         // seek successful, lets read
         if not WriteFile2(h, Buffer, WriteLength, ActualLengthWritten, nil) then
         begin
            Error := GetLastError;
            Debug('Write failed error=' + IntToStr(GetLastError), DebugOff);
            raise Exception.Create('Write Failed: (' + IntToStr(GetLastError) + ')'#10 + SysErrorMessage(Error));
         end
         else if WriteLength <> ActualLengthWritten then
         begin
            Debug('Possible error, only ' + IntToStr(ActualLengthWritten) + ' bytes written', DebugLow);
         end;
      end
Bis zu der berechneten Stelle wird nun der Cursor in der Datei, also in dem Fall der Sector, verschoben. Das SeekFilePointer ist im Prinzip nichts anderes als ein intelligenter verschiebe - Algorithmus.

Wenn der Cursor erfolgreich verschoben wurde, das Suchergebnis also keinen ungültigen Wert zurückliefert, wird mit WriteFile2 auf dem Pointer der Datei aus dem Pointer der Quelldaten so viele Bytes geschrieben, wie in WriteLength spezifiziert wurde. In ActualLengthWritten kommt die Anzahl der tatsächlich geschriebenen Bytes zurück. Die beiden Werte sollten eigentlich identisch sein Wenn das nicht geklappt haben sollte gibts entsprechende Meldungen.

Das Close schmeisst hinterher das Handle auf das File sauber weg und schliesst die Schreibverbindung.

Viel mehr Magie steckt da nicht dahinter.
Ein bisschen F1 drücken auf den interessanten Schlagworten und die Api-Hilfe sollten hier eigentlich reichen, um da vollständig durchzusteigen.

Cya,

Sebastian
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org
  Mit Zitat antworten Zitat