home *** CD-ROM | disk | FTP | other *** search
- program AutoInst2;
-
- { ==================================================================
-
- Program: AutoInst v2.0
- Author: David Dubois
- Zelkop Software
- Halifax, Nova Scotia
- CompuServe User I.D.: 71401,747
- Date last revised: 1988.04.24
-
- ==================================================================
-
- I hereby dedicate this knowledge to the public domain. I would
- appreciate, though, if you mentioned my name.
-
- This program demonstrates how to write a program which will change
- the value of a typed constant in its own .EXE file. When the
- program is run again, the data will be initialized to the new
- value. No external files are necessary.
-
- Unlike version 1 of this program, this code will work in a unit.
-
- The code shown here is designed for Turbo Pascal version 4.0.
- There is a simpler method available for Turbo 3.0.
-
- For this example, I have written a program that writes a certain
- string a certain number of times. It then prompts the user for a
- new string and a new number. The .EXE file is updated to reflect
- the values entered by the user. The next time the program is run,
- the new values are used.
-
- USES
-
- Examples of the usefulness of this technique would be:
-
- A program that allows the user to change default display colors.
-
- A program that keeps track of a password that the user can change.
-
- HOW TO USE THIS TECHNIQUE
-
- In your own program just copy the ReInstall procedure listed here.
- Replace InstallBlock with the name of the typed constant you wish
- to change, and replace the file name with the name of your
- program. It's that easy.
-
- HOW IT WORKS
-
- You don't have to understand all the details in order to use this
- technique, but here they are.
-
- The data to be changed must be stored in a TurboPascal typed
- constant. In all effect, a typed constant is actually a pre-
- initialized variable. It is always stored in the program's Data
- Segment. The data can be of any type.
-
- First, the procedure finds the .EXE file. In this example, the
- file must be in the current directory, and the user cannot have
- changed the name of the file.
-
- The untyped file is opened with a record size of 1. This allows us
- to read or write a string of bytes using BlockRead and BlockWrite.
-
- As documented in the DOS Technical Reference, the size of the .EXE
- header, in paragraphs (a paragraph is 16 bytes), is stored as a
- two-byte word at position 8 of the file. This is read into the
- variable HeaderSize.
-
- The next step is to find the position of the typed constant in the
- .EXE file. This requires an understanding of the Turbo Pascal 4.0
- memory map, documented on the first and second pages of the Inside
- Turbo Pascal chapter. (That's chapter 26, pages 335 and 336 in my
- manual.)
-
- First, find the address in memory where the typed constant is
- stored. This can be done in Turbo Pascal by using the Seg and Ofs
- functions. Next find the segment of the PSP (program segment
- prefix). This should always be the value returned by PrefixSeg.
- That will mark the beginning of the program in memory. The
- position of the typed constant in the .EXE image should be the
- number of bytes between these two places in memory. But ...
-
- But, two corrections must be made. First, the PSP is not stored in
- the .EXE file. As mentioned on page 335, the PSP is always 256
- bytes. We must subtract that out. Secondly, there is the .EXE file
- header. The size of this has already been read in and must be
- added in to our calculations.
-
- Once the position has been determined, the data stored in the
- typed constant is written in one fell swoop using a BlockWrite.
- This replaces the original data, so that the next time the program
- is run, the new values will used.
-
- ERROR CHECKING
-
- For the sake of simplicity, error checking has been left out of
- this example.
-
- In a real-world application, I would imagine that you would want
- to check that the file has actually been found. If the user ran
- the program from a different directory, or if the program name had
- been changed, the program will fail. In this case, you may want to
- prompt the user for the path where the program can be found.
- (Perhaps you might want to store this information as well.) A
- clever program may be able to search for copies of itself on disk,
- but that's a little dangerous.
-
- Another check could be added. Before writing to disk, you could
- read the value of the data currently stored on the file to make
- sure it matches the original values. This would guarantee that the
- file had not been altered, or that the wrong version of your
- program hadn't been found.
-
- LIMITATIONS
-
- Somehow, the program must be able to find the .EXE file. The
- program cannot be run from the integrated enviroment with the
- Memory option, since no .EXE file is generated.
-
- You cannot use MicroSoft's EXEPACK on the .EXE file, or any other
- packing method I know of. This may change the position, or even
- the size of the typed constant in the file image.
-
- NOTES
-
- Since typed constants are always stored in the data segment, the
- function call to Seg ( InstallBlock ) can be replaced with DSeg. I
- prefer using Seg since it is more descriptive.
-
- One might think that Cseg can used as an alternative to using
- PrefixSeg and subtracting 256. This will work only if the code
- resides in the main program. If, on the other hand, the code is
- used in a unit, PrefixSeg must be used as described here. You
- might as well use PrefixSeg and save yourself some headaches.
-
- If you have any comments or questions I would be glad to hear
- them. If you're on CompuServe, you can EasyPlex a letter to
- 71401,747. Or leave a message on the Borland Programmer's A
- Forum (GO BPROGA). Or, you can write to
-
- Zelkop Software
- P.O. Box 5177
- Armdale, N.S.
- Canada
- B3L 4M7
-
- ==================================================================}
-
- type
- InstallBlockType = record
- TheNumber : integer;
- TheString : string;
- end;
-
- const
- InstallBlock : InstallBlockType
-
- = ( TheNumber : 3;
- TheString : 'Greetings from Zelkop Software' );
-
- procedure ReInstall;
- const
- FileName = 'AutoInst.Exe';
- var
- ExeFile : file;
- HeaderSize : word;
- begin
- assign ( ExeFile, FileName );
- reset ( ExeFile, 1 );
-
- seek ( ExeFile, 8 );
- blockread ( ExeFile, HeaderSize, sizeof ( HeaderSize ) );
-
- seek ( ExeFile, longint(16) * ( seg ( InstallBlock )
- - PrefixSeg
- + HeaderSize )
- + ofs ( InstallBlock )
- - 256 );
-
- blockwrite ( ExeFile, InstallBlock, sizeof ( InstallBlock ) );
-
- close ( ExeFile );
- end;
-
- var
- I : integer;
- begin
- with InstallBlock do
- begin
-
- { write out old data }
-
- for I := 1 to TheNumber do
- writeln ( TheString );
-
- { read in new data }
-
- write ( 'Enter TheNumber: ' );
- readln ( TheNumber );
- write ( 'Enter TheString: ' );
- readln ( TheString );
- end;
-
- { update .EXE file }
-
- ReInstall;
-
- writeln ( 'Now run this program again.' );
- end.
-