//***************************************************************************** // // HOOKS - // // 32bit stubs and thunks for 16bit hooks // // // 01-07-92 NanduriR Created. // //***************************************************************************** #include "precomp.h" #pragma hdrstop MODNAME(wowhooks.c); //***************************************************************************** // // Global data. Data is valid only in WOW process context. DLL Data is not // Shared amongst various processes. If a WOW hook is set WIN32 USER will call // the hookproc in the context of the thread that has the hook set. This implies // that all the global data in this DLL is acessible by every WOW thread. // // Just reaffirming: since USER will call the hookprocs in our process/thread // context there is no need for this data to be available // in shared memory. // //***************************************************************************** HOOKPERPROCESSDATA vaHookPPData = { NULL, 0}; // // In SetWindowsHook we return an index into this array if it was // successful. Since NULL implies an error, we cannot use the Zeroth element // in this array. So we set its 'InUse' flag to TRUE. // HOOKSTATEDATA vaHookStateData[] = { 0, TRUE, 0, NULL, (HKPROC)NULL, 0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc01,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc02,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc03,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc04,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc05,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc06,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc07,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc08,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc09,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc10,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc11,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc12,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc13,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc14,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc15,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc16,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc17,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc18,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc19,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc20,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc21,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc22,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc23,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc24,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc25,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc26,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc27,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc28,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc29,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc30,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc31,0, 0, 0, NULL, 0, FALSE, 0, NULL, (HKPROC)WU32SubStdHookProc32,0, 0, 0, NULL }; HOOKPARAMS vHookParams = {0, 0, 0}; INT viCurrentHookStateDataIndex = 0; // this is used when 'DefHookProc' is called. //***************************************************************************** // Sub-Standard Hook Procs - // // Hook Stubs. The 'index' (the fourth parameter) is an index into the // the HookStateData array. All needed info is available in this array. // The hook stubs need to be exported. // //***************************************************************************** LONG APIENTRY WU32SubStdHookProc01(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x01); } LONG APIENTRY WU32SubStdHookProc02(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x02); } LONG APIENTRY WU32SubStdHookProc03(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x03); } LONG APIENTRY WU32SubStdHookProc04(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x04); } LONG APIENTRY WU32SubStdHookProc05(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x05); } LONG APIENTRY WU32SubStdHookProc06(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x06); } LONG APIENTRY WU32SubStdHookProc07(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x07); } LONG APIENTRY WU32SubStdHookProc08(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x08); } LONG APIENTRY WU32SubStdHookProc09(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x09); } LONG APIENTRY WU32SubStdHookProc10(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x0a); } LONG APIENTRY WU32SubStdHookProc11(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x0b); } LONG APIENTRY WU32SubStdHookProc12(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x0c); } LONG APIENTRY WU32SubStdHookProc13(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x0d); } LONG APIENTRY WU32SubStdHookProc14(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x0e); } LONG APIENTRY WU32SubStdHookProc15(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x0f); } LONG APIENTRY WU32SubStdHookProc16(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x10); } LONG APIENTRY WU32SubStdHookProc17(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x11); } LONG APIENTRY WU32SubStdHookProc18(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x12); } LONG APIENTRY WU32SubStdHookProc19(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x13); } LONG APIENTRY WU32SubStdHookProc20(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x14); } LONG APIENTRY WU32SubStdHookProc21(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x15); } LONG APIENTRY WU32SubStdHookProc22(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x16); } LONG APIENTRY WU32SubStdHookProc23(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x17); } LONG APIENTRY WU32SubStdHookProc24(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x18); } LONG APIENTRY WU32SubStdHookProc25(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x19); } LONG APIENTRY WU32SubStdHookProc26(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x1a); } LONG APIENTRY WU32SubStdHookProc27(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x1b); } LONG APIENTRY WU32SubStdHookProc28(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x1c); } LONG APIENTRY WU32SubStdHookProc29(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x1d); } LONG APIENTRY WU32SubStdHookProc30(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x1e); } LONG APIENTRY WU32SubStdHookProc31(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x1f); } LONG APIENTRY WU32SubStdHookProc32(INT nCode, LONG wParam, LONG lParam) { return WU32StdHookProc(nCode, wParam, lParam, 0x20); } //***************************************************************************** // W32InitHookState: // // Initializes the global data. Note that this data is initialized for every // Process that loads this DLL. However data that is visible only to the 'WOW' // process is what we care about. // //***************************************************************************** BOOL W32InitHookState(HANDLE hMod) { INT i; vaHookPPData.hMod = hMod; vaHookPPData.cHookProcs = sizeof(vaHookStateData) / sizeof(vaHookStateData[0]); for (i = 0; i < vaHookPPData.cHookProcs; i++) { vaHookStateData[i].iIndex = (BYTE)i; vaHookStateData[i].hMod = hMod; } return TRUE; } //***************************************************************************** // W32GetNotInUseHookStateData: // // Steps through the Global HookStateData and returns a pointer to an 'unused' // element. This is called only when the Hook is being Set. // //***************************************************************************** BOOL W32GetNotInUseHookStateData(LPHOOKSTATEDATA lpData) { INT i; for (i = 0; i < vaHookPPData.cHookProcs; i++) { if (!vaHookStateData[i].InUse) { vaHookStateData[i].InUse = TRUE; *lpData = vaHookStateData[i]; return TRUE; } } LOGDEBUG(LOG_ALWAYS, ("W32GetNotInUseHookStateData: All thunk hook procs in use.\n")); return FALSE; } //***************************************************************************** // W32SetHookStateData: // // Writes into the global data structure at the specified index. // //***************************************************************************** BOOL W32SetHookStateData(LPHOOKSTATEDATA lpData) { vaHookStateData[lpData->iIndex] = *lpData; return TRUE; } //***************************************************************************** // W32GetHookStateData: // // Retrieves data from the global data structure at the specified index. // //***************************************************************************** BOOL W32GetHookStateData(LPHOOKSTATEDATA lpData) { if ( lpData->iIndex >= 0 && lpData->iIndex < vaHookPPData.cHookProcs ) { *lpData = vaHookStateData[lpData->iIndex]; return TRUE; } else { return FALSE; } } //***************************************************************************** // W32GetThunkHookProc: // // Its callled to find a 32stub for the hook that is being set. // Returns TRUE if successful else FALSE. // The data is partially updated to reflect the characteristics of the hook // that is being set. // //***************************************************************************** BOOL W32GetThunkHookProc(INT iHook, DWORD Proc16, LPHOOKSTATEDATA lpData) { register PTD ptd = CURRENTPTD(); if (W32GetNotInUseHookStateData(lpData)) { lpData->iHook = iHook; lpData->Proc16 = Proc16; lpData->TaskId = ptd->htask16 ; W32SetHookStateData(lpData); return TRUE; } else return FALSE; } //***************************************************************************** // W32IsDuplicateHook: // // Verifies if the given hook has already been set. This is to catch // certain apps which go on Setting the same hook without Unhooking the // previous hook. // // Returns the 'stubindex' if hook already exists else 0; // //***************************************************************************** INT W32IsDuplicateHook(INT iHook, DWORD Proc16, INT TaskId) { INT i; for (i = 0; i < vaHookPPData.cHookProcs; i++) { if (vaHookStateData[i].InUse && vaHookStateData[i].iHook == iHook && vaHookStateData[i].TaskId == TaskId && vaHookStateData[i].Proc16 == Proc16 ) { return i; } } return 0; } //***************************************************************************** // W32FreeHHook: // // The state of the specified hook is set to 'Not in use'. // Returns hHook of the hook being freed. // //***************************************************************************** HHOOK W32FreeHHook(INT iHook, DWORD Proc16) { register PTD ptd = CURRENTPTD(); INT i; for (i = 0; i < vaHookPPData.cHookProcs; i++) { if (vaHookStateData[i].InUse && vaHookStateData[i].iHook == iHook && vaHookStateData[i].TaskId == (INT)ptd->htask16 && vaHookStateData[i].Proc16 == Proc16) { vaHookStateData[i].InUse = FALSE; return vaHookStateData[i].hHook; } } LOGDEBUG(LOG_ALWAYS, ("W32FreeHHook: Couldn't locate the specified hook.")); return (HHOOK)NULL; } //***************************************************************************** // W32FreeHHookOfIndex: // // The state of the specified hook is set to 'Not in use'. // Returns hHook of the hook being freed. // //***************************************************************************** HHOOK W32FreeHHookOfIndex(INT iFunc) { register PTD ptd = CURRENTPTD(); if (iFunc && iFunc < vaHookPPData.cHookProcs) if (vaHookStateData[iFunc].InUse && vaHookStateData[iFunc].TaskId == (INT)ptd->htask16) { vaHookStateData[iFunc].InUse = FALSE; return vaHookStateData[iFunc].hHook; } LOGDEBUG(LOG_ALWAYS, ("W32FreeHHookOfIndex: Couldn't locate the specified hook.")); return (HHOOK)NULL; } //***************************************************************************** // W32GetHookParams: // // Returns the 32bit hookparams of the current hook. // //***************************************************************************** BOOL W32GetHookParams(LPHOOKPARAMS lpHookParams) { if (lpHookParams) { *lpHookParams = vHookParams; } return (BOOL)lpHookParams; } //***************************************************************************** // W32StdHookProc: (Standard Hook Proc) // // All the stubs call this proc. // Return value is dependent on the hook type. // //***************************************************************************** LONG APIENTRY WU32StdHookProc(INT nCode, LONG wParam, LONG lParam, INT iFunc) { // // USER will call us in WOW context. Just Verify. // if (!vaHookStateData[iFunc].InUse) { // DbgPrint("WU32StdHookProc:Stub %04x called in WRONG process\n", iFunc); return FALSE; } // // USER can call us even if we have GP Faulted - so just ignore the input // if (CURRENTPTD()->dwFlags & TDF_IGNOREINPUT) { LOGDEBUG(LOG_ALWAYS,("WU32StdHookProc Ignoring Input\n")); WOW32ASSERTMSG(gfIgnoreInputAssertGiven, "WU32StdHookProc: TDF_IGNOREINPUT hack was used, shouldn't be, " "please email DOSWOW with repro instructions. Hit 'g' to ignore this " "and suppress this assertion from now on.\n"); gfIgnoreInputAssertGiven = TRUE; return FALSE; } // // store the stubindex. If the hookproc calls the DefHookProc() we will // be able to findout the Hook Type. // viCurrentHookStateDataIndex = iFunc; // // store the hook params. These will be used if DefHookProc gets called // by the 16bit stub. We are interested only in lParam. // vHookParams.nCode = nCode; vHookParams.wParam = wParam; vHookParams.lParam = lParam; switch (vaHookStateData[iFunc].iHook) { case WH_CALLWNDPROC: return ThunkCallWndProcHook(nCode, wParam, (LPCWPSTRUCT)lParam, &vaHookStateData[iFunc]); case WH_CBT: return ThunkCbtHook(nCode, wParam, lParam, &vaHookStateData[iFunc]); case WH_KEYBOARD: return ThunkKeyBoardHook(nCode, wParam, lParam, &vaHookStateData[iFunc]); case WH_MSGFILTER: // This code is TEMP only and must be fixed. ChandanC 5/2/92. if ((WORD)vaHookStateData[iFunc].TaskId != (WORD)((PTD)CURRENTPTD())->htask16) break; WOW32ASSERT((WORD)vaHookStateData[iFunc].TaskId == (WORD)((PTD)CURRENTPTD())->htask16); case WH_SYSMSGFILTER: case WH_GETMESSAGE: return ThunkMsgFilterHook(nCode, wParam, (LPMSG)lParam, &vaHookStateData[iFunc]); break; case WH_JOURNALPLAYBACK: case WH_JOURNALRECORD: return ThunkJournalHook(nCode, wParam, (LPEVENTMSG)lParam, &vaHookStateData[iFunc]); case WH_DEBUG: return ThunkDebugHook(nCode, wParam, lParam, &vaHookStateData[iFunc]); case WH_MOUSE: return ThunkMouseHook(nCode, wParam, (LPMOUSEHOOKSTRUCT)lParam, &vaHookStateData[iFunc]); case WH_SHELL: return ThunkShellHook(nCode, wParam, lParam, &vaHookStateData[iFunc]); default: LOGDEBUG(LOG_ALWAYS,("W32StdHookProc: Unknown Hook type.")); } return (LONG)FALSE; } //***************************************************************************** // // ThunkHookProc for Hooks of type WH_CALLWNDPROC - // // Return type is VOID. // //***************************************************************************** LONG ThunkCallWndProcHook(INT nCode, LONG wParam, LPCWPSTRUCT lpCwpStruct, LPHOOKSTATEDATA lpHSData) { VPVOID vp; PCWPSTRUCT16 pCwpStruct16; PARM16 Parm16; WM32MSGPARAMEX wm32mpex; BOOL fMessageNeedsThunking; wm32mpex.Parm16.WndProc.wMsg = (WORD) lpCwpStruct->message; wm32mpex.Parm16.WndProc.wParam = (WORD) lpCwpStruct->wParam; wm32mpex.Parm16.WndProc.lParam = (LONG) lpCwpStruct->lParam; fMessageNeedsThunking = (lpCwpStruct->message < 0x400) && (aw32Msg[lpCwpStruct->message].lpfnM32 != WM32NoThunking); // This call to stackalloc16() needs to occur before the call to the message // thunking function call below ((wm32mpex.lpfnM32)(&wm32mpex)) because the // message thunks for some messages may also call stackalloc16(). This will // ensure proper nesting of stackalloc16() & stackfree16() calls. // Be sure allocation size matches stackfree16() size below vp = stackalloc16(sizeof(CWPSTRUCT16)); if (fMessageNeedsThunking) { LOGDEBUG(3,("%04X (%s)\n", CURRENTPTD()->htask16, (aw32Msg[lpCwpStruct->message].lpszW32))); wm32mpex.fThunk = THUNKMSG; wm32mpex.hwnd = lpCwpStruct->hwnd; wm32mpex.uMsg = lpCwpStruct->message; wm32mpex.uParam = lpCwpStruct->wParam; wm32mpex.lParam = lpCwpStruct->lParam; wm32mpex.lpfnM32 = aw32Msg[wm32mpex.uMsg].lpfnM32; wm32mpex.pww = (PWW)NULL; wm32mpex.fFree = TRUE; // note: this may call stackalloc16() and/or callback into 16-bit code if (!(wm32mpex.lpfnM32)(&wm32mpex)) { LOGDEBUG(LOG_ALWAYS,("ThunkCallWndProcHook: cannot thunk 32-bit message %04x\n", lpCwpStruct->message)); } } // don't call GETMISCPTR(vp..) until after returning from the thunk function // above. If the thunk function calls back into 16-bit code, the flat ptr // for vp could become invalid. GETMISCPTR(vp, pCwpStruct16); STOREWORD(pCwpStruct16->hwnd, GETHWND16(lpCwpStruct->hwnd)); STOREWORD(pCwpStruct16->message, wm32mpex.Parm16.WndProc.wMsg ); STOREWORD(pCwpStruct16->wParam, wm32mpex.Parm16.WndProc.wParam); STORELONG(pCwpStruct16->lParam, wm32mpex.Parm16.WndProc.lParam); FLUSHVDMPTR(vp, sizeof(CWPSTRUCT16), pCwpStruct16); FREEVDMPTR(pCwpStruct16); Parm16.HookProc.nCode = (SHORT)nCode; Parm16.HookProc.wParam = (SHORT)wParam; Parm16.HookProc.lParam = vp; CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&wm32mpex.lReturn); #ifdef DEBUG GETMISCPTR(vp, pCwpStruct16); if (pCwpStruct16->message != wm32mpex.Parm16.WndProc.wMsg) LOGDEBUG(LOG_ALWAYS,("ThunkCallWndProcHook: IN message != OUT message")); FREEVDMPTR(pCwpStruct16); #endif if (fMessageNeedsThunking) { wm32mpex.fThunk = UNTHUNKMSG; // Note: If the thunk of this message called stackalloc16() this unthunk // call should call stackfree16() (wm32mpex.lpfnM32)(&wm32mpex); } if(vp) { // this stackfree16() call must come after the above message unthunk // call to give the unthunk the opportunity to call stackfree16() also. // this will preserve proper nesting of stackalloc16 & stackfree16 calls stackfree16(vp, sizeof(CWPSTRUCT16)); } return (LONG)FALSE; // return value doesn't matter } //***************************************************************************** // // ThunkHookProc for Hooks of type WH_CBT - // // Return type is BOOL. // //***************************************************************************** LONG ThunkCbtHook(INT nCode, LONG wParam, LONG lParam, LPHOOKSTATEDATA lpHSData) { LONG lReturn = FALSE; PARM16 Parm16; VPVOID vp; PMOUSEHOOKSTRUCT16 pMHStruct16; PCBTACTIVATESTRUCT16 pCbtAStruct16; VPCREATESTRUCT16 vpcs16; PCBT_CREATEWND16 pCbtCWnd16; WM32MSGPARAMEX wm32mpex; Parm16.HookProc.nCode = (SHORT)nCode; Parm16.HookProc.wParam = (SHORT)wParam; Parm16.HookProc.lParam = lParam; switch(nCode) { case HCBT_MOVESIZE: // wParam = HWND, lParam = LPRECT Parm16.HookProc.wParam = GETHWND16(wParam); // be sure allocation size matches stackfree16() size below vp = stackalloc16(sizeof(RECT16)); PUTRECT16(vp, (LPRECT)lParam); Parm16.HookProc.lParam = vp; break; case HCBT_MINMAX: // wParam = HWND, lParam = SW_* --- a command Parm16.HookProc.wParam = GETHWND16(wParam); break; case HCBT_QS: // wParam = 0, lParam = 0 break; case HCBT_CREATEWND: // This stackalloc16() call needs to occur before the WM32Create() // call below to ensure proper nesting of stackalloc16 & stackfree16 // calls. // Be sure allocation size matches stackfree16() size(s) below vp = stackalloc16(sizeof(CBT_CREATEWND16)); // wParam = HWND, lParam = LPCBT_CREATEWND wm32mpex.fThunk = THUNKMSG; wm32mpex.hwnd = (HWND)wParam; wm32mpex.uMsg = 0; wm32mpex.uParam = 0; wm32mpex.lParam = (LONG)((LPCBT_CREATEWND)lParam)->lpcs; wm32mpex.pww = (PWW)GetWindowLong((HWND)wParam, GWL_WOWWORDS); /* * WM32Create now requires that pww be initialized * WM32Create calls stackalloc16()!! */ if (!wm32mpex.pww || !WM32Create(&wm32mpex)) { stackfree16(vp, sizeof(CBT_CREATEWND16)); return FALSE; } vpcs16 = wm32mpex.Parm16.WndProc.lParam; lReturn = wm32mpex.lReturn; GETMISCPTR(vp, pCbtCWnd16); STOREDWORD(pCbtCWnd16->vpcs, vpcs16); STOREWORD(pCbtCWnd16->hwndInsertAfter, GETHWNDIA16(((LPCBT_CREATEWND)lParam)->hwndInsertAfter)); Parm16.HookProc.wParam = GETHWND16(wParam); Parm16.HookProc.lParam = vp; FLUSHVDMPTR(vp, sizeof(CBT_CREATEWND16), pCbtCWnd16); FREEVDMPTR(pCbtCWnd16); break; case HCBT_DESTROYWND: // wParam = HWND, lParam = 0 Parm16.HookProc.wParam = GETHWND16(wParam); break; case HCBT_ACTIVATE: // wParam = HWND, lParam = LPCBTACTIVATESTRUCT // be sure allocation size matches stackfree16() size below vp = stackalloc16(sizeof(CBTACTIVATESTRUCT16)); GETMISCPTR(vp, pCbtAStruct16); PUTCBTACTIVATESTRUCT16(pCbtAStruct16, ((LPCBTACTIVATESTRUCT)lParam)); Parm16.HookProc.wParam = GETHWND16(wParam); Parm16.HookProc.lParam = vp; FLUSHVDMPTR(vp, sizeof(CBTACTIVATESTRUCT16), pCbtAStruct16); FREEVDMPTR(pCbtAStruct16); break; case HCBT_CLICKSKIPPED: // wParam = mouse message, lParam = LPMOUSEHOOKSTRUCT // be sure allocation size matches stackfree16() size below vp = stackalloc16(sizeof(MOUSEHOOKSTRUCT16)); GETMISCPTR(vp, pMHStruct16); PUTMOUSEHOOKSTRUCT16(pMHStruct16, (LPMOUSEHOOKSTRUCT)lParam); Parm16.HookProc.lParam = vp; FLUSHVDMPTR(vp, sizeof(MOUSEHOOKSTRUCT16), pMHStruct16); FREEVDMPTR(pMHStruct16); break; case HCBT_KEYSKIPPED: // wParam, lParam -- keyup/down message params break; case HCBT_SYSCOMMAND: // wParam = SC_ syscomand, lParam = DWORD(x,y) break; case HCBT_SETFOCUS: // wParam = HWND, lParam = HWND Parm16.HookProc.wParam = GETHWND16(wParam); Parm16.HookProc.lParam = GETHWND16(lParam); break; default: LOGDEBUG(LOG_ALWAYS, ("ThunkCbtHook: Unknown HCBT_ code\n")); break; } CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&lReturn); switch(nCode) { case HCBT_MOVESIZE: GETRECT16(vp, (LPRECT)lParam); stackfree16(vp, sizeof(RECT16)); break; case HCBT_CREATEWND: GETMISCPTR(vp, pCbtCWnd16); ((LPCBT_CREATEWND)lParam)->hwndInsertAfter = HWNDIA32(FETCHWORD(pCbtCWnd16->hwndInsertAfter)); FREEVDMPTR(pCbtCWnd16); wm32mpex.fThunk = UNTHUNKMSG; wm32mpex.lReturn = lReturn; WM32Create(&wm32mpex); // this calls stackfree16()!!! lReturn = wm32mpex.lReturn; // this must be after call to WM32Create() stackfree16(vp, sizeof(CBT_CREATEWND16)); break; case HCBT_ACTIVATE: GETMISCPTR(vp, pCbtAStruct16); GETCBTACTIVATESTRUCT16(pCbtAStruct16, (LPCBTACTIVATESTRUCT)lParam); FREEVDMPTR(pCbtAStruct16); stackfree16(vp, sizeof(CBTACTIVATESTRUCT16)); break; case HCBT_CLICKSKIPPED: GETMISCPTR(vp, pMHStruct16); GETMOUSEHOOKSTRUCT16(pMHStruct16, (LPMOUSEHOOKSTRUCT)lParam); FREEVDMPTR(pMHStruct16); stackfree16(vp, sizeof(MOUSEHOOKSTRUCT16)); break; // case HCBT_MINMAX: // case HCBT_QS: // case HCBT_DESTROYWND: // case HCBT_KEYSKIPPED: // case HCBT_SYSCOMMAND: // case HCBT_SETFOCUS: default: break; } // the value in LOWORD is the valid return value return (LONG)(BOOL)LOWORD(lReturn); } //***************************************************************************** // // ThunkHookProc for Hooks of type WH_KEYBOARD - // // Return type is BOOL. // //***************************************************************************** LONG ThunkKeyBoardHook(INT nCode, LONG wParam, LONG lParam, LPHOOKSTATEDATA lpHSData) { LONG lReturn; PARM16 Parm16; Parm16.HookProc.nCode = (SHORT)nCode; Parm16.HookProc.wParam = (SHORT)wParam; Parm16.HookProc.lParam = lParam; CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&lReturn); // the value in LOWORD is the valid return value return (LONG)(BOOL)LOWORD(lReturn); } //***************************************************************************** // // ThunkHookProc for Hooks of type WH_GETMESSAGE - // WH_MSGFILTER - // WH_SYSMSGFILTER - // // WARNING: May cause 16-bit memory movement, invalidating flat pointers. // // Return type is BOOL. // //***************************************************************************** LONG ThunkMsgFilterHook(INT nCode, LONG wParam, LPMSG lpMsg, LPHOOKSTATEDATA lpHSData) { VPVOID vp; PMSG16 pMsg16; PARM16 Parm16; WM32MSGPARAMEX wm32mpex; BOOL fHookModifiedLpMsg; HWND hwnd32; MSGPARAMEX mpex; BOOL fUseOld; static MSG msgSave; static int cRecurse = 0; static PARM16 Parm16Save; BOOL fMessageNeedsThunking; // This should be removed when all thunk functions appropiately fill these // in, till then we must have these 3 lines before calling thunk functions ! // ChandanC, 2/28/92 // wm32mpex.Parm16.WndProc.wMsg = (WORD) lpMsg->message; wm32mpex.Parm16.WndProc.wParam = (WORD) lpMsg->wParam; wm32mpex.Parm16.WndProc.lParam = (LONG) lpMsg->lParam; fMessageNeedsThunking = (lpMsg->message < 0x400) && (aw32Msg[lpMsg->message].lpfnM32 != WM32NoThunking); fThunkDDEmsg = FALSE; if (fMessageNeedsThunking) { LOGDEBUG(3,("%04X (%s)\n", CURRENTPTD()->htask16, (aw32Msg[lpMsg->message].lpszW32))); wm32mpex.fThunk = THUNKMSG; wm32mpex.hwnd = lpMsg->hwnd; wm32mpex.uMsg = lpMsg->message; wm32mpex.uParam = lpMsg->wParam; wm32mpex.lParam = lpMsg->lParam; wm32mpex.pww = (PWW)NULL; wm32mpex.fFree = FALSE; wm32mpex.lpfnM32 = aw32Msg[wm32mpex.uMsg].lpfnM32; if (!((wm32mpex.lpfnM32)(&wm32mpex))) { LOGDEBUG(LOG_ALWAYS,("ThunkMsgFilterHook: cannot thunk 32-bit message %04x\n", lpMsg->message)); } } fThunkDDEmsg = TRUE; // // Check to see if we've recursed into this routine. If so and the message // contents are the same, use the last message pointer we gave the 16 // bit app rather than allocating a new one. Need this to solve the // SoundBits Browser problem. It checks to see if the lpmsg passed // is the same as it got last time - if so, it doesn't call this other // function that causes recursion. // fUseOld = FALSE; if (cRecurse != 0 && lpMsg->hwnd == msgSave.hwnd && lpMsg->message == msgSave.message && lpMsg->wParam == msgSave.wParam && lpMsg->lParam == msgSave.lParam && lpMsg->time == msgSave.time && lpMsg->pt.x == msgSave.pt.x && lpMsg->pt.y == msgSave.pt.y) { fUseOld = TRUE; } else { // // Not the same... reset this thing in case the count is screwed // up. Also remember this message, in case we do recurse. // cRecurse = 0; msgSave = *lpMsg; } if (!fUseOld) { vp = malloc16(sizeof(MSG16)); if (vp == (VPVOID)NULL) return FALSE; GETMISCPTR(vp, pMsg16); STOREWORD(pMsg16->hwnd, GETHWND16((lpMsg)->hwnd)); STOREWORD(pMsg16->message, wm32mpex.Parm16.WndProc.wMsg ); STOREWORD(pMsg16->wParam, wm32mpex.Parm16.WndProc.wParam); STORELONG(pMsg16->lParam, wm32mpex.Parm16.WndProc.lParam); STORELONG(pMsg16->time, (lpMsg)->time); STOREWORD(pMsg16->pt.x, (lpMsg)->pt.x); STOREWORD(pMsg16->pt.y, (lpMsg)->pt.y); Parm16.HookProc.nCode = (SHORT)nCode; Parm16.HookProc.wParam = (SHORT)wParam; Parm16.HookProc.lParam = vp; // // Remember Parm16 in case we need to use it again due to the recursion // case. // Parm16Save = Parm16; } else { // // Use old message contents. // Parm16 = Parm16Save; vp = (VPVOID)Parm16Save.HookProc.lParam; GETMISCPTR(vp, pMsg16); } FLUSHVDMPTR(vp, sizeof(MSG16), pMsg16); // // Count how many times we recurse through this hook proc. Need this count // to solve the SoundBits Browser problem. It checks to see if the lpMsg // passed is the same as it got last time - if so, it doesn't call this // other function that causes recursion. // cRecurse++; CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&wm32mpex.lReturn); cRecurse--; // set the correct return value BEFORE unthunking wm32mpex.lReturn = (LONG)(BOOL)LOWORD(wm32mpex.lReturn); // // Free the 32 pointer to 16 bit args and get it again in case underlying // memory movement occured. // FREEVDMPTR(pMsg16); GETMISCPTR(vp, pMsg16); fThunkDDEmsg = FALSE; // Theoretically an app can change the lpMsg and return a totall different // data altogether. In practice most apps don't do anything so it is pretty // expensive to go through the 'unthunk' procedure all the time. So here is // a compromise. We copy the message params only if the output message is // different from the input message. // // (davehart) Polaris PackRat modifies WM_KEYDOWN messages sent to its // multiline "Note" edit control in its Phone Book Entry dialog box. // It changes wParam (the VK_ code) from 0xD (VK_RETURN) to 0xA, which // is understood by the edit control to be identical to VK_RETURN but // won't cause the dialog box to close. So we special-case here // WM_KEYDOWN where the hook proc changed the virtual key (in wParam) // and unthunk it properly. fHookModifiedLpMsg = (pMsg16->message != wm32mpex.Parm16.WndProc.wMsg) || (wm32mpex.Parm16.WndProc.wMsg == WM_KEYDOWN && pMsg16->wParam != wm32mpex.Parm16.WndProc.wParam) || (pMsg16->hwnd != GETHWND16(lpMsg->hwnd)); if (fHookModifiedLpMsg) { mpex.Parm16.WndProc.hwnd = pMsg16->hwnd; mpex.Parm16.WndProc.wMsg = pMsg16->message; mpex.Parm16.WndProc.wParam = pMsg16->wParam; mpex.Parm16.WndProc.lParam = pMsg16->lParam, mpex.iMsgThunkClass = WOWCLASS_WIN16; hwnd32 = ThunkMsg16(&mpex); // // Free the 32 pointer to 16 bit args and get it again in case // underlying memory movement occured. // FREEVDMPTR(pMsg16); GETMISCPTR(vp, pMsg16); // reset flag if message thunking failed. if (!hwnd32) fHookModifiedLpMsg = FALSE; } if (fMessageNeedsThunking) { wm32mpex.fThunk = UNTHUNKMSG; (wm32mpex.lpfnM32)(&wm32mpex); // // Free the 32 pointer to 16 bit args and get it again in case // underlying memory movement occured. // FREEVDMPTR(pMsg16); GETMISCPTR(vp, pMsg16); } fThunkDDEmsg = TRUE; if (fHookModifiedLpMsg) { lpMsg->hwnd = hwnd32; lpMsg->message = mpex.uMsg; lpMsg->wParam = mpex.uParam; lpMsg->lParam = mpex.lParam; lpMsg->time = FETCHLONG(pMsg16->time); lpMsg->pt.x = FETCHSHORT(pMsg16->pt.x); lpMsg->pt.y = FETCHSHORT(pMsg16->pt.y); } FREEVDMPTR(pMsg16); if (!fUseOld) { free16(vp); } // the value in LOWORD is the valid return value return (LONG)(BOOL)LOWORD(wm32mpex.lReturn); } //***************************************************************************** // // ThunkHookProc for Hooks of type WH_JOURNALPLAYBACK - // WH_JOUNRALRECORD - // // Return type is DWORD. // //***************************************************************************** LONG ThunkJournalHook(INT nCode, LONG wParam, LPEVENTMSG lpEventMsg, LPHOOKSTATEDATA lpHSData) { LONG lReturn; VPVOID vp; PEVENTMSG16 pEventMsg16; PARM16 Parm16; if ( lpEventMsg ) { // be sure allocation size matches stackfree16() size below vp = stackalloc16(sizeof(EVENTMSG16)); // The WIN32 EVENTMSG structure has an additional field 'hwnd', which // is not there in WIN31 EVENTMSG structure. This field can be ignored // without any repercussions. if (lpHSData->iHook == WH_JOURNALRECORD) { GETMISCPTR(vp, pEventMsg16); PUTEVENTMSG16(pEventMsg16, lpEventMsg); FLUSHVDMPTR(vp, sizeof(EVENTMSG16), pEventMsg16); FREEVDMPTR(pEventMsg16); } } else { // lpEventMsg can be NULL indicating that no message data is requested. // If this is the case, there is no need to copy data for either // journal record or playback. vp = (VPVOID)0; } Parm16.HookProc.nCode = (SHORT)nCode; Parm16.HookProc.wParam = (SHORT)wParam; Parm16.HookProc.lParam = vp; CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&lReturn); if ( lpEventMsg ) { GETMISCPTR(vp, pEventMsg16); if (lpHSData->iHook == WH_JOURNALPLAYBACK) { GetEventMessage16(pEventMsg16, lpEventMsg); #ifdef FE_SB switch (lpEventMsg->message) { case WM_CHAR: case WM_CHARTOITEM: case WM_DEADCHAR: case WM_KEYDOWN: case WM_KEYUP: case WM_MENUCHAR: case WM_SYSCHAR: case WM_SYSDEADCHAR: case WM_SYSKEYDOWN: case WM_SYSKEYUP: case WM_VKEYTOITEM: // only virtual key, not use scan code lpEventMsg->paramL &= 0x0ff; } #endif // FE_SB #ifdef DEBUG if (MessageNeedsThunking(lpEventMsg->message)) { LOGDEBUG(LOG_ALWAYS, ("ThunkJournalHook: Playing back unexpected message 0x%x", lpEventMsg->message)); } #endif } else { WOW32ASSERT(lpHSData->iHook == WH_JOURNALRECORD); WOW32ASSERT(aw32Msg[FETCHWORD(pEventMsg16->message)].lpfnM32 == WM32NoThunking); // If the app modified the message then copy the new message info // (rather than copying it every time we only copy it if the // app change the message) if (FETCHWORD(pEventMsg16->message) != lpEventMsg->message) { GetEventMessage16(pEventMsg16, lpEventMsg); } } FREEVDMPTR(pEventMsg16); if(vp) { stackfree16(vp, sizeof(EVENTMSG16)); } } return lReturn; } //***************************************************************************** // // ThunkHookProc for Hooks of type WH_DEBUG - // // Return type is BOOL. // //***************************************************************************** LONG ThunkDebugHook(INT nCode, LONG wParam, LONG lParam, LPHOOKSTATEDATA lpHSData) { LONG lReturn; lReturn = TRUE; UNREFERENCED_PARAMETER(nCode); UNREFERENCED_PARAMETER(wParam); UNREFERENCED_PARAMETER(lParam); UNREFERENCED_PARAMETER(lpHSData); LOGDEBUG(LOG_ALWAYS, ("ThunkDebugHook:Not implemented.\n")); // the value in LOWORD is the valid return value return (LONG)(BOOL)LOWORD(lReturn); } //***************************************************************************** // // ThunkHookProc for Hooks of type WH_MOUSE - // // Return type is BOOL. // //***************************************************************************** LONG ThunkMouseHook(INT nCode, LONG wParam, LPMOUSEHOOKSTRUCT lpMHStruct, LPHOOKSTATEDATA lpHSData) { LONG lReturn; VPVOID vp; PMOUSEHOOKSTRUCT16 pMHStruct16; PARM16 Parm16; // be sure allocation size matches stackfree16() size below vp = stackalloc16(sizeof(MOUSEHOOKSTRUCT16)); GETMISCPTR(vp, pMHStruct16); PUTMOUSEHOOKSTRUCT16(pMHStruct16, lpMHStruct); Parm16.HookProc.nCode = (SHORT)nCode; Parm16.HookProc.wParam = (SHORT)wParam; Parm16.HookProc.lParam = vp; FLUSHVDMPTR(vp, sizeof(MOUSEHOOKSTRUCT16), pMHStruct16); FREEVDMPTR(pMHStruct16); CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&lReturn); GETMISCPTR(vp, pMHStruct16); GETMOUSEHOOKSTRUCT16(pMHStruct16, lpMHStruct); FREEVDMPTR(pMHStruct16); if(vp) { stackfree16(vp, sizeof(MOUSEHOOKSTRUCT16)); } return (LONG)(BOOL)LOWORD(lReturn); } //***************************************************************************** // // ThunkHookProc for Hooks of type WH_SHELL - // // Return value apparently is zero. // //***************************************************************************** LONG ThunkShellHook(INT nCode, LONG wParam, LONG lParam, LPHOOKSTATEDATA lpHSData) { LONG lReturn; PARM16 Parm16; Parm16.HookProc.nCode = (SHORT)nCode; Parm16.HookProc.lParam = lParam; switch (nCode) { case HSHELL_WINDOWCREATED: case HSHELL_WINDOWDESTROYED: Parm16.HookProc.wParam = (SHORT)GETHWND16(wParam); break; case HSHELL_ACTIVATESHELLWINDOW: // fall thru default: Parm16.HookProc.wParam = (SHORT)wParam; break; } CallBack16(RET_HOOKPROC, &Parm16, lpHSData->Proc16, (PVPVOID)&lReturn); // lReturn = 0? return (LONG)lReturn; } //***************************************************************************** // W32UnhookHooks: // // Scans the list of active hooks for those for the passed in handle. // Those that match are unhooked. // //***************************************************************************** VOID W32UnhookHooks( HAND16 hMod16, BOOL fQueue ) { INT i; for (i = 0; i < vaHookPPData.cHookProcs; i++) { if (vaHookStateData[i].InUse ) { if ( !fQueue && ((HAND16)(vaHookStateData[i].hMod16) == hMod16) ) { // // Unhook this guy! // if (UnhookWindowsHookEx(vaHookStateData[i].hHook)) { LOGDEBUG(7, ("W32FreeModuleHooks: Freed iHook (WH_*) %04x\n", vaHookStateData[i].iHook)); } else { LOGDEBUG(LOG_ALWAYS, ("W32FreeModuleHooks: ERROR Freeing iHook (WH_*) %04x\n", vaHookStateData[i].iHook)); } // reset the state, even if Unhooking failed. vaHookStateData[i].TaskId = 0; vaHookStateData[i].InUse = FALSE; } } } } //***************************************************************************** // W32FreeOwnedHooks - // // Called during thread exit time. Frees all hooks set by specified thread. // //***************************************************************************** BOOL W32FreeOwnedHooks(INT iTaskId) { INT i; for (i = 0; i < vaHookPPData.cHookProcs; i++) { if (vaHookStateData[i].InUse && vaHookStateData[i].TaskId == iTaskId) { if (UnhookWindowsHookEx(vaHookStateData[i].hHook)) { LOGDEBUG(7, ("W32FreeOwnedHooks: Freed iHook (WH_*) %04x\n", vaHookStateData[i].iHook)); } else { LOGDEBUG(LOG_ALWAYS, ("W32FreeOwnedHooks: ERROR Freeing iHook (WH_*) %04x\n", vaHookStateData[i].iHook)); } // reset the state, even if Unhooking failed. vaHookStateData[i].TaskId = 0; vaHookStateData[i].InUse = FALSE; } } return TRUE; } //***************************************************************************** // W32StdDefHookProc: (Standard Def Hook Proc) // // WU32DefHookProc is called here. // WARNING: May cause 16-bit memory movement, invalidating flat pointers. // Return value is the new lParam. // //***************************************************************************** LONG APIENTRY WU32StdDefHookProc(INT nCode, LONG wParam, LONG lParam, INT iFunc) { switch (vaHookStateData[iFunc].iHook) { case WH_CALLWNDPROC: return ThunkCallWndProcHook16(nCode, wParam, (VPVOID)lParam, &vaHookStateData[iFunc]); case WH_CBT: return ThunkCbtHook16(nCode, wParam, (VPVOID)lParam, &vaHookStateData[iFunc]); case WH_KEYBOARD: return ThunkKeyBoardHook16(nCode, wParam, lParam, &vaHookStateData[iFunc]); case WH_MSGFILTER: case WH_SYSMSGFILTER: case WH_GETMESSAGE: return ThunkMsgFilterHook16(nCode, wParam, (VPVOID)lParam, &vaHookStateData[iFunc]); case WH_JOURNALPLAYBACK: case WH_JOURNALRECORD: return ThunkJournalHook16(nCode, wParam, (VPVOID)lParam, &vaHookStateData[iFunc]); case WH_DEBUG: return ThunkDebugHook16(nCode, wParam, lParam, &vaHookStateData[iFunc]); case WH_MOUSE: return ThunkMouseHook16(nCode, wParam, (VPVOID)lParam, &vaHookStateData[iFunc]); case WH_SHELL: return ThunkShellHook16(nCode, wParam, lParam, &vaHookStateData[iFunc]); default: LOGDEBUG(LOG_ALWAYS,("WU32StdDefHookProc: Unknown Hook type.\n")); } return (LONG)FALSE; } //***************************************************************************** // // 16->32 ThunkHookProc for Hooks of type WH_CALLWNDPROC - // // Return type is VOID. // //***************************************************************************** LONG ThunkCallWndProcHook16(INT nCode, LONG wParam, VPVOID vpCwpStruct, LPHOOKSTATEDATA lpHSData) { CWPSTRUCT CwpStruct; PCWPSTRUCT16 pCwpStruct16; MSGPARAMEX mpex; GETMISCPTR(vpCwpStruct, pCwpStruct16); mpex.Parm16.WndProc.hwnd = pCwpStruct16->hwnd; mpex.Parm16.WndProc.wMsg = pCwpStruct16->message; mpex.Parm16.WndProc.wParam = pCwpStruct16->wParam; mpex.Parm16.WndProc.lParam = pCwpStruct16->lParam, mpex.iMsgThunkClass = WOWCLASS_WIN16; mpex.hwnd = ThunkMsg16(&mpex); // memory may have moved FREEVDMPTR(pCwpStruct16); CwpStruct.message = mpex.uMsg; CwpStruct.wParam = mpex.uParam; CwpStruct.lParam = mpex.lParam; CwpStruct.hwnd = mpex.hwnd; mpex.lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParam, (LPARAM)&CwpStruct); if (MSG16NEEDSTHUNKING(&mpex)) { mpex.uMsg = CwpStruct.message; mpex.uParam = CwpStruct.wParam; mpex.lParam = CwpStruct.lParam; (mpex.lpfnUnThunk16)(&mpex); } return mpex.lReturn; } //***************************************************************************** // // 16->32 ThunkHookProc for Hooks of type WH_CBT - // // Return type is BOOL. // //***************************************************************************** LONG ThunkCbtHook16(INT nCode, LONG wParam, VPVOID lParam, LPHOOKSTATEDATA lpHSData) { LONG lReturn = FALSE; WPARAM wParamNew; LPARAM lParamNew; MSGPARAMEX mpex; PMOUSEHOOKSTRUCT16 pMHStruct16; PCBTACTIVATESTRUCT16 pCbtAStruct16; PCBT_CREATEWND16 pCbtCWnd16; PRECT16 pRect16; MOUSEHOOKSTRUCT MHStruct; RECT Rect; CBTACTIVATESTRUCT CbtAStruct; CBT_CREATEWND CbtCWnd; // SudeepB 28-May-1996 updated DaveHart 16-July-96 to fix limit assertions. // // Some apps like SureTrack project management package are passing // corrupted values in lParam. GETVDMPTR returns 0 for such an lParam. // Using this 0 on X86 causes corruption of IVT and on RISC causes an // AV in wow32 as zero is not a valid linear address. Such apps get // away from such criminal acts on win3.1/Win95 as no thunking is needed // there. So all the thunking below explicitly checks for GETVDMPTR // returning 0 and in that case just leaves lParam unthunked. wParamNew = (WPARAM) wParam; lParamNew = (LPARAM) lParam; switch(nCode) { // // These don't have a pointer in lParam. // case HCBT_SETFOCUS: // wParam = HWND, lParam = HWND // fall through to set wParamNew & lParamNew, // this counts on HWND32 zero-extending. case HCBT_MINMAX: // wParam = HWND, lParam = SW_* --- a command // fall through to set wParamNew & lParamNew. // this counts on HWND32 zero-extending. case HCBT_DESTROYWND: // wParam = HWND, lParam = 0 // fall through to set wParamNew & lParamNew. // this counts on HWND32 zero-extending. WOW32ASSERTMSG((HWND32(0x1234) == (HWND)0x1234), "Code depending on HWND32 zero-extending needs revision.\n"); case HCBT_QS: // wParam = 0, lParam = 0 case HCBT_KEYSKIPPED: // wParam = VK_ keycode, lParam = WM_KEYUP/DOWN lParam case HCBT_SYSCOMMAND: // wParam = SC_ syscomand, lParam = DWORD(x,y) if mouse // lParamNew and wParamNew are initialized above with no thunking. break; // // These use lParam as a pointer. // case HCBT_MOVESIZE: // wParam = HWND, lParam = LPRECT #if 0 // HWND32 is a no-op, wParamNew already initialized. wParamNew = (WPARAM) HWND32(wParam); #endif GETVDMPTR(lParam, sizeof(*pRect16), pRect16); if (pRect16) { GETRECT16(lParam, &Rect); lParamNew = (LPARAM)&Rect; FREEVDMPTR(pRect16); } break; case HCBT_CREATEWND: // wParam = HWND, lParam = LPCBT_CREATEWND #if 0 // HWND32 is a no-op, wParamNew already initialized. wParamNew = (WPARAM) HWND32(wParam); #endif GETVDMPTR(lParam, sizeof(*pCbtCWnd16), pCbtCWnd16); if (pCbtCWnd16) { lParamNew = (LPARAM)&CbtCWnd; mpex.Parm16.WndProc.hwnd = LOWORD(wParam); mpex.Parm16.WndProc.wMsg = WM_CREATE; mpex.Parm16.WndProc.wParam = 0; mpex.Parm16.WndProc.lParam = FETCHDWORD(pCbtCWnd16->vpcs); mpex.iMsgThunkClass = 0; ThunkMsg16(&mpex); // // Memory movement can occur on the 16-bit side. // FREEVDMPTR(pCbtCWnd16); GETVDMPTR(lParam, sizeof(*pCbtCWnd16), pCbtCWnd16); (LONG)CbtCWnd.lpcs = mpex.lParam; CbtCWnd.hwndInsertAfter = HWNDIA32(FETCHWORD(pCbtCWnd16->hwndInsertAfter)); FREEVDMPTR(pCbtCWnd16); } break; case HCBT_ACTIVATE: // wParam = HWND, lParam = LPCBTACTIVATESTRUCT #if 0 // HWND32 is a no-op, wParamNew already initialized. wParamNew = (WPARAM) HWND32(wParam); #endif GETVDMPTR(lParam, sizeof(*pCbtAStruct16), pCbtAStruct16); if (pCbtAStruct16) { lParamNew = (LPARAM)&CbtAStruct; GETCBTACTIVATESTRUCT16(pCbtAStruct16, &CbtAStruct); FREEVDMPTR(pCbtAStruct16); } break; case HCBT_CLICKSKIPPED: // wParam = mouse message, lParam = LPMOUSEHOOKSTRUCT GETVDMPTR(lParam, sizeof(*pMHStruct16), pMHStruct16); if (pMHStruct16) { lParamNew = (LPARAM)&MHStruct; GETMOUSEHOOKSTRUCT16(pMHStruct16, &MHStruct); FREEVDMPTR(pMHStruct16); } break; default: LOGDEBUG(LOG_ALWAYS, ("ThunkCbtHook: Unknown HCBT_ code 0x%x\n", nCode)); break; } // // Call the hook, memory movement can occur. // lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParamNew, lParamNew); switch(nCode) { // // These don't have a pointer in lParam. // // case HCBT_SETFOCUS: // wParam = HWND, lParam = HWND // case HCBT_MINMAX: // wParam = HWND, lParam = SW_* --- a command // case HCBT_DESTROYWND: // wParam = HWND, lParam = 0 // case HCBT_QS: // wParam = 0, lParam = 0 // case HCBT_KEYSKIPPED: // wParam = VK_ keycode, lParam = WM_KEYUP/DOWN lParam // case HCBT_SYSCOMMAND: // wParam = SC_ syscomand, lParam = DWORD(x,y) if mouse // break; // // These use lParam as a pointer. // case HCBT_MOVESIZE: // wParam = HWND, lParam = LPRECT PUTRECT16(lParam, (LPRECT)lParamNew); break; case HCBT_CREATEWND: // wParam = HWND, lParam = LPCBT_CREATEWND GETVDMPTR(lParam, sizeof(*pCbtCWnd16), pCbtCWnd16); if (pCbtCWnd16) { mpex.lParam = (LONG)CbtCWnd.lpcs; mpex.lReturn = lReturn; WOW32ASSERT(MSG16NEEDSTHUNKING(&mpex)); (mpex.lpfnUnThunk16)(&mpex); lReturn = mpex.lReturn; STOREWORD(pCbtCWnd16->hwndInsertAfter, GETHWNDIA16(((LPCBT_CREATEWND)lParamNew)-> hwndInsertAfter)); FLUSHVDMPTR((VPVOID)lParam, sizeof(CBT_CREATEWND16), pCbtCWnd16); FREEVDMPTR(pCbtCWnd16); } break; case HCBT_ACTIVATE: // wParam = HWND, lParam = LPCBTACTIVATESTRUCT GETVDMPTR(lParam, sizeof(*pCbtAStruct16), pCbtAStruct16); if (pCbtAStruct16) { PUTCBTACTIVATESTRUCT16(pCbtAStruct16, (LPCBTACTIVATESTRUCT)lParamNew); FLUSHVDMPTR((VPVOID)lParam, sizeof(CBTACTIVATESTRUCT16), pCbtAStruct16); FREEVDMPTR(pCbtAStruct16); } break; case HCBT_CLICKSKIPPED: // wParam = mouse message, lParam = LPMOUSEHOOKSTRUCT GETVDMPTR(lParam, sizeof(*pMHStruct16), pMHStruct16); if (pMHStruct16) { PUTMOUSEHOOKSTRUCT16(pMHStruct16, (LPMOUSEHOOKSTRUCT)lParamNew); FLUSHVDMPTR((VPVOID)lParam, sizeof(MOUSEHOOKSTRUCT16), pMHStruct16); FREEVDMPTR(pMHStruct16); } break; } // the value in LOWORD is the valid return value return (LONG)(BOOL)LOWORD(lReturn); } //***************************************************************************** // // 16->32 ThunkHookProc for Hooks of type WH_KEYBOARD - // // Return type is BOOL. // //***************************************************************************** LONG ThunkKeyBoardHook16(INT nCode, LONG wParam, LONG lParam, LPHOOKSTATEDATA lpHSData) { LONG lReturn; lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParam, (LPARAM)lParam); // the value in LOWORD is the valid return value return (LONG)(BOOL)LOWORD(lReturn); } //***************************************************************************** // // 16->32 ThunkHookProc for Hooks of type WH_GETMESSAGE - // WH_MSGFILTER - // WH_SYSMSGFILTER - // // Return type is BOOL. // //***************************************************************************** LONG ThunkMsgFilterHook16(INT nCode, LONG wParam, VPVOID vpMsg, LPHOOKSTATEDATA lpHSData) { PMSG16 pMsg16; MSG Msg; MSGPARAMEX mpex; GETMISCPTR(vpMsg, pMsg16); fThunkDDEmsg = FALSE; mpex.Parm16.WndProc.hwnd = pMsg16->hwnd; mpex.Parm16.WndProc.wMsg = pMsg16->message; mpex.Parm16.WndProc.wParam = pMsg16->wParam; mpex.Parm16.WndProc.lParam = pMsg16->lParam; mpex.iMsgThunkClass = 0; ThunkMsg16(&mpex); // // Memory movement can occur on the 16-bit side. // FREEVDMPTR(pMsg16); GETMISCPTR(vpMsg, pMsg16); fThunkDDEmsg = TRUE; Msg.message = mpex.uMsg; Msg.wParam = mpex.uParam; Msg.lParam = mpex.lParam; Msg.hwnd = HWND32(FETCHWORD(pMsg16->hwnd)); Msg.time = FETCHLONG(pMsg16->time); Msg.pt.x = FETCHSHORT(pMsg16->pt.x); Msg.pt.y = FETCHSHORT(pMsg16->pt.y); FREEVDMPTR(pMsg16); mpex.lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParam, (LPARAM)&Msg); GETMISCPTR(vpMsg, pMsg16); if (MSG16NEEDSTHUNKING(&mpex)) { mpex.uMsg = Msg.message; mpex.uParam = Msg.wParam; mpex.lParam = Msg.lParam; (mpex.lpfnUnThunk16)(&mpex); GETMISCPTR(vpMsg, pMsg16); } STORELONG(pMsg16->time, Msg.time); STOREWORD(pMsg16->pt.x, Msg.pt.x); STOREWORD(pMsg16->pt.y, Msg.pt.y); FLUSHVDMPTR(vpMsg, sizeof(MSG16), pMsg16); FREEVDMPTR(pMsg16); // the value in LOWORD is the valid return value return (LONG)(BOOL)LOWORD(mpex.lReturn); } //***************************************************************************** // // 16->32 ThunkHookProc for Hooks of type WH_JOURNALPLAYBACK - // WH_JOUNRALRECORD - // // Return type is DWORD. // //***************************************************************************** LONG ThunkJournalHook16(INT nCode, LONG wParam, VPVOID vpEventMsg, LPHOOKSTATEDATA lpHSData) { LONG lReturn; PEVENTMSG16 pEventMsg16; EVENTMSG EventMsg; LPEVENTMSG lpEventMsg; if ( vpEventMsg ) { // The WIN32 EVENTMSG structure has an additional field 'hwnd', which // is not there in WIN31 EVENTMSG structure. This field can be ignored // without any repercussions. if (lpHSData->iHook == WH_JOURNALRECORD) { GETMISCPTR(vpEventMsg, pEventMsg16); GetEventMessage16(pEventMsg16, &EventMsg); EventMsg.hwnd = (HWND)0; FREEVDMPTR(pEventMsg16); } lpEventMsg = &EventMsg; } else { lpEventMsg = NULL; } lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParam, (LPARAM)lpEventMsg ); if ( vpEventMsg ) { if (lpHSData->iHook == WH_JOURNALPLAYBACK) { GETMISCPTR(vpEventMsg, pEventMsg16); PUTEVENTMSG16(pEventMsg16, &EventMsg); FLUSHVDMPTR(vpEventMsg, sizeof(EVENTMSG16), pEventMsg16); FREEVDMPTR(pEventMsg16); } } return lReturn; } //***************************************************************************** // // 16->32 ThunkHookProc for Hooks of type WH_DEBUG - // // Return type is BOOL. // //***************************************************************************** LONG ThunkDebugHook16(INT nCode, LONG wParam, LONG lParam, LPHOOKSTATEDATA lpHSData) { LONG lReturn; lReturn = TRUE; UNREFERENCED_PARAMETER(nCode); UNREFERENCED_PARAMETER(wParam); UNREFERENCED_PARAMETER(lParam); UNREFERENCED_PARAMETER(lpHSData); LOGDEBUG(LOG_ALWAYS, ("ThunkDebugHook16:Not implemented.\n")); // the value in LOWORD is the valid return value return (LONG)(BOOL)LOWORD(lReturn); } //***************************************************************************** // // 16->32 ThunkHookProc for Hooks of type WH_MOUSE - // // Return type is BOOL. // //***************************************************************************** LONG ThunkMouseHook16(INT nCode, LONG wParam, VPVOID vpMHStruct, LPHOOKSTATEDATA lpHSData) { LONG lReturn; PMOUSEHOOKSTRUCT16 pMHStruct16; MOUSEHOOKSTRUCT MHStruct; GETMISCPTR(vpMHStruct, pMHStruct16); GETMOUSEHOOKSTRUCT16(pMHStruct16, &MHStruct); FREEVDMPTR(pMHStruct16); lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParam, (LPARAM)&MHStruct); GETMISCPTR(vpMHStruct, pMHStruct16); PUTMOUSEHOOKSTRUCT16(pMHStruct16, &MHStruct); FLUSHVDMPTR((VPVOID)vpMHStruct, sizeof(MOUSEHOOKSTRUCT16), pMHStruct16); FREEVDMPTR(pMHStruct16); return (LONG)(BOOL)LOWORD(lReturn); } //***************************************************************************** // // 16->32 ThunkHookProc for Hooks of type WH_SHELL - // // Return value is apparently zero. // //***************************************************************************** LONG ThunkShellHook16(INT nCode, LONG wParam, LONG lParam, LPHOOKSTATEDATA lpHSData) { LONG lReturn; switch (nCode) { case HSHELL_WINDOWCREATED: case HSHELL_WINDOWDESTROYED: wParam = (LONG)HWND32(wParam); break; case HSHELL_ACTIVATESHELLWINDOW: // fall thru default: break; } lReturn = CallNextHookEx(lpHSData->hHook, nCode, wParam, (LPARAM)lParam); // lReturn = 0? return (LONG)lReturn; } //***************************************************************************** // W32GetHookDDEMsglParam: // // Returns the lParam of the actual hook message. called for dde messages // only. returns valid lParam else 0. // //***************************************************************************** DWORD W32GetHookDDEMsglParam() { INT iFunc; LONG lParam; iFunc = viCurrentHookStateDataIndex; lParam = vHookParams.lParam; if (lParam) { switch (vaHookStateData[iFunc].iHook) { case WH_CALLWNDPROC: lParam = ((LPCWPSTRUCT)lParam)->lParam; break; case WH_MSGFILTER: case WH_SYSMSGFILTER: case WH_GETMESSAGE: lParam = ((LPMSG)lParam)->lParam; break; default: lParam = 0; } } return lParam; } //***************************************************************************** // GetEventMessage16: // //***************************************************************************** VOID GetEventMessage16(PEVENTMSG16 pEventMsg16, LPEVENTMSG lpEventMsg) { lpEventMsg->message = FETCHWORD(pEventMsg16->message); lpEventMsg->time = FETCHLONG(pEventMsg16->time); if ((lpEventMsg->message >= WM_KEYFIRST) && (lpEventMsg->message <= WM_KEYLAST)) { // Key event lpEventMsg->paramL = FETCHWORD(pEventMsg16->paramL); lpEventMsg->paramH = FETCHWORD(pEventMsg16->paramH) & 0x8000; lpEventMsg->paramH |= (lpEventMsg->paramL & 0xFF00) >> 8; lpEventMsg->paramL &= 0xFF; } else { // Mouse event lpEventMsg->paramL = FETCHWORD(pEventMsg16->paramL); lpEventMsg->paramH = FETCHWORD(pEventMsg16->paramH); } }