- Fix compilation errors with GCC 4.0-20041205.
[reactos.git] / reactos / subsys / win32k / ntuser / misc.c
1 /* $Id: misc.c,v 1.92 2004/12/12 23:08:11 navaraf Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * PURPOSE: Misc User funcs
6 * FILE: subsys/win32k/ntuser/misc.c
7 * PROGRAMER: Ge van Geldorp (ge@gse.nl)
8 * REVISION HISTORY:
9 * 2003/05/22 Created
10 */
11
12 #include <w32k.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* registered Logon process */
18 PW32PROCESS LogonProcess = NULL;
19
20 void W32kRegisterPrimitiveMessageQueue() {
21 extern PUSER_MESSAGE_QUEUE pmPrimitiveMessageQueue;
22 if( !pmPrimitiveMessageQueue ) {
23 PW32THREAD pThread;
24 pThread = PsGetWin32Thread();
25 if( pThread && pThread->MessageQueue ) {
26 pmPrimitiveMessageQueue = pThread->MessageQueue;
27 DPRINT( "Installed primitive input queue.\n" );
28 }
29 } else {
30 DPRINT1( "Alert! Someone is trying to steal the primitive queue.\n" );
31 }
32 }
33
34 PUSER_MESSAGE_QUEUE W32kGetPrimitiveMessageQueue() {
35 extern PUSER_MESSAGE_QUEUE pmPrimitiveMessageQueue;
36 return pmPrimitiveMessageQueue;
37 }
38
39 BOOL FASTCALL
40 IntRegisterLogonProcess(DWORD ProcessId, BOOL Register)
41 {
42 PEPROCESS Process;
43 NTSTATUS Status;
44 CSRSS_API_REQUEST Request;
45 CSRSS_API_REPLY Reply;
46
47 Status = PsLookupProcessByProcessId((PVOID)ProcessId,
48 &Process);
49 if (!NT_SUCCESS(Status))
50 {
51 SetLastWin32Error(RtlNtStatusToDosError(Status));
52 return FALSE;
53 }
54
55 if (Register)
56 {
57 /* Register the logon process */
58 if (LogonProcess != NULL)
59 {
60 ObDereferenceObject(Process);
61 return FALSE;
62 }
63
64 LogonProcess = Process->Win32Process;
65 }
66 else
67 {
68 /* Deregister the logon process */
69 if (LogonProcess != Process->Win32Process)
70 {
71 ObDereferenceObject(Process);
72 return FALSE;
73 }
74
75 LogonProcess = NULL;
76 }
77
78 ObDereferenceObject(Process);
79
80 Request.Type = CSRSS_REGISTER_LOGON_PROCESS;
81 Request.Data.RegisterLogonProcessRequest.ProcessId = ProcessId;
82 Request.Data.RegisterLogonProcessRequest.Register = Register;
83
84 Status = CsrNotify(&Request, &Reply);
85 if (! NT_SUCCESS(Status))
86 {
87 DPRINT1("Failed to register logon process with CSRSS\n");
88 return FALSE;
89 }
90
91 return TRUE;
92 }
93
94 /*
95 * @unimplemented
96 */
97 DWORD
98 STDCALL
99 NtUserCallNoParam(DWORD Routine)
100 {
101 DWORD Result = 0;
102
103 switch(Routine)
104 {
105 case NOPARAM_ROUTINE_REGISTER_PRIMITIVE:
106 W32kRegisterPrimitiveMessageQueue();
107 Result = (DWORD)TRUE;
108 break;
109
110 case NOPARAM_ROUTINE_DESTROY_CARET:
111 Result = (DWORD)IntDestroyCaret(PsGetCurrentThread()->Tcb.Win32Thread);
112 break;
113
114 case NOPARAM_ROUTINE_INIT_MESSAGE_PUMP:
115 Result = (DWORD)IntInitMessagePumpHook();
116 break;
117
118 case NOPARAM_ROUTINE_UNINIT_MESSAGE_PUMP:
119 Result = (DWORD)IntUninitMessagePumpHook();
120 break;
121
122 case NOPARAM_ROUTINE_GETMESSAGEEXTRAINFO:
123 Result = (DWORD)MsqGetMessageExtraInfo();
124 break;
125
126 case NOPARAM_ROUTINE_ANYPOPUP:
127 Result = (DWORD)IntAnyPopup();
128 break;
129
130 case NOPARAM_ROUTINE_CSRSS_INITIALIZED:
131 Result = (DWORD)CsrInit();
132 break;
133
134 case NOPARAM_ROUTINE_GDI_QUERY_TABLE:
135 Result = (DWORD)GDI_MapHandleTable(NtCurrentProcess());
136 break;
137
138 default:
139 DPRINT1("Calling invalid routine number 0x%x in NtUserCallNoParam\n", Routine);
140 SetLastWin32Error(ERROR_INVALID_PARAMETER);
141 break;
142 }
143 return Result;
144 }
145
146 /*
147 * @implemented
148 */
149 DWORD
150 STDCALL
151 NtUserCallOneParam(
152 DWORD Param,
153 DWORD Routine)
154 {
155 switch(Routine)
156 {
157 case ONEPARAM_ROUTINE_GETMENU:
158 {
159 PWINDOW_OBJECT WindowObject;
160 DWORD Result;
161
162 WindowObject = IntGetWindowObject((HWND)Param);
163 if(!WindowObject)
164 {
165 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
166 return FALSE;
167 }
168
169 Result = (DWORD)WindowObject->IDMenu;
170
171 IntReleaseWindowObject(WindowObject);
172 return Result;
173 }
174
175 case ONEPARAM_ROUTINE_ISWINDOWUNICODE:
176 {
177 PWINDOW_OBJECT WindowObject;
178 DWORD Result;
179
180 WindowObject = IntGetWindowObject((HWND)Param);
181 if(!WindowObject)
182 {
183 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
184 return FALSE;
185 }
186 Result = WindowObject->Unicode;
187 IntReleaseWindowObject(WindowObject);
188 return Result;
189 }
190
191 case ONEPARAM_ROUTINE_WINDOWFROMDC:
192 return (DWORD)IntWindowFromDC((HDC)Param);
193
194 case ONEPARAM_ROUTINE_GETWNDCONTEXTHLPID:
195 {
196 PWINDOW_OBJECT WindowObject;
197 DWORD Result;
198
199 WindowObject = IntGetWindowObject((HWND)Param);
200 if(!WindowObject)
201 {
202 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
203 return FALSE;
204 }
205
206 Result = WindowObject->ContextHelpId;
207
208 IntReleaseWindowObject(WindowObject);
209 return Result;
210 }
211
212 case ONEPARAM_ROUTINE_SWAPMOUSEBUTTON:
213 {
214 PWINSTATION_OBJECT WinStaObject;
215 NTSTATUS Status;
216 DWORD Result;
217
218 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
219 KernelMode,
220 0,
221 &WinStaObject);
222 if (!NT_SUCCESS(Status))
223 return (DWORD)FALSE;
224
225 /* FIXME
226 Result = (DWORD)IntSwapMouseButton(WinStaObject, (BOOL)Param); */
227 Result = 0;
228
229 ObDereferenceObject(WinStaObject);
230 return Result;
231 }
232
233 case ONEPARAM_ROUTINE_SWITCHCARETSHOWING:
234 return (DWORD)IntSwitchCaretShowing((PVOID)Param);
235
236 case ONEPARAM_ROUTINE_SETCARETBLINKTIME:
237 return (DWORD)IntSetCaretBlinkTime((UINT)Param);
238
239 case ONEPARAM_ROUTINE_ENUMCLIPBOARDFORMATS:
240 return (DWORD)IntEnumClipboardFormats((UINT)Param);
241
242 case ONEPARAM_ROUTINE_GETWINDOWINSTANCE:
243 {
244 PWINDOW_OBJECT WindowObject;
245 DWORD Result;
246
247 if(!(WindowObject = IntGetWindowObject((HWND)Param)))
248 {
249 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
250 return FALSE;
251 }
252
253 Result = (DWORD)WindowObject->Instance;
254 IntReleaseWindowObject(WindowObject);
255 return Result;
256 }
257
258 case ONEPARAM_ROUTINE_SETMESSAGEEXTRAINFO:
259 return (DWORD)MsqSetMessageExtraInfo((LPARAM)Param);
260
261 case ONEPARAM_ROUTINE_GETCURSORPOSITION:
262 {
263 PSYSTEM_CURSORINFO CurInfo;
264 PWINSTATION_OBJECT WinStaObject;
265 NTSTATUS Status;
266 POINT Pos;
267
268 if(!Param)
269 return (DWORD)FALSE;
270 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
271 KernelMode,
272 0,
273 &WinStaObject);
274 if (!NT_SUCCESS(Status))
275 return (DWORD)FALSE;
276
277 CurInfo = IntGetSysCursorInfo(WinStaObject);
278 /* FIXME - check if process has WINSTA_READATTRIBUTES */
279 Pos.x = CurInfo->x;
280 Pos.y = CurInfo->y;
281
282 Status = MmCopyToCaller((PPOINT)Param, &Pos, sizeof(POINT));
283 if(!NT_SUCCESS(Status))
284 {
285 ObDereferenceObject(WinStaObject);
286 SetLastNtError(Status);
287 return FALSE;
288 }
289
290 ObDereferenceObject(WinStaObject);
291
292 return (DWORD)TRUE;
293 }
294
295 case ONEPARAM_ROUTINE_ISWINDOWINDESTROY:
296 {
297 PWINDOW_OBJECT WindowObject;
298 DWORD Result;
299
300 WindowObject = IntGetWindowObject((HWND)Param);
301 if(!WindowObject)
302 {
303 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
304 return FALSE;
305 }
306
307 Result = (DWORD)IntIsWindowInDestroy(WindowObject);
308
309 IntReleaseWindowObject(WindowObject);
310 return Result;
311 }
312
313 case ONEPARAM_ROUTINE_ENABLEPROCWNDGHSTING:
314 {
315 BOOL Enable;
316 PW32PROCESS Process = PsGetWin32Process();
317
318 if(Process != NULL)
319 {
320 Enable = (BOOL)(Param != 0);
321
322 if(Enable)
323 {
324 Process->Flags &= ~W32PF_NOWINDOWGHOSTING;
325 }
326 else
327 {
328 Process->Flags |= W32PF_NOWINDOWGHOSTING;
329 }
330
331 return TRUE;
332 }
333
334 return FALSE;
335 }
336 }
337 DPRINT1("Calling invalid routine number 0x%x in NtUserCallOneParam(), Param=0x%x\n",
338 Routine, Param);
339 SetLastWin32Error(ERROR_INVALID_PARAMETER);
340 return 0;
341 }
342
343
344 /*
345 * @implemented
346 */
347 DWORD
348 STDCALL
349 NtUserCallTwoParam(
350 DWORD Param1,
351 DWORD Param2,
352 DWORD Routine)
353 {
354 NTSTATUS Status;
355 PWINDOW_OBJECT WindowObject;
356
357 switch(Routine)
358 {
359 case TWOPARAM_ROUTINE_SETDCPENCOLOR:
360 {
361 return (DWORD)IntSetDCColor((HDC)Param1, OBJ_PEN, (COLORREF)Param2);
362 }
363 case TWOPARAM_ROUTINE_SETDCBRUSHCOLOR:
364 {
365 return (DWORD)IntSetDCColor((HDC)Param1, OBJ_BRUSH, (COLORREF)Param2);
366 }
367 case TWOPARAM_ROUTINE_GETDCCOLOR:
368 {
369 return (DWORD)IntGetDCColor((HDC)Param1, (ULONG)Param2);
370 }
371 case TWOPARAM_ROUTINE_GETWINDOWRGNBOX:
372 {
373 DWORD Ret;
374 RECT rcRect;
375 Ret = (DWORD)IntGetWindowRgnBox((HWND)Param1, &rcRect);
376 Status = MmCopyToCaller((PVOID)Param2, &rcRect, sizeof(RECT));
377 if(!NT_SUCCESS(Status))
378 {
379 SetLastNtError(Status);
380 return ERROR;
381 }
382 return Ret;
383 }
384 case TWOPARAM_ROUTINE_GETWINDOWRGN:
385 {
386 return (DWORD)IntGetWindowRgn((HWND)Param1, (HRGN)Param2);
387 }
388 case TWOPARAM_ROUTINE_SETMENUBARHEIGHT:
389 {
390 DWORD Ret;
391 PMENU_OBJECT MenuObject = IntGetMenuObject((HMENU)Param1);
392 if(!MenuObject)
393 return 0;
394
395 if(Param2 > 0)
396 {
397 Ret = (MenuObject->MenuInfo.Height == (int)Param2);
398 MenuObject->MenuInfo.Height = (int)Param2;
399 }
400 else
401 Ret = (DWORD)MenuObject->MenuInfo.Height;
402 IntReleaseMenuObject(MenuObject);
403 return Ret;
404 }
405 case TWOPARAM_ROUTINE_SETMENUITEMRECT:
406 {
407 BOOL Ret;
408 SETMENUITEMRECT smir;
409 PMENU_OBJECT MenuObject = IntGetMenuObject((HMENU)Param1);
410 if(!MenuObject)
411 return 0;
412
413 if(!NT_SUCCESS(MmCopyFromCaller(&smir, (PVOID)Param2, sizeof(SETMENUITEMRECT))))
414 {
415 IntReleaseMenuObject(MenuObject);
416 return 0;
417 }
418
419 Ret = IntSetMenuItemRect(MenuObject, smir.uItem, smir.fByPosition, &smir.rcRect);
420
421 IntReleaseMenuObject(MenuObject);
422 return (DWORD)Ret;
423 }
424
425 case TWOPARAM_ROUTINE_SETGUITHRDHANDLE:
426 {
427 PUSER_MESSAGE_QUEUE MsgQueue = PsGetCurrentThread()->Tcb.Win32Thread->MessageQueue;
428
429 ASSERT(MsgQueue);
430 return (DWORD)MsqSetStateWindow(MsgQueue, (ULONG)Param1, (HWND)Param2);
431 }
432
433 case TWOPARAM_ROUTINE_ENABLEWINDOW:
434 UNIMPLEMENTED
435 return 0;
436
437 case TWOPARAM_ROUTINE_UNKNOWN:
438 UNIMPLEMENTED
439 return 0;
440
441 case TWOPARAM_ROUTINE_SHOWOWNEDPOPUPS:
442 UNIMPLEMENTED
443 return 0;
444
445 case TWOPARAM_ROUTINE_SWITCHTOTHISWINDOW:
446 UNIMPLEMENTED
447 return 0;
448
449 case TWOPARAM_ROUTINE_VALIDATERGN:
450 return (DWORD)NtUserValidateRgn((HWND) Param1, (HRGN) Param2);
451
452 case TWOPARAM_ROUTINE_SETWNDCONTEXTHLPID:
453 WindowObject = IntGetWindowObject((HWND)Param1);
454 if(!WindowObject)
455 {
456 SetLastWin32Error(ERROR_INVALID_HANDLE);
457 return (DWORD)FALSE;
458 }
459
460 WindowObject->ContextHelpId = Param2;
461
462 IntReleaseWindowObject(WindowObject);
463 return (DWORD)TRUE;
464
465 case TWOPARAM_ROUTINE_SETCARETPOS:
466 return (DWORD)IntSetCaretPos((int)Param1, (int)Param2);
467
468 case TWOPARAM_ROUTINE_GETWINDOWINFO:
469 {
470 WINDOWINFO wi;
471 DWORD Ret;
472
473 if(!(WindowObject = IntGetWindowObject((HWND)Param1)))
474 {
475 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
476 return FALSE;
477 }
478
479 #if 0
480 /*
481 * According to WINE, Windows' doesn't check the cbSize field
482 */
483
484 Status = MmCopyFromCaller(&wi.cbSize, (PVOID)Param2, sizeof(wi.cbSize));
485 if(!NT_SUCCESS(Status))
486 {
487 IntReleaseWindowObject(WindowObject);
488 SetLastNtError(Status);
489 return FALSE;
490 }
491
492 if(wi.cbSize != sizeof(WINDOWINFO))
493 {
494 IntReleaseWindowObject(WindowObject);
495 SetLastWin32Error(ERROR_INVALID_PARAMETER);
496 return FALSE;
497 }
498 #endif
499
500 if((Ret = (DWORD)IntGetWindowInfo(WindowObject, &wi)))
501 {
502 Status = MmCopyToCaller((PVOID)Param2, &wi, sizeof(WINDOWINFO));
503 if(!NT_SUCCESS(Status))
504 {
505 IntReleaseWindowObject(WindowObject);
506 SetLastNtError(Status);
507 return FALSE;
508 }
509 }
510
511 IntReleaseWindowObject(WindowObject);
512 return Ret;
513 }
514
515 case TWOPARAM_ROUTINE_REGISTERLOGONPROC:
516 return (DWORD)IntRegisterLogonProcess(Param1, (BOOL)Param2);
517
518 case TWOPARAM_ROUTINE_SETSYSCOLORS:
519 {
520 DWORD Ret = 0;
521 PVOID Buffer;
522 struct
523 {
524 INT *Elements;
525 COLORREF *Colors;
526 } ChangeSysColors;
527
528 /* FIXME - we should make use of SEH here... */
529
530 Status = MmCopyFromCaller(&ChangeSysColors, (PVOID)Param1, sizeof(ChangeSysColors));
531 if(!NT_SUCCESS(Status))
532 {
533 SetLastNtError(Status);
534 return 0;
535 }
536
537 Buffer = ExAllocatePool(PagedPool, (Param2 * sizeof(INT)) + (Param2 * sizeof(COLORREF)));
538 if(Buffer != NULL)
539 {
540 INT *Elements = (INT*)Buffer;
541 COLORREF *Colors = (COLORREF*)Buffer + Param2;
542
543 Status = MmCopyFromCaller(Elements, ChangeSysColors.Elements, Param2 * sizeof(INT));
544 if(NT_SUCCESS(Status))
545 {
546 Status = MmCopyFromCaller(Colors, ChangeSysColors.Colors, Param2 * sizeof(COLORREF));
547 if(NT_SUCCESS(Status))
548 {
549 Ret = (DWORD)IntSetSysColors((UINT)Param2, Elements, Colors);
550 }
551 else
552 SetLastNtError(Status);
553 }
554 else
555 SetLastNtError(Status);
556
557 ExFreePool(Buffer);
558 }
559 return Ret;
560 }
561
562 case TWOPARAM_ROUTINE_GETSYSCOLORBRUSHES:
563 case TWOPARAM_ROUTINE_GETSYSCOLORPENS:
564 case TWOPARAM_ROUTINE_GETSYSCOLORS:
565 {
566 DWORD Ret = 0;
567 union
568 {
569 PVOID Pointer;
570 HBRUSH *Brushes;
571 HPEN *Pens;
572 COLORREF *Colors;
573 } Buffer;
574
575 /* FIXME - we should make use of SEH here... */
576
577 Buffer.Pointer = ExAllocatePool(PagedPool, Param2 * sizeof(HANDLE));
578 if(Buffer.Pointer != NULL)
579 {
580 switch(Routine)
581 {
582 case TWOPARAM_ROUTINE_GETSYSCOLORBRUSHES:
583 Ret = (DWORD)IntGetSysColorBrushes(Buffer.Brushes, (UINT)Param2);
584 break;
585 case TWOPARAM_ROUTINE_GETSYSCOLORPENS:
586 Ret = (DWORD)IntGetSysColorPens(Buffer.Pens, (UINT)Param2);
587 break;
588 case TWOPARAM_ROUTINE_GETSYSCOLORS:
589 Ret = (DWORD)IntGetSysColors(Buffer.Colors, (UINT)Param2);
590 break;
591 default:
592 Ret = 0;
593 break;
594 }
595
596 if(Ret > 0)
597 {
598 Status = MmCopyToCaller((PVOID)Param1, Buffer.Pointer, Param2 * sizeof(HANDLE));
599 if(!NT_SUCCESS(Status))
600 {
601 SetLastNtError(Status);
602 Ret = 0;
603 }
604 }
605
606 ExFreePool(Buffer.Pointer);
607 }
608
609 return Ret;
610 }
611
612 }
613 DPRINT1("Calling invalid routine number 0x%x in NtUserCallTwoParam(), Param1=0x%x Parm2=0x%x\n",
614 Routine, Param1, Param2);
615 SetLastWin32Error(ERROR_INVALID_PARAMETER);
616 return 0;
617 }
618
619 /*
620 * @unimplemented
621 */
622 BOOL
623 STDCALL
624 NtUserCallHwndLock(
625 HWND hWnd,
626 DWORD Routine)
627 {
628 BOOL Ret = 0;
629 PWINDOW_OBJECT Window;
630
631 Window = IntGetWindowObject(hWnd);
632 if (Window == 0)
633 {
634 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
635 return FALSE;
636 }
637
638 /* FIXME: Routine can be 0x53 - 0x5E */
639 switch (Routine)
640 {
641 case HWNDLOCK_ROUTINE_ARRANGEICONICWINDOWS:
642 /* FIXME */
643 break;
644
645 case HWNDLOCK_ROUTINE_DRAWMENUBAR:
646 /* FIXME */
647 break;
648
649 case HWNDLOCK_ROUTINE_REDRAWFRAME:
650 /* FIXME */
651 break;
652
653 case HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOW:
654 Ret = IntSetForegroundWindow(Window);
655 break;
656
657 case HWNDLOCK_ROUTINE_UPDATEWINDOW:
658 /* FIXME */
659 break;
660 }
661
662 IntReleaseWindowObject(Window);
663
664 return Ret;
665 }
666
667 HWND
668 STDCALL
669 NtUserCallHwndOpt(
670 HWND Param,
671 DWORD Routine)
672 {
673 switch (Routine)
674 {
675 case HWNDOPT_ROUTINE_SETPROGMANWINDOW:
676 /* FIXME */
677 break;
678
679 case HWNDOPT_ROUTINE_SETTASKMANWINDOW:
680 /* FIXME */
681 break;
682 }
683
684 return 0;
685 }
686
687 /*
688 * @unimplemented
689 */
690 DWORD STDCALL
691 NtUserGetThreadState(
692 DWORD Routine)
693 {
694 switch (Routine)
695 {
696 case 0:
697 return (DWORD)IntGetThreadFocusWindow();
698 }
699 return 0;
700 }
701
702 VOID FASTCALL
703 IntGetFontMetricSetting(LPWSTR lpValueName, PLOGFONTW font)
704 {
705 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
706 NTSTATUS Status;
707 static LOGFONTW DefaultFont = {
708 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
709 0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
710 L"Bitstream Vera Sans"
711 };
712
713 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
714
715 QueryTable[0].Name = lpValueName;
716 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
717 QueryTable[0].EntryContext = font;
718
719 Status = RtlQueryRegistryValues(
720 RTL_REGISTRY_USER,
721 L"Control Panel\\Desktop\\WindowMetrics",
722 QueryTable,
723 NULL,
724 NULL);
725
726 if (!NT_SUCCESS(Status))
727 {
728 RtlCopyMemory(font, &DefaultFont, sizeof(LOGFONTW));
729 }
730 }
731
732 ULONG FASTCALL
733 IntSystemParametersInfo(
734 UINT uiAction,
735 UINT uiParam,
736 PVOID pvParam,
737 UINT fWinIni)
738 {
739 PWINSTATION_OBJECT WinStaObject;
740 NTSTATUS Status;
741
742 static BOOL bInitialized = FALSE;
743 static LOGFONTW IconFont;
744 static NONCLIENTMETRICSW pMetrics;
745 static BOOL GradientCaptions = TRUE;
746 static UINT FocusBorderHeight = 1;
747 static UINT FocusBorderWidth = 1;
748
749 if (!bInitialized)
750 {
751 ZeroMemory(&IconFont, sizeof(LOGFONTW));
752 ZeroMemory(&pMetrics, sizeof(NONCLIENTMETRICSW));
753
754 IntGetFontMetricSetting(L"CaptionFont", &pMetrics.lfCaptionFont);
755 IntGetFontMetricSetting(L"SmCaptionFont", &pMetrics.lfSmCaptionFont);
756 IntGetFontMetricSetting(L"MenuFont", &pMetrics.lfMenuFont);
757 IntGetFontMetricSetting(L"StatusFont", &pMetrics.lfStatusFont);
758 IntGetFontMetricSetting(L"MessageFont", &pMetrics.lfMessageFont);
759 IntGetFontMetricSetting(L"IconFont", &IconFont);
760
761 pMetrics.iBorderWidth = 1;
762 pMetrics.iScrollWidth = NtUserGetSystemMetrics(SM_CXVSCROLL);
763 pMetrics.iScrollHeight = NtUserGetSystemMetrics(SM_CYHSCROLL);
764 pMetrics.iCaptionWidth = NtUserGetSystemMetrics(SM_CXSIZE);
765 pMetrics.iCaptionHeight = NtUserGetSystemMetrics(SM_CYSIZE);
766 pMetrics.iSmCaptionWidth = NtUserGetSystemMetrics(SM_CXSMSIZE);
767 pMetrics.iSmCaptionHeight = NtUserGetSystemMetrics(SM_CYSMSIZE);
768 pMetrics.iMenuWidth = NtUserGetSystemMetrics(SM_CXMENUSIZE);
769 pMetrics.iMenuHeight = NtUserGetSystemMetrics(SM_CYMENUSIZE);
770 pMetrics.cbSize = sizeof(NONCLIENTMETRICSW);
771
772 bInitialized = TRUE;
773 }
774
775 switch(uiAction)
776 {
777 case SPI_SETDOUBLECLKWIDTH:
778 case SPI_SETDOUBLECLKHEIGHT:
779 case SPI_SETDOUBLECLICKTIME:
780 case SPI_SETDESKWALLPAPER:
781 case SPI_GETDESKWALLPAPER:
782 {
783 PSYSTEM_CURSORINFO CurInfo;
784
785 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
786 KernelMode,
787 0,
788 &WinStaObject);
789 if(!NT_SUCCESS(Status))
790 {
791 SetLastNtError(Status);
792 return (DWORD)FALSE;
793 }
794
795 switch(uiAction)
796 {
797 case SPI_SETDOUBLECLKWIDTH:
798 CurInfo = IntGetSysCursorInfo(WinStaObject);
799 /* FIXME limit the maximum value? */
800 CurInfo->DblClickWidth = uiParam;
801 break;
802 case SPI_SETDOUBLECLKHEIGHT:
803 CurInfo = IntGetSysCursorInfo(WinStaObject);
804 /* FIXME limit the maximum value? */
805 CurInfo->DblClickHeight = uiParam;
806 break;
807 case SPI_SETDOUBLECLICKTIME:
808 CurInfo = IntGetSysCursorInfo(WinStaObject);
809 /* FIXME limit the maximum time to 1000 ms? */
810 CurInfo->DblClickSpeed = uiParam;
811 break;
812 case SPI_SETDESKWALLPAPER:
813 {
814 /* This function expects different parameters than the user mode version!
815
816 We let the user mode code load the bitmap, it passed the handle to
817 the bitmap. We'll change it's ownership to system and replace it with
818 the current wallpaper bitmap */
819 HBITMAP hOldBitmap, hNewBitmap;
820 ASSERT(pvParam);
821
822 hNewBitmap = *(HBITMAP*)pvParam;
823 if(hNewBitmap != NULL)
824 {
825 BITMAPOBJ *bmp;
826 /* try to get the size of the wallpaper */
827 if(!(bmp = BITMAPOBJ_LockBitmap(hNewBitmap)))
828 {
829 ObDereferenceObject(WinStaObject);
830 return FALSE;
831 }
832 WinStaObject->cxWallpaper = bmp->SurfObj.sizlBitmap.cx;
833 WinStaObject->cyWallpaper = bmp->SurfObj.sizlBitmap.cy;
834
835 BITMAPOBJ_UnlockBitmap(hNewBitmap);
836
837 /* change the bitmap's ownership */
838 GDIOBJ_SetOwnership(hNewBitmap, NULL);
839 }
840 hOldBitmap = (HBITMAP)InterlockedExchange((LONG*)&WinStaObject->hbmWallpaper, (LONG)hNewBitmap);
841 if(hOldBitmap != NULL)
842 {
843 /* delete the old wallpaper */
844 NtGdiDeleteObject(hOldBitmap);
845 }
846 break;
847 }
848 case SPI_GETDESKWALLPAPER:
849 /* This function expects different parameters than the user mode version!
850
851 We basically return the current wallpaper handle - if any. The user
852 mode version should load the string from the registry and return it
853 without calling this function */
854 ASSERT(pvParam);
855 *(HBITMAP*)pvParam = (HBITMAP)WinStaObject->hbmWallpaper;
856 break;
857 }
858
859 /* FIXME save the value to the registry */
860
861 ObDereferenceObject(WinStaObject);
862 return TRUE;
863 }
864 case SPI_SETWORKAREA:
865 {
866 RECT *rc;
867 PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop;
868
869 if(!Desktop)
870 {
871 /* FIXME - Set last error */
872 return FALSE;
873 }
874
875 ASSERT(pvParam);
876 rc = (RECT*)pvParam;
877 Desktop->WorkArea = *rc;
878
879 return TRUE;
880 }
881 case SPI_GETWORKAREA:
882 {
883 PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop;
884
885 if(!Desktop)
886 {
887 /* FIXME - Set last error */
888 return FALSE;
889 }
890
891 ASSERT(pvParam);
892 IntGetDesktopWorkArea(Desktop, (PRECT)pvParam);
893
894 return TRUE;
895 }
896 case SPI_SETGRADIENTCAPTIONS:
897 {
898 GradientCaptions = (pvParam != NULL);
899 /* FIXME - should be checked if the color depth is higher than 8bpp? */
900 return TRUE;
901 }
902 case SPI_GETGRADIENTCAPTIONS:
903 {
904 HDC hDC;
905 BOOL Ret = GradientCaptions;
906
907 hDC = IntGetScreenDC();
908 if(hDC)
909 {
910 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && Ret;
911
912 ASSERT(pvParam);
913 *((PBOOL)pvParam) = Ret;
914 return TRUE;
915 }
916 return FALSE;
917 }
918 case SPI_SETFONTSMOOTHING:
919 {
920 IntEnableFontRendering(uiParam != 0);
921 return TRUE;
922 }
923 case SPI_GETFONTSMOOTHING:
924 {
925 ASSERT(pvParam);
926 *((BOOL*)pvParam) = IntIsFontRenderingEnabled();
927 return TRUE;
928 }
929 case SPI_GETICONTITLELOGFONT:
930 {
931 ASSERT(pvParam);
932 *((LOGFONTW*)pvParam) = IconFont;
933 return TRUE;
934 }
935 case SPI_GETNONCLIENTMETRICS:
936 {
937 ASSERT(pvParam);
938 *((NONCLIENTMETRICSW*)pvParam) = pMetrics;
939 return TRUE;
940 }
941 case SPI_GETFOCUSBORDERHEIGHT:
942 {
943 ASSERT(pvParam);
944 *((UINT*)pvParam) = FocusBorderHeight;
945 return TRUE;
946 }
947 case SPI_GETFOCUSBORDERWIDTH:
948 {
949 ASSERT(pvParam);
950 *((UINT*)pvParam) = FocusBorderWidth;
951 return TRUE;
952 }
953 case SPI_SETFOCUSBORDERHEIGHT:
954 {
955 FocusBorderHeight = (UINT)pvParam;
956 return TRUE;
957 }
958 case SPI_SETFOCUSBORDERWIDTH:
959 {
960 FocusBorderWidth = (UINT)pvParam;
961 return TRUE;
962 }
963
964 default:
965 {
966 DPRINT1("SystemParametersInfo: Unsupported Action 0x%x (uiParam: 0x%x, pvParam: 0x%x, fWinIni: 0x%x)\n",
967 uiAction, uiParam, pvParam, fWinIni);
968 return FALSE;
969 }
970 }
971 return FALSE;
972 }
973
974 /*
975 * @implemented
976 */
977 BOOL
978 STDCALL
979 NtUserSystemParametersInfo(
980 UINT uiAction,
981 UINT uiParam,
982 PVOID pvParam,
983 UINT fWinIni)
984 {
985 NTSTATUS Status;
986
987 switch(uiAction)
988 {
989 case SPI_SETDOUBLECLKWIDTH:
990 case SPI_SETDOUBLECLKHEIGHT:
991 case SPI_SETDOUBLECLICKTIME:
992 case SPI_SETGRADIENTCAPTIONS:
993 case SPI_SETFONTSMOOTHING:
994 case SPI_SETFOCUSBORDERHEIGHT:
995 case SPI_SETFOCUSBORDERWIDTH:
996 {
997 return (DWORD)IntSystemParametersInfo(uiAction, uiParam, pvParam, fWinIni);
998 }
999 case SPI_SETWORKAREA:
1000 {
1001 RECT rc;
1002 Status = MmCopyFromCaller(&rc, (PRECT)pvParam, sizeof(RECT));
1003 if(!NT_SUCCESS(Status))
1004 {
1005 SetLastNtError(Status);
1006 return FALSE;
1007 }
1008 return (DWORD)IntSystemParametersInfo(uiAction, uiParam, &rc, fWinIni);
1009 }
1010 case SPI_GETWORKAREA:
1011 {
1012 RECT rc;
1013
1014 if(!IntSystemParametersInfo(uiAction, uiParam, &rc, fWinIni))
1015 {
1016 return FALSE;
1017 }
1018
1019 Status = MmCopyToCaller((PRECT)pvParam, &rc, sizeof(RECT));
1020 if(!NT_SUCCESS(Status))
1021 {
1022 SetLastNtError(Status);
1023 return FALSE;
1024 }
1025 return TRUE;
1026 }
1027 case SPI_GETFONTSMOOTHING:
1028 case SPI_GETGRADIENTCAPTIONS:
1029 case SPI_GETFOCUSBORDERHEIGHT:
1030 case SPI_GETFOCUSBORDERWIDTH:
1031 {
1032 BOOL Ret;
1033
1034 if(!IntSystemParametersInfo(uiAction, uiParam, &Ret, fWinIni))
1035 {
1036 return FALSE;
1037 }
1038
1039 Status = MmCopyToCaller(pvParam, &Ret, sizeof(BOOL));
1040 if(!NT_SUCCESS(Status))
1041 {
1042 SetLastNtError(Status);
1043 return FALSE;
1044 }
1045 return TRUE;
1046 }
1047 case SPI_SETDESKWALLPAPER:
1048 {
1049 /* !!! As opposed to the user mode version this version accepts a handle
1050 to the bitmap! */
1051 HBITMAP hbmWallpaper;
1052
1053 Status = MmCopyFromCaller(&hbmWallpaper, pvParam, sizeof(HBITMAP));
1054 if(!NT_SUCCESS(Status))
1055 {
1056 SetLastNtError(Status);
1057 return FALSE;
1058 }
1059 return IntSystemParametersInfo(SPI_SETDESKWALLPAPER, 0, &hbmWallpaper, fWinIni);
1060 }
1061 case SPI_GETDESKWALLPAPER:
1062 {
1063 /* !!! As opposed to the user mode version this version returns a handle
1064 to the bitmap! */
1065 HBITMAP hbmWallpaper;
1066 BOOL Ret;
1067
1068 Ret = IntSystemParametersInfo(SPI_GETDESKWALLPAPER, 0, &hbmWallpaper, fWinIni);
1069
1070 Status = MmCopyToCaller(pvParam, &hbmWallpaper, sizeof(HBITMAP));
1071 if(!NT_SUCCESS(Status))
1072 {
1073 SetLastNtError(Status);
1074 return FALSE;
1075 }
1076 return Ret;
1077 }
1078 case SPI_GETICONTITLELOGFONT:
1079 {
1080 LOGFONTW IconFont;
1081
1082 if(!IntSystemParametersInfo(uiAction, uiParam, &IconFont, fWinIni))
1083 {
1084 return FALSE;
1085 }
1086
1087 Status = MmCopyToCaller(pvParam, &IconFont, sizeof(LOGFONTW));
1088 if(!NT_SUCCESS(Status))
1089 {
1090 SetLastNtError(Status);
1091 return FALSE;
1092 }
1093 return TRUE;
1094 }
1095 case SPI_GETNONCLIENTMETRICS:
1096 {
1097 NONCLIENTMETRICSW metrics;
1098
1099 Status = MmCopyFromCaller(&metrics.cbSize, pvParam, sizeof(UINT));
1100 if(!NT_SUCCESS(Status))
1101 {
1102 SetLastNtError(Status);
1103 return FALSE;
1104 }
1105 if(metrics.cbSize != sizeof(NONCLIENTMETRICSW))
1106 {
1107 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1108 return FALSE;
1109 }
1110
1111 if(!IntSystemParametersInfo(uiAction, uiParam, &metrics, fWinIni))
1112 {
1113 return FALSE;
1114 }
1115
1116 Status = MmCopyToCaller(pvParam, &metrics.cbSize, sizeof(NONCLIENTMETRICSW));
1117 if(!NT_SUCCESS(Status))
1118 {
1119 SetLastNtError(Status);
1120 return FALSE;
1121 }
1122 return TRUE;
1123 }
1124 }
1125 return FALSE;
1126 }
1127
1128 UINT
1129 STDCALL
1130 NtUserGetDoubleClickTime(VOID)
1131 {
1132 UINT Result;
1133 NTSTATUS Status;
1134 PWINSTATION_OBJECT WinStaObject;
1135 PSYSTEM_CURSORINFO CurInfo;
1136
1137 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
1138 KernelMode,
1139 0,
1140 &WinStaObject);
1141 if (!NT_SUCCESS(Status))
1142 return (DWORD)FALSE;
1143
1144 CurInfo = IntGetSysCursorInfo(WinStaObject);
1145 Result = CurInfo->DblClickSpeed;
1146
1147 ObDereferenceObject(WinStaObject);
1148 return Result;
1149 }
1150
1151 BOOL
1152 STDCALL
1153 NtUserGetGUIThreadInfo(
1154 DWORD idThread,
1155 LPGUITHREADINFO lpgui)
1156 {
1157 NTSTATUS Status;
1158 PTHRDCARETINFO CaretInfo;
1159 GUITHREADINFO SafeGui;
1160 PDESKTOP_OBJECT Desktop;
1161 PUSER_MESSAGE_QUEUE MsgQueue;
1162 PETHREAD Thread = NULL;
1163
1164 Status = MmCopyFromCaller(&SafeGui, lpgui, sizeof(DWORD));
1165 if(!NT_SUCCESS(Status))
1166 {
1167 SetLastNtError(Status);
1168 return FALSE;
1169 }
1170
1171 if(SafeGui.cbSize != sizeof(GUITHREADINFO))
1172 {
1173 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1174 return FALSE;
1175 }
1176
1177 if(idThread)
1178 {
1179 Status = PsLookupThreadByThreadId((PVOID)idThread, &Thread);
1180 if(!NT_SUCCESS(Status))
1181 {
1182 SetLastWin32Error(ERROR_ACCESS_DENIED);
1183 return FALSE;
1184 }
1185 Desktop = Thread->Tcb.Win32Thread->Desktop;
1186 }
1187 else
1188 {
1189 /* get the foreground thread */
1190 PW32THREAD W32Thread = PsGetCurrentThread()->Tcb.Win32Thread;
1191 Desktop = W32Thread->Desktop;
1192 if(Desktop)
1193 {
1194 MsgQueue = Desktop->ActiveMessageQueue;
1195 if(MsgQueue)
1196 {
1197 Thread = MsgQueue->Thread;
1198 }
1199 }
1200 }
1201
1202 if(!Thread || !Desktop)
1203 {
1204 if(idThread && Thread)
1205 ObDereferenceObject(Thread);
1206 SetLastWin32Error(ERROR_ACCESS_DENIED);
1207 return FALSE;
1208 }
1209
1210 MsgQueue = (PUSER_MESSAGE_QUEUE)Desktop->ActiveMessageQueue;
1211 CaretInfo = MsgQueue->CaretInfo;
1212
1213 SafeGui.flags = (CaretInfo->Visible ? GUI_CARETBLINKING : 0);
1214 if(MsgQueue->MenuOwner)
1215 SafeGui.flags |= GUI_INMENUMODE | MsgQueue->MenuState;
1216 if(MsgQueue->MoveSize)
1217 SafeGui.flags |= GUI_INMOVESIZE;
1218
1219 /* FIXME add flag GUI_16BITTASK */
1220
1221 SafeGui.hwndActive = MsgQueue->ActiveWindow;
1222 SafeGui.hwndFocus = MsgQueue->FocusWindow;
1223 SafeGui.hwndCapture = MsgQueue->CaptureWindow;
1224 SafeGui.hwndMenuOwner = MsgQueue->MenuOwner;
1225 SafeGui.hwndMoveSize = MsgQueue->MoveSize;
1226 SafeGui.hwndCaret = CaretInfo->hWnd;
1227
1228 SafeGui.rcCaret.left = CaretInfo->Pos.x;
1229 SafeGui.rcCaret.top = CaretInfo->Pos.y;
1230 SafeGui.rcCaret.right = SafeGui.rcCaret.left + CaretInfo->Size.cx;
1231 SafeGui.rcCaret.bottom = SafeGui.rcCaret.top + CaretInfo->Size.cy;
1232
1233 if(idThread)
1234 ObDereferenceObject(Thread);
1235
1236 Status = MmCopyToCaller(lpgui, &SafeGui, sizeof(GUITHREADINFO));
1237 if(!NT_SUCCESS(Status))
1238 {
1239 SetLastNtError(Status);
1240 return FALSE;
1241 }
1242
1243 return TRUE;
1244 }
1245
1246
1247 DWORD
1248 STDCALL
1249 NtUserGetGuiResources(
1250 HANDLE hProcess,
1251 DWORD uiFlags)
1252 {
1253 PEPROCESS Process;
1254 PW32PROCESS W32Process;
1255 NTSTATUS Status;
1256 DWORD Ret = 0;
1257
1258 Status = ObReferenceObjectByHandle(hProcess,
1259 PROCESS_QUERY_INFORMATION,
1260 PsProcessType,
1261 ExGetPreviousMode(),
1262 (PVOID*)&Process,
1263 NULL);
1264
1265 if(!NT_SUCCESS(Status))
1266 {
1267 SetLastNtError(Status);
1268 return 0;
1269 }
1270
1271 W32Process = Process->Win32Process;
1272 if(!W32Process)
1273 {
1274 ObDereferenceObject(Process);
1275 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1276 return 0;
1277 }
1278
1279 switch(uiFlags)
1280 {
1281 case GR_GDIOBJECTS:
1282 {
1283 Ret = (DWORD)W32Process->GDIObjects;
1284 break;
1285 }
1286 case GR_USEROBJECTS:
1287 {
1288 Ret = (DWORD)W32Process->UserObjects;
1289 break;
1290 }
1291 default:
1292 {
1293 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1294 break;
1295 }
1296 }
1297
1298 ObDereferenceObject(Process);
1299
1300 return Ret;
1301 }
1302
1303 NTSTATUS FASTCALL
1304 IntSafeCopyUnicodeString(PUNICODE_STRING Dest,
1305 PUNICODE_STRING Source)
1306 {
1307 NTSTATUS Status;
1308 PWSTR Src;
1309
1310 Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
1311 if(!NT_SUCCESS(Status))
1312 {
1313 return Status;
1314 }
1315
1316 if(Dest->Length > 0x4000)
1317 {
1318 return STATUS_UNSUCCESSFUL;
1319 }
1320
1321 Src = Dest->Buffer;
1322 Dest->Buffer = NULL;
1323
1324 if(Dest->Length > 0 && Src)
1325 {
1326 Dest->MaximumLength = Dest->Length;
1327 Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
1328 if(!Dest->Buffer)
1329 {
1330 return STATUS_NO_MEMORY;
1331 }
1332
1333 Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
1334 if(!NT_SUCCESS(Status))
1335 {
1336 ExFreePool(Dest->Buffer);
1337 Dest->Buffer = NULL;
1338 return Status;
1339 }
1340
1341
1342 return STATUS_SUCCESS;
1343 }
1344
1345 /* string is empty */
1346 return STATUS_SUCCESS;
1347 }
1348
1349 NTSTATUS FASTCALL
1350 IntSafeCopyUnicodeStringTerminateNULL(PUNICODE_STRING Dest,
1351 PUNICODE_STRING Source)
1352 {
1353 NTSTATUS Status;
1354 PWSTR Src;
1355
1356 Status = MmCopyFromCaller(Dest, Source, sizeof(UNICODE_STRING));
1357 if(!NT_SUCCESS(Status))
1358 {
1359 return Status;
1360 }
1361
1362 if(Dest->Length > 0x4000)
1363 {
1364 return STATUS_UNSUCCESSFUL;
1365 }
1366
1367 Src = Dest->Buffer;
1368 Dest->Buffer = NULL;
1369
1370 if(Dest->Length > 0 && Src)
1371 {
1372 Dest->MaximumLength = Dest->Length + sizeof(WCHAR);
1373 Dest->Buffer = ExAllocatePoolWithTag(PagedPool, Dest->MaximumLength, TAG_STRING);
1374 if(!Dest->Buffer)
1375 {
1376 return STATUS_NO_MEMORY;
1377 }
1378
1379 Status = MmCopyFromCaller(Dest->Buffer, Src, Dest->Length);
1380 if(!NT_SUCCESS(Status))
1381 {
1382 ExFreePool(Dest->Buffer);
1383 Dest->Buffer = NULL;
1384 return Status;
1385 }
1386
1387 /* make sure the string is null-terminated */
1388 Src = (PWSTR)((PBYTE)Dest->Buffer + Dest->Length);
1389 *Src = L'\0';
1390
1391 return STATUS_SUCCESS;
1392 }
1393
1394 /* string is empty */
1395 return STATUS_SUCCESS;
1396 }
1397
1398 NTSTATUS FASTCALL
1399 IntUnicodeStringToNULLTerminated(PWSTR *Dest, PUNICODE_STRING Src)
1400 {
1401 if (Src->Length + sizeof(WCHAR) <= Src->MaximumLength
1402 && L'\0' == Src->Buffer[Src->Length / sizeof(WCHAR)])
1403 {
1404 /* The unicode_string is already nul terminated. Just reuse it. */
1405 *Dest = Src->Buffer;
1406 return STATUS_SUCCESS;
1407 }
1408
1409 *Dest = ExAllocatePoolWithTag(PagedPool, Src->Length + sizeof(WCHAR), TAG_STRING);
1410 if (NULL == *Dest)
1411 {
1412 return STATUS_NO_MEMORY;
1413 }
1414 RtlCopyMemory(*Dest, Src->Buffer, Src->Length);
1415 (*Dest)[Src->Length / 2] = L'\0';
1416
1417 return STATUS_SUCCESS;
1418 }
1419
1420 void FASTCALL
1421 IntFreeNULLTerminatedFromUnicodeString(PWSTR NullTerminated, PUNICODE_STRING UnicodeString)
1422 {
1423 if (NullTerminated != UnicodeString->Buffer)
1424 {
1425 ExFreePool(NullTerminated);
1426 }
1427 }
1428
1429 BOOL STDCALL
1430 NtUserUpdatePerUserSystemParameters(
1431 DWORD dwReserved,
1432 BOOL bEnable)
1433 {
1434 BOOL Result = TRUE;
1435 Result &= IntDesktopUpdatePerUserSettings(bEnable);
1436 return Result;
1437 }
1438
1439 /* EOF */