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