test: srvhook.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# srvhook.c

Go to the documentation of this file.

    00001 /****************************** Module Header ******************************\
    00002 * Module Name: srvhook.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * Server side of hook calls and callbacks.
    00007 *
    00008 * 05-09-91 ScottLu      Created.
    00009 \***************************************************************************/
    00010
    00011 #include "precomp.h"
    00012 #pragma hdrstop
    00013
    00014 LRESULT fnHkINLPCBTCREATESTRUCT(UINT msg, WPARAM wParam, LPCBT_CREATEWND pcbt,
    00015     PROC xpfnProc, BOOL bAnsi);
    00016
    00017 /***************************************************************************\
    00018 * xxxHkCallHook
    00019 *
    00020 * This is the server-side stub that calls to the client to call the actual
    00021 * hook function.
    00022 *
    00023 * History:
    00024 * 05-09-91 ScottLu      Rewrote to make all hooks work client/server!
    00025 * 01-28-91 DavidPe      Created.
    00026 \***************************************************************************/
    00027
    00028 LRESULT xxxHkCallHook(
    00029     PHOOK phk,
    00030     int nCode,
    00031     WPARAM wParam,
    00032     LPARAM lParam)
    00033 {
    00034     LRESULT nRet;
    00035     PROC pfnHk, pfnHookProc;
    00036     PPFNCLIENT ppfnClient;
    00037     PCWPSTRUCTEX pcwp;
    00038     PCWPRETSTRUCTEX pcwpret;
    00039     PCLIENTINFO pci;
    00040     ULONG_PTR dwHookData;
    00041     ULONG_PTR dwFlags;
    00042     struct tagSMS *psms;
    00043     TL tlSFWLock;
    00044     BOOL fLockForeground;
    00045
    00046     DbgValidateHooks(phk, phk->iHook);
    00047     /*
    00048      * Only low level hooks are allowed in the RIT context.
    00049      * Also asssert that the hook is not destroyed
    00050      */
    00051 #ifdef REDIRECTION
    00052     UserAssert((PtiCurrent() != gptiRit)
    00053                || (phk->iHook == WH_MOUSE_LL)
    00054                || (phk->iHook == WH_KEYBOARD_LL)
    00055                || (phk->iHook == WH_HITTEST));
    00056 #else
    00057     UserAssert((PtiCurrent() != gptiRit)
    00058                || (phk->iHook == WH_MOUSE_LL)
    00059                || (phk->iHook == WH_KEYBOARD_LL));
    00060 #endif // REDIRECTION
    00061
    00062     /*
    00063      * While we're still inside the critical section make sure the
    00064      * hook hasn't been 'freed'.  If so just return 0.
    00065      */
    00066     if (phk->offPfn != 0) {
    00067         pfnHookProc = PFNHOOK(phk);
    00068     } else {
    00069         return 0;
    00070     }
    00071
    00072 #ifdef WX86
    00073
    00074
    00075     /*
    00076      *  If the HookProc is x86 image, signal the client
    00077      *  dispatch code to use a risc thunk.
    00078      */
    00079
    00080     if (phk->flags & HF_WX86KNOWNDLL) {
    00081         (ULONG_PTR)pfnHookProc |= 0x80000000;
    00082         }
    00083
    00084
    00085 #endif
    00086
    00087     ppfnClient = (phk->flags & HF_ANSI) ? &gpsi->apfnClientA :
    00088             &gpsi->apfnClientW;
    00089
    00090     /*
    00091      * LATER5.0 GerardoB. This might generate some hate reactions but I'm
    00092      *  not sure we want people hooking just to steal the foreground.
    00093      * Prevent hookprocs from other processes from switching the foreground
    00094      */
    00095     fLockForeground = (GETPTI(phk)->ppi != PpiCurrent());
    00096     if (fLockForeground) {
    00097         ThreadLockSFWLockCount(&tlSFWLock);
    00098     }
    00099
    00100
    00101     switch(phk->iHook) {
    00102     case WH_CALLWNDPROC:
    00103     case WH_CALLWNDPROCRET:
    00104        if (phk->iHook == WH_CALLWNDPROC) {
    00105           pcwp = (PCWPSTRUCTEX)lParam;
    00106           psms = pcwp->psmsSender;
    00107        } else {
    00108           pcwpret = (PCWPRETSTRUCTEX)lParam;
    00109           psms = pcwpret->psmsSender;
    00110        }
    00111
    00112         /*
    00113          * If the sender has died or timed out, don't call the
    00114          * hook because any memory the message points to may be invalid.
    00115          */
    00116         if (psms != NULL && (psms->flags & (SMF_SENDERDIED | SMF_REPLY))) {
    00117             nRet = 0;
    00118             break;
    00119         }
    00120
    00121         /*
    00122          * This is the hardest of the hooks because we need to thunk through
    00123          * the message hooks in order to deal with synchronously sent messages
    00124          * that point to structures - to get the structures passed across
    00125          * alright, etc.
    00126          *
    00127          * This will call a special client-side routine that'll rebundle the
    00128          * arguments and call the hook in the right format.
    00129          *
    00130          * Currently, the message thunk callbacks to the client-side don't take
    00131          * enough parameters to pass wParam (which == fInterThread send msg).
    00132          * To do this, call one of two functions.
    00133          */
    00134         pci = GetClientInfo();
    00135         if (phk->iHook == WH_CALLWNDPROC) {
    00136             pfnHk = ppfnClient->pfnHkINLPCWPSTRUCT;
    00137         } else {
    00138             pfnHk = ppfnClient->pfnHkINLPCWPRETSTRUCT;
    00139             pci->dwHookData = pcwpret->lResult;
    00140         }
    00141
    00142         /*
    00143          * Save current hook state.
    00144          */
    00145         dwFlags = pci->CI_flags & CI_INTERTHREAD_HOOK;
    00146         dwHookData = pci->dwHookData;
    00147
    00148         if (wParam) {
    00149             pci->CI_flags |= CI_INTERTHREAD_HOOK;
    00150         } else {
    00151             pci->CI_flags &= ~CI_INTERTHREAD_HOOK;
    00152         }
    00153
    00154         if (phk->iHook == WH_CALLWNDPROC) {
    00155            nRet = ScSendMessageSMS(
    00156                PW(pcwp->hwnd),
    00157                pcwp->message,
    00158                pcwp->wParam,
    00159                pcwp->lParam,
    00160                (ULONG_PTR)pfnHookProc, pfnHk,
    00161                (phk->flags & HF_ANSI) ?
    00162                        (SCMS_FLAGS_ANSI|SCMS_FLAGS_INONLY) :
    00163                        SCMS_FLAGS_INONLY,
    00164                psms);
    00165         } else {
    00166             nRet = ScSendMessageSMS(
    00167                 PW(pcwpret->hwnd),
    00168                 pcwpret->message,
    00169                 pcwpret->wParam,
    00170                 pcwpret->lParam,
    00171                 (ULONG_PTR)pfnHookProc, pfnHk,
    00172                 (phk->flags & HF_ANSI) ?
    00173                         (SCMS_FLAGS_ANSI|SCMS_FLAGS_INONLY) :
    00174                         SCMS_FLAGS_INONLY,
    00175                 psms);
    00176         }
    00177         /*
    00178          * Restore previous hook state.
    00179          */
    00180         pci->CI_flags ^= ((pci->CI_flags ^ dwFlags) & CI_INTERTHREAD_HOOK);
    00181         pci->dwHookData = dwHookData;
    00182         break;
    00183     case WH_CBT:
    00184         /*
    00185          * There are many different types of CBT hooks!
    00186          */
    00187         switch(nCode) {
    00188         case HCBT_CLICKSKIPPED:
    00189             goto MouseHook;
    00190             break;
    00191
    00192         case HCBT_CREATEWND:
    00193             /*
    00194              * This hook type points to a CREATESTRUCT, so we need to
    00195              * be fancy with it's thunking, because a CREATESTRUCT contains
    00196              * a pointer to CREATEPARAMS which can be anything...  so
    00197              * funnel this through our message thunks.
    00198              */
    00199             nRet = fnHkINLPCBTCREATESTRUCT(
    00200                     MAKELONG((WORD)nCode, (WORD)phk->iHook),
    00201                     wParam,
    00202                     (LPCBT_CREATEWND)lParam,
    00203                     pfnHookProc,
    00204                     (phk->flags & HF_ANSI) ? TRUE : FALSE);
    00205             break;
    00206
    00207 #ifdef REDIRECTION
    00208         case HCBT_GETCURSORPOS:
    00209
    00210             /*
    00211              * This hook type points to a POINT structure, so it's pretty
    00212              * simple.
    00213              */
    00214             nRet = fnHkINLPPOINT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00215                     wParam, (LPPOINT)lParam, (ULONG_PTR)pfnHookProc,
    00216                     ppfnClient->pfnDispatchHook);
    00217             break;
    00218 #endif // REDIRECTION
    00219
    00220         case HCBT_MOVESIZE:
    00221
    00222             /*
    00223              * This hook type points to a RECT structure, so it's pretty
    00224              * simple.
    00225              */
    00226             nRet = fnHkINLPRECT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00227                     wParam, (LPRECT)lParam, (ULONG_PTR)pfnHookProc,
    00228                     ppfnClient->pfnDispatchHook);
    00229             break;
    00230
    00231         case HCBT_ACTIVATE:
    00232             /*
    00233              * This hook type points to a CBTACTIVATESTRUCT
    00234              */
    00235             nRet = fnHkINLPCBTACTIVATESTRUCT(MAKELONG((UINT)nCode,
    00236                     (UINT)phk->iHook), wParam, (LPCBTACTIVATESTRUCT)lParam,
    00237                     (ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook);
    00238             break;
    00239
    00240         default:
    00241
    00242             /*
    00243              * The rest of the cbt hooks are all dword parameters.
    00244              */
    00245             nRet = fnHkINDWORD(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00246                     wParam, lParam, (ULONG_PTR)pfnHookProc,
    00247                     ppfnClient->pfnDispatchHook, &phk->flags);
    00248             break;
    00249         }
    00250         break;
    00251
    00252     case WH_FOREGROUNDIDLE:
    00253         /*
    00254          * These are dword parameters and are therefore real easy.
    00255          *
    00256          */
    00257         nRet = fnHkINDWORD(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00258                 wParam, lParam, (ULONG_PTR)pfnHookProc,
    00259                 ppfnClient->pfnDispatchHook, &phk->flags);
    00260         break;
    00261
    00262     case WH_SHELL:
    00263
    00264         if (nCode == HSHELL_GETMINRECT) {
    00265             /*
    00266              * This hook type points to a RECT structure, so it's pretty
    00267              * simple.
    00268              */
    00269             nRet = fnHkINLPRECT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00270                     wParam, (LPRECT)lParam, (ULONG_PTR)pfnHookProc,
    00271                     ppfnClient->pfnDispatchHook);
    00272             break;
    00273         }
    00274
    00275         /*
    00276          * Otherwise fall through to the simple case of DWORD below
    00277          */
    00278
    00279     case WH_KEYBOARD:
    00280         /*
    00281          * These are dword parameters and are therefore real easy.
    00282          */
    00283         nRet = fnHkINDWORD(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00284                 wParam, lParam, (ULONG_PTR)pfnHookProc,
    00285                 ppfnClient->pfnDispatchHook, &phk->flags);
    00286         break;
    00287
    00288     case WH_MSGFILTER:
    00289     case WH_SYSMSGFILTER:
    00290     case WH_GETMESSAGE:
    00291         /*
    00292          * These take an lpMsg as their last parameter.  Since these are
    00293          * exclusively posted parameters, and since nowhere on the server
    00294          * do we post a message with a pointer to some other structure in
    00295          * it, the lpMsg structure contents can all be treated verbatim.
    00296          */
    00297         nRet = fnHkINLPMSG(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00298                 wParam, (LPMSG)lParam, (ULONG_PTR)pfnHookProc,
    00299                 ppfnClient->pfnDispatchHook,
    00300                 (phk->flags & HF_ANSI) ? TRUE : FALSE, &phk->flags);
    00301         break;
    00302
    00303     case WH_JOURNALPLAYBACK:
    00304
    00305 #ifdef HOOKBATCH
    00306         /*
    00307          * If this hook has cached playback info then we need to grab
    00308          * the info out of the cache.
    00309          */
    00310
    00311         if (phk->cEventMessages) {
    00312             if (nCode == HC_GETNEXT) {
    00313                 LPEVENTMSG pEventMsg;
    00314                 pEventMsg = (LPEVENTMSG)lParam;
    00315
    00316                 if (phk->flags & HF_NEEDHC_SKIP)
    00317                     phk->iCurrentEvent++;
    00318
    00319                 if (phk->iCurrentEvent < phk->cEventMessages) {
    00320                     *pEventMsg = phk->aEventCache[phk->iCurrentEvent];
    00321                 } else {
    00322
    00323                     /*
    00324                      * Free the cache set if it is still around
    00325                      */
    00326                     if (phk->aEventCache) {
    00327                         UserFreePool(phk->aEventCache);
    00328                         phk->aEventCache = NULL;
    00329                     }
    00330                     phk->cEventMessages = 0;
    00331                     phk->iCurrentEvent = 0;
    00332
    00333                     goto MakeClientJournalPlaybackCall;
    00334                 }
    00335
    00336                 /*
    00337                  * Return the time and zero the batched time so if we sleep
    00338                  * this time we won't sleep again next time
    00339                  */
    00340                 nRet = pEventMsg->time;
    00341                 if (nRet)
    00342                     phk->aEventCache[phk->iCurrentEvent].time = 0;
    00343             } else if (nCode == HC_SKIP) {
    00344                 phk->iCurrentEvent++;
    00345                 nRet = 0;
    00346             }
    00347
    00348         } else {
    00349 #endif // HOOKBATCH
    00350             /*
    00351              * In order to avoid a client/server transition for HC_SKIP we
    00352              * piggy-back it on top of the next journal playback event and
    00353              * send it from there.
    00354              */
    00355 // MakeClientJournalPlaybackCall:
    00356             nRet = fnHkOPTINLPEVENTMSG(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00357                     (WPARAM)PtoHq(phk), (LPEVENTMSG)lParam, (ULONG_PTR)pfnHookProc,
    00358                     ppfnClient->pfnDispatchHook);
    00359 #ifdef HOOKBATCH
    00360         }
    00361
    00362         /*
    00363          * Determine if we received a cached set of events if so then store
    00364          * them away off of the hook.
    00365          * paramL will be the number of events.
    00366          * paramH will be the array of events.
    00367          */
    00368         if ((nCode == HC_GETNEXT) && (((LPEVENTMSG)lParam)->message == 0x12341234)) {
    00369             NTSTATUS Status;
    00370             LPEVENTMSG pEventMsg = (LPEVENTMSG)lParam;
    00371
    00372             /*
    00373              * We should not be getting another cached set if we aren't
    00374              * done with the first set
    00375              */
    00376             UserAssert((phk->cEventMessages == 0) ||
    00377                     (phk->cEventMessages >= phk->iCurrentEvent));
    00378             UserAssert((pEventMsg->paramL < 500) && (pEventMsg->paramL > 1));
    00379
    00380             /*
    00381              * Free the last cache set if it is still around
    00382              */
    00383             if (phk->aEventCache) {
    00384                 UserFreePool(phk->aEventCache);
    00385                 phk->aEventCache = NULL;
    00386             }
    00387
    00388             if (phk->aEventCache = LocalAlloc(LPTR,
    00389                     pEventMsg->paramL*sizeof(EVENTMSG))) {
    00390                 PETHREAD Thread = PsGetCurrentThread();
    00391
    00392                 Status = ZwReadVirtualMemory(Thread->Process->ProcessHandle,
    00393                         (PVOID)pEventMsg->paramH, phk->aEventCache,
    00394                         pEventMsg->paramL*sizeof(EVENTMSG), NULL);
    00395
    00396                 if (NT_SUCCESS(Status)) {
    00397                     phk->cEventMessages = pEventMsg->paramL;
    00398                     phk->iCurrentEvent = 0;
    00399
    00400                     /*
    00401                      * Fill in the real EventMsg for this message
    00402                      */
    00403                     *pEventMsg = phk->aEventCache[0];
    00404                     phk->aEventCache[0].time = 0;
    00405                 }
    00406
    00407             } else {
    00408                 phk->cEventMessages = 0;
    00409                 phk->iCurrentEvent = 0;
    00410             }
    00411         }
    00412 #endif // HOOKBATCH
    00413
    00414         phk->flags &= ~HF_NEEDHC_SKIP;
    00415         break;
    00416
    00417     case WH_JOURNALRECORD:
    00418
    00419         nRet = fnHkOPTINLPEVENTMSG(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00420                 wParam, (LPEVENTMSG)lParam, (ULONG_PTR)pfnHookProc,
    00421                 ppfnClient->pfnDispatchHook);
    00422         break;
    00423
    00424     case WH_DEBUG:
    00425         /*
    00426          * This takes an lpDebugHookStruct.
    00427          */
    00428         nRet = fnHkINLPDEBUGHOOKSTRUCT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00429                 wParam, (LPDEBUGHOOKINFO)lParam, (ULONG_PTR)pfnHookProc,
    00430                 ppfnClient->pfnDispatchHook);
    00431         break;
    00432
    00433     case WH_KEYBOARD_LL:
    00434         /*
    00435          * This takes an lpKbdHookStruct.
    00436          */
    00437         nRet = fnHkINLPKBDLLHOOKSTRUCT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00438                 wParam, (LPKBDLLHOOKSTRUCT)lParam,
    00439                 (ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook);
    00440         break;
    00441
    00442     case WH_MOUSE_LL:
    00443         /*
    00444          * This takes an lpMsllHookStruct.
    00445          */
    00446         nRet = fnHkINLPMSLLHOOKSTRUCT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00447                 wParam, (LPMSLLHOOKSTRUCT)lParam,
    00448                 (ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook);
    00449         break;
    00450
    00451     case WH_MOUSE:
    00452         /*
    00453          * This takes an lpMouseHookStructEx.
    00454          */
    00455 MouseHook:
    00456         nRet = fnHkINLPMOUSEHOOKSTRUCTEX(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00457                 wParam, (LPMOUSEHOOKSTRUCTEX)lParam,
    00458                 (ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook, &phk->flags);
    00459         break;
    00460
    00461 #ifdef REDIRECTION
    00462     case WH_HITTEST:
    00463         /*
    00464          * This takes an lpHTHookStruct.
    00465          */
    00466         nRet = fnHkINLPHTHOOKSTRUCT(MAKELONG((UINT)nCode, (UINT)phk->iHook),
    00467                 wParam, (LPHTHOOKSTRUCT)lParam,
    00468                 (ULONG_PTR)pfnHookProc, ppfnClient->pfnDispatchHook);
    00469         break;
    00470 #endif // REDIRECTION
    00471
    00472     }
    00473
    00474     if (fLockForeground) {
    00475         ThreadUnlockSFWLockCount(&tlSFWLock);
    00476     }
    00477
    00478     return nRet;
    00479 }
    00480
    00481 /***************************************************************************\
    00482 * fnHkINLPCWPEXSTRUCT
    00483 *
    00484 * This gets thunked through the message thunks, so it has the format
    00485 * of a c/s message thunk call.
    00486 *
    00487 * 05-09-91 ScottLu      Created.
    00488 \***************************************************************************/
    00489
    00490 LRESULT fnHkINLPCWPEXSTRUCT(
    00491     PWND pwnd,
    00492     UINT message,
    00493     WPARAM wParam,
    00494     LPARAM lParam,
    00495     ULONG_PTR xParam)
    00496 {
    00497     CWPSTRUCTEX cwp;
    00498     PCLIENTINFO pci = GetClientInfo();
    00499
    00500     UNREFERENCED_PARAMETER(xParam);
    00501
    00502     cwp.hwnd = HW(pwnd);
    00503     cwp.message = message;
    00504     cwp.wParam = wParam;
    00505     cwp.lParam = lParam;
    00506     cwp.psmsSender = NULL;
    00507
    00508     return xxxCallNextHookEx(HC_ACTION, (pci->CI_flags & CI_INTERTHREAD_HOOK) != 0,
    00509             (LPARAM)&cwp);
    00510 }
    00511
    00512 LRESULT fnHkINLPCWPRETEXSTRUCT(
    00513     PWND pwnd,
    00514     UINT message,
    00515     WPARAM wParam,
    00516     LPARAM lParam,
    00517     ULONG_PTR xParam)
    00518 {
    00519     CWPRETSTRUCTEX cwp;
    00520     PCLIENTINFO pci = GetClientInfo();
    00521
    00522     UNREFERENCED_PARAMETER(xParam);
    00523
    00524     cwp.hwnd = HW(pwnd);
    00525     cwp.message = message;
    00526     cwp.wParam = wParam;
    00527     cwp.lParam = lParam;
    00528     cwp.lResult = pci->dwHookData;
    00529     cwp.psmsSender = NULL;
    00530
    00531     return xxxCallNextHookEx(HC_ACTION, (pci->CI_flags & CI_INTERTHREAD_HOOK) != 0,
    00532             (LPARAM)&cwp);
    00533 }