Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4619 lines
150 KiB

/****************************** Module Header ******************************\
* Module Name: rare.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* History:
* 06-28-91 MikeHar Created.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* MetricsRecalc flags
*/
#define CALC_RESIZE 0x0001
#define CALC_FRAME 0x0002
#define CALC_MINIMIZE 0x0004
/*
* NormalizeRect flags
*/
#define NORMALIZERECT_NORMAL 0
#define NORMALIZERECT_MAXIMIZED 1
#define NORMALIZERECT_FULLSCREEN 2
/***************************************************************************\
* SnapshotMonitorRects
*
* This is called from ResetDisplay to memorize the monitor positions so
* DesktopRecalcEx will know where to move stuff.
*
* Returns the MONITORRECTS if succeeded, NULL otherwise.
*
* History:
* 09-Dec-1996 adams Created.
\***************************************************************************/
PMONITORRECTS SnapshotMonitorRects(
VOID)
{
PMONITOR pMonitor;
PMONITORRECTS pmr;
PMONITORPOS pmp;
#if DBG
ULONG cVisMon = 0;
#endif
pmr = UserAllocPool(sizeof(MONITORRECTS) + sizeof(MONITORPOS) * (gpDispInfo->cMonitors - 1),
TAG_MONITORRECTS);
if (!pmr) {
RIPERR0(ERROR_OUTOFMEMORY, RIP_WARNING, "Out of memory in SnapshotMonitorRects");
return NULL;
}
pmp = pmr->amp;
for (pMonitor = gpDispInfo->pMonitorFirst;
pMonitor;
pMonitor = pMonitor->pMonitorNext) {
if (!(pMonitor->dwMONFlags & MONF_VISIBLE)) {
continue;
}
#if DBG
cVisMon++;
#endif
CopyRect(&pmp->rcMonitor, &pMonitor->rcMonitor);
CopyRect(&pmp->rcWork, &pMonitor->rcWork);
/*
* If the device for this monitor object is not active, don't store
* the pointer to it in the list. This way the windows on the inactive
* monitor will be later moved to the default one.
*/
if (HdevFromMonitor(pMonitor) == -1) {
pmp->pMonitor = NULL;
} else {
pmp->pMonitor = pMonitor;
}
pmp++;
}
UserAssert(cVisMon == gpDispInfo->cMonitors);
pmr->cMonitor = (int)(pmp - pmr->amp);
return pmr;
}
/***************************************************************************\
* UpdateMonitorRectsSnapShot
*
* Updates a Monitor rects snapshot. Every pMonitor in MONITORPOS is checked
* to still be a valid monitor. If the pMonitor is no loger valid (deleted
* by a ChangeDisplaySettings. it is zeroed so that its windows will be
* repositioned on the primary monitor. This code is only used on by the
* reconnect in TS scenario and is there for cases that are not happening
* today: today reconnect always happens from disconnected state where we go
* from 1 monitor (the disconnected display driver) to n monitors and this
* monitor (starting in (0,0) never gets deleted because it alway matches one
* of the new n monitors (the one starting in (0,0). So this code is just in
* case of future changes.
*
* History:
\***************************************************************************/
VOID UpdateMonitorRectsSnapShot(
PMONITORRECTS pmr)
{
int i;
PMONITORPOS pmp = pmr->amp;
for (i = 0; i < pmr->cMonitor; i++) {
if (pmp->pMonitor != NULL) {
if (!IsValidMonitor(pmp->pMonitor)) {
pmp->pMonitor = NULL;
}
}
pmp++;
}
}
BOOL IsValidMonitor(
PMONITOR pMonitor)
{
PMONITOR pMonitorNext = gpDispInfo->pMonitorFirst;
while (pMonitorNext != NULL) {
if (pMonitorNext == pMonitor) {
return TRUE;
}
pMonitorNext = pMonitorNext->pMonitorNext;
}
return FALSE;
}
/***************************************************************************\
* NormalizeRect
*
* Adjusts a window rectangle when the working area changes. This can be
* because of a tray move, with the resolution staying the same, or
* because of a dynamic resolution change, with the tray staying the same
* relatively.
*
* History:
\***************************************************************************/
PMONITOR NormalizeRect(
LPRECT lprcDest,
LPRECT lprcSrc,
PMONITORRECTS pmrOld,
int iOldMonitor,
int codeFullScreen,
DWORD style)
{
LPCRECT lprcOldMonitor;
LPCRECT lprcOldWork;
LPRECT lprcNewWork;
PMONITOR pMonitor;
int cxOldMonitor;
int cyOldMonitor;
int cxNewMonitor;
int cyNewMonitor;
int dxOrg, dyOrg;
/*
* Track the window so it stays in the same place on the same monitor.
* If the old monitor is no longer active then pick a default.
*/
if ((pMonitor = pmrOld->amp[iOldMonitor].pMonitor) == NULL) {
pMonitor = GetPrimaryMonitor();
}
lprcOldMonitor = &pmrOld->amp[iOldMonitor].rcMonitor;
lprcOldWork = &pmrOld->amp[iOldMonitor].rcWork;
/*
* If is a fullscreen app just make it fullscreen at the new location.
*/
if (codeFullScreen != NORMALIZERECT_NORMAL) {
LPCRECT lprcOldSnap, lprcNewSnap;
/*
* If it is a maximized window snap it to the work area. Otherwise
* it is a rude app so snap it to the screen.
*/
if (codeFullScreen == NORMALIZERECT_MAXIMIZED) {
lprcOldSnap = lprcOldWork;
lprcNewSnap = &pMonitor->rcWork;
} else {
lprcOldSnap = lprcOldMonitor;
lprcNewSnap = &pMonitor->rcMonitor;
}
lprcDest->left = lprcSrc->left +
lprcNewSnap->left - lprcOldSnap->left;
lprcDest->top = lprcSrc->top +
lprcNewSnap->top - lprcOldSnap->top;
lprcDest->right = lprcSrc->right +
lprcNewSnap->right - lprcOldSnap->right;
lprcDest->bottom = lprcSrc->bottom +
lprcNewSnap->bottom - lprcOldSnap->bottom;
goto AllDone;
}
/*
* Offset the window by the change in desktop origin.
*/
dxOrg = pMonitor->rcMonitor.left - lprcOldMonitor->left;
dyOrg = pMonitor->rcMonitor.top - lprcOldMonitor->top;
/*
* Calculate the change in screen size (we need it in more than one place).
*/
cxOldMonitor = lprcOldMonitor->right - lprcOldMonitor->left;
cyOldMonitor = lprcOldMonitor->bottom - lprcOldMonitor->top;
cxNewMonitor = pMonitor->rcMonitor.right - pMonitor->rcMonitor.left;
cyNewMonitor = pMonitor->rcMonitor.bottom - pMonitor->rcMonitor.top;
/*
* If the monitor resolution has changed (or we moved to a new monitor)
* then factor in the size change.
*/
if (cxNewMonitor != cxOldMonitor || cyNewMonitor != cyOldMonitor) {
int xWnd = lprcSrc->left - lprcOldMonitor->left;
int yWnd = lprcSrc->top - lprcOldMonitor->top;
dxOrg += MultDiv(xWnd, cxNewMonitor - cxOldMonitor, cxOldMonitor);
dyOrg += MultDiv(yWnd, cyNewMonitor - cyOldMonitor, cyOldMonitor);
}
/*
* Compute the initial new position.
*/
CopyOffsetRect(lprcDest, lprcSrc, dxOrg, dyOrg);
lprcNewWork = &pMonitor->rcWork;
/*
* Fit horizontally. Try to fit so that the window isn't out of the
* working area horizontally. Keep left edge visible always.
*/
if (lprcDest->right > lprcNewWork->right) {
OffsetRect(lprcDest, lprcNewWork->right - lprcDest->right, 0);
}
if (lprcDest->left < lprcNewWork->left) {
OffsetRect(lprcDest, lprcNewWork->left - lprcDest->left, 0);
}
/*
* Fit vertically. Try to fit so that the window isn't out of the
* working area vertically. Keep top edge visible always.
*/
if (lprcDest->bottom > lprcNewWork->bottom) {
OffsetRect(lprcDest, 0, lprcNewWork->bottom - lprcDest->bottom);
}
if (lprcDest->top < lprcNewWork->top) {
OffsetRect(lprcDest, 0, lprcNewWork->top - lprcDest->top);
}
/*
* If the window is sizeable then shrink it if necessary.
*/
if (style & WS_THICKFRAME) {
int cSnap = 0;
if (lprcDest->right > lprcNewWork->right) {
lprcDest->right = lprcNewWork->right;
cSnap++;
}
if (lprcDest->bottom > lprcNewWork->bottom) {
lprcDest->bottom = lprcNewWork->bottom;
cSnap++;
}
/*
* Now make sure we didn't turn this normal window into a
* fullscreen window. This is a complete hack but it is much
* better than changing from 800x600 to 640x480 and ending up with
* a bunch of fullscreen apps...
*/
if (cSnap == 2) {
InflateRect(lprcDest, -1, -1);
}
}
AllDone:
return pMonitor;
}
#if DBG
/***************************************************************************\
* SetRipFlags
*
* Sets the debug rip flags.
*
* History:
* 16-Aug-1996 adams Created.
\***************************************************************************/
VOID SetRipFlags(
DWORD dwRipFlags)
{
if (gpsi) {
if (!(dwRipFlags & ~RIPF_VALIDUSERFLAGS)) {
gpsi->dwRIPFlags = ((gpsi->dwRIPFlags & ~RIPF_VALIDUSERFLAGS) | dwRipFlags);
}
}
}
/***************************************************************************\
* SetDbgTag
*
* Sets debugging level for a tag.
*
* History:
* 16-Aug-1996 adams Created.
\***************************************************************************/
VOID SetDbgTag(
int tag,
DWORD dwDBGTAGFlags)
{
if (tag > DBGTAG_Max || tag < 0) {
return;
}
if (gpsi && tag < DBGTAG_Max && !(dwDBGTAGFlags & ~DBGTAG_VALIDUSERFLAGS)) {
COPY_FLAG(gpsi->adwDBGTAGFlags[tag], dwDBGTAGFlags, DBGTAG_VALIDUSERFLAGS);
}
}
/***************************************************************************\
* SetDbgTagCount
*
* Sets the number of tags. This is necessary because one can use a
* userkdx.dll that was built in an enlistment with N tags, but use it against
* a system that has M tags (where N != M), which causes obvious problems.
*
* History:
* 05-Oct-2001 JasonSch Created.
\***************************************************************************/
VOID SetDbgTagCount(
DWORD dwCount)
{
gpsi->dwTagCount = dwCount;
}
#endif
/***************************************************************************\
* UpdateWinIniInt
*
* History:
* 18-Apr-1994 mikeke Created
\***************************************************************************/
BOOL UpdateWinIniInt(
PUNICODE_STRING pProfileUserName,
UINT idSection,
UINT wKeyNameId,
int value)
{
WCHAR szTemp[40];
WCHAR szKeyName[40];
swprintf(szTemp, L"%d", value);
ServerLoadString(hModuleWin,
wKeyNameId,
szKeyName,
ARRAY_SIZE(szKeyName));
return FastWriteProfileStringW(pProfileUserName,
idSection,
szKeyName,
szTemp);
}
/***************************************************************************\
* SetDesktopMetrics
*
* History:
* 31-Jan-1994 mikeke Ported
\***************************************************************************/
VOID SetDesktopMetrics(
VOID)
{
LPRECT lprcWork;
lprcWork = &GetPrimaryMonitor()->rcWork;
SYSMET(CXFULLSCREEN) = lprcWork->right - lprcWork->left;
SYSMET(CXMAXIMIZED) = lprcWork->right - lprcWork->left + 2 * SYSMET(CXSIZEFRAME);
SYSMET(CYFULLSCREEN) = lprcWork->bottom - lprcWork->top - SYSMET(CYCAPTION);
SYSMET(CYMAXIMIZED) = lprcWork->bottom - lprcWork->top + 2 * SYSMET(CYSIZEFRAME);
}
/***************************************************************************\
* xxxMetricsRecalc (Win95: MetricsRecalc)
*
* Does work to size/position all minimized or nonminimized
* windows. Called when frame metrics or min metrics are changed.
*
* Note that you can NOT do DeferWindowPos() with this function. SWP doesn't
* work when you do parents and children at the same time--it's only for
* peer windows. Thus we must do SetWindowPos() for each window.
*
* History:
* 06-28-91 MikeHar Ported.
\***************************************************************************/
VOID xxxMetricsRecalc(
UINT wFlags,
int dx,
int dy,
int dyCaption,
int dyMenu)
{
PHWND phwnd;
PWND pwnd;
RECT rc;
PCHECKPOINT pcp;
TL tlpwnd;
BOOL fResized;
PBWL pbwl;
PTHREADINFO ptiCurrent;
int c;
ptiCurrent = PtiCurrent();
pbwl = BuildHwndList(GETDESKINFO(ptiCurrent)->spwnd->spwndChild,
BWL_ENUMLIST | BWL_ENUMCHILDREN,
NULL);
if (!pbwl) {
return;
}
UserAssert(*pbwl->phwndNext == (HWND) 1);
c = (int)(pbwl->phwndNext - pbwl->rghwnd);
for (phwnd = pbwl->rghwnd; c > 0; c--, phwnd++) {
pwnd = RevalidateHwnd(*phwnd);
if (!pwnd) {
continue;
}
ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);
fResized = FALSE;
if ((wFlags & CALC_MINIMIZE) && TestWF(pwnd, WFMINIMIZED)) {
/*
* We're changing the minimized window dimensions. We need to
* resize. Note that we do NOT move.
*/
CopyRect(&rc, (&pwnd->rcWindow));
rc.right += dx;
rc.bottom += dy;
goto PositionWnd;
}
/*
* We're changing the size of the window because the sizing border
* changed.
*/
if ((wFlags & CALC_RESIZE) && TestWF(pwnd, WFSIZEBOX)) {
pcp = (PCHECKPOINT)_GetProp(pwnd, PROP_CHECKPOINT, PROPF_INTERNAL);
/*
* Update maximized position to account for sizing border
* We do this for DOS box also. This way client of max'ed windows
* stays in same relative position.
*/
if (pcp && (pcp->fMaxInitialized)) {
pcp->ptMax.x -= dx;
pcp->ptMax.y -= dy;
}
if (TestWF(pwnd, WFMINIMIZED)) {
if (pcp) {
InflateRect(&pcp->rcNormal, dx, dy);
}
} else {
CopyInflateRect(&rc, (&pwnd->rcWindow), dx, dy);
if (TestWF(pwnd, WFCPRESENT)) {
rc.bottom += dyCaption;
}
if (TestWF(pwnd, WFMPRESENT)) {
rc.bottom += dyMenu;
}
PositionWnd:
fResized = TRUE;
/*
* Remember SWP expects values in PARENT CLIENT coordinates.
*/
if (pwnd->spwndParent != PWNDDESKTOP(pwnd)) {
OffsetRect(&rc,
-pwnd->spwndParent->rcClient.left,
-pwnd->spwndParent->rcClient.top);
}
xxxSetWindowPos(pwnd,
PWND_TOP,
rc.left,
rc.top,
rc.right-rc.left,
rc.bottom-rc.top,
SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS |
SWP_FRAMECHANGED | SWP_NOREDRAW);
}
}
/*
* We're changing the nonclient widgets, so recalculate the client.
*/
if (wFlags & CALC_FRAME) {
/*
* Delete any cached small icons.
*/
if (dyCaption) {
xxxSendMessage(pwnd, WM_SETICON, ICON_RECREATE, 0);
}
if (!TestWF(pwnd, WFMINIMIZED) && !fResized) {
CopyRect(&rc, &(pwnd->rcWindow));
if (TestWF(pwnd, WFMPRESENT)) {
rc.bottom += dyMenu;
}
if (TestWF(pwnd, WFCPRESENT)) {
rc.bottom += dyCaption;
/*
* Maximized MDI child windows position their caption
* outside their parent's client area (negative y). If
* the caption has changed, they need to be repositioned.
*/
if (TestWF(pwnd, WFMAXIMIZED)
&& TestWF(pwnd, WFCHILD)
&& (GETFNID(pwnd->spwndParent) == FNID_MDICLIENT)) {
xxxSetWindowPos(pwnd,
PWND_TOP,
rc.left - pwnd->spwndParent->rcWindow.left,
rc.top - pwnd->spwndParent->rcWindow.top - dyCaption,
rc.right - rc.left,
rc.bottom - rc.top,
SWP_NOZORDER | SWP_NOACTIVATE |
SWP_FRAMECHANGED | SWP_NOREDRAW);
goto LoopCleanup;
}
}
xxxSetWindowPos(pwnd,
PWND_TOP,
0,
0,
rc.right-rc.left,
rc.bottom-rc.top,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE |
SWP_FRAMECHANGED | SWP_NOCOPYBITS |
SWP_NOREDRAW);
}
}
LoopCleanup:
ThreadUnlock(&tlpwnd);
}
FreeHwndList(pbwl);
}
/***************************************************************************\
* FindOldMonitor
*
* Returns the index of the monitor in "pmr" which has the greatest
* overlap with a rectangle. This function is used to determine which
* monitor a window was on after one or more monitor rectangles have
* changed.
*
* History:
* 11-Sep-1996 adams Created.
\***************************************************************************/
int FindOldMonitor(
LPCRECT lprc,
PMONITORRECTS pmr)
{
DWORD dwClosest;
int iClosest, i;
int cxRect, cyRect;
PMONITORPOS pmp;
iClosest = -1;
dwClosest = 0;
cxRect = (lprc->right - lprc->left);
cyRect = (lprc->bottom - lprc->top);
for (i = 0, pmp = pmr->amp; i < pmr->cMonitor; pmp++, i++) {
RECT rcT;
if (IntersectRect(&rcT, lprc, &pmp->rcMonitor)) {
DWORD dwT;
/*
* Convert to width/height.
*/
rcT.right -= rcT.left;
rcT.bottom -= rcT.top;
/*
* If fully enclosed, we're done.
*/
if (rcT.right == cxRect && rcT.bottom == cyRect) {
return i;
}
/*
* Use largest area.
*/
dwT = (DWORD)rcT.right * (DWORD)rcT.bottom;
if (dwT > dwClosest) {
dwClosest = dwT;
iClosest = i;
}
}
}
return iClosest;
}
/***************************************************************************\
* xxxDesktopRecalc
*
* Moves all top-level nonpopup windows into free desktop area,
* attempting to keep them in the same position relative to the monitor
* they were on. Also resets minimized info (so that when a window is
* subsequently minimized it will go to the correct location).
*
* History:
* 11-Sep-1996 adams Created.
\***************************************************************************/
VOID xxxDesktopRecalc(
PMONITORRECTS pmrOld)
{
PWND pwndDesktop;
PSMWP psmwp;
PHWND phwnd;
PBWL pbwl;
PWND pwnd;
CHECKPOINT * pcp;
int iOldMonitor;
int codeFullScreen;
UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
/*
* We never want CSRSS to position windows synchronously because it
* might get blocked by a hung app. CSRSS needs to reposition windows
* in the TS reconnect and disconnect path as part of changing display
* setting to switch display drivers or to match new client resolution.
*/
if (ISCSRSS()) {
flags |= SWP_ASYNCWINDOWPOS;
}
UserVerify(pwndDesktop = _GetDesktopWindow());
if ((pbwl = BuildHwndList(pwndDesktop->spwndChild, BWL_ENUMLIST, NULL)) == NULL) {
return;
}
if ((psmwp = InternalBeginDeferWindowPos(4)) != NULL) {
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1 && psmwp; phwnd++) {
/*
* Make sure this hwnd is still around.
*/
if ((pwnd = RevalidateHwnd(*phwnd)) == NULL ||
TestWF(pwnd, WEFTOOLWINDOW)) {
continue;
}
codeFullScreen = TestWF(pwnd, WFFULLSCREEN) ?
NORMALIZERECT_FULLSCREEN : NORMALIZERECT_NORMAL;
pcp = (PCHECKPOINT)_GetProp(pwnd, PROP_CHECKPOINT, PROPF_INTERNAL);
if (pcp) {
/*
* We don't need to blow away saved maximized positions
* anymore, since the max position is always (for top level
* windows) relative to the origin of the monitor's working
* area. And for child windows, we shouldn't do it period
* anyway.
*/
pcp->fMinInitialized = FALSE;
/*
* Figure out which monitor the position was on before things
* got shuffled around and try to keep it on that monitor. If
* it was never visible on a monitor then leave it alone.
*/
iOldMonitor = FindOldMonitor(&pcp->rcNormal, pmrOld);
if (iOldMonitor != (UINT)-1) {
NormalizeRect(&pcp->rcNormal,
&pcp->rcNormal,
pmrOld,
iOldMonitor,
codeFullScreen,
pwnd->style);
}
}
/*
* Figure out which monitor the position was on before things got
* shuffled around and try to keep it on that monitor. If it
* was never visible on a monitor then leave it alone.
*/
iOldMonitor = FindOldMonitor(&pwnd->rcWindow, pmrOld);
if (iOldMonitor != -1) {
PMONITOR pMonitorDst;
RECT rc;
/*
* Check for maximized apps that are truly maximized (as
* opposed to apps that manage their owm maximized rect).
*/
if (TestWF(pwnd, WFMAXIMIZED)) {
LPRECT lprcOldWork = &pmrOld->amp[iOldMonitor].rcWork;
if ( (pwnd->rcWindow.right - pwnd->rcWindow.left >=
lprcOldWork->right - lprcOldWork->left)
&&
(pwnd->rcWindow.bottom - pwnd->rcWindow.top >=
lprcOldWork->bottom - lprcOldWork->top)) {
codeFullScreen = NORMALIZERECT_MAXIMIZED;
}
}
pMonitorDst = NormalizeRect(&rc,
&pwnd->rcWindow,
pmrOld,
iOldMonitor,
codeFullScreen,
pwnd->style);
if (TestWF(pwnd, WFMAXFAKEREGIONAL)) {
UserAssert(pMonitorDst->hrgnMonitor);
pwnd->hrgnClip = pMonitorDst->hrgnMonitor;
}
psmwp = _DeferWindowPos(psmwp,
pwnd,
(PWND)HWND_TOP,
rc.left,
rc.top,
rc.right - rc.left,
rc.bottom - rc.top,
flags);
}
}
if (psmwp) {
xxxEndDeferWindowPosEx(psmwp, TRUE);
}
}
FreeHwndList(pbwl);
}
/***************************************************************************\
* SetWindowMetricInt
*
* History:
* 25-Feb-96 BradG Added Pixel -> TWIPS conversion
\***************************************************************************/
BOOL SetWindowMetricInt(
PUNICODE_STRING pProfileUserName,
WORD wKeyNameId,
int iIniValue)
{
/*
* If you change the below list of STR_* make sure you make a
* corresponding change in FastGetProfileIntFromID.
*/
switch (wKeyNameId) {
case STR_BORDERWIDTH:
case STR_SCROLLWIDTH:
case STR_SCROLLHEIGHT:
case STR_CAPTIONWIDTH:
case STR_CAPTIONHEIGHT:
case STR_SMCAPTIONWIDTH:
case STR_SMCAPTIONHEIGHT:
case STR_MENUWIDTH:
case STR_MENUHEIGHT:
case STR_ICONHORZSPACING:
case STR_ICONVERTSPACING:
case STR_MINWIDTH:
case STR_MINHORZGAP:
case STR_MINVERTGAP:
/*
* Always store window metrics in TWIPS
*/
iIniValue = -MultDiv(iIniValue, 72*20, gpsi->dmLogPixels);
break;
}
return UpdateWinIniInt(pProfileUserName,
PMAP_METRICS,
wKeyNameId,
iIniValue);
}
/***************************************************************************\
* SetWindowMetricFont
*
* History:
\***************************************************************************/
BOOL SetWindowMetricFont(
PUNICODE_STRING pProfileUserName,
UINT idKey,
LPLOGFONT lplf)
{
return FastWriteProfileValue(pProfileUserName,
PMAP_METRICS,
(LPWSTR)UIntToPtr(idKey),
REG_BINARY,
(LPBYTE)lplf,
sizeof(LOGFONTW));
}
/***************************************************************************\
* SetAndDrawNCMetrics
*
* History:
\***************************************************************************/
BOOL xxxSetAndDrawNCMetrics(
PUNICODE_STRING pProfileUserName,
int clNewBorder,
LPNONCLIENTMETRICS lpnc)
{
int dl;
int dxMinOld;
int dyMinOld;
int cxBorder;
int cyBorder;
int dyCaption;
int dyMenu;
dl = clNewBorder - gpsi->gclBorder;
dxMinOld = SYSMET(CXMINIMIZED);
dyMinOld = SYSMET(CYMINIMIZED);
cxBorder = SYSMET(CXBORDER);
cyBorder = SYSMET(CYBORDER);
/*
* Do we need to recalculate?
*/
if (lpnc == NULL && !dl) {
return FALSE;
}
if (lpnc) {
dyCaption = (int)lpnc->iCaptionHeight - SYSMET(CYSIZE);
dyMenu = (int)lpnc->iMenuHeight - SYSMET(CYMENUSIZE);
} else {
dyCaption = dyMenu = 0;
}
/*
* Recalculate the system metrics.
*/
xxxSetWindowNCMetrics(pProfileUserName, lpnc, TRUE, clNewBorder);
/*
* Reset our saved menu size/position info.
*/
MenuRecalc();
/*
* Reset window sized, positions, frames
*/
xxxMetricsRecalc(CALC_FRAME | (dl ? CALC_RESIZE : 0),
dl * cxBorder,
dl * cyBorder,
dyCaption,
dyMenu);
dxMinOld = SYSMET(CXMINIMIZED) - dxMinOld;
dyMinOld = SYSMET(CYMINIMIZED) - dyMinOld;
if (dxMinOld || dyMinOld) {
xxxMetricsRecalc(CALC_MINIMIZE, dxMinOld, dyMinOld, 0, 0);
}
xxxRedrawScreen();
return TRUE;
}
/***************************************************************************\
* xxxSetAndDrawMinMetrics
*
* History:
* 13-May-1994 mikeke mikeke Ported
\***************************************************************************/
BOOL xxxSetAndDrawMinMetrics(
PUNICODE_STRING pProfileUserName,
LPMINIMIZEDMETRICS lpmin)
{
/*
* Save minimized window dimensions.
*/
int dxMinOld = SYSMET(CXMINIMIZED);
int dyMinOld = SYSMET(CYMINIMIZED);
SetMinMetrics(pProfileUserName,lpmin);
/*
* Do we need to adjust minimized size?
*/
dxMinOld = SYSMET(CXMINIMIZED) - dxMinOld;
dyMinOld = SYSMET(CYMINIMIZED) - dyMinOld;
if (dxMinOld || dyMinOld) {
xxxMetricsRecalc(CALC_MINIMIZE, dxMinOld, dyMinOld, 0, 0);
}
xxxRedrawScreen();
return TRUE;
}
/***************************************************************************\
* xxxSPISetNCMetrics
*
* History:
* 13-May-1994 mikeke mikeke Ported
\***************************************************************************/
BOOL xxxSPISetNCMetrics(
PUNICODE_STRING pProfileUserName,
LPNONCLIENTMETRICS lpnc,
BOOL fAlterWinIni)
{
BOOL fWriteAllowed = !fAlterWinIni;
BOOL fChanged = FALSE;
lpnc->iBorderWidth = max(lpnc->iBorderWidth, 1);
lpnc->iBorderWidth = min(lpnc->iBorderWidth, 50);
if (fAlterWinIni) {
fChanged = SetWindowMetricInt(pProfileUserName, STR_BORDERWIDTH, lpnc->iBorderWidth);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_SCROLLWIDTH, lpnc->iScrollWidth);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_SCROLLHEIGHT, lpnc->iScrollHeight);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_CAPTIONWIDTH, lpnc->iCaptionWidth);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_CAPTIONHEIGHT, lpnc->iCaptionHeight);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_SMCAPTIONWIDTH, lpnc->iSmCaptionWidth);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_SMCAPTIONHEIGHT, lpnc->iSmCaptionHeight);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_MENUWIDTH, lpnc->iMenuWidth);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_MENUHEIGHT, lpnc->iMenuHeight);
fChanged &= SetWindowMetricFont(pProfileUserName, STR_CAPTIONFONT, &lpnc->lfCaptionFont);
fChanged &= SetWindowMetricFont(pProfileUserName, STR_SMCAPTIONFONT, &lpnc->lfSmCaptionFont);
fChanged &= SetWindowMetricFont(pProfileUserName, STR_MENUFONT, &lpnc->lfMenuFont);
fChanged &= SetWindowMetricFont(pProfileUserName, STR_STATUSFONT, &lpnc->lfStatusFont);
fChanged &= SetWindowMetricFont(pProfileUserName, STR_MESSAGEFONT, &lpnc->lfMessageFont);
fWriteAllowed = fChanged;
}
if (fWriteAllowed) {
xxxSetAndDrawNCMetrics(pProfileUserName, lpnc->iBorderWidth, lpnc);
}
return fChanged;
}
/***************************************************************************\
* xxxSPISetMinMetrics
*
* History:
* 13-May-1994 mikeke mikeke Ported
\***************************************************************************/
BOOL xxxSPISetMinMetrics(
PUNICODE_STRING pProfileUserName,
LPMINIMIZEDMETRICS lpmin,
BOOL fAlterWinIni)
{
BOOL fWriteAllowed = !fAlterWinIni;
BOOL fChanged = FALSE;
if (fAlterWinIni) {
fChanged = SetWindowMetricInt(pProfileUserName, STR_MINWIDTH, lpmin->iWidth);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_MINHORZGAP, lpmin->iHorzGap);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_MINVERTGAP, lpmin->iVertGap);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_MINARRANGE, lpmin->iArrange);
fWriteAllowed = fChanged;
}
if (fWriteAllowed) {
xxxSetAndDrawMinMetrics(pProfileUserName, lpmin);
}
return fChanged;
}
/***************************************************************************\
* SPISetIconMetrics
*
* History:
* 13-May-1994 mikeke mikeke Ported
\***************************************************************************/
BOOL SPISetIconMetrics(
PUNICODE_STRING pProfileUserName,
LPICONMETRICS lpicon,
BOOL fAlterWinIni)
{
BOOL fWriteAllowed = !fAlterWinIni;
BOOL fChanged = FALSE;
if (fAlterWinIni) {
fChanged = SetWindowMetricInt(pProfileUserName, STR_ICONHORZSPACING, lpicon->iHorzSpacing);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_ICONVERTSPACING, lpicon->iVertSpacing);
fChanged &= SetWindowMetricInt(pProfileUserName, STR_ICONTITLEWRAP, lpicon->iTitleWrap);
fChanged &= SetWindowMetricFont(pProfileUserName, STR_ICONFONT, &lpicon->lfFont);
fWriteAllowed = fChanged;
}
if (fWriteAllowed) {
SetIconMetrics(pProfileUserName,lpicon);
xxxRedrawScreen();
}
return fChanged;
}
/***************************************************************************\
* SPISetIconTitleFont
*
* History:
* 13-May-1994 mikeke mikeke Ported
\***************************************************************************/
BOOL SPISetIconTitleFont(
PUNICODE_STRING pProfileUserName,
LPLOGFONT lplf,
BOOL fAlterWinIni)
{
HFONT hfnT;
BOOL fWriteAllowed = !fAlterWinIni;
BOOL fWinIniChanged = FALSE;
if (hfnT = CreateFontFromWinIni(pProfileUserName,lplf, STR_ICONFONT)) {
if (fAlterWinIni) {
if (lplf) {
LOGFONT lf;
GreExtGetObjectW(hfnT, sizeof(LOGFONTW), &lf);
fWinIniChanged = SetWindowMetricFont(pProfileUserName, STR_ICONFONT, &lf);
} else {
/*
* !lParam so go back to current win.ini settings.
*/
fWinIniChanged = TRUE;
}
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
if (ghIconFont) {
GreMarkDeletableFont(ghIconFont);
GreDeleteObject(ghIconFont);
}
ghIconFont = hfnT;
} else {
GreMarkDeletableFont(hfnT);
GreDeleteObject(hfnT);
}
}
return fWinIniChanged;
}
/***************************************************************************\
* xxxSetSPIMetrics
*
* History:
* 13-May-1994 mikeke mikeke Ported
\***************************************************************************/
BOOL xxxSetSPIMetrics(
PUNICODE_STRING pProfileUserName,
DWORD wFlag,
LPVOID lParam,
BOOL fAlterWinIni)
{
BOOL fWinIniChanged;
switch (wFlag) {
case SPI_SETANIMATION:
if (fAlterWinIni) {
fWinIniChanged = SetWindowMetricInt(pProfileUserName,
STR_MINANIMATE,
(int)((LPANIMATIONINFO)lParam)->iMinAnimate);
if (!fWinIniChanged) {
return FALSE;
}
} else {
fWinIniChanged = FALSE;
}
SET_OR_CLEAR_PUDF(PUDF_ANIMATE, ((LPANIMATIONINFO)lParam)->iMinAnimate);
return fWinIniChanged;
case SPI_SETNONCLIENTMETRICS:
return xxxSPISetNCMetrics(pProfileUserName, (LPNONCLIENTMETRICS)lParam, fAlterWinIni);
case SPI_SETICONMETRICS:
return SPISetIconMetrics(pProfileUserName, (LPICONMETRICS)lParam, fAlterWinIni);
case SPI_SETMINIMIZEDMETRICS:
return xxxSPISetMinMetrics(pProfileUserName, (LPMINIMIZEDMETRICS)lParam, fAlterWinIni);
case SPI_SETICONTITLELOGFONT:
return SPISetIconTitleFont(pProfileUserName, (LPLOGFONT)lParam, fAlterWinIni);
default:
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "SetSPIMetrics. Invalid wFlag: 0x%x", wFlag);
return FALSE;
}
}
/***************************************************************************\
* SetFilterKeys
*
* History:
* 10-12-94 JimA Created.
\***************************************************************************/
BOOL SetFilterKeys(
PUNICODE_STRING pProfileUserName,
LPFILTERKEYS pFilterKeys)
{
LPWSTR pwszd = L"%d";
BOOL fWinIniChanged;
WCHAR szTemp[40];
swprintf(szTemp, pwszd, pFilterKeys->dwFlags);
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
PMAP_KEYBOARDRESPONSE,
L"Flags",
szTemp);
swprintf(szTemp, pwszd, pFilterKeys->iWaitMSec);
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
PMAP_KEYBOARDRESPONSE,
L"DelayBeforeAcceptance",
szTemp);
swprintf(szTemp, pwszd, pFilterKeys->iDelayMSec);
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
PMAP_KEYBOARDRESPONSE,
L"AutoRepeatDelay",
szTemp);
swprintf(szTemp, pwszd, pFilterKeys->iRepeatMSec);
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
PMAP_KEYBOARDRESPONSE,
L"AutoRepeatRate",
szTemp);
swprintf(szTemp, pwszd, pFilterKeys->iBounceMSec);
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
PMAP_KEYBOARDRESPONSE,
L"BounceTime",
szTemp);
return fWinIniChanged;
}
/***************************************************************************\
* SetMouseKeys
*
* History:
* 10-12-94 JimA Created.
\***************************************************************************/
BOOL SetMouseKeys(
PUNICODE_STRING pProfileUserName,
LPMOUSEKEYS pMK)
{
LPWSTR pwszd = L"%d";
BOOL fWinIniChanged;
WCHAR szTemp[40];
swprintf(szTemp, pwszd, pMK->dwFlags);
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
PMAP_MOUSEKEYS,
L"Flags",
szTemp);
swprintf(szTemp, pwszd, pMK->iMaxSpeed);
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
PMAP_MOUSEKEYS,
L"MaximumSpeed",
szTemp);
swprintf(szTemp, pwszd, pMK->iTimeToMaxSpeed);
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
PMAP_MOUSEKEYS,
L"TimeToMaximumSpeed",
szTemp);
return fWinIniChanged;
}
/***************************************************************************\
* SetSoundSentry
*
* History:
* 10-12-94 JimA Created.
\***************************************************************************/
BOOL SetSoundSentry(
PUNICODE_STRING pProfileUserName,
LPSOUNDSENTRY pSS)
{
LPWSTR pwszd = L"%d";
BOOL fWinIniChanged;
WCHAR szTemp[40];
swprintf(szTemp, pwszd, pSS->dwFlags);
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
PMAP_SOUNDSENTRY,
L"Flags",
szTemp);
swprintf(szTemp, pwszd, pSS->iFSTextEffect);
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
PMAP_SOUNDSENTRY,
L"TextEffect",
szTemp);
swprintf(szTemp, pwszd, pSS->iWindowsEffect);
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
PMAP_SOUNDSENTRY,
L"WindowsEffect",
szTemp);
return fWinIniChanged;
}
/***************************************************************************\
* CalculateMouseSensitivity
*
* The resultant table looks like this...
*
* Sens | Sensitivity Adjustment
* 0 | 0 * SENS_SCALAR ALGORITHM 0<=NUM<=2
* 1 | 1/32 * SENS_SCALAR (NUM/32)*SENS_SCALAR
* 2 | 1/16 * SENS_SCALAR
* 3 | 1/8 * SENS_SCALAR ALGORITHM 3<=NUM<=10
* 4 | 1/4 (2/8) * SENS_SCALAR ((NUM-2)/8)*SENS_SCALAR
* 5 | 3/8 * SENS_SCALAR
* 6 | 1/2 (4/8) * SENS_SCALAR
* 7 | 5/8 * SENS_SCALAR
* 8 | 3/4 (6/8) * SENS_SCALAR
* 9 | 7/8 * SENS_SCALAR
* 10 | 1 * SENS_SCALAR
* 11 | 5/4 * SENS_SCALAR ALGORITHM NUM>=11
* 12 | 3/2 (6/4) * SENS_SCALAR ((NUM-6)/4)*SENS_SCALAR
* 13 | 7/4 * SENS_SCALAR
* 14 | 2 (8/4) * SENS_SCALAR
* 15 | 9/4 * SENS_SCALAR
* 16 | 5/2 (10/4) * SENS_SCALAR
* 17 | 11/4 * SENS_SCALAR
* 18 | 3 (12/4) * SENS_SCALAR
* 19 | 13/4 * SENS_SCALAR
* 20 | 7/2 (14/4) * SENS_SCALAR
*
* COMMENTS: Sensitivities are constrained to be between 1 and 20.
*
* History:
* 09-27-96 jparsons Created.
\***************************************************************************/
LONG CalculateMouseSensitivity(
LONG lSens)
{
LONG lSenFactor;
if (lSens <= 2) {
lSenFactor = lSens * 256 / 32;
} else if (lSens >= 3 && lSens <= 10 ) {
lSenFactor = (lSens - 2) * 256 /8;
} else {
lSenFactor= (lSens - 6) * 256 / 4;
}
return lSenFactor;
}
/***************************************************************************\
* xxxSystemParametersInfo
*
* SPI_GETBEEP: wParam is not used. lParam is long pointer to a boolean which
* gets true if beep on, false if beep off.
*
* SPI_SETBEEP: wParam is a bool which sets beep on (true) or off (false).
* lParam is not used.
*
* SPI_GETMOUSE: wParam is not used. lParam is long pointer to an integer
* array where rgw[0] gets xMouseThreshold, rgw[1] gets
* yMouseThreshold, and rgw[2] gets gMouseSpeed.
*
* SPI_SETMOUSE: wParam is not used. lParam is long pointer to an integer
* array as described above. User's values are set to values
* in array.
*
* SPI_GETBORDER: wParam is not used. lParam is long pointer to an integer
* which gets the value of clBorder (border multiplier factor).
*
* SPI_SETBORDER: wParam is an integer which sets gpsi->gclBorder.
* lParam is not used.
*
* SPI_GETKEYBOARDDELAY: wParam is not used. lParam is a long pointer to an int
* which gets the current keyboard repeat delay setting.
*
* SPI_SETKEYBOARDDELAY: wParam is the new keyboard delay setting.
* lParam is not used.
*
* SPI_GETKEYBOARDSPEED: wParam is not used. lParam is a long pointer
* to an int which gets the current keyboard repeat
* speed setting.
*
* SPI_SETKEYBOARDSPEED: wParam is the new keyboard speed setting.
* lParam is not used.
*
* SPI_KANJIMENU: wParam contains:
* 1 - Mouse accelerator
* 2 - ASCII accelerator
* 3 - Kana accelerator
* lParam is not used. The wParam value is stored in the global
* KanjiMenu for use in accelerator displaying & searching.
*
* SPI_LANGDRIVER: wParam is not used.
* lParam contains a LPSTR to the new language driver filename.
*
* SPI_ICONHORIZONTALSPACING: wParam is the width in pixels of an icon cell.
*
* SPI_ICONVERTICALSPACING: wParam is the height in pixels of an icon cell.
*
* SPI_GETSCREENSAVETIMEOUT: wParam is not used
* lParam is a pointer to an int which gets the screen saver
* timeout value.
*
* SPI_SETSCREENSAVETIMEOUT: wParam is the time in seconds for the system
* to be idle before screensaving.
*
* SPI_GETSCREENSAVEACTIVE: lParam is a pointer to a BOOL which gets TRUE
* if the screensaver is active else gets false.
*
* SPI_SETSCREENSAVEACTIVE: if wParam is TRUE, screensaving is activated
* else it is deactivated.
*
*
* SPI_SETBLOCKSENDINPUTRESETS:
* SPI_GETBLOCKSENDINPUTRESETS:
* wParam is BOOL signifying if this is active or not.
*
* SPI_GETLOWPOWERTIMEOUT:
* SPI_GETPOWEROFFTIMEOUT: wParam is not used
* lParam is a pointer to an int which gets the appropriate
* power saving screen blanker timeout value.
*
* SPI_SETLOWPOWERTIMEOUT:
* SPI_SETPOWEROFFTIMEOUT: wParam is the time in seconds for the system
* to be idle before power saving screen blanking.
*
* SPI_GETLOWPOWERACTIVE:
* SPI_GETPOWEROFFACTIVE: lParam is a pointer to a BOOL which gets TRUE
* if the power saving screen blanker is active else gets false.
*
* SPI_SETLOWPOWERACTIVE:
* SPI_SETPOWEROFFACTIVE: if wParam is TRUE, power saving screen blanking is
* activated else it is deactivated.
*
* SPI_GETGRIDGRANULARITY: Obsolete. Returns 1 always.
*
* SPI_SETGRIDGRANULARITY: Obsolete. Does nothing.
*
* SPI_SETDESKWALLPAPER: wParam is not used; lParam is a long ptr to a string
* that holds the name of the bitmap file to be used as the
* desktop wall paper.
*
* SPI_SETDESKPATTERN: Both wParam and lParam are not used; USER will read the
* "pattern=" from WIN.INI and make it as the current desktop
* pattern;
*
* SPI_GETICONTITLEWRAP: lParam is LPINT which gets 0 if wrapping if off
* else gets 1.
*
* SPI_SETICONTITLEWRAP: wParam specifies TRUE to turn wrapping on else false
*
* SPI_GETMENUDROPALIGNMENT: lParam is LPINT which gets 0 specifies if menus
* drop left aligned else 1 if drop right aligned.
*
* SPI_SETMENUDROPALIGNMENT: wParam 0 specifies if menus drop left aligned else
* the drop right aligned.
*
* SPI_SETDOUBLECLKWIDTH: wParam specifies the width of the rectangle
* within which the second click of a double click must fall
* for it to be registered as a double click.
*
* SPI_SETDOUBLECLKHEIGHT: wParam specifies the height of the rectangle
* within which the second click of a double click must fall
* for it to be registered as a double click.
*
* SPI_GETICONTITLELOGFONT: lParam is a pointer to a LOGFONT struct which
* gets the logfont for the current icon title font. wParam
* specifies the size of the logfont struct.
*
* SPI_SETDOUBLECLICKTIME: wParm specifies the double click time
*
* SPI_SETMOUSEBUTTONSWAP: if wParam is 1, swap mouse buttons else if wParam
* is 0, don't swap buttons
* SPI_SETDRAGFULLWINDOWS: wParam = fSet.
* SPI_GETDRAGFULLWINDOWS: returns fSet.
*
* SPI_GETFILTERKEYS: lParam is a pointer to a FILTERKEYS struct. wParam
* specifies the size of the filterkeys struct.
*
* SPI_SETFILTERKEYS: lParam is a pointer to a FILTERKEYS struct. wParam
* is not used.
*
* SPI_GETSTICKYKEYS: lParam is a pointer to a STICKYKEYS struct. wParam
* specifies the size of the stickykeys struct.
*
* SPI_SETSTICKYKEYS: lParam is a pointer to a STICKYKEYS struct. wParam
* is not used.
*
* SPI_GETMOUSEKEYS: lParam is a pointer to a MOUSEKEYS struct. wParam
* specifies the size of the mousekeys struct.
*
* SPI_SETMOUSEKEYS: lParam is a pointer to a MOUSEKEYS struct. wParam
* is not used.
*
* SPI_GETACCESSTIMEOUT: lParam is a pointer to an ACCESSTIMEOUT struct.
* wParam specifies the size of the accesstimeout struct.
*
* SPI_SETACCESSTIMEOUT: lParam is a pointer to a ACCESSTIMEOUT struct.
* wParam is not used.
*
* SPI_GETTOGGLEKEYS: lParam is a pointer to a TOGGLEKEYS struct. wParam
* specifies the size of the togglekeys struct.
*
* SPI_SETTOGGLEKEYS: lParam is a pointer to a TOGGLEKEYS struct. wParam
* is not used.
*
* SPI_GETKEYBOARDPREF: lParam is a pointer to a BOOL.
* wParam is not used.
*
* SPI_SETKEYBOARDPREF: wParam is a BOOL.
* lParam is not used.
*
* SPI_GETSCREENREADER: lParam is a pointer to a BOOL.
* wParam is not used.
*
* SPI_SETSCREENREADER: wParam is a BOOL.
* lParam is not used.
*
* SPI_GETSHOWSOUNDS: lParam is a pointer to a SHOWSOUNDS struct. wParam
* specifies the size of the showsounds struct.
*
* SPI_SETSHOWSOUNDS: lParam is a pointer to a SHOWSOUNDS struct. wParam
* is not used.
*
* SPI_GETNONCLIENTMETRICS: lParam is a pointer to a NONCLIENTMETRICSW struct.
* wPAram is not used.
*
* SPI_GETSNAPTODEFBUTTON: lParam is a pointer to a BOOL which gets TRUE
* if the snap to default push button is active else gets false.
*
* SPI_SETSNAPTODEFBUTTON: if wParam is TRUE, dialog boxes will snap the mouse
* pointer to the default push button when created.
*
* SPI_GETFONTSMOOTHING:
* wParam is unused
* lParam is LPINT for boolean fFontSmoothing
*
* SPI_SETFONTSMOOTHING:
* wParam is INT for boolean fFontSmoothing
*
* SPI_GETWHEELSCROLLLINES: lParam is a pointer to a ULONG to receive the
* suggested number of lines to scroll when the wheel is
* rotated. wParam is unused.
*
* SPI_SETWHEELSCROLLLINES: wParam is a ULONG containing the suggested number
* of lines to scroll when the wheel is rotated. lParam is
* unused.
*
* SPI_SETSCREENSAVERRUNNING / SPI_SCREENSAVERRUNNING: not supported on NT.
* SPI_GETSCREENSAVERRUNNING: wParam - Not used. lParam a pointer to a BOOL which
* will receive TRUE is a screen saver is running or FALSE otherwise.
*
* SPI_SETSHOWIMEUI wParam is TRUE or FALSE
* SPI_GETSHOWIMEUI neither wParam or lParam used
*
* History:
* 06-28-91 MikeHar Ported.
* 12-8-93 SanfordS Added SPI_SET/GETDRAGFULLWINDOWS
* 20-May-1996 adams Added SPI_SET/GETWHEELSCROLLLINES
* 02-Feb-2002 MMcCr Added SPI_SET/GETBLOCKSENDINPUTRESETS
\***************************************************************************/
BOOL xxxSystemParametersInfo(
UINT wFlag,
DWORD wParam,
PVOID lParam,
UINT flags)
{
PPROCESSINFO ppi = PpiCurrent();
LPWSTR pwszd = L"%d";
WCHAR szSection[40];
WCHAR szTemp[40];
WCHAR szPat[MAX_PATH];
BOOL fWinIniChanged = FALSE;
BOOL fAlterWinIni = ((flags & SPIF_UPDATEINIFILE) != 0);
BOOL fSendWinIniChange = ((flags & SPIF_SENDCHANGE) != 0);
BOOL fWriteAllowed = !fAlterWinIni;
ACCESS_MASK amRequest;
LARGE_UNICODE_STRING strSection;
int *piTimeOut;
int iResID;
TL tlName;
PUNICODE_STRING pProfileUserName = NULL;
UserAssert(IsWinEventNotifyDeferredOK());
/*
* CONSIDER(adams): Many of the SPI_GET* could be implemented
* on the client side (SnapTo, WheelScrollLines, etc.).
*/
/*
* Features not implemented.
*/
switch (wFlag) {
case SPI_TIMEOUTS:
case SPI_KANJIMENU:
case SPI_LANGDRIVER:
case SPI_UNUSED39:
case SPI_UNUSED40:
case SPI_SETPENWINDOWS:
case SPI_GETWINDOWSEXTENSION:
case SPI_SETSCREENSAVERRUNNING: // same as SPI_SCREENSAVERRUNNING
case SPI_GETSERIALKEYS:
case SPI_SETSERIALKEYS:
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"SPI_ 0x%lx parameter not supported", wFlag);
return FALSE;
}
/*
* Perform access check. Always grant access to CSR.
*/
if (ppi->Process != gpepCSRSS) {
switch (wFlag) {
case SPI_SETBEEP:
case SPI_SETMOUSE:
case SPI_SETBORDER:
case SPI_SETKEYBOARDSPEED:
case SPI_SETDEFAULTINPUTLANG:
case SPI_SETSCREENSAVETIMEOUT:
case SPI_SETSCREENSAVEACTIVE:
case SPI_SETBLOCKSENDINPUTRESETS:
case SPI_SETLOWPOWERTIMEOUT:
case SPI_SETPOWEROFFTIMEOUT:
case SPI_SETLOWPOWERACTIVE:
case SPI_SETPOWEROFFACTIVE:
case SPI_SETGRIDGRANULARITY:
case SPI_SETDESKWALLPAPER:
case SPI_SETDESKPATTERN:
case SPI_SETKEYBOARDDELAY:
case SPI_SETICONTITLEWRAP:
case SPI_SETMENUDROPALIGNMENT:
case SPI_SETDOUBLECLKWIDTH:
case SPI_SETDOUBLECLKHEIGHT:
case SPI_SETDOUBLECLICKTIME:
case SPI_SETMOUSEBUTTONSWAP:
case SPI_SETICONTITLELOGFONT:
case SPI_SETFASTTASKSWITCH:
case SPI_SETFILTERKEYS:
case SPI_SETTOGGLEKEYS:
case SPI_SETMOUSEKEYS:
case SPI_SETSHOWSOUNDS:
case SPI_SETSTICKYKEYS:
case SPI_SETACCESSTIMEOUT:
case SPI_SETSOUNDSENTRY:
case SPI_SETKEYBOARDPREF:
case SPI_SETSCREENREADER:
case SPI_SETSNAPTODEFBUTTON:
case SPI_SETANIMATION:
case SPI_SETNONCLIENTMETRICS:
case SPI_SETICONMETRICS:
case SPI_SETMINIMIZEDMETRICS:
case SPI_SETWORKAREA:
case SPI_SETFONTSMOOTHING:
case SPI_SETMOUSEHOVERWIDTH:
case SPI_SETMOUSEHOVERHEIGHT:
case SPI_SETMOUSEHOVERTIME:
case SPI_SETWHEELSCROLLLINES:
case SPI_SETMENUSHOWDELAY:
case SPI_SETHIGHCONTRAST:
case SPI_SETDRAGFULLWINDOWS:
case SPI_SETDRAGWIDTH:
case SPI_SETDRAGHEIGHT:
case SPI_SETCURSORS:
case SPI_SETICONS:
case SPI_SETLANGTOGGLE:
amRequest = WINSTA_WRITEATTRIBUTES;
break;
case SPI_ICONHORIZONTALSPACING:
case SPI_ICONVERTICALSPACING:
if (IS_PTR(lParam)) {
amRequest = WINSTA_READATTRIBUTES;
} else if (wParam) {
amRequest = WINSTA_WRITEATTRIBUTES;
} else {
return TRUE;
}
break;
default:
if ((wFlag & SPIF_RANGETYPEMASK) && (wFlag & SPIF_SET)) {
amRequest = WINSTA_WRITEATTRIBUTES;
} else {
amRequest = WINSTA_READATTRIBUTES;
}
break;
}
if (amRequest == WINSTA_READATTRIBUTES) {
RETURN_IF_ACCESS_DENIED(ppi->amwinsta, amRequest, FALSE);
} else {
UserAssert(amRequest == WINSTA_WRITEATTRIBUTES);
if (!CheckWinstaWriteAttributesAccess()) {
return FALSE;
}
}
/*
* If we're reading, then set the write flag to ensure that the
* return value will be TRUE.
*/
if (amRequest == WINSTA_READATTRIBUTES) {
fWriteAllowed = TRUE;
}
} else {
fWriteAllowed = TRUE;
}
/*
* Make sure the section buffer is terminated.
*/
szSection[0] = 0;
switch (wFlag) {
case SPI_GETBEEP:
(*(BOOL *)lParam) = TEST_BOOL_PUDF(PUDF_BEEP);
break;
case SPI_SETBEEP:
if (fAlterWinIni) {
ServerLoadString(hModuleWin,
(wParam ? STR_BEEPYES : STR_BEEPNO),
(LPWSTR)szTemp,
10);
fWinIniChanged = FastUpdateWinIni(NULL,
PMAP_BEEP,
STR_BEEP,
szTemp);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SET_OR_CLEAR_PUDF(PUDF_BEEP, wParam);
}
break;
case SPI_SETMOUSESPEED:
if (((LONG_PTR) lParam < MOUSE_SENSITIVITY_MIN) || ((LONG_PTR) lParam > MOUSE_SENSITIVITY_MAX)) {
return FALSE;
}
if (fAlterWinIni) {
swprintf(szTemp, pwszd, lParam);
fWinIniChanged = FastUpdateWinIni(NULL,
PMAP_MOUSE,
STR_MOUSESENSITIVITY,
szTemp);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
gMouseSensitivity = PtrToLong(lParam);
gMouseSensitivityFactor = CalculateMouseSensitivity(PtrToLong(lParam));
#ifdef SUBPIXEL_MOUSE
ResetMouseAccelerationCurves();
#endif // SUBPIXEL_MOUSE
}
break;
case SPI_GETMOUSESPEED:
*((LPINT)lParam) = gMouseSensitivity;
break;
case SPI_SETMOUSETRAILS:
if (fAlterWinIni) {
swprintf(szTemp, pwszd, wParam);
fWinIniChanged = FastUpdateWinIni(NULL,
PMAP_MOUSE,
STR_MOUSETRAILS,
szTemp);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SetMouseTrails(wParam);
}
break;
case SPI_GETMOUSETRAILS:
*((LPINT)lParam) = gMouseTrails ? gMouseTrails + 1 : gMouseTrails;
break;
case SPI_GETMOUSE:
((LPINT)lParam)[0] = gMouseThresh1;
((LPINT)lParam)[1] = gMouseThresh2;
((LPINT)lParam)[2] = gMouseSpeed;
break;
case SPI_SETMOUSE:
if (fAlterWinIni) {
BOOL bWritten1, bWritten2, bWritten3;
pProfileUserName = CreateProfileUserName(&tlName);
bWritten1 = UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSETHRESH1, ((LPINT)lParam)[0]);
bWritten2 = UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSETHRESH2, ((LPINT)lParam)[1]);
bWritten3 = UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSESPEED, ((LPINT)lParam)[2]);
if (bWritten1 && bWritten2 && bWritten3) {
fWinIniChanged = TRUE;
} else {
/*
* Attempt to backout any changes.
*/
if (bWritten1) {
UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSETHRESH1, gMouseThresh1);
}
if (bWritten2) {
UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSETHRESH2, gMouseThresh2);
}
if (bWritten3) {
UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSESPEED, gMouseSpeed);
}
}
fWriteAllowed = fWinIniChanged;
FreeProfileUserName(pProfileUserName, &tlName);
}
if (fWriteAllowed) {
gMouseThresh1 = ((LPINT)lParam)[0];
gMouseThresh2 = ((LPINT)lParam)[1];
gMouseSpeed = ((LPINT)lParam)[2];
}
break;
case SPI_GETSNAPTODEFBUTTON:
(*(LPBOOL)lParam) = TEST_BOOL_PUSIF(PUSIF_SNAPTO);
break;
case SPI_SETSNAPTODEFBUTTON:
wParam = (wParam != 0);
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_SNAPTO, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SET_OR_CLEAR_PUSIF(PUSIF_SNAPTO, wParam);
}
break;
case SPI_GETBORDER:
(*(LPINT)lParam) = gpsi->gclBorder;
break;
case SPI_SETBORDER:
wParam = max((int)wParam, 1);
wParam = min(wParam, 50);
if (wParam == gpsi->gclBorder) {
/*
* If border size doesn't change, don't waste time.
*/
break;
}
pProfileUserName = CreateProfileUserName(&tlName);
if (fAlterWinIni) {
fWinIniChanged = SetWindowMetricInt(pProfileUserName, STR_BORDERWIDTH, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
xxxSetAndDrawNCMetrics(pProfileUserName, wParam, NULL);
/*
* Nice magic number of 3. So if the border is set to 1, there
* are actualy 4 pixels in the border.
*/
bSetDevDragWidth(gpDispInfo->hDev, gpsi->gclBorder + BORDER_EXTRA);
}
FreeProfileUserName(pProfileUserName, &tlName);
break;
case SPI_GETFONTSMOOTHING:
(*(LPINT)lParam) = !!(GreGetFontEnumeration() & FE_AA_ON);
break;
case SPI_SETFONTSMOOTHING:
if (CheckDesktopPolicy(NULL, (PCWSTR)STR_FONTSMOOTHING)) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
wParam = (wParam ? FE_AA_ON : 0);
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_DESKTOP, STR_FONTSMOOTHING, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
GreSetFontEnumeration(wParam | FE_SET_AA);
}
break;
case SPI_GETKEYBOARDSPEED:
(*(int *)lParam) = (gnKeyboardSpeed & KSPEED_MASK);
break;
case SPI_SETKEYBOARDSPEED:
/*
* Limit the range to max value; SetKeyboardRate takes both speed
* and delay.
*/
if (wParam > KSPEED_MASK) { // KSPEED_MASK == KSPEED_MAX
wParam = KSPEED_MASK;
}
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_KEYBOARD, STR_KEYSPEED, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
gnKeyboardSpeed = (gnKeyboardSpeed & ~KSPEED_MASK) | wParam;
SetKeyboardRate(gnKeyboardSpeed);
}
break;
case SPI_GETKEYBOARDDELAY:
(*(int *)lParam) = (gnKeyboardSpeed & KDELAY_MASK) >> KDELAY_SHIFT;
break;
case SPI_SETKEYBOARDDELAY:
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_KEYBOARD, STR_KEYDELAY, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
gnKeyboardSpeed = (gnKeyboardSpeed & ~KDELAY_MASK) | (wParam << KDELAY_SHIFT);
SetKeyboardRate(gnKeyboardSpeed);
}
break;
case SPI_SETLANGTOGGLE:
/*
* wParam unused, lParam unused. Simply reread the registry setting.
*/
return GetKbdLangSwitch(NULL);
break;
case SPI_GETDEFAULTINPUTLANG:
/*
* wParam unused. lParam is a pointer to buffer to store hkl.
*/
UserAssert(gspklBaseLayout != NULL);
(*(HKL *)lParam) = gspklBaseLayout->hkl;
break;
case SPI_SETDEFAULTINPUTLANG: {
PKL pkl;
/*
* wParam unused. lParam is new language of hkl (depending on
* whether the hiword is set).
*/
pkl = HKLtoPKL(PtiCurrent(), *(HKL *)lParam);
if (pkl == NULL) {
return FALSE;
}
if (fWriteAllowed) {
Lock(&gspklBaseLayout, pkl);
}
break;
}
case SPI_ICONHORIZONTALSPACING:
if (IS_PTR(lParam)) {
*(LPINT)lParam = SYSMET(CXICONSPACING);
} else if (wParam) {
/*
* Make sure icon spacing is reasonable.
*/
wParam = max(wParam, (DWORD)SYSMET(CXICON));
if (fAlterWinIni) {
fWinIniChanged = SetWindowMetricInt(NULL, STR_ICONHORZSPACING, wParam );
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SYSMET(CXICONSPACING) = (UINT)wParam;
}
}
break;
case SPI_ICONVERTICALSPACING:
if (IS_PTR(lParam)) {
*(LPINT)lParam = SYSMET(CYICONSPACING);
} else if (wParam) {
wParam = max(wParam, (DWORD)SYSMET(CYICON));
if (fAlterWinIni) {
fWinIniChanged = SetWindowMetricInt(NULL, STR_ICONVERTSPACING, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SYSMET(CYICONSPACING) = (UINT)wParam;
}
}
break;
case SPI_GETSCREENSAVETIMEOUT:
piTimeOut = &giScreenSaveTimeOutMs;
goto HandleGetTimeouts;
case SPI_GETLOWPOWERTIMEOUT:
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD1))) {
return FALSE;
}
piTimeOut = &giLowPowerTimeOutMs;
goto HandleGetTimeouts;
case SPI_GETPOWEROFFTIMEOUT:
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3))) {
return FALSE;
}
piTimeOut = &giPowerOffTimeOutMs;
HandleGetTimeouts:
/*
* If the screen saver is disabled, store this fact as a negative
* time out value (we give the Control Panel the absolute value
* of the screen saver time out). We store this in milliseconds.
*/
if (*piTimeOut < 0) {
(*(int *)lParam) = -*piTimeOut / 1000;
} else {
(*(int *)lParam) = *piTimeOut / 1000;
}
break;
case SPI_SETSCREENSAVETIMEOUT:
piTimeOut = &giScreenSaveTimeOutMs;
iResID = STR_SCREENSAVETIMEOUT;
goto HandleSetTimeouts;
case SPI_SETLOWPOWERTIMEOUT:
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD1))) {
return FALSE;
}
piTimeOut = &giLowPowerTimeOutMs;
iResID = STR_LOWPOWERTIMEOUT;
goto HandleSetTimeouts;
case SPI_SETPOWEROFFTIMEOUT:
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3))) {
return FALSE;
}
piTimeOut = &giPowerOffTimeOutMs;
iResID = STR_POWEROFFTIMEOUT;
HandleSetTimeouts:
if (gfSwitchInProgress) {
return FALSE;
}
/*
* Maintain the screen save active/inactive state when setting the
* time out value. Timeout value is given in seconds but stored
* in milliseconds
*/
if (CheckDesktopPolicy(NULL, (PCWSTR)IntToPtr(iResID))) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_DESKTOP, iResID, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
if (glinp.dwFlags & LINP_POWERTIMEOUTS) {
// Call video driver here to exit power down mode.
// KdPrint(("Exit video power down mode\n"));
DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0);
}
glinp.dwFlags &= ~LINP_INPUTTIMEOUTS;
if (!gbBlockSendInputResets) {
glinp.timeLastInputMessage = NtGetTickCount();
}
if (*piTimeOut < 0) {
*piTimeOut = -((int)wParam);
} else {
*piTimeOut = wParam;
}
*piTimeOut *= 1000;
}
break;
case SPI_GETBLOCKSENDINPUTRESETS:
(*(BOOL *)lParam) = (gbBlockSendInputResets != 0);
break;
case SPI_GETSCREENSAVEACTIVE:
(*(BOOL *)lParam) = (giScreenSaveTimeOutMs > 0);
break;
case SPI_GETLOWPOWERACTIVE:
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD1))) {
return FALSE;
}
(*(BOOL *)lParam) = (giLowPowerTimeOutMs > 0);
break;
case SPI_GETPOWEROFFACTIVE:
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3))) {
return FALSE;
}
(*(BOOL *)lParam) = (giPowerOffTimeOutMs > 0);
break;
case SPI_SETSCREENSAVEACTIVE:
piTimeOut = &giScreenSaveTimeOutMs;
iResID = STR_SCREENSAVEACTIVE;
goto HandleSetActive;
case SPI_SETLOWPOWERACTIVE:
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD1))) {
return FALSE;
}
piTimeOut = &giLowPowerTimeOutMs;
iResID = STR_LOWPOWERACTIVE;
goto HandleSetActive;
case SPI_SETPOWEROFFACTIVE:
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3))) {
return FALSE;
}
piTimeOut = &giPowerOffTimeOutMs;
iResID = STR_POWEROFFACTIVE;
HandleSetActive:
if (gfSwitchInProgress) {
return FALSE;
}
wParam = (wParam != 0);
if (CheckDesktopPolicy(NULL, (PCWSTR)IntToPtr(iResID))) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_DESKTOP, iResID, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
if (glinp.dwFlags & LINP_POWERTIMEOUTS) {
// Call video driver here to exit power down mode.
// KdPrint(("Exit video power down mode\n"));
DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0);
}
glinp.dwFlags &= ~LINP_INPUTTIMEOUTS;
if (!gbBlockSendInputResets) {
glinp.timeLastInputMessage = NtGetTickCount();
}
if ((*piTimeOut < 0 && wParam) ||
(*piTimeOut >= 0 && !wParam)) {
*piTimeOut = -*piTimeOut;
}
}
break;
case SPI_SETBLOCKSENDINPUTRESETS:
wParam = (wParam != 0);
if (CheckDesktopPolicy(NULL, (PCWSTR)IntToPtr(STR_BLOCKSENDINPUTRESETS))) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_DESKTOP, STR_BLOCKSENDINPUTRESETS, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
gbBlockSendInputResets = wParam;
}
break;
case SPI_SETDESKWALLPAPER:
pProfileUserName = CreateProfileUserName(&tlName);
if (CheckDesktopPolicy(pProfileUserName, (PCWSTR)STR_DTBITMAP)) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
if (fAlterWinIni) {
if (wParam != (WPARAM)-1) {
/*
* Save current wallpaper in case of failure.
*
* Unlike the rest of the per-user settings that got updated
* in xxxUpdatePerUserSystemParameters, the wallpaper is
* being updated via a direct call to SystemParametersInfo
* from UpdatePerUserSystemParameters. Force remote settings
* check in this case.
*/
FastGetProfileStringFromIDW(pProfileUserName,
PMAP_DESKTOP,
STR_DTBITMAP,
TEXT(""),
szPat,
ARRAY_SIZE(szPat),
POLICY_REMOTE);
fWinIniChanged = FastUpdateWinIni(pProfileUserName,
PMAP_DESKTOP,
STR_DTBITMAP,
(LPWSTR)lParam);
fWriteAllowed = fWinIniChanged;
} else {
fWriteAllowed = TRUE;
}
}
if (fWriteAllowed) {
if (xxxSetDeskWallpaper(pProfileUserName,(LPWSTR)lParam)) {
if (grpdeskRitInput) {
xxxInternalInvalidate(grpdeskRitInput->pDeskInfo->spwnd,
HRGN_FULL,
RDW_INVALIDATE |
RDW_ERASE |
RDW_FRAME |
RDW_ALLCHILDREN);
}
} else if (fAlterWinIni && (wParam != 0xFFFFFFFF)) {
/*
* Backout any change to win.ini.
*/
FastUpdateWinIni(pProfileUserName,PMAP_DESKTOP, STR_DTBITMAP, szPat);
fWinIniChanged = FALSE;
fWriteAllowed = fWinIniChanged;
} else if (!fAlterWinIni) {
/*
* Bug 304109 - joejo
* Make sure we return a 0 retval if we didn't do anything!
*/
fWinIniChanged = FALSE;
fWriteAllowed = fWinIniChanged;
}
}
FreeProfileUserName(pProfileUserName, &tlName);
break;
case SPI_GETDESKWALLPAPER:
/*
* Get the string from the gobal var, not the registry, as it's
* more current.
*/
if (gpszWall != NULL) {
/*
* Copy the global wallpaper name ONLY if noni-null.
*/
wcscpy(lParam, gpszWall);
} else {
/*
* Null out the string so no garbage can corrupt the user's
* buffer.
*/
(*(LPWSTR)lParam) = (WCHAR)0;
}
break;
case SPI_SETDESKPATTERN: {
BOOL fRet;
if (wParam == -1 && lParam != 0) {
return FALSE;
}
pProfileUserName = CreateProfileUserName(&tlName);
if (CheckDesktopPolicy(pProfileUserName, (PCWSTR)STR_DESKPATTERN)) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
if (fAlterWinIni && wParam != -1) {
/*
* Save the current pattern in case of failure.
*/
FastGetProfileStringFromIDW(pProfileUserName,
PMAP_DESKTOP,
STR_DESKPATTERN,
TEXT(""),
szPat,
ARRAY_SIZE(szPat),
0);
fWinIniChanged = FastUpdateWinIni(pProfileUserName,
PMAP_DESKTOP,
STR_DESKPATTERN,
(LPWSTR)lParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
fRet = xxxSetDeskPattern(pProfileUserName,
wParam == -1 ? (LPWSTR)-1 : (LPWSTR)lParam,
FALSE);
if (!fRet) {
/*
* Back out any change to win.ini.
*/
if (fAlterWinIni && wParam != -1) {
FastUpdateWinIni(pProfileUserName,
PMAP_DESKTOP,
STR_DESKPATTERN,
szPat);
}
FreeProfileUserName(pProfileUserName, &tlName);
return FALSE;
}
}
}
FreeProfileUserName(pProfileUserName, &tlName);
break;
case SPI_GETICONTITLEWRAP:
*((int *)lParam) = TEST_BOOL_PUDF(PUDF_ICONTITLEWRAP);
break;
case SPI_SETICONTITLEWRAP:
wParam = (wParam != 0);
if (fAlterWinIni) {
fWinIniChanged = SetWindowMetricInt(NULL, STR_ICONTITLEWRAP, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SET_OR_CLEAR_PUDF(PUDF_ICONTITLEWRAP, wParam);
xxxMetricsRecalc(CALC_FRAME, 0, 0, 0, 0);
}
break;
case SPI_SETDRAGWIDTH:
if (CheckDesktopPolicy(NULL, (PCWSTR)STR_DRAGWIDTH)) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_DRAGWIDTH, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SYSMET(CXDRAG) = wParam;
}
break;
case SPI_SETDRAGHEIGHT:
if (CheckDesktopPolicy(NULL, (PCWSTR)STR_DRAGHEIGHT)) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_DRAGHEIGHT, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SYSMET(CYDRAG) = wParam;
}
break;
case SPI_GETMENUDROPALIGNMENT:
(*(int *)lParam) = (SYSMET(MENUDROPALIGNMENT));
break;
case SPI_SETMENUDROPALIGNMENT:
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_WINDOWSU, STR_MENUDROPALIGNMENT, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SYSMET(MENUDROPALIGNMENT) = (BOOL)(wParam != 0);
}
break;
case SPI_SETDOUBLECLKWIDTH:
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_DOUBLECLICKWIDTH, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SYSMET(CXDOUBLECLK) = wParam;
}
break;
case SPI_SETDOUBLECLKHEIGHT:
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_DOUBLECLICKHEIGHT, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SYSMET(CYDOUBLECLK) = wParam;
}
break;
case SPI_GETICONTITLELOGFONT:
GreExtGetObjectW(ghIconFont, sizeof(LOGFONTW), lParam);
break;
case SPI_SETICONTITLELOGFONT:
{
if (lParam != NULL) {
if (wParam != sizeof(LOGFONTW)) {
return FALSE;
}
} else if (wParam) {
return FALSE;
}
pProfileUserName = CreateProfileUserName(&tlName);
fWinIniChanged = xxxSetSPIMetrics(pProfileUserName, wFlag, lParam, fAlterWinIni);
FreeProfileUserName(pProfileUserName, &tlName);
if (fAlterWinIni) {
fWriteAllowed = fWinIniChanged;
}
break;
}
case SPI_SETDOUBLECLICKTIME:
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_MOUSE, STR_DBLCLKSPEED, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
_SetDoubleClickTime((UINT)wParam);
}
break;
case SPI_GETANIMATION: {
LPANIMATIONINFO lpai = (LPANIMATIONINFO) lParam;
if (lpai == NULL || wParam != sizeof(ANIMATIONINFO)) {
return FALSE;
}
lpai->cbSize = sizeof(ANIMATIONINFO);
lpai->iMinAnimate = TEST_BOOL_PUDF(PUDF_ANIMATE);
break;
}
case SPI_GETNONCLIENTMETRICS: {
LPNONCLIENTMETRICS lpnc = (LPNONCLIENTMETRICS) lParam;
if (lpnc == NULL) {
return FALSE;
}
GetWindowNCMetrics(lpnc);
break;
}
case SPI_GETMINIMIZEDMETRICS: {
LPMINIMIZEDMETRICS lpmin = (LPMINIMIZEDMETRICS)lParam;
lpmin->cbSize = sizeof(MINIMIZEDMETRICS);
lpmin->iWidth = SYSMET(CXMINIMIZED) - 2 * SYSMET(CXFIXEDFRAME);
lpmin->iHorzGap = SYSMET(CXMINSPACING) - SYSMET(CXMINIMIZED);
lpmin->iVertGap = SYSMET(CYMINSPACING) - SYSMET(CYMINIMIZED);
lpmin->iArrange = SYSMET(ARRANGE);
break;
}
case SPI_GETICONMETRICS: {
LPICONMETRICS lpicon = (LPICONMETRICS)lParam;
lpicon->cbSize = sizeof(ICONMETRICS);
lpicon->iHorzSpacing = SYSMET(CXICONSPACING);
lpicon->iVertSpacing = SYSMET(CYICONSPACING);
lpicon->iTitleWrap = TEST_BOOL_PUDF(PUDF_ICONTITLEWRAP);
GreExtGetObjectW(ghIconFont, sizeof(LOGFONTW), &(lpicon->lfFont));
break;
}
case SPI_SETANIMATION:
case SPI_SETNONCLIENTMETRICS:
case SPI_SETICONMETRICS:
case SPI_SETMINIMIZEDMETRICS:
{
fWinIniChanged = xxxSetSPIMetrics(NULL, wFlag, lParam, fAlterWinIni);
if (fAlterWinIni) {
fWriteAllowed = fWinIniChanged;
}
ServerLoadString(hModuleWin, STR_METRICS, szSection, ARRAY_SIZE(szSection));
break;
}
case SPI_SETMOUSEBUTTONSWAP:
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_SWAPBUTTONS, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
_SwapMouseButton((wParam != 0));
}
break;
case SPI_GETFASTTASKSWITCH:
*((PINT)lParam) = TRUE; // Do the work so we don't anger anybody.
case SPI_SETFASTTASKSWITCH:
RIPMSG0(RIP_WARNING,"SPI_SETFASTTASKSWITCH and SPI_GETFASTTASKSWITCH are obsolete actions.");
break;
case SPI_GETWORKAREA:
CopyRect((LPRECT)lParam, &GetPrimaryMonitor()->rcWork);
break;
case SPI_SETWORKAREA:
{
RECT rcNewWork;
LPRECT lprcNewWork;
PMONITOR pMonitorWork;
lprcNewWork = (LPRECT)lParam;
/*
* Validate Rectangle.
*/
if (lprcNewWork != NULL &&
(lprcNewWork->right < lprcNewWork->left ||
lprcNewWork->bottom < lprcNewWork->top)) {
RIPMSG0(RIP_WARNING, "Bad work rectangle passed to SystemParametersInfo(SPI_SETWORKAREA, ...)\n");
return FALSE;
}
/*
* Figure out which monitor has the working area.
*/
if (!lprcNewWork) {
pMonitorWork = GetPrimaryMonitor();
lprcNewWork = &pMonitorWork->rcMonitor;
} else {
pMonitorWork = _MonitorFromRect(lprcNewWork, MONITOR_DEFAULTTOPRIMARY);
}
/*
* Get new working area, clipped to monitor of course.
*/
if (!IntersectRect(&rcNewWork, lprcNewWork, &pMonitorWork->rcMonitor) ||
!EqualRect(&rcNewWork, lprcNewWork))
{
/*
* Complain.
*/
RIPERR4(
ERROR_INVALID_PARAMETER,
RIP_WARNING,
"Bad work rectangle passed to SystemParametersInfo(SPI_SETWORKAREA, ...) %d, %d, %d, %d",
lprcNewWork->left, lprcNewWork->top, lprcNewWork->right, lprcNewWork->bottom);
return FALSE;
}
if (!EqualRect(&pMonitorWork->rcWork, &rcNewWork)) {
PMONITORRECTS pmr;
/*
* If we are going to reposition windows, remember the old
* monitor positions for xxxDesktopRecalc.
*/
if (wParam) {
pmr = SnapshotMonitorRects();
if (!pmr) {
return FALSE;
}
}
pMonitorWork->rcWork = rcNewWork;
if (pMonitorWork == GetPrimaryMonitor()) {
SetDesktopMetrics();
}
/*
* Reposition windows.
*/
if (wParam) {
TL tlPool;
ThreadLockPool(PtiCurrent(), pmr, &tlPool);
xxxDesktopRecalc(pmr);
ThreadUnlockAndFreePool(PtiCurrent(), &tlPool);
}
fWinIniChanged = TRUE;
}
fWriteAllowed = TRUE;
break;
}
case SPI_SETDRAGFULLWINDOWS:
if (CheckDesktopPolicy(NULL, (PCWSTR)STR_DRAGFULLWINDOWS)) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
wParam = (wParam == 1);
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_DRAGFULLWINDOWS, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SET_OR_CLEAR_PUDF(PUDF_DRAGFULLWINDOWS, wParam);
}
break;
case SPI_GETDRAGFULLWINDOWS:
*((PINT)lParam) = TEST_BOOL_PUDF(PUDF_DRAGFULLWINDOWS);
break;
case SPI_GETFILTERKEYS:
{
LPFILTERKEYS pFK = (LPFILTERKEYS)lParam;
int cbSkip = sizeof(gFilterKeys.cbSize);
if (wParam != 0 && wParam != sizeof(FILTERKEYS)) {
return FALSE;
}
if (!pFK || pFK->cbSize != sizeof(FILTERKEYS)) {
return FALSE;
}
/*
* In the future we may support multiple sizes of this data
* structure. Don't change the cbSize field of the data
* structure passed in.
*/
RtlCopyMemory((LPVOID)((LPBYTE)pFK + cbSkip),
(LPVOID)((LPBYTE)&gFilterKeys + cbSkip),
pFK->cbSize - cbSkip);
}
break;
case SPI_SETFILTERKEYS:
{
LPFILTERKEYS pFK = (LPFILTERKEYS)lParam;
if (wParam != 0 && wParam != sizeof(FILTERKEYS)) {
return FALSE;
}
if (!pFK || pFK->cbSize != sizeof(FILTERKEYS)) {
return FALSE;
}
/*
* SlowKeys and BounceKeys cannot both be active simultaneously
*/
if (pFK->iWaitMSec && pFK->iBounceMSec) {
return FALSE;
}
/*
* Do some parameter validation. We will fail on unsupported and
* undefined bits being set.
*/
if ((pFK->dwFlags & FKF_VALID) != pFK->dwFlags) {
return FALSE;
}
/*
* FKF_AVAILABLE can't be set via API. Use registry value.
*/
if (TEST_ACCESSFLAG(FilterKeys, FKF_AVAILABLE)) {
pFK->dwFlags |= FKF_AVAILABLE;
} else {
pFK->dwFlags &= ~FKF_AVAILABLE;
}
if (pFK->iWaitMSec > 20000 ||
pFK->iDelayMSec > 20000 ||
pFK->iRepeatMSec > 20000 ||
pFK->iBounceMSec > 20000) {
return FALSE;
}
if (fAlterWinIni) {
pProfileUserName = CreateProfileUserName(&tlName);
fWinIniChanged = SetFilterKeys(pProfileUserName, pFK);
fWriteAllowed = fWinIniChanged;
if (!fWinIniChanged) {
/*
* Back out any changes to win.ini.
*/
SetFilterKeys(pProfileUserName, &gFilterKeys);
}
FreeProfileUserName(pProfileUserName, &tlName);
}
if (fWriteAllowed) {
RtlCopyMemory(&gFilterKeys, pFK, pFK->cbSize);
/*
* Don't allow user to change cbSize field.
*/
gFilterKeys.cbSize = sizeof(FILTERKEYS);
if (!TEST_ACCESSFLAG(FilterKeys, FKF_FILTERKEYSON)) {
StopFilterKeysTimers();
}
SetAccessEnabledFlag();
if (FCallHookTray()) {
xxxCallHook(HSHELL_ACCESSIBILITYSTATE,
ACCESS_FILTERKEYS,
0,
WH_SHELL);
}
PostShellHookMessages(HSHELL_ACCESSIBILITYSTATE, ACCESS_FILTERKEYS);
}
}
break;
case SPI_GETSTICKYKEYS:
{
LPSTICKYKEYS pSK = (LPSTICKYKEYS)lParam;
int cbSkip = sizeof(gStickyKeys.cbSize);
if (wParam != 0 && wParam != sizeof(STICKYKEYS)) {
return FALSE;
}
if (!pSK || pSK->cbSize != sizeof(STICKYKEYS)) {
return FALSE;
}
/*
* In the future we may support multiple sizes of this data
* structure. Don't change the cbSize field of the data
* structure passed in.
*/
RtlCopyMemory((LPVOID)((LPBYTE)pSK + cbSkip),
(LPVOID)((LPBYTE)&gStickyKeys + cbSkip),
pSK->cbSize - cbSkip);
pSK->dwFlags &= ~SKF_STATEINFO;
pSK->dwFlags |= (gLatchBits&0xff) <<24;
#if SKF_LALTLATCHED != 0x10000000
#error SKF_LALTLATCHED value is incorrect
#endif
#if SKF_LCTLLATCHED != 0x04000000
#error SKF_LCTLLATCHED value is incorrect
#endif
#if SKF_LSHIFTLATCHED != 0x01000000
#error SKF_LSHIFTLATCHED value is incorrect
#endif
#if SKF_RALTLATCHED != 0x20000000
#error SKF_RALTLATCHED value is incorrect
#endif
#if SKF_RCTLLATCHED != 0x08000000
#error SKF_RCTLLATCHED value is incorrect
#endif
#if SKF_RSHIFTLATCHED != 0x02000000
#error SKF_RSHIFTLATCHED value is incorrect
#endif
pSK->dwFlags |= (gLockBits&0xff) <<16;
#if SKF_LALTLOCKED != 0x00100000
#error SKF_LALTLOCKED value is incorrect
#endif
#if SKF_LCTLLOCKED != 0x00040000
#error SKF_LCTLLOCKED value is incorrect
#endif
#if SKF_LSHIFTLOCKED != 0x00010000
#error SKF_LSHIFTLOCKED value is incorrect
#endif
#if SKF_RALTLOCKED != 0x00200000
#error SKF_RALTLOCKED value is incorrect
#endif
#if SKF_RCTLLOCKED != 0x00080000
#error SKF_RCTLLOCKED value is incorrect
#endif
#if SKF_RSHIFTLOCKED != 0x00020000
#error SKF_RSHIFTLOCKED value is incorrect
#endif
}
break;
case SPI_SETSTICKYKEYS:
{
LPSTICKYKEYS pSK = (LPSTICKYKEYS)lParam;
BOOL fWasOn;
fWasOn = TEST_BOOL_ACCESSFLAG(StickyKeys, SKF_STICKYKEYSON);
if (wParam != 0 && wParam != sizeof(STICKYKEYS)) {
return FALSE;
}
if (!pSK || pSK->cbSize != sizeof(STICKYKEYS)) {
return FALSE;
}
/*
* Do some parameter validation. We will fail on unsupported and
* undefined bits being set.
*
* Don't penalize them for using data from SPI_GETSTICKYKEYS,
* though.
*/
pSK->dwFlags &= ~SKF_STATEINFO;
if ((pSK->dwFlags & SKF_VALID) != pSK->dwFlags) {
return FALSE;
}
/*
* SKF_AVAILABLE can't be set via API. Use registry value.
*/
if (TEST_ACCESSFLAG(StickyKeys, SKF_AVAILABLE)) {
pSK->dwFlags |= SKF_AVAILABLE;
} else {
pSK->dwFlags &= ~SKF_AVAILABLE;
}
if (fAlterWinIni) {
swprintf(szTemp, pwszd, pSK->dwFlags);
fWinIniChanged = FastWriteProfileStringW(NULL,
PMAP_STICKYKEYS,
L"Flags",
szTemp);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
RtlCopyMemory(&gStickyKeys, pSK, pSK->cbSize);
/*
* Don't allow user to change cbSize field.
*/
gStickyKeys.cbSize = sizeof(STICKYKEYS);
if (!TEST_ACCESSFLAG(StickyKeys, SKF_STICKYKEYSON) && fWasOn) {
xxxTurnOffStickyKeys();
}
SetAccessEnabledFlag();
if (FCallHookTray()) {
xxxCallHook(HSHELL_ACCESSIBILITYSTATE,
ACCESS_STICKYKEYS,
0,
WH_SHELL);
}
PostShellHookMessages(HSHELL_ACCESSIBILITYSTATE, ACCESS_STICKYKEYS);
}
}
break;
case SPI_GETTOGGLEKEYS:
{
LPTOGGLEKEYS pTK = (LPTOGGLEKEYS)lParam;
int cbSkip = sizeof(gToggleKeys.cbSize);
if (wParam != 0 && wParam != sizeof(TOGGLEKEYS)) {
return FALSE;
}
if (!pTK || pTK->cbSize != sizeof(TOGGLEKEYS)) {
return FALSE;
}
/*
* In the future we may support multiple sizes of this data
* structure. Don't change the cbSize field of the data
* structure passed in.
*/
RtlCopyMemory((LPVOID)((LPBYTE)pTK + cbSkip),
(LPVOID)((LPBYTE)&gToggleKeys + cbSkip),
pTK->cbSize - cbSkip);
}
break;
case SPI_SETTOGGLEKEYS:
{
LPTOGGLEKEYS pTK = (LPTOGGLEKEYS)lParam;
if (wParam != 0 && wParam != sizeof(TOGGLEKEYS)) {
return FALSE;
}
if (!pTK || pTK->cbSize != sizeof(TOGGLEKEYS)) {
return FALSE;
}
/*
* Do some parameter validation. We will fail on unsupported and
* undefined bits being set.
*/
if ((pTK->dwFlags & TKF_VALID) != pTK->dwFlags) {
return FALSE;
}
/*
* TKF_AVAILABLE can't be set via API. Use registry value.
*/
if (TEST_ACCESSFLAG(ToggleKeys, TKF_AVAILABLE)) {
pTK->dwFlags |= TKF_AVAILABLE;
} else {
pTK->dwFlags &= ~TKF_AVAILABLE;
}
if (fAlterWinIni) {
swprintf(szTemp, pwszd, pTK->dwFlags);
fWinIniChanged = FastWriteProfileStringW(NULL,
PMAP_TOGGLEKEYS,
L"Flags",
szTemp);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
RtlCopyMemory(&gToggleKeys, pTK, pTK->cbSize);
/*
* Don't allow user to change cbSize field.
*/
gToggleKeys.cbSize = sizeof(TOGGLEKEYS);
SetAccessEnabledFlag();
}
}
break;
case SPI_GETMOUSEKEYS:
{
LPMOUSEKEYS pMK = (LPMOUSEKEYS)lParam;
int cbSkip = sizeof(gMouseKeys.cbSize);
if (wParam != 0 && wParam != sizeof(MOUSEKEYS)) {
return FALSE;
}
if (!pMK || pMK->cbSize != sizeof(MOUSEKEYS)) {
return FALSE;
}
/*
* In the future we may support multiple sizes of this data
* structure. Don't change the cbSize field of the data
* structure passed in.
*/
RtlCopyMemory((LPVOID)((LPBYTE)pMK + cbSkip),
(LPVOID)((LPBYTE)&gMouseKeys + cbSkip),
pMK->cbSize - cbSkip);
pMK->dwFlags &= ~MKF_STATEINFO;
if (gbMKMouseMode) {
pMK->dwFlags |= MKF_MOUSEMODE;
}
pMK->dwFlags |= (gwMKButtonState & 3) << 24;
#if MOUSE_BUTTON_LEFT != 0x01
#error MOUSE_BUTTON_LEFT value is incorrect
#endif
#if MOUSE_BUTTON_RIGHT != 0x02
#error MOUSE_BUTTON_RIGHT value is incorrect
#endif
#if MKF_LEFTBUTTONDOWN != 0x01000000
#error MKF_LEFTBUTTONDOWN value is incorrect
#endif
#if MKF_RIGHTBUTTONDOWN != 0x02000000
#error MKF_RIGHTBUTTONDOWN value is incorrect
#endif
pMK->dwFlags |= (gwMKCurrentButton & 3)<< 28;
#if MKF_LEFTBUTTONSEL != 0x10000000
#error MKF_LEFTBUTTONSEL value is incorrect
#endif
#if MKF_RIGHTBUTTONSEL != 0x20000000
#error MKF_RIGHTBUTTONSEL value is incorrect
#endif
}
break;
case SPI_SETMOUSEKEYS:
{
LPMOUSEKEYS pMK = (LPMOUSEKEYS)lParam;
if (wParam != 0 && wParam != sizeof(MOUSEKEYS)) {
return FALSE;
}
if (!pMK || pMK->cbSize != sizeof(MOUSEKEYS)) {
return FALSE;
}
/*
* Do some parameter validation. We will fail on unsupported and
* undefined bits being set.
*
* Don't penalize them for using data from SPI_GETMOUSEKEYS.
*/
pMK->dwFlags &= ~MKF_STATEINFO;
if ((pMK->dwFlags & MKF_VALID) != pMK->dwFlags) {
return FALSE;
}
/*
* MKF_AVAILABLE can't be set via API. Use registry value.
*/
if (TEST_ACCESSFLAG(MouseKeys, MKF_AVAILABLE)) {
pMK->dwFlags |= MKF_AVAILABLE;
} else {
pMK->dwFlags &= ~MKF_AVAILABLE;
}
if (pMK->iMaxSpeed < MAXSPEED_MIN || pMK->iMaxSpeed > MAXSPEED_MAX) {
return FALSE;
}
if (pMK->iTimeToMaxSpeed < TIMETOMAXSPEED_MIN || pMK->iTimeToMaxSpeed > TIMETOMAXSPEED_MAX) {
return FALSE;
}
if (fAlterWinIni) {
pProfileUserName = CreateProfileUserName(&tlName);
fWinIniChanged = SetMouseKeys(pProfileUserName, pMK);
fWriteAllowed = fWinIniChanged;
if (!fWinIniChanged) {
/*
* Back out any changes to win.ini.
*/
SetMouseKeys(pProfileUserName, &gMouseKeys);
}
FreeProfileUserName(pProfileUserName, &tlName);
}
if (fWriteAllowed) {
RtlCopyMemory(&gMouseKeys, pMK, pMK->cbSize);
/*
* Don't allow user to change cbSize field.
*/
gMouseKeys.cbSize = sizeof(MOUSEKEYS);
CalculateMouseTable();
if (TEST_ACCESSFLAG(MouseKeys, MKF_MOUSEKEYSON)) {
if ((TestAsyncKeyStateToggle(gNumLockVk) != 0) ^
(TEST_ACCESSFLAG(MouseKeys, MKF_REPLACENUMBERS) != 0)) {
gbMKMouseMode = TRUE;
} else {
gbMKMouseMode = FALSE;
}
MKShowMouseCursor();
} else {
MKHideMouseCursor();
}
SetAccessEnabledFlag();
if (FCallHookTray()) {
xxxCallHook(HSHELL_ACCESSIBILITYSTATE,
ACCESS_MOUSEKEYS,
0,
WH_SHELL);
}
PostShellHookMessages(HSHELL_ACCESSIBILITYSTATE, ACCESS_MOUSEKEYS);
}
}
break;
case SPI_GETHIGHCONTRAST:
{
LPHIGHCONTRAST pHC = (LPHIGHCONTRAST)lParam;
/*
* In the future we may support multiple sizes of this data
* structure. Don't change the cbSize field of the data
* structure passed in.
*/
pHC->dwFlags = gHighContrast.dwFlags;
/*
* A hostile app could deallocate the memory using a second thread,
* so shelter the copy with a try.
*/
try {
RtlCopyMemory(pHC->lpszDefaultScheme, gHighContrastDefaultScheme, MAX_SCHEME_NAME_SIZE * sizeof(WCHAR));
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
}
}
break;
case SPI_SETHIGHCONTRAST:
{
LPINTERNALSETHIGHCONTRAST pHC = (LPINTERNALSETHIGHCONTRAST)lParam;
WCHAR wcDefaultScheme[MAX_SCHEME_NAME_SIZE];
if (pHC->usDefaultScheme.Length >= MAX_SCHEME_NAME_SIZE*sizeof(WCHAR)) {
return FALSE;
}
if (pHC->usDefaultScheme.Buffer) {
/*
* Only set the scheme if the user specifies a scheme. An
* empty buffer is ignored. We do the copy here so that we
* don't need to put a try/except around the
* WriteProfileString code.
*/
try {
RtlCopyMemory(wcDefaultScheme, pHC->usDefaultScheme.Buffer, pHC->usDefaultScheme.Length);
} except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
return FALSE;
}
}
wcDefaultScheme[pHC->usDefaultScheme.Length / sizeof(WCHAR)] = 0;
if (fAlterWinIni) {
pProfileUserName = CreateProfileUserName(&tlName);
swprintf(szTemp, pwszd, pHC->dwFlags);
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
PMAP_HIGHCONTRAST,
L"Flags",
szTemp
);
fWriteAllowed = fWinIniChanged;
/*
* Note -- we do not write anything if there is no default
* scheme from the app. This is consistent with Win95/Win98
* behavior.
*/
if (pHC->usDefaultScheme.Buffer) {
fWinIniChanged |= FastWriteProfileStringW(pProfileUserName,
PMAP_HIGHCONTRAST,
TEXT("High Contrast Scheme"),
wcDefaultScheme);
}
FreeProfileUserName(pProfileUserName, &tlName);
}
if (fWriteAllowed) {
DWORD dwFlagsOld = gHighContrast.dwFlags;
LPARAM lp = fAlterWinIni ? 0 : ACCESS_HIGHCONTRASTNOREG;
#if (ACCESS_HIGHCONTRASTNOREG | ACCESS_HIGHCONTRASTOFF) != ACCESS_HIGHCONTRASTOFFNOREG
#error ACCESS_HIGHCONTRASTOFF value is incorrect
#endif
#if (ACCESS_HIGHCONTRASTNOREG | ACCESS_HIGHCONTRASTON) != ACCESS_HIGHCONTRASTONNOREG
#error ACCESS_HIGHCONTRASTON value is incorrect
#endif
#if (ACCESS_HIGHCONTRASTNOREG | ACCESS_HIGHCONTRASTCHANGE) != ACCESS_HIGHCONTRASTCHANGENOREG
#error ACCESS_HIGHCONTRASTCHANGE value is incorrect
#endif
/*
* If a NULL is specified in the lpszDefaultScheme, then it
* is not changed. This is consistent with Win95/Win98
* behavior.
*/
if (pHC->usDefaultScheme.Buffer) {
wcscpy(gHighContrastDefaultScheme, wcDefaultScheme);
}
gHighContrast.dwFlags = pHC->dwFlags;
SetAccessEnabledFlag();
/*
* Now, post message to turn high contrast on or off.
*/
if (pHC->dwFlags & HCF_HIGHCONTRASTON) {
_PostMessage(gspwndLogonNotify,
WM_LOGONNOTIFY,
LOGON_ACCESSNOTIFY,
(dwFlagsOld & HCF_HIGHCONTRASTON) ?
(ACCESS_HIGHCONTRASTCHANGE | lp) :
(ACCESS_HIGHCONTRASTON | lp));
} else {
_PostMessage(gspwndLogonNotify,
WM_LOGONNOTIFY,
LOGON_ACCESSNOTIFY,
ACCESS_HIGHCONTRASTOFF | lp);
}
}
break;
}
case SPI_GETACCESSTIMEOUT:
{
LPACCESSTIMEOUT pTO = (LPACCESSTIMEOUT)lParam;
int cbSkip = sizeof(gAccessTimeOut.cbSize);
if (wParam != 0 && wParam != sizeof(ACCESSTIMEOUT)) {
return FALSE;
}
if (!pTO || pTO->cbSize != sizeof(ACCESSTIMEOUT)) {
return FALSE;
}
/*
* In the future we may support multiple sizes of this data
* structure. Don't change the cbSize field of the data
* structure passed in.
*/
RtlCopyMemory((LPVOID)((LPBYTE)pTO + cbSkip),
(LPVOID)((LPBYTE)&gAccessTimeOut + cbSkip),
pTO->cbSize - cbSkip);
}
break;
case SPI_SETACCESSTIMEOUT:
{
LPACCESSTIMEOUT pTO = (LPACCESSTIMEOUT)lParam;
if (wParam != 0 && wParam != sizeof(ACCESSTIMEOUT)) {
return FALSE;
}
if (!pTO || pTO->cbSize != sizeof(ACCESSTIMEOUT)) {
return FALSE;
}
/*
* Do some parameter validation. We will fail on unsupported and
* undefined bits being set.
*/
if ((pTO->dwFlags & ATF_VALID) != pTO->dwFlags) {
return FALSE;
}
if (pTO->iTimeOutMSec > 3600000) {
return FALSE;
}
if (fAlterWinIni) {
pProfileUserName = CreateProfileUserName(&tlName);
swprintf(szTemp, pwszd, pTO->dwFlags);
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
PMAP_TIMEOUT,
L"Flags",
szTemp);
swprintf(szTemp, pwszd, pTO->iTimeOutMSec);
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
PMAP_TIMEOUT,
L"TimeToWait",
szTemp);
fWriteAllowed = fWinIniChanged;
if (!fWinIniChanged) {
/*
* Back out any changes to win.ini.
*/
swprintf(szTemp, pwszd, gAccessTimeOut.dwFlags);
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
PMAP_TIMEOUT,
L"Flags",
szTemp);
swprintf(szTemp, pwszd, gAccessTimeOut.iTimeOutMSec);
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
PMAP_TIMEOUT,
L"TimeToWait",
szTemp);
}
FreeProfileUserName(pProfileUserName, &tlName);
}
if (fWriteAllowed) {
RtlCopyMemory(&gAccessTimeOut, pTO, pTO->cbSize);
/*
* Don't allow user to change cbSize field.
*/
gAccessTimeOut.cbSize = sizeof(ACCESSTIMEOUT);
SetAccessEnabledFlag();
AccessTimeOutReset();
}
}
break;
case SPI_SETSHOWSOUNDS:
if (fAlterWinIni) {
swprintf(szTemp, pwszd, (wParam == 1));
fWinIniChanged = FastWriteProfileStringW(NULL,
PMAP_SHOWSOUNDS,
L"On",
szTemp);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SET_OR_CLEAR_ACCF(ACCF_SHOWSOUNDSON, wParam == 1);
SetAccessEnabledFlag();
/*
* Update the System Metrics Info.
*/
SYSMET(SHOWSOUNDS) = TEST_BOOL_ACCF(ACCF_SHOWSOUNDSON);
}
break;
case SPI_GETSHOWSOUNDS: {
PINT pint = (int *)lParam;
*pint = TEST_BOOL_ACCF(ACCF_SHOWSOUNDSON);
}
break;
case SPI_GETKEYBOARDPREF:
{
PBOOL pfKeyboardPref = (PBOOL)lParam;
*pfKeyboardPref = TEST_BOOL_ACCF(ACCF_KEYBOARDPREF);
}
break;
case SPI_SETKEYBOARDPREF:
{
BOOL fKeyboardPref = (BOOL)wParam;
if (fAlterWinIni) {
fWinIniChanged = FastWriteProfileStringW(NULL,
PMAP_KEYBOARDPREF,
L"On",
fKeyboardPref ? L"1" : L"0");
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SET_OR_CLEAR_ACCF(ACCF_KEYBOARDPREF, wParam);
}
}
break;
case SPI_GETSCREENREADER:
{
PBOOL pfScreenReader = (PBOOL)lParam;
*pfScreenReader = TEST_BOOL_ACCF(ACCF_SCREENREADER);
}
break;
case SPI_SETSCREENREADER:
{
BOOL fScreenReader = (BOOL)wParam;
if (fAlterWinIni) {
fWinIniChanged = FastWriteProfileStringW(NULL,
PMAP_SCREENREADER,
L"On",
fScreenReader ? L"1" : L"0");
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
SET_OR_CLEAR_ACCF(ACCF_SCREENREADER, wParam);
}
}
break;
case SPI_GETSOUNDSENTRY:
{
LPSOUNDSENTRY pSS = (LPSOUNDSENTRY)lParam;
int cbSkip = sizeof(gSoundSentry.cbSize);
if (wParam != 0 && wParam != sizeof(SOUNDSENTRY)) {
return FALSE;
}
if (!pSS || pSS->cbSize != sizeof(SOUNDSENTRY)) {
return FALSE;
}
/*
* In the future we may support multiple sizes of this data
* structure. Don't change the cbSize field of the data
* structure passed in.
*/
RtlCopyMemory((LPVOID)((LPBYTE)pSS + cbSkip),
(LPVOID)((LPBYTE)&gSoundSentry + cbSkip),
pSS->cbSize - cbSkip);
}
break;
case SPI_SETSOUNDSENTRY:
{
LPSOUNDSENTRY pSS = (LPSOUNDSENTRY)lParam;
if (wParam != 0 && wParam != sizeof(SOUNDSENTRY)) {
return FALSE;
}
if (!pSS || pSS->cbSize != sizeof(SOUNDSENTRY)) {
return FALSE;
}
/*
* Do some parameter validation. We will fail on unsupported and
* undefined bits being set.
*/
if ((pSS->dwFlags & SSF_VALID) != pSS->dwFlags) {
return FALSE;
}
/*
* We don't support SSWF_CUSTOM.
*/
if (pSS->iWindowsEffect > SSWF_DISPLAY) {
return FALSE;
}
/*
* No support for non-windows apps.
*/
if (pSS->iFSTextEffect != SSTF_NONE) {
return FALSE;
}
if (pSS->iFSGrafEffect != SSGF_NONE) {
return FALSE;
}
/*
* SSF_AVAILABLE can't be set via API. Use registry value.
*/
if (TEST_ACCESSFLAG(SoundSentry, SSF_AVAILABLE)) {
pSS->dwFlags |= SSF_AVAILABLE;
} else {
pSS->dwFlags &= ~SSF_AVAILABLE;
}
if (fAlterWinIni) {
pProfileUserName = CreateProfileUserName(&tlName);
fWinIniChanged = SetSoundSentry(pProfileUserName, pSS);
fWriteAllowed = fWinIniChanged;
if (!fWinIniChanged) {
/*
* Back out any changes to win.ini
*/
SetSoundSentry(pProfileUserName, &gSoundSentry);
}
FreeProfileUserName(pProfileUserName, &tlName);
}
if (fWriteAllowed) {
RtlCopyMemory(&gSoundSentry, pSS, pSS->cbSize);
/*
* Don't allow user to change cbSize field.
*/
gSoundSentry.cbSize = sizeof(SOUNDSENTRY);
SetAccessEnabledFlag();
}
}
break;
case SPI_SETCURSORS:
pProfileUserName = CreateProfileUserName(&tlName);
xxxUpdateSystemCursorsFromRegistry(pProfileUserName);
FreeProfileUserName(pProfileUserName, &tlName);
break;
case SPI_SETICONS:
pProfileUserName = CreateProfileUserName(&tlName);
xxxUpdateSystemIconsFromRegistry(pProfileUserName);
FreeProfileUserName(pProfileUserName, &tlName);
break;
case SPI_GETMOUSEHOVERWIDTH:
*((UINT *)lParam) = gcxMouseHover;
break;
case SPI_SETMOUSEHOVERWIDTH:
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_MOUSEHOVERWIDTH, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
gcxMouseHover = wParam;
}
break;
case SPI_GETMOUSEHOVERHEIGHT:
*((UINT *)lParam) = gcyMouseHover;
break;
case SPI_SETMOUSEHOVERHEIGHT:
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_MOUSEHOVERHEIGHT, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
gcyMouseHover = wParam;
}
break;
case SPI_GETMOUSEHOVERTIME:
*((UINT *)lParam) = gdtMouseHover;
break;
case SPI_SETMOUSEHOVERTIME:
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_MOUSEHOVERTIME, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
gdtMouseHover = wParam;
}
break;
case SPI_GETWHEELSCROLLLINES:
(*(LPDWORD)lParam) = gpsi->ucWheelScrollLines;
break;
case SPI_SETWHEELSCROLLLINES:
if (CheckDesktopPolicy(NULL, (PCWSTR)STR_WHEELSCROLLLINES)) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_WHEELSCROLLLINES, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed)
gpsi->ucWheelScrollLines = (UINT)wParam;
break;
case SPI_GETMENUSHOWDELAY:
(*(LPDWORD)lParam) = gdtMNDropDown;
break;
case SPI_SETMENUSHOWDELAY:
if (CheckDesktopPolicy(NULL, (PCWSTR)STR_MENUSHOWDELAY)) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
if (fAlterWinIni) {
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_MENUSHOWDELAY, wParam);
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed)
gdtMNDropDown = wParam;
break;
case SPI_GETSCREENSAVERRUNNING:
(*(LPBOOL)lParam) = gppiScreenSaver != NULL;
break;
case SPI_SETSHOWIMEUI:
return xxxSetIMEShowStatus(!!wParam);
case SPI_GETSHOWIMEUI:
(*(LPBOOL)lParam) = _GetIMEShowStatus();
break;
default:
#define ppvi (UPDWORDPointer(wFlag))
#define uDataRead ((UINT)fWinIniChanged)
if (wFlag < SPI_MAX) {
RIPERR1(ERROR_INVALID_SPI_VALUE,
RIP_WARNING,
"xxxSystemParamtersInfo: Invalid SPI_: 0x%x",
wFlag);
return FALSE;
}
UserAssert(wFlag & SPIF_RANGETYPEMASK);
if (!(wFlag & SPIF_SET)) {
if ((wFlag & SPIF_RANGETYPEMASK) == SPIF_BOOL) {
BOOL fDisable, fDisableValue;
UserAssert(UPIsBOOLRange(wFlag));
/*
* Handle settings that can be disabled by additional conditions.
*/
fDisable = fDisableValue = FALSE;
if (wFlag < SPI_GETUIEFFECTS) {
if (!TestUP(UIEFFECTS)) {
switch (wFlag) {
case SPI_GETACTIVEWNDTRKZORDER:
case SPI_GETACTIVEWINDOWTRACKING:
#ifdef MOUSE_IP
case SPI_GETMOUSESONAR:
#endif
case SPI_GETMOUSECLICKLOCK:
break;
case SPI_GETKEYBOARDCUES:
fDisableValue = TRUE;
/* Fall Through */
default:
fDisable = TRUE;
break;
}
} else {
switch (wFlag) {
case SPI_GETKEYBOARDCUES:
if (TEST_BOOL_ACCF(ACCF_KEYBOARDPREF)) {
fDisableValue = TRUE;
fDisable = TRUE;
}
break;
case SPI_GETGRADIENTCAPTIONS:
case SPI_GETSELECTIONFADE:
case SPI_GETMENUFADE:
case SPI_GETTOOLTIPFADE:
case SPI_GETCURSORSHADOW:
if (gbDisableAlpha) {
fDisable = TRUE;
}
break;
}
}
}
/*
* Give them the disabled value or read the actual one.
*/
if (fDisable) {
*((BOOL *)lParam) = fDisableValue;
} else if (wFlag == SPI_GETUIEFFECTS && IsRemoteConnection()) {
/*
* Fix for 689707.
* In remote connections, lie about the SPI_GETUIEFFECTS.
* We look at a certain subset of the uieffects array.
* If all the subset bits are off,
* we return FALSE, otherwise TRUE.
*/
*((BOOL *)lParam) = !!(TestUP(CURSORSHADOW) |
TestUP(MENUANIMATION) |
TestUP(MENUFADE) |
TestUP(TOOLTIPANIMATION) |
TestUP(TOOLTIPFADE) |
TestUP(COMBOBOXANIMATION) |
TestUP(LISTBOXSMOOTHSCROLLING));
} else {
*((BOOL *)lParam) = !!TestUPBOOL(gpdwCPUserPreferencesMask, wFlag);
}
} else {
UserAssert(UPIsDWORDRange(wFlag));
*((DWORD *)lParam) = UPDWORDValue(wFlag);
switch(wFlag) {
case SPI_GETFONTSMOOTHINGCONTRAST:
/*
* If the contrast value was never set by the user,
* we will return the default value from the display
* driver
*/
if (*((DWORD *)lParam) == 0) {
*((DWORD *)lParam) = GreGetFontContrast();
}
break;
default:
break;
}
}
} else {
pProfileUserName = CreateProfileUserName(&tlName);
if ((wFlag & SPIF_RANGETYPEMASK) == SPIF_BOOL) {
DWORD pdwValue [SPI_BOOLMASKDWORDSIZE];
UserAssert(UPIsBOOLRange(wFlag));
UserAssert(sizeof(pdwValue) == sizeof(gpdwCPUserPreferencesMask));
if (gpviCPUserPreferences->uSection == PMAP_DESKTOP) {
if (CheckDesktopPolicy(pProfileUserName, gpviCPUserPreferences->pwszKeyName)) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
}
if (fAlterWinIni) {
/*
* We only need to set/clear the bit passed in, however,
* we write the whole bit mask to the registry. Since
* the info in gpdwCPUserPreferencesMask might not match
* what it is in the registry, we need to read the
* registry before we write to it.
*/
uDataRead = FastGetProfileValue(pProfileUserName,
gpviCPUserPreferences->uSection,
gpviCPUserPreferences->pwszKeyName,
NULL,
(LPBYTE)pdwValue,
sizeof(pdwValue),
0);
/*
* If some bits are not in the registry, get them from
* gpdwCPUserPreferencesMask.
*/
UserAssert(uDataRead <= sizeof(gpdwCPUserPreferencesMask));
RtlCopyMemory(pdwValue + uDataRead,
gpdwCPUserPreferencesMask + uDataRead,
sizeof(gpdwCPUserPreferencesMask) - uDataRead);
/*
* Set/Clear the new state and write it.
*/
if (lParam) {
SetUPBOOL(pdwValue, wFlag);
} else {
ClearUPBOOL(pdwValue, wFlag);
}
fWinIniChanged = FastWriteProfileValue(pProfileUserName,
gpviCPUserPreferences->uSection,
gpviCPUserPreferences->pwszKeyName,
REG_BINARY,
(LPBYTE)pdwValue,
sizeof(pdwValue));
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
if (lParam) {
SetUPBOOL(gpdwCPUserPreferencesMask, wFlag);
} else {
ClearUPBOOL(gpdwCPUserPreferencesMask, wFlag);
}
/*
* Propagate gpsi flags.
*/
switch (wFlag) {
case SPI_SETUIEFFECTS:
PropagetUPBOOLTogpsi(UIEFFECTS);
SetPointer(TRUE);
/*
* Fall through.
*/
case SPI_SETGRADIENTCAPTIONS:
CreateBitmapStrip();
xxxRedrawScreen();
break;
case SPI_SETCOMBOBOXANIMATION:
PropagetUPBOOLTogpsi(COMBOBOXANIMATION);
break;
case SPI_SETLISTBOXSMOOTHSCROLLING:
PropagetUPBOOLTogpsi(LISTBOXSMOOTHSCROLLING);
break;
case SPI_SETKEYBOARDCUES:
PropagetUPBOOLTogpsi(KEYBOARDCUES);
break;
case SPI_SETCURSORSHADOW:
SetPointer(TRUE);
break;
case SPI_SETFLATMENU:
xxxRedrawScreen();
break;
}
}
} else {
UserAssert(UPIsDWORDRange(wFlag));
if (ppvi->uSection == PMAP_DESKTOP) {
if (CheckDesktopPolicy(pProfileUserName, ppvi->pwszKeyName)) {
fAlterWinIni = FALSE;
fWriteAllowed = FALSE;
}
}
if (fAlterWinIni) {
fWinIniChanged = FastWriteProfileValue(pProfileUserName,
ppvi->uSection,
ppvi->pwszKeyName,
REG_DWORD,
(LPBYTE)&lParam,
sizeof(DWORD));
fWriteAllowed = fWinIniChanged;
}
if (fWriteAllowed) {
ppvi->dwValue = PtrToUlong(lParam);
switch(wFlag) {
case SPI_SETCARETWIDTH:
gpsi->uCaretWidth = ppvi->dwValue;
break;
case SPI_SETFOCUSBORDERWIDTH:
if (ppvi->dwValue) {
SYSMET(CXFOCUSBORDER) = ppvi->dwValue;
}
break;
case SPI_SETFOCUSBORDERHEIGHT:
if (ppvi->dwValue) {
SYSMET(CYFOCUSBORDER) = ppvi->dwValue;
}
break;
case SPI_SETFONTSMOOTHINGTYPE:
GreSetFontEnumeration((ppvi->dwValue & FE_FONTSMOOTHINGCLEARTYPE) ? FE_CT_ON | FE_SET_CT : FE_SET_CT);
break;
case SPI_SETFONTSMOOTHINGCONTRAST:
GreSetFontContrast(ppvi->dwValue);
break;
case SPI_SETFONTSMOOTHINGORIENTATION:
GreSetLCDOrientation(ppvi->dwValue);
break;
default:
break;
}
}
}
FreeProfileUserName(pProfileUserName, &tlName);
}
break;
#undef ppvi
#undef uDataRead
}
if (fWinIniChanged && fSendWinIniChange) {
ULONG_PTR dwResult;
RtlInitLargeUnicodeString(&strSection, szSection, (UINT)-1);
xxxSendMessageTimeout(PWND_BROADCAST,
WM_SETTINGCHANGE,
wFlag,
(LPARAM)&strSection,
SMTO_NORMAL,
100,
&dwResult);
}
return fWriteAllowed;
}
/***************************************************************************\
* _RegisterShellHookWindow
*
* History:
\***************************************************************************/
BOOL _RegisterShellHookWindow(
PWND pwnd)
{
PDESKTOPINFO pdeskinfo;
if (pwnd->head.rpdesk == NULL) {
return FALSE;
}
pdeskinfo = pwnd->head.rpdesk->pDeskInfo;
/*
* Add pwnd to the desktop's Volatile Window Pointer List (VWPL) of
* ShellHook windows. If this call initializes the VWPL, set the
* (re)allocation threshhold to 2 PWNDs (we know we never have more than
* 2 windows in this list anyway)
*/
if (VWPLAdd(&(pdeskinfo->pvwplShellHook), pwnd, 2)) {
SetWF(pwnd, WFSHELLHOOKWND);
return TRUE;
}
return FALSE;
}
/***************************************************************************\
* _DeregisterShellHookWindow
*
* History:
\***************************************************************************/
BOOL _DeregisterShellHookWindow(
PWND pwnd)
{
PDESKTOPINFO pdeskinfo;
if (pwnd->head.rpdesk == NULL) {
return FALSE;
}
pdeskinfo = pwnd->head.rpdesk->pDeskInfo;
if (VWPLRemove(&(pdeskinfo->pvwplShellHook), pwnd)) {
ClrWF(pwnd, WFSHELLHOOKWND);
}
return TRUE;
}
/***************************************************************************\
* xxxSendMinRectMessages
*
* History:
\***************************************************************************/
BOOL xxxSendMinRectMessages(
PWND pwnd,
RECT *lpRect)
{
BOOL fRet = FALSE;
HWND hwnd = HW(pwnd);
PTHREADINFO pti = PtiCurrent();
PDESKTOPINFO pdeskinfo;
DWORD nPwndShellHook;
PWND pwndShellHook;
if (IsHooked(pti, WHF_SHELL)) {
xxxCallHook(HSHELL_GETMINRECT, (WPARAM)hwnd, (LPARAM)lpRect, WH_SHELL);
fRet = TRUE;
}
pdeskinfo = GETDESKINFO(pti);
if (pdeskinfo->pvwplShellHook == NULL) {
return fRet;
}
nPwndShellHook = 0;
pwndShellHook = NULL;
while (pwndShellHook = VWPLNext(pdeskinfo->pvwplShellHook, pwndShellHook, &nPwndShellHook)) {
TL tlpwnd;
ULONG_PTR dwRes;
ThreadLock(pwndShellHook, &tlpwnd);
if (xxxSendMessageTimeout(pwndShellHook, WM_KLUDGEMINRECT, (WPARAM)(hwnd), (LPARAM)lpRect,
SMTO_NORMAL, 100, &dwRes))
fRet = TRUE;
/*
* pdeskinfo->pvwplShellHook may have been realloced to a different
* location and size during the WM_KLUDGEMINRECT callback.
*/
ThreadUnlock(&tlpwnd);
}
return fRet;
}
/***************************************************************************\
* PostShellHookMessages
*
* History:
\***************************************************************************/
VOID PostShellHookMessages(
UINT message,
LPARAM lParam)
{
PDESKTOPINFO pdeskinfo = GETDESKINFO(PtiCurrent());
DWORD nPwndShellHook;
PWND pwndShellHook;
nPwndShellHook = 0;
pwndShellHook = NULL;
/*
* We want to allow anyone who's listening for these WM_APPCOMMAND
* messages to be able to take the foreground. I.E., pressing mail will
* launch outlook AND bring it to the foreground. We set the token to
* null so anyone can steal the foreground - else it isn't clear who
* should have the right to steal it - only one person gets the right.
* We let them fight it out to decide who gets foreground if more than
* one listener will try make a foreground change.
*/
if (HSHELL_APPCOMMAND == message) {
TAGMSG0(DBGTAG_FOREGROUND,
"PostShellHookMessages cleared last input token - open foreground.");
glinp.ptiLastWoken = NULL;
}
/*
* Loop through all the windows registered to listen for shell hooks and
* post the message to them.
*/
while (pwndShellHook = VWPLNext(pdeskinfo->pvwplShellHook, pwndShellHook, &nPwndShellHook)) {
if (pwndShellHook == pdeskinfo->spwndProgman) {
switch (message) {
case HSHELL_WINDOWCREATED:
_PostMessage(pwndShellHook, gpsi->uiShellMsg, guiOtherWindowCreated, lParam);
break;
case HSHELL_WINDOWDESTROYED:
_PostMessage(pwndShellHook, gpsi->uiShellMsg, guiOtherWindowDestroyed, lParam);
break;
}
} else {
_PostMessage(pwndShellHook, gpsi->uiShellMsg, message, lParam);
}
}
}
/***************************************************************************\
* _ResetDblClk
*
* History:
\***************************************************************************/
VOID _ResetDblClk(
VOID)
{
PtiCurrent()->pq->timeDblClk = 0L;
}
/***************************************************************************\
* SetMsgBox
*
* History:
\***************************************************************************/
VOID SetMsgBox(
PWND pwnd)
{
pwnd->head.rpdesk->pDeskInfo->cntMBox++;
SetWF(pwnd, WFMSGBOX);
}
/***************************************************************************\
* xxxSimulateShiftF10
*
* This routine is called to convert a WM_CONTEXTHELP message back to a
* SHIFT-F10 sequence for old applications. It is called from the default
* window procedure.
*
* History:
* 22-Aug-95 BradG Ported from Win95 (rare.asm)
\***************************************************************************/
VOID xxxSimulateShiftF10(
VOID)
{
/*
* VK_SHIFT down
*/
xxxKeyEvent(VK_LSHIFT, 0x2A | SCANCODE_SIMULATED, NtGetTickCount(), 0,
#ifdef GENERIC_INPUT
NULL,
NULL,
#endif
FALSE);
/*
* VK_F10 down
*/
xxxKeyEvent(VK_F10, 0x44 | SCANCODE_SIMULATED, NtGetTickCount(), 0,
#ifdef GENERIC_INPUT
NULL,
NULL,
#endif
FALSE);
/*
* VK_F10 up
*/
xxxKeyEvent(VK_F10 | KBDBREAK, 0x44 | SCANCODE_SIMULATED, NtGetTickCount(), 0,
#ifdef GENERIC_INPUT
NULL,
NULL,
#endif
FALSE);
/*
* VK_SHIFT up
*/
xxxKeyEvent(VK_LSHIFT | KBDBREAK, 0x2A | SCANCODE_SIMULATED, NtGetTickCount(), 0,
#ifdef GENERIC_INPUT
NULL,
NULL,
#endif
FALSE);
}
/*
* VWPL (Volatile Window Pointer List) Implementation details.
* ===========================================================
* Volatile Window Pointer Lists are used to keep a list of windows that we want
* to send messages to, where the list may get altered during each of those send
* message callbacks.
*
* The list is volatile in that it can change its size, contents and location
* while we continue to traverse the list.
*
* Examples of use:
* - hungapp redraw code in hungapp.c
* - xxxSendMinRectMessages stuff in rare.c
*
* Members of the VWPL struct:
* cPwnd
* The number of pwnds in the list, not including NULLs
* cElem
* The size of the list, including NULLs.
* cThreshhold
* When growing, the number of extra spaces to add to the list.
* When (cElem - cPwnd) > cThreshhold, that's when we reallocate to shrink.
* apwnd[]
* An array of pwnds.
* The array may have some empty slots, but they will all be at the end.
*
* VWPL Internal Invariants:
* - no pwnd appears more than once.
* - cPwnd <= cElem
* - number of unused slots (cElem - cPwnd) < cThreshhold
* - all unused slots are at the end of the aPwnd[] array
*
* Restrictions on use of VWPLs:
* - NULL pwnd is not allowed (except in unused slots)
* - all pwnds in the list must be valid: pwnds must be explicitly removed from
* the list in their xxxFreeWindow.
*/
#if DBG_VWPL
BOOL DbgCheckVWPL(
PVWPL pvwpl)
{
DWORD ixPwnd;
if (!pvwpl) {
return TRUE;
}
UserAssert(pvwpl->cElem >= pvwpl->cPwnd);
/*
* Check that cElem is not too big.
*/
UserAssert(pvwpl->cElem < 1000);
/*
* Check that the pwnds are all in the first cPwnd slots.
*/
for (ixPwnd = 0; ixPwnd < pvwpl->cPwnd; ixPwnd++) {
UserAssert(pvwpl->aPwnd[ixPwnd] != NULL);
}
#if ZERO_INIT_VWPL
/*
* Check that the NULLs are all in the last few slots.
*/
for (ixPwnd = pvwpl->cPwnd; ixPwnd < pvwpl->cElem; ixPwnd++) {
UserAssert(pvwpl->aPwnd[ixPwnd] == NULL);
}
#endif
/*
* Check that no pwnds appears twice.
*/
for (ixPwnd = 0; ixPwnd < pvwpl->cPwnd; ixPwnd++) {
DWORD ix2;
for (ix2 = ixPwnd + 1; ix2 < pvwpl->cPwnd; ix2++) {
UserAssert(pvwpl->aPwnd[ixPwnd] != pvwpl->aPwnd[ix2]);
}
}
}
#else
#define DbgCheckVWPL(foo)
#endif
/*****************************************************************************\
* VWPLAdd
*
* Adds a pwnd to a VWPL (Volatile Window Pointer List). Allocates or
* reallocates memory as required.
*
* History:
* 98-01-30 IanJa Created.
\*****************************************************************************/
BOOL VWPLAdd(
PVWPL *ppvwpl,
PWND pwnd,
DWORD dwThreshhold)
{
PVWPL pvwpl;
DWORD ixPwnd;
TAGMSG2(DBGTAG_VWPL, "VWPL %#p + %#p", *ppvwpl, pwnd);
UserAssert(pwnd);
if (*ppvwpl == NULL) {
/*
* Initialize the VWPL.
*/
UserAssert(dwThreshhold >= 2); // could be 1, but that would be silly
pvwpl = (PVWPL)UserAllocPool(sizeof(VWPL) + (sizeof(PWND) * dwThreshhold),
TAG_VWPL);
if (pvwpl == NULL) {
RIPMSG1(RIP_WARNING,
"VWPLAdd fail to allocate initial %lx",
sizeof(VWPL) + (sizeof(PWND) * dwThreshhold));
DbgCheckVWPL(*ppvwpl);
return FALSE;
}
pvwpl->cElem = dwThreshhold;
pvwpl->cThreshhold = dwThreshhold;
#if ZERO_INIT_VWPL
RtlZeroMemory(&(pvwpl->aPwnd[0]), (sizeof(PWND) * dwThreshhold));
#endif
pvwpl->cPwnd = 0;
*ppvwpl = pvwpl;
ixPwnd = 0;
goto AddPwnd;
} else {
pvwpl = *ppvwpl;
for (ixPwnd = 0; ixPwnd < pvwpl->cElem; ixPwnd++) {
if (pwnd == pvwpl->aPwnd[ixPwnd]) {
DbgCheckVWPL(*ppvwpl);
return FALSE; // callers require FALSE this case
}
}
if (pvwpl->cPwnd >= pvwpl->cElem ) {
/*
* Didn't find it already there, and no space so grow the VWPL.
*/
DWORD dwSize;
DWORD dwSizeNew;
dwSize = sizeof(VWPL) + (sizeof(PWND) * pvwpl->cElem);
dwSizeNew = dwSize + (sizeof(PWND) * pvwpl->cThreshhold);
pvwpl = (PVWPL)UserReAllocPool(pvwpl, dwSize, dwSizeNew, TAG_VWPL);
if (pvwpl == NULL) {
RIPMSG2(RIP_WARNING,
"VWPLAdd fail to reallocate %lx to %lx", dwSize, dwSizeNew);
DbgCheckVWPL(*ppvwpl);
return FALSE;
}
#if ZERO_INIT_VWPL
RtlZeroMemory(&(pvwpl->aPwnd[pvwpl->cPwnd]), (sizeof(PWND) * dwThreshhold));
#endif
pvwpl->cElem += pvwpl->cThreshhold;
*ppvwpl = pvwpl;
}
}
AddPwnd:
ixPwnd = pvwpl->cPwnd;
pvwpl->aPwnd[ixPwnd] = pwnd;
pvwpl->cPwnd++;
DbgCheckVWPL(*ppvwpl);
return TRUE;
}
/*****************************************************************************\
* VWPLRemove
*
* Removes a pwnd from a VWPL list of pwnds. Reallocates memory as required.
*
* Returns FALSE if the pwnd was not found.
*
* History:
* 98-01-30 IanJa Created.
\*****************************************************************************/
BOOL VWPLRemove(
PVWPL *ppvwpl,
PWND pwnd)
{
PVWPL pvwpl = *ppvwpl;
DWORD ixPwnd;
TAGMSG2(DBGTAG_VWPL, "VWPL %#p - %#p", *ppvwpl, pwnd);
UserAssert(pwnd);
if (!pvwpl) {
return FALSE;
}
for (ixPwnd = 0; ixPwnd < pvwpl->cElem; ixPwnd++) {
if (pwnd == pvwpl->aPwnd[ixPwnd]) {
goto PwndIsFound;
}
}
DbgCheckVWPL(*ppvwpl);
return FALSE;
PwndIsFound:
pvwpl->aPwnd[ixPwnd] = NULL;
pvwpl->cPwnd--;
if (pvwpl->cPwnd == 0) {
UserFreePool(pvwpl);
*ppvwpl = NULL;
return TRUE;
}
/*
* Compact the VWPL to keep all the empty slots at the end. If these
* free slots exceeds the threshhold, realloc to shrink. It doesn't
* matter that we change the order.
*/
pvwpl->aPwnd[ixPwnd] = pvwpl->aPwnd[pvwpl->cPwnd];
#if ZERO_INIT_VWPL
pvwpl->aPwnd[pvwpl->cPwnd] = NULL;
#endif
if ((pvwpl->cElem - pvwpl->cPwnd) >= pvwpl->cThreshhold) {
DWORD dwSize;
DWORD dwSizeNew;
dwSize = sizeof(VWPL) + (sizeof(PWND) * pvwpl->cElem);
dwSizeNew = sizeof(VWPL) + (sizeof(PWND) * pvwpl->cPwnd);
pvwpl = (PVWPL)UserReAllocPool(pvwpl, dwSize, dwSizeNew, TAG_VWPL);
if (pvwpl == NULL) {
RIPMSG2(RIP_WARNING,
"VWPLRemove fail to reallocate %lx to %lx",
dwSize, dwSizeNew);
DbgCheckVWPL(*ppvwpl);
return TRUE;
}
pvwpl->cElem = pvwpl->cPwnd;
*ppvwpl = pvwpl;
}
DbgCheckVWPL(*ppvwpl);
return TRUE;
}
/*****************************************************************************\
* VWPLNext
*
* Returns the next pwnd from a VWPL (Volatile Window Pointer List).
*
* Setting *pnPrev to 0 will return the first pwnd in the VWPL, and gets a new
* value in *pnPrev which is to be used in a subsequent call to VWPLNext to
* obtain the next pwnd.
* Returns NULL when the last pwnd has been obtained, and sets *pnPrev back to 0
*
* History:
* 98-01-30 IanJa Created.
\*****************************************************************************/
PWND VWPLNext(
PVWPL pvwpl,
PWND pwndPrev,
DWORD *pnPrev)
{
DbgCheckVWPL(pvwpl);
if (!pvwpl) {
TAGMSG1(DBGTAG_VWPL, "VWPL %#p => NULL (empty)", pvwpl);
return NULL;
}
if (*pnPrev >= pvwpl->cPwnd) {
goto NoMorePwnds;
}
/*
* If our previous pwnd is still there, advance to the next slot
* (else it has gone, so return the one now occupying its slot).
*/
if (pvwpl->aPwnd[*pnPrev] == pwndPrev) {
(*pnPrev)++;
}
if (*pnPrev < pvwpl->cPwnd) {
UserAssert(pvwpl->aPwnd[*pnPrev] != pwndPrev);
TAGMSG2(DBGTAG_VWPL, "VWPL %#p => %#p", pvwpl, pvwpl->aPwnd[*pnPrev]);
return pvwpl->aPwnd[*pnPrev];
}
/*
* We came to the end.
*/
NoMorePwnds:
TAGMSG1(DBGTAG_VWPL, "VWPL 0x%p => NULL (end)", pvwpl);
*pnPrev = 0;
return NULL;
}
/*****************************************************************************\
* RestoreMonitorsAndWindowsRects
*
* Restore a windows sizes and positions previously captured in a WMSNAPSHOT
* structure. Capture happens when disconnecting from local console and
* restore happens when connecting back to local console.
\*****************************************************************************/
NTSTATUS RestoreMonitorsAndWindowsRects(
VOID)
{
PMONITORRECTS pmr;
int i;
int j;
BOOL bFound;
PSMWP psmwp;
PWND pwnd;
NTSTATUS Status;
PWPSNAPSHOT pwps = NULL;
/*
* Don't do anything if not multimon.
*/
if (!IsMultimon()) {
return STATUS_SUCCESS;
}
/*
* Nothing to do if we don't currently have captured monitors or
* windows snapshots.
*/
if (gwms.pmr == NULL || gwms.pwps == NULL) {
Status = STATUS_UNSUCCESSFUL;
goto Exit;
}
/*
* Get Current monitors layout.
*/
pmr = SnapshotMonitorRects();
if (pmr == NULL) {
Status = STATUS_NO_MEMORY;
goto Exit;
}
/*
* make sure monitors we captured are still there.
*/
Status = STATUS_SUCCESS;
for (i = 0; i < gwms.pmr->cMonitor; i++) {
bFound = FALSE;
for (j = 0; j < pmr->cMonitor; j++) {
if (EqualRect(&gwms.pmr->amp[i].rcMonitor, &pmr->amp[j].rcMonitor)) {
bFound = TRUE;
break;
}
}
if (!bFound) {
Status = STATUS_UNSUCCESSFUL;
break;
}
}
UserFreePool(pmr);
/*
* Position Windows now.
*/
if (NT_SUCCESS(Status)) {
if ((psmwp = InternalBeginDeferWindowPos(4)) != NULL) {
for (i = 0, pwps = gwms.pwps; (i < gwms.cWindows) && (psmwp != NULL) ; i++, pwps++) {
/*
* Make sure this hwnd is still here.
*/
if ((pwnd = RevalidateHwnd(pwps->hwnd)) == NULL ||
TestWF(pwnd, WEFTOOLWINDOW)) {
continue;
}
psmwp = _DeferWindowPos(psmwp,
pwnd,
(PWND)HWND_TOP,
pwps->rcWindow.left,
pwps->rcWindow.top,
pwps->rcWindow.right - pwps->rcWindow.left,
pwps->rcWindow.bottom - pwps->rcWindow.top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
if (psmwp != NULL) {
xxxEndDeferWindowPosEx(psmwp, TRUE);
} else{
Status = STATUS_NO_MEMORY;
}
}
}
Exit:
CleanupMonitorsAndWindowsSnapShot();
return Status;
}
/*****************************************************************************\
* SnapShotMonitorsAndWindowsRects
*
* Captures windows sizes and positions in a WMSNAPSHOT structure. Capture
* happens when disconnecting from local console.
\*****************************************************************************/
NTSTATUS SnapShotMonitorsAndWindowsRects(
VOID)
{
/*
* First, cleanup anything left over from previous captures.
*/
if (gwms.pmr != NULL || gwms.pwps != NULL) {
CleanupMonitorsAndWindowsSnapShot();
}
/*
* Get a snaphot of current monitors configuration.
*/
if ((gwms.pmr = SnapshotMonitorRects()) == NULL) {
return STATUS_NO_MEMORY;
}
/*
* Get a snaphsot of windows positions.
*/
if ((gwms.pwps = SnapshotWindowRects(&gwms.cWindows)) == NULL) {
CleanupMonitorsAndWindowsSnapShot();
return STATUS_NO_MEMORY;
}
return STATUS_SUCCESS;
}
/*****************************************************************************\
* CleanupMonitorsAndWindowsSnapShot
*
* Frees memory allocated to capture windows sizes and positions a WMSNAPSHOT
* structure.
\*****************************************************************************/
VOID CleanupMonitorsAndWindowsSnapShot(
VOID)
{
PWPSNAPSHOT pwps = gwms.pwps;
if (gwms.pmr != NULL) {
UserFreePool(gwms.pmr);
gwms.pmr = NULL;
}
if (pwps != NULL) {
UserFreePool(gwms.pwps);
gwms.pwps = NULL;
}
gwms.cWindows = 0;
}
/*****************************************************************************\
* SnapshotWindowRects
*
* Allocates memory to capture window sizes and positions in a WMSNAPSHOT
* structure.
\*****************************************************************************/
PWPSNAPSHOT SnapshotWindowRects(
int *pnWindows)
{
PWND pwndDesktop;
PHWND phwnd;
PBWL pbwl;
PWND pwnd;
int nWindows = 0;
PWPSNAPSHOT pwps = NULL;
PWPSNAPSHOT pReturnedpwps = NULL;
/*
* Initialize captured windows count.
*/
*pnWindows = 0;
/*
* Build a list of top windows.
*/
UserVerify(pwndDesktop = _GetDesktopWindow());
if ((pbwl = BuildHwndList(pwndDesktop->spwndChild, BWL_ENUMLIST, NULL)) == NULL) {
return NULL;
}
/*
* Count maximum captured windows to allocate WPSNAPSHOT array.
*/
phwnd = pbwl->rghwnd;
while (*phwnd != (HWND)1) {
nWindows++;
phwnd++;
}
if (nWindows != 0) {
pwps = UserAllocPoolWithQuotaZInit(sizeof(WPSNAPSHOT) * nWindows, TAG_SWP);
}
if (pwps == NULL) {
FreeHwndList(pbwl);
return NULL;
}
pReturnedpwps = pwps;
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
/*
* Make sure this hwnd is still around.
*/
if ((pwnd = RevalidateHwnd(*phwnd)) == NULL || TestWF(pwnd, WEFTOOLWINDOW) ) {
continue;
}
pwps->hwnd = *phwnd;
CopyRect(&pwps->rcWindow, &pwnd->rcWindow);
(*pnWindows)++;
pwps++;
}
if (*pnWindows != 0) {
return pReturnedpwps;
} else {
UserFreePool(pReturnedpwps);
return NULL;
}
}