Copy makefile
[reactos.git] / reactos / subsys / win32k / ntuser / desktop.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 * $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Desktops
24 * FILE: subsys/win32k/ntuser/desktop.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29
30 /* INCLUDES ******************************************************************/
31 #include <w32k.h>
32
33 #if 0
34 /* not yet defined in w32api... */
35 NTSTATUS STDCALL
36 ObFindHandleForObject(IN PEPROCESS Process,
37 IN PVOID Object,
38 IN POBJECT_TYPE ObjectType,
39 IN POBJECT_HANDLE_INFORMATION HandleInformation,
40 OUT PHANDLE Handle);
41 #else
42 #define ObFindHandleForObject(Process, Object, ObjectType, HandleInformation, Handle) \
43 (STATUS_UNSUCCESSFUL)
44 #endif
45
46 /* GLOBALS *******************************************************************/
47
48 /* Currently active desktop */
49 PDESKTOP_OBJECT InputDesktop = NULL;
50 HDESK InputDesktopHandle = NULL;
51 HDC ScreenDeviceContext = NULL;
52
53 BOOL g_PaintDesktopVersion = FALSE;
54
55 /* INITALIZATION FUNCTIONS ****************************************************/
56
57 NTSTATUS FASTCALL
58 InitDesktopImpl(VOID)
59 {
60 return STATUS_SUCCESS;
61 }
62
63 NTSTATUS FASTCALL
64 CleanupDesktopImpl(VOID)
65 {
66 return STATUS_SUCCESS;
67 }
68
69 /* PRIVATE FUNCTIONS **********************************************************/
70
71 NTSTATUS FASTCALL
72 IntParseDesktopPath(PEPROCESS Process,
73 PUNICODE_STRING DesktopPath,
74 HWINSTA *hWinSta,
75 HDESK *hDesktop)
76 {
77 OBJECT_ATTRIBUTES ObjectAttributes;
78 UNICODE_STRING WinSta, Desktop, FullName;
79 BOOL DesktopPresent = FALSE;
80 BOOL WinStaPresent = FALSE;
81 NTSTATUS Status;
82
83 ASSERT(hWinSta);
84
85 *hWinSta = NULL;
86
87 if(hDesktop != NULL)
88 {
89 *hDesktop = NULL;
90 }
91
92 RtlInitUnicodeString(&WinSta, NULL);
93 RtlInitUnicodeString(&Desktop, NULL);
94
95 if(DesktopPath != NULL && DesktopPath->Buffer != NULL && DesktopPath->Length > sizeof(WCHAR))
96 {
97 PWCHAR c = DesktopPath->Buffer;
98 USHORT wl = 0;
99 USHORT l = DesktopPath->Length;
100
101 /*
102 * Parse the desktop path string which can be in the form "WinSta\Desktop"
103 * or just "Desktop". In latter case WinSta0 will be used.
104 */
105
106 while(l > 0)
107 {
108 if(*c == L'\\')
109 {
110 wl = (ULONG_PTR)c - (ULONG_PTR)DesktopPath->Buffer;
111 break;
112 }
113 l -= sizeof(WCHAR);
114 c++;
115 }
116
117 if(wl > 0)
118 {
119 WinSta.Length = wl;
120 WinSta.MaximumLength = wl + sizeof(WCHAR);
121 WinSta.Buffer = DesktopPath->Buffer;
122
123 WinStaPresent = TRUE;
124 c++;
125 }
126
127 Desktop.Length = DesktopPath->Length - wl;
128 if(wl > 0)
129 {
130 Desktop.Length -= sizeof(WCHAR);
131 }
132 if(Desktop.Length > 0)
133 {
134 Desktop.MaximumLength = Desktop.Length + sizeof(WCHAR);
135 Desktop.Buffer = ((wl > 0) ? c : DesktopPath->Buffer);
136 DesktopPresent = TRUE;
137 }
138 }
139
140 if(!WinStaPresent)
141 {
142 /* search the process handle table for (inherited) window station
143 handles, use a more appropriate one than WinSta0 if possible. */
144 Status = ObFindHandleForObject(Process,
145 NULL,
146 ExWindowStationObjectType,
147 NULL,
148 (PHANDLE)hWinSta);
149 if(!NT_SUCCESS(Status))
150 {
151 /* we had no luck searching for opened handles, use WinSta0 now */
152 RtlInitUnicodeString(&WinSta, L"WinSta0");
153 }
154 }
155
156 if(!DesktopPresent && hDesktop != NULL)
157 {
158 /* search the process handle table for (inherited) desktop
159 handles, use a more appropriate one than Default if possible. */
160 Status = ObFindHandleForObject(Process,
161 NULL,
162 ExDesktopObjectType,
163 NULL,
164 (PHANDLE)hDesktop);
165 if(!NT_SUCCESS(Status))
166 {
167 /* we had no luck searching for opened handles, use Desktop now */
168 RtlInitUnicodeString(&Desktop, L"Default");
169 }
170 }
171
172 if(*hWinSta == NULL)
173 {
174 if(!IntGetFullWindowStationName(&FullName, &WinSta, NULL))
175 {
176 return STATUS_INSUFFICIENT_RESOURCES;
177 }
178
179 /* open the window station */
180 InitializeObjectAttributes(&ObjectAttributes,
181 &FullName,
182 OBJ_CASE_INSENSITIVE,
183 NULL,
184 NULL);
185
186 Status = ObOpenObjectByName(&ObjectAttributes,
187 ExWindowStationObjectType,
188 NULL,
189 UserMode,
190 0,
191 NULL,
192 (HANDLE*)hWinSta);
193
194 RtlFreeUnicodeString(&FullName);
195
196 if(!NT_SUCCESS(Status))
197 {
198 SetLastNtError(Status);
199 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta, PsGetCurrentProcessId());
200 return Status;
201 }
202 }
203
204 if(hDesktop != NULL && *hDesktop == NULL)
205 {
206 if(!IntGetFullWindowStationName(&FullName, &WinSta, &Desktop))
207 {
208 NtClose(*hWinSta);
209 *hWinSta = NULL;
210 return STATUS_INSUFFICIENT_RESOURCES;
211 }
212
213 /* open the desktop object */
214 InitializeObjectAttributes(&ObjectAttributes,
215 &FullName,
216 OBJ_CASE_INSENSITIVE,
217 NULL,
218 NULL);
219
220 Status = ObOpenObjectByName(&ObjectAttributes,
221 ExDesktopObjectType,
222 NULL,
223 UserMode,
224 0,
225 NULL,
226 (HANDLE*)hDesktop);
227
228 RtlFreeUnicodeString(&FullName);
229
230 if(!NT_SUCCESS(Status))
231 {
232 *hDesktop = NULL;
233 NtClose(*hWinSta);
234 *hWinSta = NULL;
235 SetLastNtError(Status);
236 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop, PsGetCurrentProcessId());
237 return Status;
238 }
239 }
240
241 return STATUS_SUCCESS;
242 }
243
244 /*
245 * IntValidateDesktopHandle
246 *
247 * Validates the desktop handle.
248 *
249 * Remarks
250 * If the function succeeds, the handle remains referenced. If the
251 * fucntion fails, last error is set.
252 */
253
254 NTSTATUS FASTCALL
255 IntValidateDesktopHandle(
256 HDESK Desktop,
257 KPROCESSOR_MODE AccessMode,
258 ACCESS_MASK DesiredAccess,
259 PDESKTOP_OBJECT *Object)
260 {
261 NTSTATUS Status;
262
263 Status = ObReferenceObjectByHandle(
264 Desktop,
265 DesiredAccess,
266 ExDesktopObjectType,
267 AccessMode,
268 (PVOID*)Object,
269 NULL);
270
271 if (!NT_SUCCESS(Status))
272 SetLastNtError(Status);
273
274 return Status;
275 }
276
277 VOID FASTCALL
278 IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop, PRECT Rect)
279 {
280 PRECT Ret;
281
282 ASSERT(Desktop);
283
284 Ret = &Desktop->WorkArea;
285 if((Ret->right == -1) && ScreenDeviceContext)
286 {
287 PDC dc;
288 BITMAPOBJ *BitmapObj;
289 dc = DC_LockDc(ScreenDeviceContext);
290 /* FIXME - Handle dc == NULL!!!! */
291 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
292 if(BitmapObj)
293 {
294 Ret->right = BitmapObj->SurfObj.sizlBitmap.cx;
295 Ret->bottom = BitmapObj->SurfObj.sizlBitmap.cy;
296 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
297 }
298 DC_UnlockDc(ScreenDeviceContext);
299 }
300
301 if(Rect)
302 {
303 *Rect = *Ret;
304 }
305 }
306
307 PDESKTOP_OBJECT FASTCALL
308 IntGetActiveDesktop(VOID)
309 {
310 return InputDesktop;
311 }
312
313 /*
314 * returns or creates a handle to the desktop object
315 */
316 HDESK FASTCALL
317 IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject)
318 {
319 NTSTATUS Status;
320 HDESK Ret;
321
322 ASSERT(DesktopObject);
323
324 Status = ObFindHandleForObject(PsGetCurrentProcess(),
325 DesktopObject,
326 ExDesktopObjectType,
327 NULL,
328 (PHANDLE)&Ret);
329
330 if(!NT_SUCCESS(Status))
331 {
332 Status = ObOpenObjectByPointer(DesktopObject,
333 0,
334 NULL,
335 0,
336 ExDesktopObjectType,
337 UserMode,
338 (PHANDLE)&Ret);
339 if(!NT_SUCCESS(Status))
340 {
341 /* unable to create a handle */
342 DPRINT1("Unable to create a desktop handle\n");
343 return NULL;
344 }
345 }
346
347 return Ret;
348 }
349
350 PUSER_MESSAGE_QUEUE FASTCALL
351 IntGetFocusMessageQueue(VOID)
352 {
353 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
354 if (!pdo)
355 {
356 DPRINT("No active desktop\n");
357 return(NULL);
358 }
359 return (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
360 }
361
362 VOID FASTCALL
363 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue)
364 {
365 PUSER_MESSAGE_QUEUE Old;
366 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
367 if (!pdo)
368 {
369 DPRINT("No active desktop\n");
370 return;
371 }
372 if(NewQueue != NULL)
373 {
374 if(NewQueue->Desktop != NULL)
375 {
376 DPRINT("Message Queue already attached to another desktop!\n");
377 return;
378 }
379 IntReferenceMessageQueue(NewQueue);
380 InterlockedExchange((LONG*)&NewQueue->Desktop, (LONG)pdo);
381 }
382 Old = (PUSER_MESSAGE_QUEUE)InterlockedExchange((LONG*)&pdo->ActiveMessageQueue, (LONG)NewQueue);
383 if(Old != NULL)
384 {
385 InterlockedExchange((LONG*)&Old->Desktop, 0);
386 IntDereferenceMessageQueue(Old);
387 }
388 }
389
390 HWND FASTCALL IntGetDesktopWindow(VOID)
391 {
392 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
393 if (!pdo)
394 {
395 DPRINT("No active desktop\n");
396 return NULL;
397 }
398 return pdo->DesktopWindow;
399 }
400
401 HWND FASTCALL IntGetCurrentThreadDesktopWindow(VOID)
402 {
403 PDESKTOP_OBJECT pdo = PsGetWin32Thread()->Desktop;
404 if (NULL == pdo)
405 {
406 DPRINT1("Thread doesn't have a desktop\n");
407 return NULL;
408 }
409 return pdo->DesktopWindow;
410 }
411
412 BOOL FASTCALL IntDesktopUpdatePerUserSettings(BOOL bEnable)
413 {
414 if (bEnable)
415 {
416 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
417 NTSTATUS Status;
418
419 RtlZeroMemory(QueryTable, sizeof(QueryTable));
420
421 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
422 QueryTable[0].Name = L"PaintDesktopVersion";
423 QueryTable[0].EntryContext = &g_PaintDesktopVersion;
424
425 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
426 Status = RtlQueryRegistryValues(RTL_REGISTRY_USER,
427 L"Control Panel\\Desktop",
428 QueryTable, NULL, NULL);
429 if (!NT_SUCCESS(Status))
430 {
431 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
432 Status);
433 g_PaintDesktopVersion = FALSE;
434 return FALSE;
435 }
436
437 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion);
438
439 return TRUE;
440 }
441 else
442 {
443 g_PaintDesktopVersion = FALSE;
444 return TRUE;
445 }
446 }
447
448 /* PUBLIC FUNCTIONS ***********************************************************/
449
450 NTSTATUS FASTCALL
451 IntShowDesktop(PDESKTOP_OBJECT Desktop, ULONG Width, ULONG Height)
452 {
453 CSRSS_API_REQUEST Request;
454 CSRSS_API_REPLY Reply;
455
456 Request.Type = CSRSS_SHOW_DESKTOP;
457 Request.Data.ShowDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
458 Request.Data.ShowDesktopRequest.Width = Width;
459 Request.Data.ShowDesktopRequest.Height = Height;
460
461 return CsrNotify(&Request, &Reply);
462 }
463
464 NTSTATUS FASTCALL
465 IntHideDesktop(PDESKTOP_OBJECT Desktop)
466 {
467 #if 0
468 CSRSS_API_REQUEST Request;
469 CSRSS_API_REPLY Reply;
470
471 Request.Type = CSRSS_HIDE_DESKTOP;
472 Request.Data.HideDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
473
474 return NotifyCsrss(&Request, &Reply);
475 #else
476 PWINDOW_OBJECT DesktopWindow;
477
478 DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
479 if (! DesktopWindow)
480 {
481 return ERROR_INVALID_WINDOW_HANDLE;
482 }
483 DesktopWindow->Style &= ~WS_VISIBLE;
484
485 return STATUS_SUCCESS;
486 #endif
487 }
488
489 /*
490 * NtUserCreateDesktop
491 *
492 * Creates a new desktop.
493 *
494 * Parameters
495 * lpszDesktopName
496 * Name of the new desktop.
497 *
498 * dwFlags
499 * Interaction flags.
500 *
501 * dwDesiredAccess
502 * Requested type of access.
503 *
504 * lpSecurity
505 * Security descriptor.
506 *
507 * hWindowStation
508 * Handle to window station on which to create the desktop.
509 *
510 * Return Value
511 * If the function succeeds, the return value is a handle to the newly
512 * created desktop. If the specified desktop already exists, the function
513 * succeeds and returns a handle to the existing desktop. When you are
514 * finished using the handle, call the CloseDesktop function to close it.
515 * If the function fails, the return value is NULL.
516 *
517 * Status
518 * @implemented
519 */
520
521 HDESK STDCALL
522 NtUserCreateDesktop(
523 PUNICODE_STRING lpszDesktopName,
524 DWORD dwFlags,
525 ACCESS_MASK dwDesiredAccess,
526 LPSECURITY_ATTRIBUTES lpSecurity,
527 HWINSTA hWindowStation)
528 {
529 OBJECT_ATTRIBUTES ObjectAttributes;
530 PWINSTATION_OBJECT WinStaObject;
531 PDESKTOP_OBJECT DesktopObject;
532 UNICODE_STRING DesktopName;
533 NTSTATUS Status;
534 HDESK Desktop;
535 CSRSS_API_REQUEST Request;
536 CSRSS_API_REPLY Reply;
537
538 DPRINT("CreateDesktop: %wZ\n", lpszDesktopName);
539
540 Status = IntValidateWindowStationHandle(
541 hWindowStation,
542 KernelMode,
543 0, /* FIXME - WINSTA_CREATEDESKTOP */
544 &WinStaObject);
545
546 if (! NT_SUCCESS(Status))
547 {
548 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
549 hWindowStation, lpszDesktopName);
550 SetLastNtError(Status);
551 return NULL;
552 }
553
554 if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
555 lpszDesktopName))
556 {
557 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
558 ObDereferenceObject(WinStaObject);
559 return NULL;
560 }
561
562 ObDereferenceObject(WinStaObject);
563
564 /*
565 * Try to open already existing desktop
566 */
567
568 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
569
570 /* Initialize ObjectAttributes for the desktop object */
571 InitializeObjectAttributes(
572 &ObjectAttributes,
573 &DesktopName,
574 0,
575 NULL,
576 NULL);
577
578 Status = ObOpenObjectByName(
579 &ObjectAttributes,
580 ExDesktopObjectType,
581 NULL,
582 UserMode,
583 dwDesiredAccess,
584 NULL,
585 (HANDLE*)&Desktop);
586
587 if (NT_SUCCESS(Status))
588 {
589 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
590 ExFreePool(DesktopName.Buffer);
591 return Desktop;
592 }
593
594 /*
595 * No existing desktop found, try to create new one
596 */
597
598 Status = ObCreateObject(
599 KernelMode,
600 ExDesktopObjectType,
601 &ObjectAttributes,
602 ExGetPreviousMode(),
603 NULL,
604 sizeof(DESKTOP_OBJECT),
605 0,
606 0,
607 (PVOID*)&DesktopObject);
608
609 if (! NT_SUCCESS(Status))
610 {
611 DPRINT1("Failed creating desktop (%wZ)\n", &DesktopName);
612 ExFreePool(DesktopName.Buffer);
613 SetLastNtError(STATUS_UNSUCCESSFUL);
614 return NULL;
615 }
616
617 // init desktop area
618 DesktopObject->WorkArea.left = 0;
619 DesktopObject->WorkArea.top = 0;
620 DesktopObject->WorkArea.right = -1;
621 DesktopObject->WorkArea.bottom = -1;
622 IntGetDesktopWorkArea(DesktopObject, NULL);
623
624 /* Initialize some local (to win32k) desktop state. */
625 DesktopObject->ActiveMessageQueue = NULL;
626
627 Status = ObInsertObject(
628 (PVOID)DesktopObject,
629 NULL,
630 STANDARD_RIGHTS_REQUIRED,
631 0,
632 NULL,
633 (HANDLE*)&Desktop);
634
635 ObDereferenceObject(DesktopObject);
636 ExFreePool(DesktopName.Buffer);
637
638 if (! NT_SUCCESS(Status))
639 {
640 DPRINT1("Failed to create desktop handle\n");
641 SetLastNtError(Status);
642 return NULL;
643 }
644
645 /*
646 * Create a handle for CSRSS and notify CSRSS
647 */
648 Request.Type = CSRSS_CREATE_DESKTOP;
649 Status = CsrInsertObject((PVOID)DesktopObject,
650 NULL,
651 GENERIC_ALL,
652 0,
653 NULL,
654 (HANDLE*)&Request.Data.CreateDesktopRequest.DesktopHandle);
655 if (! NT_SUCCESS(Status))
656 {
657 DPRINT1("Failed to create desktop handle for CSRSS\n");
658 ZwClose(Desktop);
659 SetLastNtError(Status);
660 return NULL;
661 }
662
663 Status = CsrNotify(&Request, &Reply);
664 if (! NT_SUCCESS(Status))
665 {
666 CsrCloseHandle(Request.Data.CreateDesktopRequest.DesktopHandle);
667 DPRINT1("Failed to notify CSRSS about new desktop\n");
668 ZwClose(Desktop);
669 SetLastNtError(Status);
670 return NULL;
671 }
672
673 return Desktop;
674 }
675
676 /*
677 * NtUserOpenDesktop
678 *
679 * Opens an existing desktop.
680 *
681 * Parameters
682 * lpszDesktopName
683 * Name of the existing desktop.
684 *
685 * dwFlags
686 * Interaction flags.
687 *
688 * dwDesiredAccess
689 * Requested type of access.
690 *
691 * Return Value
692 * Handle to the desktop or zero on failure.
693 *
694 * Status
695 * @implemented
696 */
697
698 HDESK STDCALL
699 NtUserOpenDesktop(
700 PUNICODE_STRING lpszDesktopName,
701 DWORD dwFlags,
702 ACCESS_MASK dwDesiredAccess)
703 {
704 OBJECT_ATTRIBUTES ObjectAttributes;
705 PWINSTATION_OBJECT WinStaObject;
706 UNICODE_STRING DesktopName;
707 NTSTATUS Status;
708 HDESK Desktop;
709
710 /*
711 * Validate the window station handle and compose the fully
712 * qualified desktop name
713 */
714
715 Status = IntValidateWindowStationHandle(
716 PsGetCurrentProcess()->Win32WindowStation,
717 KernelMode,
718 0,
719 &WinStaObject);
720
721 if (!NT_SUCCESS(Status))
722 {
723 DPRINT1("Failed validation of window station handle (0x%X)\n",
724 PsGetCurrentProcess()->Win32WindowStation);
725 SetLastNtError(Status);
726 return 0;
727 }
728
729 if (!IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
730 lpszDesktopName))
731 {
732 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
733 ObDereferenceObject(WinStaObject);
734 return 0;
735 }
736
737 ObDereferenceObject(WinStaObject);
738
739 DPRINT1("Trying to open desktop (%wZ)\n", &DesktopName);
740
741 /* Initialize ObjectAttributes for the desktop object */
742 InitializeObjectAttributes(
743 &ObjectAttributes,
744 &DesktopName,
745 0,
746 NULL,
747 NULL);
748
749 Status = ObOpenObjectByName(
750 &ObjectAttributes,
751 ExDesktopObjectType,
752 NULL,
753 UserMode,
754 dwDesiredAccess,
755 NULL,
756 (HANDLE*)&Desktop);
757
758 if (!NT_SUCCESS(Status))
759 {
760 SetLastNtError(Status);
761 ExFreePool(DesktopName.Buffer);
762 return 0;
763 }
764
765 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
766 ExFreePool(DesktopName.Buffer);
767
768 return Desktop;
769 }
770
771 /*
772 * NtUserOpenInputDesktop
773 *
774 * Opens the input (interactive) desktop.
775 *
776 * Parameters
777 * dwFlags
778 * Interaction flags.
779 *
780 * fInherit
781 * Inheritance option.
782 *
783 * dwDesiredAccess
784 * Requested type of access.
785 *
786 * Return Value
787 * Handle to the input desktop or zero on failure.
788 *
789 * Status
790 * @implemented
791 */
792
793 HDESK STDCALL
794 NtUserOpenInputDesktop(
795 DWORD dwFlags,
796 BOOL fInherit,
797 ACCESS_MASK dwDesiredAccess)
798 {
799 PDESKTOP_OBJECT Object;
800 NTSTATUS Status;
801 HDESK Desktop;
802
803 DPRINT("About to open input desktop\n");
804
805 /* Get a pointer to the desktop object */
806
807 Status = IntValidateDesktopHandle(
808 InputDesktopHandle,
809 UserMode,
810 0,
811 &Object);
812
813 if (!NT_SUCCESS(Status))
814 {
815 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
816 return (HDESK)0;
817 }
818
819 /* Create a new handle to the object */
820
821 Status = ObOpenObjectByPointer(
822 Object,
823 0,
824 NULL,
825 dwDesiredAccess,
826 ExDesktopObjectType,
827 UserMode,
828 (HANDLE*)&Desktop);
829
830 ObDereferenceObject(Object);
831
832 if (NT_SUCCESS(Status))
833 {
834 DPRINT("Successfully opened input desktop\n");
835 return (HDESK)Desktop;
836 }
837
838 SetLastNtError(Status);
839 return (HDESK)0;
840 }
841
842 /*
843 * NtUserCloseDesktop
844 *
845 * Closes a desktop handle.
846 *
847 * Parameters
848 * hDesktop
849 * Handle to the desktop.
850 *
851 * Return Value
852 * Status
853 *
854 * Remarks
855 * The desktop handle can be created with NtUserCreateDesktop or
856 * NtUserOpenDesktop. This function will fail if any thread in the calling
857 * process is using the specified desktop handle or if the handle refers
858 * to the initial desktop of the calling process.
859 *
860 * Status
861 * @implemented
862 */
863
864 BOOL STDCALL
865 NtUserCloseDesktop(HDESK hDesktop)
866 {
867 PDESKTOP_OBJECT Object;
868 NTSTATUS Status;
869
870 DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
871
872 Status = IntValidateDesktopHandle(
873 hDesktop,
874 UserMode,
875 0,
876 &Object);
877
878 if (!NT_SUCCESS(Status))
879 {
880 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
881 return FALSE;
882 }
883
884 ObDereferenceObject(Object);
885
886 DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
887
888 Status = ZwClose(hDesktop);
889 if (!NT_SUCCESS(Status))
890 {
891 SetLastNtError(Status);
892 return FALSE;
893 }
894
895 return TRUE;
896 }
897
898
899 static int GetSystemVersionString(LPWSTR buffer)
900 {
901 RTL_OSVERSIONINFOEXW versionInfo;
902 int len;
903
904 versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
905
906 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
907 return 0;
908
909 if (versionInfo.dwMajorVersion <= 4)
910 len = swprintf(buffer,
911 L"ReactOS Version %d.%d %s Build %d",
912 versionInfo.dwMajorVersion, versionInfo.dwMinorVersion,
913 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
914 else
915 len = swprintf(buffer,
916 L"ReactOS %s (Build %d)",
917 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
918
919 return len;
920 }
921
922 /*
923 * NtUserPaintDesktop
924 *
925 * The NtUserPaintDesktop function fills the clipping region in the
926 * specified device context with the desktop pattern or wallpaper. The
927 * function is provided primarily for shell desktops.
928 *
929 * Parameters
930 * hDC
931 * Handle to the device context.
932 *
933 * Status
934 * @implemented
935 */
936
937 BOOL STDCALL
938 NtUserPaintDesktop(HDC hDC)
939 {
940 RECT Rect;
941 HBRUSH DesktopBrush, PreviousBrush;
942 HWND hWndDesktop;
943 BOOL doPatBlt = TRUE;
944 int len;
945
946 PWINSTATION_OBJECT WinSta = PsGetWin32Thread()->Desktop->WindowStation;
947
948 IntGdiGetClipBox(hDC, &Rect);
949
950 hWndDesktop = IntGetDesktopWindow();
951 DesktopBrush = (HBRUSH)NtUserGetClassLong(hWndDesktop, GCL_HBRBACKGROUND, FALSE);
952
953 /*
954 * Paint desktop background
955 */
956
957 if(WinSta->hbmWallpaper != NULL)
958 {
959 PWINDOW_OBJECT DeskWin;
960
961 if((DeskWin = IntGetWindowObject(hWndDesktop)))
962 {
963 SIZE sz;
964 int x, y;
965 HDC hWallpaperDC;
966
967 sz.cx = DeskWin->WindowRect.right - DeskWin->WindowRect.left;
968 sz.cy = DeskWin->WindowRect.bottom - DeskWin->WindowRect.top;
969 IntReleaseWindowObject(DeskWin);
970
971 x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
972 y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
973
974 hWallpaperDC = NtGdiCreateCompatableDC(hDC);
975 if(hWallpaperDC != NULL)
976 {
977 HBITMAP hOldBitmap;
978
979 if(x > 0 || y > 0)
980 {
981 /* FIXME - clip out the bitmap */
982 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
983 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
984 NtGdiSelectObject(hDC, PreviousBrush);
985 }
986 else
987 doPatBlt = FALSE;
988
989 hOldBitmap = NtGdiSelectObject(hWallpaperDC, WinSta->hbmWallpaper);
990 NtGdiBitBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, hWallpaperDC, 0, 0, SRCCOPY);
991 NtGdiSelectObject(hWallpaperDC, hOldBitmap);
992
993 NtGdiDeleteDC(hWallpaperDC);
994 }
995 }
996 }
997
998 if (doPatBlt) {
999 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
1000 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1001 NtGdiSelectObject(hDC, PreviousBrush);
1002 }
1003
1004 /*
1005 * Display system version on the desktop background
1006 */
1007
1008 if (g_PaintDesktopVersion) {
1009 static WCHAR s_wszVersion[256] = {0};
1010 RECT rect;
1011
1012 if (*s_wszVersion)
1013 len = wcslen(s_wszVersion);
1014 else
1015 len = GetSystemVersionString(s_wszVersion);
1016
1017 if (len) {
1018 if (!NtUserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0)) {
1019 rect.right = NtUserGetSystemMetrics(SM_CXSCREEN);
1020 rect.bottom = NtUserGetSystemMetrics(SM_CYSCREEN);
1021 }
1022
1023 COLORREF color_old = NtGdiSetTextColor(hDC, RGB(255,255,255));
1024 UINT align_old = NtGdiSetTextAlign(hDC, TA_RIGHT);
1025 int mode_old = NtGdiSetBkMode(hDC, TRANSPARENT);
1026
1027 NtGdiTextOut(hDC, rect.right-16, rect.bottom-48, s_wszVersion, len);
1028
1029 NtGdiSetBkMode(hDC, mode_old);
1030 NtGdiSetTextAlign(hDC, align_old);
1031 NtGdiSetTextColor(hDC, color_old);
1032 }
1033 }
1034
1035 return TRUE;
1036 }
1037
1038
1039 /*
1040 * NtUserSwitchDesktop
1041 *
1042 * Sets the current input (interactive) desktop.
1043 *
1044 * Parameters
1045 * hDesktop
1046 * Handle to desktop.
1047 *
1048 * Return Value
1049 * Status
1050 *
1051 * Status
1052 * @unimplemented
1053 */
1054
1055 BOOL STDCALL
1056 NtUserSwitchDesktop(HDESK hDesktop)
1057 {
1058 PDESKTOP_OBJECT DesktopObject;
1059 NTSTATUS Status;
1060
1061 DPRINT("About to switch desktop (0x%X)\n", hDesktop);
1062
1063 Status = IntValidateDesktopHandle(
1064 hDesktop,
1065 UserMode,
1066 0,
1067 &DesktopObject);
1068
1069 if (!NT_SUCCESS(Status))
1070 {
1071 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1072 return FALSE;
1073 }
1074
1075 /*
1076 * Don't allow applications switch the desktop if it's locked, unless the caller
1077 * is the logon application itself
1078 */
1079 if((DesktopObject->WindowStation->Flags & WSS_LOCKED) &&
1080 LogonProcess != NULL && LogonProcess != PsGetWin32Process())
1081 {
1082 ObDereferenceObject(DesktopObject);
1083 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
1084 return FALSE;
1085 }
1086
1087 /* FIXME: Fail if the desktop belong to an invisible window station */
1088 /* FIXME: Fail if the process is associated with a secured
1089 desktop such as Winlogon or Screen-Saver */
1090 /* FIXME: Connect to input device */
1091
1092 /* Set the active desktop in the desktop's window station. */
1093 DesktopObject->WindowStation->ActiveDesktop = DesktopObject;
1094
1095 /* Set the global state. */
1096 InputDesktop = DesktopObject;
1097 InputDesktopHandle = hDesktop;
1098 InputWindowStation = DesktopObject->WindowStation;
1099
1100 ObDereferenceObject(DesktopObject);
1101
1102 return TRUE;
1103 }
1104
1105 /*
1106 * NtUserResolveDesktopForWOW
1107 *
1108 * Status
1109 * @unimplemented
1110 */
1111
1112 DWORD STDCALL
1113 NtUserResolveDesktopForWOW(DWORD Unknown0)
1114 {
1115 UNIMPLEMENTED
1116 return 0;
1117 }
1118
1119 /*
1120 * NtUserGetThreadDesktop
1121 *
1122 * Status
1123 * @implemented
1124 */
1125
1126 HDESK STDCALL
1127 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
1128 {
1129 NTSTATUS Status;
1130 PETHREAD Thread;
1131 PDESKTOP_OBJECT DesktopObject;
1132 HDESK Ret, hThreadDesktop;
1133 OBJECT_HANDLE_INFORMATION HandleInformation;
1134
1135 if(!dwThreadId)
1136 {
1137 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1138 return 0;
1139 }
1140
1141 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1142 if(!NT_SUCCESS(Status))
1143 {
1144 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1145 return 0;
1146 }
1147
1148 if(Thread->ThreadsProcess == PsGetCurrentProcess())
1149 {
1150 /* just return the handle, we queried the desktop handle of a thread running
1151 in the same context */
1152 Ret = Thread->Tcb.Win32Thread->hDesktop;
1153 ObDereferenceObject(Thread);
1154 return Ret;
1155 }
1156
1157 /* get the desktop handle and the desktop of the thread */
1158 if(!(hThreadDesktop = Thread->Tcb.Win32Thread->hDesktop) ||
1159 !(DesktopObject = Thread->Tcb.Win32Thread->Desktop))
1160 {
1161 ObDereferenceObject(Thread);
1162 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
1163 return NULL;
1164 }
1165
1166 /* we could just use DesktopObject instead of looking up the handle, but latter
1167 may be a bit safer (e.g. when the desktop is being destroyed */
1168 /* switch into the context of the thread we're trying to get the desktop from,
1169 so we can use the handle */
1170 KeAttachProcess(Thread->ThreadsProcess);
1171 Status = ObReferenceObjectByHandle(hThreadDesktop,
1172 GENERIC_ALL,
1173 ExDesktopObjectType,
1174 UserMode,
1175 (PVOID*)&DesktopObject,
1176 &HandleInformation);
1177 KeDetachProcess();
1178
1179 /* the handle couldn't be found, there's nothing to get... */
1180 if(!NT_SUCCESS(Status))
1181 {
1182 ObDereferenceObject(Thread);
1183 return NULL;
1184 }
1185
1186 /* lookup our handle table if we can find a handle to the desktop object,
1187 if not, create one */
1188 Ret = IntGetDesktopObjectHandle(DesktopObject);
1189
1190 /* all done, we got a valid handle to the desktop */
1191 ObDereferenceObject(DesktopObject);
1192 ObDereferenceObject(Thread);
1193 return Ret;
1194 }
1195
1196 /*
1197 * NtUserSetThreadDesktop
1198 *
1199 * Status
1200 * @implemented
1201 */
1202
1203 BOOL STDCALL
1204 NtUserSetThreadDesktop(HDESK hDesktop)
1205 {
1206 PW32THREAD W32Thread;
1207 PDESKTOP_OBJECT DesktopObject;
1208 NTSTATUS Status;
1209
1210 /* Validate the new desktop. */
1211 Status = IntValidateDesktopHandle(
1212 hDesktop,
1213 UserMode,
1214 0,
1215 &DesktopObject);
1216
1217 if (!NT_SUCCESS(Status))
1218 {
1219 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1220 return FALSE;
1221 }
1222
1223 W32Thread = PsGetWin32Thread();
1224
1225 /* FIXME: Should check here to see if the thread has any windows. */
1226
1227 if (W32Thread->Desktop != NULL)
1228 {
1229 ObDereferenceObject(W32Thread->Desktop);
1230 }
1231
1232 W32Thread->Desktop = DesktopObject;
1233 W32Thread->hDesktop = hDesktop;
1234
1235 return TRUE;
1236 }
1237
1238 /* EOF */