|
|
/****************************** Module Header ******************************\
* Module Name: wow.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains shared code between USER32 and USER16 * No New CODE should be added to this file, unless its shared * with USER16. * * History: * 29-DEC-93 NanduriR shared user32/user16 code. \***************************************************************************/
#include "wow.h"
#ifdef _USERK_
#define CHECK_RESTRICTED() \
if (((PTHREADINFO)W32GetCurrentThread())->TIF_flags & TIF_RESTRICTED) { \ if (!ValidateHandleSecure(h)) \ pobj = NULL; \ } \
#else
#define CHECK_RESTRICTED() \
if (pci && (pci->dwTIFlags & TIF_RESTRICTED) && pobj) { \ if (!NtUserValidateHandleSecure(h)) \ pobj = NULL; \ } \
#endif
#ifdef _USERK_
#define GET_CURRENT_CLIENTINFO() \
{ \ PW32THREAD pW32Thread; \ \ pW32Thread = W32GetCurrentThread(); \ \ if (pW32Thread) { \ pci = ((PTHREADINFO)pW32Thread)->pClientInfo; \ } else { \ pci = NULL; \ } \ }
#else
#define GET_CURRENT_CLIENTINFO() \
pci = GetClientInfo();
#endif // _USERK_
/*
* We have two types of desktop validation: * */
#ifdef _USERK_
#define DESKTOPVALIDATE(pci, pobj) \
UNREFERENCED_PARAMETER(pci);
#define DESKTOPVALIDATECCX(pti, pobj) \
try { \ if (((PVOID)pobj >= pti->pClientInfo->pDeskInfo->pvDesktopBase) && \ ((PVOID)pobj < pti->pClientInfo->pDeskInfo->pvDesktopLimit)) { \ pobj = (PBYTE)pobj - pti->ulClientDelta; \ } \ } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { \ pobj = NULL; \ } \
#define SHAREDVALIDATE(pobj)
#else
#define DESKTOPVALIDATE(pci, pobj) \
if (pci->pDeskInfo && \ pobj >= pci->pDeskInfo->pvDesktopBase && \ pobj < pci->pDeskInfo->pvDesktopLimit) { \ pobj = (KERNEL_PVOID)((KERNEL_ULONG_PTR)pobj - pci->ulClientDelta); \ } else { \ pobj = (KERNEL_PVOID)NtUserCallOneParam((ULONG_PTR)h, \ SFI__MAPDESKTOPOBJECT); \ } \
#define SHAREDVALIDATE(pobj) \
pobj = REBASESHAREDPTRALWAYS(pobj);
#endif // _USERK_
/*
* Keep the general path through validation straight without jumps - that * means tunneling if()'s for this routine - this'll make validation fastest * because of instruction caching. * * In order to have the validation code in one place only, we define * the *ValidateHandleMacro macros which are to be included by the * HMValidateHanlde* routines. We don't make these into functions * because we're optimizing on time, not size. */ #define ValidateHandleMacro(pci, pobj, h, bType) \
StartValidateHandleMacro(h) \ BeginAliveValidateHandleMacro() \ BeginTypeValidateHandleMacro(pobj, bType) \ DESKTOPVALIDATE(pci, pobj) \ EndTypeValidateHandleMacro \ EndAliveValidateHandleMacro() \ EndValidateHandleMacro
#ifdef _USERK_
#define ValidateCatHandleMacro(pci, pobj, h, bType) \
StartValidateHandleMacro(h) \ BeginTypeValidateHandleMacro(pobj, bType) \ DESKTOPVALIDATE(pci, pobj) \ EndTypeValidateHandleMacro \ EndValidateHandleMacro #define ValidateCatHandleMacroCcx(pti, pobj, h, bType) \
StartValidateHandleMacro(h) \ BeginTypeValidateHandleMacro(pobj, bType) \ DESKTOPVALIDATECCX(pti, pobj) \ EndTypeValidateHandleMacro \ EndValidateHandleMacro #endif
#define ValidateSharedHandleMacro(pobj, h, bType) \
StartValidateHandleMacro(h) \ BeginAliveValidateHandleMacro() \ BeginTypeValidateHandleMacro(pobj, bType) \ SHAREDVALIDATE(pobj) \ EndTypeValidateHandleMacro \ EndAliveValidateHandleMacro() \ EndValidateHandleMacro
/*
* The handle validation routines should be optimized for time, not size, * since they get called so often. */ #pragma optimize("t", on)
/***************************************************************************\
* HMValidateHandle * * This routine validates a handle manager handle. * * 01-22-92 ScottLu Created. \***************************************************************************/
PVOID FASTCALL HMValidateHandle( HANDLE h, BYTE bType) { DWORD dwError; KERNEL_PVOID pobj = NULL; PCLIENTINFO pci;
GET_CURRENT_CLIENTINFO();
#if DBG && !defined(_USERK_)
/*
* We don't want 32 bit apps passing 16 bit handles * we should consider failing this before we get * stuck supporting it (Some VB apps do this). */ if (pci && (h != NULL) && (HMUniqFromHandle(h) == 0) && !(pci->dwTIFlags & TIF_16BIT)) { RIPMSG3(RIP_WARNING, "HMValidateHandle: 32bit process [%d] using 16 bit handle [%#p] bType:%#lx", HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), h, (DWORD)bType); } #endif
/*
* Object can't be located in shared memory. */ UserAssert(bType != TYPE_MONITOR);
/*
* Validation macro. Falls through if the handle is invalid. */ ValidateHandleMacro(pci, pobj, h, bType);
/*
* check for secure process */ CHECK_RESTRICTED();
if (pobj != NULL) { return KPVOID_TO_PVOID(pobj); }
switch (bType) {
case TYPE_WINDOW: dwError = ERROR_INVALID_WINDOW_HANDLE; break;
case TYPE_MENU: dwError = ERROR_INVALID_MENU_HANDLE; break;
case TYPE_CURSOR: dwError = ERROR_INVALID_CURSOR_HANDLE; break;
case TYPE_ACCELTABLE: dwError = ERROR_INVALID_ACCEL_HANDLE; break;
case TYPE_HOOK: dwError = ERROR_INVALID_HOOK_HANDLE; break;
case TYPE_SETWINDOWPOS: dwError = ERROR_INVALID_DWP_HANDLE; break;
default: dwError = ERROR_INVALID_HANDLE; break; }
RIPERR2(dwError, RIP_WARNING, "HMValidateHandle: Invalid:%#p Type:%#lx", h, (DWORD)bType);
/*
* If we get here, it's an error. */ return NULL; }
/***************************************************************************\
* HMValidateHandleNoSecure * * This routine validates a handle manager handle. * * 01-22-92 ScottLu Created. \***************************************************************************/ PVOID FASTCALL HMValidateHandleNoSecure( HANDLE h, BYTE bType) { KERNEL_PVOID pobj = NULL; PCLIENTINFO pci;
GET_CURRENT_CLIENTINFO();
#if !defined(_USERK_)
/*
* We don't want 32 bit apps passing 16 bit handles * we should consider failing this before we get * stuck supporting it (Some VB apps do this). */ if (pci && (h != NULL) && (HMUniqFromHandle(h) == 0) && !(pci->dwTIFlags & TIF_16BIT)) { RIPMSG3(RIP_WARNING, "HMValidateHandle: 32bit process [%d] using 16 bit handle [%#p] bType:%#lx", HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), h, (DWORD)bType); } #endif
/*
* Object can't be located in shared memory. */ UserAssert(bType != TYPE_MONITOR);
/*
* Validation macro. */ ValidateHandleMacro(pci, pobj, h, bType);
return KPVOID_TO_PVOID(pobj); }
#if defined(_USERK_)
PVOID FASTCALL HMValidateCatHandleNoSecure( HANDLE h, BYTE bType) { PVOID pobj = NULL; PCLIENTINFO pci;
GET_CURRENT_CLIENTINFO();
/*
* Object can't be located in shared memory. */ UserAssert(bType != TYPE_MONITOR);
/*
* Validation macro. */ ValidateCatHandleMacro(pci, pobj, h, bType);
return pobj; } PVOID FASTCALL HMValidateCatHandleNoSecureCCX( HANDLE h, BYTE bType, PTHREADINFO pti) { PVOID pobj = NULL;
/*
* Object can't be located in shared memory. */ UserAssert(bType != TYPE_MONITOR);
/*
* Validation macro. */ ValidateCatHandleMacroCcx(pti, pobj, h, bType);
return pobj; }
PVOID FASTCALL HMValidateCatHandleNoRip( HANDLE h, BYTE bType) { PVOID pobj = NULL; PCLIENTINFO pci;
/*
* This is the fastest way way to do validation, because * unlike HMValidateHandle, this function doesn't set the * last error. * * Validation macro. Falls through if the handle is invalid. */
GET_CURRENT_CLIENTINFO();
/*
* Object can't be located in shared memory. */ UserAssert(bType != TYPE_MONITOR);
ValidateCatHandleMacro(pci, pobj, h, bType);
/*
* check for secure process */ CHECK_RESTRICTED();
return pobj; } #endif
PVOID FASTCALL HMValidateHandleNoRip( HANDLE h, BYTE bType) { KERNEL_PVOID pobj = NULL; PCLIENTINFO pci;
/*
* This is the fastest way way to do validation, because * unlike HMValidateHandle, this function doesn't set the * last error. * * Validation macro. Falls through if the handle is invalid. */
GET_CURRENT_CLIENTINFO();
/*
* Object can't be located in shared memory. */ UserAssert(bType != TYPE_MONITOR);
ValidateHandleMacro(pci, pobj, h, bType);
/*
* check for secure process */ CHECK_RESTRICTED();
return KPVOID_TO_PVOID(pobj); }
#if DBG && !defined(_USERK_)
/*
* HMValidateHandleNoDesktop is a debug-client-side only function * used to verify a given handle without calling DESKTOPVALIDATE. * If the handle is valid, it returns the object's kernel pointer * which can be used as a BOOL value only. * Use this function to verify handles for which corresponding phe->phead * is a pool allocation (as opposed to desktop-heap allocations). */ KERNEL_PVOID FASTCALL HMValidateHandleNoDesktop( HANDLE h, BYTE bType) { KERNEL_PVOID pobj = NULL;
StartValidateHandleMacro(h) BeginTypeValidateHandleMacro(pobj, bType) EndTypeValidateHandleMacro EndValidateHandleMacro return pobj; } #endif
/***************************************************************************\
* HMValidateSharedHandle * * This routine validates a handle manager handle allocated in * shared memory. * * History: * 02-Apr-1997 adams Created. \***************************************************************************/
PVOID FASTCALL HMValidateSharedHandle( HANDLE h, BYTE bType) { DWORD dwError; KERNEL_PVOID pobj = NULL;
#if DBG && !defined(_USERK_)
/*
* We don't want 32 bit apps passing 16 bit handles * we should consider failing this before we get * stuck supporting it (Some VB apps do this). */ if ((h != NULL) && (HMUniqFromHandle(h) == 0) && !(GetClientInfo()->dwTIFlags & TIF_16BIT)) { RIPMSG3(RIP_WARNING, "HMValidateHandle: 32bit process [%d] using 16 bit handle [%#p] bType:%#lx", HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), h, (DWORD)bType); } #endif
/*
* Validation macro. Falls through if the handle is invalid. */ ValidateSharedHandleMacro(pobj, h, bType);
if (pobj != NULL) return KPVOID_TO_PVOID(pobj);
switch (bType) { case TYPE_MONITOR: dwError = ERROR_INVALID_MONITOR_HANDLE; break;
default: dwError = ERROR_INVALID_HANDLE; break; }
RIPERR2(dwError, RIP_WARNING, "HMValidateSharedHandle: Invalid:%#p Type:%#lx", h, (DWORD)bType);
/*
* If we get here, it's an error. */ return NULL; }
/*
* Switch back to default optimization. */ #pragma optimize("", on)
/***************************************************************************\
* MNLookUpItem * * Return a pointer to the menu item specified by wCmd and wFlags * * History: * 10-11-90 JimA Translated from ASM * 01-07-93 FritzS Ported from Chicago \***************************************************************************/
PITEM MNLookUpItem( PMENU pMenu, UINT wCmd, BOOL fByPosition, PMENU *ppMenuItemIsOn) { PITEM pItem; PITEM pItemRet = NULL; PITEM pItemMaybe; PMENU pMenuMaybe = NULL; int i;
if (ppMenuItemIsOn != NULL) *ppMenuItemIsOn = NULL;
if (pMenu == NULL || !pMenu->cItems || wCmd == MFMWFP_NOITEM) { // RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "MNLookUpItem: invalid item");
return NULL; }
/*
* dwFlags determines how we do the search */ if (fByPosition) { if (wCmd < (UINT)pMenu->cItems) { pItemRet = &((PITEM)REBASEALWAYS(pMenu, rgItems))[wCmd]; if (ppMenuItemIsOn != NULL) *ppMenuItemIsOn = pMenu; return (pItemRet); } else return NULL; } /*
* Walk down the menu and try to find an item with an ID of wCmd. * The search procedes from the end of the menu (as was done in * assembler). */
/* this is the Chicago code, which walks from the front of the menu -- Fritz */
// for (pItem = &pMenu->rgItems[i - 1]; pItemRet == NULL && i--; --pItem) {
for (i = 0, pItem = REBASEALWAYS(pMenu, rgItems); i < (int)pMenu->cItems; i++, pItem++) {
/*
* If the item is a popup, recurse down the tree */ if (pItem->spSubMenu != NULL) { //
// COMPAT:
// Allow apps to pass in menu handle as ID in menu APIs. We
// remember that this popup had a menu handle with the same ID
// value. This is a 2nd choice though. We still want to see
// if there's some actual command that has this ID value first.
//
if (pItem->wID == wCmd) { pMenuMaybe = pMenu; pItemMaybe = pItem; }
pItemRet = MNLookUpItem((PMENU)REBASEPTR(pMenu, pItem->spSubMenu), wCmd, FALSE, ppMenuItemIsOn); if (pItemRet != NULL) return pItemRet; } else if (pItem->wID == wCmd) {
/*
* Found the item, now save things for later */ if (ppMenuItemIsOn != NULL) *ppMenuItemIsOn = pMenu; return pItem; } }
if (pMenuMaybe) { // no non popup menu match found -- use the 2nd choice popup menu
// match
if (ppMenuItemIsOn != NULL) *ppMenuItemIsOn = pMenuMaybe; return(pItemMaybe); }
return(NULL); }
/***************************************************************************\
* GetMenuState * * Either returns the state of a menu item or the state and item count * of a popup. * * History: * 10-11-90 JimA Translated from ASM \***************************************************************************/
UINT _GetMenuState( PMENU pMenu, UINT wId, UINT dwFlags) { PITEM pItem; DWORD fFlags;
/*
* If the item does not exist, leave */ if ((pItem = MNLookUpItem(pMenu, wId, (BOOL) (dwFlags & MF_BYPOSITION), NULL)) == NULL) return (UINT)-1;
fFlags = pItem->fState | pItem->fType;
#ifndef _USERK_
/*
* Add old MFT_BITMAP flag to keep old apps happy */ if ((pItem->hbmp != NULL) && (pItem->lpstr == NULL)) { fFlags |= MFT_BITMAP; } #endif
if (pItem->spSubMenu != NULL) { /*
* If the item is a popup, return item count in high byte and * popup flags in low byte */
fFlags = ((fFlags | MF_POPUP) & 0x00FF) + (((PMENU)REBASEPTR(pMenu, pItem->spSubMenu))->cItems << 8); }
return fFlags; }
/***************************************************************************\
* GetPrevPwnd * * * * History: * 11-05-90 darrinm Ported from Win 3.0 sources. \***************************************************************************/
PWND GetPrevPwnd( PWND pwndList, PWND pwndFind) { PWND pwndFound, pwndNext;
if (pwndList == NULL) return NULL;
if (pwndList->spwndParent == NULL) return NULL;
pwndNext = REBASEPWND(pwndList, spwndParent); pwndNext = REBASEPWND(pwndNext, spwndChild); pwndFound = NULL;
while (pwndNext != NULL) { if (pwndNext == pwndFind) break; pwndFound = pwndNext; pwndNext = REBASEPWND(pwndNext, spwndNext); }
return (pwndNext == pwndFind) ? pwndFound : NULL; }
/***************************************************************************\
* _GetWindow (API) * * * History: * 11-05-90 darrinm Ported from Win 3.0 sources. * 02-19-91 JimA Added enum access check * 05-04-02 DarrinM Removed enum access check and moved to USERRTL.DLL \***************************************************************************/
PWND _GetWindow( PWND pwnd, UINT cmd) { PWND pwndT; BOOL fRebase = FALSE;
/*
* If this is a desktop window, return NULL for sibling or * parent information. */ if (GETFNID(pwnd) == FNID_DESKTOP) { switch (cmd) { case GW_CHILD: break;
default: return NULL; break; } }
/*
* Rebase the returned window at the end of the routine * to avoid multiple test for pwndT == NULL. */ pwndT = NULL; switch (cmd) { case GW_HWNDNEXT: pwndT = pwnd->spwndNext; fRebase = TRUE; break;
case GW_HWNDFIRST: if (pwnd->spwndParent) { pwndT = REBASEPWND(pwnd, spwndParent); pwndT = REBASEPWND(pwndT, spwndChild); if (GetAppCompatFlags(NULL) & GACF_IGNORETOPMOST) { while (pwndT != NULL) { if (!TestWF(pwndT, WEFTOPMOST)) break; pwndT = REBASEPWND(pwndT, spwndNext); } } } break;
case GW_HWNDLAST: pwndT = GetPrevPwnd(pwnd, NULL); break;
case GW_HWNDPREV: pwndT = GetPrevPwnd(pwnd, pwnd); break;
case GW_OWNER: pwndT = pwnd->spwndOwner; fRebase = TRUE; break;
case GW_CHILD: pwndT = pwnd->spwndChild; fRebase = TRUE; break;
#if !defined(_USERK_)
case GW_ENABLEDPOPUP: pwndT = (PWND)NtUserCallHwnd(PtoHq(pwnd), SFI_DWP_GETENABLEDPOPUP); fRebase = TRUE; break; #endif
default: RIPERR0(ERROR_INVALID_GW_COMMAND, RIP_VERBOSE, ""); return NULL; }
if (pwndT != NULL && fRebase) pwndT = REBASEPTR(pwnd, pwndT);
return pwndT; }
/***************************************************************************\
* _GetParent (API) * * * * History: * 11-12-90 darrinm Ported. * 02-19-91 JimA Added enum access check * 05-04-92 DarrinM Removed enum access check and moved to USERRTL.DLL \***************************************************************************/
PWND _GetParent( PWND pwnd) { /*
* For 1.03 compatibility reasons, we should return NULL * for top level "tiled" windows and owner for other popups. * pwndOwner is set to NULL in xxxCreateWindow for top level * "tiled" windows. */ if (!(TestwndTiled(pwnd))) { if (TestwndChild(pwnd)) pwnd = REBASEPWND(pwnd, spwndParent); else pwnd = REBASEPWND(pwnd, spwndOwner); return pwnd; }
/*
* The window was not a child window; they may have been just testing * if it was */ return NULL; }
/***************************************************************************\
* GetSubMenu * * Return the handle of a popup menu. * * History: * 10-11-90 JimA Translated from ASM \***************************************************************************/
PMENU _GetSubMenu( PMENU pMenu, int nPos) { PITEM pItem; PMENU pPopup = NULL;
/*
* Make sure nPos refers to a valid popup */ if ((UINT)nPos < (UINT)((PMENU)pMenu)->cItems) { pItem = &((PITEM)REBASEALWAYS(pMenu, rgItems))[nPos]; if (pItem->spSubMenu != NULL) pPopup = (PMENU)REBASEPTR(pMenu, pItem->spSubMenu);
}
return pPopup; }
/***************************************************************************\
* _IsChild (API) * * * * History: * 11-07-90 darrinm Translated from Win 3.0 ASM code. \***************************************************************************/
BOOL _IsChild( PWND pwndParent, PWND pwnd) { /*
* Don't need a test to get out of the loop because the * desktop is not a child. */ while (pwnd != NULL) { if (!TestwndChild(pwnd)) return FALSE;
pwnd = REBASEPWND(pwnd, spwndParent); if (pwndParent == pwnd) return TRUE; } return FALSE; }
/***************************************************************************\
* _IsWindowVisible (API) * * IsWindowVisible returns the TRUEVIS state of a window, rather than just * the state of its WFVISIBLE flag. According to this routine, a window is * considered visible when it and all the windows on its parent chain are * visible (WFVISIBLE flag set). A special case hack was put in that causes * any icon window being dragged to be considered as visible. * * History: * 11-12-90 darrinm Ported. \***************************************************************************/
BOOL _IsWindowVisible( PWND pwnd) { /*
* Check if this is the iconic window being moved around with a mouse * If so, return a TRUE, though, strictly speaking, it is hidden. * This helps the Tracer guys from going crazy! * Fix for Bug #57 -- SANKAR -- 08-08-89 -- */ if (pwnd == NULL) return TRUE;
for (;;) { if (!TestWF(pwnd, WFVISIBLE)) return FALSE; if (GETFNID(pwnd) == FNID_DESKTOP) break; pwnd = REBASEPWND(pwnd, spwndParent); }
return TRUE; }
/***************************************************************************\
* _ClientToScreen (API) * * Map a point from client to screen-relative coordinates. * * History: * 11-12-90 darrinm Translated from Win 3.0 ASM code. \***************************************************************************/
VOID _ClientToScreen( PWND pwnd, PPOINT ppt) { /*
* Client and screen coordinates are the same for the * desktop window. */ if (GETFNID(pwnd) != FNID_DESKTOP) { if (TestWF(pwnd, WEFLAYOUTRTL)) { ppt->x = pwnd->rcClient.right - ppt->x; } else { ppt->x += pwnd->rcClient.left; } ppt->y += pwnd->rcClient.top; } }
/***************************************************************************\
* _GetClientRect (API) * * * * History: * 26-Oct-1990 DarrinM Implemented. \***************************************************************************/
VOID _GetClientRect( PWND pwnd, LPRECT prc) { /*
* If this is a 3.1 app, and it's minimized, then we need to return * a rectangle other than the real-client-rect. This is necessary since * there is no client-rect-size in Win4.0. Apps such as PackRat 1.0 * will GPF if returned a empty-rect. */ if (TestWF(pwnd, WFMINIMIZED) && !TestWF(pwnd, WFWIN40COMPAT)) { prc->left = 0; prc->top = 0; prc->right = SYSMETRTL(CXMINIMIZED); prc->bottom = SYSMETRTL(CYMINIMIZED);
} else {
if (GETFNID(pwnd) != FNID_DESKTOP) { *prc = pwnd->rcClient; OffsetRect(prc, -pwnd->rcClient.left, -pwnd->rcClient.top); } else { /*
* For compatibility, return the rect of the primary * monitor for the desktop window. */ prc->left = prc->top = 0; prc->right = SYSMETRTL(CXSCREEN); prc->bottom = SYSMETRTL(CYSCREEN); } } }
/***************************************************************************\
* _GetWindowRect (API) * * * * History: * 26-Oct-1990 DarrinM Implemented. \***************************************************************************/
VOID _GetWindowRect( PWND pwnd, LPRECT prc) {
if (GETFNID(pwnd) != FNID_DESKTOP) { *prc = pwnd->rcWindow; } else { /*
* For compatibility, return the rect of the primary * monitor for the desktop window. */ prc->left = 0; prc->top = 0; prc->right = SYSMETRTL(CXSCREEN); prc->bottom = SYSMETRTL(CYSCREEN); } }
/***************************************************************************\
* _ScreenToClient (API) * * Map a point from screen to client-relative coordinates. * * History: * 11-12-90 darrinm Translated from Win 3.0 ASM code. \***************************************************************************/
VOID _ScreenToClient( PWND pwnd, PPOINT ppt) { /*
* Client and screen coordinates are the same for the * desktop window. */ if (GETFNID(pwnd) != FNID_DESKTOP) { if (TestWF(pwnd, WEFLAYOUTRTL)) { ppt->x = pwnd->rcClient.right - ppt->x; } else { ppt->x -= pwnd->rcClient.left; } ppt->y -= pwnd->rcClient.top; } } /***************************************************************************\
* PhkNextValid * * This helper routine walk the phkNext chain looking for the next valid * hook (i.e., not marked as destroyed). If the end of the local (or * thread specific) hook chain is reached, then it jumps to the global * (or desktop) chain. * * Once a hook is destroyed, we don't want anymore activity on it; however, * if the hook is locked at destroy time (= someone is calling it), then * we keep it in the list so CallNextHook will work properly * * History: * 03/24/96 GerardoB Moved to rtl and added *Valid stuff. * 01-30-91 DavidPe Created. \***************************************************************************/ PHOOK PhkNextValid(PHOOK phk) {
#if DBG
int iHook = phk->iHook; #ifdef _USERK_
CheckCritInShared(); #endif
#endif
do { /*
* If this hook is marked as destroyed, it must be either * locked or we should be in the process of destroying it */ UserAssert(!(phk->flags & HF_DESTROYED) || (((PHEAD)phk)->cLockObj != 0) || (phk->flags & HF_INCHECKWHF)); /*
* Get the next hook */ if (phk->phkNext != NULL) { phk = REBASEALWAYS(phk, phkNext); } else if (!(phk->flags & HF_GLOBAL)) { #ifdef _USERK_
phk = PtiCurrent()->pDeskInfo->aphkStart[phk->iHook + 1]; #else
PCLIENTINFO pci = GetClientInfo(); phk = pci->pDeskInfo->aphkStart[phk->iHook + 1]; /*
* If it found a pointer, rebase it. */ if (phk != NULL) { (KPBYTE)phk -= pci->ulClientDelta; } #endif
UserAssert((phk == NULL) || (phk->flags & HF_GLOBAL)); } else { return NULL; } /*
* If destroyed, keep looking. */ } while ((phk != NULL) && (phk->flags & HF_DESTROYED));
#ifdef _USERK_
DbgValidateHooks(phk, iHook); #endif
return phk; }
|