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 <stdio.h>

# include <stdlib.h>

main(int argc, char **argv)

{

int i=0;

while (i < argc)

printf("%s\n",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