Microsoft KB Archive/67845

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

Article ID: 67845

Article Last Modified on 7/27/2004

-

APPLIES TO


 * Microsoft Windows Device Development Kit (DDK) for Windows 3.0
 * Microsoft Windows Device Development Kit (DDK) for Windows 3.1

-



This article was previously published under Q67845



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:

  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   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   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:   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 &quot;Microsoft Windows Device Driver Kit: Device Driver Adaptation Guide&quot; for Windows 3.1 and in Appendix D of the &quot;Microsoft Windows Device Development Kit Virtual Device Adaptation Guide&quot; for Windows 3.0.

DPMI (Interrupt 31h) services are documented in the Intel document &quot;MS-DOS Protected Mode Interface Specification.&quot; 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 query words: 3.00 3.10 DDKDPMI DDKTSR

Keywords: KB67845

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.