Exemod - Colocando arquivos e strings dentro do exe em runtime

Top  Previous  Next

unit ExeMod;

{

This is the first beta of the full version 1.00

That allows an ExeMod exe to work properly even

from a CD..for info on how an exe on CD is handled

please see the notes in the Interface section.

 

Written by G.A. Carpenter (works on D2 thru D7)

This is FreeWare for any purpose...use as you will.

Consider it public domain... feel free to make

any changes you want... if you improve it I'd love

to get a copy of the improvements :-)

 

gacarpenter386@yahoo.com <gwen carpenter (Gwena)>

 

You can use this in any program, commercial or freeware,

and you DO NOT need to mention where it came from.

(no attribution needed)

 

If you use NT/2000/XP please read the NT-NOTE below!

 

This unit enables you to make a delphi application that can

alter its own exe file on disk... this appears to happen

at runtime but actually the switch quickly takes place after

a shutdown of the running app during which a copy of the exe

deletes the old version and replaces it with a new version.

 

While it is also possible to alter a running exe directly by altering

the hd sectors that hold the exe's data. I abandoned that scheme

because although it worked quickly and transparently it proved to

be risky :-(

 

This unit lets you easily create...

-Self altering exe files

-Program Generators

-Apps that update live over the internet

-Apps that keep an internal record of data

 (no ini file or registry usage needed)

-File handling utils

-Copy protection schemes

-Self extracting archives

-Programs that alter and store data in other programs and files.

...and many other strange things ;-)

 

 

NOTE! ExeMod will not delete a demarc delimited string from an

external file if the deletion would take the file down to 0 bytes

in length! This is because some disk cleanup utils can be set to

automatically remove 0 length files. If you intend to use an external

file to hold data that will be handled by ExeMod you should begin

by placing at least a single byte of data at the beginning of the file.

 

------

NT-NOTE!

 

If you use ExeMod.pas on an NT machine then you may need to run the exe

outside the delphi ide... for some reason NT causes the debugger to

faint at the sight of my code :-)  the exe files run just fine on NT

but just not from inside the ide....

 

-------

Here are some simple demos for you to look over.

 

(Remember to put ExeMod.pas into your compiler's path or into your

project's directory... then add ExeMod to your program's uses clause)

------------------------------------------------------------------------

-Code to alter a byte in an exe and then alter the exe at runtime and

put the change onto the exe's file on disk

 

procedure TForm1.Button1Click(Sender: TObject);

begin

 ReadExe;  //Read exe file from disk and put into global string named Exe

 Exe[3] := 'A';  //Change byte 3 of Global string Exe

 AlterExe;   //Alter the exe file on disk then quickly restart program

end;

------------------------------------------------------------------------

-Code to add a file from disk to the end of the exe at runtime.

Assume a small txt file named C:\myfile.txt exists and contains

the text 'test'

 

procedure TForm1.Button1Click(Sender: TObject);

begin

 AddFile2Exe('gac1','C:\myfile.txt');

 AlterExe;

end;

 

The string 'gac1' serves to locate the data at the end of the exe.

I call gac1 a 'Demarc name' because when combined with a few other

characters it serves as a demarcation line in the exe file... this

gives you an easy way to search through the file and find the location

of the start of your data.

 

Here is what is added to the exe at runtime when you click the button

 

SO!#GAC1¶testEO!#GAC1

 

The data from the file is the 4 bytes 'test' all the rest is just delimiter

data so that ExeMod can locate the data in the exe file.

The Character '¶' in the string is to tell the program where the name

given to the data string ('GAC1') ends. it is chr(182) please do NOT

use chr(182) as a character in any demarc name or you will cause an error!

 

AddFile2Exe will load the exe from disk if it has not already been

loaded... it checks to see if Exe = '' and if so does a ReadExe;

-----------------------------------------------------------------------

-Code to extract an ExeMod data block from the exe at runtime and save

it to a file on disk... then remove the block from the exe and alter the

exe on disk so that it no longer contains any trace of the data block.

 

procedure TForm1.Button1Click(Sender: TObject);

begin

 ExtractAndStrip('gac1','myfile2.txt');

 AlterExe;

end;

 

This extracts the ExeMod data block gac1 to a file named 'myfile2.txt'

the file is placed into the directory where the program's exe file is

located.

 

This sort of code is good for making a self-extracting installation

program in delphi. All of your help files,dlls..etc can be extracted

during the first run of your program... exe size will be small because

the data will be removed from the exe after extraction. All files will

be extracted to the program's dir unless a full path name is given.

-----------------------------------------------------------------------

Code to save a copy of the running exe

 

procedure TForm1.Button1Click(Sender: TObject);

begin

 Exe2File('MyNewExe.exe');

 Exe := ''; //set Exe to empty string (save space if data no longer needed)

end;

 

Saves a copy of the running exe as myNewExe.exe in the same directory

where the running exe is. If Exe has been altered the altered version

will be saved... if Exe has not been loaded yet then ReadExe is called.

-----------------------------------------------------------------------

Code to save a modified copy of the running exe... this simple code

gives you a program generator.

 

procedure TForm1.Button1Click(Sender: TObject);

begin

 ReadExe;

 //add code here to modify the string named 'Exe'

 Exe2File('MyNewExe.exe');

 Exe := ''; //set Exe to empty string (save space if data no longer needed)

end;

 

This simple code is actually VERY powerful and VERY useful...

-----------------------------------------------------------------------

 

---> Much more Demo code and many more  procedures to come..soon as I

get some more free time :-)

 

 

}

 

interface

 

uses

 Windows, SysUtils, Classes, Forms, ShellAPI, Dialogs;

 

var Exe: string;

 

procedure Delay(ms: longint);

procedure ReadExe;

procedure String2File(String2BeSaved, FileName: string);

function  WinDrv: char;

function  GetDemarcCount: integer;

procedure GetDemarcName(DNumber: Integer; var DName: String);

function  File2String(FileName: string): string;

function  PeekExeByte(Byte2Get: Integer): byte;

function  PeekExeWord(Word2Get: Integer): word;

procedure PeekExeString(StartByte,Count: Integer; var ReturnedStr: String);

procedure PokeExeByte(Byte2set: Integer; ByteVal: Byte);

procedure PokeExeByteI(Byte2set: Integer; ByteVal: Byte);

procedure PokeExeString(StartByte: Integer; String2Insert: String);

procedure PokeExeStringI(StartByte: Integer; String2Insert: String);

procedure ExtractFromExe(DemarcStr: string; var ExtractedStr: string);

procedure ExtractFromFile(DemarcStr: string; DataFile: string; var ExtractedStr: string);

procedure DelFromString(DemarcStr: string; var String2Change: string);

procedure DelFromExe(DemarcStr: string);

procedure DelFromFile(DemarcStr, FileName: string);

procedure Add2File(DemarcStr, FileName, String2Add: string);

procedure ReplaceInFile(DemarcStr, FileName, ReplacementString: string);

procedure TackOnFile(DemarcStr, FileName, File2Add: string);

procedure Add2String(DemarcStr, String2Add: string; var String2Alter: string);

procedure ReplaceInString(DemarcStr, ReplacementString:

 string; var String2Alter: string);

procedure ReplaceInExe(DemarcStr, ReplacementString: string);

procedure InsOrReplaceInString(DemarcStr, ReplacementString:

 string; var String2Alter: string);

procedure InsOrReplaceInExe(DemarcStr, ReplacementString: string);

procedure AlterExe;

procedure ExtractAndStrip(DemarcStr, FileName: string);

procedure Exe2File(FileName: string);

procedure Extract2File(DemarcStr, FileName: string);

procedure AddFile2Exe(DemarcStr, FileName: string);

procedure Add2Exe(DemarcStr, String2Add: string);

procedure Stream2Exe(TempStream: TMemoryStream);

procedure String2Stream(a: String;var b: TMemoryStream);

procedure Stream2String(b: TMemoryStream;var a: String);

 

 

implementation

 

//==================================================

//This is just a simple procedure to implement a delay

 

procedure Delay(ms: longint);

var

 TheTime: LongInt;

begin

 TheTime := GetTickCount + ms;

 while GetTickCount < TheTime do

   Application.ProcessMessages;

end;

//===================================================

 

//===================================================

//This code returns the char of the drive where

//windows is installed

 

function  WinDrv: char;

var

  WinDir : String;

  n      : Integer;

begin

  SetLength(WinDir,256);

  n := GetWindowsDirectory(PChar(WinDir),256);

  SetLength(WinDir,n);

  Result := WinDir[1];

end;

//===================================================

 

//===================================================

//This function returns the number of data strings that

//are stored in the exe under demarc names... if demarc

//delimited data strings have been added to the global

//string Exe but not yet flushed to disk by an AlterExe

//command, they will still be included in this count!

 

function  GetDemarcCount: integer;

var Count,X: Integer;

begin

Count := 0;

If Exe = '' then ReadExe;

For X := 1 to Length(Exe)-10 do

  begin

    If  (Exe[X] = 'S'and (Exe[X+1] = 'O')

    and (Exe[X+2] = '!'and (Exe[X+3] = '#')

    then

    begin

      Inc(Count);

    end;

  end;

Result := Count;

end;

//===================================================

 

//===================================================

//You pass a number (DNumber) to this procedure and it

//returns a string (DName) that contains the DNumber'th

//demarc name from the exe file. If the DNumber'th

//demarc string does not exist then an empty string

//is returned. This procedure lets you easily look through

//the running exe or any other file to discover the demarc

//names under which data has been stored.

 

procedure GetDemarcName(DNumber: Integer; var DName: String);

var Count,X,Y: Integer;

begin

Count := 0;

If Exe = '' then ReadExe;

For X := 1 to Length(Exe)-10 do

  begin

    If  (Exe[X] = 'S'and (Exe[X+1] = 'O')

    and (Exe[X+2] = '!'and (Exe[X+3] = '#')

    then

    begin

      Inc(Count);

      If Count = DNumber then

      begin

        Y := X+4;

        While Exe[Y] <> chr(182) do

        begin

          DName := DName+Exe[Y];

          Inc(Y);

        end;

      end;

    end;

  end;

end;

//===================================================

 

 

//===================================================

//This code loads the Exe file from disk and into

//the global string var 'Exe'

 

procedure ReadExe;

var

 ExeStream: TFileStream;

begin

 ExeStream := TFileStream.Create(Application.ExeName, fmOpenRead

   or fmShareDenyNone);

 try

   SetLength(Exe, ExeStream.Size);

   ExeStream.ReadBuffer(Pointer(Exe)^, ExeStream.Size);

 finally

   ExeStream.Free;

 end;

end;

//===================================================

 

//===================================================

//This code can write any string to disk as a file

 

procedure String2File(String2BeSaved, FileName: string);

var

 MyStream: TMemoryStream;

begin

 if String2BeSaved = '' then exit;

 SetCurrentDir(ExtractFilePath(Application.ExeName));

 MyStream := TMemoryStream.Create;

 try

   MyStream.WriteBuffer(Pointer(String2BeSaved)^, Length(String2BeSaved));

   MyStream.SaveToFile(FileName);

 finally

   MyStream.Free;

 end;

end;

//===================================================

 

//===================================================

//This code can read any file from disk and into a string

 

function File2String(FileName: string): string;

var

 MyStream: TMemoryStream;

 MyString: string;

begin

 MyStream := TMemoryStream.Create;

 try

   MyStream.LoadFromFile(FileName);

   MyStream.Position := 0;

   SetLength(MyString, MyStream.Size);

   MyStream.ReadBuffer(Pointer(MyString)^, MyStream.Size);

 finally

   MyStream.Free;

 end;

 Result := MyString;

end;

//===================================================

 

//===================================================

//This code lets you read a byte from the running exe

//directly from the ram. Byte 1 = first byte of exe

//DO NOT attempt to read values lower than 1 or function

//will fail and produce random data. Be advised that

//bytes that are appended to the exe file cannot be read

//using this function as that data is not in ram at runtime!

//Do not attempt to read within or beyond a few hundred bytes

//of the end of your exe (minus any appended data) as data

//beyond that range cannot be retrieved with this simple

//function... there is no range checking for the upper

//bound so use caution.

 

function  PeekExeByte(Byte2Get: Integer): byte;

Begin

If Byte2Get < 1 then Exit;

Result := byte(pointer(Hinstance+Byte2Get-1)^);

End;

//===================================================

 

//===================================================

//This function is nearly identical to the one above

//so the comments for PeekExeByte apply here as well.

 

function  PeekExeWord(Word2Get: Integer): word;

Begin

If Word2Get < 1 then Exit;

Result := word(pointer(Hinstance+Word2Get-1)^);

End;

//===================================================

 

//===================================================

//This code returns a string from the exe image in RAM

//cautions are similar to PeekExeByte

 

procedure PeekExeString(StartByte,Count: Integer; var ReturnedStr: String);

var X: Integer;

Begin

  If StartByte < 1 then Exit;

  For X := StartByte to StartByte+Count-1 do

  begin

    ReturnedStr := ReturnedStr+(char(pointer(Hinstance+X-1)^));

  end;

End;

//===================================================

 

//===================================================

//This code can stuff a string into the exe starting at

//a specified point... changes are NOT immediately saved

//to disk.

 

procedure PokeExeString(StartByte: Integer; String2Insert: String);

var X: Integer;

Begin

  If Exe = '' then ReadExe;

  If StartByte + Length(String2Insert) > Length(Exe) then Exit;

  If StartByte < 1 then Exit;

  For X := 1 to Length(String2Insert) do

  begin

    Exe[X+StartByte-1] := String2Insert[X];

  end;

end;

//===================================================

 

//===================================================

//This code can stuff a string into the exe starting at

//a specified point... changes ARE immediately saved

//to disk... Take care!

 

procedure PokeExeStringI(StartByte: Integer; String2Insert: String);

var X: Integer;

Begin

  If Exe = '' then ReadExe;

  If StartByte + Length(String2Insert) > Length(Exe) then Exit;

  If StartByte < 1 then Exit;

  For X := 1 to Length(String2Insert) do

  begin

    Exe[X+StartByte-1] := String2Insert[X];

  end;

  AlterExe;

end;

//===================================================

 

 

//===================================================

//Pokes a byte value into a specified byte in the string

//named Exe. This string holds the image of the running

//executable. The altered version of exe is NOT immediately

//written to disk!

 

procedure PokeExeByte(Byte2set: Integer; ByteVal: Byte);

Begin

If Exe = '' then ReadExe;

If Byte2Set > Length(Exe) then Exit;

Exe[Byte2Set] := chr(ByteVal);

end;

//===================================================

 

//===================================================

//Identical to PokeExeByte procedure except the changed

//byte IS immediately written to disk! USE CARE as the

//state of the exe will be lost on restart unless you

//store all desired data inside the string named Exe.

 

procedure PokeExeByteI(Byte2set: Integer; ByteVal: Byte);

Begin

If Exe = '' then ReadExe;

If Byte2Set > Length(Exe) then Exit;

Exe[Byte2Set] := chr(ByteVal);

AlterExe;

end;

//===================================================

 

//===================================================

//This code gets data from the exe that was stored under a

//specified demarc name and places it into a string

 

procedure ExtractFromExe(DemarcStr: string; var ExtractedStr: string);

var

 d, e: integer;

begin

 if Length(Exe) = 0 then ReadExe;

 if Pos(uppercase('so!#' + DemarcStr + chr(182)), Exe) > 0 then

 begin

   d := Pos(uppercase('so!#' + DemarcStr + chr(182)), Exe)

     + length(uppercase('so!#' + DemarcStr + chr(182)));

   e := Pos(uppercase('eo!#' + DemarcStr), Exe);

   ExtractedStr := Copy(Exe, d, e - d);

 end;

end;

//===================================================

 

 

//===================================================

//This code gets a demarc delimited data string from

//an external file and loads it into a string

 

procedure ExtractFromFile(DemarcStr: string; DataFile: string; var ExtractedStr: string);

var

 d, e: integer;

 Temp: String;

begin

 Temp := File2String(DataFile);

 if Pos(uppercase('so!#' + DemarcStr + chr(182)), Temp) > 0 then

 begin

   d := Pos(uppercase('so!#' + DemarcStr + chr(182)), Temp)

     + length(uppercase('so!#' + DemarcStr + chr(182)));

   e := Pos(uppercase('eo!#' + DemarcStr), Temp);

   ExtractedStr := Copy(Temp, d, e - d);

 end;

end;

//===================================================

 

 

//===================================================

//This code deletes a demarc delimited string from any other string

 

procedure DelFromString(DemarcStr: string; var String2Change: string);

var

 a, b: string;

begin

 a := UpperCase('so!#' + DemarcStr + chr(182));

 b := UpperCase('eo!#' + DemarcStr);

 delete(String2Change, pos(a, String2Change), (pos(b, String2Change)

   + length(b) - pos(a, String2Change)));

end;

//===================================================

 

//===================================================

//This code deletes a demarc delimited string from global

//string named Exe

 

procedure DelFromExe(DemarcStr: string);

begin

If Exe = '' then ReadExe;

DelFromString(DemarcStr,Exe);

end;

//===================================================

 

 

//===================================================

//This code deletes a demarc delimited string from a

//file on disk

 

procedure DelFromFile(DemarcStr, FileName: string);

var

 MyString: string;

begin

 MyString := File2String(FileName);

 DelFromString(DemarcStr, MyString);

 String2File(MyString, FileName);

end;

//===================================================

 

//===================================================

//This code adds a demarc delimited string to a file

 

procedure Add2File(DemarcStr, FileName, String2Add: string);

var

 MyString: string;

begin

 If DemarcStr = '' then Exit;

 MyString := File2String(FileName);

 MyString := MyString + uppercase('so!#' + DemarcStr + chr(182)) + String2Add + uppercase

   ('eo!#' + DemarcStr);

 String2File(MyString, FileName);

end;

//===================================================

 

//===================================================

//This code adds a demarc delimited string to a file

//if the string already exists it is replaced

 

procedure ReplaceInFile(DemarcStr, FileName, ReplacementString: string);

begin

 If DemarcStr = '' then Exit;

 DelFromFile(DemarcStr, FileName);

 Add2File(DemarcStr, FileName, ReplacementString);

end;

//===================================================

 

//===================================================

//This code adds a demarc delimited file to another file

 

procedure TackOnFile(DemarcStr, FileName, File2Add: string);

var

 Mystring: string;

begin

 If DemarcStr = '' then Exit;

 MyString := File2String(File2add);

 Add2File(DemarcStr, FileName, MyString);

end;

//===================================================

 

//===================================================

//This code adds a demarc delimited string to any other

//string.

 

procedure Add2String(DemarcStr, String2Add: string; var String2Alter: string);

begin

 If DemarcStr = '' then Exit;

 String2Alter := String2Alter + uppercase('so!#' + DemarcStr + chr(182))

   + String2Add + uppercase('eo!#' + DemarcStr);

end;

//===================================================

 

//===================================================

//This code replaces the data held within a demarc delimited

//string with new data... the demarc string must exist.

 

procedure ReplaceInString(DemarcStr, ReplacementString: string;

 var String2Alter: string);

begin

 If DemarcStr = '' then Exit;

 if pos(uppercase('so!#' + DemarcStr + chr(182)), String2Alter) = 0 then exit;

 DelFromString(DemarcStr, String2Alter);

 Add2String(DemarcStr, ReplacementString, String2Alter);

end;

//===================================================

 

//===================================================

//This code replaces the data held within a demarc delimited

//string with new data... the demarc string must exist. this

//is identical to ReplaceInString except it defaults to

//the global string named Exe.

 

procedure ReplaceInExe(DemarcStr, ReplacementString: string);

begin

 If DemarcStr = '' then Exit;

 if pos(uppercase('so!#' + DemarcStr + chr(182)), Exe) = 0 then exit;

 DelFromString(DemarcStr, Exe);

 Add2String(DemarcStr, ReplacementString, Exe);

end;

//===================================================

 

//===================================================

//This code will replace the data held within a demarc delimited

//string with new data... if the demarc delimited string does not

//exist it will be created.

 

procedure InsOrReplaceInString(DemarcStr, ReplacementString: string;

 var String2Alter: string);

begin

 If DemarcStr = '' then Exit;

 DelFromString(DemarcStr, String2Alter);

 Add2String(DemarcStr, ReplacementString, String2Alter);

end;

//===================================================

 

//===================================================

//This code will replace the data held within a demarc delimited

//string with new data... if the demarc delimited string does not

//exist it will be created. This is identical with InsOrReplaceInString

//except it defaults to the global string Exe.

 

procedure InsOrReplaceInExe(DemarcStr, ReplacementString: string);

begin

 If DemarcStr = '' then Exit;

 If Exe = '' Then ReadExe;

 DelFromString(DemarcStr, Exe);

 Add2String(DemarcStr, ReplacementString, Exe);

end;

//===================================================

 

//===================================================

//This code swaps the current version of the running exe

//on disk for the version that is held in the global 

//string named 'Exe' Your application quickly shuts down and

//re-starts as the new version. ANY DATA THAT YOU WANT THE NEW

//VERSION TO BE AWARE OF MUST BE PASSED AS DATA INCLUDED

//IN 'Exe' before calling this procedure!!!

 

procedure AlterExe;

begin

 if (Exe) <> '' then

 begin

   String2File(Exe, 'temp0a0.exe');

   ShellExecute(0'open', PChar('temp0a0.exe'),

     PChar('"'+ExtractFilename(Application.ExeName)+'"'), nil, SW_SHOW);

   Application.Terminate;

 end;

end;

//===================================================

 

//===================================================

//This code extracts a demarc delimited string from the 

//global string 'Exe' to a file. The data is then stripped

//out of 'Exe'  .. this procedure is very useful for

//making self extracting archives that remove all the

//archived files from the exe after extraction... reducing

//hd space required... just store all your dll's, images

//etc in the exe and extract and strip them the first

//time the user runs the program :-)

 

procedure ExtractAndStrip(DemarcStr, FileName: string);

var

 Temp: string;

begin

 ExtractFromExe(DemarcStr, Temp);

 if Length(Temp) <> 0 then

 begin

   DelFromString(DemarcStr, Exe);

   String2File(Temp, FileName);

 end;

end;

//===================================================

 

//===================================================

//This code saves the global string exe to disk as a

//new exe.

 

procedure Exe2File(FileName: string);

begin

 if Exe = '' then ReadExe;

 String2File(Exe, FileName);

end;

//===================================================

 

//===================================================

//This code extracts a demarc delimited string from the

//exe and saves it as a file.

 

procedure Extract2File(DemarcStr, FileName: string);

var

 MyString: string;

begin

 ExtractFromExe(DemarcStr, MyString);

 if MyString <> '' then String2File(MyString, FileName);

end;

//===================================================

 

//===================================================

//This code adds a file to the global string exe as

//a demarc delimited string.

 

procedure AddFile2Exe(DemarcStr, FileName: string);

var

 MyString: string;

begin

 If DemarcStr = '' then Exit;

 MyString := File2String(FileName);

 if Exe = '' then ReadExe;

 Add2String(DemarcStr, MyString, Exe);

end;

//===================================================

 

//===================================================

//This code adds a demarc delimited string to the

//global string Exe.

 

procedure Add2Exe(DemarcStr, String2Add: string);

begin

 If DemarcStr = '' then Exit;

 if Exe = '' then readExe;

 Add2String(DemarcStr, String2Add, Exe);

end;

//===================================================

 

//===================================================

//This code replaces the current exe file on disk with

//one that is held in a TMemoryStream. This makes it

//easy to update an exe by downloading a new version

//over the internet and into a stream... use any of

//the free internet packs... like Fpiettes or Synapse lib

 

procedure Stream2Exe(TempStream: TMemoryStream);

begin

 SetCurrentDir(ExtractFilePath(Application.ExeName));

 TempStream.SaveToFile('temp0a0.exe');

 ShellExecute(0'open', PChar('temp0a0.exe'),

   PChar(ExtractFilename(Application.ExeName)), nil, SW_SHOW);

 Application.Terminate;

end;

//===================================================

 

//==============================================================================

//This code copies a string to a stream

 

procedure String2Stream(a: String;var b: TMemoryStream);

begin

b.Position := 0;

b.WriteBuffer(Pointer(a)^,Length(a));

b.Position := 0;

end;

 

//==============================================================================

 

//==============================================================================

//This code copies a stream to a string

 

procedure Stream2String(b: TMemoryStream;var a: String);

begin

b.Position := 0;

SetLength(a,b.Size);

b.ReadBuffer(Pointer(a)^,b.Size);

b.Position := 0;

end;

 

//==============================================================================

//This is the ExeMod.pas Initialization code...this code runs each time your

//exe is started... this code handles the actual swapping of one version of

//the exe for another. This is done by an exe file swap and re-start carried

//out by a temporary copy of the exe named temp0a0.exe. The initialization

//code can look for and delete a file named temp0a0.exe if it is found

//in the current dir. This is how temp0a0.exe is removed after an exe swap. 

 

initialization

 begin

   SetCurrentDir(ExtractFilePath(Application.ExeName));

 

//******************************************************************************

//NOTE--> WinDrv = The drive where Windows is installed!

//

//Beginning of code that lets an ExeMod exe work properly even

//if it is on a read-only CD ... this code will cause the exe

//on the CD to create a dir on WinDrv with the same name as the running

//exe. Then it moves a copy of the exe to that dir and runs that

//copy before shutting down. Thereafter any time the exe on CD is

//run it will act only as a shortcut to the version on WinDrv.

//If you do not want this functionality then just comment out this

//code or delete it from this unit. You can also disable this code

//by changing byte 3 of your exe so that it holds a zero value.

//'MZP' becomes 'MZ' followed by a zero byte.

//Programs that do not attempt to alter themselves at runtime and

//which do not attempt to save files in the current dir should

//disable this code... otherwise the app will always needlessly copy

//itself to WinDrv and run from there!

 

if (FileGetAttr(Application.ExeName) and faReadOnly) > 0 then

begin

  if PeekExeByte(3) = 0 then Exit;

  FileSetAttr(Application.ExeName, FileGetAttr(Application.ExeName)

        xor faReadOnly);

  if (FileGetAttr(Application.ExeName) and faReadOnly) > 0  then

    begin

    If FileExists(Windrv+':\'+ExtractFileName(Application.ExeName)+

          '\'+ExtractFileName(Application.ExeName)) then

      begin

        ShellExecute(0'open', PChar((WinDrv+':\'+ExtractFileName(Application.ExeName)+

              '\'+ExtractFileName(Application.ExeName))),nil, nil, SW_SHOW);

        Application.Terminate;

      end

      else

      begin

        CreateDir(WinDrv+':\'+ExtractFileName(Application.ExeName));

        Exe2File(WinDrv+':\'+ExtractFileName(Application.ExeName)+

          '\'+ExtractFileName(Application.ExeName));

        ShellExecute(0'open', PChar((WinDrv+':\'+ExtractFileName(Application.ExeName)+

          '\'+ExtractFileName(Application.ExeName))),nil, nil, SW_SHOW);

        Application.terminate;

      end;

    end;

end;

//This is the end of the code that allows proper operation from a CD.

//******************************************************************************

 

   if ParamStr(1) = 'deltemp' then

   begin

     while not (deletefile('temp0a0.exe')) do

     begin

       if (FileGetAttr('temp0a0.exe'and faReadOnly) > 0

         then FileSetAttr('temp0a0.exe', FileGetAttr('temp0a0.exe')

         xor faReadOnly);

       delay(10);

     end;

     deletefile('temp0a0.exe');

   end;

   if UpperCase(ExtractFileName(Application.ExeName)) = ('TEMP0A0.EXE') then

   begin

     ReadExe;

     while not (deletefile(ParamStr(1))) do

     begin

       if (FileGetAttr(ParamStr(1)) and faReadOnly) > 0

         then FileSetAttr(ParamStr(1), FileGetAttr(ParamStr(1))

         xor faReadOnly);

       delay(10);

     end;

     String2File(Exe, ParamStr(1));

     ShellExecute(0'open', PChar(ParamStr(1)),

       PChar('deltemp'), nil, SW_SHOW);

     Application.Terminate;

   end;

 end;

 

end.

 

// exemplo de password dentro do proprio EXE:

 

procedure TForm1.FormCreate(Sender: TObject);

Var Temp: String;

begin

ExtractFromExe('MyPwrd',Temp);

If Temp = '' then Button1.Caption :=

'You Must Create A Password For This Program. Enter It Below And Click Here'

else

begin

  Button1.Caption :=

  'Enter Your Password Below And Click Here To Access Program';

  Form1.Color := $00aec2ff;

end;

end;

 

procedure TForm1.Button1Click(Sender: TObject);

Var Temp: String;

begin

If Button1.Caption[1] = 'Y' then

begin

  If Edit1.Text = '' then Exit;

  Add2Exe('MyPwrd',Edit1.Text); //add a pw to the exe

  AlterExe; //alter and restart the exe

end

else

begin

  ExtractFromExe('MyPwrd',Temp);

  If Temp = Edit1.Text Then

  begin

    Form1.Height := 350;

    Edit1.Visible := False;

    Button1.Visible := False;

    Image1.Visible := True;

    Label1.Visible := True;

    Exe := ''//set exe string to empty string

  end;

end;

end;

 

procedure TForm1.Button2Click(Sender: TObject);

begin

  DelFromExe('MyPwrd');

end;

 

/////////// exemplo que grava numero de acessos e data/hora dentro do exe

 

procedure TForm1.FormCreate(Sender: TObject);

var temp: string;

begin

If paramstr(1) = '' then

begin

ExtractFromExe('FirstDateTime',Temp);

If Temp = '' then

Add2Exe('FirstDateTime', DateToStr(Date) + ' ' + TimeToStr(Time));

Exe := Exe + '[' + DateToStr(Date) + ' ' + TimeToStr(Time) + ']'+chr(13)+chr(10);

AlterExe;

end

else if ParamStr(1) = 'deltemp' then WindowState := WsNormal;

ExtractFromExe('FirstDateTime',Temp);

Form1.Caption := 'First Run Time ' + Temp + ' ->This Run Time '

 + DateToStr(Date) + ' ' + TimeToStr(Time);

end;

 

procedure TForm1.SpeedButton1Click(Sender: TObject);

begin

ReadExe;

Exe :=  Copy(Exe,(Pos(UpperCase('eo!#firstdatetime'),Exe))+17,

    Length(Exe)-(Pos(UpperCase('eo!#firstdatetime'),Exe))+17);

Exe2File('runtimes.txt');

Exe := '';

ShellExecute(0'open', PChar('runtimes.txt'),nil,nil, SW_SHOW);

end;

 

//////////////// exemplo que grava um jpg e extrai dentro do exe

 

//This procedure handles adding a file to an exe

//==============================================================================

procedure TForm1.SpeedButton1Click(Sender: TObject); 

Var Temp: String;

begin

 

if Exe = '' then ReadExe;    //These 2 lines make sure that a new file cannot

if Exe[3] <> 'P' then Exit;  //be added to a finalized exe..

 

OpenDialog1.Execute;

If OpenDialog1.FileName <> '' then

begin

  Add2Exe('YourFileName'+IntToStr(Count),ExtractFileName(OpenDialog1.FileName));

  AddFile2Exe('YourFile'+IntToStr(Count),OpenDialog1.FileName);

  Inc(Count);

end;

end;

//==============================================================================

 

 

 

//This procedure rebuilds the exe at runtime by adding all the files.

//==============================================================================

procedure TForm1.SpeedButton2Click(Sender: TObject);

Var Temp: String;

begin

ExtractFromExe('YourFileName0',Temp);

If Temp = '' then Exit;

Exe[3] := Chr(Count);

AlterExe;

end;

//==============================================================================

 

 

 

//This procedure extracts a finished archive to disk and views it with browser..

//the first file you stuffed into the exe is what will be executed so make

//certain you put the main page as the first saved file... usually this is

//index.htm/l  ... but it could be anything at all... including another exe :-)

//==============================================================================

procedure TForm1.SpeedButton3Click(Sender: TObject);

Var

Temp: String;

X,Y: Byte;

begin

ReadExe;

If Exe[3] = 'P' then Exit;

Y := ord(Exe[3])-1;

For X := 0 to Y do

begin

  ExtractFromExe('YourFileName'+IntToStr(X),Temp);

  Extract2File('YourFile'+IntToStr(X),Temp);

end;

ExtractFromExe('YourFileName0',Temp);

ShellExecute(Form1.Handle,nil,pchar(Temp),

nil,nil, SW_SHOWNORMAL);

end;

//==============================================================================

 

 

 

//This procedure returns the running exe to its original state .. to activate

//this just double click somewhere on the form of either a finalized program

//or do it if you make a mistake while building an exe and want to start over.

//==============================================================================

procedure TForm1.FormDblClick(Sender: TObject);

Var

Temp: String;

X,Y: Byte;

begin

Y := ord(Exe[3])-1;

For X := 0 to Y do

begin

  DelFromString('YourFileName'+IntToStr(X),Exe);

  DelFromString('YourFile'+IntToStr(X),Exe);

  Exe[3] := 'P';

end;

AlterExe;

end;

//==============================================================================

//This procedure always runs first and it checks to see if the exe is a

//finalized ebook... if it is it alters the appearance of the form to reflect

//that fact :-)

//==============================================================================

procedure TForm1.FormCreate(Sender: TObject);

begin

ReadExe;

if Exe[3] <> 'P' then

begin

  Form1.Height := 85;

  SpeedButton3.Top := 14;

  Form1.Color := $00BFDABA;

  SpeedButton3.Visible := True;

  SpeedButton1.Visible := False;

  SpeedButton2.Visible := False;

end;

end;