Windows2000/private/ntos/w32/ntuser/rtl/wow.c
2020-09-30 17:12:32 +02:00

1081 lines
26 KiB
C

/****************************** 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(pci, pobj) \
if ( ((PVOID)pobj >= pci->pDeskInfo->pvDesktopBase) && \
((PVOID)pobj < pci->pDeskInfo->pvDesktopLimit)) { \
pobj = (PBYTE)pobj - pci->ulClientDelta; \
} \
#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(pci, pobj, h, bType) \
StartValidateHandleMacro(h) \
BeginTypeValidateHandleMacro(pobj, bType) \
DESKTOPVALIDATECCX(pci, 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 != 0 && !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 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 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,
PCLIENTINFO ccxPci)
{
PVOID pobj = NULL;
/*
* Object can't be located in shared memory.
*/
UserAssert(bType != TYPE_MONITOR);
/*
* Validation macro.
*/
ValidateCatHandleMacroCcx(ccxPci, 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 pobj;
}
#if DBG != 0 && !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 != 0 && !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 pobj;
switch (bType) {
case TYPE_MONITOR:
dwError = ERROR_INVALID_MONITOR_HANDLE;
break;
default:
UserAssertMsg0(0, "Logic error in HMValidateSharedHandle");
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 (PVOID)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) {
#ifdef USE_MIRRORING
if (TestWF(pwnd, WEFLAYOUTRTL)) {
ppt->x = pwnd->rcClient.right - ppt->x;
} else
#endif
{
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) {
#ifdef USE_MIRRORING
if (TestWF(pwnd, WEFLAYOUTRTL)) {
ppt->x = pwnd->rcClient.right - ppt->x;
} else
#endif
{
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;
}