;--------------------------------------------------------------------------- ; Optimzed Code Path - on x86 builds effectively excecutes USER32 code. ; ; Created: ; 16-DEC-93 nandurir ;--------------------------------------------------------------------------- TITLE USER5.ASM PAGE ,132 .286p .xlist include ks386p.inc .286p NOEXTERNS=1 ; to suppress including most of the stuff in user.inc include wow.inc include wowusr.inc ;;;;;include cmacros.inc include user.inc .list externFP WOW16Call createSeg _TEXT,CODE,WORD,PUBLIC,CODE createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP defgrp DGROUP,DATA externFP WowSetCompatHandle ;--------------------------------------------------------------------------- ; Optimized thunks for x86 only ; ; ;--------------------------------------------------------------------------- ifndef PMODE32 USER16CLIENTTHUNK macro Iapi, api, argtypeslist, returntype, api32, apispecificcode, callserver sBegin CODE index = 0 IRP argtype, index = index + 1 ENDM IFE index &Iapi &api, 0 ELSE &Iapi &api ENDIF sEnd CODE endm else externFP OutputDebugString LOGARGS macro apiname push dx push ax push cs push OFFSET afterlog_&apiname call OutputDebugString pop ax pop dx jmp short afterlogname_&apiname afterlog_&apiname: DB 'USER: ','&apiname','()', 0dh, 0ah, 0 afterlogname_&apiname: endm ; flat selector values ; FLATDS equ KGDT_R3_DATA OR RPL_MASK FLATFS equ KGDT_R3_TEB OR RPL_MASK ; set flat ds and fs ; SETFLATDSANDFS macro .386p mov ax, FLATDS mov ds, ax mov ax, FLATFS mov fs, ax endm externFP GetSelectorBase GETFLATADDRESS macro farpointer ; check for null xor dx, dx mov ax, word ptr &farpointer+2 or ax, ax jz @F cCall GetSelectorBase, ; check for base address 0 mov cx, ax or cx, dx jz @F ; now its ok add ax, word ptr &farpointer adc dx, 0 @@: endm ; generates code like: parmW arg1 ; GENPARAM macro argtype, argname parm&argtype &argname endm pushWORD_DWORD macro argname movzx eax, &argname push eax endm pushINT_LONG macro argname movsx eax, &argname push eax endm pushDWORD_DWORD macro argname push dword ptr &argname endm pushPSZ_DWORD macro argname, apiname, argnumber GETFLATADDRESS &argname push dx push ax IFNB or ax, dx jnz @F add sp, argnumber * 4 xor eax, eax jmp short FailCall_&apiname @@: ENDIF endm pushHHOOK_DWORD macro argname push dword ptr -1 ; unreferenced parameter ; effectively an assertion endm pushARG16 macro argname push &argname endm CALLORDECLARE macro typestring, api32, totalbytes &typestring api32&@&totalbytes endm TESTCALLSERVERCONDITION macro mov edx, DWORD PTR _wow16CsrFlag test BYTE PTR [edx], 1 endm ; assumes eax is pointer to the flag CLEARCALLSERVERCONDITION macro mov BYTE PTR [edx], 0 endm ;-------------------------------------------------------------------------- ; Iapi = either DUserThunk or UserThunk ; api = actual name ; argtypeslist = list of argument 'types' like ; api32 = this function is called instead of _Api ; apispecificcode = flag indicating additional code needed for this api. ; This is intended for handling 'compatibility'. ; ; If this argument is not blank, then there must exist a macro ; APISPECIFICCODE_api, which expands to the desired code. ; At present it is included just before the 'return' to ; the app. ; ; callserver = flag indication that it may be necessary to actually call ; USER32. ; ; If this argument is not blank, then there must exist a macro ; CALLSERVERCONDITION_api which expands to the desired code and ; clears or sets the zero flag. If ZF is clear, the actual ; thunk gets called, else nop. ; ; ; generates code similar to: ; ; externFP _Api OR Api32 ; sBegin CODE ; if necessary ; FUN_WOWApi equ FUN_Api ; DUserThunk WOWApi, %(size Api16) ; endif ; ; cProc Api, , ; parmW arg1 ; cBegin ; movzx, eax, arg1 ; push eax ; call far ptr _Api OR Api32 (decorates the names) ; ; if necessary checks the callservercondtion ; resets the callservercondition ; push arg1 ; call WOWApi ; the actual thunk to wow32/server ; @@: ; endif ; ; if exists, includes code in apispecificcode_api ; endif ; cEnd ; sEnd CODE ; ; - nanduri ;-------------------------------------------------------------------------- USER16CLIENTTHUNK macro Iapi, api, argtypeslist, returntype, api32, apispecificcode, callserver ;*** declare api ; index = 0 IRP argtype, index = index + 1 ENDM IFB CALLORDECLARE , _&api, %(index*4) ELSE CALLORDECLARE , _&api32, %(index*4) ENDIF sBegin CODE ; _&api ;*** create thunk to wow32 ; IFNB FUN_WOW&api equ FUN_&api DUserThunk WOW&api, %(size api&16) ENDIF ;*** create thea Api label ; IFNB IFIDNI , cProc &api, , ELSE cProc I&api, , ENDIF ENDIF ;*** declare args ; nargcount = 0 IRP argtype, nargcount = nargcount + 1 IFIDNI , genparam W, arg%(nargcount) ENDIF IFIDNI , genparam W, arg%(nargcount) ENDIF IFIDNI , genparam W, arg%(nargcount) ENDIF IFIDNI , genparam D, arg%(nargcount) ENDIF IFIDNI , genparam D, arg%(nargcount) ENDIF IFIDNI , genparam D, arg%(nargcount) ENDIF IFIDNI , genparam D, arg%(nargcount) ENDIF IFIDNI , genparam D, arg%(nargcount) ENDIF IFIDNI , genparam W, arg%(nargcount) ENDIF IFIDNI , genparam D, arg%(nargcount) ENDIF ENDM ;*** begin body ; cBegin ;*** set 32bit registers ; SETFLATDSANDFS ;*** push args in reverse ; FailCall = 0 argtopush = nargcount REPT nargcount inputargindex = 0 IRP argtype, inputargindex = inputargindex + 1 IFE argtopush - inputargindex IFIDNI , pushWORD_DWORD arg%argtopush ENDIF IFIDNI , pushINT_LONG arg%argtopush ENDIF IFIDNI , pushINT_LONG arg%argtopush ENDIF IFIDNI , pushDWORD_DWORD arg%argtopush ENDIF IFIDNI , pushDWORD_DWORD arg%argtopush ENDIF IFIDNI , pushDWORD_DWORD arg%argtopush ENDIF IFIDNI , pushPSZ_DWORD arg%argtopush ENDIF IFIDNI , FailCall = argtopush ; fails call if null pushPSZ_DWORD arg%argtopush, &api, %argtopush ENDIF IFIDNI , pushINT_LONG arg%argtopush ENDIF IFIDNI , pushHHOOK_DWORD arg%argtopush ENDIF ENDIF ENDM argtopush = argtopush - 1 ENDM ;*** called user32/client api ; IFB CALLORDECLARE , _&api, %(nargcount*4) ELSE CALLORDECLARE , _&api32, %(nargcount*4) ENDIF ;*** check if we ever need to call server ;*** calls the real wow thunk IFNB TESTCALLSERVERCONDITION jz @F CLEARCALLSERVERCONDITION index = 0; IRP argtype, index = index + 1 pushARG16 arg%index ENDM call WOW&api @@: ENDIF ;*** check for any api specific compatibility code to execute ; IFNB APISPECIFICCODE_&api ENDIF IF FailCall FailCall_&api: ENDIF IFNB IRP argtype, IFIDNI , mov edx, eax shr edx, 16 EXITM ENDIF ENDM IFIDNI , xor ax, ax ENDIF ENDIF ifdef DEBUG ;LOGARGS &api endif cEnd ; end body sEnd CODE ; _&api endm endif ; PMODE32 assumes CS,CODE assumes DS,DATA assumes ES,NOTHING ;;;;;;;;;;sBegin CODE ; macro will generate this APISPECIFICCODE_GETCLIENTRECT macro xor eax, eax endm APISPECIFICCODE_GETKEYSTATE macro mov cl, ah and cl, 080h or al, cl endm APISPECIFICCODE_GETWINDOWRECT macro xor eax, eax endm ; The following call is only for a dBase for Windows 5.0 bug. Notice however, that this ; means that the internal KERNEL api WowSetCompatHandle will be called for every ; single invocation of GetDlgItem, no matter what app is running. This is bad, but ; on X86 platforms we don't transition to WOW32, and the cost of testing for it ; is just about as expensive as just saving it. Still, this should be removed as ; soon as we are convinced that the dBase bug has been fixed. -NeilSa APISPECIFICCODE_GETDLGITEM macro push ax call WowSetCompatHandle endm public _wow16gpsi public _wow16CsrFlag public _wow16gHighestUserAddress sBegin CODE _wow16gpsi DD 0 _wow16CsrFlag DD 0 _wow16gHighestUserAddress DD 0 sEnd CODE ; the following may end up calling wow32 USER16CLIENTTHUNK UserThunk, DEFHOOKPROC, , dword, WOW16DefHookProc,,srvcond USER16CLIENTTHUNK UserThunk, ENABLEMENUITEM, , word,,,srvcond USER16CLIENTTHUNK DUserThunk, GETKEYSTATE, , int,, compatcode, srvcond USER16CLIENTTHUNK UserThunk, GETKEYBOARDSTATE, , boolzero,,,srvcond ; the following are all thunked locally USER16CLIENTTHUNK UserThunk, CLIENTTOSCREEN, ,boolzero USER16CLIENTTHUNK UserThunk, GETCLASSNAME, , word, GETCLASSNAMEA USER16CLIENTTHUNK UserThunk, GETCLIENTRECT, , bool,,compatcode USER16CLIENTTHUNK UserThunk, GETCURSORPOS, , boolzero USER16CLIENTTHUNK DUserThunk, GETDESKTOPHWND, <>, hwnd, GETDESKTOPWINDOW USER16CLIENTTHUNK DUserThunk, GETDESKTOPWINDOW, <>, hwnd USER16CLIENTTHUNK UserThunk, GETDLGITEM, , hwnd,,compatcode USER16CLIENTTHUNK UserThunk, GETMENU, , hmenu USER16CLIENTTHUNK UserThunk, GETMENUITEMCOUNT, , int USER16CLIENTTHUNK UserThunk, GETMENUITEMID, , uint USER16CLIENTTHUNK UserThunk, GETMENUSTATE, , uint USER16CLIENTTHUNK DUserThunk, GETNEXTWINDOW, , hwnd, GETWINDOW USER16CLIENTTHUNK UserThunk, GETPARENT, , hwnd USER16CLIENTTHUNK UserThunk, GETSUBMENU, , hmenu USER16CLIENTTHUNK UserThunk, GETSYSCOLOR, , dword USER16CLIENTTHUNK UserThunk, GETSYSTEMMETRICS, , int USER16CLIENTTHUNK UserThunk, GETTOPWINDOW, , hwnd USER16CLIENTTHUNK UserThunk, GETWINDOW, , hwnd USER16CLIENTTHUNK UserThunk, GETWINDOWRECT, , bool,,compatcode USER16CLIENTTHUNK DUserThunk, ISWINDOW, , bool USER16CLIENTTHUNK UserThunk, SCREENTOCLIENT, , boolzero ifdef DEBUG USER16CLIENTTHUNK UserThunk, ISCHILD, , bool USER16CLIENTTHUNK UserThunk, ISICONIC, , bool USER16CLIENTTHUNK UserThunk, ISWINDOWENABLED, , bool USER16CLIENTTHUNK UserThunk, ISWINDOWVISIBLE, , bool USER16CLIENTTHUNK UserThunk, ISZOOMED, , bool else USER16CLIENTTHUNK DUserThunk, ISCHILD, , bool USER16CLIENTTHUNK DUserThunk, ISICONIC, , bool USER16CLIENTTHUNK DUserThunk, ISWINDOWENABLED, , bool USER16CLIENTTHUNK DUserThunk, ISWINDOWVISIBLE, , bool USER16CLIENTTHUNK DUserThunk, ISZOOMED, , bool endif ;;;;;;;;;sEnd CODE ; macro will generate this sBegin CODE ifndef PMODE32 DUserThunk GETTICKCOUNT, 0 DUserThunk GETCURRENTTIME, 0 else labelFP labelFP ; the TickCount is accessible from client address space. ; refer sdk\inc\ntexapi.h ; - nanduri .386p ; set 32bit ds push ds mov ax, FLATDS mov ds, ax ; from sdk\inc\ntexapi.h NtGetTickCount - equivalent code mov edx, MM_SHARED_USER_DATA_VA mov eax, [edx].UsTickCountLow mul dword ptr [edx].UsTickCountMultiplier shrd eax,edx,24 mov edx, eax shr edx, 010h and ax, NOT GRAINYTIC_RES ; round off to lower 64 boundary ;this is a cheap implemention of WOWCF_GRAINYTICS flag pop ds retf .286p endif sEnd CODE end