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