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().


Generated on Sat May 15 19:46:09 2004 for test by doxygen 1.3.7