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