Posted November 13, 200816 yr Hello everybody. While trying to create my own patcher with some extended features in Delphi, I created some functions that I could easy Copy-Paste to other patchers, and to ease-up further use. The first one will Patch One byte at a specified Offset: //Patches one byte at a certain Offset.Procedure OffsetBytePatch(AppPath: string; Offset: Longint; PatchByte: byte);varPatchFile: File Of Byte;begin AssignFile(PatchFile , AppPath); Reset(PatchFile); Seek(PatchFile, Offset); Write(PatchFile, PatchByte); CloseFile(PatchFile);end; The second one will Read one byte at a certain offset, for use in eg. checking if already patched. //Reads on byte at a certain Offset.Function OffsetByteRead(AppPath: string; Offset: Longint; PatchByte: byte): byte;varPatchFile: File Of Byte;ReadByte: Byte;Count: integer;begin AssignFile(PatchFile, AppPath); Reset(PatchFile); Seek(PatchFile, Offset); BlockRead(PatchFile, ReadByte, 1, Count); if Count = 1 then result := ReadByte else result := NULL;end; A Third one will patch a String, starting at a certain offset. Il will automatically keep the same size and fill remaing space with 00's. (So that whole string gets nicely patched). Perhaps usefull in eg. Custom caption changes. //Patches a String into an Executable, Starting from a certain offset.// Remaining Bytes will be filled with 00's.Procedure OffsetStringPatch(AppPath: string; Offset: Longint; PatchString: string; LengthOfBlock: integer);varPatchFile: File Of Byte;ByteArray: Array Of Byte;I: integer;beginPatchString := PatchString + StringOfChar('0', (LengthOfBlock - (LengthOfBlock - Length(PatchString))) * 2);for I := 1 to Length(PatchString) do begin ByteArray[I] := StrToInt(('$' + MidStr(PatchString, 1, 2))); Delete(PatchString, 1, 2); end; AssignFile(PatchFile, AppPath); Reset(PatchFile); Seek(PatchFile, Offset); BlockWrite(PatchFile, ByteArray, Length(ByteArray)); CloseFile(PatchFile);end; The fourth one will, how convenient, Read a string, starting at a certain offset. Might be helpfull in layout changes, to make a live editor. //Reads and Returns the String, starting at a certain Offset for LengthOfBlock bytes long.Function OffsetStringRead(AppPath: string; Offset: Longint; LengthOfBlock: integer): string;varPatchFile: File Of Byte;ByteArray: Array Of Byte;I: integer;resultString: string;begin AssignFile(PatchFile, AppPath); Reset(PatchFile); Seek(PatchFile, Offset); BlockRead(PatchFile, byteArray, LengthOfBlock); CloseFile(PatchFile);for I := 1 to Length(byteArray) do begin resultString := resultString + Chr(strtoint('$' + inttostr(byteArray[I]))); end; Note: I just created these for my own use. I'm just posting them here because they might perhaps be helpfull for any beginner. Feel free to use and edit them as much as you like. If you have any suggestions for me, I'd love to hear it. Greetingz, GuShe
December 16, 200816 yr I would recommend using Win32 API, not just for efficient, but it's faster also and safer, you never know what could happen with Delphi's VCL.nice snippets though, very basic but could be useful for others.
December 16, 200816 yr but it's faster also and safer, you never know what could happen with Delphi's VCL.faster - yesbut safer ???You have to do all sorts of error checking, allocate mem, deal with pointers and weird stuff.VCL is far easier and the speed increase is meaningless compared to the poor performance of disk access...
April 11, 200916 yr unit Unit2;interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm2 = class(TForm) Button1: TButton; Edit1: TEdit; Edit2: TEdit; Button2: TButton; OpenDialog1: TOpenDialog; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form2: TForm2; implementation {$R *.dfm} function MidStr (Const Str: String; From, Size: Word): String; begin MidStr := Copy(Str, From, Size) end; Procedure OffsetStringPatch(AppPath: string; Offset: Longint; PatchString: string; LengthOfBlock: integer); var PatchFile: File Of Byte; ByteArray: Array Of Byte; I: integer; begin PatchString := PatchString + StringOfChar('0', (LengthOfBlock - (LengthOfBlock - Length(PatchString))) * 2); for I := 1 to Length(PatchString) do begin ByteArray := StrToInt(('$' + MidStr(PatchString, 1, 2))); Delete(PatchString, 1, 2); end; AssignFile(PatchFile, AppPath); Reset(PatchFile); Seek(PatchFile, Offset); BlockWrite(PatchFile, ByteArray, Length(ByteArray)); CloseFile(PatchFile); end; procedure TForm2.Button1Click(Sender: TObject); begin opendialog1.Execute() ; edit1.Text:=opendialog1.FileName; end; procedure TForm2.Button2Click(Sender: TObject); begin OffsetStringPatch(edit1.Text,$00451000,'696e',2) end; end. and i got: ((( Edited April 11, 200916 yr by 6748222
April 11, 200916 yr Yes, there is something to be slightly improved: SetLength(byteArray,Length(PatchString)); // You must allocate memory for the arrayfor I := 0 to Length(PatchString) - 1 do begin // A dynamic array starts its index by 0... ByteArray[I] := StrToInt(('$' + MidStr(PatchString, 1, 2))); Delete(PatchString, 1, 2);end; Thanks for sharing your code Gushe Cheers Nacho_dj
April 22, 200916 yr I just noticed, why did you use BlockRead and not Read, it's a single Byte so BlockRead would be useful to read more than a single byte.
April 22, 200916 yr Author I just noticed, why did you use BlockRead and not Read, it's a single Byte so BlockRead would be useful to read more than a single byte. Not really getting what you're trying to say.
April 22, 200916 yr I just noticed, why did you use BlockRead and not Read, it's a single Byte so BlockRead would be useful to read more than a single byte. Not really getting what you're trying to say. Read() - Read data from a binary or text file BlockRead() - Reads a block of data records from an untyped binary file So if he's reading a single byte, why not just use Read() ?
April 23, 200916 yr Author I just noticed, why did you use BlockRead and not Read, it's a single Byte so BlockRead would be useful to read more than a single byte. Not really getting what you're trying to say. Read() - Read data from a binary or text file BlockRead() - Reads a block of data records from an untyped binary file So if he's reading a single byte, why not just use Read() ? Because it would add an extra if statement, resulting in nearly no remarkable better performance, right?
Create an account or sign in to comment