GP-TRICKS Logo

Scalar's GP-TRICKS Homepage

Site MapTricks SectionHow To Use the Multiplex


How To Use the Multiplex To Determine Loaded Drivers


Although DOS is a single task operating system, programs called TSRs (terminate-and-stay-resident) can lay suspended in the background and be re-activated by a single key press. The so-called Multiplex interrupt provides a way for communication with and between TSR programs. Since several of the DOS system programs like HIMEM.SYS and PRINT, which play a crucial role during program execution, make use of this interrupt it is sure worth a closer look.

The name "multiplex", or for short "MUX", for the interrupt 2Fh originates from the fact that this interrupt serves as an interface for not only one program, but for several at the same time. Often it proves necessary for a TSR program to receive information from its host program after the first installation in memory. The MUX provides a normed gateway for these needs.

The MUX can be imagined as a long chain of interrupt handlers; to make use of it, a program has to add its own handler to this chain by storing the old interrupt vector (the address that will be called when the interrupt is executed), and then making it point to its own routine. The next time the MUX is called, the program's handler will be in control. It has to check whether this interrupt issues a command to itself or if it is destined for a previous handler. In the first case, it can just go ahead and process the call, ending with an IRET opcode. In the latter case, however, it has to surrender control to the previous handler without changing registers or stack, but since the old vector was stored, that, too, is not a problem

To enable the handler to determine the responsiblity for this interrupt call, every TSR program was given an 8-bit number, the MUX code. The following table shows which MUX codes correspond to what programs:

MUX codeProgram
00h - 7Fhreserved for DOS
      01hPRINT
      06hASSIGN
      10hSHARE
      1AhANSI.SYS
      43hHIMEM
      48hDOSKEY
      4AhDBLSPACE.BIN
      ADhKEYB
      B0hGRAFTABL
      B7hAPPEND
B8h - BFhreserved for networks
C0h - FFhfor use with applications

These MUX codes are delivered inside the AH register. If, say, a 10h is found on examination, the top handler knows this is for the SHARE multiplex handler and hands the request on to the previous handler. This does the same until the SHARE handler is finally reached. It can then process whatever is given in the other registers.

Before I can explain how it is possible to determine what drivers are loaded, it is necessary to talk of MUX code competition. Since many TSR programs have to share the range from C0h to FFh, a situation might arise when a TSR wants to install, but the MUX code is already used by a program in memory. The new program would change the interrupt vector, and commands would never get to the older TSR. To keep this from happening, all MUX handlers have to have a function called "installation check." To do this check, the MUX code has to be sent in AH and 00h in AL. If the MUX code is already in use, AL will have a value different from zero on return. In this case, the TSR program that wants to install right now either has to switch to an alternate MUX code or refuse to install.

But since all MUX handlers have this "installation check" routine, it is possible to use it to determine which TSRs are installed and which are not. The only prerequisite is that the MUX code is known. The code in Listing 1 tests if some of the most common TSR programs are present in memory.

The program is really very simple: It just consists of a loop that cycles through a list of nine MUX codes. Inside the loop, it loads the MUX code into AH and zero into AL. After calling interrupt 2Fh, it checks the AL register: If it still is zero, the driver is not installed.

Unfortunately, many of DOS' system programs that could use the MUX (like EMM386) do not, for reasons only known to Microsoft. On the other hand, many networking and other programs, mainly shareware, do use MUX, and they are easy to detect. In application development, the Multiplex interrupt provides you with a powerful tool to test for incompatible drivers. As soon as you find an incompatibility, include a check and you are at least on the safe side. I once had a very nasty incompatibility with SHARE, and for a long time the only thing I could do was print a message if SHARE was installed. But it kept many computers from crashing and gave me time to code around this incompatibilty. But that's another story.

When dealing with the MUX interrupt, or any other interrupt, Ralf Brown's Interrupt List is an excellent reference. Well, here comes Listing 1:

Listing 1
Borland Pascal 7.0
program MuxAnalyser;
uses Dos;
{ list of MUX codes }
const MUXCodes:array[1..9] of byte =
      ($01,$06,$10,$1A,$43,$48,$AD,$B8,$B7);
      MUXNames:array[1..9] of string =
{ list of names of MUX handlers }
      ('PRINT','ASSIGN','SHARE','ANSI.SYS','HIMEM',
       'DOSKEY','KEYB','GRAFTABL','APPEND');
var regs:Registers;
    a:byte;
begin
   for a:=1 to 9 do { cycle through list }
   begin
      { call "installation check" }
      regs.al:=$00; regs.ah:=MUXCodes[a]; intr($2F,regs);
      Write(MUXNames[a]:10,' is ');
      { driver not installed if AL still = 0 }
      if regs.al=$00 then Write('not ');
      WriteLn('installed');
   end;
   WriteLn;
end.


Back to Top of Page


This article is © 1998-2008 by M. G. Ricken and was exclusively written for GP-Tricks.
Copyright © 1998-2008 by M.G.Ricken        E-Mail: Scalar@psynet.net     |     mgricken@gptricks.de