Search code examples
assemblydosx86-16

Full path to self in DOS executable


In my 16bit DOS program I want to get the full path to the instance of my program, using DOS interrupt or its internal tables. In other words, I'm looking for DOS equivalent of Windows API function GetModuleFileName(NULL)

Interrupt 21h/AH=60h seemed to be a right track but it fails when the program is not in current directory. I made a simple test program:

MYTEST PROGRAM FORMAT=COM
    MOV AH,60h    ; TRUENAME - CANONICALIZE FILENAME OR PATH.
    MOV SI,MyName
    MOV DI,MyFullName
    INT 21h       ; Convert filename DS:SI to canonizalized name in ES:DI.
    MOV AH,09h    ; WRITE STRING$ TO STARNDARD OUTPUT.
    MOV DX,DI
    INT 21h       ; Display the canonizalized name.
    RET           ; Terminate program.
MyName     DB "MYTEST.COM",0 ; The ASCIIZ name of self (this executable program).
MyFullName DB 256 * BYTE '$' ; Room for the canonizalized name, $-terminated.
  ENDPROGRAM MYTEST

It was created as "C:\WORK\MYTEST.COM" and run in DOSBox on Windows 10/64bits:

C:\WORK>dir
MYTEST   COM     284 Bytes.
C:\WORK>mytest
C:\WORK\MYTEST.COM      REM this works as expected.
C:\WORK>d:
D:\>c:mytest
D:\MYTEST.COM           REM this is wrong, no such file exists.
D:\>

Does anybody know a way how to get argv[0] in 16bit assembler program?


Solution

  • Depending on DOS version you might use the undocumented fact that the file name can be found after the environment variables. Such as:

    org 100h
    
        mov ax, [2Ch]    ; segment of environment from PSP
        mov ds, ax
        xor si, si
    findloop:
        cmp word [si], 0 ; one zero for end of string, another for end of table
        lea si, [si+1]
        jne findloop
        lodsb            ; skip end of table
        lodsw            ; number of additional strings (?)
        cmp ax, 1
        jne error
        mov ah, 2
    printloop:
        lodsb
        test al, al
        jz done
        mov dl, al
        int 21h
        jmp printloop
    done:
    error:
        mov ax, 4C00h
        int 21h
    

    At least in dosbox this gives the full path. Under different OS you might need to combine with the current directory or even search PATH, if it works at all.