INT 21h AH=44h is a family of calls, selected by AL, that ask about or control the device behind a handle or a drive, rather than moving data through it. The one most programs need is AL = 00h, get device information: for the handle in BX it returns a word in DX that says what the handle is connected to.
| DX bit | A device (bit 7 = 1) | A file (bit 7 = 0) |
|---|---|---|
| 0 | console input (the keyboard) | bits 0-5: the drive, 0 = A, 1 = B, 2 = C |
| 1 | console output (the screen) | |
| 2 | the NUL device | |
| 3 | the clock device | |
| 4 | fast output through INT 29h | |
| 5 | binary (raw) mode: no Ctrl+C check, no line editing | |
| 6 | end-of-input flag | not written since it was opened |
| 7 | 1: a character device | 0: a disk file |
| 14 | the driver takes control strings (02h / 03h) | |
| 15 | on a network drive |
Bit 7 is the test. A program that wants to know whether its output is redirected asks about handle 1: a device with bit 1 set is the screen, bit 7 = 0 means a file (PROG > OUT.TXT), and a device without bit 1 is NUL or a printer. MORE and programs that draw progress bars use this to decide whether to pause, or whether to draw at all.
MOV DX, OFFSET M1MOV AH, 09h ; DOS: print the string at DS:DXINT 21hMOV BX, 1 ; handle 1, standard outputCALL KINDMOV AX, 3D01h ; open the NUL device for writingMOV DX, OFFSET NULNINT 21hCALL CHECKMOV BX, AXMOV DX, OFFSET M2MOV AH, 09h ; DOS: print the string at DS:DXINT 21hCALL KINDMOV AH, 3Eh ; close itINT 21hMOV AH, 3Ch ; DOS: create TEST.TXTXOR CX, CX ; CX = 0: normal attributesMOV DX, OFFSET FNAMEINT 21hCALL CHECK ; stop if CF = 1MOV BX, AX ; BX = the handleMOV DX, OFFSET M3MOV AH, 09h ; DOS: print the string at DS:DXINT 21hCALL KINDMOV AH, 3Eh ; close the handleINT 21hMOV AH, 41h ; delete TEST.TXTMOV DX, OFFSET FNAMEINT 21hFNAME DB "TEST.TXT", 0NULN DB "NUL", 0M1 DB "standard output: $"M2 DB "NUL: $"M3 DB "TEST.TXT: $"KIND PROC NEAR ; print what handle BX isMOV AX, 4400h ; DOS IOCTL 00h: get device informationINT 21h ; DX = the information wordTEST DL, 80h ; bit 7: a device?JZ KIND2TEST DL, 03h ; bits 0 and 1: console input, outputMOV DX, OFFSET KCON ; (MOV leaves the flags alone)JNZ KIND1MOV DX, OFFSET KDEVKIND1:MOV AH, 09hINT 21hRETKIND2:AND DL, 3Fh ; a file: bits 0-5 = the drive, 0 = AADD DL, "A"MOV KDRV, DLMOV DX, OFFSET KFILEMOV AH, 09hINT 21hRETKIND ENDPKCON DB "the console", 13, 10, "$"KDEV DB "a device, not the console", 13, 10, "$"KFILE DB "a file on drive "KDRV DB "?", 13, 10, "$"CHECK PROC NEAR ; CF = 1: print the error code in AL and exitJNC CHECK1PUSH AXMOV DX, OFFSET FAILMSGMOV AH, 09hINT 21hPOP AXCALL PHEXBMOV AX, 4C01h ; exit with code 1INT 21hCHECK1:RETCHECK ENDPFAILMSG DB "failed: error $"PHEXB PROC NEAR ; print AL as two hex digitsPUSH CXPUSH DXMOV DH, AL ; keep the byteMOV CL, 4SHR AL, CL ; the high digit firstMOV CX, 2PHEXB1:AND AL, 0FhADD AL, "0"CMP AL, "9"JBE PHEXB2ADD AL, 7 ; 10..15 -> "A".."F"PHEXB2:MOV DL, ALMOV AH, 02h ; DOS: print DLINT 21hMOV AL, DH ; then the low digitLOOP PHEXB1POP DXPOP CXRETPHEXB ENDP
Seeing redirection
Run with its output redirected to a file, the example above would report a file for standard output. The next one gets that effect without a command line: it points handle 1 at TEST.TXT with INT 21h AH=45h and 46h, as COMMAND.COM does for >, and asks while the redirection is in place. The answer is printed through handle 1, so it lands in the file, and the program shows it once handle 1 is back on the console.
MOV AH, 3Ch ; create TEST.TXTXOR CX, CXMOV DX, OFFSET FNAMEINT 21hCALL CHECKMOV SI, AX ; SI = the fileMOV AH, 45h ; keep a copy of standard outputMOV BX, 1INT 21hCALL CHECKMOV DI, AX ; DI = the console, savedMOV AH, 46h ; handle 1 := the file, as "> TEST.TXT"MOV BX, SIMOV CX, 1INT 21hCALL CHECKMOV BX, 1CALL KIND ; the answer goes into the fileMOV AH, 46h ; handle 1 := the console againMOV BX, DIMOV CX, 1INT 21hCALL CHECKMOV AH, 3Eh ; close the saved copyMOV BX, DIINT 21hMOV DX, OFFSET M1MOV AH, 09h ; DOS: print the string at DS:DXINT 21hMOV AX, 4200h ; rewind the fileMOV BX, SIXOR CX, CXXOR DX, DXINT 21hMOV AH, 3Fh ; read what KIND wrote thereMOV CX, 64MOV DX, OFFSET BUFINT 21hCALL CHECKMOV CX, AXCALL OUT1 ; print it (DX = BUF still)MOV AH, 3Eh ; close the handleINT 21hMOV AH, 41h ; delete TEST.TXTMOV DX, OFFSET FNAMEINT 21hFNAME DB "TEST.TXT", 0M1 DB "while redirected, handle 1 was: $"BUF DB 64 DUP (?)KIND PROC NEAR ; print what handle BX isMOV AX, 4400h ; DOS IOCTL 00h: get device informationINT 21h ; DX = the information wordTEST DL, 80h ; bit 7: a device?JZ KIND2TEST DL, 03h ; bits 0 and 1: console input, outputMOV DX, OFFSET KCON ; (MOV leaves the flags alone)JNZ KIND1MOV DX, OFFSET KDEVKIND1:MOV AH, 09hINT 21hRETKIND2:AND DL, 3Fh ; a file: bits 0-5 = the drive, 0 = AADD DL, "A"MOV KDRV, DLMOV DX, OFFSET KFILEMOV AH, 09hINT 21hRETKIND ENDPKCON DB "the console", 13, 10, "$"KDEV DB "a device, not the console", 13, 10, "$"KFILE DB "a file on drive "KDRV DB "?", 13, 10, "$"CHECK PROC NEAR ; CF = 1: print the error code in AL and exitJNC CHECK1PUSH AXMOV DX, OFFSET FAILMSGMOV AH, 09hINT 21hPOP AXCALL PHEXBMOV AX, 4C01h ; exit with code 1INT 21hCHECK1:RETCHECK ENDPFAILMSG DB "failed: error $"PHEXB PROC NEAR ; print AL as two hex digitsPUSH CXPUSH DXMOV DH, AL ; keep the byteMOV CL, 4SHR AL, CL ; the high digit firstMOV CX, 2PHEXB1:AND AL, 0FhADD AL, "0"CMP AL, "9"JBE PHEXB2ADD AL, 7 ; 10..15 -> "A".."F"PHEXB2:MOV DL, ALMOV AH, 02h ; DOS: print DLINT 21hMOV AL, DH ; then the low digitLOOP PHEXB1POP DXPOP CXRETPHEXB ENDPOUT1 PROC NEAR ; write CX bytes at DS:DX to handle 1PUSH BXMOV BX, 1 ; standard outputMOV AH, 40hINT 21hPOP BXRETOUT1 ENDP
Other subfunctions
| AL | Does |
|---|---|
| 01h | set device information from DX (DH must be 0): bit 5 on CON switches it to raw mode |
| 02h / 03h | read / write a control string from / to a character device driver |
| 04h / 05h | the same for the block device of the drive in BL |
| 06h | input status: AL = FFh ready, 00h not (a file: not at its end yet) |
| 07h | output status |
| 08h | is the drive in BL removable? AX = 0 yes, 1 no |
| 09h | is the drive in BL on a network? bit 12 of DX |
| 0Ah | is the handle in BX on a network? bit 15 of DX |
| 0Dh | generic block device request (DOS 3.2+): disk geometry, formatting, the volume serial |
DOSBox-X leaves bit 6 at 0 for a writable file on a host folder, where MS-DOS sets it until the first write, and CON's bit 6 there can change with the keyboard. Test single bits (7, 1, the drive bits) rather than comparing the whole word.