/****************************** Module Header ******************************\ * Module Name: random.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains a random collection of support routines for the User * API functions. Many of these functions will be moved to more appropriate * files once we get our act together. * * History: * 10-17-90 DarrinM Created. * 02-06-91 IanJa HWND revalidation added (none required) \***************************************************************************/ #include "precomp.h" #pragma hdrstop /***************************************************************************\ * xxxUpdateWindows * * User mode wrapper \***************************************************************************/ BOOL xxxUpdateWindows( PWND pwnd, HRGN hrgn) { CheckLock(pwnd); xxxUpdateThreadsWindows(PtiCurrent(), pwnd, hrgn); return TRUE; } /***************************************************************************\ * ValidateState * * States allowed to be set/cleared by Set/ClearWindowState. If you're * allowing a new flag here, you must make sure it won't cause an AV * in the kernel if someone sets it maliciously. \***************************************************************************/ #define NUM_BYTES 16 // Window state bytes are 0 to F, explanation in user.h CONST BYTE abValidateState[NUM_BYTES] = { 0, // 0 0, // 1 0, // 2 0, // 3 0, // 4 LOBYTE(WFWIN40COMPAT), 0, // 6 LOBYTE(WFNOANIMATE), 0, // 8 LOBYTE(WEFEDGEMASK), LOBYTE(WEFSTATICEDGE), 0, // B LOBYTE(EFPASSWORD), LOBYTE(CBFHASSTRINGS | EFREADONLY), LOBYTE(WFTABSTOP | WFSYSMENU | WFVSCROLL | WFHSCROLL | WFBORDER), LOBYTE(WFCLIPCHILDREN) }; BOOL ValidateState( DWORD dwFlags) { BYTE bOffset = HIBYTE(dwFlags), bState = LOBYTE(dwFlags); if (bOffset > NUM_BYTES - 1) { return FALSE; } else { return ((bState & abValidateState[bOffset]) == bState); } } /***************************************************************************\ * Set/ClearWindowState * * Wrapper functions for User mode to be able to set state flags. \***************************************************************************/ VOID SetWindowState( PWND pwnd, DWORD dwFlags) { /* * Don't let anyone mess with someone else's window. */ if (GETPTI(pwnd)->ppi == PtiCurrent()->ppi) { if (ValidateState(dwFlags)) { SetWF(pwnd, dwFlags); } else { RIPMSG1(RIP_ERROR, "SetWindowState: invalid flag 0x%x", dwFlags); } } else { RIPMSG1(RIP_WARNING, "SetWindowState: current ppi doesn't own pwnd %#p", pwnd); } } VOID ClearWindowState( PWND pwnd, DWORD dwFlags) { /* * Don't let anyone mess with someone else's window. */ if (GETPTI(pwnd)->ppi == PtiCurrent()->ppi) { if (ValidateState(dwFlags)) { ClrWF(pwnd, dwFlags); } else { RIPMSG1(RIP_ERROR, "SetWindowState: invalid flag 0x%x", dwFlags); } } else { RIPMSG1(RIP_WARNING, "ClearWindowState: current ppi doesn't own pwnd %#p", pwnd); } } /***************************************************************************\ * CheckPwndFilter * * * * History: * 11-07-90 DarrinM Translated Win 3.0 ASM code. \***************************************************************************/ BOOL CheckPwndFilter( PWND pwnd, PWND pwndFilter) { if ((pwndFilter == NULL) || (pwndFilter == pwnd) || ((pwndFilter == (PWND)1) && (pwnd == NULL))) { return TRUE; } return _IsChild(pwndFilter, pwnd); } /***************************************************************************\ * AllocateUnicodeString * * History: * 10-25-90 MikeHar Wrote. * 11-09-90 DarrinM Fixed. * 01-13-92 GregoryW Neutralized. * 03-05-98 FritzS Only allocate Length+1 \***************************************************************************/ BOOL AllocateUnicodeString( PUNICODE_STRING pstrDst, PUNICODE_STRING cczpstrSrc) { if (cczpstrSrc == NULL) { RtlInitUnicodeString(pstrDst, NULL); return TRUE; } pstrDst->Buffer = UserAllocPoolWithQuota(cczpstrSrc->Length+sizeof(UNICODE_NULL), TAG_TEXT); if (pstrDst->Buffer == NULL) { return FALSE; } try { RtlCopyMemory(pstrDst->Buffer, cczpstrSrc->Buffer, cczpstrSrc->Length); } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { UserFreePool(pstrDst->Buffer); pstrDst->Buffer = NULL; return FALSE; } pstrDst->MaximumLength = cczpstrSrc->Length+sizeof(UNICODE_NULL); pstrDst->Length = cczpstrSrc->Length; pstrDst->Buffer[pstrDst->Length / sizeof(WCHAR)] = 0; return TRUE; } /***************************************************************************\ * xxxGetControlColor * * History: * 02-12-92 JimA Ported from Win31 sources \***************************************************************************/ HBRUSH xxxGetControlColor( PWND pwndParent, PWND pwndCtl, HDC hdc, UINT message) { HBRUSH hbrush; /* * If we're sending to a window of another thread, don't send this message * but instead call DefWindowProc(). New rule about the CTLCOLOR messages. * Need to do this so that we don't send an hdc owned by one thread to * another thread. It is also a harmless change. */ if (PpiCurrent() != GETPTI(pwndParent)->ppi) { return (HBRUSH)xxxDefWindowProc(pwndParent, message, (WPARAM)hdc, (LPARAM)HW(pwndCtl)); } hbrush = (HBRUSH)xxxSendMessage(pwndParent, message, (WPARAM)hdc, (LPARAM)HW(pwndCtl)); /* * If the brush returned from the parent is invalid, get a valid brush from * xxxDefWindowProc. */ if (hbrush == 0 || !GreValidateServerHandle(hbrush, BRUSH_TYPE)) { if (hbrush != 0) { RIPMSG2(RIP_WARNING, "Invalid HBRUSH from WM_CTLCOLOR*** msg 0x%x brush 0x%x", message, hbrush); } hbrush = (HBRUSH)xxxDefWindowProc(pwndParent, message, (WPARAM)hdc, (LPARAM)pwndCtl); } return hbrush; } /***************************************************************************\ * xxxGetControlBrush * * * * History: * 12-10-90 IanJa type replaced with new 32-bit message * 01-21-91 IanJa Prefix '_' denoting exported function (although not API) \***************************************************************************/ HBRUSH xxxGetControlBrush( PWND pwnd, HDC hdc, UINT message) { HBRUSH hbr; PWND pwndSend; TL tlpwndSend; CheckLock(pwnd); if ((pwndSend = (TestwndPopup(pwnd) ? pwnd->spwndOwner : pwnd->spwndParent)) == NULL) { pwndSend = pwnd; } ThreadLock(pwndSend, &tlpwndSend); /* * Last parameter changes the message into a ctlcolor id. */ hbr = xxxGetControlColor(pwndSend, pwnd, hdc, message); ThreadUnlock(&tlpwndSend); return hbr; } /***************************************************************************\ * xxxHardErrorControl * * Performs kernel-mode hard error support functions. * * History: * 02-08-95 JimA Created. \***************************************************************************/ UINT xxxHardErrorControl( DWORD dwCmd, HANDLE handle, PDESKRESTOREDATA pdrdRestore) { PTHREADINFO ptiClient, ptiCurrent = PtiCurrent(); PDESKTOP pdesk; PUNICODE_STRING pstrName; NTSTATUS Status; PETHREAD Thread; BOOL fAllowForeground; /* * turn off BlockInput so the user can respond to the hard error popup */ gptiBlockInput = NULL; UserAssert(ISCSRSS()); switch (dwCmd) { /* * Code to catch Windows Bug 469607. */ #ifdef PRERELEASE case HardErrorCheckOnDesktop: if (ptiCurrent == gptiForeground && ptiCurrent->rpdesk == NULL) { FRE_RIPMSG0(RIP_ERROR, "Harderror thread exiting while not on a desktop"); } break; #endif case HardErrorSetup: /* * Don't do it if the system has not been initialized. */ if (grpdeskRitInput == NULL) { RIPMSG0(RIP_WARNING, "HardErrorControl: System not initialized"); return HEC_ERROR; } /* * Setup caller as the hard error handler. */ if (gHardErrorHandler.pti != NULL) { RIPMSG1(RIP_WARNING, "HardErrorControl: pti not NULL %#p", gHardErrorHandler.pti); return HEC_ERROR; } /* * Mark the handler as active. */ gHardErrorHandler.pti = ptiCurrent; /* * Clear any pending quits. */ ptiCurrent->TIF_flags &= ~TIF_QUITPOSTED; break; case HardErrorCleanup: /* * Remove caller as the hard error handler. */ if (gHardErrorHandler.pti != ptiCurrent) { return HEC_ERROR; } gHardErrorHandler.pti = NULL; break; case HardErrorAttachUser: case HardErrorInDefDesktop: /* * Check for exit conditions. We do not allow attaches to the * disconnect desktop. */ if (ISTS()) { if ((grpdeskRitInput == NULL) || ((grpdeskRitInput == gspdeskDisconnect) && (gspdeskShouldBeForeground == NULL)) || ((grpdeskRitInput == gspdeskDisconnect) && (gspdeskShouldBeForeground == gspdeskDisconnect))) { return HEC_ERROR; } } /* * Only attach to a user desktop. */ if (ISTS() && grpdeskRitInput == gspdeskDisconnect) { pstrName = POBJECT_NAME(gspdeskShouldBeForeground); } else { pstrName = POBJECT_NAME(grpdeskRitInput); } if (pstrName && (!_wcsicmp(TEXT("Winlogon"), pstrName->Buffer) || !_wcsicmp(TEXT("Disconnect"), pstrName->Buffer) || !_wcsicmp(TEXT("Screen-saver"), pstrName->Buffer))) { RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, ""); return HEC_WRONGDESKTOP; } if (dwCmd == HardErrorInDefDesktop) { /* * Clear any pending quits. */ ptiCurrent->TIF_flags &= ~TIF_QUITPOSTED; return HEC_SUCCESS; } /* * Fall through. */ case HardErrorAttach: /* * Save a pointer to and prevent destruction of the * current queue. This will give us a queue to return * to if journalling is occuring when we tear down the * hard error popup. */ gHardErrorHandler.pqAttach = ptiCurrent->pq; (ptiCurrent->pq->cLockCount)++; /* * Fall through. */ case HardErrorAttachNoQueue: /* * Check for exit conditions. We do not allow attaches to the * disconnect desktop. */ if (ISTS()) { if ((grpdeskRitInput == NULL) || ((grpdeskRitInput == gspdeskDisconnect) && (gspdeskShouldBeForeground == NULL)) || ((grpdeskRitInput == gspdeskDisconnect) && (gspdeskShouldBeForeground == gspdeskDisconnect))) { return HEC_ERROR; } } /* * Attach the handler to the current desktop. */ /* * Don't allow an attach to the disconnected desktop, but * remember this for later when we detach. */ gbDisconnectHardErrorAttach = FALSE; if (ISTS() && grpdeskRitInput == gspdeskDisconnect) { pdesk = gspdeskShouldBeForeground; gbDisconnectHardErrorAttach = TRUE; } else { pdesk = grpdeskRitInput; } UserAssert(pdesk != NULL); Status = xxxSetCsrssThreadDesktop(pdesk, pdrdRestore); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "HardErrorControl: HardErrorAttachNoQueue failed: 0x%x", Status); if (dwCmd != HardErrorAttachNoQueue) { gHardErrorHandler.pqAttach = NULL; UserAssert(ptiCurrent->pq->cLockCount); (ptiCurrent->pq->cLockCount)--; } return HEC_ERROR; } /* * Make sure we actually set the pdesk in the current thread */ UserAssert(ptiCurrent->rpdesk != NULL); /* * Determine if this box can come to the foreground. * Let it come to the foreground if it doesn't have a pti * (it might have just failed to load). */ fAllowForeground = FALSE; if (handle != NULL) { Status = ObReferenceObjectByHandle(handle, THREAD_QUERY_INFORMATION, *PsThreadType, UserMode, &Thread, NULL); if (NT_SUCCESS(Status)) { ptiClient = PtiFromThread(Thread); if ((ptiClient == NULL) || CanForceForeground(ptiClient->ppi)) { fAllowForeground = TRUE; } UnlockThread(Thread); } else { RIPMSGF2(RIP_WARNING, "Failed to get thread (0x%p), Status: 0x%x", handle, Status); } } if (fAllowForeground) { ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; TAGMSG1(DBGTAG_FOREGROUND, "xxxHardErrorControl set TIF %#lx", ptiCurrent); } else { ptiCurrent->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE; TAGMSG1(DBGTAG_FOREGROUND, "xxxHardErrorControl clear TIF %#lx", ptiCurrent); } break; case HardErrorDetach: /* * xxxSwitchDesktop may have sent WM_QUIT to the msgbox, so * ensure that the quit flag is reset. */ ptiCurrent->TIF_flags &= ~TIF_QUITPOSTED; /* * We will reset the hard-error queue to the pre-allocated * one so if we end up looping back (i.e. from a desktop * switch), we will have a valid queue in case the desktop * was deleted. */ UserAssert(gHardErrorHandler.pqAttach->cLockCount); (gHardErrorHandler.pqAttach->cLockCount)--; DeferWinEventNotify(); BEGINATOMICCHECK(); if (ptiCurrent->pq != gHardErrorHandler.pqAttach) { UserAssert(gHardErrorHandler.pqAttach->cThreads == 0); AllocQueue(NULL, gHardErrorHandler.pqAttach); gHardErrorHandler.pqAttach->cThreads++; zzzAttachToQueue(ptiCurrent, gHardErrorHandler.pqAttach, NULL, FALSE); } gHardErrorHandler.pqAttach = NULL; ENDATOMICCHECK(); zzzEndDeferWinEventNotify(); /* * Fall through. */ case HardErrorDetachNoQueue: /* * Detach the handler from the desktop and return * status to indicate if a switch has occured. */ pdesk = ptiCurrent->rpdesk; xxxRestoreCsrssThreadDesktop(pdrdRestore); if (ISTS()) { /* * The hard error message box gets a desktop switch notification, * so remember that we lied to him and lie (or unlie) to him again. * A desktop switch did occur. */ if (gbDisconnectHardErrorAttach) { gbDisconnectHardErrorAttach = FALSE; return HEC_DESKTOPSWITCH; } #ifdef WAY_LATER /* * This happened once and caused a trap when a KeyEvent() came in and we * directed it to this queue. I think this is a MS window that we caught * since we use this so much for license popup's. */ if (gHardErrorHandler.pqAttach == gpqForeground) { gpqForeground = NULL; } #endif } return (pdesk != grpdeskRitInput ? HEC_DESKTOPSWITCH : HEC_SUCCESS); } return HEC_SUCCESS; }