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