85dc431b9ffd61c5c200255e396ae8876aeed006
[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 PWINSTATION_OBJECT WinStaObject;
952 UNICODE_STRING DesktopName;
953 NTSTATUS Status;
954 HDESK Desktop;
955 DECLARE_RETURN(HDESK);
956
957 DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName);
958 UserEnterExclusive();
959
960 /*
961 * Validate the window station handle and compose the fully
962 * qualified desktop name
963 */
964
965 Status = IntValidateWindowStationHandle(
966 PsGetCurrentProcess()->Win32WindowStation,
967 KernelMode,
968 0,
969 &WinStaObject);
970
971 if (!NT_SUCCESS(Status))
972 {
973 DPRINT1("Failed validation of window station handle (0x%X)\n",
974 PsGetCurrentProcess()->Win32WindowStation);
975 SetLastNtError(Status);
976 RETURN( 0);
977 }
978
979 if (!IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
980 lpszDesktopName))
981 {
982 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
983 ObDereferenceObject(WinStaObject);
984 RETURN( 0);
985 }
986
987 ObDereferenceObject(WinStaObject);
988
989 DPRINT1("Trying to open desktop (%wZ)\n", &DesktopName);
990
991 /* Initialize ObjectAttributes for the desktop object */
992 InitializeObjectAttributes(
993 &ObjectAttributes,
994 &DesktopName,
995 0,
996 NULL,
997 NULL);
998
999 Status = ObOpenObjectByName(
1000 &ObjectAttributes,
1001 ExDesktopObjectType,
1002 NULL,
1003 UserMode,
1004 dwDesiredAccess,
1005 NULL,
1006 (HANDLE*)&Desktop);
1007
1008 if (!NT_SUCCESS(Status))
1009 {
1010 SetLastNtError(Status);
1011 ExFreePool(DesktopName.Buffer);
1012 RETURN( 0);
1013 }
1014
1015 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
1016 ExFreePool(DesktopName.Buffer);
1017
1018 RETURN( Desktop);
1019
1020 CLEANUP:
1021 DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_);
1022 UserLeave();
1023 END_CLEANUP;
1024 }
1025
1026 /*
1027 * NtUserOpenInputDesktop
1028 *
1029 * Opens the input (interactive) desktop.
1030 *
1031 * Parameters
1032 * dwFlags
1033 * Interaction flags.
1034 *
1035 * fInherit
1036 * Inheritance option.
1037 *
1038 * dwDesiredAccess
1039 * Requested type of access.
1040 *
1041 * Return Value
1042 * Handle to the input desktop or zero on failure.
1043 *
1044 * Status
1045 * @implemented
1046 */
1047
1048 HDESK STDCALL
1049 NtUserOpenInputDesktop(
1050 DWORD dwFlags,
1051 BOOL fInherit,
1052 ACCESS_MASK dwDesiredAccess)
1053 {
1054 PDESKTOP_OBJECT Object;
1055 NTSTATUS Status;
1056 HDESK Desktop;
1057 DECLARE_RETURN(HDESK);
1058
1059 DPRINT("Enter NtUserOpenInputDesktop\n");
1060 UserEnterExclusive();
1061
1062 DPRINT("About to open input desktop\n");
1063
1064 /* Get a pointer to the desktop object */
1065
1066 Status = IntValidateDesktopHandle(
1067 InputDesktopHandle,
1068 UserMode,
1069 0,
1070 &Object);
1071
1072 if (!NT_SUCCESS(Status))
1073 {
1074 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop);
1075 RETURN((HDESK)0);
1076 }
1077
1078 /* Create a new handle to the object */
1079
1080 Status = ObOpenObjectByPointer(
1081 Object,
1082 0,
1083 NULL,
1084 dwDesiredAccess,
1085 ExDesktopObjectType,
1086 UserMode,
1087 (HANDLE*)&Desktop);
1088
1089 ObDereferenceObject(Object);
1090
1091 if (NT_SUCCESS(Status))
1092 {
1093 DPRINT("Successfully opened input desktop\n");
1094 RETURN((HDESK)Desktop);
1095 }
1096
1097 SetLastNtError(Status);
1098 RETURN((HDESK)0);
1099
1100 CLEANUP:
1101 DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_);
1102 UserLeave();
1103 END_CLEANUP;
1104 }
1105
1106 /*
1107 * NtUserCloseDesktop
1108 *
1109 * Closes a desktop handle.
1110 *
1111 * Parameters
1112 * hDesktop
1113 * Handle to the desktop.
1114 *
1115 * Return Value
1116 * Status
1117 *
1118 * Remarks
1119 * The desktop handle can be created with NtUserCreateDesktop or
1120 * NtUserOpenDesktop. This function will fail if any thread in the calling
1121 * process is using the specified desktop handle or if the handle refers
1122 * to the initial desktop of the calling process.
1123 *
1124 * Status
1125 * @implemented
1126 */
1127
1128 BOOL STDCALL
1129 NtUserCloseDesktop(HDESK hDesktop)
1130 {
1131 PDESKTOP_OBJECT Object;
1132 NTSTATUS Status;
1133 DECLARE_RETURN(BOOL);
1134
1135 DPRINT("Enter NtUserCloseDesktop\n");
1136 UserEnterExclusive();
1137
1138 DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
1139
1140 Status = IntValidateDesktopHandle(
1141 hDesktop,
1142 UserMode,
1143 0,
1144 &Object);
1145
1146 if (!NT_SUCCESS(Status))
1147 {
1148 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1149 RETURN(FALSE);
1150 }
1151
1152 ObDereferenceObject(Object);
1153
1154 DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
1155
1156 Status = ZwClose(hDesktop);
1157 if (!NT_SUCCESS(Status))
1158 {
1159 SetLastNtError(Status);
1160 RETURN(FALSE);
1161 }
1162
1163 RETURN(TRUE);
1164
1165 CLEANUP:
1166 DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_);
1167 UserLeave();
1168 END_CLEANUP;
1169 }
1170
1171
1172
1173
1174 /*
1175 * NtUserPaintDesktop
1176 *
1177 * The NtUserPaintDesktop function fills the clipping region in the
1178 * specified device context with the desktop pattern or wallpaper. The
1179 * function is provided primarily for shell desktops.
1180 *
1181 * Parameters
1182 * hDC
1183 * Handle to the device context.
1184 *
1185 * Status
1186 * @implemented
1187 */
1188
1189 BOOL STDCALL
1190 NtUserPaintDesktop(HDC hDC)
1191 {
1192 RECT Rect;
1193 HBRUSH DesktopBrush, PreviousBrush;
1194 HWND hWndDesktop;
1195 BOOL doPatBlt = TRUE;
1196 PWINDOW_OBJECT WndDesktop;
1197 int len;
1198 DECLARE_RETURN(BOOL);
1199
1200 UserEnterExclusive();
1201 DPRINT("Enter NtUserPaintDesktop\n");
1202
1203 PWINSTATION_OBJECT WinSta = PsGetWin32Thread()->Desktop->WindowStation;
1204
1205 IntGdiGetClipBox(hDC, &Rect);
1206
1207 hWndDesktop = IntGetDesktopWindow();
1208 if (!(WndDesktop = UserGetWindowObject(hWndDesktop)))
1209 RETURN(FALSE);
1210
1211 DesktopBrush = (HBRUSH)IntGetClassLong(WndDesktop, GCL_HBRBACKGROUND, FALSE); //fixme: verify retval
1212
1213
1214 /*
1215 * Paint desktop background
1216 */
1217
1218 if(WinSta->hbmWallpaper != NULL)
1219 {
1220 PWINDOW_OBJECT DeskWin;
1221
1222 if((DeskWin = UserGetWindowObject(hWndDesktop)))
1223 {
1224 SIZE sz;
1225 int x, y;
1226 HDC hWallpaperDC;
1227
1228 sz.cx = DeskWin->WindowRect.right - DeskWin->WindowRect.left;
1229 sz.cy = DeskWin->WindowRect.bottom - DeskWin->WindowRect.top;
1230
1231 if(WinSta->WallpaperMode == wmStretch ||
1232 WinSta->WallpaperMode == wmTile)
1233 {
1234 x = 0;
1235 y = 0;
1236 }
1237 else
1238 {
1239 x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
1240 y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
1241 }
1242
1243 hWallpaperDC = NtGdiCreateCompatibleDC(hDC);
1244 if(hWallpaperDC != NULL)
1245 {
1246 HBITMAP hOldBitmap;
1247
1248 if(x > 0 || y > 0)
1249 {
1250 /* FIXME - clip out the bitmap
1251 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1252 once we support DSTINVERT */
1253 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
1254 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1255 NtGdiSelectObject(hDC, PreviousBrush);
1256 }
1257
1258 //Do not fill the background after it is painted no matter the size of the picture
1259 doPatBlt = FALSE;
1260
1261 hOldBitmap = NtGdiSelectObject(hWallpaperDC, WinSta->hbmWallpaper);
1262
1263 if(WinSta->WallpaperMode == wmStretch)
1264 {
1265 #if 0 //Broken Stretch Code
1266 /* Fix me, stretch the bitmap to fit the screen. I'm not smart enough to do this :( */
1267 BITMAPINFO bmINFO;
1268 LPVOID pBits;
1269 bmINFO.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1270 /* Get bits */
1271 NtGdiGetDIBits(hDC,
1272 WinSta->hbmWallpaper,
1273 0,
1274 WinSta->cyWallpaper,
1275 NULL, // what goes here?
1276 &bmINFO,
1277 DIB_RGB_COLORS);
1278
1279 bmINFO.bmiHeader.biCompression = BI_RGB;
1280
1281 pBits = ExAllocatePool(PagedPool,bmINFO.bmiHeader.biSizeImage);
1282
1283 if(pBits == NULL)
1284 {
1285 doPatBlt = TRUE;
1286 }
1287 else
1288 {
1289
1290 NtGdiGetDIBits(hDC,
1291 WinSta->hbmWallpaper,
1292 0,
1293 WinSta->cyWallpaper,
1294 (LPVOID)pBits, // what goes here?
1295 &bmINFO,
1296 DIB_RGB_COLORS);
1297 DPRINT1("Before Draw\n");
1298
1299 /* Stretch it to fit the screen */
1300 NtGdiStretchDIBits(hDC,
1301 0,
1302 0,
1303 Rect.right,
1304 Rect.bottom,
1305 0,
1306 0,
1307 WinSta->cxWallpaper,
1308 WinSta->cyWallpaper,
1309 (LPVOID)pBits, // get this from NtGdiGetDiBits?
1310 &bmINFO, // get this from NtGdiGetDiBits?
1311 DIB_RGB_COLORS,
1312 SRCCOPY);
1313 ExFreePool(pBits);
1314 }
1315 #else
1316 /* Draw nothing */
1317 doPatBlt = TRUE;
1318 #endif //Broken Stretch Code
1319 }
1320 else if(WinSta->WallpaperMode == wmTile)
1321 {
1322
1323 for(y = 0; y < Rect.bottom; y += WinSta->cyWallpaper)
1324 {
1325 for(x = 0; x < Rect.right; x += WinSta->cxWallpaper)
1326 {
1327 NtGdiBitBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, hWallpaperDC, 0, 0, SRCCOPY);
1328 }
1329 }
1330 }
1331 else
1332 {
1333 NtGdiBitBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, hWallpaperDC, 0, 0, SRCCOPY);
1334 }
1335 NtGdiSelectObject(hWallpaperDC, hOldBitmap);
1336 NtGdiDeleteDC(hWallpaperDC);
1337 }
1338 }
1339 }
1340
1341 /* Back ground is set to none, clear the screen */
1342 if (doPatBlt)
1343 {
1344 PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
1345 NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
1346 NtGdiSelectObject(hDC, PreviousBrush);
1347 }
1348
1349 /*
1350 * Display system version on the desktop background
1351 */
1352
1353 if (g_PaintDesktopVersion)
1354 {
1355 static WCHAR s_wszVersion[256] = {0};
1356 RECT rect;
1357
1358 if (*s_wszVersion)
1359 len = wcslen(s_wszVersion);
1360 else
1361 len = GetSystemVersionString(s_wszVersion);
1362
1363 if (len)
1364 {
1365 if (!UserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0))
1366 {
1367 rect.right = UserGetSystemMetrics(SM_CXSCREEN);
1368 rect.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1369 }
1370
1371 COLORREF color_old = NtGdiSetTextColor(hDC, RGB(255,255,255));
1372 UINT align_old = NtGdiSetTextAlign(hDC, TA_RIGHT);
1373 int mode_old = NtGdiSetBkMode(hDC, TRANSPARENT);
1374
1375 NtGdiTextOut(hDC, rect.right-16, rect.bottom-48, s_wszVersion, len);
1376
1377 NtGdiSetBkMode(hDC, mode_old);
1378 NtGdiSetTextAlign(hDC, align_old);
1379 NtGdiSetTextColor(hDC, color_old);
1380 }
1381 }
1382
1383 RETURN(TRUE);
1384
1385 CLEANUP:
1386 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_);
1387 UserLeave();
1388 END_CLEANUP;
1389 }
1390
1391
1392 /*
1393 * NtUserSwitchDesktop
1394 *
1395 * Sets the current input (interactive) desktop.
1396 *
1397 * Parameters
1398 * hDesktop
1399 * Handle to desktop.
1400 *
1401 * Return Value
1402 * Status
1403 *
1404 * Status
1405 * @unimplemented
1406 */
1407
1408 BOOL STDCALL
1409 NtUserSwitchDesktop(HDESK hDesktop)
1410 {
1411 PDESKTOP_OBJECT DesktopObject;
1412 NTSTATUS Status;
1413 DECLARE_RETURN(BOOL);
1414
1415 UserEnterExclusive();
1416 DPRINT("Enter NtUserSwitchDesktop\n");
1417
1418 DPRINT("About to switch desktop (0x%X)\n", hDesktop);
1419
1420 Status = IntValidateDesktopHandle(
1421 hDesktop,
1422 UserMode,
1423 0,
1424 &DesktopObject);
1425
1426 if (!NT_SUCCESS(Status))
1427 {
1428 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1429 RETURN(FALSE);
1430 }
1431
1432 /*
1433 * Don't allow applications switch the desktop if it's locked, unless the caller
1434 * is the logon application itself
1435 */
1436 if((DesktopObject->WindowStation->Flags & WSS_LOCKED) &&
1437 LogonProcess != NULL && LogonProcess != PsGetWin32Process())
1438 {
1439 ObDereferenceObject(DesktopObject);
1440 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
1441 RETURN(FALSE);
1442 }
1443
1444 /* FIXME: Fail if the desktop belong to an invisible window station */
1445 /* FIXME: Fail if the process is associated with a secured
1446 desktop such as Winlogon or Screen-Saver */
1447 /* FIXME: Connect to input device */
1448
1449 /* Set the active desktop in the desktop's window station. */
1450 DesktopObject->WindowStation->ActiveDesktop = DesktopObject;
1451
1452 /* Set the global state. */
1453 InputDesktop = DesktopObject;
1454 InputDesktopHandle = hDesktop;
1455 InputWindowStation = DesktopObject->WindowStation;
1456
1457 ObDereferenceObject(DesktopObject);
1458
1459 RETURN(TRUE);
1460
1461 CLEANUP:
1462 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_);
1463 UserLeave();
1464 END_CLEANUP;
1465 }
1466
1467 /*
1468 * NtUserResolveDesktopForWOW
1469 *
1470 * Status
1471 * @unimplemented
1472 */
1473
1474 DWORD STDCALL
1475 NtUserResolveDesktopForWOW(DWORD Unknown0)
1476 {
1477 UNIMPLEMENTED
1478 return 0;
1479 }
1480
1481 /*
1482 * NtUserGetThreadDesktop
1483 *
1484 * Status
1485 * @implemented
1486 */
1487
1488 HDESK STDCALL
1489 NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
1490 {
1491 NTSTATUS Status;
1492 PETHREAD Thread;
1493 PDESKTOP_OBJECT DesktopObject;
1494 HDESK Ret, hThreadDesktop;
1495 OBJECT_HANDLE_INFORMATION HandleInformation;
1496 DECLARE_RETURN(HDESK);
1497
1498 UserEnterExclusive();
1499 DPRINT("Enter NtUserGetThreadDesktop\n");
1500
1501 if(!dwThreadId)
1502 {
1503 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1504 RETURN(0);
1505 }
1506
1507 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1508 if(!NT_SUCCESS(Status))
1509 {
1510 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1511 RETURN(0);
1512 }
1513
1514 if(Thread->ThreadsProcess == PsGetCurrentProcess())
1515 {
1516 /* just return the handle, we queried the desktop handle of a thread running
1517 in the same context */
1518 Ret = ((PW32THREAD)Thread->Tcb.Win32Thread)->hDesktop;
1519 ObDereferenceObject(Thread);
1520 RETURN(Ret);
1521 }
1522
1523 /* get the desktop handle and the desktop of the thread */
1524 if(!(hThreadDesktop = ((PW32THREAD)Thread->Tcb.Win32Thread)->hDesktop) ||
1525 !(DesktopObject = ((PW32THREAD)Thread->Tcb.Win32Thread)->Desktop))
1526 {
1527 ObDereferenceObject(Thread);
1528 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
1529 RETURN(NULL);
1530 }
1531
1532 /* we could just use DesktopObject instead of looking up the handle, but latter
1533 may be a bit safer (e.g. when the desktop is being destroyed */
1534 /* switch into the context of the thread we're trying to get the desktop from,
1535 so we can use the handle */
1536 KeAttachProcess(&Thread->ThreadsProcess->Pcb);
1537 Status = ObReferenceObjectByHandle(hThreadDesktop,
1538 GENERIC_ALL,
1539 ExDesktopObjectType,
1540 UserMode,
1541 (PVOID*)&DesktopObject,
1542 &HandleInformation);
1543 KeDetachProcess();
1544
1545 /* the handle couldn't be found, there's nothing to get... */
1546 if(!NT_SUCCESS(Status))
1547 {
1548 ObDereferenceObject(Thread);
1549 RETURN(NULL);
1550 }
1551
1552 /* lookup our handle table if we can find a handle to the desktop object,
1553 if not, create one */
1554 Ret = IntGetDesktopObjectHandle(DesktopObject);
1555
1556 /* all done, we got a valid handle to the desktop */
1557 ObDereferenceObject(DesktopObject);
1558 ObDereferenceObject(Thread);
1559 RETURN(Ret);
1560
1561 CLEANUP:
1562 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_);
1563 UserLeave();
1564 END_CLEANUP;
1565 }
1566
1567 /*
1568 * NtUserSetThreadDesktop
1569 *
1570 * Status
1571 * @implemented
1572 */
1573
1574 BOOL STDCALL
1575 NtUserSetThreadDesktop(HDESK hDesktop)
1576 {
1577 PW32THREAD W32Thread;
1578 PDESKTOP_OBJECT DesktopObject;
1579 NTSTATUS Status;
1580 DECLARE_RETURN(BOOL);
1581
1582 UserEnterExclusive();
1583 DPRINT("Enter NtUserSetThreadDesktop\n");
1584
1585 /* Validate the new desktop. */
1586 Status = IntValidateDesktopHandle(
1587 hDesktop,
1588 UserMode,
1589 0,
1590 &DesktopObject);
1591
1592 if (!NT_SUCCESS(Status))
1593 {
1594 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
1595 RETURN(FALSE);
1596 }
1597
1598 W32Thread = PsGetWin32Thread();
1599
1600 /* FIXME: Should check here to see if the thread has any windows. */
1601
1602 if (W32Thread->Desktop != NULL)
1603 {
1604 ObDereferenceObject(W32Thread->Desktop);
1605 }
1606
1607 W32Thread->Desktop = DesktopObject;
1608 W32Thread->hDesktop = hDesktop;
1609
1610 RETURN(TRUE);
1611
1612 CLEANUP:
1613 DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_);
1614 UserLeave();
1615 END_CLEANUP;
1616 }
1617
1618 /* EOF */