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