Revert, thx Thomas, wasnt sure.
[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
32 #include <w32k.h>
33
34 #define NDEBUG
35 #include <debug.h>
36
37 /* GLOBALS *******************************************************************/
38
39 /* Currently active desktop */
40 PDESKTOP_OBJECT InputDesktop = NULL;
41 HDESK InputDesktopHandle = NULL;
42 HDC ScreenDeviceContext = NULL;
43
44 BOOL g_PaintDesktopVersion = FALSE;
45
46 /* INITALIZATION FUNCTIONS ****************************************************/
47
48 static GENERIC_MAPPING IntDesktopMapping =
49 {
50 STANDARD_RIGHTS_READ | DESKTOP_ENUMERATE | DESKTOP_READOBJECTS,
51 STANDARD_RIGHTS_WRITE | DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_HOOKCONTROL |
52 DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD | DESKTOP_WRITEOBJECTS,
53 STANDARD_RIGHTS_EXECUTE | DESKTOP_SWITCHDESKTOP,
54 STANDARD_RIGHTS_REQUIRED | DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_ENUMERATE |
55 DESKTOP_HOOKCONTROL | DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD |
56 DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_WRITEOBJECTS
57 };
58
59 NTSTATUS FASTCALL
60 InitDesktopImpl(VOID)
61 {
62 /* Set Desktop Object Attributes */
63 ExDesktopObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(DESKTOP_OBJECT);
64 ExDesktopObjectType->TypeInfo.GenericMapping = IntDesktopMapping;
65
66 return STATUS_SUCCESS;
67 }
68
69 NTSTATUS FASTCALL
70 CleanupDesktopImpl(VOID)
71 {
72 return STATUS_SUCCESS;
73 }
74
75 /* OBJECT CALLBACKS **********************************************************/
76
77 NTSTATUS STDCALL
78 IntDesktopObjectCreate(PVOID ObjectBody,
79 PVOID Parent,
80 PWSTR RemainingPath,
81 struct _OBJECT_ATTRIBUTES* ObjectAttributes)
82 {
83 PDESKTOP_OBJECT Desktop = (PDESKTOP_OBJECT)ObjectBody;
84 UNICODE_STRING UnicodeString;
85
86 DPRINT("Creating desktop (0x%X) Name (%S)\n", Desktop, RemainingPath);
87 if (RemainingPath == NULL)
88 {
89 return STATUS_SUCCESS;
90 }
91
92 if (wcschr((RemainingPath + 1), '\\') != NULL)
93 {
94 return STATUS_UNSUCCESSFUL;
95 }
96
97 RtlInitUnicodeString(&UnicodeString, (RemainingPath + 1));
98
99 InitializeListHead(&Desktop->ShellHookWindows);
100
101 Desktop->WindowStation = (PWINSTATION_OBJECT)Parent;
102
103 /* Put the desktop on the window station's list of associcated desktops */
104 // ExInterlocked
105 InsertTailList(
106 &Desktop->WindowStation->DesktopListHead,
107 &Desktop->ListEntry);//,
108 // &Desktop->WindowStation->Lock);
109
110 return RtlCreateUnicodeString(&Desktop->Name, UnicodeString.Buffer);
111 }
112
113 VOID STDCALL
114 IntDesktopObjectDelete(PVOID DeletedObject)
115 {
116 PDESKTOP_OBJECT Desktop = (PDESKTOP_OBJECT)DeletedObject;
117
118 DPRINT("Deleting desktop (0x%X)\n", Desktop);
119
120 /* Remove the desktop from the window station's list of associcated desktops */
121 RemoveEntryList(&Desktop->ListEntry);
122
123 RtlFreeUnicodeString(&Desktop->Name);
124 }
125
126 /* PRIVATE FUNCTIONS **********************************************************/
127
128 static int GetSystemVersionString(LPWSTR buffer)
129 {
130 RTL_OSVERSIONINFOEXW versionInfo;
131 int len;
132
133 versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
134
135 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
136 return 0;
137
138 if (versionInfo.dwMajorVersion <= 4)
139 len = swprintf(buffer,
140 L"ReactOS Version %d.%d %s Build %d",
141 versionInfo.dwMajorVersion, versionInfo.dwMinorVersion,
142 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
143 else
144 len = swprintf(buffer,
145 L"ReactOS %s (Build %d)",
146 versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
147
148 return len;
149 }
150
151
152 NTSTATUS FASTCALL
153 IntParseDesktopPath(PEPROCESS Process,
154 PUNICODE_STRING DesktopPath,
155 HWINSTA *hWinSta,
156 HDESK *hDesktop)
157 {
158 OBJECT_ATTRIBUTES ObjectAttributes;
159 UNICODE_STRING WinSta, Desktop, FullName;
160 BOOL DesktopPresent = FALSE;
161 BOOL WinStaPresent = FALSE;
162 NTSTATUS Status;
163
164 ASSERT(hWinSta);
165
166 *hWinSta = NULL;
167
168 if(hDesktop != NULL)
169 {
170 *hDesktop = NULL;
171 }
172
173 RtlInitUnicodeString(&WinSta, NULL);
174 RtlInitUnicodeString(&Desktop, NULL);
175
176 if(DesktopPath != NULL && DesktopPath->Buffer != NULL && DesktopPath->Length > sizeof(WCHAR))
177 {
178 PWCHAR c = DesktopPath->Buffer;
179 USHORT wl = 0;
180 USHORT l = DesktopPath->Length;
181
182 /*
183 * Parse the desktop path string which can be in the form "WinSta\Desktop"
184 * or just "Desktop". In latter case WinSta0 will be used.
185 */
186
187 while(l > 0)
188 {
189 if(*c == L'\\')
190 {
191 wl = (ULONG_PTR)c - (ULONG_PTR)DesktopPath->Buffer;
192 break;
193 }
194 l -= sizeof(WCHAR);
195 c++;
196 }
197
198 if(wl > 0)
199 {
200 WinSta.Length = wl;
201 WinSta.MaximumLength = wl + sizeof(WCHAR);
202 WinSta.Buffer = DesktopPath->Buffer;
203
204 WinStaPresent = TRUE;
205 c++;
206 }
207
208 Desktop.Length = DesktopPath->Length - wl;
209 if(wl > 0)
210 {
211 Desktop.Length -= sizeof(WCHAR);
212 }
213 if(Desktop.Length > 0)
214 {
215 Desktop.MaximumLength = Desktop.Length + sizeof(WCHAR);
216 Desktop.Buffer = ((wl > 0) ? c : DesktopPath->Buffer);
217 DesktopPresent = TRUE;
218 }
219 }
220
221 if(!WinStaPresent)
222 {
223 /* search the process handle table for (inherited) window station
224 handles, use a more appropriate one than WinSta0 if possible. */
225 Status = ObFindHandleForObject(Process,
226 NULL,
227 ExWindowStationObjectType,
228 NULL,
229 (PHANDLE)hWinSta);
230 if(!NT_SUCCESS(Status))
231 {
232 /* we had no luck searching for opened handles, use WinSta0 now */
233 RtlInitUnicodeString(&WinSta, L"WinSta0");
234 }
235 }
236
237 if(!DesktopPresent && hDesktop != NULL)
238 {
239 /* search the process handle table for (inherited) desktop
240 handles, use a more appropriate one than Default if possible. */
241 Status = ObFindHandleForObject(Process,
242 NULL,
243 ExDesktopObjectType,
244 NULL,
245 (PHANDLE)hDesktop);
246 if(!NT_SUCCESS(Status))
247 {
248 /* we had no luck searching for opened handles, use Desktop now */
249 RtlInitUnicodeString(&Desktop, L"Default");
250 }
251 }
252
253 if(*hWinSta == NULL)
254 {
255 if(!IntGetFullWindowStationName(&FullName, &WinSta, NULL))
256 {
257 return STATUS_INSUFFICIENT_RESOURCES;
258 }
259
260 /* open the window station */
261 InitializeObjectAttributes(&ObjectAttributes,
262 &FullName,
263 OBJ_CASE_INSENSITIVE,
264 NULL,
265 NULL);
266
267 Status = ObOpenObjectByName(&ObjectAttributes,
268 ExWindowStationObjectType,
269 NULL,
270 KernelMode,
271 0,
272 NULL,
273 (HANDLE*)hWinSta);
274
275 RtlFreeUnicodeString(&FullName);
276
277 if(!NT_SUCCESS(Status))
278 {
279 SetLastNtError(Status);
280 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta, PsGetCurrentProcessId());
281 return Status;
282 }
283 }
284
285 if(hDesktop != NULL && *hDesktop == NULL)
286 {
287 if(!IntGetFullWindowStationName(&FullName, &WinSta, &Desktop))
288 {
289 NtClose(*hWinSta);
290 *hWinSta = NULL;
291 return STATUS_INSUFFICIENT_RESOURCES;
292 }
293
294 /* open the desktop object */
295 InitializeObjectAttributes(&ObjectAttributes,
296 &FullName,
297 OBJ_CASE_INSENSITIVE,
298 NULL,
299 NULL);
300
301 Status = ObOpenObjectByName(&ObjectAttributes,
302 ExDesktopObjectType,
303 NULL,
304 KernelMode,
305 0,
306 NULL,
307 (HANDLE*)hDesktop);
308
309 RtlFreeUnicodeString(&FullName);
310
311 if(!NT_SUCCESS(Status))
312 {
313 *hDesktop = NULL;
314 NtClose(*hWinSta);
315 *hWinSta = NULL;
316 SetLastNtError(Status);
317 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop, PsGetCurrentProcessId());
318 return Status;
319 }
320 }
321
322 return STATUS_SUCCESS;
323 }
324
325 /*
326 * IntValidateDesktopHandle
327 *
328 * Validates the desktop handle.
329 *
330 * Remarks
331 * If the function succeeds, the handle remains referenced. If the
332 * fucntion fails, last error is set.
333 */
334
335 NTSTATUS FASTCALL
336 IntValidateDesktopHandle(
337 HDESK Desktop,
338 KPROCESSOR_MODE AccessMode,
339 ACCESS_MASK DesiredAccess,
340 PDESKTOP_OBJECT *Object)
341 {
342 NTSTATUS Status;
343
344 Status = ObReferenceObjectByHandle(
345 Desktop,
346 DesiredAccess,
347 ExDesktopObjectType,
348 AccessMode,
349 (PVOID*)Object,
350 NULL);
351
352 if (!NT_SUCCESS(Status))
353 SetLastNtError(Status);
354
355 return Status;
356 }
357
358 VOID FASTCALL
359 IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop, PRECT Rect)
360 {
361 PRECT Ret;
362
363 ASSERT(Desktop);
364
365 Ret = &Desktop->WorkArea;
366 if((Ret->right == -1) && ScreenDeviceContext)
367 {
368 PDC dc;
369 BITMAPOBJ *BitmapObj;
370 dc = DC_LockDc(ScreenDeviceContext);
371 /* FIXME - Handle dc == NULL!!!! */
372 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
373 if(BitmapObj)
374 {
375 Ret->right = BitmapObj->SurfObj.sizlBitmap.cx;
376 Ret->bottom = BitmapObj->SurfObj.sizlBitmap.cy;
377 BITMAPOBJ_UnlockBitmap(BitmapObj);
378 }
379 DC_UnlockDc(dc);
380 }
381
382 if(Rect)
383 {
384 *Rect = *Ret;
385 }
386 }
387
388 PDESKTOP_OBJECT FASTCALL
389 IntGetActiveDesktop(VOID)
390 {
391 return InputDesktop;
392 }
393
394 /*
395 * returns or creates a handle to the desktop object
396 */
397 HDESK FASTCALL
398 IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject)
399 {
400 NTSTATUS Status;
401 HDESK Ret;
402
403 ASSERT(DesktopObject);
404
405 Status = ObFindHandleForObject(PsGetCurrentProcess(),
406 DesktopObject,
407 ExDesktopObjectType,
408 NULL,
409 (PHANDLE)&Ret);
410
411 if(!NT_SUCCESS(Status))
412 {
413 Status = ObOpenObjectByPointer(DesktopObject,
414 0,
415 NULL,
416 0,
417 ExDesktopObjectType,
418 UserMode,
419 (PHANDLE)&Ret);
420 if(!NT_SUCCESS(Status))
421 {
422 /* unable to create a handle */
423 DPRINT1("Unable to create a desktop handle\n");
424 return NULL;
425 }
426 }
427
428 return Ret;
429 }
430
431 PUSER_MESSAGE_QUEUE FASTCALL
432 IntGetFocusMessageQueue(VOID)
433 {
434 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
435 if (!pdo)
436 {
437 DPRINT("No active desktop\n");
438 return(NULL);
439 }
440 return (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
441 }
442
443 VOID FASTCALL
444 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue)
445 {
446 PUSER_MESSAGE_QUEUE Old;
447 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
448 if (!pdo)
449 {
450 DPRINT("No active desktop\n");
451 return;
452 }
453 if(NewQueue != NULL)
454 {
455 if(NewQueue->Desktop != NULL)
456 {
457 DPRINT("Message Queue already attached to another desktop!\n");
458 return;
459 }
460 IntReferenceMessageQueue(NewQueue);
461 InterlockedExchange((LONG*)&NewQueue->Desktop, (LONG)pdo);
462 }
463 Old = (PUSER_MESSAGE_QUEUE)InterlockedExchange((LONG*)&pdo->ActiveMessageQueue, (LONG)NewQueue);
464 if(Old != NULL)
465 {
466 InterlockedExchange((LONG*)&Old->Desktop, 0);
467 IntDereferenceMessageQueue(Old);
468 }
469 }
470
471 HWND FASTCALL IntGetDesktopWindow(VOID)
472 {
473 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
474 if (!pdo)
475 {
476 DPRINT("No active desktop\n");
477 return NULL;
478 }
479 return pdo->DesktopWindow;
480 }
481
482 PWINDOW_OBJECT FASTCALL UserGetDesktopWindow(VOID)
483 {
484 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
485
486 if (!pdo)
487 {
488 DPRINT("No active desktop\n");
489 return NULL;
490 }
491
492 return UserGetWindowObject(pdo->DesktopWindow);
493 }
494
495
496 HWND FASTCALL IntGetCurrentThreadDesktopWindow(VOID)
497 {
498 PDESKTOP_OBJECT pdo = PsGetWin32Thread()->Desktop;
499 if (NULL == pdo)
500 {
501 DPRINT1("Thread doesn't have a desktop\n");
502 return NULL;
503 }
504 return pdo->DesktopWindow;
505 }
506
507 BOOL FASTCALL IntDesktopUpdatePerUserSettings(BOOL bEnable)
508 {
509 if (bEnable)
510 {
511 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
512 NTSTATUS Status;
513
514 RtlZeroMemory(QueryTable, sizeof(QueryTable));
515
516 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
517 QueryTable[0].Name = L"PaintDesktopVersion";
518 QueryTable[0].EntryContext = &g_PaintDesktopVersion;
519
520 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
521 Status = RtlQueryRegistryValues(RTL_REGISTRY_USER,
522 L"Control Panel\\Desktop",
523 QueryTable, NULL, NULL);
524 if (!NT_SUCCESS(Status))
525 {
526 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
527 Status);
528 g_PaintDesktopVersion = FALSE;
529 return FALSE;
530 }
531
532 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion);
533
534 return TRUE;
535 }
536 else
537 {
538 g_PaintDesktopVersion = FALSE;
539 return TRUE;
540 }
541 }
542
543 /* PUBLIC FUNCTIONS ***********************************************************/
544
545 NTSTATUS FASTCALL
546 co_IntShowDesktop(PDESKTOP_OBJECT Desktop, ULONG Width, ULONG Height)
547 {
548 CSR_API_MESSAGE Request;
549
550 Request.Type = MAKE_CSR_API(SHOW_DESKTOP, CSR_GUI);
551 Request.Data.ShowDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
552 Request.Data.ShowDesktopRequest.Width = Width;
553 Request.Data.ShowDesktopRequest.Height = Height;
554
555 return co_CsrNotify(&Request);
556 }
557
558 NTSTATUS FASTCALL
559 IntHideDesktop(PDESKTOP_OBJECT Desktop)
560 {
561 #if 0
562 CSRSS_API_REQUEST Request;
563 CSRSS_API_REPLY Reply;
564
565 Request.Type = CSRSS_HIDE_DESKTOP;
566 Request.Data.HideDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
567
568 return NotifyCsrss(&Request, &Reply);
569 #else
570
571 PWINDOW_OBJECT DesktopWindow;
572
573 DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
574 if (! DesktopWindow)
575 {
576 return ERROR_INVALID_WINDOW_HANDLE;
577 }
578 DesktopWindow->Style &= ~WS_VISIBLE;
579
580 return STATUS_SUCCESS;
581 #endif
582 }
583
584
585
586
587 static
588 HWND* FASTCALL
589 UserBuildShellHookHwndList(PDESKTOP_OBJECT Desktop)
590 {
591 ULONG entries=0;
592 PSHELL_HOOK_WINDOW Current;
593 HWND* list;
594
595 /* fixme: if we save nb elements in desktop, we dont have to loop to find nb entries */
596 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
597 entries++;
598
599 if (!entries) return NULL;
600
601 list = ExAllocatePool(PagedPool, sizeof(HWND) * (entries + 1)); /* alloc one extra for nullterm */
602 if (list)
603 {
604 HWND* cursor = list;
605
606 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
607 *cursor++ = Current->hWnd;
608
609 *cursor = NULL; /* nullterm list */
610 }
611
612 return list;
613 }
614
615 /*
616 * Send the Message to the windows registered for ShellHook
617 * notifications. The lParam contents depend on the Message. See
618 * MSDN for more details (RegisterShellHookWindow)
619 */
620 VOID co_IntShellHookNotify(WPARAM Message, LPARAM lParam)
621 {
622 PDESKTOP_OBJECT Desktop = IntGetActiveDesktop();
623 HWND* HwndList;
624
625 static UINT MsgType = 0;
626
627 if (!MsgType)
628 {
629
630 /* Too bad, this doesn't work.*/
631 #if 0
632 UNICODE_STRING Str;
633 RtlInitUnicodeString(&Str, L"SHELLHOOK");
634 MsgType = UserRegisterWindowMessage(&Str);
635 #endif
636
637 MsgType = IntAddAtom(L"SHELLHOOK");
638
639 DPRINT("MsgType = %x\n", MsgType);
640 if (!MsgType)
641 DPRINT1("LastError: %x\n", GetLastNtError());
642 }
643
644 if (!Desktop)
645 {
646 DPRINT1("IntShellHookNotify: No desktop!\n");
647 return;
648 }
649
650 HwndList = UserBuildShellHookHwndList(Desktop);
651 if (HwndList)
652 {
653 HWND* cursor = HwndList;
654
655 for (; *cursor; cursor++)
656 {
657 DPRINT("Sending notify\n");
658 co_IntPostOrSendMessage(*cursor,
659 MsgType,
660 Message,
661 lParam);
662 }
663
664 ExFreePool(HwndList);
665 }
666
667 }
668
669 /*
670 * Add the window to the ShellHookWindows list. The windows
671 * on that list get notifications that are important to shell
672 * type applications.
673 *
674 * TODO: Validate the window? I'm not sure if sending these messages to
675 * an unsuspecting application that is not your own is a nice thing to do.
676 */
677 BOOL IntRegisterShellHookWindow(HWND hWnd)
678 {
679 PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop;
680 PSHELL_HOOK_WINDOW Entry;
681
682 DPRINT("IntRegisterShellHookWindow\n");
683
684 /* First deregister the window, so we can be sure it's never twice in the
685 * list.
686 */
687 IntDeRegisterShellHookWindow(hWnd);
688
689 Entry = ExAllocatePoolWithTag(PagedPool,
690 sizeof(SHELL_HOOK_WINDOW),
691 TAG_WINSTA);
692
693 if (!Entry)
694 return FALSE;
695
696 Entry->hWnd = hWnd;
697
698 InsertTailList(&Desktop->ShellHookWindows, &Entry->ListEntry);
699
700 return TRUE;
701 }
702
703 /*
704 * Remove the window from the ShellHookWindows list. The windows
705 * on that list get notifications that are important to shell
706 * type applications.
707 */
708 BOOL IntDeRegisterShellHookWindow(HWND hWnd)
709 {
710 PDESKTOP_OBJECT Desktop = PsGetWin32Thread()->Desktop;
711 PSHELL_HOOK_WINDOW Current;
712
713 LIST_FOR_EACH(Current, &Desktop->ShellHookWindows, SHELL_HOOK_WINDOW, ListEntry)
714 {
715 if (Current->hWnd == hWnd)
716 {
717 RemoveEntryList(&Current->ListEntry);
718 ExFreePool(Current);
719 return TRUE;
720 }
721 }
722
723 return FALSE;
724 }
725
726
727
728
729 /* SYSCALLS *******************************************************************/
730
731
732 /*
733 * NtUserCreateDesktop
734 *
735 * Creates a new desktop.
736 *
737 * Parameters
738 * lpszDesktopName
739 * Name of the new desktop.
740 *
741 * dwFlags
742 * Interaction flags.
743 *
744 * dwDesiredAccess
745 * Requested type of access.
746 *
747 * lpSecurity
748 * Security descriptor.
749 *
750 * hWindowStation
751 * Handle to window station on which to create the desktop.
752 *
753 * Return Value
754 * If the function succeeds, the return value is a handle to the newly
755 * created desktop. If the specified desktop already exists, the function
756 * succeeds and returns a handle to the existing desktop. When you are
757 * finished using the handle, call the CloseDesktop function to close it.
758 * If the function fails, the return value is NULL.
759 *
760 * Status
761 * @implemented
762 */
763
764 HDESK STDCALL
765 NtUserCreateDesktop(
766 PUNICODE_STRING lpszDesktopName,
767 DWORD dwFlags,
768 ACCESS_MASK dwDesiredAccess,
769 LPSECURITY_ATTRIBUTES lpSecurity,
770 HWINSTA hWindowStation)
771 {
772 OBJECT_ATTRIBUTES ObjectAttributes;
773 PWINSTATION_OBJECT WinStaObject;
774 PDESKTOP_OBJECT DesktopObject;
775 UNICODE_STRING DesktopName;
776 NTSTATUS Status;
777 HDESK Desktop;
778 CSR_API_MESSAGE Request;
779 DECLARE_RETURN(HDESK);
780
781 DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName);
782 UserEnterExclusive();
783
784 Status = IntValidateWindowStationHandle(
785 hWindowStation,
786 KernelMode,
787 0, /* FIXME - WINSTA_CREATEDESKTOP */
788 &WinStaObject);
789
790 if (! NT_SUCCESS(Status))
791 {
792 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
793 hWindowStation, lpszDesktopName);
794 SetLastNtError(Status);
795 RETURN( NULL);
796 }
797
798 if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
799 lpszDesktopName))
800 {
801 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
802 ObDereferenceObject(WinStaObject);
803 RETURN( NULL);
804 }
805
806 ObDereferenceObject(WinStaObject);
807
808 /*
809 * Try to open already existing desktop
810 */
811
812 DPRINT1("Trying to open desktop (%wZ)\n", &DesktopName);
813
814 /* Initialize ObjectAttributes for the desktop object */
815 InitializeObjectAttributes(
816 &ObjectAttributes,
817 &DesktopName,
818 0,
819 NULL,
820 NULL);
821
822 Status = ObOpenObjectByName(
823 &ObjectAttributes,
824 ExDesktopObjectType,
825 NULL,
826 KernelMode,
827 dwDesiredAccess,
828 NULL,
829 (HANDLE*)&Desktop);
830
831 if (NT_SUCCESS(Status))
832 {
833 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
834 ExFreePool(DesktopName.Buffer);
835 RETURN( Desktop);
836 }
837
838 /*
839 * No existing desktop found, try to create new one
840 */
841
842 Status = ObCreateObject(
843 KernelMode,
844 ExDesktopObjectType,
845 &ObjectAttributes,
846 ExGetPreviousMode(),
847 NULL,
848 sizeof(DESKTOP_OBJECT),
849 0,
850 0,
851 (PVOID*)&DesktopObject);
852
853 if (! NT_SUCCESS(Status))
854 {
855 DPRINT1("Failed creating desktop (%wZ)\n", &DesktopName);
856 ExFreePool(DesktopName.Buffer);
857 SetLastNtError(STATUS_UNSUCCESSFUL);
858 RETURN( NULL);
859 }
860
861 // init desktop area
862 DesktopObject->WorkArea.left = 0;
863 DesktopObject->WorkArea.top = 0;
864 DesktopObject->WorkArea.right = -1;
865 DesktopObject->WorkArea.bottom = -1;
866 IntGetDesktopWorkArea(DesktopObject, NULL);
867
868 /* Initialize some local (to win32k) desktop state. */
869 DesktopObject->ActiveMessageQueue = NULL;
870
871 Status = ObInsertObject(
872 (PVOID)DesktopObject,
873 NULL,
874 STANDARD_RIGHTS_REQUIRED,
875 0,
876 NULL,
877 (HANDLE*)&Desktop);
878
879 ObDereferenceObject(DesktopObject);
880 ExFreePool(DesktopName.Buffer);
881
882 if (! NT_SUCCESS(Status))
883 {
884 DPRINT1("Failed to create desktop handle\n");
885 SetLastNtError(Status);
886 RETURN( NULL);
887 }
888
889 /*
890 * Create a handle for CSRSS and notify CSRSS
891 */
892 Request.Type = MAKE_CSR_API(CREATE_DESKTOP, CSR_GUI);
893 Status = CsrInsertObject(Desktop,
894 GENERIC_ALL,
895 (HANDLE*)&Request.Data.CreateDesktopRequest.DesktopHandle);
896 if (! NT_SUCCESS(Status))
897 {
898 DPRINT1("Failed to create desktop handle for CSRSS\n");
899 ZwClose(Desktop);
900 SetLastNtError(Status);
901 RETURN( NULL);
902 }
903
904 Status = co_CsrNotify(&Request);
905 if (! NT_SUCCESS(Status))
906 {
907 CsrCloseHandle(Request.Data.CreateDesktopRequest.DesktopHandle);
908 DPRINT1("Failed to notify CSRSS about new desktop\n");
909 ZwClose(Desktop);
910 SetLastNtError(Status);
911 RETURN( NULL);
912 }
913
914 RETURN( Desktop);
915
916 CLEANUP:
917 DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_);
918 UserLeave();
919 END_CLEANUP;
920 }
921
922 /*
923 * NtUserOpenDesktop
924 *
925 * Opens an existing desktop.
926 *
927 * Parameters
928 * lpszDesktopName
929 * Name of the existing desktop.
930 *
931 * dwFlags
932 * Interaction flags.
933 *
934 * dwDesiredAccess
935 * Requested type of access.
936 *
937 * Return Value
938 * Handle to the desktop or zero on failure.
939 *
940 * Status
941 * @implemented
942 */
943
944 HDESK STDCALL
945 NtUserOpenDesktop(
946 PUNICODE_STRING lpszDesktopName,
947 DWORD dwFlags,
948 ACCESS_MASK dwDesiredAccess)
949 {
950 OBJECT_ATTRIBUTES ObjectAttributes;
951 HWINSTA WinSta;
952 PWINSTATION_OBJECT WinStaObject;
953 UNICODE_STRING DesktopName;
954 NTSTATUS Status;
955 HDESK Desktop;
956 DECLARE_RETURN(HDESK);
957
958 DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName);
959 UserEnterExclusive();
960
961 /*
962 * Validate the window station handle and compose the fully
963 * qualified desktop name
964 */
965
966 WinSta = UserGetProcessWindowStation();
967 Status = IntValidateWindowStationHandle(
968 WinSta,
969 KernelMode,
970 0,
971 &WinStaObject);
972
973 if (!NT_SUCCESS(Status))
974 {
975 DPRINT1("Failed validation of window station handle (0x%X)\n", WinSta);
976 SetLastNtError(Status);
977 RETURN( 0);
978 }
979
980 if (!IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
981 lpszDesktopName))
982 {
983 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
984 ObDereferenceObject(WinStaObject);
985 RETURN( 0);
986 }
987
988 ObDereferenceObject(WinStaObject);
989
990 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
991
992 /* Initialize ObjectAttributes for the desktop object */
993 InitializeObjectAttributes(
994 &ObjectAttributes,
995 &DesktopName,
996 0,
997 NULL,
998 NULL);
999
1000 Status = ObOpenObjectByName(
1001 &ObjectAttributes,
1002 ExDesktopObjectType,
1003 NULL,
1004 KernelMode,
1005 dwDesiredAccess,
1006 NULL,
1007 (HANDLE*)&Desktop);
1008
1009 if (!NT_SUCCESS(Status))
1010 {
1011 SetLastNtError(Status);
1012 ExFreePool(DesktopName.Buffer);
1013 RETURN( 0);
1014 }
1015
1016 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
1017 ExFreePool(DesktopName.Buffer);
1018
1019 RETURN( Desktop);
1020
1021 CLEANUP:
1022 DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_);
1023 UserLeave();
1024 END_CLEANUP;
1025 }
1026
1027 /*
1028 * NtUserOpenInputDesktop
1029 *
1030 * Opens the input (interactive) desktop.
1031 *
1032 * Parameters
1033 * dwFlags
1034 * Interaction flags.
1035 *
1036 * fInherit
1037 * Inheritance option.
1038 *
1039 * dwDesiredAccess
1040 * Requested type of access.
1041 *
1042 * Return Value
1043 * Handle to the input desktop or zero on failure.
1044 *
1045 * Status
1046 * @implemented
1047 */
1048
1049 HDESK STDCALL
1050 NtUserOpenInputDesktop(
1051 DWORD dwFlags,
1052 BOOL fInherit,
1053 ACCESS_MASK dwDesiredAccess)
1054 {
1055 PDESKTOP_OBJECT Object;
1056 NTSTATUS Status;
1057 HDESK Desktop;
1058 DECLARE_RETURN(HDESK);
1059
1060 DPRINT("Enter NtUserOpenInputDesktop\n");
1061 UserEnterExclusive();
1062
1063 DPRINT("About to open input desktop\n");
1064
1065 /* Get a pointer to the desktop object */
1066
1067 Status = IntValidateDesktopHandle(
1068 InputDesktopHandle,
1069 UserMode,
1070 0,
1071 &Object);
1072
1073 if (!NT_SUCCESS(Status))
1074 {
1075 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
1076 RETURN((HDESK)0);
1077 }
1078
1079 /* Create a new handle to the object */
1080
1081 Status = ObOpenObjectByPointer(
1082 Object,
1083 0,
1084 NULL,
1085 dwDesiredAccess,
1086 ExDesktopObjectType,
1087 UserMode,
1088 (HANDLE*)&Desktop);
1089
1090 ObDereferenceObject(Object);
1091
1092 if (NT_SUCCESS(Status))
1093 {
1094 DPRINT("Successfully opened input desktop\n");
1095 RETURN((HDESK)Desktop);
1096 }
1097
1098 SetLastNtError(Status);
1099 RETURN((HDESK)0);
1100
1101 CLEANUP:
1102 DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_);
1103 UserLeave();
1104 END_CLEANUP;
1105 }
1106
1107 /*
1108 * NtUserCloseDesktop
1109 *
1110 * Closes a desktop handle.
1111 *
1112 * Parameters
1113 * hDesktop
1114 * Handle to the desktop.
1115 *
1116 * Return Value
1117 * Status
1118 *
1119 * Remarks
1120 * The desktop handle can be created with NtUserCreateDesktop or
1121 * NtUserOpenDesktop. This function will fail if any thread in the calling
1122 * process is using the specified desktop handle or if the handle refers
1123 * to the initial desktop of the calling process.
1124 *
1125 * Status
1126 * @implemented
1127 */
1128
1129 BOOL STDCALL
1130 NtUserCloseDesktop(HDESK hDesktop)
1131 {
1132 PDESKTOP_OBJECT Object;
1133 NTSTATUS Status;
1134 DECLARE_RETURN(BOOL);
1135
1136 DPRINT("Enter NtUserCloseDesktop\n");
1137 UserEnterExclusive();
1138
1139 DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
1140
1141 Status = IntValidateDesktopHandle(
1142 hDesktop,
1143 UserMode,
1144 0,
1145 &Object);
1146
1147 if (!NT_SUCCESS(Status))
1148 {
1149 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1150 RETURN(FALSE);
1151 }
1152
1153 ObDereferenceObject(Object);
1154
1155 DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
1156
1157 Status = ZwClose(hDesktop);
1158 if (!NT_SUCCESS(Status))
1159 {
1160 SetLastNtError(Status);
1161 RETURN(FALSE);
1162 }
1163
1164 RETURN(TRUE);
1165
1166 CLEANUP:
1167 DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_);
1168 UserLeave();
1169 END_CLEANUP;
1170 }
1171
1172
1173
1174
1175 /*
1176 * NtUserPaintDesktop
1177 *
1178 * The NtUserPaintDesktop function fills the clipping region in the
1179 * specified device context with the desktop pattern or wallpaper. The
1180 * function is provided primarily for shell desktops.
1181 *
1182 * Parameters
1183 * hDC
1184 * Handle to the device context.
1185 *
1186 * Status
1187 * @implemented
1188 */
1189
1190 BOOL STDCALL
1191 NtUserPaintDesktop(HDC hDC)
1192 {
1193 RECT Rect;
1194 HBRUSH DesktopBrush, PreviousBrush;
1195 HWND hWndDesktop;
1196 BOOL doPatBlt = TRUE;
1197 PWINDOW_OBJECT WndDesktop;
1198 int len;
1199 DECLARE_RETURN(BOOL);
1200
1201 UserEnterExclusive();
1202 DPRINT("Enter NtUserPaintDesktop\n");
1203
1204 PWINSTATION_OBJECT WinSta = PsGetWin32Thread()->Desktop->WindowStation;
1205
1206 IntGdiGetClipBox(hDC, &Rect);
1207
1208 hWndDesktop = IntGetDesktopWindow();
1209
1210 WndDesktop = UserGetWindowObject(hWndDesktop);
1211 if (!WndDesktop)
1212 {
1213 RETURN(FALSE);
1214 }
1215
1216 DesktopBrush = (HBRUSH)IntGetClassLong(WndDesktop, GCL_HBRBACKGROUND, FALSE); //fixme: verify retval
1217
1218
1219 /*
1220 * Paint desktop background
1221 */
1222
1223 if (WinSta->hbmWallpaper != NULL)
1224 {
1225 PWINDOW_OBJECT DeskWin;
1226
1227 DeskWin = UserGetWindowObject(hWndDesktop);
1228
1229 if (DeskWin)
1230 {
1231 SIZE sz;
1232 int x, y;
1233 HDC hWallpaperDC;
1234
1235 sz.cx = DeskWin->WindowRect.right - DeskWin->WindowRect.left;
1236 sz.cy = DeskWin->WindowRect.bottom - DeskWin->WindowRect.top;
1237
1238 if (WinSta->WallpaperMode == wmStretch ||
1239 WinSta->WallpaperMode == wmTile)
1240 {
1241 x = 0;
1242 y = 0;
1243 }
1244 else
1245 {
1246 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
1247 x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
1248 y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
1249 }
1250
1251 hWallpaperDC = NtGdiCreateCompatibleDC(hDC);
1252 if(hWallpaperDC != NULL)
1253 {
1254 HBITMAP hOldBitmap;
1255
1256 /* fill in the area that the bitmap is not going to cover */
1257 if (x > 0 || y > 0)
1258 {
1259 /* FIXME - clip out the bitmap
1260 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1261 once we support DSTINVERT */
1262 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
1263 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1264 NtGdiSelectObject(hDC, PreviousBrush);
1265 }
1266
1267 /*Do not fill the background after it is painted no matter the size of the picture */
1268 doPatBlt = FALSE;
1269
1270 hOldBitmap = NtGdiSelectObject(hWallpaperDC, WinSta->hbmWallpaper);
1271
1272 if (WinSta->WallpaperMode == wmStretch)
1273 {
1274 NtGdiStretchBlt(hDC,
1275 x,
1276 y,
1277 Rect.right,
1278 Rect.bottom,
1279 hWallpaperDC,
1280 0,
1281 0,
1282 WinSta->cxWallpaper,
1283 WinSta->cyWallpaper,
1284 SRCCOPY,
1285 0);
1286 }
1287 else if (WinSta->WallpaperMode == wmTile)
1288 {
1289 /* paint the bitmap across the screen then down */
1290 for(y = 0; y < Rect.bottom; y += WinSta->cyWallpaper)
1291 {
1292 for(x = 0; x < Rect.right; x += WinSta->cxWallpaper)
1293 {
1294 NtGdiBitBlt(hDC,
1295 x,
1296 y,
1297 WinSta->cxWallpaper,
1298 WinSta->cyWallpaper,
1299 hWallpaperDC,
1300 0,
1301 0,
1302 SRCCOPY,
1303 0,
1304 0);
1305 }
1306 }
1307 }
1308 else
1309 {
1310 NtGdiBitBlt(hDC,
1311 x,
1312 y,
1313 WinSta->cxWallpaper,
1314 WinSta->cyWallpaper,
1315 hWallpaperDC,
1316 0,
1317 0,
1318 SRCCOPY,
1319 0,
1320 0);
1321 }
1322 NtGdiSelectObject(hWallpaperDC, hOldBitmap);
1323 NtGdiDeleteDC(hWallpaperDC);
1324 }
1325 }
1326 }
1327
1328 /* Back ground is set to none, clear the screen */
1329 if (doPatBlt)
1330 {
1331 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
1332 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1333 NtGdiSelectObject(hDC, PreviousBrush);
1334 }
1335
1336 /*
1337 * Display system version on the desktop background
1338 */
1339
1340 if (g_PaintDesktopVersion)
1341 {
1342 static WCHAR s_wszVersion[256] = {0};
1343 RECT rect;
1344
1345 if (*s_wszVersion)
1346 {
1347 len = wcslen(s_wszVersion);
1348 }
1349 else
1350 {
1351 len = GetSystemVersionString(s_wszVersion);
1352 }
1353
1354 if (len)
1355 {
1356 if (!UserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0))
1357 {
1358 rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1359 rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1360 }
1361
1362 COLORREF color_old = NtGdiSetTextColor(hDC, RGB(255,255,255));
1363 UINT align_old = NtGdiSetTextAlign(hDC, TA_RIGHT);
1364 int mode_old = NtGdiSetBkMode(hDC, TRANSPARENT);
1365
1366 NtGdiTextOut(hDC, rect.right-16, rect.bottom-48, s_wszVersion, len);
1367
1368 NtGdiSetBkMode(hDC, mode_old);
1369 NtGdiSetTextAlign(hDC, align_old);
1370 NtGdiSetTextColor(hDC, color_old);
1371 }
1372 }
1373
1374 RETURN(TRUE);
1375
1376 CLEANUP:
1377 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_);
1378 UserLeave();
1379 END_CLEANUP;
1380 }
1381
1382
1383 /*
1384 * NtUserSwitchDesktop
1385 *
1386 * Sets the current input (interactive) desktop.
1387 *
1388 * Parameters
1389 * hDesktop
1390 * Handle to desktop.
1391 *
1392 * Return Value
1393 * Status
1394 *
1395 * Status
1396 * @unimplemented
1397 */
1398
1399 BOOL STDCALL
1400 NtUserSwitchDesktop(HDESK hDesktop)
1401 {
1402 PDESKTOP_OBJECT DesktopObject;
1403 NTSTATUS Status;
1404 DECLARE_RETURN(BOOL);
1405
1406 UserEnterExclusive();
1407 DPRINT("Enter NtUserSwitchDesktop\n");
1408
1409 DPRINT("About to switch desktop (0x%X)\n", hDesktop);
1410
1411 Status = IntValidateDesktopHandle(
1412 hDesktop,
1413 UserMode,
1414 0,
1415 &DesktopObject);
1416
1417 if (!NT_SUCCESS(Status))
1418 {
1419 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1420 RETURN(FALSE);
1421 }
1422
1423 /*
1424 * Don't allow applications switch the desktop if it's locked, unless the caller
1425 * is the logon application itself
1426 */
1427 if((DesktopObject->WindowStation->Flags & WSS_LOCKED) &&
1428 LogonProcess != NULL && LogonProcess != PsGetWin32Process())
1429 {
1430 ObDereferenceObject(DesktopObject);
1431 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
1432 RETURN(FALSE);
1433 }
1434
1435 /* FIXME: Fail if the desktop belong to an invisible window station */
1436 /* FIXME: Fail if the process is associated with a secured
1437 desktop such as Winlogon or Screen-Saver */
1438 /* FIXME: Connect to input device */
1439
1440 /* Set the active desktop in the desktop's window station. */
1441 DesktopObject->WindowStation->ActiveDesktop = DesktopObject;
1442
1443 /* Set the global state. */
1444 InputDesktop = DesktopObject;
1445 InputDesktopHandle = hDesktop;
1446 InputWindowStation = DesktopObject->WindowStation;
1447
1448 ObDereferenceObject(DesktopObject);
1449
1450 RETURN(TRUE);
1451
1452 CLEANUP:
1453 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_);
1454 UserLeave();
1455 END_CLEANUP;
1456 }
1457
1458 /*
1459 * NtUserResolveDesktopForWOW
1460 *
1461 * Status
1462 * @unimplemented
1463 */
1464
1465 DWORD STDCALL
1466 NtUserResolveDesktopForWOW(DWORD Unknown0)
1467 {
1468 UNIMPLEMENTED
1469 return 0;
1470 }
1471
1472 /*
1473 * NtUserGetThreadDesktop
1474 *
1475 * Status
1476 * @implemented
1477 */
1478
1479 HDESK STDCALL
1480 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
1481 {
1482 NTSTATUS Status;
1483 PETHREAD Thread;
1484 PDESKTOP_OBJECT DesktopObject;
1485 HDESK Ret, hThreadDesktop;
1486 OBJECT_HANDLE_INFORMATION HandleInformation;
1487 DECLARE_RETURN(HDESK);
1488
1489 UserEnterExclusive();
1490 DPRINT("Enter NtUserGetThreadDesktop\n");
1491
1492 if(!dwThreadId)
1493 {
1494 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1495 RETURN(0);
1496 }
1497
1498 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1499 if(!NT_SUCCESS(Status))
1500 {
1501 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1502 RETURN(0);
1503 }
1504
1505 if(Thread->ThreadsProcess == PsGetCurrentProcess())
1506 {
1507 /* just return the handle, we queried the desktop handle of a thread running
1508 in the same context */
1509 Ret = ((PW32THREAD)Thread->Tcb.Win32Thread)->hDesktop;
1510 ObDereferenceObject(Thread);
1511 RETURN(Ret);
1512 }
1513
1514 /* get the desktop handle and the desktop of the thread */
1515 if(!(hThreadDesktop = ((PW32THREAD)Thread->Tcb.Win32Thread)->hDesktop) ||
1516 !(DesktopObject = ((PW32THREAD)Thread->Tcb.Win32Thread)->Desktop))
1517 {
1518 ObDereferenceObject(Thread);
1519 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
1520 RETURN(NULL);
1521 }
1522
1523 /* we could just use DesktopObject instead of looking up the handle, but latter
1524 may be a bit safer (e.g. when the desktop is being destroyed */
1525 /* switch into the context of the thread we're trying to get the desktop from,
1526 so we can use the handle */
1527 KeAttachProcess(&Thread->ThreadsProcess->Pcb);
1528 Status = ObReferenceObjectByHandle(hThreadDesktop,
1529 GENERIC_ALL,
1530 ExDesktopObjectType,
1531 UserMode,
1532 (PVOID*)&DesktopObject,
1533 &HandleInformation);
1534 KeDetachProcess();
1535
1536 /* the handle couldn't be found, there's nothing to get... */
1537 if(!NT_SUCCESS(Status))
1538 {
1539 ObDereferenceObject(Thread);
1540 RETURN(NULL);
1541 }
1542
1543 /* lookup our handle table if we can find a handle to the desktop object,
1544 if not, create one */
1545 Ret = IntGetDesktopObjectHandle(DesktopObject);
1546
1547 /* all done, we got a valid handle to the desktop */
1548 ObDereferenceObject(DesktopObject);
1549 ObDereferenceObject(Thread);
1550 RETURN(Ret);
1551
1552 CLEANUP:
1553 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_);
1554 UserLeave();
1555 END_CLEANUP;
1556 }
1557
1558 /*
1559 * NtUserSetThreadDesktop
1560 *
1561 * Status
1562 * @implemented
1563 */
1564
1565 BOOL STDCALL
1566 NtUserSetThreadDesktop(HDESK hDesktop)
1567 {
1568 PW32THREAD W32Thread;
1569 PDESKTOP_OBJECT DesktopObject;
1570 NTSTATUS Status;
1571 DECLARE_RETURN(BOOL);
1572
1573 UserEnterExclusive();
1574 DPRINT("Enter NtUserSetThreadDesktop\n");
1575
1576 /* Validate the new desktop. */
1577 Status = IntValidateDesktopHandle(
1578 hDesktop,
1579 UserMode,
1580 0,
1581 &DesktopObject);
1582
1583 if (!NT_SUCCESS(Status))
1584 {
1585 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1586 RETURN(FALSE);
1587 }
1588
1589 W32Thread = PsGetWin32Thread();
1590
1591 /* FIXME: Should check here to see if the thread has any windows. */
1592
1593 if (W32Thread->Desktop != NULL)
1594 {
1595 ObDereferenceObject(W32Thread->Desktop);
1596 }
1597
1598 W32Thread->Desktop = DesktopObject;
1599 W32Thread->hDesktop = hDesktop;
1600
1601 RETURN(TRUE);
1602
1603 CLEANUP:
1604 DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_);
1605 UserLeave();
1606 END_CLEANUP;
1607 }
1608
1609 /* EOF */