serialize gui switching and switching the focus message queue
[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: desktop.c,v 1.18 2004/08/08 17:57:34 weiden Exp $
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 /* INITALIZATION FUNCTIONS ****************************************************/
54
55 NTSTATUS FASTCALL
56 InitDesktopImpl(VOID)
57 {
58 return STATUS_SUCCESS;
59 }
60
61 NTSTATUS FASTCALL
62 CleanupDesktopImpl(VOID)
63 {
64 return STATUS_SUCCESS;
65 }
66
67 /* PRIVATE FUNCTIONS **********************************************************/
68
69 /*
70 * IntValidateDesktopHandle
71 *
72 * Validates the desktop handle.
73 *
74 * Remarks
75 * If the function succeeds, the handle remains referenced. If the
76 * fucntion fails, last error is set.
77 */
78
79 NTSTATUS FASTCALL
80 IntValidateDesktopHandle(
81 HDESK Desktop,
82 KPROCESSOR_MODE AccessMode,
83 ACCESS_MASK DesiredAccess,
84 PDESKTOP_OBJECT *Object)
85 {
86 NTSTATUS Status;
87
88 Status = ObReferenceObjectByHandle(
89 Desktop,
90 DesiredAccess,
91 ExDesktopObjectType,
92 AccessMode,
93 (PVOID*)Object,
94 NULL);
95
96 if (!NT_SUCCESS(Status))
97 SetLastNtError(Status);
98
99 return Status;
100 }
101
102 VOID FASTCALL
103 IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop, PRECT Rect)
104 {
105 PRECT Ret;
106
107 ASSERT(Desktop);
108
109 Ret = &Desktop->WorkArea;
110 if((Ret->right == -1) && ScreenDeviceContext)
111 {
112 PDC dc;
113 BITMAPOBJ *BitmapObj;
114 dc = DC_LockDc(ScreenDeviceContext);
115 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
116 if(BitmapObj)
117 {
118 Ret->right = BitmapObj->SurfObj.sizlBitmap.cx;
119 Ret->bottom = BitmapObj->SurfObj.sizlBitmap.cy;
120 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
121 }
122 DC_UnlockDc(ScreenDeviceContext);
123 }
124
125 if(Rect)
126 {
127 *Rect = *Ret;
128 }
129 }
130
131 PDESKTOP_OBJECT FASTCALL
132 IntGetActiveDesktop(VOID)
133 {
134 return InputDesktop;
135 }
136
137 /*
138 * returns or creates a handle to the desktop object
139 */
140 HDESK FASTCALL
141 IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject)
142 {
143 NTSTATUS Status;
144 HDESK Ret;
145
146 ASSERT(DesktopObject);
147
148 Status = ObFindHandleForObject(PsGetCurrentProcess(),
149 DesktopObject,
150 ExDesktopObjectType,
151 NULL,
152 (PHANDLE)&Ret);
153
154 if(!NT_SUCCESS(Status))
155 {
156 Status = ObOpenObjectByPointer(DesktopObject,
157 0,
158 NULL,
159 0,
160 ExDesktopObjectType,
161 UserMode,
162 (PHANDLE)&Ret);
163 if(!NT_SUCCESS(Status))
164 {
165 /* unable to create a handle */
166 DPRINT1("Unable to create a desktop handle\n");
167 return NULL;
168 }
169 }
170
171 return Ret;
172 }
173
174 PUSER_MESSAGE_QUEUE FASTCALL
175 IntGetFocusMessageQueue(VOID)
176 {
177 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
178 if (!pdo)
179 {
180 DPRINT("No active desktop\n");
181 return(NULL);
182 }
183 return (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
184 }
185
186 VOID FASTCALL
187 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue)
188 {
189 PUSER_MESSAGE_QUEUE Old;
190 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
191 if (!pdo)
192 {
193 DPRINT("No active desktop\n");
194 return;
195 }
196 if(NewQueue != NULL)
197 {
198 if(NewQueue->Desktop != NULL)
199 {
200 DPRINT("Message Queue already attached to another desktop!\n");
201 return;
202 }
203 IntReferenceMessageQueue(NewQueue);
204 InterlockedExchange((LONG*)&NewQueue->Desktop, (LONG)pdo);
205 }
206 Old = (PUSER_MESSAGE_QUEUE)InterlockedExchange((LONG*)&pdo->ActiveMessageQueue, (LONG)NewQueue);
207 if(Old != NULL)
208 {
209 InterlockedExchange((LONG*)&Old->Desktop, 0);
210 IntDereferenceMessageQueue(Old);
211 }
212 }
213
214 HWND FASTCALL IntGetDesktopWindow(VOID)
215 {
216 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
217 if (!pdo)
218 {
219 DPRINT("No active desktop\n");
220 return NULL;
221 }
222 return pdo->DesktopWindow;
223 }
224
225 HWND FASTCALL IntGetCurrentThreadDesktopWindow(VOID)
226 {
227 PDESKTOP_OBJECT pdo = PsGetWin32Thread()->Desktop;
228 if (NULL == pdo)
229 {
230 DPRINT1("Thread doesn't have a desktop\n");
231 return NULL;
232 }
233 return pdo->DesktopWindow;
234 }
235
236 /* PUBLIC FUNCTIONS ***********************************************************/
237
238 NTSTATUS FASTCALL
239 IntShowDesktop(PDESKTOP_OBJECT Desktop, ULONG Width, ULONG Height)
240 {
241 CSRSS_API_REQUEST Request;
242 CSRSS_API_REPLY Reply;
243
244 Request.Type = CSRSS_SHOW_DESKTOP;
245 Request.Data.ShowDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
246 Request.Data.ShowDesktopRequest.Width = Width;
247 Request.Data.ShowDesktopRequest.Height = Height;
248
249 return CsrNotify(&Request, &Reply);
250 }
251
252 NTSTATUS FASTCALL
253 IntHideDesktop(PDESKTOP_OBJECT Desktop)
254 {
255 #if 0
256 CSRSS_API_REQUEST Request;
257 CSRSS_API_REPLY Reply;
258
259 Request.Type = CSRSS_HIDE_DESKTOP;
260 Request.Data.HideDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
261
262 return NotifyCsrss(&Request, &Reply);
263 #else
264 PWINDOW_OBJECT DesktopWindow;
265
266 DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
267 if (! DesktopWindow)
268 {
269 return ERROR_INVALID_WINDOW_HANDLE;
270 }
271 DesktopWindow->Style &= ~WS_VISIBLE;
272
273 return STATUS_SUCCESS;
274 #endif
275 }
276
277 /*
278 * NtUserCreateDesktop
279 *
280 * Creates a new desktop.
281 *
282 * Parameters
283 * lpszDesktopName
284 * Name of the new desktop.
285 *
286 * dwFlags
287 * Interaction flags.
288 *
289 * dwDesiredAccess
290 * Requested type of access.
291 *
292 * lpSecurity
293 * Security descriptor.
294 *
295 * hWindowStation
296 * Handle to window station on which to create the desktop.
297 *
298 * Return Value
299 * If the function succeeds, the return value is a handle to the newly
300 * created desktop. If the specified desktop already exists, the function
301 * succeeds and returns a handle to the existing desktop. When you are
302 * finished using the handle, call the CloseDesktop function to close it.
303 * If the function fails, the return value is NULL.
304 *
305 * Status
306 * @implemented
307 */
308
309 HDESK STDCALL
310 NtUserCreateDesktop(
311 PUNICODE_STRING lpszDesktopName,
312 DWORD dwFlags,
313 ACCESS_MASK dwDesiredAccess,
314 LPSECURITY_ATTRIBUTES lpSecurity,
315 HWINSTA hWindowStation)
316 {
317 OBJECT_ATTRIBUTES ObjectAttributes;
318 PWINSTATION_OBJECT WinStaObject;
319 PDESKTOP_OBJECT DesktopObject;
320 UNICODE_STRING DesktopName;
321 NTSTATUS Status;
322 HDESK Desktop;
323 CSRSS_API_REQUEST Request;
324 CSRSS_API_REPLY Reply;
325
326 Status = IntValidateWindowStationHandle(
327 hWindowStation,
328 KernelMode,
329 0,
330 &WinStaObject);
331
332 if (! NT_SUCCESS(Status))
333 {
334 DPRINT1("Failed validation of window station handle (0x%X)\n",
335 hWindowStation);
336 SetLastNtError(Status);
337 return NULL;
338 }
339
340 if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
341 lpszDesktopName))
342 {
343 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
344 ObDereferenceObject(WinStaObject);
345 return NULL;
346 }
347
348 ObDereferenceObject(WinStaObject);
349
350 /*
351 * Try to open already existing desktop
352 */
353
354 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
355
356 /* Initialize ObjectAttributes for the desktop object */
357 InitializeObjectAttributes(
358 &ObjectAttributes,
359 &DesktopName,
360 0,
361 NULL,
362 NULL);
363
364 Status = ObOpenObjectByName(
365 &ObjectAttributes,
366 ExDesktopObjectType,
367 NULL,
368 UserMode,
369 dwDesiredAccess,
370 NULL,
371 (HANDLE*)&Desktop);
372
373 if (NT_SUCCESS(Status))
374 {
375 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
376 ExFreePool(DesktopName.Buffer);
377 return Desktop;
378 }
379
380 /*
381 * No existing desktop found, try to create new one
382 */
383
384 Status = ObCreateObject(
385 ExGetPreviousMode(),
386 ExDesktopObjectType,
387 &ObjectAttributes,
388 ExGetPreviousMode(),
389 NULL,
390 sizeof(DESKTOP_OBJECT),
391 0,
392 0,
393 (PVOID*)&DesktopObject);
394
395 if (! NT_SUCCESS(Status))
396 {
397 DPRINT1("Failed creating desktop (%wZ)\n", &DesktopName);
398 ExFreePool(DesktopName.Buffer);
399 SetLastNtError(STATUS_UNSUCCESSFUL);
400 return NULL;
401 }
402
403 // init desktop area
404 DesktopObject->WorkArea.left = 0;
405 DesktopObject->WorkArea.top = 0;
406 DesktopObject->WorkArea.right = -1;
407 DesktopObject->WorkArea.bottom = -1;
408 IntGetDesktopWorkArea(DesktopObject, NULL);
409
410 /* Initialize some local (to win32k) desktop state. */
411 DesktopObject->ActiveMessageQueue = NULL;
412
413 Status = ObInsertObject(
414 (PVOID)DesktopObject,
415 NULL,
416 STANDARD_RIGHTS_REQUIRED,
417 0,
418 NULL,
419 (HANDLE*)&Desktop);
420
421 ObDereferenceObject(DesktopObject);
422 ExFreePool(DesktopName.Buffer);
423
424 if (! NT_SUCCESS(Status))
425 {
426 DPRINT1("Failed to create desktop handle\n");
427 SetLastNtError(Status);
428 return NULL;
429 }
430
431 Request.Type = CSRSS_CREATE_DESKTOP;
432 memcpy(Request.Data.CreateDesktopRequest.DesktopName, lpszDesktopName->Buffer,
433 lpszDesktopName->Length);
434 Request.Data.CreateDesktopRequest.DesktopName[lpszDesktopName->Length / sizeof(WCHAR)] = L'\0';
435
436 Status = CsrNotify(&Request, &Reply);
437 if (! NT_SUCCESS(Status))
438 {
439 DPRINT1("Failed to notify CSRSS about new desktop\n");
440 ZwClose(Desktop);
441 SetLastNtError(Status);
442 return NULL;
443 }
444
445 return Desktop;
446 }
447
448 /*
449 * NtUserOpenDesktop
450 *
451 * Opens an existing desktop.
452 *
453 * Parameters
454 * lpszDesktopName
455 * Name of the existing desktop.
456 *
457 * dwFlags
458 * Interaction flags.
459 *
460 * dwDesiredAccess
461 * Requested type of access.
462 *
463 * Return Value
464 * Handle to the desktop or zero on failure.
465 *
466 * Status
467 * @implemented
468 */
469
470 HDESK STDCALL
471 NtUserOpenDesktop(
472 PUNICODE_STRING lpszDesktopName,
473 DWORD dwFlags,
474 ACCESS_MASK dwDesiredAccess)
475 {
476 OBJECT_ATTRIBUTES ObjectAttributes;
477 PWINSTATION_OBJECT WinStaObject;
478 UNICODE_STRING DesktopName;
479 NTSTATUS Status;
480 HDESK Desktop;
481
482 /*
483 * Validate the window station handle and compose the fully
484 * qualified desktop name
485 */
486
487 Status = IntValidateWindowStationHandle(
488 PROCESS_WINDOW_STATION(),
489 KernelMode,
490 0,
491 &WinStaObject);
492
493 if (!NT_SUCCESS(Status))
494 {
495 DPRINT("Failed validation of window station handle (0x%X)\n",
496 PROCESS_WINDOW_STATION());
497 SetLastNtError(Status);
498 return 0;
499 }
500
501 if (!IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
502 lpszDesktopName))
503 {
504 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
505 ObDereferenceObject(WinStaObject);
506 return 0;
507 }
508
509 ObDereferenceObject(WinStaObject);
510
511 DPRINT("Trying to open desktop station (%wZ)\n", &DesktopName);
512
513 /* Initialize ObjectAttributes for the desktop object */
514 InitializeObjectAttributes(
515 &ObjectAttributes,
516 &DesktopName,
517 0,
518 NULL,
519 NULL);
520
521 Status = ObOpenObjectByName(
522 &ObjectAttributes,
523 ExDesktopObjectType,
524 NULL,
525 UserMode,
526 dwDesiredAccess,
527 NULL,
528 (HANDLE*)&Desktop);
529
530 if (!NT_SUCCESS(Status))
531 {
532 SetLastNtError(Status);
533 ExFreePool(DesktopName.Buffer);
534 return 0;
535 }
536
537 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
538 ExFreePool(DesktopName.Buffer);
539
540 return Desktop;
541 }
542
543 /*
544 * NtUserOpenInputDesktop
545 *
546 * Opens the input (interactive) desktop.
547 *
548 * Parameters
549 * dwFlags
550 * Interaction flags.
551 *
552 * fInherit
553 * Inheritance option.
554 *
555 * dwDesiredAccess
556 * Requested type of access.
557 *
558 * Return Value
559 * Handle to the input desktop or zero on failure.
560 *
561 * Status
562 * @implemented
563 */
564
565 HDESK STDCALL
566 NtUserOpenInputDesktop(
567 DWORD dwFlags,
568 BOOL fInherit,
569 ACCESS_MASK dwDesiredAccess)
570 {
571 PDESKTOP_OBJECT Object;
572 NTSTATUS Status;
573 HDESK Desktop;
574
575 DPRINT("About to open input desktop\n");
576
577 /* Get a pointer to the desktop object */
578
579 Status = IntValidateDesktopHandle(
580 InputDesktopHandle,
581 UserMode,
582 0,
583 &Object);
584
585 if (!NT_SUCCESS(Status))
586 {
587 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
588 return (HDESK)0;
589 }
590
591 /* Create a new handle to the object */
592
593 Status = ObOpenObjectByPointer(
594 Object,
595 0,
596 NULL,
597 dwDesiredAccess,
598 ExDesktopObjectType,
599 UserMode,
600 (HANDLE*)&Desktop);
601
602 ObDereferenceObject(Object);
603
604 if (NT_SUCCESS(Status))
605 {
606 DPRINT("Successfully opened input desktop\n");
607 return (HDESK)Desktop;
608 }
609
610 SetLastNtError(Status);
611 return (HDESK)0;
612 }
613
614 /*
615 * NtUserCloseDesktop
616 *
617 * Closes a desktop handle.
618 *
619 * Parameters
620 * hDesktop
621 * Handle to the desktop.
622 *
623 * Return Value
624 * Status
625 *
626 * Remarks
627 * The desktop handle can be created with NtUserCreateDesktop or
628 * NtUserOpenDesktop. This function will fail if any thread in the calling
629 * process is using the specified desktop handle or if the handle refers
630 * to the initial desktop of the calling process.
631 *
632 * Status
633 * @implemented
634 */
635
636 BOOL STDCALL
637 NtUserCloseDesktop(HDESK hDesktop)
638 {
639 PDESKTOP_OBJECT Object;
640 NTSTATUS Status;
641
642 DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
643
644 Status = IntValidateDesktopHandle(
645 hDesktop,
646 UserMode,
647 0,
648 &Object);
649
650 if (!NT_SUCCESS(Status))
651 {
652 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
653 return FALSE;
654 }
655
656 ObDereferenceObject(Object);
657
658 DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
659
660 Status = ZwClose(hDesktop);
661 if (!NT_SUCCESS(Status))
662 {
663 SetLastNtError(Status);
664 return FALSE;
665 }
666
667 return TRUE;
668 }
669
670 /*
671 * NtUserPaintDesktop
672 *
673 * The NtUserPaintDesktop function fills the clipping region in the
674 * specified device context with the desktop pattern or wallpaper. The
675 * function is provided primarily for shell desktops.
676 *
677 * Parameters
678 * hdc
679 * Handle to the device context.
680 *
681 * Status
682 * @implemented
683 */
684
685 BOOL STDCALL
686 NtUserPaintDesktop(HDC hDC)
687 {
688 RECT Rect;
689 HBRUSH DesktopBrush, PreviousBrush;
690 HWND hWndDesktop;
691
692 IntGdiGetClipBox(hDC, &Rect);
693
694 hWndDesktop = IntGetDesktopWindow();
695 DesktopBrush = (HBRUSH)NtUserGetClassLong(hWndDesktop, GCL_HBRBACKGROUND, FALSE);
696
697 /*
698 * Paint desktop background
699 */
700
701 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
702 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
703 NtGdiSelectObject(hDC, PreviousBrush);
704
705 return TRUE;
706 }
707
708 /*
709 * NtUserSwitchDesktop
710 *
711 * Sets the current input (interactive) desktop.
712 *
713 * Parameters
714 * hDesktop
715 * Handle to desktop.
716 *
717 * Return Value
718 * Status
719 *
720 * Status
721 * @unimplemented
722 */
723
724 BOOL STDCALL
725 NtUserSwitchDesktop(HDESK hDesktop)
726 {
727 PDESKTOP_OBJECT DesktopObject;
728 NTSTATUS Status;
729
730 DPRINT("About to switch desktop (0x%X)\n", hDesktop);
731
732 Status = IntValidateDesktopHandle(
733 hDesktop,
734 UserMode,
735 0,
736 &DesktopObject);
737
738 if (!NT_SUCCESS(Status))
739 {
740 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
741 return FALSE;
742 }
743
744 /*
745 * Don't allow applications switch the desktop if it's locked, unless the caller
746 * is the logon application itself
747 */
748 if((DesktopObject->WindowStation->Flags & WSS_LOCKED) &&
749 LogonProcess != NULL && LogonProcess != PsGetWin32Process())
750 {
751 ObDereferenceObject(DesktopObject);
752 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
753 return FALSE;
754 }
755
756 /* FIXME: Fail if the desktop belong to an invisible window station */
757 /* FIXME: Fail if the process is associated with a secured
758 desktop such as Winlogon or Screen-Saver */
759 /* FIXME: Connect to input device */
760
761 /* Set the active desktop in the desktop's window station. */
762 DesktopObject->WindowStation->ActiveDesktop = DesktopObject;
763
764 /* Set the global state. */
765 InputDesktop = DesktopObject;
766 InputDesktopHandle = hDesktop;
767 InputWindowStation = DesktopObject->WindowStation;
768
769 ObDereferenceObject(DesktopObject);
770
771 return TRUE;
772 }
773
774 /*
775 * NtUserResolveDesktopForWOW
776 *
777 * Status
778 * @unimplemented
779 */
780
781 DWORD STDCALL
782 NtUserResolveDesktopForWOW(DWORD Unknown0)
783 {
784 UNIMPLEMENTED
785 return 0;
786 }
787
788 /*
789 * NtUserGetThreadDesktop
790 *
791 * Status
792 * @implemented
793 */
794
795 HDESK STDCALL
796 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
797 {
798 NTSTATUS Status;
799 PETHREAD Thread;
800 PDESKTOP_OBJECT DesktopObject;
801 HDESK Ret, hThreadDesktop;
802 OBJECT_HANDLE_INFORMATION HandleInformation;
803
804 if(!dwThreadId)
805 {
806 SetLastWin32Error(ERROR_INVALID_PARAMETER);
807 return 0;
808 }
809
810 Status = PsLookupThreadByThreadId((PVOID)dwThreadId, &Thread);
811 if(!NT_SUCCESS(Status))
812 {
813 SetLastWin32Error(ERROR_INVALID_PARAMETER);
814 return 0;
815 }
816
817 if(Thread->ThreadsProcess == PsGetCurrentProcess())
818 {
819 /* just return the handle, we queried the desktop handle of a thread running
820 in the same context */
821 Ret = Thread->Win32Thread->hDesktop;
822 ObDereferenceObject(Thread);
823 return Ret;
824 }
825
826 /* get the desktop handle and the desktop of the thread */
827 if(!(hThreadDesktop = Thread->Win32Thread->hDesktop) ||
828 !(DesktopObject = Thread->Win32Thread->Desktop))
829 {
830 ObDereferenceObject(Thread);
831 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
832 return NULL;
833 }
834
835 /* we could just use DesktopObject instead of looking up the handle, but latter
836 may be a bit safer (e.g. when the desktop is being destroyed */
837 /* switch into the context of the thread we're trying to get the desktop from,
838 so we can use the handle */
839 KeAttachProcess(Thread->ThreadsProcess);
840 Status = ObReferenceObjectByHandle(hThreadDesktop,
841 GENERIC_ALL,
842 ExDesktopObjectType,
843 UserMode,
844 (PVOID*)&DesktopObject,
845 &HandleInformation);
846 KeDetachProcess();
847
848 /* the handle couldn't be found, there's nothing to get... */
849 if(!NT_SUCCESS(Status))
850 {
851 ObDereferenceObject(Thread);
852 return NULL;
853 }
854
855 /* lookup our handle table if we can find a handle to the desktop object,
856 if not, create one */
857 Ret = IntGetDesktopObjectHandle(DesktopObject);
858
859 /* all done, we got a valid handle to the desktop */
860 ObDereferenceObject(DesktopObject);
861 ObDereferenceObject(Thread);
862 return Ret;
863 }
864
865 /*
866 * NtUserSetThreadDesktop
867 *
868 * Status
869 * @implemented
870 */
871
872 BOOL STDCALL
873 NtUserSetThreadDesktop(HDESK hDesktop)
874 {
875 PW32THREAD W32Thread;
876 PDESKTOP_OBJECT DesktopObject;
877 NTSTATUS Status;
878
879 /* Validate the new desktop. */
880 Status = IntValidateDesktopHandle(
881 hDesktop,
882 UserMode,
883 0,
884 &DesktopObject);
885
886 if (!NT_SUCCESS(Status))
887 {
888 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
889 return FALSE;
890 }
891
892 W32Thread = PsGetWin32Thread();
893 /* Check for setting the same desktop as before. */
894 if (DesktopObject == W32Thread->Desktop)
895 {
896 W32Thread->hDesktop = hDesktop;
897 ObDereferenceObject(DesktopObject);
898 return TRUE;
899 }
900
901 /* FIXME: Should check here to see if the thread has any windows. */
902
903 if (W32Thread->Desktop != NULL)
904 {
905 ObDereferenceObject(W32Thread->Desktop);
906 }
907
908 W32Thread->Desktop = DesktopObject;
909 W32Thread->hDesktop = hDesktop;
910
911 return TRUE;
912 }
913
914 /* EOF */