Merge from amd64-branch:
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / sysparams.c
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: subsystem/win32/win32k/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 <w32k.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 #include <winsta.h>
20
21 #define KeRosDumpStackFrames(Frames, Count) KdSystemDebugControl('DsoR', (PVOID)Frames, Count, NULL, 0, NULL, KernelMode)
22 HBITMAP NTAPI UserLoadImage(PCWSTR);
23 BOOL NTAPI W32kDosPathNameToNtPathName(PCWSTR, PUNICODE_STRING);
24
25 BOOL gbDebug = 0;
26 SPIVALUES gspv;
27 BOOL gbSpiInitialized = FALSE;
28 PWINSTATION_OBJECT gpwinstaCurrent = NULL;
29
30 // HACK! We initialize SPI before we have a proper surface to get this from.
31 #define dpi 96
32 //(pPrimarySurface->GDIInfo.ulLogPixelsY)
33 #define REG2METRIC(reg) (reg > 0 ? reg : ((-(reg) * dpi + 720) / 1440))
34 #define METRIC2REG(met) (-((((met) * 1440)- 0) / dpi))
35
36 #define REQ_INTERACTIVE_WINSTA(err) \
37 if (gpwinstaCurrent != InputWindowStation) \
38 { \
39 SetLastWin32Error(err); \
40 return 0; \
41 }
42
43 #define DPRINTX if (gbDebug) DPRINT1
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_SCRACT = L"ScreenSaveActive";
63 static const WCHAR* VAL_GRID = L"GridGranularity";
64 static const WCHAR* VAL_DRAG = L"DragFullWindows";
65 static const WCHAR* VAL_DRAGHEIGHT = L"DragHeight";
66 static const WCHAR* VAL_DRAGWIDTH = L"DragWidth";
67 static const WCHAR* VAL_FNTSMOOTH = L"FontSmoothing";
68 static const WCHAR* VAL_SCRLLLINES = L"WheelScrollLines";
69 static const WCHAR* VAL_CLICKLOCKTIME = L"ClickLockTime";
70 #if (_WIN32_WINNT >= 0x0600)
71 static const WCHAR* VAL_SCRLLCHARS = L"WheelScrollChars";
72 #endif
73 static const WCHAR* VAL_USERPREFMASK = L"UserPreferencesMask";
74
75 static const WCHAR* KEY_MDALIGN = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
76 static const WCHAR* VAL_MDALIGN = L"MenuDropAlignment";
77
78 static const WCHAR* KEY_METRIC = L"Control Panel\\Desktop\\WindowMetrics";
79 static const WCHAR* VAL_BORDER = L"BorderWidth";
80 static const WCHAR* VAL_ICONSPC = L"IconSpacing";
81 static const WCHAR* VAL_ICONVSPC = L"IconVerticalspacing";
82 static const WCHAR* VAL_ITWRAP = L"IconTitleWrap";
83
84 static const WCHAR* KEY_SOUND = L"Control Panel\\Sound";
85 static const WCHAR* VAL_BEEP = L"Beep";
86
87 static const WCHAR* KEY_KBD = L"Control Panel\\Keyboard";
88 static const WCHAR* VAL_KBDSPD = L"KeyboardSpeed";
89 static const WCHAR* VAL_KBDDELAY = L"KeyboardDelay";
90
91 static const WCHAR* KEY_SHOWSNDS = L"Control Panel\\Accessibility\\ShowSounds";
92 static const WCHAR* KEY_KDBPREF = L"Control Panel\\Accessibility\\Keyboard Preference";
93 static const WCHAR* KEY_SCRREAD = L"Control Panel\\Accessibility\\Blind Access";
94 static const WCHAR* VAL_ON = L"On";
95
96
97
98 /** Loading the settings ******************************************************/
99
100 static
101 INT
102 SpiLoadDWord(PCWSTR pwszKey, PCWSTR pwszValue, INT iValue)
103 {
104 DWORD Result;
105 if (!RegReadUserSetting(pwszKey, pwszValue, REG_DWORD, &Result, sizeof(Result)))
106 {
107 return iValue;
108 }
109 return Result;
110 }
111
112 static
113 INT
114 SpiLoadInt(PCWSTR pwszKey, PCWSTR pwszValue, INT iValue)
115 {
116 WCHAR awcBuffer[12];
117 ULONG cbSize;
118
119 cbSize = sizeof(awcBuffer);
120 if (!RegReadUserSetting(pwszKey, pwszValue, REG_SZ, awcBuffer, cbSize))
121 {
122 return iValue;
123 }
124 return _wtoi(awcBuffer);
125 }
126
127 static
128 DWORD
129 SpiLoadUserPrefMask(DWORD dValue)
130 {
131 DWORD Result;
132 if (!RegReadUserSetting(KEY_DESKTOP, VAL_USERPREFMASK, REG_BINARY, &Result, sizeof(Result)))
133 {
134 return dValue;
135 }
136 return Result;
137 }
138
139 static
140 INT
141 SpiLoadMouse(PCWSTR pwszValue, INT iValue)
142 {
143 return SpiLoadInt(KEY_MOUSE, pwszValue, iValue);
144 }
145
146 static
147 INT
148 SpiLoadMetric(PCWSTR pwszValue, INT iValue)
149 {
150 INT iRegVal;
151
152 iRegVal = SpiLoadInt(KEY_METRIC, pwszValue, METRIC2REG(iValue));
153 DPRINT("Loaded metric setting '%S', iValue=%d(reg:%d), ret=%d(reg:%d)\n",
154 pwszValue, iValue, METRIC2REG(iValue), REG2METRIC(iRegVal), iRegVal);
155 return REG2METRIC(iRegVal);
156 }
157
158 static
159 VOID
160 SpiLoadFont(PLOGFONTW plfOut, LPWSTR pwszValueName, PLOGFONTW plfDefault)
161 {
162 BOOL bResult;
163
164 bResult = RegReadUserSetting(KEY_METRIC,
165 pwszValueName,
166 REG_BINARY,
167 plfOut,
168 sizeof(LOGFONTW));
169 if (!bResult)
170 *plfOut = *plfDefault;
171 }
172
173 static
174 VOID
175 SpiFixupValues()
176 {
177 /* Fixup values */
178 gspv.ncm.iCaptionWidth = max(gspv.ncm.iCaptionWidth, 8);
179 gspv.ncm.iBorderWidth = max(gspv.ncm.iBorderWidth, 1);
180 gspv.ncm.iScrollWidth = max(gspv.ncm.iScrollWidth, 8);
181 gspv.ncm.iScrollHeight = max(gspv.ncm.iScrollHeight, 8);
182 // gspv.ncm.iMenuHeight = max(gspv.ncm.iMenuHeight, gspv.tmMenuFont.tmHeight);
183 // gspv.ncm.iMenuHeight = max(gspv.ncm.iMenuHeight,
184 // 2 + gspv.tmMenuFont.tmHeight +
185 // gspv.tmMenuFont.tmExternalLeading);
186 if (gspv.iDblClickTime == 0) gspv.iDblClickTime = 500;
187
188 // FIXME: hack!!!
189 gspv.tmMenuFont.tmHeight = 11;
190 gspv.tmMenuFont.tmExternalLeading = 2;
191
192 gspv.tmCaptionFont.tmHeight = 11;
193 gspv.tmCaptionFont.tmExternalLeading = 2;
194
195 }
196
197 static
198 VOID
199 SpiUpdatePerUserSystemParameters()
200 {
201 static LOGFONTW lf1 = {-11, 0, 0, 0, FW_NORMAL, FALSE, FALSE,
202 FALSE, ANSI_CHARSET, 0, 0, DEFAULT_QUALITY,
203 VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif"};
204 static LOGFONTW lf2 = {-11, 0, 0, 0, FW_BOLD, FALSE, FALSE,
205 FALSE, ANSI_CHARSET, 0, 0, DEFAULT_QUALITY,
206 VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif"};
207
208 DPRINT("Enter SpiUpdatePerUserSystemParameters\n");
209
210 /* Clear the structure */
211 memset(&gspv, 0, sizeof(gspv));
212
213 /* Load mouse settings */
214 gspv.caiMouse.FirstThreshold = SpiLoadMouse(VAL_MOUSE1, 6);
215 gspv.caiMouse.SecondThreshold = SpiLoadMouse(VAL_MOUSE2, 10);
216 gspv.caiMouse.Acceleration = gspv.iMouseSpeed = SpiLoadMouse(VAL_MOUSE3, 1);
217 gspv.bMouseBtnSwap = SpiLoadMouse(VAL_SWAP, 0);
218 gspv.bSnapToDefBtn = SpiLoadMouse(VAL_SNAPDEFBTN, 0);
219 gspv.iMouseTrails = SpiLoadMouse(VAL_MOUSETRAILS, 0);
220 gspv.iDblClickTime = SpiLoadMouse(VAL_DBLCLKTIME, 500);
221 gspv.iDblClickWidth = SpiLoadMouse(VAL_DBLCLKWIDTH, 4);
222 gspv.iDblClickHeight = SpiLoadMouse(VAL_DBLCLKHEIGHT, 4);
223 gspv.iMouseHoverTime = SpiLoadMouse(VAL_HOVERTIME, 400);
224 gspv.iMouseHoverWidth = SpiLoadMouse(VAL_HOVERWIDTH, 4);
225 gspv.iMouseHoverHeight = SpiLoadMouse(VAL_HOVERHEIGHT, 4);
226
227 /* Load NONCLIENTMETRICS */
228 gspv.ncm.cbSize = sizeof(NONCLIENTMETRICSW);
229 gspv.ncm.iBorderWidth = SpiLoadMetric(VAL_BORDER, 1);
230 gspv.ncm.iScrollWidth = SpiLoadMetric(L"ScrollWidth", 16);
231 gspv.ncm.iScrollHeight = SpiLoadMetric(L"ScrollHeight", 16);
232 gspv.ncm.iCaptionWidth = SpiLoadMetric(L"CaptionWidth", 19);
233 gspv.ncm.iCaptionHeight = SpiLoadMetric(L"CaptionHeight", 19);
234 gspv.ncm.iSmCaptionWidth = SpiLoadMetric(L"SmCaptionWidth", 12);
235 gspv.ncm.iSmCaptionHeight = SpiLoadMetric(L"SmCaptionHeight", 14);
236 gspv.ncm.iMenuWidth = SpiLoadMetric(L"MenuWidth", 18);
237 gspv.ncm.iMenuHeight = SpiLoadMetric(L"MenuHeight", 18);
238 #if (WINVER >= 0x0600)
239 gspv.ncm.iPaddedBorderWidth = SpiLoadMetric(L"PaddedBorderWidth", 18);
240 #endif
241 SpiLoadFont(&gspv.ncm.lfCaptionFont, L"CaptionFont", &lf2);
242 SpiLoadFont(&gspv.ncm.lfSmCaptionFont, L"SmCaptionFont", &lf1);
243 SpiLoadFont(&gspv.ncm.lfMenuFont, L"MenuFont", &lf1);
244 SpiLoadFont(&gspv.ncm.lfStatusFont, L"StatusFont", &lf1);
245 SpiLoadFont(&gspv.ncm.lfMessageFont, L"MessageFont", &lf1);
246
247 /* Load MINIMIZEDMETRICS */
248 gspv.mm.cbSize = sizeof(MINIMIZEDMETRICS);
249 gspv.mm.iWidth = SpiLoadMetric(L"MinWidth", 160);
250 gspv.mm.iHorzGap = SpiLoadMetric(L"MinHorzGap", 160);
251 gspv.mm.iVertGap = SpiLoadMetric(L"MinVertGap", 24);
252 gspv.mm.iArrange = SpiLoadInt(KEY_METRIC, L"MinArrange", ARW_HIDE);
253
254 /* Load ICONMETRICS */
255 gspv.im.cbSize = sizeof(ICONMETRICSW);
256 gspv.im.iHorzSpacing = SpiLoadMetric(VAL_ICONSPC, 64);
257 gspv.im.iVertSpacing = SpiLoadMetric(VAL_ICONVSPC, 64);
258 gspv.im.iTitleWrap = SpiLoadMetric(VAL_ITWRAP, 0);
259 SpiLoadFont(&gspv.im.lfFont, L"IconFont", &lf1);
260
261 /* Load desktop settings */
262 gspv.bDragFullWindows = SpiLoadInt(KEY_DESKTOP, VAL_DRAG, 0);
263 gspv.iWheelScrollLines = SpiLoadInt(KEY_DESKTOP, VAL_SCRLLLINES, 3);
264 gspv.dwMouseClickLockTime = SpiLoadDWord(KEY_DESKTOP, VAL_CLICKLOCKTIME, 1200);
265 gspv.dwUserPrefMask = SpiLoadUserPrefMask(UPM_DEFAULT);
266 gspv.bMouseClickLock = (gspv.dwUserPrefMask & UPM_CLICKLOCK) != 0;
267 gspv.bMouseCursorShadow = (gspv.dwUserPrefMask & UPM_CURSORSHADOW) != 0;
268 #if (_WIN32_WINNT >= 0x0600)
269 gspv.iWheelScrollChars = SpiLoadInt(KEY_DESKTOP, VAL_SCRLLCHARS, 3);
270 #endif
271
272 /* Some hardcoded values for now */
273
274 gspv.tmCaptionFont.tmAveCharWidth = 6;
275 gspv.bBeep = TRUE;
276 gspv.bFlatMenu = FALSE;
277 gspv.uiFocusBorderWidth = 1;
278 gspv.uiFocusBorderHeight = 1;
279 gspv.bMenuDropAlign = 1;
280 gspv.bDropShadow = 1;
281 gspv.dwMenuShowDelay = 100;
282
283 gspv.iScrSaverTimeout = 10;
284 gspv.bScrSaverActive = FALSE;
285 gspv.bScrSaverRunning = FALSE;
286 #if(WINVER >= 0x0600)
287 gspv.bScrSaverSecure = FALSE;
288 #endif
289
290 /* Make sure we don't use broken values */
291 SpiFixupValues();
292
293 /* Update SystemMetrics */
294 InitMetrics();
295 }
296
297 BOOL
298 InitSysParams()
299 {
300 SpiUpdatePerUserSystemParameters();
301 gbSpiInitialized = TRUE;
302 return TRUE;
303 }
304
305
306 BOOL
307 APIENTRY
308 NtUserUpdatePerUserSystemParameters(
309 DWORD dwReserved,
310 BOOL bEnable)
311 {
312 BOOL bResult;
313
314 DPRINT("Enter NtUserUpdatePerUserSystemParameters\n");
315 UserEnterExclusive();
316
317 SpiUpdatePerUserSystemParameters();
318 bResult = IntDesktopUpdatePerUserSettings(bEnable);
319
320 DPRINT("Leave NtUserUpdatePerUserSystemParameters, returning %d\n", bResult);
321 UserLeave();
322
323 return bResult;
324 }
325
326
327 /** Storing the settings ******************************************************/
328
329 static
330 VOID
331 SpiStoreDWord(PCWSTR pwszKey, PCWSTR pwszValue, DWORD Value)
332 {
333 RegWriteUserSetting(pwszKey,
334 pwszValue,
335 REG_DWORD,
336 &Value,
337 sizeof(Value));
338 }
339
340 static
341 VOID
342 SpiStoreSz(PCWSTR pwszKey, PCWSTR pwszValue, PCWSTR pwsz)
343 {
344 RegWriteUserSetting(pwszKey,
345 pwszValue,
346 REG_SZ,
347 (PWSTR)pwsz,
348 wcslen(pwsz) * sizeof(WCHAR));
349 }
350
351 static
352 VOID
353 SpiStoreSzInt(PCWSTR pwszKey, PCWSTR pwszValue, INT iValue)
354 {
355 WCHAR awcBuffer[15];
356
357 _itow(iValue, awcBuffer, 10);
358 RegWriteUserSetting(pwszKey,
359 pwszValue,
360 REG_SZ,
361 awcBuffer,
362 (wcslen(awcBuffer) + 1) * sizeof(WCHAR));
363 }
364
365 static
366 VOID
367 SpiStoreMetric(LPCWSTR pwszValue, INT iValue)
368 {
369 SpiStoreSzInt(KEY_METRIC, pwszValue, METRIC2REG(iValue));
370 }
371
372 static
373 VOID
374 SpiStoreFont(PCWSTR pwszValue, LOGFONTW* plogfont)
375 {
376 RegWriteUserSetting(KEY_METRIC,
377 pwszValue,
378 REG_BINARY,
379 plogfont,
380 sizeof(LOGFONTW));
381 }
382
383
384 /** Get/Set value *************************************************************/
385
386 // FIXME: get rid of the flags and only use this from um. kernel can access data directly.
387 static
388 UINT_PTR
389 SpiMemCopy(PVOID pvDst, PVOID pvSrc, ULONG cbSize, BOOL bProtect, BOOL bToUser)
390 {
391 NTSTATUS Status = STATUS_SUCCESS;
392
393 if (bProtect)
394 {
395 _SEH2_TRY
396 {
397 if (bToUser)
398 {
399 ProbeForWrite(pvDst, cbSize, 1);
400 }
401 else
402 {
403 ProbeForRead(pvSrc, cbSize, 1);
404 }
405 memcpy(pvDst, pvSrc, cbSize);
406 }
407 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
408 {
409 Status = _SEH2_GetExceptionCode();
410 }
411 _SEH2_END
412 }
413 else
414 {
415 memcpy(pvDst, pvSrc, cbSize);
416 }
417
418 if (!NT_SUCCESS(Status))
419 {
420 SetLastNtError(Status);
421 DPRINT("SpiMemCopy failed, pvDst=%p, pvSrc=%p, bProtect=%d, bToUser=%d\n", pvDst, pvSrc, bProtect, bToUser);
422 }
423 return NT_SUCCESS(Status);
424 }
425
426 static inline
427 UINT_PTR
428 SpiGet(PVOID pvParam, PVOID pvData, ULONG cbSize, FLONG fl)
429 {
430 REQ_INTERACTIVE_WINSTA(ERROR_ACCESS_DENIED);
431 return SpiMemCopy(pvParam, pvData, cbSize, fl & SPIF_PROTECT, TRUE);
432 }
433
434 static inline
435 UINT_PTR
436 SpiSet(PVOID pvData, PVOID pvParam, ULONG cbSize, FLONG fl)
437 {
438 REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
439 return SpiMemCopy(pvData, pvParam, cbSize, fl & SPIF_PROTECT, FALSE);
440 }
441
442 static inline
443 UINT_PTR
444 SpiGetEx(PVOID pvParam, PVOID pvData, ULONG cbSize, FLONG fl)
445 {
446 ULONG cbBufSize;
447 /* Get the cbSite member from UM memory */
448 if (!SpiSet(&cbBufSize, pvParam, sizeof(ULONG), fl))
449 return 0;
450 /* Verify the correct size */
451 if (cbBufSize != cbSize)
452 return 0;
453 return SpiGet(pvParam, pvData, cbSize, fl);
454 }
455
456 static inline
457 UINT_PTR
458 SpiGetInt(PVOID pvParam, PVOID piValue, FLONG fl)
459 {
460 return SpiGet(pvParam, piValue, sizeof(INT), fl);
461 }
462
463 static inline
464 UINT_PTR
465 SpiSetYesNo(BOOL *pbData, BOOL bValue, PCWSTR pwszKey, PCWSTR pwszValue, FLONG fl)
466 {
467 REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
468 *pbData = bValue ? TRUE : FALSE;
469 if (fl & SPIF_UPDATEINIFILE)
470 {
471 SpiStoreSz(pwszKey, pwszValue, bValue ? L"Yes" : L"No");
472 }
473 return (UINT_PTR)pwszKey;
474 }
475
476 static inline
477 UINT_PTR
478 SpiSetBool(BOOL *pbData, INT iValue, PCWSTR pwszKey, PCWSTR pwszValue, FLONG fl)
479 {
480 REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
481 *pbData = iValue ? TRUE : FALSE;
482 if (fl & SPIF_UPDATEINIFILE)
483 {
484 SpiStoreSzInt(pwszKey, pwszValue, iValue);
485 }
486 return (UINT_PTR)pwszKey;
487 }
488
489 static inline
490 UINT_PTR
491 SpiSetDWord(PVOID pvData, INT iValue, PCWSTR pwszKey, PCWSTR pwszValue, FLONG fl)
492 {
493 REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
494 *(INT*)pvData = iValue;
495 if (fl & SPIF_UPDATEINIFILE)
496 {
497 SpiStoreDWord(pwszKey, pwszValue, iValue);
498 }
499 return (UINT_PTR)pwszKey;
500 }
501
502 static inline
503 UINT_PTR
504 SpiSetInt(PVOID pvData, INT iValue, PCWSTR pwszKey, PCWSTR pwszValue, FLONG fl)
505 {
506 REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
507 *(INT*)pvData = iValue;
508 if (fl & SPIF_UPDATEINIFILE)
509 {
510 SpiStoreSzInt(pwszKey, pwszValue, iValue);
511 }
512 return (UINT_PTR)pwszKey;
513 }
514
515 static inline
516 UINT_PTR
517 SpiSetMetric(PVOID pvData, INT iValue, PCWSTR pwszValue, FLONG fl)
518 {
519 REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
520 *(INT*)pvData = iValue;
521 if (fl & SPIF_UPDATEINIFILE)
522 {
523 SpiStoreMetric(pwszValue, iValue);
524 }
525 return (UINT_PTR)KEY_METRIC;
526 }
527
528 static inline
529 UINT_PTR
530 SpiSetUserPref(DWORD dwMask, PVOID pvValue, FLONG fl)
531 {
532 DWORD dwRegMask;
533 BOOL bValue = (BOOL)pvValue;
534
535 REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
536
537 /* Set or clear bit according to bValue */
538 gspv.dwUserPrefMask = bValue ? gspv.dwUserPrefMask | dwMask :
539 gspv.dwUserPrefMask & ~dwMask;
540
541 if (fl & SPIF_UPDATEINIFILE)
542 {
543 /* Read current value */
544 RegReadUserSetting(KEY_DESKTOP,
545 VAL_USERPREFMASK,
546 REG_BINARY,
547 &dwRegMask,
548 sizeof(DWORD));
549
550 /* Set or clear bit according to bValue */
551 dwRegMask = bValue ? dwRegMask | dwMask : dwRegMask & ~dwMask;
552
553 /* write back value */
554 RegWriteUserSetting(KEY_DESKTOP,
555 VAL_USERPREFMASK,
556 REG_BINARY,
557 &dwRegMask,
558 sizeof(DWORD));
559 }
560
561 return (UINT_PTR)KEY_DESKTOP;
562 }
563
564 static inline
565 UINT_PTR
566 SpiGetUserPref(DWORD dwMask, PVOID pvParam, FLONG fl)
567 {
568 INT iValue = gspv.dwUserPrefMask & dwMask ? 1 : 0;
569 return SpiGetInt(pvParam, &iValue, fl);
570 }
571
572 static
573 UINT_PTR
574 SpiSetWallpaper(PVOID pvParam, FLONG fl)
575 {
576 UNICODE_STRING ustr;
577 WCHAR awc[MAX_PATH];
578 BOOL bResult;
579 HBITMAP hbmp, hOldBitmap;
580 SURFACE *psurfBmp;
581 ULONG ulTile, ulStyle;
582
583 REQ_INTERACTIVE_WINSTA(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
584
585 if (!pvParam)
586 {
587 /* FIXME: Reset Wallpaper to registry value */
588 return (UINT_PTR)KEY_DESKTOP;
589 }
590
591 /* Capture UNICODE_STRING */
592 bResult = SpiMemCopy(&ustr, pvParam, sizeof(UNICODE_STRING), fl & SPIF_PROTECT, 0);
593 if (!bResult) return 0;
594 if (ustr.Length > MAX_PATH * sizeof(WCHAR))
595 return 0;
596
597 /* Copy the string buffer name */
598 bResult = SpiMemCopy(gspv.awcWallpaper, ustr.Buffer, ustr.Length, fl & SPIF_PROTECT, 0);
599 if (!bResult) return 0;
600
601 /* Update the UNICODE_STRING */
602 gspv.ustrWallpaper.Buffer = gspv.awcWallpaper;
603 gspv.ustrWallpaper.MaximumLength = MAX_PATH * sizeof(WCHAR);
604 gspv.ustrWallpaper.Length = ustr.Length;
605 gspv.awcWallpaper[ustr.Length / sizeof(WCHAR)] = 0;
606
607 DPRINT("SpiSetWallpaper, name=%S\n", gspv.awcWallpaper);
608
609 /* Update registry */
610 if (fl & SPIF_UPDATEINIFILE)
611 {
612 SpiStoreSz(KEY_DESKTOP, L"Wallpaper", gspv.awcWallpaper);
613 }
614
615 /* Got a filename? */
616 if (gspv.awcWallpaper[0] != 0)
617 {
618 /* Convert file name to nt file name */
619 ustr.Buffer = awc;
620 ustr.MaximumLength = MAX_PATH * sizeof(WCHAR);
621 ustr.Length = 0;
622 if (!W32kDosPathNameToNtPathName(gspv.awcWallpaper, &ustr))
623 {
624 DPRINT1("RtlDosPathNameToNtPathName_U failed\n");
625 return 0;
626 }
627
628 /* Load the Bitmap */
629 hbmp = UserLoadImage(ustr.Buffer);
630 if (!hbmp)
631 {
632 DPRINT1("UserLoadImage failed\n");
633 return 0;
634 }
635
636 /* Try to get the size of the wallpaper */
637 if(!(psurfBmp = SURFACE_LockSurface(hbmp)))
638 {
639 GreDeleteObject(hbmp);
640 return 0;
641 }
642
643 gpwinstaCurrent->cxWallpaper = psurfBmp->SurfObj.sizlBitmap.cx;
644 gpwinstaCurrent->cyWallpaper = psurfBmp->SurfObj.sizlBitmap.cy;
645 gpwinstaCurrent->WallpaperMode = wmCenter;
646
647 SURFACE_UnlockSurface(psurfBmp);
648
649 /* Change the bitmap's ownership */
650 GDIOBJ_SetOwnership(hbmp, NULL);
651
652 /* Yes, Windows really loads the current setting from the registry. */
653 ulTile = SpiLoadInt(KEY_DESKTOP, L"TileWallpaper", 0);
654 ulStyle = SpiLoadInt(KEY_DESKTOP, L"WallpaperStyle", 0);
655 DPRINT("SpiSetWallpaper: ulTile=%ld, ulStyle=%d\n", ulTile, ulStyle);
656
657 /* Check the values we found in the registry */
658 if(ulTile && !ulStyle)
659 {
660 gpwinstaCurrent->WallpaperMode = wmTile;
661 }
662 else if(!ulTile && ulStyle == 2)
663 {
664 gpwinstaCurrent->WallpaperMode = wmStretch;
665 }
666 }
667 else
668 {
669 /* Remove wallpaper */
670 gpwinstaCurrent->cxWallpaper = 0;
671 gpwinstaCurrent->cyWallpaper = 0;
672 hbmp = 0;
673 }
674
675 /* Take care of the old wallpaper, if any */
676 hOldBitmap = gpwinstaCurrent->hbmWallpaper;
677 if(hOldBitmap != NULL)
678 {
679 /* Delete the old wallpaper */
680 GDIOBJ_SetOwnership(hOldBitmap, PsGetCurrentProcess());
681 GreDeleteObject(hOldBitmap);
682 }
683
684 /* Set the new wallpaper */
685 gpwinstaCurrent->hbmWallpaper = hbmp;
686
687 NtUserRedrawWindow(UserGetShellWindow(), NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
688
689
690 return (UINT_PTR)KEY_DESKTOP;
691 }
692
693 static
694 UINT_PTR
695 SpiGetSet(UINT uiAction, UINT uiParam, PVOID pvParam, FLONG fl)
696 {
697 switch (uiAction)
698 {
699 case SPI_GETBEEP:
700 return SpiGetInt(pvParam, &gspv.bBeep, fl);
701
702 case SPI_SETBEEP:
703 return SpiSetYesNo(&gspv.bBeep, uiParam, KEY_SOUND, VAL_BEEP, fl);
704
705 case SPI_GETMOUSE:
706 return SpiGet(pvParam, &gspv.caiMouse, 3 * sizeof(INT), fl);
707
708 case SPI_SETMOUSE:
709 if (!SpiSet(&gspv.caiMouse, pvParam, 3 * sizeof(INT), fl))
710 return 0;
711 if (fl & SPIF_UPDATEINIFILE)
712 {
713 SpiStoreSzInt(KEY_MOUSE, VAL_MOUSE1, gspv.caiMouse.FirstThreshold);
714 SpiStoreSzInt(KEY_MOUSE, VAL_MOUSE2, gspv.caiMouse.SecondThreshold);
715 SpiStoreSzInt(KEY_MOUSE, VAL_MOUSE3, gspv.caiMouse.Acceleration);
716 }
717 return (UINT_PTR)KEY_MOUSE;
718
719 case SPI_GETBORDER:
720 return SpiGetInt(pvParam, &gspv.ncm.iBorderWidth, fl);
721
722 case SPI_SETBORDER:
723 uiParam = max(uiParam, 1);
724 return SpiSetInt(&gspv.ncm.iBorderWidth, uiParam, KEY_METRIC, VAL_BORDER, fl);
725
726 case SPI_GETKEYBOARDSPEED:
727 return SpiGetInt(pvParam, &gspv.dwKbdSpeed, fl);
728
729 case SPI_SETKEYBOARDSPEED:
730 return SpiSetInt(&gspv.dwKbdSpeed, uiParam, KEY_KBD, VAL_KBDSPD, fl);
731
732 case SPI_LANGDRIVER:
733 DPRINT1("SPI_LANGDRIVER is unimplemented\n");
734 break;
735
736 case SPI_GETSCREENSAVETIMEOUT:
737 return SpiGetInt(pvParam, &gspv.iScrSaverTimeout, fl);
738
739 case SPI_SETSCREENSAVETIMEOUT:
740 return SpiSetInt(&gspv.iScrSaverTimeout, uiParam, KEY_DESKTOP, VAL_SCRTO, fl);
741
742 case SPI_GETSCREENSAVEACTIVE:
743 return SpiGetInt(pvParam, &gspv.bScrSaverActive, fl);
744
745 case SPI_SETSCREENSAVEACTIVE:
746 return SpiSetInt(&gspv.bScrSaverActive, uiParam, KEY_DESKTOP, VAL_SCRACT, fl);
747
748 case SPI_GETGRIDGRANULARITY:
749 return SpiGetInt(pvParam, &gspv.uiGridGranularity, fl);
750
751 case SPI_SETGRIDGRANULARITY:
752 return SpiSetInt(&gspv.uiGridGranularity, uiParam, KEY_DESKTOP, VAL_GRID, fl);
753
754 case SPI_GETDESKWALLPAPER:
755 uiParam = min(uiParam, gspv.ustrWallpaper.Length + 1);
756 return SpiGet(pvParam, gspv.awcWallpaper, uiParam, fl);
757
758 case SPI_SETDESKWALLPAPER:
759 return SpiSetWallpaper(pvParam, fl);
760
761 case SPI_SETDESKPATTERN:
762 DPRINT1("SPI_SETDESKPATTERN is unimplemented\n");
763 break;
764
765 case SPI_GETKEYBOARDDELAY:
766 return SpiGetInt(pvParam, &gspv.iKbdDelay, fl);
767
768 case SPI_SETKEYBOARDDELAY:
769 return SpiSetInt(&gspv.iKbdDelay, uiParam, KEY_KBD, VAL_KBDDELAY, fl);
770
771 case SPI_ICONHORIZONTALSPACING:
772 if (pvParam)
773 {
774 return SpiGetInt(pvParam, &gspv.im.iHorzSpacing, fl);
775 }
776 uiParam = max(uiParam, 32);
777 return SpiSetMetric(&gspv.im.iHorzSpacing, uiParam, VAL_ICONSPC, fl);
778
779 case SPI_ICONVERTICALSPACING:
780 if (pvParam)
781 {
782 return SpiGetInt(pvParam, &gspv.im.iVertSpacing, fl);
783 }
784 uiParam = max(uiParam, 32);
785 return SpiSetMetric(&gspv.im.iVertSpacing, uiParam, VAL_ICONVSPC, fl);
786
787 case SPI_GETICONTITLEWRAP:
788 return SpiGetInt(pvParam, &gspv.im.iTitleWrap, fl);
789
790 case SPI_SETICONTITLEWRAP:
791 return SpiSetInt(&gspv.im.iTitleWrap, uiParam, KEY_METRIC, VAL_ITWRAP, fl);
792
793 case SPI_GETMENUDROPALIGNMENT:
794 return SpiGetInt(pvParam, &gspv.bMenuDropAlign, fl);
795
796 case SPI_SETMENUDROPALIGNMENT:
797 return SpiSetBool(&gspv.bMenuDropAlign, uiParam, KEY_MDALIGN, VAL_MDALIGN, fl);
798
799 case SPI_SETDOUBLECLKWIDTH:
800 return SpiSetInt(&gspv.iDblClickWidth, uiParam, KEY_MOUSE, VAL_DBLCLKWIDTH, fl);
801
802 case SPI_SETDOUBLECLKHEIGHT:
803 return SpiSetInt(&gspv.iDblClickHeight, uiParam, KEY_MOUSE, VAL_DBLCLKHEIGHT, fl);
804
805 case SPI_GETICONTITLELOGFONT:
806 return SpiGet(pvParam, &gspv.im.lfFont, sizeof(LOGFONTW), fl);
807
808 case SPI_SETICONTITLELOGFONT:
809 if (!SpiSet(&gspv.im.lfFont, pvParam, sizeof(LOGFONTW), fl))
810 return 0;
811 if (fl & SPIF_UPDATEINIFILE)
812 {
813 SpiStoreFont(L"IconFont", &gspv.im.lfFont);
814 }
815 return (UINT_PTR)KEY_METRIC;
816
817 case SPI_SETDOUBLECLICKTIME:
818 return SpiSetInt(&gspv.iDblClickTime, uiParam, KEY_MOUSE, VAL_DBLCLKTIME, fl);
819
820 case SPI_SETMOUSEBUTTONSWAP:
821 return SpiSetInt(&gspv.bMouseBtnSwap, uiParam, KEY_MOUSE, VAL_SWAP, fl);
822
823 case SPI_GETFASTTASKSWITCH:
824 return SpiGetInt(pvParam, &gspv.bFastTaskSwitch, fl);
825
826 case SPI_SETFASTTASKSWITCH:
827 /* According to Winetest this one is unimplemented */
828 return 0;
829
830 case SPI_GETDRAGFULLWINDOWS:
831 return SpiGetInt(pvParam, &gspv.bDragFullWindows, fl);
832
833 case SPI_SETDRAGFULLWINDOWS:
834 return SpiSetInt(&gspv.bDragFullWindows, uiParam, KEY_DESKTOP, VAL_DRAG, fl);
835
836 case SPI_GETNONCLIENTMETRICS:
837 return SpiGet(pvParam, &gspv.ncm, sizeof(NONCLIENTMETRICSW), fl);
838
839 case SPI_SETNONCLIENTMETRICS:
840 if (!SpiSet(&gspv.ncm, pvParam, sizeof(NONCLIENTMETRICSW), fl))
841 return 0;
842 if (fl & SPIF_UPDATEINIFILE)
843 {
844 SpiStoreMetric(VAL_BORDER, gspv.ncm.iBorderWidth);
845 SpiStoreMetric(L"ScrollWidth", gspv.ncm.iScrollWidth);
846 SpiStoreMetric(L"ScrollHeight", gspv.ncm.iScrollHeight);
847 SpiStoreMetric(L"CaptionWidth", gspv.ncm.iCaptionWidth);
848 SpiStoreMetric(L"CaptionHeight", gspv.ncm.iCaptionHeight);
849 SpiStoreMetric(L"SmCaptionWidth", gspv.ncm.iSmCaptionWidth);
850 SpiStoreMetric(L"SmCaptionHeight", gspv.ncm.iSmCaptionHeight);
851 SpiStoreMetric(L"MenuWidth", gspv.ncm.iMenuWidth);
852 SpiStoreMetric(L"MenuHeight", gspv.ncm.iMenuHeight);
853 #if (WINVER >= 0x0600)
854 SpiStoreMetric(L"PaddedBorderWidth", gspv.ncm.iPaddedBorderWidth);
855 #endif
856 SpiStoreFont(L"CaptionFont", &gspv.ncm.lfCaptionFont);
857 SpiStoreFont(L"SmCaptionFont", &gspv.ncm.lfSmCaptionFont);
858 SpiStoreFont(L"MenuFont", &gspv.ncm.lfMenuFont);
859 SpiStoreFont(L"StatusFont", &gspv.ncm.lfStatusFont);
860 SpiStoreFont(L"MessageFont", &gspv.ncm.lfMessageFont);
861 }
862 return (UINT_PTR)KEY_METRIC;
863
864 case SPI_GETMINIMIZEDMETRICS:
865 return SpiGet(pvParam, &gspv.mm, sizeof(MINIMIZEDMETRICS), fl);
866
867 case SPI_SETMINIMIZEDMETRICS:
868 if (!SpiSet(&gspv.mm, pvParam, sizeof(MINIMIZEDMETRICS), fl))
869 return 0;
870 gspv.mm.iWidth = max(0, gspv.mm.iWidth);
871 gspv.mm.iHorzGap = max(0, gspv.mm.iHorzGap);
872 gspv.mm.iVertGap = max(0, gspv.mm.iVertGap);
873 gspv.mm.iArrange = gspv.mm.iArrange & 0xf;
874 if (fl & SPIF_UPDATEINIFILE)
875 {
876 SpiStoreMetric(L"MinWidth", gspv.mm.iWidth);
877 SpiStoreMetric(L"MinHorzGap", gspv.mm.iHorzGap);
878 SpiStoreMetric(L"MinVertGap", gspv.mm.iVertGap);
879 SpiStoreMetric(L"MinArrange", gspv.mm.iArrange);
880 }
881 return (UINT_PTR)KEY_METRIC;
882
883 case SPI_GETICONMETRICS:
884 return SpiGet(pvParam, &gspv.im, sizeof(ICONMETRICS), fl);
885
886 case SPI_SETICONMETRICS:
887 if (!SpiSet(&gspv.im, pvParam, sizeof(ICONMETRICS), fl))
888 return 0;
889 if (fl & SPIF_UPDATEINIFILE)
890 {
891 SpiStoreMetric(VAL_ICONSPC, gspv.im.iHorzSpacing);
892 SpiStoreMetric(VAL_ICONVSPC, gspv.im.iVertSpacing);
893 SpiStoreMetric(VAL_ITWRAP, gspv.im.iTitleWrap);
894 SpiStoreFont(L"IconFont", &gspv.im.lfFont);
895 }
896 return (UINT_PTR)KEY_METRIC;
897
898 case SPI_GETWORKAREA: // FIXME: the workarea should be part of the MONITOR
899 {
900 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
901 PDESKTOP pdesktop = pti->rpdesk;
902 RECTL rclWorkarea;
903
904 if(!pdesktop)
905 return 0;
906
907 IntGetDesktopWorkArea(pdesktop, &rclWorkarea);
908 return SpiGet(pvParam, &rclWorkarea, sizeof(RECTL), fl);
909 }
910
911 case SPI_SETWORKAREA: // FIXME: the workarea should be part of the MONITOR
912 {
913 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
914 PDESKTOP pdesktop = pti->rpdesk;
915 RECT rcWorkArea;
916
917 if(!pdesktop)
918 return 0;
919
920 if (!SpiSet(&rcWorkArea, pvParam, sizeof(RECTL), fl))
921 return 0;
922
923 /* Verify the new values */
924 if (rcWorkArea.left < 0 ||
925 rcWorkArea.top < 0 ||
926 rcWorkArea.right > gpsi->aiSysMet[SM_CXSCREEN] ||
927 rcWorkArea.bottom > gpsi->aiSysMet[SM_CYSCREEN] ||
928 rcWorkArea.right <= rcWorkArea.left ||
929 rcWorkArea.bottom <= rcWorkArea.top)
930 return 0;
931
932 pdesktop->WorkArea = rcWorkArea;
933 if (fl & SPIF_UPDATEINIFILE)
934 {
935 // FIXME: what to do?
936 }
937 return (UINT_PTR)KEY_DESKTOP;
938 }
939
940 case SPI_SETPENWINDOWS:
941 DPRINT1("SPI_SETPENWINDOWS is unimplemented\n");
942 break;
943
944 case SPI_GETFILTERKEYS:
945 return SpiGet(pvParam, &gspv.filterkeys, sizeof(FILTERKEYS), fl);
946
947 case SPI_SETFILTERKEYS:
948 if (!SpiSet(&gspv.filterkeys, pvParam, sizeof(FILTERKEYS), fl))
949 return 0;
950 if (fl & SPIF_UPDATEINIFILE)
951 {
952 // FIXME: what to do?
953 }
954 return (UINT_PTR)KEY_DESKTOP;
955
956 case SPI_GETTOGGLEKEYS:
957 return SpiGet(pvParam, &gspv.togglekeys, sizeof(TOGGLEKEYS), fl);
958
959 case SPI_SETTOGGLEKEYS:
960 if (!SpiSet(&gspv.togglekeys, pvParam, sizeof(TOGGLEKEYS), fl))
961 return 0;
962 if (fl & SPIF_UPDATEINIFILE)
963 {
964 // FIXME: what to do?
965 }
966 return (UINT_PTR)KEY_DESKTOP;
967
968 case SPI_GETMOUSEKEYS:
969 return SpiGet(pvParam, &gspv.mousekeys, sizeof(MOUSEKEYS), fl);
970
971 case SPI_SETMOUSEKEYS:
972 if (!SpiSet(&gspv.mousekeys, pvParam, sizeof(MOUSEKEYS), fl))
973 return 0;
974 if (fl & SPIF_UPDATEINIFILE)
975 {
976 // FIXME: what to do?
977 }
978 return (UINT_PTR)KEY_DESKTOP;
979
980 case SPI_GETSHOWSOUNDS:
981 return SpiGetInt(pvParam, &gspv.bShowSounds, fl);
982
983 case SPI_SETSHOWSOUNDS:
984 return SpiSetBool(&gspv.bShowSounds, uiParam, KEY_SHOWSNDS, VAL_ON, fl);
985
986 case SPI_GETSTICKYKEYS:
987 if (uiParam != sizeof(STICKYKEYS))
988 return 0;
989 return SpiGetEx(pvParam, &gspv.stickykeys, sizeof(STICKYKEYS), fl);
990
991 case SPI_SETSTICKYKEYS:
992 if (!SpiSet(&gspv.stickykeys, pvParam, sizeof(STICKYKEYS), fl))
993 return 0;
994 if (fl & SPIF_UPDATEINIFILE)
995 {
996 // FIXME: what to do?
997 }
998 return (UINT_PTR)KEY_DESKTOP;
999
1000 case SPI_GETACCESSTIMEOUT:
1001 if (uiParam != 0 && uiParam != sizeof(ACCESSTIMEOUT))
1002 return 0;
1003 return SpiGetEx(pvParam, &gspv.accesstimeout, sizeof(ACCESSTIMEOUT), fl);
1004
1005 case SPI_SETACCESSTIMEOUT:
1006 if (!SpiSet(&gspv.accesstimeout, pvParam, sizeof(ACCESSTIMEOUT), fl))
1007 return 0;
1008 if (fl & SPIF_UPDATEINIFILE)
1009 {
1010 // FIXME: what to do?
1011 }
1012 return (UINT_PTR)KEY_DESKTOP;
1013
1014 case SPI_GETSERIALKEYS:
1015 return SpiGet(pvParam, &gspv.serialkeys, sizeof(SERIALKEYS), fl);
1016
1017 case SPI_SETSERIALKEYS:
1018 if (!SpiSet(&gspv.serialkeys, pvParam, sizeof(SERIALKEYS), fl))
1019 return 0;
1020 if (fl & SPIF_UPDATEINIFILE)
1021 {
1022 // FIXME: what to do?
1023 }
1024 return (UINT_PTR)KEY_DESKTOP;
1025
1026 case SPI_GETSOUNDSENTRY:
1027 return SpiGet(pvParam, &gspv.soundsentry, sizeof(SOUNDSENTRY), fl);
1028
1029 case SPI_SETSOUNDSENTRY:
1030 if (!SpiSet(&gspv.soundsentry, pvParam, sizeof(SOUNDSENTRY), fl))
1031 return 0;
1032 if (fl & SPIF_UPDATEINIFILE)
1033 {
1034 // FIXME: what to do?
1035 }
1036 return (UINT_PTR)KEY_DESKTOP;
1037
1038 case SPI_GETHIGHCONTRAST:
1039 return SpiGet(pvParam, &gspv.highcontrast, sizeof(HIGHCONTRAST), fl);
1040
1041 case SPI_SETHIGHCONTRAST:
1042 if (!SpiSet(&gspv.highcontrast, pvParam, sizeof(HIGHCONTRAST), fl))
1043 return 0;
1044 if (fl & SPIF_UPDATEINIFILE)
1045 {
1046 // FIXME: what to do?
1047 }
1048 return (UINT_PTR)KEY_DESKTOP;
1049
1050 case SPI_GETKEYBOARDPREF:
1051 return SpiGetInt(pvParam, &gspv.bKbdPref, fl);
1052
1053 case SPI_SETKEYBOARDPREF:
1054 return SpiSetBool(&gspv.bKbdPref, uiParam, KEY_KDBPREF, VAL_ON, fl);
1055
1056 case SPI_GETSCREENREADER:
1057 return SpiGetInt(pvParam, &gspv.bScreenReader, fl);
1058
1059 case SPI_SETSCREENREADER:
1060 return SpiSetBool(&gspv.bScreenReader, uiParam, KEY_SCRREAD, VAL_ON, fl);
1061
1062 case SPI_GETANIMATION:
1063 return SpiGet(pvParam, &gspv.animationinfo, sizeof(ANIMATIONINFO), fl);
1064
1065 case SPI_SETANIMATION:
1066 if (!SpiSet(&gspv.animationinfo, pvParam, sizeof(ANIMATIONINFO), fl))
1067 return 0;
1068 if (fl & SPIF_UPDATEINIFILE)
1069 {
1070 // FIXME: what to do?
1071 }
1072 return (UINT_PTR)KEY_DESKTOP;
1073
1074 case SPI_GETFONTSMOOTHING:
1075 return SpiGetInt(pvParam, &gspv.bFontSmoothing, fl);
1076
1077 case SPI_SETFONTSMOOTHING:
1078 gspv.bFontSmoothing = uiParam ? TRUE : FALSE;
1079 if (fl & SPIF_UPDATEINIFILE)
1080 {
1081 SpiStoreSzInt(KEY_DESKTOP, VAL_FNTSMOOTH, uiParam ? 2 : 0);
1082 }
1083 return (UINT_PTR)KEY_DESKTOP;
1084
1085 case SPI_SETDRAGWIDTH:
1086 return SpiSetInt(&gspv.iDragWidth, uiParam, KEY_DESKTOP, VAL_DRAGWIDTH, fl);
1087
1088 case SPI_SETDRAGHEIGHT:
1089 return SpiSetInt(&gspv.iDragHeight, uiParam, KEY_DESKTOP, VAL_DRAGHEIGHT, fl);
1090
1091 case SPI_SETHANDHELD:
1092 return SpiSetBool(&gspv.bHandHeld, uiParam, KEY_DESKTOP, L"HandHeld", fl);
1093
1094 case SPI_GETLOWPOWERTIMEOUT:
1095 return SpiGetInt(pvParam, &gspv.iLowPwrTimeout, fl);
1096
1097 case SPI_GETPOWEROFFTIMEOUT:
1098 return SpiGetInt(pvParam, &gspv.iPwrOffTimeout, fl);
1099
1100 case SPI_SETLOWPOWERTIMEOUT:
1101 return SpiSetInt(&gspv.iLowPwrTimeout, uiParam, KEY_DESKTOP, L"LowPowerTimeOut", fl);
1102
1103 case SPI_SETPOWEROFFTIMEOUT:
1104 return SpiSetInt(&gspv.iPwrOffTimeout, uiParam, KEY_DESKTOP, L"PowerOffTimeOut", fl);
1105
1106 case SPI_GETLOWPOWERACTIVE:
1107 return SpiGetInt(pvParam, &gspv.iPwrOffTimeout, fl);
1108
1109 case SPI_GETPOWEROFFACTIVE:
1110 return SpiGetInt(pvParam, &gspv.bPwrOffActive, fl);
1111
1112 case SPI_SETLOWPOWERACTIVE:
1113 return SpiSetBool(&gspv.bLowPwrActive, uiParam, KEY_DESKTOP, L"LowPowerActive", fl);
1114
1115 case SPI_SETPOWEROFFACTIVE:
1116 return SpiSetBool(&gspv.bPwrOffActive, uiParam, KEY_DESKTOP, L"PowerOffActive", fl);
1117
1118 case SPI_SETCURSORS:
1119 DPRINT1("SPI_SETCURSORS is unimplemented\n");
1120 break;
1121
1122 case SPI_SETICONS:
1123 DPRINT1("SPI_SETICONS is unimplemented\n");
1124 break;
1125
1126 case SPI_GETDEFAULTINPUTLANG:
1127 DPRINT1("SPI_GETDEFAULTINPUTLANG is unimplemented\n");
1128 break;
1129
1130 case SPI_SETDEFAULTINPUTLANG:
1131 DPRINT1("SPI_SETDEFAULTINPUTLANG is unimplemented\n");
1132 break;
1133
1134 case SPI_SETLANGTOGGLE:
1135 DPRINT1("SPI_SETLANGTOGGLE is unimplemented\n");
1136 break;
1137
1138 case SPI_GETWINDOWSEXTENSION:
1139 DPRINT1("SPI_GETWINDOWSEXTENSION is unimplemented\n");
1140 break;
1141
1142 case SPI_GETMOUSETRAILS:
1143 return SpiGetInt(pvParam, &gspv.iMouseTrails, fl);
1144
1145 case SPI_SETMOUSETRAILS:
1146 return SpiSetInt(&gspv.iMouseTrails, uiParam, KEY_MOUSE, VAL_MOUSETRAILS, fl);
1147
1148 case SPI_GETSNAPTODEFBUTTON:
1149 return SpiGetInt(pvParam, &gspv.bSnapToDefBtn, fl);
1150
1151 case SPI_SETSNAPTODEFBUTTON:
1152 return SpiSetBool(&gspv.bSnapToDefBtn, uiParam, KEY_MOUSE, VAL_SNAPDEFBTN, fl);
1153
1154 case SPI_GETMOUSEHOVERWIDTH:
1155 return SpiGetInt(pvParam, &gspv.iMouseHoverWidth, fl);
1156
1157 case SPI_SETMOUSEHOVERWIDTH:
1158 return SpiSetInt(&gspv.iMouseHoverWidth, uiParam, KEY_MOUSE, VAL_HOVERWIDTH, fl);
1159
1160 case SPI_GETMOUSEHOVERHEIGHT:
1161 return SpiGetInt(pvParam, &gspv.iMouseHoverHeight, fl);
1162
1163 case SPI_SETMOUSEHOVERHEIGHT:
1164 return SpiSetInt(&gspv.iMouseHoverHeight, uiParam, KEY_MOUSE, VAL_HOVERHEIGHT, fl);
1165
1166 case SPI_GETMOUSEHOVERTIME:
1167 return SpiGetInt(pvParam, &gspv.iMouseHoverTime, fl);
1168
1169 case SPI_SETMOUSEHOVERTIME:
1170 /* see http://msdn2.microsoft.com/en-us/library/ms724947.aspx
1171 * copy text from it, if some agument why xp and 2003 behovir diffent
1172 * only if they do not have SP install
1173 * " Windows Server 2003 and Windows XP: The operating system does not
1174 * enforce the use of USER_TIMER_MAXIMUM and USER_TIMER_MINIMUM until
1175 * Windows Server 2003 SP1 and Windows XP SP2 "
1176 */
1177 return SpiSetInt(&gspv.iMouseHoverTime, uiParam, KEY_MOUSE, VAL_HOVERTIME, fl);
1178
1179 case SPI_GETWHEELSCROLLLINES:
1180 return SpiGetInt(pvParam, &gspv.iWheelScrollLines, fl);
1181
1182 case SPI_SETWHEELSCROLLLINES:
1183 return SpiSetInt(&gspv.iWheelScrollLines, uiParam, KEY_DESKTOP, VAL_SCRLLLINES, fl);
1184
1185 case SPI_GETMENUSHOWDELAY:
1186 return SpiGetInt(pvParam, &gspv.dwMenuShowDelay, fl);
1187
1188 case SPI_SETMENUSHOWDELAY:
1189 return SpiSetInt(&gspv.dwMenuShowDelay, uiParam, KEY_DESKTOP, L"MenuShowDelay", fl);
1190
1191 #if (_WIN32_WINNT >= 0x0600)
1192 case SPI_GETWHEELSCROLLCHARS:
1193 return SpiGetInt(pvParam, &gspv.uiWheelScrollChars, fl);
1194
1195 case SPI_SETWHEELSCROLLCHARS:
1196 return SpiSetInt(&gspv.uiWheelScrollChars, uiParam, KEY_DESKTOP, VAL_SCRLLCHARS, fl);
1197 #endif
1198 case SPI_GETSHOWIMEUI:
1199 return SpiGetInt(pvParam, &gspv.bShowImeUi, fl);
1200
1201 case SPI_SETSHOWIMEUI:
1202 return SpiSetBool(&gspv.bShowImeUi, uiParam, KEY_DESKTOP, L"", fl);
1203
1204 case SPI_GETMOUSESPEED:
1205 return SpiGetInt(pvParam, &gspv.iMouseSpeed, fl);
1206
1207 case SPI_SETMOUSESPEED:
1208 // vgl SETMOUSE
1209 return SpiSetInt(&gspv.iMouseSpeed, uiParam, KEY_MOUSE, VAL_MOUSE3, fl);
1210
1211 case SPI_GETSCREENSAVERRUNNING:
1212 return SpiGetInt(pvParam, &gspv.bScrSaverRunning, fl);
1213
1214 case SPI_SETSCREENSAVERRUNNING:
1215 // FIXME: also return value?
1216 return SpiSetBool(&gspv.bScrSaverRunning, uiParam, KEY_MOUSE, L"", fl);
1217
1218 #if(WINVER >= 0x0600)
1219 case SPI_GETAUDIODESCRIPTION:
1220 return SpiGet(pvParam, &gspv.audiodesription, sizeof(AUDIODESCRIPTION), fl);
1221
1222 case SPI_SETAUDIODESCRIPTION:
1223 DPRINT1("SPI_SETAUDIODESCRIPTION is unimplemented\n");
1224 break;
1225
1226 case SPI_GETSCREENSAVESECURE:
1227 return SpiGetInt(pvParam, &gspv.bScrSaverSecure, fl);
1228
1229 case SPI_SETSCREENSAVESECURE:
1230 return SpiSetBool(&gspv.bScrSaverSecure, uiParam, KEY_DESKTOP, L"ScreenSaverIsSecure", fl);
1231 #endif
1232
1233 case SPI_GETACTIVEWINDOWTRACKING:
1234 return SpiGetUserPref(UPM_ACTIVEWINDOWTRACKING, pvParam, fl);
1235
1236 case SPI_SETACTIVEWINDOWTRACKING:
1237 return SpiSetUserPref(UPM_ACTIVEWINDOWTRACKING, pvParam, fl);
1238
1239 case SPI_GETMENUANIMATION:
1240 return SpiGetUserPref(UPM_MENUANIMATION, pvParam, fl);
1241
1242 case SPI_SETMENUANIMATION:
1243 return SpiSetUserPref(UPM_MENUANIMATION, pvParam, fl);
1244
1245 case SPI_GETCOMBOBOXANIMATION:
1246 return SpiGetUserPref(UPM_COMBOBOXANIMATION, pvParam, fl);
1247
1248 case SPI_SETCOMBOBOXANIMATION:
1249 return SpiSetUserPref(UPM_COMBOBOXANIMATION, pvParam, fl);
1250
1251 case SPI_GETLISTBOXSMOOTHSCROLLING:
1252 return SpiGetUserPref(UPM_LISTBOXSMOOTHSCROLLING, pvParam, fl);
1253
1254 case SPI_SETLISTBOXSMOOTHSCROLLING:
1255 return SpiSetUserPref(UPM_LISTBOXSMOOTHSCROLLING, pvParam, fl);
1256
1257 case SPI_GETGRADIENTCAPTIONS:
1258 return SpiGetUserPref(UPM_GRADIENTCAPTIONS, pvParam, fl);
1259
1260 case SPI_SETGRADIENTCAPTIONS:
1261 return SpiSetUserPref(UPM_GRADIENTCAPTIONS, pvParam, fl);
1262
1263 case SPI_GETKEYBOARDCUES:
1264 return SpiGetUserPref(UPM_KEYBOARDCUES, pvParam, fl);
1265
1266 case SPI_SETKEYBOARDCUES:
1267 return SpiSetUserPref(UPM_KEYBOARDCUES, pvParam, fl);
1268
1269 case SPI_GETACTIVEWNDTRKZORDER:
1270 return SpiGetUserPref(UPM_ACTIVEWNDTRKZORDER, pvParam, fl);
1271
1272 case SPI_SETACTIVEWNDTRKZORDER:
1273 return SpiSetUserPref(UPM_ACTIVEWNDTRKZORDER, pvParam, fl);
1274
1275 case SPI_GETHOTTRACKING:
1276 return SpiGetUserPref(UPM_HOTTRACKING, pvParam, fl);
1277
1278 case SPI_SETHOTTRACKING:
1279 return SpiSetUserPref(UPM_HOTTRACKING, pvParam, fl);
1280
1281 case SPI_GETMENUFADE:
1282 return SpiGetUserPref(UPM_MENUFADE, pvParam, fl);
1283
1284 case SPI_SETMENUFADE:
1285 return SpiSetUserPref(UPM_MENUFADE, pvParam, fl);
1286
1287 case SPI_GETSELECTIONFADE:
1288 return SpiGetUserPref(UPM_SELECTIONFADE, pvParam, fl);
1289
1290 case SPI_SETSELECTIONFADE:
1291 return SpiSetUserPref(UPM_SELECTIONFADE, pvParam, fl);
1292
1293 case SPI_GETTOOLTIPANIMATION:
1294 return SpiGetUserPref(UPM_TOOLTIPANIMATION, pvParam, fl);
1295
1296 case SPI_SETTOOLTIPANIMATION:
1297 return SpiSetUserPref(UPM_TOOLTIPANIMATION, pvParam, fl);
1298
1299 case SPI_GETTOOLTIPFADE:
1300 return SpiGetUserPref(UPM_TOOLTIPFADE, pvParam, fl);
1301
1302 case SPI_SETTOOLTIPFADE:
1303 return SpiSetUserPref(UPM_TOOLTIPFADE, pvParam, fl);
1304
1305 case SPI_GETCURSORSHADOW:
1306 return SpiGetUserPref(UPM_CURSORSHADOW, pvParam, fl);
1307
1308 case SPI_SETCURSORSHADOW:
1309 gspv.bMouseCursorShadow = (BOOL)pvParam;
1310 return SpiSetUserPref(UPM_CURSORSHADOW, pvParam, fl);
1311
1312 case SPI_GETUIEFFECTS:
1313 return SpiGetUserPref(UPM_UIEFFECTS, pvParam, fl);
1314
1315 case SPI_SETUIEFFECTS:
1316 return SpiSetUserPref(UPM_UIEFFECTS, pvParam, fl);
1317
1318 case SPI_GETMOUSESONAR:
1319 return SpiGetInt(pvParam, &gspv.bMouseSonar, fl);
1320
1321 case SPI_SETMOUSESONAR:
1322 return SpiSetBool(&gspv.bMouseSonar, uiParam, KEY_MOUSE, L"", fl);
1323
1324 case SPI_GETMOUSECLICKLOCK:
1325 return SpiGetUserPref(UPM_CLICKLOCK, pvParam, fl);
1326
1327 case SPI_SETMOUSECLICKLOCK:
1328 gspv.bMouseClickLock = (BOOL)pvParam;
1329 return SpiSetUserPref(UPM_CLICKLOCK, pvParam, fl);
1330
1331 case SPI_GETMOUSEVANISH:
1332 return SpiGetInt(pvParam, &gspv.bMouseVanish, fl);
1333
1334 case SPI_SETMOUSEVANISH:
1335 return SpiSetBool(&gspv.bMouseVanish, uiParam, KEY_MOUSE, L"", fl);
1336
1337 case SPI_GETFLATMENU:
1338 return SpiGetInt(pvParam, &gspv.bFlatMenu, fl);
1339
1340 case SPI_SETFLATMENU:
1341 return SpiSetBool(&gspv.bFlatMenu, uiParam, KEY_MOUSE, L"", fl);
1342
1343 case SPI_GETDROPSHADOW:
1344 return SpiGetInt(pvParam, &gspv.bDropShadow, fl);
1345
1346 case SPI_SETDROPSHADOW:
1347 return SpiSetBool(&gspv.bDropShadow, uiParam, KEY_MOUSE, L"", fl);
1348
1349 case SPI_GETBLOCKSENDINPUTRESETS:
1350 return SpiGetInt(pvParam, &gspv.bBlockSendInputResets, fl);
1351
1352 case SPI_SETBLOCKSENDINPUTRESETS:
1353 return SpiSetBool(&gspv.bBlockSendInputResets, uiParam, KEY_MOUSE, L"", fl);
1354
1355 #if(_WIN32_WINNT >= 0x0600)
1356 case SPI_GETDISABLEOVERLAPPEDCONTENT:
1357 return SpiGetInt(pvParam, &gspv.bDisableOverlappedContent, fl);
1358
1359 case SPI_SETDISABLEOVERLAPPEDCONTENT:
1360 return SpiSetBool(&gspv.bDisableOverlappedContent, uiParam, KEY_MOUSE, L"", fl);
1361
1362 case SPI_GETCLIENTAREAANIMATION:
1363 return SpiGetInt(pvParam, &gspv.bClientAnimation, fl);
1364
1365 case SPI_SETCLIENTAREAANIMATION:
1366 return SpiSetBool(&gspv.bClientAnimation, uiParam, KEY_MOUSE, L"", fl);
1367
1368 case SPI_GETCLEARTYPE:
1369 return SpiGetInt(pvParam, &gspv.bClearType, fl);
1370
1371 case SPI_SETCLEARTYPE:
1372 return SpiSetBool(&gspv.bClearType, uiParam, KEY_MOUSE, L"", fl);
1373
1374 case SPI_GETSPEECHRECOGNITION:
1375 return SpiGetInt(pvParam, &gspv.bSpeechRecognition, fl);
1376
1377 case SPI_SETSPEECHRECOGNITION:
1378 return SpiSetBool(&gspv.bSpeechRecognition, uiParam, KEY_MOUSE, L"", fl);
1379 #endif
1380
1381 case SPI_GETFOREGROUNDLOCKTIMEOUT:
1382 return SpiGetInt(pvParam, &gspv.dwForegroundLockTimeout, fl);
1383
1384 case SPI_SETFOREGROUNDLOCKTIMEOUT:
1385 return SpiSetInt(&gspv.dwForegroundLockTimeout, uiParam, KEY_MOUSE, L"", fl);
1386
1387 case SPI_GETACTIVEWNDTRKTIMEOUT:
1388 return SpiGetInt(pvParam, &gspv.dwActiveTrackingTimeout, fl);
1389
1390 case SPI_SETACTIVEWNDTRKTIMEOUT:
1391 return SpiSetInt(&gspv.dwActiveTrackingTimeout, uiParam, KEY_MOUSE, L"", fl);
1392
1393 case SPI_GETFOREGROUNDFLASHCOUNT:
1394 return SpiGetInt(pvParam, &gspv.dwForegroundFlashCount, fl);
1395
1396 case SPI_SETFOREGROUNDFLASHCOUNT:
1397 return SpiSetInt(&gspv.dwForegroundFlashCount, uiParam, KEY_MOUSE, L"", fl);
1398
1399 case SPI_GETCARETWIDTH:
1400 return SpiGetInt(pvParam, &gspv.dwCaretWidth, fl);
1401
1402 case SPI_SETCARETWIDTH:
1403 return SpiSetInt(&gspv.dwCaretWidth, uiParam, KEY_MOUSE, L"", fl);
1404
1405 case SPI_GETMOUSECLICKLOCKTIME:
1406 return SpiGetInt(pvParam, &gspv.dwMouseClickLockTime, fl);
1407
1408 case SPI_SETMOUSECLICKLOCKTIME:
1409 return SpiSetDWord(&gspv.dwMouseClickLockTime, uiParam, KEY_DESKTOP, VAL_CLICKLOCKTIME, fl);
1410
1411 case SPI_GETFONTSMOOTHINGTYPE:
1412 return SpiGetInt(pvParam, &gspv.uiFontSmoothingType, fl);
1413
1414 case SPI_SETFONTSMOOTHINGTYPE:
1415 return SpiSetInt(&gspv.uiFontSmoothingType, uiParam, KEY_MOUSE, L"", fl);
1416
1417 case SPI_GETFONTSMOOTHINGCONTRAST:
1418 return SpiGetInt(pvParam, &gspv.uiFontSmoothingContrast, fl);
1419
1420 case SPI_SETFONTSMOOTHINGCONTRAST:
1421 return SpiSetInt(&gspv.uiFontSmoothingContrast, uiParam, KEY_MOUSE, L"", fl);
1422
1423 case SPI_GETFOCUSBORDERWIDTH:
1424 return SpiGetInt(pvParam, &gspv.uiFocusBorderWidth, fl);
1425
1426 case SPI_SETFOCUSBORDERWIDTH:
1427 return SpiSetInt(&gspv.uiFocusBorderWidth, uiParam, KEY_MOUSE, L"", fl);
1428
1429 case SPI_GETFOCUSBORDERHEIGHT:
1430 return SpiGetInt(pvParam, &gspv.uiFocusBorderHeight, fl);
1431
1432 case SPI_SETFOCUSBORDERHEIGHT:
1433 return SpiSetInt(&gspv.uiFocusBorderHeight, uiParam, KEY_MOUSE, L"", fl);
1434
1435 case SPI_GETFONTSMOOTHINGORIENTATION:
1436 return SpiGetInt(pvParam, &gspv.uiFontSmoothingOrientation, fl);
1437
1438 case SPI_SETFONTSMOOTHINGORIENTATION:
1439 return SpiSetInt(&gspv.uiFontSmoothingOrientation, uiParam, KEY_MOUSE, L"", fl);
1440
1441 /* The following are undocumented, but valid SPI values */
1442 case 0x1010:
1443 case 0x1011:
1444 case 0x1028:
1445 case 0x1029:
1446 case 0x102A:
1447 case 0x102B:
1448 case 0x102C:
1449 case 0x102D:
1450 case 0x102E:
1451 case 0x102F:
1452 case 0x1030:
1453 case 0x1031:
1454 case 0x1032:
1455 case 0x1033:
1456 case 0x1034:
1457 case 0x1035:
1458 case 0x1036:
1459 case 0x1037:
1460 case 0x1038:
1461 case 0x1039:
1462 case 0x103A:
1463 case 0x103B:
1464 case 0x103C:
1465 case 0x103D:
1466 DPRINT1("Undocumented SPI value %x is unimplemented\n", uiAction);
1467 break;
1468
1469 default:
1470 DPRINT1("Invalid SPI value: %d\n", uiAction);
1471 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1472 return 0;
1473 }
1474
1475 return 0;
1476 }
1477
1478 BOOL
1479 FASTCALL
1480 UserSystemParametersInfo(
1481 UINT uiAction,
1482 UINT uiParam,
1483 PVOID pvParam,
1484 UINT fWinIni)
1485 {
1486 ULONG_PTR ulResult;
1487
1488 if (!gbSpiInitialized)
1489 {
1490 KeRosDumpStackFrames(NULL, 20);
1491 return FALSE;
1492 }
1493
1494 /* Get a pointer to the current Windowstation */
1495 gpwinstaCurrent = IntGetWinStaObj();
1496
1497 if (!gpwinstaCurrent)
1498 {
1499 DPRINT1("UserSystemParametersInfo called without active windowstation.\n");
1500 //KeRosDumpStackFrames(NULL, 0);
1501 }
1502
1503 /* Do the actual operation */
1504 ulResult = SpiGetSet(uiAction, uiParam, pvParam, fWinIni);
1505
1506 /* Did we change something? */
1507 if (ulResult > 1)
1508 {
1509 SpiFixupValues();
1510
1511 /* Update system metrics */
1512 InitMetrics();
1513
1514 /* Send notification to toplevel windows, if requested */
1515 if (fWinIni & (SPIF_SENDCHANGE | SPIF_SENDWININICHANGE))
1516 {
1517 /* Send WM_SETTINGCHANGE to all toplevel windows */
1518 co_IntSendMessageTimeout(HWND_BROADCAST,
1519 WM_SETTINGCHANGE,
1520 (WPARAM)uiAction,
1521 (LPARAM)ulResult,
1522 SMTO_NORMAL,
1523 100,
1524 &ulResult);
1525 }
1526 ulResult = 1;
1527 }
1528
1529 /* Dereference the windowstation */
1530 if (gpwinstaCurrent)
1531 {
1532 ObDereferenceObject(gpwinstaCurrent);
1533 gpwinstaCurrent = NULL;
1534 }
1535
1536 return ulResult;
1537 }
1538
1539 BOOL
1540 APIENTRY
1541 NtUserSystemParametersInfo(
1542 UINT uiAction,
1543 UINT uiParam,
1544 PVOID pvParam,
1545 UINT fWinIni)
1546 {
1547 BOOL bResult;
1548
1549 DPRINT("Enter NtUserSystemParametersInfo(%d)\n", uiAction);
1550 UserEnterExclusive();
1551
1552 //if (uiAction == SPI_SETMOUSE) gbDebug = 1;
1553
1554 // FIXME: get rid of the flags and only use this from um. kernel can access data directly.
1555 /* Set UM memory protection flag */
1556 fWinIni |= SPIF_PROTECT;
1557
1558 /* Call internal function */
1559 bResult = UserSystemParametersInfo(uiAction, uiParam, pvParam, fWinIni);
1560
1561 //DPRINTX("NtUserSystemParametersInfo SPI_ICONHORIZONTALSPACING uiParam=%d, pvParam=%p, pvParam=%d bResult=%d\n",
1562 // uiParam, pvParam, pvParam?*(UINT*)pvParam:0, bResult);
1563
1564 DPRINT("Leave NtUserSystemParametersInfo, returning %d\n", bResult);
1565 UserLeave();
1566
1567 //DPRINTX("NtUserSystemParametersInfo SPI_ICONHORIZONTALSPACING bResult=%d\n", bResult);
1568 //gbDebug = 0;
1569
1570 return bResult;
1571 }