Calling a DLL Written for Windows from a TSR for MS-DOS

Last reviewed: April 12, 1995
Article ID: Q67845
The information in this article applies to:
  • Microsoft Windows Device Development Kit (DDK) for Windows versions 3.0 and 3.1

SUMMARY

A TSR (terminate-and-stay-resident) program running under MS-DOS can call a dynamic-link library (DLL) written for the Microsoft Windows environment. This is possible by using the Interrupt 2Fh services provided by Windows and the MS-DOS Protected Mode Interface (DPMI).

MORE INFORMATION

To call the TSR program, an application can use the DPMI Simulate Real Mode Interrupt function or the DPMI Call Real Mode Procedure function with a FAR return frame.

To call a DLL from a TSR, perform the following four steps:

  1. Design the function to be called from the TSR similar to an interrupt service routine (ISR), and put it into a DLL. The module definition (DEF) file for the DLL must contain the statement CODE PRELOAD FIXED. Here is a code fragment for a callback function:

    ; My callback code in a CODE PRELOAD FIXED Windows DLL ; ; Note: The real mode CS:IP in the real mode CallStruct must

       ;        be fixed up for IRET to work correctly, as shown below:
    
       My_Call_Back:                         ; The real mode callback entry
    
          ;==========================================================
          ; On entry to this routine:
          ;
          ;   DS:SI -> Real mode SS:SP
          ;   ES:DI -> Real mode call structure
          ;   Interrupts disabled
          ;
          ; On exit:
          ;   ES:DI -> Real mode call structure
          ;==========================================================
    
          call     Do_It                     ; Function that handles
                                             ; the callback
    
          cld
          lodsw                              ; Get real mode IP from stack
          mov      WORD PTR es:[di+2Ah], ax  ; Store IP in call struc
          lodsw                              ; Get real mode CS from stack
          mov      WORD PTR es:[di+2Ch], ax  ; Store CS in call struc
          add      WORD PTR es:[di+2Eh], 4   ; Bump real mode SP past CS:IP
    
          iret                               ; Exit My_Call_Back
    
    

  2. Use the DPMI Allocate Real Mode callback function to set up a callback address to the function, as follows:

          mov      ax, 0303h               ; Allocate real mode callback
                                           ; address
          push     ds
          push     cs
          pop      ds
          mov      si, OFFSET My_Call_Back
          pop      es
          mov      di, OFFSET MyRMCS       ; Offset of real mode call
                                           ;   structure, used for DPMI
                                           ;   translation services
                                           ;   (see Chapter 11 of the
                                           ;   INTEL DPMI Spec. v 0.9)
    
          int      31h                     ; Call DPMI
    
          jc       CB_Error                ; If carry set, call failed
          jmp      Set_CB_Addr
    
       CB_Error:
          mov      ax, 1
          jmp      Set_CB_Exit
    
       Set_CB_Addr:
          mov      WORD PTR CB_Addr+2, cx   ; Store SEG:OFF of callback
          mov      WORD PTR CB_Addr, dx     ;   address in local variable
    
       Set_CB_Exit :                        ; Exit
    
    
    

  3. Pass the real mode callback address, returned from the code above, to the TSR and store it, as follows:

    ; Call the TSR, passing the real mode callback in BX:CX

    Notify_TSR:

          mov      bx, WORD PTR CB_Addr+2    ; Real mode callback seg
          mov      cx, WORD PTR CB_Addr      ; Real mode callback off
          mov      ax, 8F00h                 ; ID and function number
          int      TSR_Int_No
    
          cmp      al, 00h
          jz       Notify_Success
    
       Notify_Failure:
          mov      al, 1                     ; Return failure in AL
    
       Notify_Success:
    
    
    

  4. When it is time for the TSR to call the DLL, use Interrupt 2Fh to determine whether the current virtual machine (VM) is VM 1 (the Windows VM). If it is, use the assembly language statement CALL DWORD PTR dwCallBackAddr to call the real mode callback address. If the current VM is not VM 1, use the Interrupt 2Fh service Switch VMs and Callback (Function 1685h). Specify the real mode callback address stored in the TSR in step 3 above for the ES:BX value in the call.

    ; ; Code in TSR, which is loaded before Windows ;

    Call_DLL_Entry:

          mov      ax, 1683h                 ; Windows Interrupt 2Fh
          int      2Fh                       ;    (Get Current VM)
    
    
          cmp      bx, 1                     ; Windows is always VM 1
                                             ; (version 3.0 *ONLY*)
          jz       Call_DLL                  ; We're in Windows VM
    
       Switch_VMs_And_Call_DLL:              ; We're not in Windows VM
    
          mov      ax, 1685h                 ; Windows Interrupt 2Fh
                                             ;   switch VMs and callback
          mov      bx, 1                     ; Windows 3.0 is always VM 1
          mov      cx, 0                     ; All flags off
          mov      dx, 0                     ; Priority boost not required
          mov      si, 0                     ;
          mov      di, seg SwitchProc        ; Segment of switch procedure
          mov      es, di                    ;
          mov      di, offset SwitchProc     ; Offset of switch procedure
          int      2Fh                       ;
    
          jnc      My_1685h_Success
    
       My_1685h_Error:
    
          ; AX = error code:   1 = Invalid VM ID
          ;                    2 = Invalid priority boost
          ;                    3 = Invalid flags
    
          .
          .
          .
    
          jmp      Call_DLL_Exit
    
       My_1685h_Success:
    
            mov     ax, 0
            jmp     Call_DLL_Exit
    
       Call_DLL:
    
          Call     DWORD PTR CB_Addr          ; FAR CALL to real mode
                                              ;   callback
    
       Call_DLL_Exit:
    
          .
          .
          .
    
          iret                               ; return to caller or
                                             ;   hardware interrupt
    
       SwitchProc proc
    
          pusha
          push    ds
          push    es
    
          call    DWORD PTR CB_Addr          ; FAR CALL to real mode
                                             ;   callback
          pop     es
          pop     ds
          popa
    
          iret                               ; Switches back to VM from
                                             ;   which it was called
    
       SwitchProc endp
    
    
The four steps above allocate a unique procedure callback address and pass it to the TSR, which stores the address. When the TSR calls the DLL, if the Windows virtual machine (VM) is running, the TSR calls the callback address directly. Otherwise, the TSR calls the Switch VMs and Callback function to schedule the Windows virtual machine. One parameter for this function is the address to call once the requested VM is running.

In this case, the Windows scheduler switches VMs, then it calls the SwitchProc function in the TSR. When SwitchProc calls the routine in the DLL that corresponds to the allocated real mode callback address, the DLL receives control to perform its processing.

Once the DLL completes its processing, it executes an IRET instruction to return control to the SwitchProc. Then SwitchProc itself executes an IRET instruction. At this point, the Windows scheduler switches back to the VM from which it was called.

All Interrupt 2Fh functions are documented in Appendix C of the "Microsoft Windows Device Driver Kit: Device Driver Adaptation Guide" for Windows 3.1 and in Appendix D of the "Microsoft Windows Device Development Kit Virtual Device Adaptation Guide" for Windows 3.0.

DPMI (Interrupt 31h) services are documented in the Intel document "MS-DOS Protected Mode Interface Specification." A paper copy of the DPMI specification is available free of charge from Intel Literature. In the United States, contact Intel at (800) 548-4725. Outside the US, contact the Intel distributor for your country.


Additional reference words: 3.00 3.10 DDKDPMI DDKTSR
KBCategory: kbprg
KBSubcategory: IsrInt21Quest


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: April 12, 1995
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.