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