/****************************** 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 "precomp.h" #pragma hdrstop /***************************************************************************\ * ValidateHwnd * * Verify that the handle is valid. If the handle is invalid or access * cannot be granted fail. * * History: * 03-18-92 DarrinM Created from pieces of misc server-side funcs. \***************************************************************************/ PWND FASTCALL ValidateHwnd( HWND hwnd) { PCLIENTINFO pci = GetClientInfo(); /* * Attempt fast window validation. */ if (hwnd != NULL && hwnd == pci->CallbackWnd.hwnd) { return pci->CallbackWnd.pwnd; } /* * Validate that the handle is of the proper type. */ return HMValidateHandle(hwnd, TYPE_WINDOW); } PWND FASTCALL ValidateHwndNoRip( HWND hwnd) { PCLIENTINFO pci = GetClientInfo(); /* * Attempt fast window validation. */ if (hwnd != NULL && hwnd == pci->CallbackWnd.hwnd) { return pci->CallbackWnd.pwnd; } /* * Validate the handle is of the proper type. */ return HMValidateHandleNoRip(hwnd, TYPE_WINDOW); } FUNCLOG3(LOG_GENERAL, int, WINAPI, GetClassNameA, HWND, hwnd, LPSTR, lpClassName, int, nMaxCount) int WINAPI GetClassNameA( HWND hwnd, LPSTR lpClassName, int nMaxCount) { PCLS pcls; LPSTR lpszClassNameSrc; PWND pwnd; int cchSrc; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) return FALSE; try { if (nMaxCount != 0) { pcls = (PCLS)REBASEALWAYS(pwnd, pcls); lpszClassNameSrc = REBASEPTR(pwnd, pcls->lpszAnsiClassName); cchSrc = lstrlenA(lpszClassNameSrc); nMaxCount = min(cchSrc, nMaxCount - 1); RtlCopyMemory(lpClassName, lpszClassNameSrc, nMaxCount); lpClassName[nMaxCount] = '\0'; } } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { nMaxCount = 0; } return nMaxCount; } /***************************************************************************\ * _GetDesktopWindow (API) * * History: * 11-07-90 darrinm Implemented. \***************************************************************************/ PWND _GetDesktopWindow( VOID) { PCLIENTINFO pci; ConnectIfNecessary(0); pci = GetClientInfo(); return (PWND)((KERNEL_ULONG_PTR)pci->pDeskInfo->spwnd - pci->ulClientDelta); } HWND GetDesktopWindow( VOID) { PWND pwnd = _GetDesktopWindow(); PCLIENTINFO pci = GetClientInfo(); /* * Validate the parent window's handle if a restricted process. */ if (pci && (pci->dwTIFlags & TIF_RESTRICTED)) { if (ValidateHwnd(HW(pwnd)) == NULL) { return NULL; } } return HW(pwnd); } PWND _GetDlgItem( PWND pwnd, int id) { if (pwnd != NULL) { pwnd = REBASEPWND(pwnd, spwndChild); while (pwnd != NULL) { if (PtrToLong(pwnd->spmenu) == id) { break; } pwnd = REBASEPWND(pwnd, spwndNext); } } return pwnd; } FUNCLOG2(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, GetDlgItem, HWND, hwnd, int, id) HWND GetDlgItem( HWND hwnd, int id) { PWND pwnd; HWND hwndRet; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return NULL; } pwnd = _GetDlgItem(pwnd, id); hwndRet = HW(pwnd); if (hwndRet == (HWND)0) { RIPERR0(ERROR_CONTROL_ID_NOT_FOUND, RIP_VERBOSE, ""); } return hwndRet; } FUNCLOG1(LOG_GENERAL, HMENU, DUMMYCALLINGTYPE, GetMenu, HWND, hwnd) HMENU GetMenu( HWND hwnd) { PWND pwnd; PMENU pmenu; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return 0; } /* * Some ill-behaved apps use GetMenu to get the child id, so * only map to the handle for non-child windows. */ if (!TestwndChild(pwnd)) { pmenu = REBASE(pwnd, spmenu); return (HMENU)PtoH(pmenu); } else { return (HMENU)KPVOID_TO_PVOID(pwnd->spmenu); } } /***************************************************************************\ * GetMenuItemCount * * Returns a count of the number of items in the menu. Returns -1 if * invalid menu. * * History: \***************************************************************************/ FUNCLOG1(LOG_GENERAL, int, DUMMYCALLINGTYPE, GetMenuItemCount, HMENU, hMenu) int GetMenuItemCount( HMENU hMenu) { PMENU pMenu; pMenu = VALIDATEHMENU(hMenu); if (pMenu == NULL) { return -1; } return pMenu->cItems; } /***************************************************************************\ * GetMenuItemID * * Return the ID of a menu item at the specified position. * * History: \***************************************************************************/ FUNCLOG2(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, GetMenuItemID, HMENU, hMenu, int, nPos) UINT GetMenuItemID( HMENU hMenu, int nPos) { PMENU pMenu; PITEM pItem; pMenu = VALIDATEHMENU(hMenu); if (pMenu == NULL) { return (UINT)-1; } /* * If the position is valid and the item is not a popup, get the ID * Don't allow negative indexes, because that'll cause an access violation. */ if (nPos < (int)pMenu->cItems && nPos >= 0) { pItem = &((PITEM)REBASEALWAYS(pMenu, rgItems))[nPos]; if (pItem->spSubMenu == NULL) { return pItem->wID; } } return (UINT)-1; } FUNCLOG3(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, GetMenuState, HMENU, hMenu, UINT, uId, UINT, uFlags) UINT GetMenuState( HMENU hMenu, UINT uId, UINT uFlags) { PMENU pMenu; pMenu = VALIDATEHMENU(hMenu); if (pMenu == NULL || (uFlags & ~MF_VALID) != 0) { return (UINT)-1; } return _GetMenuState(pMenu, uId, uFlags); } FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsWindow, HWND, hwnd) BOOL IsWindow( HWND hwnd) { PWND pwnd; /* * Validate the handle is of type window */ pwnd = ValidateHwndNoRip(hwnd); /* * And validate this handle is valid for this desktop by trying to read it */ if (pwnd != NULL) { try { if (pwnd->fnid & FNID_DELETED_BIT) { pwnd = 0; } } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { RIPMSG1(RIP_WARNING, "IsWindow: Window %#p not of this desktop", pwnd); pwnd = 0; } } return !!pwnd; } FUNCLOG2(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, GetWindow, HWND, hwnd, UINT, wCmd) HWND GetWindow( HWND hwnd, UINT wCmd) { PWND pwnd; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return NULL; } pwnd = _GetWindow(pwnd, wCmd); return HW(pwnd); } FUNCLOG1(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, GetParent, HWND, hwnd) HWND GetParent( HWND hwnd) { PWND pwnd; PCLIENTINFO pci; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return NULL; } try { pwnd = _GetParent(pwnd); hwnd = HW(pwnd); } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { hwnd = NULL; } pci = GetClientInfo(); /* * validate the parent window's handle if a restricted process */ if (pci && (pci->dwTIFlags & TIF_RESTRICTED)) { if (ValidateHwnd(hwnd) == NULL) { return NULL; } } return hwnd; } FUNCLOG2(LOG_GENERAL, HMENU, DUMMYCALLINGTYPE, GetSubMenu, HMENU, hMenu, int, nPos) HMENU GetSubMenu( HMENU hMenu, int nPos) { PMENU pMenu; pMenu = VALIDATEHMENU(hMenu); if (pMenu == NULL) { return 0; } pMenu = _GetSubMenu(pMenu, nPos); return (HMENU)PtoH(pMenu); } FUNCLOG1(LOG_GENERAL, DWORD, DUMMYCALLINGTYPE, GetSysColor, int, nIndex) DWORD GetSysColor( int nIndex) { /* * Return 0 if the index is out of range. */ if (nIndex < 0 || nIndex >= COLOR_MAX) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid parameter \"nIndex\" (%ld) to GetSysColor", nIndex); return 0; } return gpsi->argbSystem[nIndex]; } FUNCLOG1(LOG_GENERAL, int, DUMMYCALLINGTYPE, GetSystemMetrics, int, index) int GetSystemMetrics( int index) { int ret; BEGIN_USERAPIHOOK() ret = guah.pfnGetSystemMetrics(index); END_USERAPIHOOK() return ret; } int RealGetSystemMetrics( int index) { ConnectIfNecessary(0); /* * First check for values that aren't in the aiSysMet array. */ switch (index) { case SM_REMOTESESSION: return ISREMOTESESSION(); } /* * If it's in the BOOLEAN system metric range then do our magic. */ if (index >= SM_STARTBOOLRANGE && index <= SM_ENDBOOLRANGE) { return SYSMETBOOL2(index); } if (index < 0 || index >= SM_CMETRICS) { return 0; } switch (index) { case SM_DBCSENABLED: #ifdef FE_SB return TEST_SRVIF(SRVIF_DBCS); #else return FALSE; #endif case SM_IMMENABLED: #ifdef FE_IME return TEST_SRVIF(SRVIF_IME); #else return FALSE; #endif case SM_MIDEASTENABLED: return TEST_SRVIF(SRVIF_MIDEAST); } if (!Is400Compat(GetClientInfo()->dwExpWinVer)) { /* * SCROLL BAR * before 4.0, the scroll bars and the border overlapped by a pixel. Many apps * rely on this overlap when they compute dimensions. Now, in 4.0, this pixel * overlap is no longer there. So for old apps, we lie and pretend the overlap * is there by making the scroll bar widths one bigger. * * DLGFRAME * In Win3.1, SM_CXDLGFRAME & SM_CYDLGFRAME were border space MINUS 1 * In Win4.0, they are border space * * CAPTION * In Win3.1, SM_CYCAPTION was the caption height PLUS 1 * In Win4.0, SM_CYCAPTION is the caption height * * MENU * In Win3.1, SM_CYMENU was the menu height MINUS 1 * In Win4.0, SM_CYMENU is the menu height */ switch (index) { case SM_CXDLGFRAME: case SM_CYDLGFRAME: case SM_CYMENU: case SM_CYFULLSCREEN: return gpsi->aiSysMet[index] - 1; case SM_CYCAPTION: case SM_CXVSCROLL: case SM_CYHSCROLL: return gpsi->aiSysMet[index] + 1; } } return gpsi->aiSysMet[index]; } /***************************************************************************\ * GetTopWindow (API) * * This poorly named API should really be called 'GetFirstChild', which is * what it does. * * History: * 11-12-90 darrinm Ported. * 02-19-91 JimA Added enum access check * 05-04-02 DarrinM Removed enum access check and moved to USERRTL.DLL \***************************************************************************/ FUNCLOG1(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, GetTopWindow, HWND, hwnd) HWND GetTopWindow( HWND hwnd) { PWND pwnd; /* * Allow a NULL hwnd to go through here. */ if (hwnd == NULL) { pwnd = _GetDesktopWindow(); } else { pwnd = ValidateHwnd(hwnd); } if (pwnd == NULL) { return NULL; } pwnd = REBASEPWND(pwnd, spwndChild); return HW(pwnd); } FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsChild, HWND, hwndParent, HWND, hwnd) BOOL IsChild( HWND hwndParent, HWND hwnd) { PWND pwnd, pwndParent; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return FALSE; } pwndParent = ValidateHwnd(hwndParent); if (pwndParent == NULL) { return FALSE; } return _IsChild(pwndParent, pwnd); } FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsIconic, HWND, hwnd) BOOL IsIconic( HWND hwnd) { PWND pwnd; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return FALSE; } return _IsIconic(pwnd); } FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsWindowEnabled, HWND, hwnd) BOOL IsWindowEnabled( HWND hwnd) { PWND pwnd; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return FALSE; } return _IsWindowEnabled(pwnd); } FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsWindowVisible, HWND, hwnd) BOOL IsWindowVisible( HWND hwnd) { PWND pwnd; BOOL bRet; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { bRet = FALSE; } else { try { bRet = _IsWindowVisible(pwnd); } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { bRet = FALSE; } } return bRet; } FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, IsZoomed, HWND, hwnd) BOOL IsZoomed( HWND hwnd) { PWND pwnd; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return FALSE; } return _IsZoomed(pwnd); } FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, ClientToScreen, HWND, hwnd, LPPOINT, ppoint) BOOL ClientToScreen( HWND hwnd, LPPOINT ppoint) { PWND pwnd; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return FALSE; } _ClientToScreen(pwnd, ppoint); return TRUE; } FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, GetClientRect, HWND, hwnd, LPRECT, prect) BOOL GetClientRect( HWND hwnd, LPRECT prect) { PWND pwnd; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return FALSE; } _GetClientRect(pwnd, prect); return TRUE; } FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, GetCursorPos, LPPOINT, lpPoint) BOOL GetCursorPos( LPPOINT lpPoint) { return (BOOL)NtUserCallOneParam((ULONG_PTR)lpPoint, SFI_XXXGETCURSORPOS); } FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, GetWindowRect, HWND, hwnd, LPRECT, prect) BOOL GetWindowRect( HWND hwnd, LPRECT prect) { PWND pwnd; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return FALSE; } _GetWindowRect(pwnd, prect); return TRUE; } FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, ScreenToClient, HWND, hwnd, LPPOINT, ppoint) BOOL ScreenToClient( HWND hwnd, LPPOINT ppoint) { PWND pwnd; pwnd = ValidateHwnd(hwnd); if (pwnd == NULL) { return FALSE; } _ScreenToClient(pwnd, ppoint); return TRUE; } FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, EnableMenuItem, HMENU, hMenu, UINT, uIDEnableItem, UINT, uEnable) BOOL EnableMenuItem( HMENU hMenu, UINT uIDEnableItem, UINT uEnable) { PMENU pMenu; PITEM pItem; pMenu = VALIDATEHMENU(hMenu); if (pMenu == NULL) { return (BOOL)-1; } /* * Get a pointer the the menu item. */ if ((pItem = MNLookUpItem(pMenu, uIDEnableItem, (BOOL) (uEnable & MF_BYPOSITION), NULL)) == NULL) { return (DWORD)-1; } /* * If the item is already in the state we're * trying to set, just return. */ if ((pItem->fState & MFS_GRAYED) == (uEnable & MFS_GRAYED)) { return pItem->fState & MFS_GRAYED; } return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable); } /***************************************************************************\ * CallNextHookEx * * This routine is called to call the next hook in the hook chain. * * 05-09-91 ScottLu Created. \***************************************************************************/ FUNCLOG4(LOG_GENERAL, LRESULT, WINAPI, CallNextHookEx, HHOOK, hhk, int, nCode, WPARAM, wParam, LPARAM, lParam) LRESULT WINAPI CallNextHookEx( HHOOK hhk, int nCode, WPARAM wParam, LPARAM lParam) { LRESULT nRet; BOOL bAnsi; DWORD dwHookCurrent; PCLIENTINFO pci; ULONG_PTR dwHookData; ULONG_PTR dwFlags; UNREFERENCED_PARAMETER(hhk); ConnectIfNecessary(0); pci = GetClientInfo(); dwHookCurrent = pci->dwHookCurrent; bAnsi = LOWORD(dwHookCurrent); /* * If this is the last hook in the hook chain then return 0; we're done. */ if (PhkNextValid((PHOOK)((KERNEL_ULONG_PTR)pci->phkCurrent - pci->ulClientDelta)) == NULL) { return 0; } switch ((INT)(SHORT)HIWORD(dwHookCurrent)) { case WH_CALLWNDPROC: case WH_CALLWNDPROCRET: /* * This is the hardest of the hooks because we need to thunk through * the message hooks in order to deal with synchronously sent messages * that point to structures - to get the structures passed across * alright, etc. * * This will call a special kernel-side routine that'll rebundle the * arguments and call the hook in the right format. * * Currently, the message thunk callbacks to the client-side don't take * enough parameters to pass wParam (which == fInterThread send msg). * To do this, save the state of wParam in the CLIENTINFO structure. */ dwFlags = KERNEL_ULONG_PTR_TO_ULONG_PTR(pci->CI_flags) & CI_INTERTHREAD_HOOK; dwHookData = KERNEL_ULONG_PTR_TO_ULONG_PTR(pci->dwHookData); if (wParam) { pci->CI_flags |= CI_INTERTHREAD_HOOK; } else { pci->CI_flags &= ~CI_INTERTHREAD_HOOK; } if ((INT)(SHORT)HIWORD(dwHookCurrent) == WH_CALLWNDPROC) { nRet = CsSendMessage( ((LPCWPSTRUCT)lParam)->hwnd, ((LPCWPSTRUCT)lParam)->message, ((LPCWPSTRUCT)lParam)->wParam, ((LPCWPSTRUCT)lParam)->lParam, 0, FNID_HKINLPCWPEXSTRUCT, bAnsi); } else { pci->dwHookData = ((LPCWPRETSTRUCT)lParam)->lResult; nRet = CsSendMessage( ((LPCWPRETSTRUCT)lParam)->hwnd, ((LPCWPRETSTRUCT)lParam)->message, ((LPCWPRETSTRUCT)lParam)->wParam, ((LPCWPRETSTRUCT)lParam)->lParam, 0, FNID_HKINLPCWPRETEXSTRUCT, bAnsi); } /* * Restore previous hook state. */ pci->CI_flags ^= ((pci->CI_flags ^ dwFlags) & CI_INTERTHREAD_HOOK); pci->dwHookData = dwHookData; break; default: nRet = NtUserCallNextHookEx(nCode, wParam, lParam, bAnsi); } return nRet; }