Gushe Posted November 13, 2008 Posted November 13, 2008 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
0xFF Posted December 16, 2008 Posted December 16, 2008 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.
Killboy Posted December 16, 2008 Posted December 16, 2008 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...
6748222 Posted April 11, 2009 Posted April 11, 2009 (edited) 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, 2009 by 6748222
Nacho_dj Posted April 11, 2009 Posted April 11, 2009 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
6748222 Posted April 11, 2009 Posted April 11, 2009 (edited) Thanks 4 fast replay hey! its works now Edited April 11, 2009 by 6748222
0xFF Posted April 22, 2009 Posted April 22, 2009 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.
Gushe Posted April 22, 2009 Author Posted April 22, 2009 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.
0xFF Posted April 22, 2009 Posted April 22, 2009 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() ?
Gushe Posted April 23, 2009 Author Posted April 23, 2009 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?
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now