xref: /reactos/win32ss/user/ntuser/sysparams.c (revision b5218987)
1 /*
2  * COPYRIGHT:        GPL, see COPYING in the top level directory
3  * PROJECT:          ReactOS win32 kernel mode subsystem server
4  * PURPOSE:          System parameters functions
5  * FILE:             win32ss/user/ntuser/sysparams.c
6  * PROGRAMER:        Timo Kreuzer (timo.kreuzer@reactos.org)
7  */
8 
9 // TODO:
10 // - Check all values that are in Winsta in ROS.
11 // - Does setting invalid fonts work?
12 // - Save appropriate text metrics.
13 
14 #include <win32k.h>
15 DBG_DEFAULT_CHANNEL(UserSysparams);
16 
17 SPIVALUES gspv;
18 BOOL gbSpiInitialized = FALSE;
19 BOOL g_PaintDesktopVersion = FALSE;
20 
21 // HACK! We initialize SPI before we have a proper surface to get this from.
22 #define dpi 96
23 //(pPrimarySurface->GDIInfo.ulLogPixelsY)
24 #define REG2METRIC(reg) (reg > 0 ? reg : ((-(reg) * dpi + 720) / 1440))
25 #define METRIC2REG(met) (-((((met) * 1440)- 0) / dpi))
26 
27 #define REQ_INTERACTIVE_WINSTA(err) \
28 do { \
29     if (GetW32ProcessInfo()->prpwinsta != InputWindowStation) \
30     { \
31         if (GetW32ProcessInfo()->prpwinsta == NULL) \
32         { \
33             ERR("NtUserSystemParametersInfo called without active window station, and it requires an interactive one\n"); \
34         } \
35         else \
36         { \
37             ERR("NtUserSystemParametersInfo requires interactive window station (current is '%wZ')\n", \
38                 &(OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(GetW32ProcessInfo()->prpwinsta))->Name)); \
39         } \
40         EngSetLastError(err); \
41         return 0; \
42     } \
43 } while (0)
44 
45 static const WCHAR* KEY_MOUSE = L"Control Panel\\Mouse";
46 static const WCHAR* VAL_MOUSE1 = L"MouseThreshold1";
47 static const WCHAR* VAL_MOUSE2 = L"MouseThreshold2";
48 static const WCHAR* VAL_MOUSE3 = L"MouseSpeed";
49 static const WCHAR* VAL_MOUSETRAILS = L"MouseTrails";
50 static const WCHAR* VAL_DBLCLKWIDTH = L"DoubleClickWidth";
51 static const WCHAR* VAL_DBLCLKHEIGHT = L"DoubleClickHeight";
52 static const WCHAR* VAL_DBLCLKTIME = L"DoubleClickSpeed";
53 static const WCHAR* VAL_SNAPDEFBTN = L"SnapToDefaultButton";
54 static const WCHAR* VAL_SWAP = L"SwapMouseButtons";
55 static const WCHAR* VAL_HOVERTIME = L"MouseHoverTime";
56 static const WCHAR* VAL_HOVERWIDTH = L"MouseHoverWidth";
57 static const WCHAR* VAL_HOVERHEIGHT = L"MouseHoverHeight";
58 static const WCHAR* VAL_SENSITIVITY = L"MouseSensitivity";
59 
60 static const WCHAR* KEY_DESKTOP = L"Control Panel\\Desktop";
61 static const WCHAR* VAL_SCRTO = L"ScreenSaveTimeOut";
62 static const WCHAR* VAL_SCRNSV = L"SCRNSAVE.EXE";
63 static const WCHAR* VAL_SCRACT = L"ScreenSaveActive";
64 static const WCHAR* VAL_GRID = L"GridGranularity";
65 static const WCHAR* VAL_DRAG = L"DragFullWindows";
66 static const WCHAR* VAL_DRAGHEIGHT = L"DragHeight";
67 static const WCHAR* VAL_DRAGWIDTH = L"DragWidth";
68 static const WCHAR* VAL_FONTSMOOTHING = L"FontSmoothing";
69 static const WCHAR* VAL_FONTSMOOTHINGTYPE = L"FontSmoothingType";
70 static const WCHAR* VAL_FONTSMOOTHINGCONTRAST = L"FontSmoothingGamma";
71 static const WCHAR* VAL_FONTSMOOTHINGORIENTATION = L"FontSmoothingOrientation";
72 static const WCHAR* VAL_SCRLLLINES = L"WheelScrollLines";
73 static const WCHAR* VAL_CLICKLOCKTIME = L"ClickLockTime";
74 static const WCHAR* VAL_PAINTDESKVER = L"PaintDesktopVersion";
75 static const WCHAR* VAL_CARETRATE = L"CursorBlinkRate";
76 #if (_WIN32_WINNT >= 0x0600)
77 static const WCHAR* VAL_SCRLLCHARS = L"WheelScrollChars";
78 #endif
79 static const WCHAR* VAL_USERPREFMASK = L"UserPreferencesMask";
80 
81 static const WCHAR* KEY_MDALIGN = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
82 static const WCHAR* VAL_MDALIGN = L"MenuDropAlignment";
83 
84 static const WCHAR* KEY_METRIC = L"Control Panel\\Desktop\\WindowMetrics";
85 static const WCHAR* VAL_BORDER = L"BorderWidth";
86 static const WCHAR* VAL_ICONSPC = L"IconSpacing";
87 static const WCHAR* VAL_ICONVSPC = L"IconVerticalspacing";
88 static const WCHAR* VAL_ITWRAP = L"IconTitleWrap";
89 
90 static const WCHAR* KEY_SOUND = L"Control Panel\\Sound";
91 static const WCHAR* VAL_BEEP = L"Beep";
92 
93 static const WCHAR* KEY_KBD = L"Control Panel\\Keyboard";
94 static const WCHAR* VAL_KBDSPD = L"KeyboardSpeed";
95 static const WCHAR* VAL_KBDDELAY = L"KeyboardDelay";
96 
97 static const WCHAR* KEY_SHOWSNDS = L"Control Panel\\Accessibility\\ShowSounds";
98 static const WCHAR* KEY_KDBPREF = L"Control Panel\\Accessibility\\Keyboard Preference";
99 static const WCHAR* KEY_SCRREAD = L"Control Panel\\Accessibility\\Blind Access";
100 static const WCHAR* VAL_ON = L"On";
101 
102 
103 
104 /** Loading the settings ******************************************************/
105 
106 static
107 INT
108 SpiLoadDWord(PCWSTR pwszKey, PCWSTR pwszValue, INT iValue)
109 {
110     DWORD Result;
111     if (!RegReadUserSetting(pwszKey, pwszValue, REG_DWORD, &Result, sizeof(Result)))
112     {
113         return iValue;
114     }
115     return Result;
116 }
117 
118 static
119 INT
120 SpiLoadInt(PCWSTR pwszKey, PCWSTR pwszValue, INT iValue)
121 {
122     WCHAR awcBuffer[12];
123     ULONG cbSize;
124 
125     cbSize = sizeof(awcBuffer);
126     if (!RegReadUserSetting(pwszKey, pwszValue, REG_SZ, awcBuffer, cbSize))
127     {
128         return iValue;
129     }
130     return _wtoi(awcBuffer);
131 }
132 
133 static
134 DWORD
135 SpiLoadUserPrefMask(DWORD dValue)
136 {
137     DWORD Result;
138     if (!RegReadUserSetting(KEY_DESKTOP, VAL_USERPREFMASK, REG_BINARY, &Result, sizeof(Result)))
139     {
140         return dValue;
141     }
142     return Result;
143 }
144 
145 static
146 DWORD
147 SpiLoadTimeOut(VOID)
148 {   // Must have the string!
149     WCHAR szApplicationName[MAX_PATH];
150     RtlZeroMemory(&szApplicationName, sizeof(szApplicationName));
151     if (!RegReadUserSetting(KEY_DESKTOP, VAL_SCRNSV, REG_SZ, &szApplicationName, sizeof(szApplicationName)))
152     {
153         return 0;
154     }
155     if (szApplicationName[0] == 0) return 0;
156     return SpiLoadInt(KEY_DESKTOP, VAL_SCRTO, 600);
157 }
158 
159 static
160 INT
161 SpiLoadMouse(PCWSTR pwszValue, INT iValue)
162 {
163     return SpiLoadInt(KEY_MOUSE, pwszValue, iValue);
164 }
165 
166 static
167 INT
168 SpiLoadMetric(PCWSTR pwszValue, INT iValue)
169 {
170     INT iRegVal;
171 
172     iRegVal = SpiLoadInt(KEY_METRIC, pwszValue, METRIC2REG(iValue));
173     TRACE("Loaded metric setting '%S', iValue=%d(reg:%d), ret=%d(reg:%d)\n",
174            pwszValue, iValue, METRIC2REG(iValue), REG2METRIC(iRegVal), iRegVal);
175     return REG2METRIC(iRegVal);
176 }
177 
178 static
179 VOID
180 SpiLoadFont(PLOGFONTW plfOut, LPWSTR pwszValueName, PLOGFONTW plfDefault)
181 {
182     BOOL bResult;
183 
184     bResult = RegReadUserSetting(KEY_METRIC,
185                                  pwszValueName,
186                                  REG_BINARY,
187                                  plfOut,
188                                  sizeof(LOGFONTW));
189     if (!bResult)
190         *plfOut = *plfDefault;
191 }
192 
193 static
194 VOID
195 SpiFixupValues(VOID)
196 {
197     /* Fixup values */
198     gspv.ncm.iCaptionWidth = max(gspv.ncm.iCaptionWidth, 8);
199     gspv.ncm.iBorderWidth = max(gspv.ncm.iBorderWidth, 1);
200     gspv.ncm.iScrollWidth = max(gspv.ncm.iScrollWidth, 8);
201     gspv.ncm.iScrollHeight = max(gspv.ncm.iScrollHeight, 8);
202 //    gspv.ncm.iMenuHeight = max(gspv.ncm.iMenuHeight, gspv.tmMenuFont.tmHeight);
203 //    gspv.ncm.iMenuHeight = max(gspv.ncm.iMenuHeight,
204 //                               2 + gspv.tmMenuFont.tmHeight +
205 //                               gspv.tmMenuFont.tmExternalLeading);
206     if (gspv.iDblClickTime == 0) gspv.iDblClickTime = 500;
207 
208     // FIXME: Hack!!!
209     gspv.tmMenuFont.tmHeight = 11;
210     gspv.tmMenuFont.tmExternalLeading = 2;
211 
212     gspv.tmCaptionFont.tmHeight = 11;
213     gspv.tmCaptionFont.tmExternalLeading = 2;
214 
215 }
216 
217 static
218 VOID
219 SpiUpdatePerUserSystemParameters(VOID)
220 {
221     static LOGFONTW lf1 = {-11, 0, 0, 0, FW_NORMAL, FALSE, FALSE,
222                            FALSE, ANSI_CHARSET, 0, 0, DEFAULT_QUALITY,
223                            VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif"};
224     static LOGFONTW lf2 = {-11, 0, 0, 0, FW_BOLD, FALSE, FALSE,
225                            FALSE, ANSI_CHARSET, 0, 0, DEFAULT_QUALITY,
226                            VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif"};
227 
228     TRACE("Enter SpiUpdatePerUserSystemParameters\n");
229 
230     /* Clear the structure */
231     RtlZeroMemory(&gspv, sizeof(gspv));
232 
233     /* Load mouse settings */
234     gspv.caiMouse.FirstThreshold = SpiLoadMouse(VAL_MOUSE1, 6);
235     gspv.caiMouse.SecondThreshold = SpiLoadMouse(VAL_MOUSE2, 10);
236     gspv.caiMouse.Acceleration = SpiLoadMouse(VAL_MOUSE3, 1);
237     gspv.iMouseSpeed = SpiLoadMouse(VAL_SENSITIVITY, 10);
238     gspv.bMouseBtnSwap = SpiLoadMouse(VAL_SWAP, 0);
239     gspv.bSnapToDefBtn = SpiLoadMouse(VAL_SNAPDEFBTN, 0);
240     gspv.iMouseTrails = SpiLoadMouse(VAL_MOUSETRAILS, 0);
241     gspv.iDblClickTime = SpiLoadMouse(VAL_DBLCLKTIME, 500);
242     gspv.iDblClickWidth = SpiLoadMouse(VAL_DBLCLKWIDTH, 4);
243     gspv.iDblClickHeight = SpiLoadMouse(VAL_DBLCLKHEIGHT, 4);
244     gspv.iMouseHoverTime = SpiLoadMouse(VAL_HOVERTIME, 400);
245     gspv.iMouseHoverWidth = SpiLoadMouse(VAL_HOVERWIDTH, 4);
246     gspv.iMouseHoverHeight = SpiLoadMouse(VAL_HOVERHEIGHT, 4);
247 
248     /* Load keyboard settings */
249     gspv.dwKbdSpeed = SpiLoadInt(KEY_KBD, VAL_KBDSPD, 31);
250     gspv.iKbdDelay = SpiLoadInt(KEY_KBD, VAL_KBDDELAY, 1);
251 
252     /* Load NONCLIENTMETRICS */
253     gspv.ncm.cbSize = sizeof(NONCLIENTMETRICSW);
254     gspv.ncm.iBorderWidth = SpiLoadMetric(VAL_BORDER, 1);
255     gspv.ncm.iScrollWidth = SpiLoadMetric(L"ScrollWidth", 16);
256     gspv.ncm.iScrollHeight = SpiLoadMetric(L"ScrollHeight", 16);
257     gspv.ncm.iCaptionWidth = SpiLoadMetric(L"CaptionWidth", 19);
258     gspv.ncm.iCaptionHeight = SpiLoadMetric(L"CaptionHeight", 19);
259     gspv.ncm.iSmCaptionWidth = SpiLoadMetric(L"SmCaptionWidth", 12);
260     gspv.ncm.iSmCaptionHeight = SpiLoadMetric(L"SmCaptionHeight", 15);
261     gspv.ncm.iMenuWidth = SpiLoadMetric(L"MenuWidth", 18);
262     gspv.ncm.iMenuHeight = SpiLoadMetric(L"MenuHeight", 18);
263 #if (WINVER >= 0x0600)
264     gspv.ncm.iPaddedBorderWidth = SpiLoadMetric(L"PaddedBorderWidth", 18);
265 #endif
266     SpiLoadFont(&gspv.ncm.lfCaptionFont, L"CaptionFont", &lf2);
267     SpiLoadFont(&gspv.ncm.lfSmCaptionFont, L"SmCaptionFont", &lf1);
268     SpiLoadFont(&gspv.ncm.lfMenuFont, L"MenuFont", &lf1);
269     SpiLoadFont(&gspv.ncm.lfStatusFont, L"StatusFont", &lf1);
270     SpiLoadFont(&gspv.ncm.lfMessageFont, L"MessageFont", &lf1);
271 
272     /* Load MINIMIZEDMETRICS */
273     gspv.mm.cbSize = sizeof(MINIMIZEDMETRICS);
274     gspv.mm.iWidth = SpiLoadMetric(L"MinWidth", 160);
275     gspv.mm.iHorzGap = SpiLoadMetric(L"MinHorzGap", 160);
276     gspv.mm.iVertGap = SpiLoadMetric(L"MinVertGap", 24);
277     gspv.mm.iArrange = SpiLoadInt(KEY_METRIC, L"MinArrange", ARW_HIDE);
278 
279     /* Load ICONMETRICS */
280     gspv.im.cbSize = sizeof(ICONMETRICSW);
281     gspv.im.iHorzSpacing = SpiLoadMetric(VAL_ICONSPC, 64);
282     gspv.im.iVertSpacing = SpiLoadMetric(VAL_ICONVSPC, 64);
283     gspv.im.iTitleWrap = SpiLoadMetric(VAL_ITWRAP, 1);
284     SpiLoadFont(&gspv.im.lfFont, L"IconFont", &lf1);
285 
286     /* Load desktop settings */
287     gspv.bDragFullWindows = SpiLoadInt(KEY_DESKTOP, VAL_DRAG, 0);
288     gspv.iWheelScrollLines = SpiLoadInt(KEY_DESKTOP, VAL_SCRLLLINES, 3);
289     gspv.dwMouseClickLockTime = SpiLoadDWord(KEY_DESKTOP, VAL_CLICKLOCKTIME, 1200);
290     gpsi->dtCaretBlink = SpiLoadInt(KEY_DESKTOP, VAL_CARETRATE, 530);
291     gspv.dwUserPrefMask = SpiLoadUserPrefMask(UPM_DEFAULT);
292     gspv.bMouseClickLock = (gspv.dwUserPrefMask & UPM_CLICKLOCK) != 0;
293     gspv.bMouseCursorShadow = (gspv.dwUserPrefMask & UPM_CURSORSHADOW) != 0;
294     gspv.bFontSmoothing = SpiLoadInt(KEY_DESKTOP, VAL_FONTSMOOTHING, 0) == 2;
295     gspv.uiFontSmoothingType = SpiLoadDWord(KEY_DESKTOP, VAL_FONTSMOOTHINGTYPE, 1);
296     gspv.uiFontSmoothingContrast = SpiLoadDWord(KEY_DESKTOP, VAL_FONTSMOOTHINGCONTRAST, 1400);
297     gspv.uiFontSmoothingOrientation = SpiLoadDWord(KEY_DESKTOP, VAL_FONTSMOOTHINGORIENTATION, 1);
298 #if (_WIN32_WINNT >= 0x0600)
299     gspv.uiWheelScrollChars = SpiLoadInt(KEY_DESKTOP, VAL_SCRLLCHARS, 3);
300 #endif
301 
302     /* Some hardcoded values for now */
303 
304     gspv.tmCaptionFont.tmAveCharWidth = 6;
305     gspv.bBeep = TRUE;
306     gspv.uiFocusBorderWidth = 1;
307     gspv.uiFocusBorderHeight = 1;
308     gspv.bMenuDropAlign = 0;
309     gspv.dwMenuShowDelay = SpiLoadInt(KEY_DESKTOP, L"MenuShowDelay", 400);
310     gspv.dwForegroundFlashCount = 3;
311 
312     gspv.iScrSaverTimeout = SpiLoadTimeOut();
313     gspv.bScrSaverActive = FALSE;
314     gspv.bScrSaverRunning = FALSE;
315 #if(WINVER >= 0x0600)
316     gspv.bScrSaverSecure = FALSE;
317 #endif
318 
319     gspv.bFastTaskSwitch = TRUE;
320 
321     gspv.accesstimeout.cbSize = sizeof(ACCESSTIMEOUT);
322     gspv.filterkeys.cbSize = sizeof(FILTERKEYS);
323     gspv.togglekeys.cbSize = sizeof(TOGGLEKEYS);
324     gspv.mousekeys.cbSize = sizeof(MOUSEKEYS);
325     gspv.stickykeys.cbSize = sizeof(STICKYKEYS);
326     gspv.serialkeys.cbSize = sizeof(SERIALKEYS);
327     gspv.soundsentry.cbSize = sizeof(SOUNDSENTRYW);
328     gspv.highcontrast.cbSize = sizeof(HIGHCONTRASTW);
329     gspv.animationinfo.cbSize = sizeof(ANIMATIONINFO);
330 
331     /* Make sure we don't use broken values */
332     SpiFixupValues();
333 
334     /* Update SystemMetrics */
335     InitMetrics();
336 
337     if (gbSpiInitialized && gpsi)
338     {
339        if (gspv.bKbdPref) gpsi->dwSRVIFlags |= SRVINFO_KBDPREF;
340        if (SPITESTPREF(UPM_KEYBOARDCUES)) gpsi->PUSIFlags |= PUSIF_KEYBOARDCUES;
341        if (SPITESTPREF(UPM_COMBOBOXANIMATION)) gpsi->PUSIFlags |= PUSIF_COMBOBOXANIMATION;
342        if (SPITESTPREF(UPM_LISTBOXSMOOTHSCROLLING)) gpsi->PUSIFlags |= PUSIF_LISTBOXSMOOTHSCROLLING;
343     }
344     gdwLanguageToggleKey = UserGetLanguageToggle();
345 }
346 
347 BOOL
348 InitSysParams(VOID)
349 {
350     SpiUpdatePerUserSystemParameters();
351     gbSpiInitialized = TRUE;
352     return TRUE;
353 }
354 
355 
356 BOOL
357 APIENTRY
358 NtUserUpdatePerUserSystemParameters(
359     DWORD dwReserved,
360     BOOL bEnable)
361 {
362     BOOL bResult;
363 
364     TRACE("Enter NtUserUpdatePerUserSystemParameters\n");
365     UserEnterExclusive();
366 
367     SpiUpdatePerUserSystemParameters();
368     if(bEnable)
369         g_PaintDesktopVersion = SpiLoadDWord(KEY_DESKTOP, VAL_PAINTDESKVER, 0);
370     else
371         g_PaintDesktopVersion = FALSE;
372     bResult = TRUE;
373 
374     TRACE("Leave NtUserUpdatePerUserSystemParameters, returning %d\n", bResult);
375     UserLeave();
376 
377     return bResult;
378 }
379 
380 
381 /** Storing the settings ******************************************************/
382 
383 static
384 VOID
385 SpiStoreDWord(PCWSTR pwszKey, PCWSTR pwszValue, DWORD Value)
386 {
387     RegWriteUserSetting(pwszKey,
388                         pwszValue,
389                         REG_DWORD,
390                         &Value,
391                         sizeof(Value));
392 }
393 
394 static
395 VOID
396 SpiStoreSz(PCWSTR pwszKey, PCWSTR pwszValue, PCWSTR pwsz)
397 {
398     RegWriteUserSetting(pwszKey,
399                         pwszValue,
400                         REG_SZ,
401                         pwsz,
402                         (wcslen(pwsz) + 1) * sizeof(WCHAR));
403 }
404 
405 static
406 VOID
407 SpiStoreSzInt(PCWSTR pwszKey, PCWSTR pwszValue, INT iValue)
408 {
409     WCHAR awcBuffer[15];
410 
411     _itow(iValue, awcBuffer, 10);
412     RegWriteUserSetting(pwszKey,
413                         pwszValue,
414                         REG_SZ,
415                         awcBuffer,
416                         (wcslen(awcBuffer) + 1) * sizeof(WCHAR));
417 }
418 
419 static
420 VOID
421 SpiStoreMetric(LPCWSTR pwszValue, INT iValue)
422 {
423     SpiStoreSzInt(KEY_METRIC, pwszValue, METRIC2REG(iValue));
424 }
425 
426 static
427 VOID
428 SpiStoreFont(PCWSTR pwszValue, LOGFONTW* plogfont)
429 {
430     RegWriteUserSetting(KEY_METRIC,
431                         pwszValue,
432                         REG_BINARY,
433                         plogfont,
434                         sizeof(LOGFONTW));
435 }
436 
437 
438 /** Get/Set value *************************************************************/
439 
440 // FIXME: get rid of the flags and only use this from um. kernel can access data directly.
441 static
442 UINT_PTR
443 SpiMemCopy(PVOID pvDst, PVOID pvSrc, ULONG cbSize, BOOL bProtect)
444 {
445     NTSTATUS Status = STATUS_SUCCESS;
446 
447     if (bProtect)
448     {
449         _SEH2_TRY
450         {
451             RtlCopyMemory(pvDst, pvSrc, cbSize);
452         }
453         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
454         {
455             Status = _SEH2_GetExceptionCode();
456         }
457         _SEH2_END;
458     }
459     else
460     {
461         RtlCopyMemory(pvDst, pvSrc, cbSize);
462     }
463 
464     if (!NT_SUCCESS(Status))
465     {
466         SetLastNtError(Status);
467         ERR("SpiMemCopy failed, pvDst=%p, pvSrc=%p, bProtect=%d\n", pvDst, pvSrc, bProtect);
468     }
469 
470     return NT_SUCCESS(Status);
471 }
472 
473 static inline
474 UINT_PTR
475 SpiGet(PVOID pvParam, PVOID pvData, ULONG cbSize, FLONG fl)
476 {
477     REQ_INTERACTIVE_WINSTA(ERROR_ACCESS_DENIED);
478     return SpiMemCopy(pvParam, pvData, cbSize, fl & SPIF_PROTECT);
479 }
480 
481 static inline
482 UINT_PTR
483 SpiSet(PVOID pvData, PVOID pvParam, ULONG cbSize, FLONG fl)
484 {
485     REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
486     return SpiMemCopy(pvData, pvParam, cbSize, fl & SPIF_PROTECT);
487 }
488 
489 static inline
490 UINT_PTR
491 SpiGetEx(PVOID pvParam, PVOID pvData, ULONG cbSize, FLONG fl)
492 {
493     ULONG cbBufSize;
494     /* Get the cbSite member from UM memory */
495     if (!SpiSet(&cbBufSize, pvParam, sizeof(ULONG), fl))
496         return 0;
497     /* Verify the correct size */
498     if (cbBufSize != cbSize)
499         return 0;
500     return SpiGet(pvParam, pvData, cbSize, fl);
501 }
502 
503 static inline
504 UINT_PTR
505 SpiGetInt(PVOID pvParam, PVOID piValue, FLONG fl)
506 {
507     return SpiGet(pvParam, piValue, sizeof(INT), fl);
508 }
509 
510 static inline
511 UINT_PTR
512 SpiSetYesNo(BOOL *pbData, BOOL bValue, PCWSTR pwszKey, PCWSTR pwszValue, FLONG fl)
513 {
514     REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
515     *pbData = bValue ? TRUE : FALSE;
516     if (fl & SPIF_UPDATEINIFILE)
517     {
518         SpiStoreSz(pwszKey, pwszValue, bValue ? L"Yes" : L"No");
519     }
520     return (UINT_PTR)pwszKey;
521 }
522 
523 static inline
524 UINT_PTR
525 SpiSetBool(BOOL *pbData, INT iValue, PCWSTR pwszKey, PCWSTR pwszValue, FLONG fl)
526 {
527     REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
528     *pbData = iValue ? TRUE : FALSE;
529     if (fl & SPIF_UPDATEINIFILE)
530     {
531         SpiStoreSzInt(pwszKey, pwszValue, iValue);
532     }
533     return (UINT_PTR)pwszKey;
534 }
535 
536 static inline
537 UINT_PTR
538 SpiSetDWord(PVOID pvData, INT iValue, PCWSTR pwszKey, PCWSTR pwszValue, FLONG fl)
539 {
540     REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
541     *(INT*)pvData = iValue;
542     if (fl & SPIF_UPDATEINIFILE)
543     {
544         SpiStoreDWord(pwszKey, pwszValue, iValue);
545     }
546     return (UINT_PTR)pwszKey;
547 }
548 
549 static inline
550 UINT_PTR
551 SpiSetInt(PVOID pvData, INT iValue, PCWSTR pwszKey, PCWSTR pwszValue, FLONG fl)
552 {
553     REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
554     *(INT*)pvData = iValue;
555     if (fl & SPIF_UPDATEINIFILE)
556     {
557         SpiStoreSzInt(pwszKey, pwszValue, iValue);
558     }
559     return (UINT_PTR)pwszKey;
560 }
561 
562 static inline
563 UINT_PTR
564 SpiSetMetric(PVOID pvData, INT iValue, PCWSTR pwszValue, FLONG fl)
565 {
566     REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
567     *(INT*)pvData = iValue;
568     if (fl & SPIF_UPDATEINIFILE)
569     {
570         SpiStoreMetric(pwszValue, iValue);
571     }
572     return (UINT_PTR)KEY_METRIC;
573 }
574 
575 static inline
576 UINT_PTR
577 SpiSetUserPref(DWORD dwMask, PVOID pvValue, FLONG fl)
578 {
579     DWORD dwRegMask;
580     BOOL bValue = PtrToUlong(pvValue);
581 
582     REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
583 
584     /* Set or clear bit according to bValue */
585     gspv.dwUserPrefMask = bValue ? gspv.dwUserPrefMask | dwMask :
586                                    gspv.dwUserPrefMask & ~dwMask;
587 
588     if (fl & SPIF_UPDATEINIFILE)
589     {
590         /* Read current value */
591         if (!RegReadUserSetting(KEY_DESKTOP,
592                                 VAL_USERPREFMASK,
593                                 REG_BINARY,
594                                 &dwRegMask,
595                                 sizeof(DWORD)))
596         {
597             WARN("Failed to read UserPreferencesMask setting\n");
598             dwRegMask = 0;
599         }
600 
601         /* Set or clear bit according to bValue */
602         dwRegMask = bValue ? (dwRegMask | dwMask) : (dwRegMask & ~dwMask);
603 
604         /* write back value */
605         RegWriteUserSetting(KEY_DESKTOP,
606                             VAL_USERPREFMASK,
607                             REG_BINARY,
608                             &dwRegMask,
609                             sizeof(DWORD));
610     }
611 
612     return (UINT_PTR)KEY_DESKTOP;
613 }
614 
615 static inline
616 UINT_PTR
617 SpiGetUserPref(DWORD dwMask, PVOID pvParam, FLONG fl)
618 {
619     INT iValue = gspv.dwUserPrefMask & dwMask ? 1 : 0;
620     return SpiGetInt(pvParam, &iValue, fl);
621 }
622 
623 static
624 UINT_PTR
625 SpiSetWallpaper(PVOID pvParam, FLONG fl)
626 {
627     UNICODE_STRING ustr;
628     WCHAR awc[MAX_PATH];
629     BOOL bResult;
630     HBITMAP hbmp, hOldBitmap;
631     SURFACE *psurfBmp;
632     ULONG ulTile, ulStyle;
633 
634     REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
635 
636     if (!pvParam)
637     {
638         /* FIXME: Reset Wallpaper to registry value */
639         return (UINT_PTR)KEY_DESKTOP;
640     }
641 
642     /* Capture UNICODE_STRING */
643     bResult = SpiMemCopy(&ustr, pvParam, sizeof(ustr), fl & SPIF_PROTECT);
644     if (!bResult)
645     {
646         return 0;
647     }
648     if (ustr.Length > MAX_PATH * sizeof(WCHAR))
649     {
650         return 0;
651     }
652 
653     /* Copy the string buffer name */
654     bResult = SpiMemCopy(gspv.awcWallpaper, ustr.Buffer, ustr.Length, fl & SPIF_PROTECT);
655     if (!bResult)
656     {
657         return 0;
658     }
659 
660     /* Update the UNICODE_STRING */
661     gspv.ustrWallpaper.Buffer = gspv.awcWallpaper;
662     gspv.ustrWallpaper.MaximumLength = MAX_PATH * sizeof(WCHAR);
663     gspv.ustrWallpaper.Length = ustr.Length;
664     gspv.awcWallpaper[ustr.Length / sizeof(WCHAR)] = 0;
665 
666     TRACE("SpiSetWallpaper, name=%S\n", gspv.awcWallpaper);
667 
668     /* Update registry */
669     if (fl & SPIF_UPDATEINIFILE)
670     {
671         SpiStoreSz(KEY_DESKTOP, L"Wallpaper", gspv.awcWallpaper);
672     }
673 
674     /* Got a filename? */
675     if (gspv.awcWallpaper[0] != 0)
676     {
677         /* Convert file name to nt file name */
678         ustr.Buffer = awc;
679         ustr.MaximumLength = MAX_PATH * sizeof(WCHAR);
680         ustr.Length = 0;
681         if (!W32kDosPathNameToNtPathName(gspv.awcWallpaper, &ustr))
682         {
683             ERR("RtlDosPathNameToNtPathName_U failed\n");
684             return 0;
685         }
686 
687         /* Load the Bitmap */
688         hbmp = UserLoadImage(ustr.Buffer);
689         if (!hbmp)
690         {
691             ERR("UserLoadImage failed\n");
692             return 0;
693         }
694 
695         /* Try to get the size of the wallpaper */
696         if (!(psurfBmp = SURFACE_ShareLockSurface(hbmp)))
697         {
698             GreDeleteObject(hbmp);
699             return 0;
700         }
701 
702         gspv.cxWallpaper = psurfBmp->SurfObj.sizlBitmap.cx;
703         gspv.cyWallpaper = psurfBmp->SurfObj.sizlBitmap.cy;
704         gspv.WallpaperMode = wmCenter;
705 
706         SURFACE_ShareUnlockSurface(psurfBmp);
707 
708         /* Change the bitmap's ownership */
709         GreSetObjectOwner(hbmp, GDI_OBJ_HMGR_PUBLIC);
710 
711         /* Yes, Windows really loads the current setting from the registry. */
712         ulTile = SpiLoadInt(KEY_DESKTOP, L"TileWallpaper", 0);
713         ulStyle = SpiLoadInt(KEY_DESKTOP, L"WallpaperStyle", 0);
714         TRACE("SpiSetWallpaper: ulTile=%lu, ulStyle=%lu\n", ulTile, ulStyle);
715 
716         /* Check the values we found in the registry */
717         if (ulTile && !ulStyle)
718         {
719             gspv.WallpaperMode = wmTile;
720         }
721         else if (!ulTile && ulStyle)
722         {
723             if (ulStyle == 2)
724             {
725                 gspv.WallpaperMode = wmStretch;
726             }
727             else if (ulStyle == 6)
728             {
729                 gspv.WallpaperMode = wmFit;
730             }
731             else if (ulStyle == 10)
732             {
733                 gspv.WallpaperMode = wmFill;
734             }
735         }
736     }
737     else
738     {
739         /* Remove wallpaper */
740         gspv.cxWallpaper = 0;
741         gspv.cyWallpaper = 0;
742         hbmp = 0;
743     }
744 
745     /* Take care of the old wallpaper, if any */
746     hOldBitmap = gspv.hbmWallpaper;
747     if(hOldBitmap != NULL)
748     {
749         /* Delete the old wallpaper */
750         GreSetObjectOwner(hOldBitmap, GDI_OBJ_HMGR_POWNED);
751         GreDeleteObject(hOldBitmap);
752     }
753 
754     /* Set the new wallpaper */
755     gspv.hbmWallpaper = hbmp;
756 
757     NtUserRedrawWindow(UserGetShellWindow(), NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
758 
759 
760     return (UINT_PTR)KEY_DESKTOP;
761 }
762 
763 static BOOL
764 SpiNotifyNCMetricsChanged(VOID)
765 {
766     PWND pwndDesktop, pwndCurrent;
767     HWND *ahwnd;
768     USER_REFERENCE_ENTRY Ref;
769     int i;
770 
771     pwndDesktop = UserGetDesktopWindow();
772     ASSERT(pwndDesktop);
773 
774     ahwnd = IntWinListChildren(pwndDesktop);
775     if(!ahwnd)
776         return FALSE;
777 
778     for (i = 0; ahwnd[i]; i++)
779     {
780         pwndCurrent = UserGetWindowObject(ahwnd[i]);
781         if(!pwndCurrent)
782             continue;
783 
784         UserRefObjectCo(pwndCurrent, &Ref);
785         co_WinPosSetWindowPos(pwndCurrent, 0, pwndCurrent->rcWindow.left,pwndCurrent->rcWindow.top,
786                                               pwndCurrent->rcWindow.right-pwndCurrent->rcWindow.left
787                                               ,pwndCurrent->rcWindow.bottom - pwndCurrent->rcWindow.top,
788                               SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|
789                               SWP_NOMOVE|SWP_NOZORDER|SWP_NOREDRAW);
790         UserDerefObjectCo(pwndCurrent);
791     }
792 
793     ExFreePoolWithTag(ahwnd, USERTAG_WINDOWLIST);
794 
795     return TRUE;
796 }
797 
798 static
799 UINT_PTR
800 SpiGetSet(UINT uiAction, UINT uiParam, PVOID pvParam, FLONG fl)
801 {
802     switch (uiAction)
803     {
804         case SPI_GETBEEP:
805             return SpiGetInt(pvParam, &gspv.bBeep, fl);
806 
807         case SPI_SETBEEP:
808             return SpiSetYesNo(&gspv.bBeep, uiParam, KEY_SOUND, VAL_BEEP, fl);
809 
810         case SPI_GETMOUSE:
811             return SpiGet(pvParam, &gspv.caiMouse, 3 * sizeof(INT), fl);
812 
813         case SPI_SETMOUSE:
814             if (!SpiSet(&gspv.caiMouse, pvParam, 3 * sizeof(INT), fl))
815                 return 0;
816             if (fl & SPIF_UPDATEINIFILE)
817             {
818                 SpiStoreSzInt(KEY_MOUSE, VAL_MOUSE1, gspv.caiMouse.FirstThreshold);
819                 SpiStoreSzInt(KEY_MOUSE, VAL_MOUSE2, gspv.caiMouse.SecondThreshold);
820                 SpiStoreSzInt(KEY_MOUSE, VAL_MOUSE3, gspv.caiMouse.Acceleration);
821             }
822             return (UINT_PTR)KEY_MOUSE;
823 
824         case SPI_GETBORDER:
825             return SpiGetInt(pvParam, &gspv.ncm.iBorderWidth, fl);
826 
827         case SPI_SETBORDER:
828             uiParam = max(uiParam, 1);
829             return SpiSetInt(&gspv.ncm.iBorderWidth, uiParam, KEY_METRIC, VAL_BORDER, fl);
830 
831         case SPI_GETKEYBOARDSPEED:
832             return SpiGetInt(pvParam, &gspv.dwKbdSpeed, fl);
833 
834         case SPI_SETKEYBOARDSPEED:
835             return SpiSetInt(&gspv.dwKbdSpeed, uiParam, KEY_KBD, VAL_KBDSPD, fl);
836 
837         case SPI_LANGDRIVER:
838             ERR("SPI_LANGDRIVER is unimplemented\n");
839             break;
840 
841         case SPI_GETSCREENSAVETIMEOUT:
842             return SpiGetInt(pvParam, &gspv.iScrSaverTimeout, fl);
843 
844         case SPI_SETSCREENSAVETIMEOUT:
845             return SpiSetInt(&gspv.iScrSaverTimeout, uiParam, KEY_DESKTOP, VAL_SCRTO, fl);
846 
847         case SPI_GETSCREENSAVEACTIVE:
848             return SpiGetInt(pvParam, &gspv.bScrSaverActive, fl);
849 
850         case SPI_SETSCREENSAVEACTIVE:
851             return SpiSetInt(&gspv.bScrSaverActive, uiParam, KEY_DESKTOP, VAL_SCRACT, fl);
852 
853         case SPI_GETGRIDGRANULARITY:
854             return SpiGetInt(pvParam, &gspv.uiGridGranularity, fl);
855 
856         case SPI_SETGRIDGRANULARITY:
857             return SpiSetInt(&gspv.uiGridGranularity, uiParam, KEY_DESKTOP, VAL_GRID, fl);
858 
859         case SPI_GETDESKWALLPAPER:
860             uiParam = min(uiParam, gspv.ustrWallpaper.Length + 1UL);
861             return SpiGet(pvParam, gspv.awcWallpaper, uiParam, fl);
862 
863         case SPI_SETDESKWALLPAPER:
864             return SpiSetWallpaper(pvParam, fl);
865 
866         case SPI_SETDESKPATTERN:
867             ERR("SPI_SETDESKPATTERN is unimplemented\n");
868             break;
869 
870         case SPI_GETKEYBOARDDELAY:
871             return SpiGetInt(pvParam, &gspv.iKbdDelay, fl);
872 
873         case SPI_SETKEYBOARDDELAY:
874             return SpiSetInt(&gspv.iKbdDelay, uiParam, KEY_KBD, VAL_KBDDELAY, fl);
875 
876         case SPI_ICONHORIZONTALSPACING:
877             if (pvParam)
878             {
879                 return SpiGetInt(pvParam, &gspv.im.iHorzSpacing, fl);
880             }
881             uiParam = max(uiParam, 32);
882             return SpiSetMetric(&gspv.im.iHorzSpacing, uiParam, VAL_ICONSPC, fl);
883 
884         case SPI_ICONVERTICALSPACING:
885             if (pvParam)
886             {
887                 return SpiGetInt(pvParam, &gspv.im.iVertSpacing, fl);
888             }
889             uiParam = max(uiParam, 32);
890             return SpiSetMetric(&gspv.im.iVertSpacing, uiParam, VAL_ICONVSPC, fl);
891 
892         case SPI_GETICONTITLEWRAP:
893             return SpiGetInt(pvParam, &gspv.im.iTitleWrap, fl);
894 
895         case SPI_SETICONTITLEWRAP:
896             return SpiSetInt(&gspv.im.iTitleWrap, uiParam, KEY_METRIC, VAL_ITWRAP, fl);
897 
898         case SPI_GETMENUDROPALIGNMENT:
899             return SpiGetInt(pvParam, &gspv.bMenuDropAlign, fl);
900 
901         case SPI_SETMENUDROPALIGNMENT:
902             return SpiSetBool(&gspv.bMenuDropAlign, uiParam, KEY_MDALIGN, VAL_MDALIGN, fl);
903 
904         case SPI_SETDOUBLECLKWIDTH:
905             return SpiSetInt(&gspv.iDblClickWidth, uiParam, KEY_MOUSE, VAL_DBLCLKWIDTH, fl);
906 
907         case SPI_SETDOUBLECLKHEIGHT:
908             return SpiSetInt(&gspv.iDblClickHeight, uiParam, KEY_MOUSE, VAL_DBLCLKHEIGHT, fl);
909 
910         case SPI_GETICONTITLELOGFONT:
911             return SpiGet(pvParam, &gspv.im.lfFont, sizeof(LOGFONTW), fl);
912 
913         case SPI_SETICONTITLELOGFONT:
914             if (!SpiSet(&gspv.im.lfFont, pvParam, sizeof(LOGFONTW), fl))
915                 return 0;
916             if (fl & SPIF_UPDATEINIFILE)
917             {
918                 SpiStoreFont(L"IconFont", &gspv.im.lfFont);
919             }
920             return (UINT_PTR)KEY_METRIC;
921 
922         case SPI_SETDOUBLECLICKTIME:
923             return SpiSetInt(&gspv.iDblClickTime, uiParam, KEY_MOUSE, VAL_DBLCLKTIME, fl);
924 
925         case SPI_SETMOUSEBUTTONSWAP:
926             return SpiSetInt(&gspv.bMouseBtnSwap, uiParam, KEY_MOUSE, VAL_SWAP, fl);
927 
928         case SPI_GETFASTTASKSWITCH:
929             return SpiGetInt(pvParam, &gspv.bFastTaskSwitch, fl);
930 
931         case SPI_SETFASTTASKSWITCH:
932             /* According to Winetest this one is unimplemented */
933             return 1;
934 
935         case SPI_GETDRAGFULLWINDOWS:
936             return SpiGetInt(pvParam, &gspv.bDragFullWindows, fl);
937 
938         case SPI_SETDRAGFULLWINDOWS:
939             return SpiSetInt(&gspv.bDragFullWindows, uiParam, KEY_DESKTOP, VAL_DRAG, fl);
940 
941         case SPI_GETNONCLIENTMETRICS:
942         {
943             return SpiGet(pvParam, &gspv.ncm, sizeof(NONCLIENTMETRICSW), fl);
944         }
945 
946         case SPI_SETNONCLIENTMETRICS:
947         {
948             LPNONCLIENTMETRICSW metrics = (LPNONCLIENTMETRICSW)pvParam;
949 
950             /* Fixup user's structure size */
951             metrics->cbSize = sizeof(NONCLIENTMETRICSW);
952 
953             if (!SpiSet(&gspv.ncm, metrics, sizeof(NONCLIENTMETRICSW), fl))
954                 return 0;
955 
956             if (fl & SPIF_UPDATEINIFILE)
957             {
958                 SpiStoreMetric(VAL_BORDER, gspv.ncm.iBorderWidth);
959                 SpiStoreMetric(L"ScrollWidth", gspv.ncm.iScrollWidth);
960                 SpiStoreMetric(L"ScrollHeight", gspv.ncm.iScrollHeight);
961                 SpiStoreMetric(L"CaptionWidth", gspv.ncm.iCaptionWidth);
962                 SpiStoreMetric(L"CaptionHeight", gspv.ncm.iCaptionHeight);
963                 SpiStoreMetric(L"SmCaptionWidth", gspv.ncm.iSmCaptionWidth);
964                 SpiStoreMetric(L"SmCaptionHeight", gspv.ncm.iSmCaptionHeight);
965                 SpiStoreMetric(L"MenuWidth", gspv.ncm.iMenuWidth);
966                 SpiStoreMetric(L"MenuHeight", gspv.ncm.iMenuHeight);
967 #if (WINVER >= 0x0600)
968                 SpiStoreMetric(L"PaddedBorderWidth", gspv.ncm.iPaddedBorderWidth);
969 #endif
970                 SpiStoreFont(L"CaptionFont", &gspv.ncm.lfCaptionFont);
971                 SpiStoreFont(L"SmCaptionFont", &gspv.ncm.lfSmCaptionFont);
972                 SpiStoreFont(L"MenuFont", &gspv.ncm.lfMenuFont);
973                 SpiStoreFont(L"StatusFont", &gspv.ncm.lfStatusFont);
974                 SpiStoreFont(L"MessageFont", &gspv.ncm.lfMessageFont);
975             }
976 
977             if(!SpiNotifyNCMetricsChanged())
978                 return 0;
979 
980             return (UINT_PTR)KEY_METRIC;
981         }
982 
983         case SPI_GETMINIMIZEDMETRICS:
984         {
985             return SpiGet(pvParam, &gspv.mm, sizeof(MINIMIZEDMETRICS), fl);
986         }
987 
988         case SPI_SETMINIMIZEDMETRICS:
989         {
990             LPMINIMIZEDMETRICS metrics = (LPMINIMIZEDMETRICS)pvParam;
991 
992             /* Fixup user's structure size */
993             metrics->cbSize = sizeof(MINIMIZEDMETRICS);
994 
995             if (!SpiSet(&gspv.mm, metrics, sizeof(MINIMIZEDMETRICS), fl))
996                 return 0;
997 
998             gspv.mm.iWidth = max(0, gspv.mm.iWidth);
999             gspv.mm.iHorzGap = max(0, gspv.mm.iHorzGap);
1000             gspv.mm.iVertGap = max(0, gspv.mm.iVertGap);
1001             gspv.mm.iArrange = gspv.mm.iArrange & 0xf;
1002 
1003             if (fl & SPIF_UPDATEINIFILE)
1004             {
1005                 SpiStoreMetric(L"MinWidth", gspv.mm.iWidth);
1006                 SpiStoreMetric(L"MinHorzGap", gspv.mm.iHorzGap);
1007                 SpiStoreMetric(L"MinVertGap", gspv.mm.iVertGap);
1008                 SpiStoreMetric(L"MinArrange", gspv.mm.iArrange);
1009             }
1010 
1011             return (UINT_PTR)KEY_METRIC;
1012         }
1013 
1014         case SPI_GETICONMETRICS:
1015         {
1016             return SpiGet(pvParam, &gspv.im, sizeof(ICONMETRICSW), fl);
1017         }
1018 
1019         case SPI_SETICONMETRICS:
1020         {
1021             LPICONMETRICSW metrics = (LPICONMETRICSW)pvParam;
1022 
1023             /* Fixup user's structure size */
1024             metrics->cbSize = sizeof(ICONMETRICSW);
1025 
1026             if (!SpiSet(&gspv.im, metrics, sizeof(ICONMETRICSW), fl))
1027                 return 0;
1028 
1029             if (fl & SPIF_UPDATEINIFILE)
1030             {
1031                 SpiStoreMetric(VAL_ICONSPC, gspv.im.iHorzSpacing);
1032                 SpiStoreMetric(VAL_ICONVSPC, gspv.im.iVertSpacing);
1033                 SpiStoreMetric(VAL_ITWRAP, gspv.im.iTitleWrap);
1034                 SpiStoreFont(L"IconFont", &gspv.im.lfFont);
1035             }
1036             return (UINT_PTR)KEY_METRIC;
1037         }
1038 
1039         case SPI_GETWORKAREA:
1040         {
1041             PMONITOR pmonitor = UserGetPrimaryMonitor();
1042 
1043             if(!pmonitor)
1044                 return 0;
1045 
1046             return SpiGet(pvParam, &pmonitor->rcWork, sizeof(RECTL), fl);
1047         }
1048 
1049         case SPI_SETWORKAREA:
1050         {
1051             PMONITOR pmonitor;
1052             RECTL rcWorkArea, rcIntersect;
1053 
1054             if (!pvParam)
1055                 return 0;
1056 
1057             RtlCopyMemory(&rcWorkArea, pvParam, sizeof(rcWorkArea));
1058 
1059             /* fail if empty */
1060             if (RECTL_bIsEmptyRect(&rcWorkArea))
1061                 return 0;
1062 
1063             /* get the nearest monitor */
1064             pmonitor = UserMonitorFromRect(&rcWorkArea, MONITOR_DEFAULTTONEAREST);
1065             if (!pmonitor)
1066                 return 0;
1067 
1068             /* fail unless work area is completely in monitor */
1069             if (!RECTL_bIntersectRect(&rcIntersect, &pmonitor->rcMonitor, &rcWorkArea) ||
1070                 !RtlEqualMemory(&rcIntersect, &rcWorkArea, sizeof(rcIntersect)))
1071             {
1072                 return 0;
1073             }
1074 
1075             if (!SpiSet(&pmonitor->rcWork, pvParam, sizeof(RECTL), fl))
1076                 return 0;
1077 
1078             if (fl & SPIF_UPDATEINIFILE)
1079             {
1080                 // FIXME: What to do?
1081             }
1082             return (UINT_PTR)KEY_DESKTOP;
1083         }
1084 
1085         case SPI_SETPENWINDOWS:
1086             ERR("SPI_SETPENWINDOWS is unimplemented\n");
1087             break;
1088 
1089         case SPI_GETFILTERKEYS:
1090         {
1091             LPFILTERKEYS FilterKeys = (LPFILTERKEYS)pvParam;
1092 
1093             if (uiParam != 0 && uiParam != sizeof(FILTERKEYS))
1094                 return 0;
1095 
1096             if (!FilterKeys || FilterKeys->cbSize != sizeof(FILTERKEYS))
1097                 return 0;
1098 
1099             return SpiGet(pvParam, &gspv.filterkeys, sizeof(FILTERKEYS), fl);
1100         }
1101 
1102         case SPI_SETFILTERKEYS:
1103         {
1104             LPFILTERKEYS FilterKeys = (LPFILTERKEYS)pvParam;
1105 
1106             if (uiParam != 0 && uiParam != sizeof(FILTERKEYS))
1107                 return 0;
1108 
1109             if (!FilterKeys || FilterKeys->cbSize != sizeof(FILTERKEYS))
1110                 return 0;
1111 
1112             if (!SpiSet(&gspv.filterkeys, pvParam, sizeof(FILTERKEYS), fl))
1113                 return 0;
1114 
1115             if (fl & SPIF_UPDATEINIFILE)
1116             {
1117                 // FIXME: What to do?
1118             }
1119             return (UINT_PTR)KEY_DESKTOP;
1120         }
1121 
1122         case SPI_GETTOGGLEKEYS:
1123         {
1124             LPTOGGLEKEYS ToggleKeys = (LPTOGGLEKEYS)pvParam;
1125 
1126             if (uiParam != 0 && uiParam != sizeof(TOGGLEKEYS))
1127                 return 0;
1128 
1129             if (!ToggleKeys || ToggleKeys->cbSize != sizeof(TOGGLEKEYS))
1130                 return 0;
1131 
1132             return SpiGet(pvParam, &gspv.togglekeys, sizeof(TOGGLEKEYS), fl);
1133         }
1134 
1135         case SPI_SETTOGGLEKEYS:
1136         {
1137             LPTOGGLEKEYS ToggleKeys = (LPTOGGLEKEYS)pvParam;
1138 
1139             if (uiParam != 0 && uiParam != sizeof(TOGGLEKEYS))
1140                 return 0;
1141 
1142             if (!ToggleKeys || ToggleKeys->cbSize != sizeof(TOGGLEKEYS))
1143                 return 0;
1144 
1145             if (!SpiSet(&gspv.togglekeys, pvParam, sizeof(TOGGLEKEYS), fl))
1146                 return 0;
1147 
1148             if (fl & SPIF_UPDATEINIFILE)
1149             {
1150                 // FIXME: What to do?
1151             }
1152             return (UINT_PTR)KEY_DESKTOP;
1153         }
1154 
1155         case SPI_GETMOUSEKEYS:
1156         {
1157             LPMOUSEKEYS MouseKeys = (LPMOUSEKEYS)pvParam;
1158 
1159             if (uiParam != 0 && uiParam != sizeof(MOUSEKEYS))
1160                 return 0;
1161 
1162             if (!MouseKeys || MouseKeys->cbSize != sizeof(MOUSEKEYS))
1163                 return 0;
1164 
1165             return SpiGet(pvParam, &gspv.mousekeys, sizeof(MOUSEKEYS), fl);
1166         }
1167 
1168         case SPI_SETMOUSEKEYS:
1169         {
1170             LPMOUSEKEYS MouseKeys = (LPMOUSEKEYS)pvParam;
1171 
1172             if (uiParam != 0 && uiParam != sizeof(MOUSEKEYS))
1173                 return 0;
1174 
1175             if (!MouseKeys || MouseKeys->cbSize != sizeof(MOUSEKEYS))
1176                 return 0;
1177 
1178             if (!SpiSet(&gspv.mousekeys, pvParam, sizeof(MOUSEKEYS), fl))
1179                 return 0;
1180 
1181             if (fl & SPIF_UPDATEINIFILE)
1182             {
1183                 // FIXME: What to do?
1184             }
1185             return (UINT_PTR)KEY_DESKTOP;
1186         }
1187 
1188         case SPI_GETSHOWSOUNDS:
1189             return SpiGetInt(pvParam, &gspv.bShowSounds, fl);
1190 
1191         case SPI_SETSHOWSOUNDS:
1192             return SpiSetBool(&gspv.bShowSounds, uiParam, KEY_SHOWSNDS, VAL_ON, fl);
1193 
1194         case SPI_GETSTICKYKEYS:
1195         {
1196             LPSTICKYKEYS StickyKeys = (LPSTICKYKEYS)pvParam;
1197 
1198             if (uiParam != 0 && uiParam != sizeof(STICKYKEYS))
1199                 return 0;
1200 
1201             if (!StickyKeys || StickyKeys->cbSize != sizeof(STICKYKEYS))
1202                 return 0;
1203 
1204             return SpiGetEx(pvParam, &gspv.stickykeys, sizeof(STICKYKEYS), fl);
1205         }
1206 
1207         case SPI_SETSTICKYKEYS:
1208         {
1209             LPSTICKYKEYS StickyKeys = (LPSTICKYKEYS)pvParam;
1210 
1211             if (uiParam != 0 && uiParam != sizeof(STICKYKEYS))
1212                 return 0;
1213 
1214             if (!StickyKeys || StickyKeys->cbSize != sizeof(STICKYKEYS))
1215                 return 0;
1216 
1217             if (!SpiSet(&gspv.stickykeys, pvParam, sizeof(STICKYKEYS), fl))
1218                 return 0;
1219 
1220             if (fl & SPIF_UPDATEINIFILE)
1221             {
1222                 // FIXME: What to do?
1223             }
1224             return (UINT_PTR)KEY_DESKTOP;
1225         }
1226 
1227         case SPI_GETACCESSTIMEOUT:
1228         {
1229             LPACCESSTIMEOUT AccessTimeout = (LPACCESSTIMEOUT)pvParam;
1230 
1231             if (uiParam != 0 && uiParam != sizeof(ACCESSTIMEOUT))
1232                 return 0;
1233 
1234             if (!AccessTimeout || AccessTimeout->cbSize != sizeof(ACCESSTIMEOUT))
1235                 return 0;
1236 
1237             return SpiGetEx(pvParam, &gspv.accesstimeout, sizeof(ACCESSTIMEOUT), fl);
1238         }
1239 
1240         case SPI_SETACCESSTIMEOUT:
1241         {
1242             LPACCESSTIMEOUT AccessTimeout = (LPACCESSTIMEOUT)pvParam;
1243 
1244             if (uiParam != 0 && uiParam != sizeof(ACCESSTIMEOUT))
1245             {
1246                 return 0;
1247             }
1248 
1249             if (!AccessTimeout || AccessTimeout->cbSize != sizeof(ACCESSTIMEOUT))
1250             {
1251                 return 0;
1252             }
1253 
1254             if (!SpiSet(&gspv.accesstimeout, pvParam, sizeof(ACCESSTIMEOUT), fl))
1255                 return 0;
1256 
1257             if (fl & SPIF_UPDATEINIFILE)
1258             {
1259                 // FIXME: What to do?
1260             }
1261             return (UINT_PTR)KEY_DESKTOP;
1262         }
1263 
1264         case SPI_GETSERIALKEYS:
1265         {
1266             LPSERIALKEYS SerialKeys = (LPSERIALKEYS)pvParam;
1267 
1268             if (uiParam != 0 && uiParam != sizeof(SERIALKEYS))
1269                 return 0;
1270 
1271             if (!SerialKeys || SerialKeys->cbSize != sizeof(SERIALKEYS))
1272                 return 0;
1273 
1274             return SpiGet(pvParam, &gspv.serialkeys, sizeof(SERIALKEYS), fl);
1275         }
1276 
1277         case SPI_SETSERIALKEYS:
1278         {
1279             LPSERIALKEYS SerialKeys = (LPSERIALKEYS)pvParam;
1280 
1281             if (uiParam != 0 && uiParam != sizeof(SERIALKEYS))
1282                 return 0;
1283 
1284             if (!SerialKeys || SerialKeys->cbSize != sizeof(SERIALKEYS))
1285                 return 0;
1286 
1287             if (!SpiSet(&gspv.serialkeys, pvParam, sizeof(SERIALKEYS), fl))
1288                 return 0;
1289 
1290             if (fl & SPIF_UPDATEINIFILE)
1291             {
1292                 // FIXME: What to do?
1293             }
1294             return (UINT_PTR)KEY_DESKTOP;
1295         }
1296 
1297         case SPI_GETSOUNDSENTRY:
1298         {
1299             LPSOUNDSENTRYW SoundsEntry = (LPSOUNDSENTRYW)pvParam;
1300 
1301             if (uiParam != 0 && uiParam != sizeof(SOUNDSENTRYW))
1302                 return 0;
1303 
1304             if (!SoundsEntry || SoundsEntry->cbSize != sizeof(SOUNDSENTRYW))
1305                 return 0;
1306 
1307             return SpiGet(pvParam, &gspv.soundsentry, sizeof(SOUNDSENTRYW), fl);
1308         }
1309 
1310         case SPI_SETSOUNDSENTRY:
1311         {
1312             LPSOUNDSENTRYW SoundsEntry = (LPSOUNDSENTRYW)pvParam;
1313 
1314             if (uiParam != 0 && uiParam != sizeof(SOUNDSENTRYW))
1315                 return 0;
1316 
1317             if (!SoundsEntry || SoundsEntry->cbSize != sizeof(SOUNDSENTRYW))
1318                 return 0;
1319 
1320             if (!SpiSet(&gspv.soundsentry, pvParam, sizeof(SOUNDSENTRYW), fl))
1321                 return 0;
1322 
1323             if (fl & SPIF_UPDATEINIFILE)
1324             {
1325                 // FIXME: What to do?
1326             }
1327             return (UINT_PTR)KEY_DESKTOP;
1328         }
1329 
1330         case SPI_GETHIGHCONTRAST:
1331         {
1332             LPHIGHCONTRASTW highcontrast = (LPHIGHCONTRASTW)pvParam;
1333 
1334             if (uiParam != 0 && uiParam != sizeof(HIGHCONTRASTW))
1335                 return 0;
1336 
1337             if (!highcontrast || highcontrast->cbSize != sizeof(HIGHCONTRASTW))
1338                 return 0;
1339 
1340             return SpiGet(pvParam, &gspv.highcontrast, sizeof(HIGHCONTRASTW), fl);
1341         }
1342 
1343         case SPI_SETHIGHCONTRAST:
1344         {
1345             LPHIGHCONTRASTW highcontrast = (LPHIGHCONTRASTW)pvParam;
1346 
1347             if (uiParam != 0 && uiParam != sizeof(HIGHCONTRASTW))
1348                 return 0;
1349 
1350             if (!highcontrast || highcontrast->cbSize != sizeof(HIGHCONTRASTW))
1351                 return 0;
1352 
1353             if (!SpiSet(&gspv.highcontrast, pvParam, sizeof(HIGHCONTRASTW), fl))
1354                 return 0;
1355 
1356             if (fl & SPIF_UPDATEINIFILE)
1357             {
1358                 // FIXME: What to do?
1359             }
1360             return (UINT_PTR)KEY_DESKTOP;
1361         }
1362 
1363         case SPI_GETKEYBOARDPREF:
1364             return SpiGetInt(pvParam, &gspv.bKbdPref, fl);
1365 
1366         case SPI_SETKEYBOARDPREF:
1367             return SpiSetBool(&gspv.bKbdPref, uiParam, KEY_KDBPREF, VAL_ON, fl);
1368 
1369         case SPI_GETSCREENREADER:
1370             return SpiGetInt(pvParam, &gspv.bScreenReader, fl);
1371 
1372         case SPI_SETSCREENREADER:
1373             return SpiSetBool(&gspv.bScreenReader, uiParam, KEY_SCRREAD, VAL_ON, fl);
1374 
1375         case SPI_GETANIMATION:
1376             return SpiGet(pvParam, &gspv.animationinfo, sizeof(ANIMATIONINFO), fl);
1377 
1378         case SPI_SETANIMATION:
1379             if (!SpiSet(&gspv.animationinfo, pvParam, sizeof(ANIMATIONINFO), fl))
1380                 return 0;
1381             if (fl & SPIF_UPDATEINIFILE)
1382             {
1383                 // FIXME: What to do?
1384             }
1385             return (UINT_PTR)KEY_DESKTOP;
1386 
1387         case SPI_GETFONTSMOOTHING:
1388             return SpiGetInt(pvParam, &gspv.bFontSmoothing, fl);
1389 
1390         case SPI_SETFONTSMOOTHING:
1391             gspv.bFontSmoothing = (uiParam == 2);
1392             if (fl & SPIF_UPDATEINIFILE)
1393             {
1394                 SpiStoreSz(KEY_DESKTOP, VAL_FONTSMOOTHING, (uiParam == 2) ? L"2" : L"0");
1395             }
1396             return (UINT_PTR)KEY_DESKTOP;
1397 
1398         case SPI_SETDRAGWIDTH:
1399             return SpiSetInt(&gspv.iDragWidth, uiParam, KEY_DESKTOP, VAL_DRAGWIDTH, fl);
1400 
1401         case SPI_SETDRAGHEIGHT:
1402             return SpiSetInt(&gspv.iDragHeight, uiParam, KEY_DESKTOP, VAL_DRAGHEIGHT, fl);
1403 
1404         case SPI_SETHANDHELD:
1405             return SpiSetBool(&gspv.bHandHeld, uiParam, KEY_DESKTOP, L"HandHeld", fl);
1406 
1407         case SPI_GETLOWPOWERTIMEOUT:
1408             return SpiGetInt(pvParam, &gspv.iLowPwrTimeout, fl);
1409 
1410         case SPI_GETPOWEROFFTIMEOUT:
1411             return SpiGetInt(pvParam, &gspv.iPwrOffTimeout, fl);
1412 
1413         case SPI_SETLOWPOWERTIMEOUT:
1414             return SpiSetInt(&gspv.iLowPwrTimeout, uiParam, KEY_DESKTOP, L"LowPowerTimeOut", fl);
1415 
1416         case SPI_SETPOWEROFFTIMEOUT:
1417             return SpiSetInt(&gspv.iPwrOffTimeout, uiParam, KEY_DESKTOP, L"PowerOffTimeOut", fl);
1418 
1419         case SPI_GETLOWPOWERACTIVE:
1420             return SpiGetInt(pvParam, &gspv.iPwrOffTimeout, fl);
1421 
1422         case SPI_GETPOWEROFFACTIVE:
1423             return SpiGetInt(pvParam, &gspv.bPwrOffActive, fl);
1424 
1425         case SPI_SETLOWPOWERACTIVE:
1426             return SpiSetBool(&gspv.bLowPwrActive, uiParam, KEY_DESKTOP, L"LowPowerActive", fl);
1427 
1428         case SPI_SETPOWEROFFACTIVE:
1429             return SpiSetBool(&gspv.bPwrOffActive, uiParam, KEY_DESKTOP, L"PowerOffActive", fl);
1430 
1431         case SPI_SETCURSORS:
1432             ERR("SPI_SETCURSORS is unimplemented\n");
1433             break;
1434 
1435         case SPI_SETICONS:
1436             ERR("SPI_SETICONS is unimplemented\n");
1437             break;
1438 
1439         case SPI_GETDEFAULTINPUTLANG:
1440             if (!gspklBaseLayout)
1441                 return FALSE;
1442 
1443             return SpiGet(pvParam, &gspklBaseLayout->hkl, sizeof(HKL), fl);
1444 
1445         case SPI_SETDEFAULTINPUTLANG:
1446         {
1447             HKL hkl;
1448 
1449             /* Note: SPIF_UPDATEINIFILE is not supported */
1450             if ((fl & SPIF_UPDATEINIFILE) || !SpiSet(&hkl, pvParam, sizeof(hkl), fl))
1451                 return FALSE;
1452 
1453             return UserSetDefaultInputLang(hkl);
1454         }
1455 
1456         case SPI_SETLANGTOGGLE:
1457             gdwLanguageToggleKey = UserGetLanguageToggle();
1458             return gdwLanguageToggleKey;
1459             break;
1460 
1461         case SPI_GETWINDOWSEXTENSION:
1462             ERR("SPI_GETWINDOWSEXTENSION is unimplemented\n");
1463             break;
1464 
1465         case SPI_GETMOUSETRAILS:
1466             return SpiGetInt(pvParam, &gspv.iMouseTrails, fl);
1467 
1468         case SPI_SETMOUSETRAILS:
1469             return SpiSetInt(&gspv.iMouseTrails, uiParam, KEY_MOUSE, VAL_MOUSETRAILS, fl);
1470 
1471         case SPI_GETSNAPTODEFBUTTON:
1472             return SpiGetInt(pvParam, &gspv.bSnapToDefBtn, fl);
1473 
1474         case SPI_SETSNAPTODEFBUTTON:
1475             return SpiSetBool(&gspv.bSnapToDefBtn, uiParam, KEY_MOUSE, VAL_SNAPDEFBTN, fl);
1476 
1477         case SPI_GETMOUSEHOVERWIDTH:
1478             return SpiGetInt(pvParam, &gspv.iMouseHoverWidth, fl);
1479 
1480         case SPI_SETMOUSEHOVERWIDTH:
1481             return SpiSetInt(&gspv.iMouseHoverWidth, uiParam, KEY_MOUSE, VAL_HOVERWIDTH, fl);
1482 
1483         case SPI_GETMOUSEHOVERHEIGHT:
1484             return SpiGetInt(pvParam, &gspv.iMouseHoverHeight, fl);
1485 
1486         case SPI_SETMOUSEHOVERHEIGHT:
1487             return SpiSetInt(&gspv.iMouseHoverHeight, uiParam, KEY_MOUSE, VAL_HOVERHEIGHT, fl);
1488 
1489         case SPI_GETMOUSEHOVERTIME:
1490             return SpiGetInt(pvParam, &gspv.iMouseHoverTime, fl);
1491 
1492         case SPI_SETMOUSEHOVERTIME:
1493            /* See http://msdn2.microsoft.com/en-us/library/ms724947.aspx
1494             * copy text from it, if some agument why xp and 2003 behovir diffent
1495             * only if they do not have SP install
1496             * " Windows Server 2003 and Windows XP: The operating system does not
1497             *   enforce the use of USER_TIMER_MAXIMUM and USER_TIMER_MINIMUM until
1498             *   Windows Server 2003 SP1 and Windows XP SP2 "
1499             */
1500             return SpiSetInt(&gspv.iMouseHoverTime, uiParam, KEY_MOUSE, VAL_HOVERTIME, fl);
1501 
1502         case SPI_GETWHEELSCROLLLINES:
1503             return SpiGetInt(pvParam, &gspv.iWheelScrollLines, fl);
1504 
1505         case SPI_SETWHEELSCROLLLINES:
1506             return SpiSetInt(&gspv.iWheelScrollLines, uiParam, KEY_DESKTOP, VAL_SCRLLLINES, fl);
1507 
1508         case SPI_GETMENUSHOWDELAY:
1509             return SpiGetInt(pvParam, &gspv.dwMenuShowDelay, fl);
1510 
1511         case SPI_SETMENUSHOWDELAY:
1512             return SpiSetInt(&gspv.dwMenuShowDelay, uiParam, KEY_DESKTOP, L"MenuShowDelay", fl);
1513 
1514 #if (_WIN32_WINNT >= 0x0600)
1515         case SPI_GETWHEELSCROLLCHARS:
1516             return SpiGetInt(pvParam, &gspv.uiWheelScrollChars, fl);
1517 
1518         case SPI_SETWHEELSCROLLCHARS:
1519             return SpiSetInt(&gspv.uiWheelScrollChars, uiParam, KEY_DESKTOP, VAL_SCRLLCHARS, fl);
1520 #endif
1521         case SPI_GETSHOWIMEUI:
1522             return SpiGetInt(pvParam, &gspv.bShowImeUi, fl);
1523 
1524         case SPI_SETSHOWIMEUI:
1525             return SpiSetBool(&gspv.bShowImeUi, uiParam, KEY_DESKTOP, L"", fl);
1526 
1527         case SPI_GETMOUSESPEED:
1528             return SpiGetInt(pvParam, &gspv.iMouseSpeed, fl);
1529 
1530         case SPI_SETMOUSESPEED:
1531         {
1532             /* Allowed range is [1:20] */
1533             if ((INT_PTR)pvParam < 1 || (INT_PTR)pvParam > 20)
1534                 return 0;
1535             else
1536                 return SpiSetInt(&gspv.iMouseSpeed, (INT_PTR)pvParam, KEY_MOUSE, VAL_SENSITIVITY, fl);
1537         }
1538 
1539         case SPI_GETSCREENSAVERRUNNING:
1540             return SpiGetInt(pvParam, &gspv.bScrSaverRunning, fl);
1541 
1542         case SPI_SETSCREENSAVERRUNNING:
1543             // FIXME: also return value?
1544             return SpiSetBool(&gspv.bScrSaverRunning, uiParam, KEY_MOUSE, L"", fl);
1545 
1546 #if(WINVER >= 0x0600)
1547         case SPI_GETAUDIODESCRIPTION:
1548             return SpiGet(pvParam, &gspv.audiodescription, sizeof(AUDIODESCRIPTION), fl);
1549 
1550         case SPI_SETAUDIODESCRIPTION:
1551             ERR("SPI_SETAUDIODESCRIPTION is unimplemented\n");
1552             break;
1553 
1554         case SPI_GETSCREENSAVESECURE:
1555             return SpiGetInt(pvParam, &gspv.bScrSaverSecure, fl);
1556 
1557         case SPI_SETSCREENSAVESECURE:
1558             return SpiSetBool(&gspv.bScrSaverSecure, uiParam, KEY_DESKTOP, L"ScreenSaverIsSecure", fl);
1559 #endif
1560 
1561         case SPI_GETACTIVEWINDOWTRACKING:
1562             return SpiGetUserPref(UPM_ACTIVEWINDOWTRACKING, pvParam, fl);
1563 
1564         case SPI_SETACTIVEWINDOWTRACKING:
1565             return SpiSetUserPref(UPM_ACTIVEWINDOWTRACKING, pvParam, fl);
1566 
1567         case SPI_GETMENUANIMATION:
1568             return SpiGetUserPref(UPM_MENUANIMATION, pvParam, fl);
1569 
1570         case SPI_SETMENUANIMATION:
1571             return SpiSetUserPref(UPM_MENUANIMATION, pvParam, fl);
1572 
1573         case SPI_GETCOMBOBOXANIMATION:
1574             return SpiGetUserPref(UPM_COMBOBOXANIMATION, pvParam, fl);
1575 
1576         case SPI_SETCOMBOBOXANIMATION:
1577             return SpiSetUserPref(UPM_COMBOBOXANIMATION, pvParam, fl);
1578 
1579         case SPI_GETLISTBOXSMOOTHSCROLLING:
1580             return SpiGetUserPref(UPM_LISTBOXSMOOTHSCROLLING, pvParam, fl);
1581 
1582         case SPI_SETLISTBOXSMOOTHSCROLLING:
1583             return SpiSetUserPref(UPM_LISTBOXSMOOTHSCROLLING, pvParam, fl);
1584 
1585         case SPI_GETGRADIENTCAPTIONS:
1586             return SpiGetUserPref(UPM_GRADIENTCAPTIONS, pvParam, fl);
1587 
1588         case SPI_SETGRADIENTCAPTIONS:
1589             return SpiSetUserPref(UPM_GRADIENTCAPTIONS, pvParam, fl);
1590 
1591         case SPI_GETKEYBOARDCUES:
1592             return SpiGetUserPref(UPM_KEYBOARDCUES, pvParam, fl);
1593 
1594         case SPI_SETKEYBOARDCUES:
1595             return SpiSetUserPref(UPM_KEYBOARDCUES, pvParam, fl);
1596 
1597         case SPI_GETACTIVEWNDTRKZORDER:
1598             return SpiGetUserPref(UPM_ACTIVEWNDTRKZORDER, pvParam, fl);
1599 
1600         case SPI_SETACTIVEWNDTRKZORDER:
1601             return SpiSetUserPref(UPM_ACTIVEWNDTRKZORDER, pvParam, fl);
1602 
1603         case SPI_GETHOTTRACKING:
1604             return SpiGetUserPref(UPM_HOTTRACKING, pvParam, fl);
1605 
1606         case SPI_SETHOTTRACKING:
1607             return SpiSetUserPref(UPM_HOTTRACKING, pvParam, fl);
1608 
1609         case SPI_GETMENUFADE:
1610             return SpiGetUserPref(UPM_MENUFADE, pvParam, fl);
1611 
1612         case SPI_SETMENUFADE:
1613             return SpiSetUserPref(UPM_MENUFADE, pvParam, fl);
1614 
1615         case SPI_GETSELECTIONFADE:
1616             return SpiGetUserPref(UPM_SELECTIONFADE, pvParam, fl);
1617 
1618         case SPI_SETSELECTIONFADE:
1619             return SpiSetUserPref(UPM_SELECTIONFADE, pvParam, fl);
1620 
1621         case SPI_GETTOOLTIPANIMATION:
1622             return SpiGetUserPref(UPM_TOOLTIPANIMATION, pvParam, fl);
1623 
1624         case SPI_SETTOOLTIPANIMATION:
1625             return SpiSetUserPref(UPM_TOOLTIPANIMATION, pvParam, fl);
1626 
1627         case SPI_GETTOOLTIPFADE:
1628             return SpiGetUserPref(UPM_TOOLTIPFADE, pvParam, fl);
1629 
1630         case SPI_SETTOOLTIPFADE:
1631             return SpiSetUserPref(UPM_TOOLTIPFADE, pvParam, fl);
1632 
1633         case SPI_GETCURSORSHADOW:
1634             return SpiGetUserPref(UPM_CURSORSHADOW, pvParam, fl);
1635 
1636         case SPI_SETCURSORSHADOW:
1637             gspv.bMouseCursorShadow = PtrToUlong(pvParam);
1638             return SpiSetUserPref(UPM_CURSORSHADOW, pvParam, fl);
1639 
1640         case SPI_GETUIEFFECTS:
1641             return SpiGetUserPref(UPM_UIEFFECTS, pvParam, fl);
1642 
1643         case SPI_SETUIEFFECTS:
1644             return SpiSetUserPref(UPM_UIEFFECTS, pvParam, fl);
1645 
1646         case SPI_GETMOUSESONAR:
1647             return SpiGetInt(pvParam, &gspv.bMouseSonar, fl);
1648 
1649         case SPI_SETMOUSESONAR:
1650             return SpiSetBool(&gspv.bMouseSonar, uiParam, KEY_MOUSE, L"", fl);
1651 
1652         case SPI_GETMOUSECLICKLOCK:
1653             return SpiGetUserPref(UPM_CLICKLOCK, pvParam, fl);
1654 
1655         case SPI_SETMOUSECLICKLOCK:
1656             gspv.bMouseClickLock = PtrToUlong(pvParam);
1657             return SpiSetUserPref(UPM_CLICKLOCK, pvParam, fl);
1658 
1659         case SPI_GETMOUSEVANISH:
1660             return SpiGetInt(pvParam, &gspv.bMouseVanish, fl);
1661 
1662         case SPI_SETMOUSEVANISH:
1663             return SpiSetBool(&gspv.bMouseVanish, uiParam, KEY_MOUSE, L"", fl);
1664 
1665         case SPI_GETFLATMENU:
1666             return SpiGetUserPref(UPM_FLATMENU, pvParam, fl);
1667 
1668         case SPI_SETFLATMENU:
1669             return SpiSetUserPref(UPM_FLATMENU, pvParam, fl);
1670 
1671         case SPI_GETDROPSHADOW:
1672             return SpiGetUserPref(UPM_DROPSHADOW, pvParam, fl);
1673 
1674         case SPI_SETDROPSHADOW:
1675             return SpiSetUserPref(UPM_DROPSHADOW, pvParam, fl);
1676 
1677         case SPI_GETBLOCKSENDINPUTRESETS:
1678             return SpiGetInt(pvParam, &gspv.bBlockSendInputResets, fl);
1679 
1680         case SPI_SETBLOCKSENDINPUTRESETS:
1681             return SpiSetBool(&gspv.bBlockSendInputResets, uiParam, KEY_MOUSE, L"", fl);
1682 
1683 #if(_WIN32_WINNT >= 0x0600)
1684         case SPI_GETDISABLEOVERLAPPEDCONTENT:
1685             return SpiGetInt(pvParam, &gspv.bDisableOverlappedContent, fl);
1686 
1687         case SPI_SETDISABLEOVERLAPPEDCONTENT:
1688             return SpiSetBool(&gspv.bDisableOverlappedContent, uiParam, KEY_MOUSE, L"", fl);
1689 
1690         case SPI_GETCLIENTAREAANIMATION:
1691             return SpiGetInt(pvParam, &gspv.bClientAreaAnimation, fl);
1692 
1693         case SPI_SETCLIENTAREAANIMATION:
1694             return SpiSetBool(&gspv.bClientAreaAnimation, uiParam, KEY_MOUSE, L"", fl);
1695 
1696         case SPI_GETCLEARTYPE:
1697             return SpiGetInt(pvParam, &gspv.bClearType, fl);
1698 
1699         case SPI_SETCLEARTYPE:
1700             return SpiSetBool(&gspv.bClearType, uiParam, KEY_MOUSE, L"", fl);
1701 
1702         case SPI_GETSPEECHRECOGNITION:
1703             return SpiGetInt(pvParam, &gspv.bSpeechRecognition, fl);
1704 
1705         case SPI_SETSPEECHRECOGNITION:
1706             return SpiSetBool(&gspv.bSpeechRecognition, uiParam, KEY_MOUSE, L"", fl);
1707 #endif
1708 
1709         case SPI_GETFOREGROUNDLOCKTIMEOUT:
1710             return SpiGetInt(pvParam, &gspv.dwForegroundLockTimeout, fl);
1711 
1712         case SPI_SETFOREGROUNDLOCKTIMEOUT:
1713             return SpiSetInt(&gspv.dwForegroundLockTimeout, uiParam, KEY_MOUSE, L"", fl);
1714 
1715         case SPI_GETACTIVEWNDTRKTIMEOUT:
1716             return SpiGetInt(pvParam, &gspv.dwActiveTrackingTimeout, fl);
1717 
1718         case SPI_SETACTIVEWNDTRKTIMEOUT:
1719             return SpiSetInt(&gspv.dwActiveTrackingTimeout, uiParam, KEY_MOUSE, L"", fl);
1720 
1721         case SPI_GETFOREGROUNDFLASHCOUNT:
1722             return SpiGetInt(pvParam, &gspv.dwForegroundFlashCount, fl);
1723 
1724         case SPI_SETFOREGROUNDFLASHCOUNT:
1725             return SpiSetInt(&gspv.dwForegroundFlashCount, uiParam, KEY_MOUSE, L"", fl);
1726 
1727         case SPI_GETCARETWIDTH:
1728             return SpiGetInt(pvParam, &gspv.dwCaretWidth, fl);
1729 
1730         case SPI_SETCARETWIDTH:
1731             return SpiSetInt(&gspv.dwCaretWidth, uiParam, KEY_MOUSE, L"", fl);
1732 
1733         case SPI_GETMOUSECLICKLOCKTIME:
1734             return SpiGetInt(pvParam, &gspv.dwMouseClickLockTime, fl);
1735 
1736         case SPI_SETMOUSECLICKLOCKTIME:
1737             return SpiSetDWord(&gspv.dwMouseClickLockTime, uiParam, KEY_DESKTOP, VAL_CLICKLOCKTIME, fl);
1738 
1739         case SPI_GETFONTSMOOTHINGTYPE:
1740             return SpiGetInt(pvParam, &gspv.uiFontSmoothingType, fl);
1741 
1742         case SPI_SETFONTSMOOTHINGTYPE:
1743             return SpiSetDWord(&gspv.uiFontSmoothingType, PtrToUlong(pvParam), KEY_DESKTOP, VAL_FONTSMOOTHINGTYPE, fl);
1744 
1745         case SPI_GETFONTSMOOTHINGCONTRAST:
1746             return SpiGetInt(pvParam, &gspv.uiFontSmoothingContrast, fl);
1747 
1748         case SPI_SETFONTSMOOTHINGCONTRAST:
1749             return SpiSetDWord(&gspv.uiFontSmoothingContrast, PtrToUlong(pvParam), KEY_DESKTOP, VAL_FONTSMOOTHINGCONTRAST, fl);
1750 
1751         case SPI_GETFOCUSBORDERWIDTH:
1752             return SpiGetInt(pvParam, &gspv.uiFocusBorderWidth, fl);
1753 
1754         case SPI_SETFOCUSBORDERWIDTH:
1755             return SpiSetInt(&gspv.uiFocusBorderWidth, uiParam, KEY_MOUSE, L"", fl);
1756 
1757         case SPI_GETFOCUSBORDERHEIGHT:
1758             return SpiGetInt(pvParam, &gspv.uiFocusBorderHeight, fl);
1759 
1760         case SPI_SETFOCUSBORDERHEIGHT:
1761             return SpiSetInt(&gspv.uiFocusBorderHeight, uiParam, KEY_MOUSE, L"", fl);
1762 
1763         case SPI_GETFONTSMOOTHINGORIENTATION:
1764             return SpiGetInt(pvParam, &gspv.uiFontSmoothingOrientation, fl);
1765 
1766         case SPI_SETFONTSMOOTHINGORIENTATION:
1767             return SpiSetDWord(&gspv.uiFontSmoothingOrientation, PtrToUlong(pvParam), KEY_DESKTOP, VAL_FONTSMOOTHINGORIENTATION, fl);
1768 
1769         /* The following are undocumented, but valid SPI values */
1770         case 0x1010:
1771         case 0x1011:
1772         case 0x1028:
1773         case 0x1029:
1774         case 0x102A:
1775         case 0x102B:
1776         case 0x102C:
1777         case 0x102D:
1778         case 0x102E:
1779         case 0x102F:
1780         case 0x1030:
1781         case 0x1031:
1782         case 0x1032:
1783         case 0x1033:
1784         case 0x1034:
1785         case 0x1035:
1786         case 0x1036:
1787         case 0x1037:
1788         case 0x1038:
1789         case 0x1039:
1790         case 0x103A:
1791         case 0x103B:
1792         case 0x103C:
1793         case 0x103D:
1794             ERR("Undocumented SPI value %x is unimplemented\n", uiAction);
1795             break;
1796 
1797         default:
1798             ERR("Invalid SPI value: %u\n", uiAction);
1799             EngSetLastError(ERROR_INVALID_PARAMETER);
1800             return 0;
1801     }
1802 
1803     return 0;
1804 }
1805 
1806 static BOOL
1807 SpiGetSetProbeBuffer(UINT uiAction, UINT uiParam, PVOID pvParam)
1808 {
1809     BOOL bToUser = TRUE;
1810     ULONG cbSize = 0;
1811 
1812     switch (uiAction)
1813     {
1814         case SPI_GETBEEP:
1815         case SPI_GETBORDER:
1816         case SPI_GETKEYBOARDSPEED:
1817         case SPI_GETSCREENSAVETIMEOUT:
1818         case SPI_GETSCREENSAVEACTIVE:
1819         case SPI_GETGRIDGRANULARITY:
1820         case SPI_GETKEYBOARDDELAY:
1821         case SPI_GETICONTITLEWRAP:
1822         case SPI_GETMENUDROPALIGNMENT:
1823         case SPI_GETFASTTASKSWITCH:
1824         case SPI_GETDRAGFULLWINDOWS:
1825         case SPI_GETSHOWSOUNDS:
1826         case SPI_GETKEYBOARDPREF:
1827         case SPI_GETSCREENREADER:
1828         case SPI_GETFONTSMOOTHING:
1829         case SPI_GETLOWPOWERTIMEOUT:
1830         case SPI_GETPOWEROFFTIMEOUT:
1831         case SPI_GETLOWPOWERACTIVE:
1832         case SPI_GETPOWEROFFACTIVE:
1833         case SPI_GETMOUSETRAILS:
1834         case SPI_GETSNAPTODEFBUTTON:
1835         case SPI_GETMOUSEHOVERWIDTH:
1836         case SPI_GETMOUSEHOVERHEIGHT:
1837         case SPI_GETMOUSEHOVERTIME:
1838         case SPI_GETWHEELSCROLLLINES:
1839         case SPI_GETMENUSHOWDELAY:
1840 #if (_WIN32_WINNT >= 0x0600)
1841         case SPI_GETWHEELSCROLLCHARS:
1842 #endif
1843         case SPI_GETSHOWIMEUI:
1844         case SPI_GETMOUSESPEED:
1845         case SPI_GETSCREENSAVERRUNNING:
1846 #if(WINVER >= 0x0600)
1847         case SPI_GETSCREENSAVESECURE:
1848 #endif
1849         case SPI_GETACTIVEWINDOWTRACKING:
1850         case SPI_GETMENUANIMATION:
1851         case SPI_GETCOMBOBOXANIMATION:
1852         case SPI_GETLISTBOXSMOOTHSCROLLING:
1853         case SPI_GETGRADIENTCAPTIONS:
1854         case SPI_GETKEYBOARDCUES:
1855         case SPI_GETACTIVEWNDTRKZORDER:
1856         case SPI_GETHOTTRACKING:
1857         case SPI_GETMENUFADE:
1858         case SPI_GETSELECTIONFADE:
1859         case SPI_GETTOOLTIPANIMATION:
1860         case SPI_GETTOOLTIPFADE:
1861         case SPI_GETCURSORSHADOW:
1862         case SPI_GETUIEFFECTS:
1863         case SPI_GETMOUSESONAR:
1864         case SPI_GETMOUSECLICKLOCK:
1865         case SPI_GETMOUSEVANISH:
1866         case SPI_GETFLATMENU:
1867         case SPI_GETDROPSHADOW:
1868         case SPI_GETBLOCKSENDINPUTRESETS:
1869 #if(_WIN32_WINNT >= 0x0600)
1870         case SPI_GETDISABLEOVERLAPPEDCONTENT:
1871         case SPI_GETCLIENTAREAANIMATION:
1872         case SPI_GETCLEARTYPE:
1873         case SPI_GETSPEECHRECOGNITION:
1874 #endif
1875         case SPI_GETFOREGROUNDLOCKTIMEOUT:
1876         case SPI_GETACTIVEWNDTRKTIMEOUT:
1877         case SPI_GETFOREGROUNDFLASHCOUNT:
1878         case SPI_GETCARETWIDTH:
1879         case SPI_GETMOUSECLICKLOCKTIME:
1880         case SPI_GETFONTSMOOTHINGTYPE:
1881         case SPI_GETFONTSMOOTHINGCONTRAST:
1882         case SPI_GETFOCUSBORDERWIDTH:
1883         case SPI_GETFOCUSBORDERHEIGHT:
1884         case SPI_GETFONTSMOOTHINGORIENTATION:
1885             cbSize = sizeof(INT);
1886             break;
1887 
1888         case SPI_ICONHORIZONTALSPACING:
1889         case SPI_ICONVERTICALSPACING:
1890             if (pvParam) cbSize = sizeof(INT);
1891             break;
1892 
1893         case SPI_GETMOUSE:
1894             cbSize = 3 * sizeof(INT);
1895             break;
1896 
1897         case SPI_GETDESKWALLPAPER:
1898             cbSize = min(uiParam, gspv.ustrWallpaper.Length + 1UL);
1899             break;
1900 
1901         case SPI_GETICONTITLELOGFONT:
1902             cbSize = sizeof(LOGFONTW);
1903             break;
1904 
1905         case SPI_GETNONCLIENTMETRICS:
1906             cbSize = sizeof(NONCLIENTMETRICSW);
1907             break;
1908 
1909         case SPI_GETMINIMIZEDMETRICS:
1910             cbSize = sizeof(MINIMIZEDMETRICS);
1911             break;
1912 
1913         case SPI_GETICONMETRICS:
1914             cbSize = sizeof(ICONMETRICSW);
1915             break;
1916 
1917         case SPI_GETWORKAREA:
1918             cbSize = sizeof(RECTL);
1919             break;
1920 
1921         case SPI_GETFILTERKEYS:
1922             cbSize = sizeof(FILTERKEYS);
1923             break;
1924 
1925         case SPI_GETTOGGLEKEYS:
1926             cbSize = sizeof(TOGGLEKEYS);
1927             break;
1928 
1929         case SPI_GETMOUSEKEYS:
1930             cbSize = sizeof(MOUSEKEYS);
1931             break;
1932 
1933         case SPI_GETSTICKYKEYS:
1934             cbSize = sizeof(STICKYKEYS);
1935             break;
1936 
1937         case SPI_GETACCESSTIMEOUT:
1938             cbSize = sizeof(ACCESSTIMEOUT);
1939             break;
1940 
1941         case SPI_GETSERIALKEYS:
1942             cbSize = sizeof(SERIALKEYS);
1943             break;
1944 
1945         case SPI_GETSOUNDSENTRY:
1946             cbSize = sizeof(SOUNDSENTRYW);
1947             break;
1948 
1949         case SPI_GETHIGHCONTRAST:
1950             cbSize = sizeof(HIGHCONTRASTW);
1951             break;
1952 
1953         case SPI_GETANIMATION:
1954             cbSize = sizeof(ANIMATIONINFO);
1955             break;
1956 
1957         case SPI_GETDEFAULTINPUTLANG:
1958             cbSize = sizeof(HKL);
1959             break;
1960 
1961 #if(WINVER >= 0x0600)
1962         case SPI_GETAUDIODESCRIPTION:
1963             cbSize = sizeof(AUDIODESCRIPTION);
1964             break;
1965 #endif
1966 
1967         case SPI_SETMOUSE:
1968             cbSize = 3 * sizeof(INT);
1969             bToUser = FALSE;
1970             break;
1971 
1972         case SPI_SETICONTITLELOGFONT:
1973             cbSize = sizeof(LOGFONTW);
1974             bToUser = FALSE;
1975             break;
1976 
1977         case SPI_SETNONCLIENTMETRICS:
1978             cbSize = sizeof(NONCLIENTMETRICSW);
1979             bToUser = FALSE;
1980             break;
1981 
1982         case SPI_SETMINIMIZEDMETRICS:
1983             cbSize = sizeof(MINIMIZEDMETRICS);
1984             bToUser = FALSE;
1985             break;
1986 
1987         case SPI_SETICONMETRICS:
1988             cbSize = sizeof(ICONMETRICSW);
1989             bToUser = FALSE;
1990             break;
1991 
1992         case SPI_SETWORKAREA:
1993             cbSize = sizeof(RECTL);
1994             bToUser = FALSE;
1995             break;
1996 
1997         case SPI_SETFILTERKEYS:
1998             cbSize = sizeof(FILTERKEYS);
1999             bToUser = FALSE;
2000             break;
2001 
2002         case SPI_SETTOGGLEKEYS:
2003             cbSize = sizeof(TOGGLEKEYS);
2004             bToUser = FALSE;
2005             break;
2006 
2007         case SPI_SETMOUSEKEYS:
2008             cbSize = sizeof(MOUSEKEYS);
2009             bToUser = FALSE;
2010             break;
2011 
2012         case SPI_SETSTICKYKEYS:
2013             cbSize = sizeof(STICKYKEYS);
2014             bToUser = FALSE;
2015             break;
2016 
2017         case SPI_SETACCESSTIMEOUT:
2018             cbSize = sizeof(ACCESSTIMEOUT);
2019             bToUser = FALSE;
2020             break;
2021 
2022         case SPI_SETSERIALKEYS:
2023             cbSize = sizeof(SERIALKEYS);
2024             bToUser = FALSE;
2025             break;
2026 
2027         case SPI_SETSOUNDSENTRY:
2028             cbSize = sizeof(SOUNDSENTRYW);
2029             bToUser = FALSE;
2030             break;
2031 
2032         case SPI_SETHIGHCONTRAST:
2033             cbSize = sizeof(HIGHCONTRASTW);
2034             bToUser = FALSE;
2035             break;
2036 
2037         case SPI_SETANIMATION:
2038             cbSize = sizeof(ANIMATIONINFO);
2039             bToUser = FALSE;
2040             break;
2041 
2042         case SPI_SETDEFAULTINPUTLANG:
2043             cbSize = sizeof(HKL);
2044             bToUser = FALSE;
2045             break;
2046 
2047         case SPI_SETMOUSESPEED:
2048             cbSize = sizeof(INT);
2049             bToUser = FALSE;
2050             break;
2051     }
2052 
2053     if (cbSize)
2054     {
2055         _SEH2_TRY
2056         {
2057             if (bToUser)
2058             {
2059                 ProbeForWrite(pvParam, cbSize, sizeof(UCHAR));
2060             }
2061             else
2062             {
2063                 ProbeForRead(pvParam, cbSize, sizeof(UCHAR));
2064             }
2065         }
2066         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2067         {
2068             _SEH2_YIELD(return FALSE);
2069         }
2070         _SEH2_END;
2071     }
2072 
2073     return TRUE;
2074 }
2075 
2076 BOOL
2077 FASTCALL
2078 UserSystemParametersInfo(
2079     UINT uiAction,
2080     UINT uiParam,
2081     PVOID pvParam,
2082     UINT fWinIni)
2083 {
2084     ULONG_PTR ulResult;
2085     PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
2086 
2087     ASSERT(ppi);
2088 
2089     if (!gbSpiInitialized)
2090     {
2091         KeRosDumpStackFrames(NULL, 20);
2092         //ASSERT(FALSE);
2093         return FALSE;
2094     }
2095 
2096     /* Get a pointer to the current Windowstation */
2097     if (!ppi->prpwinsta)
2098     {
2099         ERR("UserSystemParametersInfo called without active window station.\n");
2100         //ASSERT(FALSE);
2101         //return FALSE;
2102     }
2103 
2104     if ((fWinIni & SPIF_PROTECT) && !SpiGetSetProbeBuffer(uiAction, uiParam, pvParam))
2105     {
2106         EngSetLastError(ERROR_NOACCESS);
2107         return FALSE;
2108     }
2109 
2110     /* Do the actual operation */
2111     ulResult = SpiGetSet(uiAction, uiParam, pvParam, fWinIni);
2112 
2113     /* Did we change something? */
2114     if (ulResult > 1)
2115     {
2116         SpiFixupValues();
2117 
2118         /* Update system metrics */
2119         InitMetrics();
2120 
2121         /* Send notification to toplevel windows, if requested */
2122         if (fWinIni & SPIF_SENDCHANGE)
2123         {
2124             /* Send WM_SETTINGCHANGE to all toplevel windows */
2125             co_IntSendMessageTimeout(HWND_BROADCAST,
2126                                      WM_SETTINGCHANGE,
2127                                      (WPARAM)uiAction,
2128                                      (LPARAM)ulResult,
2129                                      SMTO_NORMAL,
2130                                      100,
2131                                      &ulResult);
2132         }
2133         ulResult = 1;
2134     }
2135 
2136     return ulResult;
2137 }
2138 
2139 BOOL
2140 APIENTRY
2141 NtUserSystemParametersInfo(
2142     UINT uiAction,
2143     UINT uiParam,
2144     PVOID pvParam,
2145     UINT fWinIni)
2146 {
2147     BOOL bResult;
2148 
2149     TRACE("Enter NtUserSystemParametersInfo(%u)\n", uiAction);
2150     UserEnterExclusive();
2151 
2152     // FIXME: Get rid of the flags and only use this from um. kernel can access data directly.
2153     /* Set UM memory protection flag */
2154     fWinIni |= SPIF_PROTECT;
2155 
2156     /* Call internal function */
2157     bResult = UserSystemParametersInfo(uiAction, uiParam, pvParam, fWinIni);
2158 
2159     TRACE("Leave NtUserSystemParametersInfo, returning %d\n", bResult);
2160     UserLeave();
2161 
2162     return bResult;
2163 }
2164 
2165 /* EOF */
2166