home *** CD-ROM | disk | FTP | other *** search
- program SetPath;
-
- { Program: SetPath
- Author: David Dubois
- Zelkop Software
- Halifax, N.S.
- CompuServe User I.D.: 71401,747
- Date: 1988.04.27
-
- I hereby dedicate this knowledge to the public domain. Feel free to use
- it, but if you do, please mention my name. There are no guarantees, and
- in fact, I wouldn't bet a dollar that it will work every time.
-
- I just figured this all out in the last couple of hours, so please
- excuse the sparse documentation. I hope to upload something more
- concrete in the near future.
-
- This program shows how to find the global MS-DOS enviroment.
-
- As an example, this program will update the PATH= string in the global
- enviroment to the string passed as a parameter.
-
- On normal circumstances, a program can only work with its own copy of
- the DOS enviroment. The purpose of this program is to break that
- barrier.
-
- THINGS YOU MAY NOT HAVE KNOWN
-
- Every program that is run gets its own Program Segment Prefix (PSP).
- This is an area of memory that COMMAND.COM uses to communicate
- information to the program. For example, one such bit of information is
- the segment address of the program's copy of the enviroment.
-
- At offset $16 of the PSP you can find the segment address of the parent
- program's PSP.
-
- In COMMAND.COM's PSP, this segment actually points to itself.
-
- Therefore, we can find COMMAND.COM's PSP by tracing the line back,
- until we get to a program whose PSP's parent is itself.
-
- "Aha!", you say, "so we just look at COMMAND.COM's PSP to see where its
- enviroment is." Sorry, it's not that simple. Understandably,
- COMMAND.COM treats its own PSP a little differently than its
- children's. Particularly, where usually one can find the segment
- address of the enviroment, one instead finds zeros. Hmmm ...
-
- Here comes the shaky part:
-
- The thing to realize, is since the size of the enviroment is not set in
- stone, COMMAND.COM has to dynamically allocate the memory for it. This
- is done with the standard DOS memory allocation calls. Therefore,
- somewhere, nearby, there must be memory allocation block with the
- global enviroment in it. (This is shaky logic step #1).
-
- A memory allocation block starts on a segment boundary. The first byte
- is either a $4D (letter M) or a $5A (letter Z). It will be $5A only if
- this is the last memory that has been allocated. In this program I have
- assumed that the block we're looking for won't be the last. (That is
- shaky logic step #2.) The next two bytes are the segment of the PSP
- that allocated the memory. This we are pretty sure we know. The next
- two bytes are a bonus: a word describing the number of paragraphs that
- were allocated. If we can find what we are looking for, this should be
- the size of the enviroment.
-
- Let's look for such a block. Starting at COMMAND.COM's PSP segment, we
- look through segment boundaries until we find a match. We will assume
- that such a block will be found. (Shaky logic step #3) Even, worse we
- will assume that the first such block we find is the enviroment block.
- (Finally, shaky logic step #4).
-
- Assuming that the great spirit of PC-dom is working in our favor today,
- and all of these assumptions turn out to be true, we are all set. The
- enviroment itself starts at the next segment boundary (as is the nature
- of DOS allocated memory blocks) and we know the size of the enviroment.
- Now we can have our way.
-
- REPLACING THE PATH
-
- This part was written in hurry. I was anxious to share the information
- so far described with all our friends. I haven't put in proper checks
- to make sure that overflow does not occur. If that happens, some of the
- strings will become truncated, but I don't think smoke will start
- coming out the back of the machine. Perhaps in the near future I will
- clean it up and release a new version. I won't go too deeply into an
- explanation.
-
- Essentially it starts with a blank, NewEnv, the same size as the old
- enviroment. It copies in the new PATH, then it copies the old
- enviroment, filtering out any old PATH. Then fills the rest, if any
- with zeros. I added two zeros onto the end as a safety measure. Then
- copy the new over the old.
-
- COMMENTS, SUGGESTIONS, CURSES
-
- That this works at all is based on experimental, rather than properly
- documented, evidence. There are no guarantees. But then, its free.
-
- I'm open to any comments or suggestions that anyone out there might
- have. Specifically, I'd be interested to know if it works on your
- machine, or if it doesn't work on your machine. If it doesn't work, can
- you find an alternate solution for your machine, or find out what,
- specifically, is wrong with my assumptions? Can anyone out there find
- any documentation that would guarantee my assumptions are true? Can any
- of you prove Fermat's last conjecture?
-
- You can write me at
-
- David Dubois
- Zelkop Software
- P.O. Box 5177
- Armdale, N.S.
- Canada
- B3L 4M7
-
- or you if you're on CompuServe you can EasyPlex me at 71401,747, or
- leave a message on the Borland's Programmer A Forum (GO BPROGA). }
-
- type
- EnvType = array [ 1 .. 32768 ] of char;
- EnvPtr = ^ EnvType;
- var
- Env : EnvPtr;
- Bytes : word;
-
- procedure FindEnvironment;
- var
- CommandSeg : word;
- TempSeg : word;
- BlockSeg : word;
- begin
- TempSeg := PrefixSeg; { Trace the PSP's }
- repeat { back into previous }
- CommandSeg := TempSeg; { generations }
- TempSeg := memw [ TempSeg : $16 ];
- until CommandSeg = TempSeg;
-
- BlockSeg := CommandSeg; { Look for }
- repeat { allocation block }
- inc ( BlockSeg );
- until ( mem [ BlockSeg : 0 ] = $4D )
- and ( memw [ BlockSeg : 1 ] = CommandSeg );
-
- Env := ptr ( succ ( BlockSeg ), 0 ); { pointer to enviroment }
- Bytes := 16 * memw [ BlockSeg : 3 ]; { size of enviroment in bytes }
- end;
-
- procedure ReplacePath ( NewPath : string );
- var
- NewEnv : EnvPtr;
- OldOfs : word;
- NewOfs : word;
- I : word;
- begin
- getmem ( NewEnv, Bytes ); { make place to copy }
-
- OldOfs := 1;
- NewOfs := 1;
-
- for I := 1 to length ( NewPath ) do { uppercaserize }
- NewPath [ I ] := upcase ( NewPath [ I ] );
- NewPath := 'PATH=' + NewPath + #0; { store new path }
- for I := 1 to length ( NewPath ) do
- begin
- NewEnv ^ [ NewOfs ] := NewPath [ I ];
- inc ( NewOfs );
- end;
-
- while ( NewOfs <= Bytes ) and ( OldOfs <= Bytes ) do { copy rest }
- if ( Env ^ [ OldOfs ] = 'P' )
- and ( Env ^ [ OldOfs + 1 ] = 'A' )
- and ( Env ^ [ OldOfs + 2 ] = 'T' ) { filter out }
- and ( Env ^ [ OldOfs + 3 ] = 'H' ) { old path }
- and ( Env ^ [ OldOfs + 4 ] = '=' ) then
- begin
- while Env ^ [ OldOfs ] <> #0 do
- inc ( OldOfs );
- inc ( OldOfs );
- end
- else
- begin
- NewEnv ^ [ NewOfs ] := Env ^ [ OldOfs ]; { moving }
- inc ( NewOfs );
- inc ( OldOfs );
- end;
-
- while NewOfs <= Bytes do
- begin
- NewEnv ^ [ NewOfs ] := #0; { fill rest }
- inc ( NewOfs );
- end;
-
- NewEnv ^ [ Bytes - 1 ] := #0; { safety }
- NewEnv ^ [ Bytes ] := #0;
-
- move ( NewEnv ^, Env ^, Bytes ); { do it }
- end;
-
- begin
- FindEnvironment;
- ReplacePath ( paramstr ( 1 ) );
- end.