TITLE   WOW16CAL.ASM
    PAGE    ,132
;
; WOW v1.0
;
; Copyright (c) 1991, Microsoft Corporation
;
; WOW16CAL.ASM
; Thunk router in 16-bit space to route Windows API calls to WOW32
;
; History:
;   25-Jan-1991 Jeff Parsons (jeffpar) Created.
;   24-Apr-91   Matt Felton (mattfe) Incorporated into Kernel
;   29-May-91   Matt Felton (mattfe) Added Multi-Tasking
;   30-Apr-1992 Mike Tricker (MikeTri) Added MultiMedia callbacks
;
;   .xlist
    include kernel.inc
    include tdb.inc
    include dbgsvc.inc
    include wow.inc
    include dpmi.inc
    include cmacros.inc

; include NEW_SEG1 struc used in GetProcModule

    include newexe.inc

    .list

    HACK16  equ 1           ;enable hacks

.286p

Entry   macro name
    ;align 16
    public name
    name&:
    endm

externFP SETCURSORICONFLAG
externFP SETDDEHANDLEFLAG
externFP LOCALALLOC
externFP LOCALREALLOC
externFP LOCALLOCK
externFP LOCALHANDLE
externFP LOCALUNLOCK
externFP LOCALSIZE
externFP LOCALFREE
externFP LOCALINIT
externFP LOCKSEGMENT
externFP UNLOCKSEGMENT
externFP GLOBALALLOC
externFP GLOBALLOCK
externFP GLOBALHANDLE
externFP GLOBALUNLOCK
externFP GLOBALSIZE
externFP GLOBALFREE
externFP FINDRESOURCE
externFP LOADRESOURCE
externFP FREERESOURCE
externFP LOCKRESOURCE
externFP SIZEOFRESOURCE
externFP Int21Handler
externFP IsBadReadPtr
externFP GetSelectorLimit
externFP GetExpWinVer
externNP SwitchTask
externNP WOW16TaskStarted
externFP GetExePtr
externFP GetModuleUsage
externFP WOWGetFastAddress
externFP WOWGetFastCbRetAddress
externFP WowGetFlatAddressArray
externFP WOWNotifyWOW32
externFP GETMODULEHANDLE
externFP GETPROCADDRESS
externFP PrestoChangoSelector
externFP GetModuleFileName
externFP WinExec
externW  gdtdsc
externW  pLocalHeap
externW  hUser
externNP SetOwner
externFP WowCheckUserGdi
externFP GetExePtr
externFP FatalExit

sBegin  NRESCODE
externFP get_sel_flags
externFP set_sel_for_dib
externFP RestoreDib
sEnd    NRESCODE

DataBegin
externW wCurTaskSS
externW wCurTaskBP
externW Win_PDB              ;MikeTri - extracting DOS PDB and SFT
externD pFileTable
externB fExitOnLastApp
externD plstrcmp

if PMODE
externW THHOOK
externD FastBop
externD FastWOW
externW FastWOWCS
externD FastWOWCbRet
externW FastWOWCbRetCS
if PMODE32
externD FlatAddressArray
endif
endif
externW WOWFastBopping
externW curTDB
externW cur_drive_owner
externW LockTDB
externB num_tasks
externW DebugWOW
externW topPDB
externW TraceOff
externD pDosWowData
;ifdef FE_SB
;externW hModNotepad
;endif ; FE_SB

UserModuleName DB 'USER.EXE', 0

DataEnd


sBegin  CODE
assumes CS,CODE
assumes DS,NOTHING
assumes ES,NOTHING

        public  apfnWOW16Func       ;make public to help debugging
apfnWOW16Func   dw  WOW16Return     ;order MUST match RET_* (wow.h)
        dw  WOW16DebugReturn
        dw  WOW16Debug
        dw  WOW16WndProc
        dw  WOW16EnumFontProc
        dw  WOW16EnumWindowProc
        dw  WOW16LocalAlloc
        dw  WOW16LocalReAlloc
        dw  WOW16LocalLock
        dw  WOW16LocalUnlock
        dw  WOW16LocalSize
        dw  WOW16LocalFree
        dw  WOW16GlobalAllocLock
        dw  WOW16GlobalLock
        dw  WOW16GlobalUnlock
        dw  WOW16GlobalUnlockFree
        dw  WOW16FindResource
        dw  WOW16LoadResource
        dw  WOW16FreeResource
        dw  WOW16LockResource
        dw  WOW16GlobalUnlock   ;there is no UnlockResource
        dw  WOW16SizeofResource
        dw  WOW16LockSegment
        dw  WOW16UnlockSegment
        dw  WOW16EnumMetaFileProc
        dw  WOW16TaskStartedTmp        ; in Tasking.asm
        dw  WOW16HookProc
        dw  WOW16SubClassProc
        dw  WOW16LineDDAProc
        dw  WOW16GrayStringProc
        dw  WOW16ForceTaskExit
        dw  WOW16SetCurDir
        dw  WOW16EnumObjProc
        dw  WOW16SetCursorIconFlag
        dw  WOW16SetAbortProc
        dw  WOW16EnumPropsProc
        dw  WOW16ForceSegmentFault
        dw  WOW16lstrcmp
        dw  0                           ;FREE
        dw  0                           ;FREE
        dw  0                           ;FREE
        dw  0                           ;FREE
        dw  WOW16GetExePtr
        dw  0                          ; WOW16GetModuleUsage removed
        dw  WOW16ForceTaskFault
        dw  WOW16GetExpWinVer
        dw  WOW16GetCurDir
        dw  WOW16GetDosPDB
        dw  WOW16GetDosSFT
        dw  WOW16ForegroundIdle
        dw  WOW16WinsockBlockHook
        dw  WOW16SetDdeHandleFlag
        dw  WOW16ChangeSelector
        dw  WOW16GetModuleFilename
        dw  WOW16WordBreakProc
        dw  WOW16WinExec
        dw  WOW16WOWCallback16
        dw  WOW16GetDibSize
        dw  WOW16GetDibFlags
        dw  WOW16SetDibSel
        dw  WOW16FreeDibSel
;ifdef FE_SB
;        dw  WOW16SetFNotepad           ; for Lotus Freelance for Win
;endif ; FE_SB

functableend equ $

; the aRets table looks like this: ...retf, ...retf 2, ...retf 4,  ...

CRETENTRIES equ 020h
; generate the retf n codetable

    bytes = 0
    REPT CRETENTRIES
        align 8
        IFE  bytes
aRets:
        ENDIF
        pop  bx             ;restore app BX
        pop  bp
        add  sp, 0ah          ;pop thunk ret address, wCallID/lpfn, wArgs
        retf bytes
    bytes = bytes + 2
    ENDM
align 8
rettableend equ $
RETFCODESIZE equ (rettableend - aRets) / CRETENTRIES
.errnz ((rettableend - aRets) AND 01h)  ; complain if odd
.erre (RETFCODESIZE EQ 08h)
                                   ; if the size is not 8 bytes need to
                                   ; change the code that indexes 'aRets'

;----------------------------------------------------------------------------
; these comments are a result of hard labour (so called  'fruits'
; of hard labour)
;
; 1. If you make a change in VDMFRAME or similar such change, make sure
;    tasking.asm is in sync. pay attention to the labels wow16doneboot,
;    wow16taskstarted and the resetting of vf_wES (all in tasking.asm)
;
; 2. The general purpose registers es, bx, cx which are saved around the
;    the api thunks. LATER these have to be removed with care and caution.
;    If you just remove the push/pop of these, kernel31 won't boot.
;    These registers will have to be saved around certain calls in krnl286/386
;    for it to  boot.
;
;                                            - nanduri ramakrishna
;
;-----------------------------------------------------------------------------


;-----------------------------------------------------------------------------
; NOTES:
;
; the frame at time of bop is of type VDMFRAME
; the frame at the time of a callback is CBVDMFRAME.
; VDMFRAME and CBVDMFRAME share the first few fields (the order is important)
; but the structures don't overlap.
;
;   ie stack looks like this
;
;               ss:sp = VDMFRAME
;               ...  BOP ....
;  if return from BOP:
;               ss:sp = VDMFRAME
;  if from callback16:
;               ss:sp = CBVDMFRAME
;                .....callback function...
;                                               - nanduri ramakrishna
;-----------------------------------------------------------------------------

    assumes ds, nothing
    assumes es, nothing

align 16
cProc WOW16Call,<PUBLIC,FAR>
    ; parmW   wArgs       ; # paramater bytes pushed for this API
    ; parmW   wCallID


; note that 'bp' of api thunk and callback differ

    pFrame    equ [bp-vf_wBP]
    wAppBX    equ [pFrame].vf_wBX
    wApiRetID equ [pFrame].vf_wRetID
    wAX       equ [pFrame].vf_wAX
    wArgs     equ [pFrame].vf_cbArgs

; for callback16

    pCBFrame  equ [bp-cvf_Parm16];
    vpfnProc  equ [pCBFrame].cvf_vpfnProc
    hInst     equ [pCBFrame+cvf_Parm16].wp_hInst
    hwnd      equ [pCBFrame+cvf_Parm16].wp_hwnd
    wMsg      equ [pCBFrame+cvf_Parm16].wp_wMsg
    wParam    equ [pCBFrame+cvf_Parm16].wp_wParam
    lParam    equ [pCBFrame+cvf_Parm16].wp_lParam

    vpfnWndProc equ [di-cvf_Parm16].cvf_vpfnProc

    lpstr1     equ [pCBFrame+cvf_Parm16].lstrcmpParms.lstrcmp16_lpstr1
    lpstr2     equ [pCBFrame+cvf_Parm16].lstrcmpParms.lstrcmp16_lpstr2

    cbackAX equ [pCBFrame].cvf_wAX   ;
    cbackDX equ [pCBFrame].cvf_wDX
    wGenUse1   equ [pCBFrame].cvf_wGenUse1
    wGenUse2   equ [pCBFrame].cvf_wGenUse2
    vfSP       equ [pCBFrame].cvf_vpStack   ; lo word is sp = ptr to vdmframe

; The stack frame here is defined in wow.h make sure they match
; the order is very important.

cBegin nogen

wc_set_vdmframe:
    push bp
    mov  bp, sp                     ; standard frame
    push bx                         ; REMOVE LATER APPs BX
    push es                         ; REMOVE LATER
    push cx                         ; REMOVE LATER
ifndef PM386
    ; %OUT building 286
    push    ax                      ; dummy values for fs,gs in 286
    push    ax
else
.386
    ; %OUT building 386
    push fs
    push gs
.286
endif
    push ds
    sub  sp, 4                      ; room for api dword return value
    push si                         ; standard regs
    push di

WOW16ApiCall:
    push bp
    push    RET_RETURN  ;push default wRetID (do not move see tasking.asm)
    SetKernelDS ds
    push    [curTDB]        ;save current 16bit task handle (see tasking.asm)
    mov di,ss
    mov [wCurTaskSS],di     ;save current task SS
    mov [wCurTaskBP],bp     ;save current task BP

;   We don't want to allow debuggers to trace into 32 bit land, since they
;   will get lost.

    mov     TraceOff,1h

    test    [WOWFastBopping], 0ffffh
    jz      WOW16SlowVector

WOW16FastVector:

.386
    call    fword ptr [FastWOW]
.286
    jmp     short WOW16CallContinue

    public WOW16SlowVector
Entry   WOW16SlowVector
    BOP BOP_WOW

    public WOW16CallContinue
WOW16CallContinue:  ; don't move this label!  see comment below

    SetKernelDS ds

    xor     ax,ax
    xchg    TraceOff,ax
    test    ax,2h                        ; Turn Tracing Back on ?
    jnz     turn_on_trace_bit

W16C_010:
;   Check for Task Switch
    pop ax                               ; retrieve current task ID
    cmp ax, [curTDB]                     ; Task Switch ?
    jnz jmpSwitchTask                    ; Yes -> Perform Task Switch

    public WOW16CallNewTaskRet           ; from tasking.asm
WOW16CallNewTaskRet:

    pop bx                               ;retrieve wRetID
    pop bp                               ;localbp
    cmp bx, RET_RETURN
    jnz WOW16_From_CallBack16

    public WOW16Return
WOW16Return:

    ; we don't want to return to the thunk, that's just going to
    ; do a RETF n  where n is the # of parameters to the API.
    ; doing this takes about half the time of a RETF on a 486
    ; according to the clock counts in the book.  but RETF also flushes
    ; the instruction prefetch queue, and we're touching one less page
    ; (probably a TLB miss if we're coming back from a call with a long
    ; code path).

wc_restore_regs:

    pop  di
    pop  si
    pop  ax             ;
    pop  dx
    pop  ds
ifndef PM386
    pop  cx             ; trash cx for two dumy words, as real cx is going
    pop  cx             ; to be popped after this.
else
.386
    pop  gs
    pop  fs
.286
endif

    pop  cx                         ; REMOVE LATER
    pop  es                         ; REMOVE LATER
    mov  bx,wArgs       ; get the # of bytes this API took
if KDEBUG
    or   bx, bx
    jz   @F
    test bx, 01h
    jz   @F
    int 3               ; error. odd #bytes to pop
@@:
    cmp  bx, CRETENTRIES * 2
    jl   @F
    int 3               ; error. outside aRets tablerange
@@:
endif
    shl  bx, 2          ; convert it to offset into aRets table
    add  bx, codeoffset aRets
    jmp  bx             ; dispatch to the right RETF n


;
;   If a debugger was tracing the app then reenable on the 16 bit side again
;

turn_on_trace_bit:
    pushf
    pop     ax
    or      ax,FLG_TRAP
    push    ax
    popf
    jmps    W16C_010


    public WOW16_From_CallBack16
WOW16_From_CallBack16:      ; exception RET_DEBUGRETURN and RET_TASKSTARTED
    mov si, bp              ; save bp, dont push on stack
    mov bp, sp              ; for convenience.

    mov ax, ss
    mov es, ax
    mov ds, ax

    mov ax, cbackAX         ; for prolog initialization
    add bx,bx
    jmp apfnWOW16Func[bx]   ;route to appropriate function handler


    public WOW16DebugReturn
Entry   WOW16DebugReturn
     ; undo the 'callback' munging
    mov bp, si
    int 3               ;that's all folks
    jmps WOW16Return

jmpSwitchTask:
    jmp SwitchTask  ; Go perform a Task Switch

    public WOW16TaskStartedTmp
Entry  WOW16TaskStartedTmp
     ; undo the 'callback' munging
    mov  bp, si

    pop  di
    pop  si
    pop  ax             ;
    pop  dx
    pop  ds

ifndef PM386
    pop  cx             ; trash cx for two dumy words, as real cx is going
    pop  cx             ; to be popped after this.
else
.386
    pop  gs
    pop  fs
.286
endif
    pop  cx                         ; REMOVE LATER
    pop  es                         ; REMOVE LATER
    pop  bx                         ; pop  bx  ; REMOVE LATER;
    mov  wApiRetID, RET_RETURN
    jmp  WOW16TaskStarted

;
; Call Back Routines
; On entry, SS:SP points to PARM16 structure
; Assumes PARM16 is followed by vpfn
;

    public WOW16WOWCallback16
Entry   WOW16WOWCallback16    ; 32-bit generic callback

    call    [vpfnProc]        ; call the target proc
    mov     si, [wGenUse1]    ; si = cbArgs
    sub     sp, si            ; undo effect of "RET cbArgs"
    jmp WOW16Done

    public WOW16WndProc
Entry   WOW16WndProc

; don't expect si and di to be saved by the callback function - so save the
; critical info elsewhere like on stack.

; we set 'si' to 'hwnd'. this fixes a bug in QuickCase (qcasew.exe) where
; options.tools.add doesn't bring up a dialog box.
;
    mov     cx,hwnd         ;for later use
    mov     di,bp           ;MSAccess debug version walks BP chain.  they're
    mov     bp,si           ; testing it for us, let's make it easier for them.
    mov     wAX,di          ;save current bp in vdmframe.wAX - temporary
                            ;note:
                            ;   current 'bp (ie di) = 'sp' ,also vdmFrame can be
                            ;   accessed with the new 'bp' (ie 'si').
    mov     si,cx           ;si has hwnd
    call    [vpfnWndProc]   ;call the window proc (AX already set)
    mov     bp,wAX          ;restore pre-callback bp
    mov     sp,bp           ;restore pre-callback sp
    jmp     WOW16Done       ;call back to WOW32

    public WOW16EnumFontProc
Entry   WOW16EnumFontProc

    call    [vpfnProc]      ;call the font proc
ifdef FE_SB  ; HACK for Golf , MS-GolfJ has ( retf  0x34 )!!!
    mov     sp,bp
else
    sub     sp,size PARMEFP ;undo the effect of the proc's RET 0Eh
endif ;FE_SB
    jmp     WOW16Done       ;call back to WOW32

    public WOW16EnumObjProc
Entry   WOW16EnumObjProc
    call    [vpfnProc]      ;call the obj proc
    sub     sp,size PARMEOP ;undo the effect of the proc's RET 0Eh
    jmp     WOW16Done       ;call back to WOW32

    public WOW16EnumWindowProc
Entry   WOW16EnumWindowProc
    call    [vpfnProc]      ;call the font proc
    sub     sp,size PARMEWP ;undo the effect of the proc's RET 06h
    jmp     WOW16Done       ;call back to WOW32

    public WOW16LineDDAProc
Entry   WOW16LineDDAProc
    call    [vpfnProc]      ;call the Line DDA proc
    sub     sp,size PARMDDA     ;undo the effect of the proc's RET 0Eh
    jmp     WOW16Done       ;call back to WOW32

    public WOW16GrayStringProc
Entry   WOW16GrayStringProc
    call    [vpfnProc]      ;call the Graystring proc
    sub     sp,size PARMGST     ;undo the effect of the proc's RET 0Eh
    jmp     WOW16Done       ;call back to WOW32

    public WOW16EnumPropsProc
Entry   WOW16EnumPropsProc
    call    [vpfnProc]      ;call the obj proc
    sub     sp,size PARMEPP ;undo the effect of the proc's RET
    jmp     WOW16Done       ;call back to WOW32

    public WOW16WordBreakProc
Entry   WOW16WordBreakProc
    call    [vpfnProc]      ;call the wordbreak proc
    sub     sp,size PARMWBP ;undo the effect of the proc's RET
    jmp     WOW16Done       ;call back to WOW32

if 0
;
; MultiMedia callbacks - MikeTri 30-Apr-1992
;

Entry   WOW16MidiInFunc
    call    [vpfnProc]      ;call the MidiIn proc
    sub sp,size PARMMIF     ;undo the effect of the proc's RET 12h
    jmp WOW16Done           ;call back to WOW32

Entry   WOW16MidiOutFunc
    call    [vpfnProc]      ;call the MidiOut proc
    sub sp,size PARMMOF     ;undo the effect of the proc's RET 12h
    jmp WOW16Done           ;call back to WOW32

Entry   WOW16IOProc
    call    [vpfnProc]      ;call the MMIO proc
    sub sp,size PARMIOP     ;undo the effect of the proc's RET 0Eh
    jmp WOW16Done           ;call back to WOW32

Entry   WOW16TimeFunc
    call    [vpfnProc]      ;call the Time proc
    sub sp,size PARMTIF     ;undo the effect of the proc's RET 10h
    jmp WOW16Done           ;call back to WOW32

Entry   WOW16WaveInFunc
    call    [vpfnProc]      ;call the WaveIn proc
    sub sp,size PARMWIF     ;undo the effect of the proc's RET 12h
    jmp WOW16Done           ;call back to WOW32

Entry   WOW16WaveOutFunc
    call    [vpfnProc]      ;call the WaveOut proc
    sub     sp,size PARMWOF ;undo the effect of the proc's RET 12h
    jmp     WOW16Done       ;call back to WOW32
endif

Entry   WOW16LocalAlloc
    mov     ax,wMsg         ; set up DS with hInstance
    mov     ds,ax

    cmp     ds:[pLocalHeap], 0  ; already have a local heap in this DS?
    jnz     @f                  ;   yes

    ; we need to LocalInit this segment
    ; note: Win3.1 doesn't check return codes on GlobalSize, LocalInit

    push    ds
    call    far ptr GLOBALSIZE
    sub     ax, 64

    push    ds
    push    0
    push    ax
    call    far ptr LOCALINIT

    push    ds
    call    far ptr UNLOCKSEGMENT

@@:

    push    wParam          ;push wFlags
    push    lParam.lo       ;push wBytes
    call    far ptr LOCALALLOC  ;get hmem in AX
    mov     dx,ds           ; return DS in hiword of handle
    jmp     WOW16Done       ;

Entry   WOW16LocalReAlloc
    mov     ax,lParam.hi    ; set up DS with value from alloc
    mov     ds,ax

    push    lParam.lo       ;push hMem
    push    wMsg            ;push wBytes
    push    wParam          ;push wFlags
    call    far ptr LOCALREALLOC;get hmem in AX
    mov     dx,ds           ;hiword of handle=DS
    jmp     WOW16Done

Entry   WOW16LocalLock

if  0

; HACK32   remove this!

    mov     ax,lParam.hi    ; set up DS with value from alloc
    mov     ds,ax

    push    lParam.lo       ;push hMem
    call    far ptr LOCALLOCK   ;
    sub     dx,dx       ;
    or      ax,ax           ;
    jz      short lalock_done   ;
    IFDEF   HACK16
    push    ax
    push    -1
    call    far ptr LOCKSEGMENT
    pop     ax
    ENDIF
    mov dx,ds           ;if success, return full address in DX:AX
lalock_done:                ;

endif

    jmp WOW16Done       ;

Entry   WOW16LocalUnlock
if  0

; HACK32   remove this!

    mov     ax,lParam.hi    ; set up DS with value from alloc
    mov     ds,ax

    push    lParam.lo       ;push hMem
    call    far ptr LOCALUNLOCK ;
    or      ax,ax       ;
    jnz     short lufree_done   ;
    IFDEF   HACK16
    push    -1
    call    far ptr UNLOCKSEGMENT
    sub     ax,ax   ;
    ENDIF
lufree_done:                ;
    cwd             ;

endif

    jmp WOW16Done       ;

Entry   WOW16LocalSize
    mov     ax,lParam.hi    ; set up DS with value from alloc
    mov     ds,ax

    push    lParam.lo       ;push hMem
    call    far ptr LOCALSIZE   ;
    sub     dx,dx
    jmp     WOW16Done

Entry   WOW16LocalFree
    push    es              ; IsBadReadPtr can trash ES and BX
    push    bx
    mov     ax,lParam.hi    ; get selector of current local heap
    push    ax              ; set up for call to IsBadReadPtr
    push    0
    push    1
    call    far ptr IsBadReadPtr  ; is selector still valid?
    pop     bx
    pop     es
    or      ax,ax
    jnz     wlf_done              ; ax != 0 -> nope!

    mov     ax,lParam.hi    ; set up DS with value from alloc
    mov     ds,ax

    push    lParam.lo       ;push hMem
    call    far ptr LOCALFREE   ;
wlf_done:
    jmp WOW16Done       ;


Entry   WOW16GlobalAllocLock
    push    wParam          ;push wFlags
    push    lParam.hi       ;push dwBytes
    push    lParam.lo       ;
    call    far ptr GLOBALALLOC ;get hmem in AX
    sub     dx,dx           ;
    or      ax,ax           ;
    jz      short galock_done   ;
    push    ax          ;save hmem
    push    ax          ;push hmem
    call    far ptr GLOBALLOCK  ;get seg:off in DX:AX
    pop     bx          ;recover hmem in BX
galock_done:                ;
    mov     wGenUse1, bx
    jmp     WOW16Done       ;

Entry   WOW16GlobalLock
    push    wParam          ;push hMem
    call    far ptr GLOBALLOCK  ;
    push    ax          ;save return value
    push    dx          ;
    or      ax,dx
    jz      glock_exit
    push    wParam          ;push hMem
    call    far ptr GLOBALSIZE  ;
glock_exit:
    mov     wGenUse2,ax           ;save size
    mov     wGenUse1,dx           ;
    pop     dx          ;
    pop     ax          ;
    jmp     WOW16Done       ;

Entry   WOW16GlobalUnlock
    push    wParam          ;push hMem
    call    far ptr GLOBALUNLOCK;
    cmp     ax,1            ;
    sbb     ax,ax           ;
    cwd             ;make return code a full 32-bits
    jmp WOW16Done       ;

Entry   WOW16GlobalUnlockFree
    push    lParam.hi       ;push segment of address to free
    call    far ptr GLOBALHANDLE;
    or      dx,ax           ;valid handle?
    jz      short gufree_done   ;no
    push    ax          ;save a copy of hmem for the free
    push    ax          ;push hmem to unlock
    call    far ptr GLOBALUNLOCK;
    pop     cx          ;recover copy of hmem
    or      ax,ax           ;is lock count now zero?
    jnz     short gufree_err    ;no
    push    cx          ;push hmem to free
    call    far ptr GLOBALFREE  ;
gufree_exit:                ;
    or      ax,ax           ;
    mov     ax,1            ;if success, return TRUE; otherwise, FALSE
    jz      short gufree_done   ;
gufree_err:             ;
    sub     ax,ax           ;
gufree_done:                ;
    cwd             ;
    jmp     WOW16Done       ;

Entry   WOW16FindResource
    push    wParam          ;push hTask
    call    far ptr GetExpWinVer
    push    ax              ;save expwinver

    push    wParam          ;push hTask
    push    lParam.hi       ;push vpName
    push    lParam.lo       ;
    push    hwnd            ;push vpType
    push    wMsg            ;
    call    far ptr FINDRESOURCE;
;    or  ax,ax              ;
;    jz  short findres_done ;
;findres_done:              ;
    cwd                     ;make return code a full 32-bits
    pop     cx              ; expwinver
    mov     wGenUse1, cx
    jmp  WOW16Done     ;

Entry   WOW16LoadResource
    push    wParam          ;push hTask
    push    lParam.lo       ;push hResInfo
    call    far ptr LOADRESOURCE;
    cwd             ;make return code a full 32-bits
    jmp  WOW16Done     ;

Entry   WOW16FreeResource
    push    wParam          ;push hResData
    call    far ptr FREERESOURCE;
    cmp ax,1
    sbb ax,ax
    cwd              ;make return code a full 32-bits
    jmp WOW16Done

Entry   WOW16LockResource
    push    wParam       ;hResData
    call    far ptr LOCKRESOURCE;
    push    ax          ; save res pointer
    push    dx
    or      dx,dx

; I commented out the following code because it is breaking the US builds
; in the case where hResData is bad.  If you put code like this in, please
; comment in *detail* (with bug number perhaps) why you did.  
; In this case, jz lres_err isn't accounting for the push ax, push dx 
; instructions above.  If there is a case where the stack is off by 4 bytes
; please put a note in as to how & why.  - cmjones
;
;ifdef FE_SB             ;avoid to break stack
;    jz      lres_err
;else
    jz      lres_exit
;endif ; FE_SB
    push    wParam       ;push hResData
    call    far ptr GLOBALSIZE
lres_exit:
    mov     wGenUse2,ax           ;save size
    mov     wGenUse1,dx           ;
    pop     dx
    pop     ax
    jmp     WOW16Done

; see "I commented out..." note above
;ifdef FE_SB            ;avoid to break stack
;lres_err:
;    xor     ax,ax
;    jmp     WOW16Done
;endif ; FE_SB

Entry   WOW16SizeofResource
    push    wParam       ;push hTask
    push    lParam.lo        ;push hResInfo
    call    far ptr SIZEOFRESOURCE          ; DX:AX is DWORD size
    jmp     WOW16Done

Entry   WOW16LockSegment
    push    wParam       ;push wSeg
    call    far ptr LOCKSEGMENT
    sub     dx,dx
    jmp     WOW16Done

Entry   WOW16UnlockSegment
    push    wParam          ;push wSeg
    call    far ptr UNLOCKSEGMENT
    cmp ax,1
    sbb ax,ax
    cwd              ;make return code a full 32-bits
    jmp  WOW16Done

;MikeTri Beginning of temporary hack for testing - 17-Aug-1992

Entry   WOW16GetDosPDB
    push ds                     ;Save DS
    SetKernelDS                 ;Pick up Kernel DS
    mov  dx, Win_PDB            ;Copy Windows PDB to DX (selector)
    mov  ax,0                   ;Move 0 to AX (offset)
    UnSetKernelDS               ;Get rid of kernel DS
    pop  ds                     ;Restore callers DS
    jmp  WOW16Done              ;Exit

Entry   WOW16GetDosSFT
    push ds                     ;Save DS
    SetKernelDS                 ;Pick up Kernel DS
    mov  dx,pFileTable.sel      ;Move SFT selector value to DX
    mov  ax,pFileTable.off      ;Move SFT offset value to AX
    UnSetKernelDS               ;Get rid of kernel DS
    pop  ds                     ;Restore callers DS
    jmp  WOW16Done

;MikeTri End of temporary hack for testing - 17-Aug-1992

Entry   WOW16EnumMetaFileProc
    call    [vpfnProc]          ;call the apps MetaFile proc
    sub     sp,size PARMEMP     ;undo the effect of the proc's RET 0x10h
    jmp     WOW16Done   ;call back to WOW32

Entry   WOW16HookProc

    call    [vpfnProc]          ;call the apps Hook Proc.
    sub     sp,size PARMHKP      ;undo the effect of the proc's RET 0x08h
    jmp     WOW16Done   ;call back to WOW32


Entry   WOW16SetAbortProc
    call    [vpfnProc]          ;call the apps abort proc
;   sub     sp,size PARMSAP     ;undo the effect of the proc's RET 0x04h
;
;   Use 'bp' to restore 'sp' instead of subtracting 4bytes from sp. this is
;   because Wordperfect's Informs doesn't pop the arguments off the stack.
;   However it preserves 'bp'.
;
;   Here in wow, sp is same as bp .  The correct value  is in 'bp' - see
;   WOW16_From_CallBack16
;
;   Similar fix can also be found in win31 - core\gdi, function queryabort()
;
;                                   - nandurir
;

    mov     sp, bp
    jmp     WOW16Done           ;call back to WOW32


Entry   WOW16SubClassProc

    push    ds
    SetKernelDS ds
    mov     ax, hUser
    pop     ds                       ; restore ds
    UnSetKernelDS ds
    pop     cx                       ; cx = the ordinal number
    push    cx                       ; restore stack pointer
    push    ax                       ; hModule
    push    0                        ; hiword of ordinal number
    push    cx                       ; the ordinal
    call    GetProcAddress
    jmp     WOW16Done   ;call back to WOW32

Entry   WOW16SetCurDir
    call    SetCurrentDrive           ; on the stack is drive number;
    call    WOW16SetCurrentDirectory  ; on the stack is directory name;
    sub     sp,size PARMDIR           ; restore stack
    jmp     WOW16Done   ;call back to WOW32


Entry   WOW16SetDdeHandleFlag
    push    wParam          ;push hMem
    push    wMsg            ;push fSet
    call    far ptr SETDDEHANDLEFLAG
    jmp     WOW16Done       ;


Entry   WOW16SetCursorIconFlag
    push    wParam          ;push hMem
    push    wMsg            ;push fSet
    call    far ptr SETCURSORICONFLAG
    jmp     WOW16Done       ;


Entry   WOW16GetExePtr
    push    wParam          ;push hInstance
    call    GetExePtr
    jmp     WOW16Done

;ifdef FE_SB
;Entry   WOW16SetFNotepad
;    push    ds
;    SetKernelDS                 ; pick up Kernel DS
;    mov     ax,wParam
;    mov     hModNotepad,ax      ; handle of notepad32
;    pop     ds                  ; restore ds
;    UnSetKernelDS ds
;    jmp     WOW16Done
;endif ; FE_SB

Entry   WOW16ForceTaskExit
    mov     ax,4CFFH        ; Hung App Support Forces Current Task to Exit
    DOSCALL
    INT3_NEVER

Entry   WOW16GetModuleFilename
    push    wParam      ; hInstance
    push    lParam.hi   ; selector of filename buffer
    push    lParam.lo   ; offset   of filename buffer
    push    wMsg        ; bytes    in filename buffer
    call    far ptr GetModuleFileName
    jmp     WOW16Done       ; Just return return value

Entry   WOW16WinExec
    push    lParam.hi   ; selector of lpszCmdLine
    push    lParam.lo   ; offset   of lpszCmdLine
    push    wParam      ; fuCmdShow
    call    far ptr WinExec
    jmp    WOW16Done       ; Just return return value

Entry   WOW16GetExpWinVer
    push    wParam          ;push hInstance
    call    GetExpWinVer
    jmp     WOW16Done

Entry   WOW16GetCurDir
    call    WOW16GetCurrentDirectory
    sub     sp,size PARMDIR           ; restore stack
    jmp     WOW16Done   ;call back to WOW32


Entry   WOW16ForceTaskFault
    ; %OUT    Ignore Impure warning A4100 its required for Forcing a GP Fault
    mov     cs:gdtdsc,0     ; Force a GP Fault - Write to our CS
    jmp     WOW16ForceTaskFault

Entry   WOW16ForceSegmentFault
    push    es          ; IsBadReadPtr can trash ES & BX
    push    bx
    push    lParam.hi   ; selector of lp
    push    lParam.lo   ; offset   of lp
    push    1           ; min byte size
    call    far ptr IsBadReadPtr  ; force segment fault or handle GPF
    pop     bx
    pop     es
    jmps    WOW16Done

Entry   WOW16lstrcmp
    push ds                     ;Save DS
    SetKernelDS                 ;Pick up Kernel DS
    push    word ptr lpstr1[2]
    push    word ptr lpstr1[0]
    push    word ptr lpstr2[2]
    push    word ptr lpstr2[0]
    call    [plstrcmp]
    UnSetKernelDS               ;Get rid of kernel DS
    pop  ds                     ;Restore callers DS
    jmps    WOW16Done

Entry   WOW16ForegroundIdle
    mov     ax,1689h        ;notify application that the foreground
    int     2fh             ;task has gone idle
    jmps    WOW16Done

Entry   WOW16WinsockBlockHook
    call    [vpfnProc]          ;call the apps Hook Proc.
    jmps    WOW16Done           ;call back to WOW32

Entry   WOW16ChangeSelector
    push    wParam          ;push wSeg
    push    wParam          ;push wSeg
    call    far ptr PRESTOCHANGOSELECTOR;
    cCall   SetOwner,<wParam,-1>   ; Make this new guy the owner
    jmps    WOW16Done       ; Just return return value

Entry   WOW16GetDibSize
    push    wParam      ; selector for which size is being queryed
    call    far ptr GetSelectorLimit
    jmps    WOW16Done       ; Just return return value

Entry   WOW16GetDibFlags
    cCall   get_sel_flags,<wParam>
    jmps    WOW16Done       ; Just return return value

Entry   WOW16SetDibSel
    cCall   set_sel_for_dib,<wParam,wMsg,lParam.lo,lParam.hi,hwnd>
    jmps    WOW16Done       ; Just return return value

Entry   WOW16FreeDibSel
    cCall   RestoreDib,<wParam,wMsg,lParam.hi,lParam.lo>
    jmps    WOW16Done       ; Just return return value

Entry   WOW16Debug
    int 3               ;that's all folks
    ;fall into WOW16Done

Entry   WOW16Done
    mov     cbackAX, ax      ; set return value
    mov     cbackDX, dx

    mov     bp, word ptr vfSP    ; verify the saved ES is still valid 
.386p
    verr    [bp].vf_wES          ;    see bug #121760 
    jz      @f                   ; jump if still valid
    mov     [bp].vf_wES, es      ; if not, update saved ES with a known good one
@@:                              ;    - cmjones  11/12/97
    mov     bp, [bp].vf_wLocalBP

    ; fall  thru. the return values are set for a 'real' callback only
    ; don't use 'entry' macro for wow16doneboot as it 'align 16s' the label
    ; thus putting extra instructions between cbackDx, dx and mov bp,si.

    public  WOW16DoneBoot           ; tasking.asm needs this label
WOW16DoneBoot:                      ; tasking.asm needs this label
    push    bp                   ;rebuild the frame
    push    RET_RETURN           ;push default wRetID (do not move see tasking.asm)
    SetKernelDS ds
    push    [curTDB]        ;save current 16bit task handle (see tasking.asm)
    mov [wCurTaskSS],ss     ;save current task SS
    mov [wCurTaskBP],bp     ;save current task BP
    mov     TraceOff,1h             ; Don't allow debuggers to trace to 32 bit land

    test    [FastWOWCbRetCS], 0ffffh
    jz      WOW16SlowCBReturn

.386
    call    fword ptr [FastWOWCbRet]
.286

    ; don't put any code here!!!
    ; when fastbopping, after kernel has booted we return
    ; directly to WOW16CallContinue

    jmp     WOW16CallContinue


WOW16SlowCBReturn:

    IFE PMODE
    BOP BOP_UNSIMULATE          ;return from host_simulate
    ELSE
    FBOP BOP_UNSIMULATE,,FastBop
    ENDIF

    jmp     WOW16CallContinue

cEnd nogen ; WOW16Call



;
; Initialize address of fast Bop entry to monitor.
;
cProc WOWFastBopInit,<PUBLIC,FAR>
cBegin
IF PMODE
    push    ds
    push    es
    push    bx
    push    dx

    DPMIBOP GetFastBopAddress
    CheckKernelDS   ds              ; On debug, check that DS is really kernels
    ReSetKernelDS   ds              ; Assume it otherwise.
    ;
    ; Set up FastBop address (for DPMI, and WOW without WOW16FastVector)

    mov     word ptr [FastBop],bx
    mov     word ptr [FastBop + 2],dx
    mov     word ptr [FastBop + 4],es
    or      bx,dx
    jz      NoFastWow

    call    far ptr WOWGetFastAddress
    mov     word ptr [FastWOW],ax
    mov     word ptr [FastWOW+2],dx

    or      ax,dx
    jz      NoFastWow

    mov     word ptr [FastWOWCS],es
    mov word ptr [WOWFastBopping],1

    call    far ptr WOWGetFastCbRetAddress
    mov     word ptr [FastWOWCbRet],ax
    mov     word ptr [FastWOWCbRet+2],dx

    or      ax,dx
    jz      NoFastCb

    mov     word ptr [FastWOWCbRetCS],es

if PMODE32
    call    far ptr WowGetFlatAddressArray
    mov     word ptr [FlatAddressArray],ax
    mov     word ptr [FlatAddressArray + 2],dx
endif
NoFastCb:
NoFastWow:

    pop     dx
    pop     bx
    pop     es
    pop     ds
    UnSetKernelDS ds
ENDIF
cEnd    WOWFastBopInit

cProc WOWNotifyTHHOOK,<PUBLIC,FAR>
cBegin
    CheckKernelDS ds
    ReSetKernelDS ds

    mov     DebugWOW,0

if PMODE32
    push    1
else
    push    0
endif
    push    seg THHOOK
    push    offset THHOOK
    push    DBG_TOOLHELP
    FBOP BOP_DEBUGGER,,FastBop
    add     sp,+8

    push    seg cur_drive_owner
    push    offset cur_drive_owner

    push    topPDB
    push    0

    push    seg LockTDB
    push    offset LockTDB

    push    seg DebugWOW
    push    offset DebugWOW

    push    seg curTDB
    push    offset curTDB

    push    seg num_tasks
    push    offset num_tasks

    push    codeBase
    push    codeOffset Int21Handler

    call    WOWNotifyWOW32

    UnSetKernelDS ds
cEnd    WOWNotifyTHHOOK

cProc WOWQueryDebug,<PUBLIC,FAR>
cBegin
    push    ds

    SetKernelDS

    mov     ax,DebugWOW

    pop     ds
    UnSetKernelDS

cEnd WOWQueryDebug


;*--------------------------------------------------------------------------*
;*
;*  WOW16GetCurrentDirectory() -
;*
;*      - Drive =0 implies 'current' drive.
;*--------------------------------------------------------------------------*
cProc WOW16GetCurrentDirectory, <NEAR, PUBLIC>, <SI, DI>

ParmD lpDest
ParmW Drive

cBegin
        push    ds          ; Preserve DS
        les     di,lpDest       ; ES:DI = lpDest
        push    es
        pop     ds          ; DS:DI = lpDest
        cld
        mov     ax,Drive        ; AX = Drive
        or      al,al       ; Zero?
        jnz     CDGotDrive      ; Yup, skip
        mov     ah,19h      ; Get Current Disk
        DOSCALL
        inc     al          ; Convert to logical drive number
CDGotDrive:
        mov     dl,al       ; DL = Logical Drive Number
        add     al, 040h    ; drive letter
        mov     ah, 03Ah    ; ':'
        stosw
        mov     al,'\'      ; Start string with a backslash
        stosb
        mov     byte ptr es:[di],0  ; Null terminate in case of error
        mov     si,di       ; DS:SI = lpDest[1]
        mov     ah,47h      ; Get Current Directory
        DOSCALL
        jc      CDExit      ; Skip if error
        xor     ax,ax       ; Return FALSE if no error
CDExit:
        pop     ds          ; Restore DS
cEnd


;*--------------------------------------------------------------------------*
;*                                                                          *
;*  WOW16SetCurrentDirectory() -                                            *
;*                                                                          *
;*--------------------------------------------------------------------------*

cProc WOW16SetCurrentDirectory, <NEAR, PUBLIC>,<si,di>

ParmD lpDirName

cBegin
        push    ds          ; Preserve DS
        lds     dx,lpDirName    ; DS:DX = lpDirName
    mov ah,3Bh      ; Change Current Directory
    DOSCALL
        jc      SCDExit     ; Skip on error
        xor     ax,ax       ; Return FALSE if successful
SCDExit:
        pop     ds          ; Restore DS
cEnd


;*--------------------------------------------------------------------------*
;*                                      *
;*  SetCurrentDrive() -                             *
;*                                      *
;*--------------------------------------------------------------------------*

; Returns the number of drives in AX.

cProc SetCurrentDrive, <NEAR, PUBLIC>,<si,di>

ParmW Drive

cBegin
        mov     dx,Drive
    mov ah,0Eh      ; Set Current Drive
    DOSCALL
        sub     ah,ah       ; Zero out AH
cEnd


; --- GetTaskHandle0 ---
; ripped out piece of GetTaskHandle, taken from CONTEXT.ASM which was not
; part of WOW's kernel, so we copied this little piece out.
;

GetTaskHandle0:
        or      ax,ax
        jnz     gt1
        SetKernelDS     es
        mov     ax,curTDB
gt1:    mov     es,ax
        assumes es, nothing
;       cmp     es:[TDB_sig],TDB_SIGNATURE
;       jne     gt2
        ret
;gt2:   kerror  ERR_TASKID,<GetTaskHandle: Invalid task handle>
;       ret


;*--------------------------------------------------------------------------*
;*                                                                          *
;*  WowSetExitOnLastApp(WORD fExitOnLastApp)                                *
;*     Sets fExitOnLastApp variable which causes kernel to exit when the    *
;*     last app except WowExec exits.  Called by WowExec for seperate       *
;*     WOW VDMs, which need to exit after the last app closes.              *
;*                                                                          *
;*--------------------------------------------------------------------------*

cProc  WowSetExitOnLastApp, <PUBLIC, FAR>

ParmW fExit

cBegin
    SetKernelDS

    mov     ax, fExit
    mov     fExitOnLastApp, al
cEnd

;-----------------------------------------------------------------------;
; WowFixWin32CurDir
;
; Called by thunks for PrivateProfile APIs which need Win32 current
; directory to reflect Win16 current directory (imagine that!)
;
; Trashes AX, DX which shouldn't matter
;
; History:
;  Mon Dec 20, 1993  -by-  Dave Hart [DaveHart]
;   Don't ask me about current directories and WOW!  I'll deny it all!
;-----------------------------------------------------------------------;

Entry WowFixWin32CurDir
        push    ds
        SetKernelDS
        mov     ax,[CurTDB]
        or      ax,ax
        jz      WFW32CD_Exit
        mov     ds,ax                       ; DS points to TDB
        UnSetKernelDS
        cmp     ds:[TDB_sig],TDB_SIGNATURE
        jne     WFW32CD_Exit
        mov     dl,ds:[TDB_Drive]
        and     dl,7fh
        mov     ah,0Eh                      ; change drive
        DOSCALL
        mov     dx,TDB_LFNDirectory         ; DS:DX points to TDB curdir
        mov     ah,3Bh                      ; change directory
        DOSCALL
if KDEBUG
        jnc     WFW32CD_Exit
        krDebugOut DEB_WARN, "WowFixWin32CurDir: DOS fn 3B fails error #AX"
endif
WFW32CD_Exit:
        pop     ds
        ret

; sudeepb 11-May-1994
;
; This hackcheck is for simcity. Simcity does a GlobalSize on GDI.EXE and
; USER.EXE to figure out how much free resources are available. WOW's USER
; GDI have pretty small DGROUP, hence the size returns fails the check of
; this app. So we need to fake a bigger size.
;

cProc HackCheck,<PUBLIC,NEAR>
    parmW   handle
cBegin]
    push    es
    SetKernelDS es
    ; first check in the TDB that the currently running app is SCW.
    mov     ax,curtdb
    mov     es,ax
    xor     ax,ax
    cmp     word ptr es:[0f2h],4353h    ; SC (mod name in TDB at f2 offset)
    jne     hc5
    cmp     word ptr es:[0f4h],0057h    ; W
    jne     hc5

    ; Its SCW. Now get the module table for the given handle and check if its
    ; for USER.EXE and GDI.EXE
    cCall   GetExePtr,<handle>
    or      ax,ax
    jz      hc5
    mov     ds,ax
    mov     si,ds:[ne_pfileinfo]
    lea     dx,[si].opFile          ; DS:DX -> path
    cCall   WowCheckUserGdi,<ds,dx> ; Much easier to check this in 32bit land.
hc5:
    pop     es
cEnd

;-----------------------------------------------------------------------;
; WowSetCompatHandle
;
; This routine takes a single parameter and saves it in the TDB. It is
; used to take care of a bug in dBase where it confuses handle values.
; This is a private API called by USER.EXE.
;
; All registers must be saved. DS is saved automatically by cmacros.
; History:
;-----------------------------------------------------------------------;

cProc  WowSetCompatHandle, <PUBLIC, FAR>
ParmW handle
cBegin
        push    bx
        SetKernelDS
        mov     bx,[CurTDB]
        or      bx,bx
        jz      @f                              ;check for zero just in case
        mov     ds,bx                           ; DS points to TDB
        UnSetKernelDS
        mov     bx, handle
        mov     ds:[TDB_CompatHandle],bx        ;save it here
@@:
        pop     bx
cEnd

sEND    CODE

end