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