Microsoft KB Archive/68100

Finding a Program’s Fully Qualified Pathname ID Number: Q68100

3.x 4.00 4.01 MS-DOS

Problem:

I have an application that needs to know where it was loaded from and executed by MS-DOS. Specifically, it needs to know the complete pathname of where the program actually resides in order to be able to access associated program data files stored in the same directory as the program.

Response:

The section 4.3, “The MS-DOS Program Segment,” in the “Microsoft MS-DOS Programmer’s Reference,” includes a brief explanation about a data structure area that MS-DOS sets up in addition to the copy of the parent’s environment variables whenever it loads and executes a program. The reference also states that programs can use this area to determine where a program was loaded. Note that support for this additional information added to the program’s environment block began with MS-DOS version 3.00.

This data structure includes the MS-DOS default supplied fully qualified pathname of the program that owns the environment. A fully qualified pathname (or filename) consists of the complete path from the root directory, prefixed by a logical drive and followed by the program name and extension. Thus, by locating this MS-DOS supplied pathname string, a program can know where it was loaded and executed from. Locating this fully qualified pathname is a simple task from assembly language, but is even simpler for a Microsoft C language program, since the C run-time places this fully qualified pathname in string ARGV[0]. See the programming samples included below for the exact methodology.

More Information:

When MS-DOS executes a program, it copies the parent’s environment and places the segment address of this copy at offset +2cH in the program segment prefix (PSP). The environment is a series of ASCII strings, each of which is terminated by a zero byte. The set of strings that composes the environment itself is terminated by another zero byte. Following the end of the environment is a set of initial arguments that MS-DOS passes to a program. This set of arguments, or the data structure, consists of a word count of the number of strings that follow this environment and the set of ASCIIZ strings. This count is normally one (but can be more), since MS-DOS also supplies the fully qualified pathname of the program or process owning this environment as the first ASCIIZ string in this data structure. Note that this structure should not be confused with the unformatted parameter area at offset +80H within the PSP area, which contains all the characters typed after the command invocation on the MS-DOS command line.

C and Assembly Language Coding Examples
———————– ARGV.C ———————————

/* This test program will display all program invocation / / DOS command line arguments. Note: C run-time ARGV[0] / / is the FULLY QUALIFIED PATHNAME. */

= include  =

= include  =

main(int argc, char **argv) { int i=0;

while (i < argc) printf(“%s”,argv[i++]);

}

———————– FINDP.ASM ——————————–

TITLE  TEST: DISPLAY FULLY QUALIFIED PATHNAME Comment | This test program only displays the FULLY QUALIFIED PATHNAME which follows the program’s environment string area.

Assemble source with MASM 5.1+ and LINK to .EXE format. |

DOSSEG .MODEL SMALL

.DATA

.CODE START:


 * ES=DS=PSP Segment. Get environment segment from PSP. mov ax,es:[2ch] mov es,ax mov ds,ax ;set DS=ES


 * Scan for end environment strings (find two null bytes) ;Use SCASB because don’t know if will find even or odd aligned. xor al,al ;looking for first null byte xor di,di ;offset zero for environment seg mov cx,08000h ;32K bytes max environment size cld scan_bytes: repnz scasb ;scan for first zero byte cmp byte ptr [di],0 ;Found first, test next byte ;for zero too. jnz scan_bytes ;not zero, continue scan


 * Display “fully qualified pathname” which follows end environment ;and is terminated by a null byte add di,3 ;Adjust DI to point to beginning of mov si,di ;ASCIIZ string by skipping over null ;byte+word count preceding string.


 * display string via BIOS INT 10H, TTY get_byte: cld lodsb or al,al ;test for null terminating byte jz done mov ah,0eh ;BIOS INT 10H, TTY int 10h jmp short get_byte

done: mov ax,4c00h ;MS-DOS INT 21H terminate program

int    21h

END    START