INT 21h AH=45h returns a new handle number that refers to the same open file as BX. It is not a second open. DOS keeps one entry per open file in its system file table, with the file pointer, the access mode and the buffers, and both handles point to that entry. A read, a write or a seek through either handle moves the pointer for both.
What the copy is good for: closing it. INT 21h AH=3Eh on the copy writes out DOS's buffers and updates the directory entry, while the original stays open at its position. Before DOS 3.3 brought a commit call (68h), duplicate-and-close was the way to make sure the data had reached the disk.
MOV 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 AH, 45h ; DOS: duplicate the handle in BXINT 21hCALL CHECKMOV DI, AX ; DI = the copyMOV AH, 40h ; write "ABC" through the originalMOV CX, 3MOV DX, OFFSET ABCINT 21hCALL CHECKPUSH BXMOV BX, DI ; ask the copy where the pointer isMOV AX, 4201h ; seek 0 from the current positionXOR CX, CXXOR DX, DXINT 21hCALL CHECKMOV SI, AX ; SI = the position, seen through the copyMOV AH, 3Eh ; close the copy: DOS flushes the fileINT 21hPOP BXMOV AH, 40h ; the original still works: write "DE"MOV CX, 2MOV DX, OFFSET ABC+3INT 21hCALL CHECKMOV AX, 4202h ; the size: seek 0 from the endXOR CX, CXXOR DX, DXINT 21hCALL CHECKMOV DI, AX ; DI = the sizeMOV AH, 3Eh ; close the handleINT 21hMOV AH, 41h ; delete TEST.TXTMOV DX, OFFSET FNAMEINT 21hMOV DX, OFFSET M1MOV AH, 09h ; DOS: print the string at DS:DXINT 21hMOV AX, SICALL PDECMOV DX, OFFSET CRLFMOV AH, 09h ; DOS: print the string at DS:DXINT 21hMOV DX, OFFSET M2MOV AH, 09h ; DOS: print the string at DS:DXINT 21hMOV AX, DICALL PDECMOV DX, OFFSET CRLFMOV AH, 09h ; DOS: print the string at DS:DXINT 21hFNAME DB "TEST.TXT", 0ABC DB "ABCDE"M1 DB "position seen through the copy: $"M2 DB "after closing the copy, size: $"CRLF 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 ENDPPDEC PROC NEAR ; print AX in decimalPUSH BXPUSH CXPUSH DXMOV BX, 10XOR CX, CX ; CX = digits pushedPDEC1:XOR DX, DXDIV BX ; AX = AX / 10, DX = the last digitPUSH DXINC CXOR AX, AXJNZ PDEC1PDEC2:POP DX ; the digits come back first to lastADD DL, "0"MOV AH, 02hINT 21hLOOP PDEC2POP DXPOP CXPOP BXRETPDEC ENDP
Redirection
The other use is saving a standard handle. Function 46h, force duplicate, makes handle CX refer to the same open file as BX, closing whatever CX was before. COMMAND.COM runs PROG > FILE with the pair: it opens the file, keeps a copy of handle 1 with 45h, points handle 1 at the file with 46h, and when the program returns puts the saved copy back with 46h and closes it. The INT 21h AH=44h article does the same inside one program.
Errors: 04h when all 20 handles of the program are in use, 06h when BX is not an open handle. Handles a child program inherits through EXEC are shared the same way, file pointer included, unless the file was opened with bit 7 of the access mode set (INT 21h AH=3Dh).