test: kernel/winable.c File Reference

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

# winable.c File Reference

`#include "precomp.h"`

Go to the source code of this file.

## Defines

#define | DBGVERIFYEVENTHOOK(peh)
#define | DBGVERIFYNOTIFY(pNotify)

## Functions

WINEVENTPROC | xxxGetEventProc (PEVENTHOOK pEventOrg)
PNOTIFY | CreateNotify (PEVENTHOOK peh, DWORD event, PWND pwnd, LONG idObject, LONG idChild, PTHREADINFO ptiEvent, DWORD dwTime)
PEVENTHOOK | xxxProcessNotifyWinEvent (PNOTIFY pNotify)
VOID | xxxFlushDeferredWindowEvents ()
VOID | xxxWindowEvent (DWORD event, PWND pwnd, LONG idObject, LONG idChild, DWORD dwFlags)
VOID | RemoveNotify (PNOTIFY *ppNotify)
VOID | DestroyNotify (PNOTIFY pNotifyDestroy)
VOID | FreeThreadsWinEvents (PTHREADINFO pti)
PEVENTHOOK | _SetWinEventHook (DWORD eventMin, DWORD eventMax, HMODULE hmodWinEventProc, PUNICODE_STRING pstrLib, WINEVENTPROC pfnWinEventProc, HANDLE hEventProcess, DWORD idEventThread, DWORD dwFlags)
BOOL | _UnhookWinEvent (PEVENTHOOK pEventUnhook)
VOID | DestroyEventHook (PEVENTHOOK pEventDestroy)

## Variables

NOTIFY | notifyCache
BOOL | fNotifyCacheInUse = FALSE

## Define Documentation

#define DBGVERIFYEVENTHOOK | ( | peh |  | ) |

| Definition at line 33 of file kernel/winable.c. Referenced by _UnhookWinEvent(), DestroyEventHook(), RemoveNotify(), xxxProcessNotifyWinEvent(), and xxxWindowEvent().

#define DBGVERIFYNOTIFY | ( | pNotify |  | ) |

| Definition at line 34 of file kernel/winable.c. Referenced by DestroyNotify(), xxxProcessNotifyWinEvent(), and xxxWindowEvent().

## Function Documentation

PEVENTHOOK _SetWinEventHook | ( | DWORD | eventMin,
|  | DWORD | eventMax,
|  | HMODULE | hmodWinEventProc,
|  | PUNICODE_STRING | pstrLib,
|  | WINEVENTPROC | pfnWinEventProc,
|  | HANDLE | hEventProcess,
|  | DWORD | idEventThread,
|  | DWORD | dwFlags
| ) |

Definition at line 674 of file kernel/winable.c.

References AddHmodDependency(), dwFlags, tagEVENTHOOK::eventMax, tagEVENTHOOK::eventMin, FALSE, tagEVENTHOOK::fDestroyed, tagEVENTHOOK::fIgnoreOwnProcess, tagEVENTHOOK::fIgnoreOwnThread, tagEVENTHOOK::fSync, GetHmodTableIndex(), gpWinEventHooks, tagEVENTHOOK::hEventProcess, HMAllocObject(), tagEVENTHOOK::idEventThread, tagEVENTHOOK::ihmod, NULL, tagEVENTHOOK::offPfn, tagEVENTHOOK::pehNext, PtiCurrent, PtiFromThreadId(), SET_SRVIF, SRVIF_WINEVENTHOOKS, tagTHREADINFO::TIF_flags, TIF_GUITHREADINITIALIZED, TIF_INCLEANUP, TYPE_WINEVENTHOOK, and UINT.

Referenced by NtUserSetWinEventHook().

    00683 {
    00684     PEVENTHOOK pEventNew;
    00685     PTHREADINFO ptiCurrent;
    00686
    00687     int ihmod;
    00688
    00689     ptiCurrent = PtiCurrent();
    00690
    00691     //
    00692     // If exiting, fail the call.
    00693     //
    00694     if (ptiCurrent->TIF_flags & TIF_INCLEANUP) {
    00695         RIPMSG1(RIP_ERROR, "SetWinEventHook: Fail call - thread %#p in cleanup", ptiCurrent);
    00696         return NULL;
    00697     }
    00698
    00699     /*
    00700      * Check to see if filter proc is valid.
    00701      */
    00702     if (pfnWinEventProc == NULL) {
    00703         RIPERR0(ERROR_INVALID_FILTER_PROC, RIP_VERBOSE, "pfnWinEventProc == NULL");
    00704         return NULL;
    00705     }
    00706
    00707     if (eventMin > eventMax) {
    00708         RIPERR0(ERROR_INVALID_HOOK_FILTER, RIP_VERBOSE, "eventMin > eventMax");
    00709         return NULL;
    00710     }
    00711
    00712     if (dwFlags & WINEVENT_INCONTEXT) {
    00713         /*
    00714          * WinEventProc to be called in context of hooked thread, so needs a DLL
    00715          */
    00716         if (hmodWinEventProc == NULL) {
    00717             RIPERR0(ERROR_HOOK_NEEDS_HMOD, RIP_VERBOSE, "");
    00718             return NULL;
    00719         } else if (pstrLib == NULL) {
    00720             /*
    00721              * If we got an hmod, we should get a DLL name too!
    00722              */
    00723             RIPERR1(ERROR_DLL_NOT_FOUND, RIP_ERROR,
    00724                     "hmod %#p, but no lib name", hmodWinEventProc);
    00725             return NULL;
    00726         }
    00727         ihmod = GetHmodTableIndex(pstrLib);
    00728         if (ihmod == -1) {
    00729             RIPERR0(ERROR_MOD_NOT_FOUND, RIP_VERBOSE, "");
    00730             return NULL;
    00731         }
    00732     } else {
    00733         ihmod = -1;            // means no DLL is required
    00734         hmodWinEventProc = 0;
    00735     }
    00736
    00737     /*
    00738      * Check the thread id, check it is a GUI thread.
    00739      */
    00740     if (idEventThread != 0) {
    00741         PTHREADINFO ptiT;
    00742
    00743         ptiT = PtiFromThreadId(idEventThread);
    00744         if ((ptiT == NULL) ||
    00745                 !(ptiT->TIF_flags & TIF_GUITHREADINITIALIZED)) {
    00746             RIPERR1(ERROR_INVALID_THREAD_ID, RIP_VERBOSE, "pti %#p", ptiT);
    00747             return NULL;
    00748         }
    00749     }
    00750
    00751     //
    00752     // Create the window for async events first.  Creating it might yield,
    00753     // so we want to do this before we've touched our event array.
    00754     //
    00755     // NOTE that USER itself will not pass on window creation/destruction
    00756     // notifications for
    00757     //      * IME windows
    00758     //      * OLE windows
    00759     //      * RPC windows
    00760     //      * Event windows
    00761     //
    00762
    00763     //
    00764     // Get a new event.
    00765     //
    00766     pEventNew = (PEVENTHOOK)HMAllocObject(ptiCurrent, NULL,
    00767             TYPE_WINEVENTHOOK, sizeof(EVENTHOOK));
    00768     if (!pEventNew)
    00769         return NULL;
    00770
    00771     //
    00772     // Fill in the new event.
    00773     //
    00774     pEventNew->eventMin = (UINT)eventMin;
    00775     pEventNew->eventMax = (UINT)eventMax;
    00776
    00777     // pEventNew->f32Bit = ((dwFlags & WINEVENT_32BITCALLER) != 0);
    00778     pEventNew->fIgnoreOwnThread = ((dwFlags & WINEVENT_SKIPOWNTHREAD) != 0);
    00779     pEventNew->fIgnoreOwnProcess = ((dwFlags & WINEVENT_SKIPOWNPROCESS) != 0);
    00780     pEventNew->fDestroyed = FALSE;
    00781     pEventNew->fSync = ((dwFlags & WINEVENT_INCONTEXT) != 0);
    00782
    00783     pEventNew->hEventProcess = hEventProcess;
    00784     pEventNew->idEventThread = idEventThread;
    00785     // pEventNew->cInUse = 0;
    00786
    00787     pEventNew->ihmod = ihmod;
    00788
    00789     /*
    00790      * Add a dependency on this module - meaning, increment a count
    00791      * that simply counts the number of hooks set into this module.
    00792      */
    00793     if (pEventNew->ihmod >= 0) {
    00794         AddHmodDependency(pEventNew->ihmod);
    00795     }
    00796
    00797     /*
    00798      * If pfnWinEventProc is in caller's process and no DLL is involved,
    00799      * then pEventNew->offPfn is the actual address.
    00800      */
    00801     pEventNew->offPfn = ((ULONG_PTR)pfnWinEventProc) - ((ULONG_PTR)hmodWinEventProc);
    00802
    00803     //
    00804     //
    00805     // Link our event into the master list.
    00806     //
    00807     // Note that we count on USER to not generate any events when installing
    00808     // our hook.  The caller can't handle it yet since he hasn't got back
    00809     // his event handle from this call.
    00810     //
    00811     pEventNew->pehNext = gpWinEventHooks;
    00812     gpWinEventHooks = pEventNew;
    00813     SET_SRVIF(SRVIF_WINEVENTHOOKS);
    00814
    00815     return pEventNew;
    00816 }

BOOL _UnhookWinEvent | ( | PEVENTHOOK | pEventUnhook | ) |

Definition at line 827 of file kernel/winable.c.

References DBGVERIFYEVENTHOOK, DestroyEventHook(), FALSE, GETPTI, HMIsMarkDestroy, PtiCurrent, and TRUE.

Referenced by NtUserUnhookWinEvent().

    00828 {
    00829     DBGVERIFYEVENTHOOK(pEventUnhook);
    00830
    00831     if (HMIsMarkDestroy(pEventUnhook) || (GETPTI(pEventUnhook) != PtiCurrent())) {
    00832         //
    00833         // We do this to avoid someone calling UnhookWinEvent() the first
    00834         // time, then somehow getting control again and calling it a second
    00835         // time before we've managed to free up the event since someone was
    00836         // in the middle of using it at the first UWE call.
    00837         //
    00838
    00839         RIPERR0(ERROR_INVALID_HANDLE, RIP_WARNING, "_UnhookWinEvent: Invalid event hook");
    00840         return FALSE;
    00841     }
    00842
    00843     //
    00844     // Purge this baby if all notifications are done.
    00845     //      * if there are SYNC ones pending, the caller will clean this up
    00846     //          upon the return from calling the event
    00847     //      * if there are ASYNC ones pending, the receiver will not call
    00848     //          the event and clean it up when he gets it.
    00849     //
    00850
    00851     //
    00852     // NOTE that DestroyEventHook() does not yield!
    00853     //
    00854     DestroyEventHook(pEventUnhook);
    00855
    00856     return TRUE;
    00857 }

PNOTIFY CreateNotify | ( | PEVENTHOOK | peh,
|  | DWORD | event,
|  | PWND | pwnd,
|  | LONG | idObject,
|  | LONG | idChild,
|  | PTHREADINFO | ptiEvent,
|  | DWORD | dwTime
| ) |

Definition at line 425 of file kernel/winable.c.

References tagNOTIFY::dwEventTime, tagNOTIFY::dwWEFlags, tagNOTIFY::event, fNotifyCacheInUse, tagEVENTHOOK::fSync, gpLastPendingNotify, gpPendingNotifies, HW, tagNOTIFY::hwnd, tagNOTIFY::idChild, tagNOTIFY::idObject, tagNOTIFY::idSenderThread, Lock, notifyCache, NULL, tagNOTIFY::pNotifyNext, tagNOTIFY::ptiReceiver, tagNOTIFY::spEventHook, TIDq, TRUE, and WEF_ASYNC.

Referenced by xxxWindowEvent().

    00427 {
    00428     PNOTIFY pNotify;
    00429     UserAssert(pEvent != NULL);
    00430
    00431     //
    00432     // Get a pointer.  From cache if available.
    00433     // IanJa - change this to allocate from zone a la AllocQEntry??
    00434     //
    00435     if (!fNotifyCacheInUse) {
    00436         fNotifyCacheInUse = TRUE;
    00437         pNotify = &notifyCache;
    00438 #if DBG
    00439         //
    00440         // Make sure we aren't forgetting to set any fields.
    00441         //
    00442         // DebugFillBuffer(pNotify, sizeof(NOTIFY));
    00443 #endif
    00444     } else {
    00445         pNotify = (PNOTIFY)UserAllocPool(sizeof(NOTIFY), TAG_NOTIFY);
    00446         if (!pNotify)
    00447             return NULL;
    00448     }
    00449
    00450
    00451     /*
    00452      * Fill in the notify block.
    00453      */
    00454     pNotify->spEventHook = NULL;
    00455     Lock(&pNotify->spEventHook, pEvent);
    00456     pNotify->hwnd = HW(pwnd);
    00457     pNotify->event = event;
    00458     pNotify->idObject = idObject;
    00459     pNotify->idChild = idChild;
    00460     pNotify->idSenderThread = TIDq(ptiSender);
    00461     UserAssert(pNotify->idSenderThread != 0);
    00462     pNotify->dwEventTime = dwTime;
    00463     pNotify->dwWEFlags = pEvent->fSync ? 0 : WEF_ASYNC;
    00464     pNotify->pNotifyNext = NULL;
    00465     pNotify->ptiReceiver = NULL;
    00466 #if DBG
    00467     gnNotifies++;
    00468 #endif
    00469
    00470     /*
    00471      * The order of non-deferred notifications doesn't matter; they are here
    00472      * simply for cleanup/in-use tracking. However, deferred notifications must
    00473      * be ordered with most recent at the end, so just order them all that way.
    00474      */
    00475     if (gpPendingNotifies) {
    00476         UserAssert(gpLastPendingNotify);
    00477         UserAssert(gpLastPendingNotify->pNotifyNext == NULL);
    00478         gpLastPendingNotify->pNotifyNext = pNotify;
    00479     } else {
    00480         gpPendingNotifies = pNotify;
    00481     }
    00482     gpLastPendingNotify = pNotify;
    00483
    00484     return pNotify;
    00485 }

VOID DestroyEventHook | ( | PEVENTHOOK | pEventDestroy | ) |

Definition at line 879 of file kernel/winable.c.

References DBGVERIFYEVENTHOOK, tagEVENTHOOK::fDestroyed, gpWinEventHooks, HMFreeObject(), HMMarkObjectDestroy(), tagEVENTHOOK::ihmod, tagEVENTHOOK::pehNext, RemoveHmodDependency(), SET_OR_CLEAR_SRVIF, SRVIF_WINEVENTHOOKS, and TRUE.

Referenced by _UnhookWinEvent(), and FreeThreadsWinEvents().

    00880 {
    00881     PEVENTHOOK *ppEvent;
    00882     PEVENTHOOK pEventT;
    00883
    00884     DBGVERIFYEVENTHOOK(pEventDestroy);
    00885     UserAssert(gpWinEventHooks);
    00886
    00887     /*
    00888      * Mark this event as destroyed, but don't remove it from the event list
    00889      * until its lock count goes to 0 - we may be traversing the list
    00890      * within xxxWindowEvent, so we mustn't break the link to the next hook.
    00891      */
    00892     pEventDestroy->fDestroyed = TRUE;
    00893
    00894     /*
    00895      * If the object is locked, mark it for destroy but don't free it yet.
    00896      */
    00897     if (!HMMarkObjectDestroy(pEventDestroy))
    00898         return;
    00899
    00900     /*
    00901      * Remove this from our event list.
    00902      */
    00903     for (ppEvent = &gpWinEventHooks; pEventT = *ppEvent; ppEvent = &pEventT->pehNext) {
    00904         if (pEventT == pEventDestroy) {
    00905             *ppEvent = pEventDestroy->pehNext;
    00906             break;
    00907         }
    00908     }
    00909     UserAssert(pEventT);
    00910     SET_OR_CLEAR_SRVIF(SRVIF_WINEVENTHOOKS, gpWinEventHooks);
    00911
    00912     /*
    00913      * Make sure each hooked thread will unload the hook proc DLL
    00914      */
    00915     if (pEventDestroy->ihmod >= 0) {
    00916         RemoveHmodDependency(pEventDestroy->ihmod);
    00917     }
    00918
    00919     /*
    00920      * Free this pointer.
    00921      */
    00922     HMFreeObject(pEventDestroy);
    00923
    00924     return;
    00925 }

VOID DestroyNotify | ( | PNOTIFY | pNotifyDestroy | ) |

Definition at line 566 of file kernel/winable.c.

References DBGVERIFYNOTIFY, gpPendingNotifies, NULL, tagNOTIFY::pNotifyNext, PtiCurrent, tagNOTIFY::ptiReceiver, and RemoveNotify().

Referenced by CleanEventMessage(), FreeThreadsWinEvents(), and xxxProcessNotifyWinEvent().

    00567 {
    00568     PNOTIFY  *ppNotify;
    00569     PNOTIFY  pNotifyT;
    00570
    00571     DBGVERIFYNOTIFY(pNotifyDestroy);
    00572
    00573     /*
    00574      * Either this notify isn't currently in the process of calling back
    00575      * (which means ptiReceiver is NULL) or the thread destroying it
    00576      * must be the one that was calling back (which means this thread
    00577      * was destroyed during the callback and is cleaning up).
    00578      */
    00579     UserAssert((pNotifyDestroy->ptiReceiver == NULL) ||
    00580             (pNotifyDestroy->ptiReceiver == PtiCurrent()));
    00581
    00582     ppNotify = &gpPendingNotifies;
    00583     while (pNotifyT = *ppNotify) {
    00584         if (pNotifyT == pNotifyDestroy) {
    00585             RemoveNotify(ppNotify);
    00586             return;
    00587         } else {
    00588             ppNotify = &pNotifyT->pNotifyNext;
    00589         }
    00590     }
    00591     RIPMSG1(RIP_ERROR, "DestroyNotify %#p - not found", pNotifyDestroy);
    00592 }

VOID FreeThreadsWinEvents | ( | PTHREADINFO | pti | ) |

Definition at line 615 of file kernel/winable.c.

References DestroyEventHook(), DestroyNotify(), DWORD, tagNOTIFY::dwWEFlags, GETPTI, gpPendingNotifies, gpWinEventHooks, tagNOTIFY::idSenderThread, NULL, tagEVENTHOOK::pehNext, tagNOTIFY::pNotifyNext, tagNOTIFY::ptiReceiver, WEF_ASYNC, and WEF_POSTED.

Referenced by xxxDestroyThreadInfo().

    00616 {
    00617     PEVENTHOOK peh, pehNext;
    00618     PNOTIFY pn, pnNext;
    00619     DWORD idCurrentThread = W32GetCurrentTID();
    00620
    00621     /*
    00622      * Loop through all the notifications
    00623      */
    00624     for (pn = gpPendingNotifies; pn; pn = pnNext) {
    00625         pnNext = pn->pNotifyNext;
    00626
    00627         /*
    00628          * Only destroy sync notifications that belong to this thread
    00629          * and are not currently calling back i.e. ptiReceiver must be NULL.
    00630          * Otherwise, when we come back from the callback in
    00631          * xxxProcessNotifyWinEvent we will operate on a freed notify.
    00632          * Also destroy the notification if the receiver is going away
    00633          * or else it gets leaked as long as the sender is alive.
    00634          */
    00635         if ((pn->idSenderThread == idCurrentThread &&
    00636                 pn->ptiReceiver == NULL) || (pn->ptiReceiver == pti)) {
    00637             if ((pn->dwWEFlags & WEF_ASYNC) == 0) {
    00638                 UserAssert((pn->dwWEFlags & WEF_POSTED) == 0);
    00639                 DestroyNotify(pn);
    00640             }
    00641         }
    00642     }
    00643
    00644     peh = gpWinEventHooks;
    00645     while (peh) {
    00646         pehNext = peh->pehNext;
    00647         if (GETPTI(peh) == pti) {
    00648             DestroyEventHook(peh);
    00649         }
    00650         peh = pehNext;
    00651     }
    00652     // Async notification not yet processed may still be posted in a queue,
    00653     // pending being read and processed (gnNotifies > 0), although the
    00654     // originating hook has now been unhooked (maybe gpWinEventHooks == NULL)
    00655     // so the following assert is no good:
    00656     // UserAssert(gpWinEventHooks || (!gpWinEventHooks && !gnNotifies));
    00657 }

VOID RemoveNotify | ( | PNOTIFY * | ppNotify | ) |

Definition at line 495 of file kernel/winable.c.

References DBGVERIFYEVENTHOOK, tagNOTIFY::dwWEFlags, FALSE, fNotifyCacheInUse, gpLastPendingNotify, gpPendingNotifies, notifyCache, NULL, tagNOTIFY::pNotifyNext, tagNOTIFY::spEventHook, Unlock, and WEF_DEFERNOTIFY.

Referenced by DestroyNotify().

    00496 {
    00497     PNOTIFY pNotifyRemove;
    00498
    00499     pNotifyRemove = *ppNotify;
    00500
    00501     /*
    00502      * First, get it out of the pending list.
    00503      */
    00504     *ppNotify = pNotifyRemove->pNotifyNext;
    00505
    00506 #if DBG
    00507     if (pNotifyRemove->dwWEFlags & WEF_DEFERNOTIFY) {
    00508         UserAssert(gnDeferredWinEvents > 0);
    00509         gnDeferredWinEvents--;
    00510     }
    00511 #endif
    00512     if (*ppNotify == NULL) {
    00513         /*
    00514          * Removing last notify, so fix up gpLastPendingNotify:
    00515          * If list now empty, there is no last item.
    00516          */
    00517         if (gpPendingNotifies == NULL) {
    00518             gpLastPendingNotify = NULL;
    00519         } else {
    00520             gpLastPendingNotify = CONTAINING_RECORD(ppNotify, NOTIFY, pNotifyNext);
    00521         }
    00522     }
    00523     UserAssert((gpPendingNotifies == 0) || (gpPendingNotifies > (PNOTIFY)100));
    00524
    00525     DBGVERIFYEVENTHOOK(pNotifyRemove->spEventHook);
    00526
    00527     /*
    00528      * This may cause the win event hook to be freed.
    00529      */
    00530     Unlock(&pNotifyRemove->spEventHook);
    00531
    00532     //
    00533     // Now free it.  Either put it back in the cache if it is the cache,
    00534     // or really free it otherwise.
    00535     //
    00536     if (pNotifyRemove == &notifyCache) {
    00537         UserAssert(fNotifyCacheInUse);
    00538         fNotifyCacheInUse = FALSE;
    00539     } else {
    00540         UserFreePool(pNotifyRemove);
    00541     }
    00542 #if DBG
    00543     UserAssert(gnNotifies > 0);
    00544     gnNotifies--;
    00545 #endif
    00546 }

VOID xxxFlushDeferredWindowEvents | ( |  | ) |

Definition at line 217 of file kernel/winable.c.

References DWORD, tagNOTIFY::dwWEFlags, gpPendingNotifies, tagNOTIFY::idSenderThread, IsWinEventNotifyDeferredOK, tagNOTIFY::pNotifyNext, WEF_ASYNC, WEF_DEFERNOTIFY, and xxxProcessNotifyWinEvent().

Referenced by xxxWindowEvent().

    00218 {
    00219     PNOTIFY pNotify;
    00220     DWORD idCurrentThread = W32GetCurrentTID();
    00221
    00222     if (idCurrentThread == 0) {
    00223         RIPMSG0(RIP_ERROR, "processing deferred notifications before we have a pti!");
    00224         // return;
    00225     }
    00226
    00227     UserAssert(IsWinEventNotifyDeferredOK());
    00228
    00229     pNotify = gpPendingNotifies;
    00230     while (pNotify) {
    00231         if (((pNotify->dwWEFlags & WEF_DEFERNOTIFY) == 0) ||
    00232                 (pNotify->idSenderThread != idCurrentThread)) {
    00233             // UserAssert(pNotify->idSenderThread == idCurrentThread); // just testing!
    00234             pNotify = pNotify->pNotifyNext;
    00235         } else {
    00236             /*
    00237              * Clear WEF_DEFERNOTIFY so that if we recurse in the callback
    00238              * we won't try to send this notification again.
    00239              */
    00240             pNotify->dwWEFlags &= ~WEF_DEFERNOTIFY;
    00241 #if DBG
    00242             gnDeferredWinEvents--;
    00243 #endif
    00244             /*
    00245              * We shouldn't have deferred ASYNC notifications: we should have
    00246              * posted them immediately.
    00247              */
    00248             UserAssert((pNotify->dwWEFlags & WEF_ASYNC) == 0);
    00249             xxxProcessNotifyWinEvent(pNotify);
    00250             /*
    00251              * Start again at the head of the list, in case it munged during
    00252              * the callback.
    00253              */
    00254             pNotify = gpPendingNotifies;
    00255         }
    00256     }
    00257 }

WINEVENTPROC xxxGetEventProc | ( | PEVENTHOOK | pEventOrg | ) |

Definition at line 936 of file kernel/winable.c.

References CheckLock, FALSE, tagEVENTHOOK::fSync, HMIsMarkDestroy, tagEVENTHOOK::ihmod, NULL, tagEVENTHOOK::offPfn, PFNHOOK, PtiCurrent, TESTHMODLOADED, and xxxLoadHmodIndex().

Referenced by xxxProcessNotifyWinEvent().

    00936                                       {
    00937     PTHREADINFO ptiCurrent;
    00938
    00939     UserAssert(pEventOrg);
    00940     UserAssert(pEventOrg->fSync);
    00941     UserAssert(pEventOrg->ihmod >= 0);
    00942     UserAssert(pEventOrg->offPfn != 0);
    00943
    00944     CheckLock(pEventOrg);
    00945
    00946     /*
    00947      * Make sure the hook is still around before we
    00948      * try and call it.
    00949      */
    00950     if (HMIsMarkDestroy(pEventOrg)) {
    00951         return NULL;
    00952     }
    00953
    00954     ptiCurrent = PtiCurrent();
    00955
    00956     /*
    00957      * Make sure the DLL for this hook, if any, has been loaded
    00958      * for the current process.
    00959      */
    00960     if ((pEventOrg->ihmod != -1) &&
    00961             (TESTHMODLOADED(ptiCurrent, pEventOrg->ihmod) == 0)) {
    00962
    00963         /*
    00964          * Try loading the library, since it isn't loaded in this processes
    00965          * context.  The hook is alrerady locked, so it won't go away while
    00966          * we're loading this library.
    00967          */
    00968         if (xxxLoadHmodIndex(pEventOrg->ihmod, FALSE) == NULL) {
    00969             return NULL;
    00970         }
    00971     }
    00972
    00973     /*
    00974      * While we're still inside the critical section make sure the
    00975      * hook hasn't been 'freed'.  If so just return NULL.
    00976      * IanJa - since WinEvent has already been called, you might think that we
    00977      * should pass the event on, but the hooker may not be expecting this after
    00978      * having cancelled the hook!  In any case, seems we may have two ways
    00979      * of detecting that this hook has been removed:
    00980      */
    00981
    00982     /*
    00983      * Make sure the hook is still around before we
    00984      * try and call it.
    00985      */
    00986     if (HMIsMarkDestroy(pEventOrg)) {
    00987         return NULL;
    00988     }
    00989
    00990     return (WINEVENTPROC)PFNHOOK(pEventOrg);
    00991 }

PEVENTHOOK xxxProcessNotifyWinEvent | ( | PNOTIFY | pNotify | ) |

Definition at line 68 of file kernel/winable.c.

References BEGINATOMICCHECK, DBGVERIFYEVENTHOOK, DBGVERIFYNOTIFY, DestroyNotify(), tagNOTIFY::dwWEFlags, ENDATOMICCHECK, tagEVENTHOOK::fDestroyed, tagEVENTHOOK::fSync, GETPTI, gptiRit, tagEVENTHOOK::head, tagEVENTHOOK::ihmod, IsRestricted(), tagPROCESSINFO::luidSession, NULL, tagEVENTHOOK::offPfn, tagEVENTHOOK::pehNext, PostEventMessage(), tagTHREADINFO::ppi, PtiCurrent, tagNOTIFY::ptiReceiver, QEVENT_NOTIFYWINEVENT, RtlEqualLuid(), tagNOTIFY::spEventHook, ThreadLockAlways, ThreadUnlock, TIF_ALLOWOTHERACCOUNTHOOK, TIF_CSRSSTHREAD, tagTHREADINFO::TIF_flags, TIF_INCLEANUP, TIF_SYSTEMTHREAD, TIF_WOW64, WEF_ASYNC, WEF_DEFERNOTIFY, WEF_POSTED, xxxClientCallWinEventProc(), and xxxGetEventProc().

Referenced by xxxFlushDeferredWindowEvents(), xxxProcessEventMessage(), and xxxWindowEvent().

    00069 {
    00070     WINEVENTPROC   pfn;
    00071     PEVENTHOOK     pEventHook;
    00072     TL             tlpEventHook;
    00073     PTHREADINFO    ptiCurrent = PtiCurrent();
    00074
    00075     pEventHook = pNotify->spEventHook;
    00076     DBGVERIFYEVENTHOOK(pEventHook);
    00077     UserAssert(pEventHook->head.cLockObj);
    00078
    00079     if (((pNotify->dwWEFlags & (WEF_ASYNC | WEF_POSTED)) == WEF_ASYNC)
    00080         ||
    00081         (ptiCurrent->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD | TIF_INCLEANUP))
    00082
    00083         ||
    00084         (!RtlEqualLuid(&GETPTI(pEventHook)->ppi->luidSession, &ptiCurrent->ppi->luidSession) &&
    00085          !(ptiCurrent->TIF_flags & TIF_ALLOWOTHERACCOUNTHOOK))
    00086
    00087         ||
    00088         (GETPTI(pEventHook)->ppi != ptiCurrent->ppi &&
    00089          IsRestricted(GETPTI(pEventHook)->pEThread))
    00090
    00091 #if defined(_WIN64)
    00092         ||
    00093         ((GETPTI(pEventHook)->TIF_flags & TIF_WOW64) != (ptiCurrent->TIF_flags & TIF_WOW64))
    00094 #endif
    00095         ) {
    00096         /*
    00097          * POST
    00098          *
    00099          * WinEvent Hook set without WINEVENT_INCONTEXT flag are posted;
    00100          * Events from system threads are posted because there is no user-mode
    00101          *    part to callback to;
    00102          * Console is not permitted to load DLLs, so we must post back to the
    00103          *    hooking application;
    00104          * DLLs can not be loaded cross bit type(32bit to 64bit) on 64bit NT
    00105          *    so we must post(It may be usefull to let the app be aware and
    00106          *    even supply both a 32bit and a 64bit DLL that are aware of each other);
    00107          * Threads in cleanup can't get called back, so turn their
    00108          *    notifications into async ones. (Better late than never).
    00109          *
    00110          * If forcing these events ASYNC is unacceptable, we might consider
    00111          * doing system/console SYNC events like low-level hooks (sync with
    00112          * timeout: but may have to post it if the timeout expires) - IanJa
    00113          */
    00114         PQ  pqReceiver = GETPTI(pEventHook)->pq;
    00115         PEVENTHOOK pEventHookNext = pEventHook->pehNext;
    00116
    00117         BEGINATOMICCHECK();
    00118
    00119         DBGVERIFYNOTIFY(pNotify);
    00120         pNotify->dwWEFlags |= WEF_POSTED | WEF_ASYNC;
    00121         if (!pqReceiver || (GETPTI(pEventHook) == gptiRit) ||
    00122                 pEventHook->fDestroyed ||
    00123                 !PostEventMessage(GETPTI(pEventHook), pqReceiver,
    00124                                   QEVENT_NOTIFYWINEVENT,
    00125                                   NULL, 0, 0, (LPARAM)pNotify)) {
    00126             /*
    00127              * If the receiver doesn't have a queue or the
    00128              * post failed (low memory), cleanup what we just
    00129              * created.
    00130              * Note: destroying the notification may destroy pEventHook too.
    00131              */
    00132             RIPMSG2(RIP_WARNING, "failed to post NOTIFY at %#p, time %lx\n",
    00133                       pNotify, pNotify->dwEventTime);
    00134             DestroyNotify(pNotify);
    00135         }
    00136
    00137         ENDATOMICCHECK();
    00138
    00139         if (pEventHookNext) {
    00140             DBGVERIFYEVENTHOOK(pEventHookNext);
    00141         }
    00142         return pEventHookNext;
    00143     }
    00144
    00145     /*
    00146      * Don't call back if the hook has been destroyed (unhooked).
    00147      */
    00148     if (pEventHook->fDestroyed) {
    00149         /*
    00150          * Save the next hook since DestroyNotify may cause pEventHook to
    00151          * be freed by unlocking it.
    00152          */
    00153         pEventHook = pEventHook->pehNext;
    00154         DestroyNotify(pNotify);
    00155         return pEventHook;
    00156     }
    00157
    00158     /*
    00159      * CALLBACK
    00160      *
    00161      * This leaves the critical section.
    00162      * We return the next Event Hook in the list so that the caller doesn't
    00163      * have to lock pEventHook.
    00164      */
    00165     UserAssert((pNotify->dwWEFlags & WEF_DEFERNOTIFY) == 0);
    00166
    00167     ThreadLockAlways(pEventHook, &tlpEventHook);
    00168
    00169     UserAssertMsg1(pNotify->ptiReceiver == NULL,
    00170          "pNotify %#p is already in callback!  Reentrant?", pNotify);
    00171     pNotify->ptiReceiver = ptiCurrent;
    00172
    00173     if (!pEventHook->fSync) {
    00174         UserAssert(pEventHook->ihmod == -1);
    00175         pfn = (WINEVENTPROC)pEventHook->offPfn;
    00176     } else {
    00177         pfn = xxxGetEventProc(pEventHook);
    00178     }
    00179     if (pfn) {
    00180         xxxClientCallWinEventProc(pfn, pEventHook, pNotify);
    00181         DBGVERIFYNOTIFY(pNotify);
    00182         DBGVERIFYEVENTHOOK(pEventHook);
    00183         UserAssert(pEventHook->head.cLockObj);
    00184     }
    00185
    00186     pNotify->ptiReceiver = NULL;
    00187
    00188     /*
    00189      * Save the next item in the list, ThreadUnlock() may destroy pEventHook.
    00190      * DestroyNotify() may also kill the event if it is a zombie (destroyed
    00191      * but being used, waiting for use count to go to 0 before being freed).
    00192      */
    00193     pEventHook = pEventHook->pehNext;
    00194     ThreadUnlock(&tlpEventHook);
    00195
    00196     /*
    00197      * We are done with the notification.  Kill it.
    00198      *
    00199      * NOTE that DestroyNotify does not yield, which is why we can hang on
    00200      * to the pehNext field above around this call.
    00201      *
    00202      * NOTE ALSO that DestroyNotify will kill the event it references if the
    00203      * ref count goes down to zero and it was zombied earlier.
    00204      */
    00205     DestroyNotify(pNotify);
    00206
    00207     return pEventHook;
    00208 }

VOID xxxWindowEvent | ( | DWORD | event,
|  | PWND | pwnd,
|  | LONG | idObject,
|  | LONG | idChild,
|  | DWORD | dwFlags
| ) |

Definition at line 274 of file kernel/winable.c.

References CreateNotify(), DBGVERIFYEVENTHOOK, DBGVERIFYNOTIFY, dwFlags, DWORD, tagNOTIFY::dwWEFlags, tagEVENTHOOK::eventMax, tagEVENTHOOK::eventMin, tagEVENTHOOK::fDestroyed, tagEVENTHOOK::fIgnoreOwnProcess, tagEVENTHOOK::fIgnoreOwnThread, FWINABLE, GETPTI, gptiCurrent, gpWinEventHooks, tagEVENTHOOK::head, tagEVENTHOOK::hEventProcess, HMIsMarkDestroy, tagEVENTHOOK::idEventThread, NtGetTickCount(), NULL, tagEVENTHOOK::pehNext, tagTHREADINFO::ppi, _THROBJHEAD::pti, PtiCurrent, tagTHREADINFO::rpdesk, TestWF, ThreadLockPti, ThreadLockWithPti, ThreadUnlock, ThreadUnlockPti, TIDq, TIF_DISABLEHOOKS, tagTHREADINFO::TIF_flags, TIF_INCLEANUP, WEF_ASYNC, WEF_DEFERNOTIFY, WEF_USEPWNDTHREAD, WFDESTROYED, xxxFlushDeferredWindowEvents(), and xxxProcessNotifyWinEvent().

Referenced by NtUserNotifyWinEvent(), UpdateLayeredSprite(), xxxActivateThisWindow(), xxxCalcClientRect(), xxxCancelCoolSwitch(), xxxCreateCaret(), xxxCreateWindowEx(), xxxDefWindowProc(), xxxDestroyThreadInfo(), xxxDestroyWindow(), xxxDragObject(), xxxEnableSBCtlArrows(), xxxEnableWindow(), xxxEnableWndSBArrows(), xxxEndScroll(), xxxHelpLoop(), xxxMinMaximize(), xxxMNCancel(), xxxMNCloseHierarchy(), xxxMNOpenHierarchy(), xxxMNSelectItem(), xxxMNStartMenu(), xxxMNSwitchToAlternateMenu(), xxxMoveSize(), xxxMoveSwitchWndHilite(), xxxMS_TrackMove(), xxxSBTrackLoop(), xxxSBWndProc(), xxxScanSysQueue(), xxxSendChangedMsgs(), xxxSendFocusMessages(), xxxSendMenuSelect(), xxxSetConsoleCaretInfo(), xxxSetParent(), xxxSetScrollBar(), xxxShowSwitchWindow(), xxxTrackCaptionButton(), and xxxTrackPopupMenuEx().

    00280 {
    00281     PEVENTHOOK peh;
    00282     PEVENTHOOK pehNext;
    00283     PTHREADINFO ptiCurrent, ptiEvent;
    00284     DWORD   dwTime;
    00285     PPROCESSINFO ppiEvent;
    00286     DWORD idEventThread;
    00287     HANDLE hEventProcess;
    00288     PNOTIFY pNotify;
    00289     TL tlpwnd;
    00290     TL tlpti;
    00291
    00292     /*
    00293      * Do not bother with CheckLock(pwnd) - we ThreadLock it below.
    00294      */
    00295     UserAssert(FWINABLE());
    00296
    00297     /*
    00298      * This thread is in startup, and has not yet had it's pti set up
    00299      * This is pretty rare, but sometimes encountered in stress.
    00300      * Test gptiCurrent to avoid the UserAssert(gptiCurrent) in PtiCurrent()
    00301      */
    00302     if (gptiCurrent == NULL) {
    00303         RIPMSG3(RIP_WARNING, "Ignore WinEvent %lx %#p %lx... no PtiCurrent yet",
    00304                 event, pwnd, idObject);
    00305         return;
    00306     }
    00307     ptiCurrent = PtiCurrent();
    00308
    00309     /*
    00310      * Don't bother with destroyed windows
    00311      */
    00312     if (pwnd && TestWF(pwnd, WFDESTROYED)) {
    00313         RIPMSG3(RIP_WARNING,
    00314                 "Ignore WinEvent %lx %#p %lx... pwnd already destroyed",
    00315                 event, pwnd, idObject);
    00316         return;
    00317     }
    00318
    00319     /*
    00320      * Under some special circumstances we have to defer
    00321      */
    00322     if (ptiCurrent->TIF_flags & (TIF_DISABLEHOOKS | TIF_INCLEANUP)) {
    00323         dwFlags |= WEF_DEFERNOTIFY;
    00324     }
    00325
    00326     /*
    00327      * Determine process and thread issuing the event notification
    00328      */
    00329     if ((dwFlags & WEF_USEPWNDTHREAD) && pwnd) {
    00330         ptiEvent = GETPTI(pwnd);
    00331     } else {
    00332         ptiEvent = ptiCurrent;
    00333     }
    00334     idEventThread = TIDq(ptiEvent);
    00335     ppiEvent = ptiEvent->ppi;
    00336     hEventProcess = ptiEvent->pEThread->Cid.UniqueProcess;
    00337
    00338     dwTime = NtGetTickCount();
    00339
    00340     ThreadLockWithPti(ptiCurrent, pwnd, &tlpwnd);
    00341     ThreadLockPti(ptiCurrent, ptiEvent, &tlpti);
    00342
    00343     /*
    00344      * If we're not deferring the current notification process any pending
    00345      * deferred notifications before proceeding with the current notification
    00346      */
    00347     if (!(dwFlags & WEF_DEFERNOTIFY)) {
    00348         xxxFlushDeferredWindowEvents();
    00349     }
    00350
    00351     for (peh = gpWinEventHooks; peh; peh = pehNext) {
    00352         DBGVERIFYEVENTHOOK(peh);
    00353         pehNext = peh->pehNext;
    00354
    00355         //
    00356         // Is event in the right range?  And is it for this process/thread?
    00357         // Note that we skip destroyed events.  They will be freed any
    00358         // second now, it's just that yielding may have caused reentrancy.
    00359         //
    00360         // If the caller said to ignore events on his own thread, make sure
    00361         // we skip them.
    00362         //
    00363         if (!peh->fDestroyed                &&
    00364             (peh->eventMin <= event)        &&
    00365             (event <= peh->eventMax)        &&
    00366             (!peh->hEventProcess || (peh->hEventProcess == hEventProcess)) &&
    00367             (!peh->fIgnoreOwnProcess || (ppiEvent != GETPTI(peh)->ppi)) &&
    00368             (!peh->idEventThread || (peh->idEventThread == idEventThread))  &&
    00369             (!peh->fIgnoreOwnThread || (ptiEvent != GETPTI(peh))) &&
    00370             // temp fix from SP3 - best to architect events on a per-desktop
    00371             // basis, with a separate pWinEventHook list per desktop. (IanJa)
    00372             (peh->head.pti->rpdesk == ptiCurrent->rpdesk))
    00373         {
    00374             /*
    00375              * Don't create new notifications for zombie event hooks.
    00376              * When an event is destroyed, it stays as a zombie until the in-use
    00377              * count goes to zero (all it's async and deferred notifies gone)
    00378              */
    00379             if (HMIsMarkDestroy(peh)) {
    00380                 break;
    00381             }
    00382
    00383             UserAssert(peh->fDestroyed == 0);
    00384
    00385             if ((pNotify = CreateNotify(peh, event, pwnd, idObject,
    00386                     idChild, ptiEvent, dwTime)) == NULL) {
    00387                 break;
    00388             }
    00389             pNotify->dwWEFlags |= dwFlags;
    00390
    00391             /*
    00392              * If it's async, don't defer it: post it straight away.
    00393              */
    00394             if (pNotify->dwWEFlags & WEF_ASYNC) {
    00395                 pNotify->dwWEFlags &= ~WEF_DEFERNOTIFY;
    00396             }
    00397
    00398             if (pNotify->dwWEFlags & WEF_DEFERNOTIFY) {
    00399 #if DBG
    00400                 gnDeferredWinEvents++;
    00401 #endif
    00402                 DBGVERIFYNOTIFY(pNotify);
    00403             } else {
    00404                 pehNext = xxxProcessNotifyWinEvent(pNotify);
    00405             }
    00406         }
    00407     }
    00408
    00409     ThreadUnlockPti(ptiCurrent, &tlpti);
    00410     ThreadUnlock(&tlpwnd);
    00411 }

## Variable Documentation

BOOL fNotifyCacheInUse = FALSE`[static]`

| Definition at line 42 of file kernel/winable.c. Referenced by CreateNotify(), and RemoveNotify().

NOTIFY notifyCache`[static]`

| Definition at line 41 of file kernel/winable.c. Referenced by CreateNotify(), and RemoveNotify().