3 * ReactOS W32 Subsystem
4 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * COPYRIGHT: See COPYING in the top level directory
23 * PROJECT: ReactOS kernel
25 * FILE: subsys/win32k/ntuser/desktop.c
26 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
28 * 06-06-2001 CSH Created
31 /* INCLUDES ******************************************************************/
44 IN OUT PDESKTOP Desktop
47 /* GLOBALS *******************************************************************/
49 /* Currently active desktop */
50 PDESKTOP InputDesktop
= NULL
;
51 HDESK InputDesktopHandle
= NULL
;
52 HDC ScreenDeviceContext
= NULL
;
53 BOOL g_PaintDesktopVersion
= FALSE
;
55 GENERIC_MAPPING IntDesktopMapping
=
57 STANDARD_RIGHTS_READ
| DESKTOP_ENUMERATE
|
59 STANDARD_RIGHTS_WRITE
| DESKTOP_CREATEMENU
|
60 DESKTOP_CREATEWINDOW
|
62 DESKTOP_JOURNALPLAYBACK
|
63 DESKTOP_JOURNALRECORD
|
65 STANDARD_RIGHTS_EXECUTE
| DESKTOP_SWITCHDESKTOP
,
66 STANDARD_RIGHTS_REQUIRED
| DESKTOP_CREATEMENU
|
67 DESKTOP_CREATEWINDOW
|
70 DESKTOP_JOURNALPLAYBACK
|
71 DESKTOP_JOURNALRECORD
|
73 DESKTOP_SWITCHDESKTOP
|
77 /* OBJECT CALLBACKS **********************************************************/
81 IntDesktopObjectParse(IN PVOID ParseObject
,
83 IN OUT PACCESS_STATE AccessState
,
84 IN KPROCESSOR_MODE AccessMode
,
86 IN OUT PUNICODE_STRING CompleteName
,
87 IN OUT PUNICODE_STRING RemainingName
,
88 IN OUT PVOID Context OPTIONAL
,
89 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
94 OBJECT_ATTRIBUTES ObjectAttributes
;
95 PLIST_ENTRY NextEntry
, ListHead
;
96 PWINSTATION_OBJECT WinStaObject
= (PWINSTATION_OBJECT
)ParseObject
;
97 PUNICODE_STRING DesktopName
;
99 /* Set the list pointers and loop the window station */
100 ListHead
= &WinStaObject
->DesktopListHead
;
101 NextEntry
= ListHead
->Flink
;
102 while (NextEntry
!= ListHead
)
104 /* Get the current desktop */
105 Desktop
= CONTAINING_RECORD(NextEntry
, DESKTOP
, ListEntry
);
108 DesktopName
= GET_DESKTOP_NAME(Desktop
);
111 /* Compare the name */
112 if (RtlEqualUnicodeString(RemainingName
,
114 (Attributes
& OBJ_CASE_INSENSITIVE
)))
116 /* We found a match. Did this come from a create? */
119 /* Unless OPEN_IF was given, fail with an error */
120 if (!(Attributes
& OBJ_OPENIF
))
123 return STATUS_OBJECT_NAME_COLLISION
;
127 /* Otherwise, return with a warning only */
128 Status
= STATUS_OBJECT_NAME_EXISTS
;
133 /* This was a real open, so this is OK */
134 Status
= STATUS_SUCCESS
;
137 /* Reference the desktop and return it */
138 ObReferenceObject(Desktop
);
144 /* Go to the next desktop */
145 NextEntry
= NextEntry
->Flink
;
148 /* If we got here but this isn't a create, then fail */
149 if (!Context
) return STATUS_OBJECT_NAME_NOT_FOUND
;
151 /* Create the desktop object */
152 InitializeObjectAttributes(&ObjectAttributes
, RemainingName
, 0, NULL
, NULL
);
153 Status
= ObCreateObject(KernelMode
,
162 if (!NT_SUCCESS(Status
)) return Status
;
164 /* Initialize shell hook window list and set the parent */
165 InitializeListHead(&Desktop
->ShellHookWindows
);
166 Desktop
->WindowStation
= (PWINSTATION_OBJECT
)ParseObject
;
168 /* Put the desktop on the window station's list of associated desktops */
169 InsertTailList(&Desktop
->WindowStation
->DesktopListHead
,
170 &Desktop
->ListEntry
);
172 /* Set the desktop object and return success */
174 return STATUS_SUCCESS
;
178 IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
180 PDESKTOP Desktop
= (PDESKTOP
)Parameters
->Object
;
182 DPRINT("Deleting desktop (0x%X)\n", Desktop
);
184 /* Remove the desktop from the window station's list of associcated desktops */
185 RemoveEntryList(&Desktop
->ListEntry
);
187 IntFreeDesktopHeap(Desktop
);
190 /* PRIVATE FUNCTIONS **********************************************************/
194 DesktopAlloc(PDESKTOP DesktopObject
, SIZE_T Size
)
196 return RtlAllocateHeap(DesktopObject
->pheapDesktop
, HEAP_NO_SERIALIZE
, Size
);
201 DesktopFree(PDESKTOP DesktopObject
, PVOID HeapBase
)
203 return RtlFreeHeap(DesktopObject
->pheapDesktop
, HEAP_NO_SERIALIZE
, HeapBase
);
208 InitDesktopImpl(VOID
)
210 /* Set Desktop Object Attributes */
211 ExDesktopObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(DESKTOP
);
212 ExDesktopObjectType
->TypeInfo
.GenericMapping
= IntDesktopMapping
;
213 return STATUS_SUCCESS
;
218 CleanupDesktopImpl(VOID
)
220 return STATUS_SUCCESS
;
223 static int GetSystemVersionString(LPWSTR buffer
)
225 RTL_OSVERSIONINFOEXW versionInfo
;
228 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
230 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
233 if (versionInfo
.dwMajorVersion
<= 4)
234 len
= swprintf(buffer
,
235 L
"ReactOS Version %d.%d %s Build %d",
236 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
237 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
239 len
= swprintf(buffer
,
240 L
"ReactOS %s (Build %d)",
241 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
248 IntParseDesktopPath(PEPROCESS Process
,
249 PUNICODE_STRING DesktopPath
,
253 OBJECT_ATTRIBUTES ObjectAttributes
;
254 UNICODE_STRING WinSta
, Desktop
, FullName
;
255 BOOL DesktopPresent
= FALSE
;
256 BOOL WinStaPresent
= FALSE
;
268 RtlInitUnicodeString(&WinSta
, NULL
);
269 RtlInitUnicodeString(&Desktop
, NULL
);
271 if(DesktopPath
!= NULL
&& DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
273 PWCHAR c
= DesktopPath
->Buffer
;
275 USHORT l
= DesktopPath
->Length
;
278 * Parse the desktop path string which can be in the form "WinSta\Desktop"
279 * or just "Desktop". In latter case WinSta0 will be used.
286 wl
= (ULONG_PTR
)c
- (ULONG_PTR
)DesktopPath
->Buffer
;
296 WinSta
.MaximumLength
= wl
+ sizeof(WCHAR
);
297 WinSta
.Buffer
= DesktopPath
->Buffer
;
299 WinStaPresent
= TRUE
;
303 Desktop
.Length
= DesktopPath
->Length
- wl
;
306 Desktop
.Length
-= sizeof(WCHAR
);
308 if(Desktop
.Length
> 0)
310 Desktop
.MaximumLength
= Desktop
.Length
+ sizeof(WCHAR
);
311 Desktop
.Buffer
= ((wl
> 0) ? c
: DesktopPath
->Buffer
);
312 DesktopPresent
= TRUE
;
319 /* search the process handle table for (inherited) window station
320 handles, use a more appropriate one than WinSta0 if possible. */
321 if (!ObFindHandleForObject(Process
,
323 ExWindowStationObjectType
,
328 /* we had no luck searching for opened handles, use WinSta0 now */
329 RtlInitUnicodeString(&WinSta
, L
"WinSta0");
333 if(!DesktopPresent
&& hDesktop
!= NULL
)
336 /* search the process handle table for (inherited) desktop
337 handles, use a more appropriate one than Default if possible. */
338 if (!ObFindHandleForObject(Process
,
345 /* we had no luck searching for opened handles, use Desktop now */
346 RtlInitUnicodeString(&Desktop
, L
"Default");
352 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, NULL
))
354 return STATUS_INSUFFICIENT_RESOURCES
;
357 /* open the window station */
358 InitializeObjectAttributes(&ObjectAttributes
,
360 OBJ_CASE_INSENSITIVE
,
364 Status
= ObOpenObjectByName(&ObjectAttributes
,
365 ExWindowStationObjectType
,
372 ExFreePoolWithTag(FullName
.Buffer
, TAG_STRING
);
374 if(!NT_SUCCESS(Status
))
376 SetLastNtError(Status
);
377 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta
, PsGetCurrentProcessId());
382 if(hDesktop
!= NULL
&& *hDesktop
== NULL
)
384 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, &Desktop
))
388 return STATUS_INSUFFICIENT_RESOURCES
;
391 /* open the desktop object */
392 InitializeObjectAttributes(&ObjectAttributes
,
394 OBJ_CASE_INSENSITIVE
,
398 Status
= ObOpenObjectByName(&ObjectAttributes
,
406 ExFreePoolWithTag(FullName
.Buffer
, TAG_STRING
);
408 if(!NT_SUCCESS(Status
))
413 SetLastNtError(Status
);
414 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop
, PsGetCurrentProcessId());
419 return STATUS_SUCCESS
;
423 * IntValidateDesktopHandle
425 * Validates the desktop handle.
428 * If the function succeeds, the handle remains referenced. If the
429 * fucntion fails, last error is set.
433 IntValidateDesktopHandle(
435 KPROCESSOR_MODE AccessMode
,
436 ACCESS_MASK DesiredAccess
,
441 Status
= ObReferenceObjectByHandle(
449 if (!NT_SUCCESS(Status
))
450 SetLastNtError(Status
);
456 IntGetDesktopWorkArea(PDESKTOP Desktop
, RECTL
*Rect
)
462 Ret
= &Desktop
->WorkArea
;
463 if((Ret
->right
== -1) && ScreenDeviceContext
)
467 dc
= DC_LockDc(ScreenDeviceContext
);
468 /* FIXME - Handle dc == NULL!!!! */
469 psurf
= SURFACE_LockSurface(dc
->rosdc
.hBitmap
);
472 Ret
->right
= psurf
->SurfObj
.sizlBitmap
.cx
;
473 Ret
->bottom
= psurf
->SurfObj
.sizlBitmap
.cy
;
474 SURFACE_UnlockSurface(psurf
);
486 IntGetActiveDesktop(VOID
)
492 * returns or creates a handle to the desktop object
495 IntGetDesktopObjectHandle(PDESKTOP DesktopObject
)
500 ASSERT(DesktopObject
);
502 if (!ObFindHandleForObject(PsGetCurrentProcess(),
508 Status
= ObOpenObjectByPointer(DesktopObject
,
515 if(!NT_SUCCESS(Status
))
517 /* unable to create a handle */
518 DPRINT1("Unable to create a desktop handle\n");
524 DPRINT1("Got handle: %lx\n", Ret
);
530 PUSER_MESSAGE_QUEUE FASTCALL
531 IntGetFocusMessageQueue(VOID
)
533 PDESKTOP pdo
= IntGetActiveDesktop();
536 DPRINT("No active desktop\n");
539 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
543 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
545 PUSER_MESSAGE_QUEUE Old
;
546 PDESKTOP pdo
= IntGetActiveDesktop();
549 DPRINT("No active desktop\n");
554 if(NewQueue
->Desktop
!= NULL
)
556 DPRINT("Message Queue already attached to another desktop!\n");
559 IntReferenceMessageQueue(NewQueue
);
560 (void)InterlockedExchangePointer((PVOID
*)&NewQueue
->Desktop
, pdo
);
562 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchangePointer((PVOID
*)&pdo
->ActiveMessageQueue
, NewQueue
);
565 (void)InterlockedExchangePointer((PVOID
*)&Old
->Desktop
, 0);
566 IntDereferenceMessageQueue(Old
);
570 HWND FASTCALL
IntGetDesktopWindow(VOID
)
572 PDESKTOP pdo
= IntGetActiveDesktop();
575 DPRINT("No active desktop\n");
578 return pdo
->DesktopWindow
;
581 PWINDOW_OBJECT FASTCALL
UserGetDesktopWindow(VOID
)
583 PDESKTOP pdo
= IntGetActiveDesktop();
587 DPRINT("No active desktop\n");
591 return UserGetWindowObject(pdo
->DesktopWindow
);
595 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
597 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
598 PDESKTOP pdo
= pti
->Desktop
;
601 DPRINT1("Thread doesn't have a desktop\n");
604 return pdo
->DesktopWindow
;
607 BOOL FASTCALL
IntDesktopUpdatePerUserSettings(BOOL bEnable
)
611 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
614 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
616 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
617 QueryTable
[0].Name
= L
"PaintDesktopVersion";
618 QueryTable
[0].EntryContext
= &g_PaintDesktopVersion
;
620 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
621 Status
= RtlQueryRegistryValues(RTL_REGISTRY_USER
,
622 L
"Control Panel\\Desktop",
623 QueryTable
, NULL
, NULL
);
624 if (!NT_SUCCESS(Status
))
626 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
628 g_PaintDesktopVersion
= FALSE
;
632 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion
);
638 g_PaintDesktopVersion
= FALSE
;
643 /* PUBLIC FUNCTIONS ***********************************************************/
648 PWINDOW_OBJECT Window
= NULL
;
650 UserEnterExclusive();
652 Window
= UserGetDesktopWindow();
654 IntInvalidateWindows( Window
,
655 Window
->UpdateRegion
,
665 co_IntShowDesktop(PDESKTOP Desktop
, ULONG Width
, ULONG Height
)
667 CSR_API_MESSAGE Request
;
669 Request
.Type
= MAKE_CSR_API(SHOW_DESKTOP
, CSR_GUI
);
670 Request
.Data
.ShowDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
671 Request
.Data
.ShowDesktopRequest
.Width
= Width
;
672 Request
.Data
.ShowDesktopRequest
.Height
= Height
;
674 return co_CsrNotify(&Request
);
678 IntHideDesktop(PDESKTOP Desktop
)
681 CSRSS_API_REQUEST Request
;
682 CSRSS_API_REPLY Reply
;
684 Request
.Type
= CSRSS_HIDE_DESKTOP
;
685 Request
.Data
.HideDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
687 return NotifyCsrss(&Request
, &Reply
);
690 PWINDOW_OBJECT DesktopWindow
;
693 DesktopWindow
= IntGetWindowObject(Desktop
->DesktopWindow
);
696 return ERROR_INVALID_WINDOW_HANDLE
;
698 DesktopWnd
= DesktopWindow
->Wnd
;
699 DesktopWnd
->Style
&= ~WS_VISIBLE
;
701 return STATUS_SUCCESS
;
710 UserBuildShellHookHwndList(PDESKTOP Desktop
)
713 PSHELL_HOOK_WINDOW Current
;
716 /* fixme: if we save nb elements in desktop, we dont have to loop to find nb entries */
717 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
720 if (!entries
) return NULL
;
722 list
= ExAllocatePool(PagedPool
, sizeof(HWND
) * (entries
+ 1)); /* alloc one extra for nullterm */
727 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
728 *cursor
++ = Current
->hWnd
;
730 *cursor
= NULL
; /* nullterm list */
737 * Send the Message to the windows registered for ShellHook
738 * notifications. The lParam contents depend on the Message. See
739 * MSDN for more details (RegisterShellHookWindow)
741 VOID
co_IntShellHookNotify(WPARAM Message
, LPARAM lParam
)
743 PDESKTOP Desktop
= IntGetActiveDesktop();
746 static UINT MsgType
= 0;
751 /* Too bad, this doesn't work.*/
754 RtlInitUnicodeString(&Str
, L
"SHELLHOOK");
755 MsgType
= UserRegisterWindowMessage(&Str
);
758 MsgType
= IntAddAtom(L
"SHELLHOOK");
760 DPRINT("MsgType = %x\n", MsgType
);
762 DPRINT1("LastError: %x\n", GetLastNtError());
767 DPRINT("IntShellHookNotify: No desktop!\n");
771 HwndList
= UserBuildShellHookHwndList(Desktop
);
774 HWND
* cursor
= HwndList
;
776 for (; *cursor
; cursor
++)
778 DPRINT("Sending notify\n");
779 co_IntPostOrSendMessage(*cursor
,
785 ExFreePool(HwndList
);
791 * Add the window to the ShellHookWindows list. The windows
792 * on that list get notifications that are important to shell
795 * TODO: Validate the window? I'm not sure if sending these messages to
796 * an unsuspecting application that is not your own is a nice thing to do.
798 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
800 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
801 PDESKTOP Desktop
= pti
->Desktop
;
802 PSHELL_HOOK_WINDOW Entry
;
804 DPRINT("IntRegisterShellHookWindow\n");
806 /* First deregister the window, so we can be sure it's never twice in the
809 IntDeRegisterShellHookWindow(hWnd
);
811 Entry
= ExAllocatePoolWithTag(PagedPool
,
812 sizeof(SHELL_HOOK_WINDOW
),
820 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
826 * Remove the window from the ShellHookWindows list. The windows
827 * on that list get notifications that are important to shell
830 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
832 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
833 PDESKTOP Desktop
= pti
->Desktop
;
834 PSHELL_HOOK_WINDOW Current
;
836 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
838 if (Current
->hWnd
== hWnd
)
840 RemoveEntryList(&Current
->ListEntry
);
850 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop
)
852 if (Desktop
->DesktopHeapSection
!= NULL
)
854 ObDereferenceObject(Desktop
->DesktopHeapSection
);
855 Desktop
->DesktopHeapSection
= NULL
;
858 /* SYSCALLS *******************************************************************/
862 * NtUserCreateDesktop
864 * Creates a new desktop.
868 * Name of the new desktop.
874 * Requested type of access.
877 * Security descriptor.
880 * Handle to window station on which to create the desktop.
883 * If the function succeeds, the return value is a handle to the newly
884 * created desktop. If the specified desktop already exists, the function
885 * succeeds and returns a handle to the existing desktop. When you are
886 * finished using the handle, call the CloseDesktop function to close it.
887 * If the function fails, the return value is NULL.
895 PUNICODE_STRING lpszDesktopName
,
897 ACCESS_MASK dwDesiredAccess
,
898 LPSECURITY_ATTRIBUTES lpSecurity
,
899 HWINSTA hWindowStation
)
901 OBJECT_ATTRIBUTES ObjectAttributes
;
902 PWINSTATION_OBJECT WinStaObject
;
903 PDESKTOP DesktopObject
;
904 UNICODE_STRING DesktopName
;
907 CSR_API_MESSAGE Request
;
908 PVOID DesktopHeapSystemBase
= NULL
;
909 SIZE_T DesktopInfoSize
;
910 UNICODE_STRING SafeDesktopName
;
912 ULONG_PTR HeapSize
= 4 * 1024 * 1024; /* FIXME */
913 DECLARE_RETURN(HDESK
);
916 DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName
);
917 UserEnterExclusive();
919 Status
= IntValidateWindowStationHandle(
922 0, /* FIXME - WINSTA_CREATEDESKTOP */
925 if (! NT_SUCCESS(Status
))
927 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
928 hWindowStation
, lpszDesktopName
);
929 SetLastNtError(Status
);
932 if(lpszDesktopName
!= NULL
)
934 Status
= IntSafeCopyUnicodeString(&SafeDesktopName
, lpszDesktopName
);
935 if(!NT_SUCCESS(Status
))
937 SetLastNtError(Status
);
943 RtlInitUnicodeString(&SafeDesktopName
, NULL
);
946 if (! IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
949 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
950 ObDereferenceObject(WinStaObject
);
952 ExFreePoolWithTag(SafeDesktopName
.Buffer
, TAG_STRING
);
956 ExFreePoolWithTag(SafeDesktopName
.Buffer
, TAG_STRING
);
957 ObDereferenceObject(WinStaObject
);
960 * Try to open already existing desktop
963 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName
);
965 /* Initialize ObjectAttributes for the desktop object */
966 InitializeObjectAttributes(
973 Status
= ObOpenObjectByName(
979 (PVOID
)&DummyContext
,
981 if (!NT_SUCCESS(Status
)) RETURN(NULL
);
982 if (Status
== STATUS_OBJECT_NAME_EXISTS
)
984 ExFreePoolWithTag(DesktopName
.Buffer
, TAG_STRING
);
988 /* Reference the desktop */
989 Status
= ObReferenceObjectByHandle(Desktop
,
993 (PVOID
)&DesktopObject
,
995 if (!NT_SUCCESS(Status
)) RETURN(NULL
);
997 DesktopObject
->DesktopHeapSection
= NULL
;
998 DesktopObject
->pheapDesktop
= UserCreateHeap(&DesktopObject
->DesktopHeapSection
,
999 &DesktopHeapSystemBase
,
1001 if (DesktopObject
->pheapDesktop
== NULL
)
1003 ObDereferenceObject(DesktopObject
);
1004 DPRINT1("Failed to create desktop heap!\n");
1008 DesktopInfoSize
= FIELD_OFFSET(DESKTOPINFO
,
1009 szDesktopName
[(lpszDesktopName
->Length
/ sizeof(WCHAR
)) + 1]);
1011 DesktopObject
->DesktopInfo
= RtlAllocateHeap(DesktopObject
->pheapDesktop
,
1015 if (DesktopObject
->DesktopInfo
== NULL
)
1017 ObDereferenceObject(DesktopObject
);
1018 DPRINT1("Failed to create the DESKTOP structure!\n");
1022 RtlZeroMemory(DesktopObject
->DesktopInfo
,
1025 DesktopObject
->DesktopInfo
->pvDesktopBase
= DesktopHeapSystemBase
;
1026 DesktopObject
->DesktopInfo
->pvDesktopLimit
= (PVOID
)((ULONG_PTR
)DesktopHeapSystemBase
+ HeapSize
);
1027 RtlCopyMemory(DesktopObject
->DesktopInfo
->szDesktopName
,
1028 lpszDesktopName
->Buffer
,
1029 lpszDesktopName
->Length
);
1031 // init desktop area
1032 DesktopObject
->WorkArea
.left
= 0;
1033 DesktopObject
->WorkArea
.top
= 0;
1034 DesktopObject
->WorkArea
.right
= -1;
1035 DesktopObject
->WorkArea
.bottom
= -1;
1036 IntGetDesktopWorkArea(DesktopObject
, NULL
);
1038 /* Initialize some local (to win32k) desktop state. */
1039 InitializeListHead(&DesktopObject
->PtiList
);
1040 DesktopObject
->ActiveMessageQueue
= NULL
;
1041 ExFreePoolWithTag(DesktopName
.Buffer
, TAG_STRING
);
1043 if (! NT_SUCCESS(Status
))
1045 DPRINT1("Failed to create desktop handle\n");
1046 SetLastNtError(Status
);
1051 * Create a handle for CSRSS and notify CSRSS
1053 Request
.Type
= MAKE_CSR_API(CREATE_DESKTOP
, CSR_GUI
);
1054 Status
= CsrInsertObject(Desktop
,
1056 (HANDLE
*)&Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
1057 if (! NT_SUCCESS(Status
))
1059 DPRINT1("Failed to create desktop handle for CSRSS\n");
1061 SetLastNtError(Status
);
1065 Status
= co_CsrNotify(&Request
);
1066 if (! NT_SUCCESS(Status
))
1068 CsrCloseHandle(Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
1069 DPRINT1("Failed to notify CSRSS about new desktop\n");
1071 SetLastNtError(Status
);
1078 DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_
);
1086 * Opens an existing desktop.
1090 * Name of the existing desktop.
1093 * Interaction flags.
1096 * Requested type of access.
1099 * Handle to the desktop or zero on failure.
1107 PUNICODE_STRING lpszDesktopName
,
1109 ACCESS_MASK dwDesiredAccess
)
1111 OBJECT_ATTRIBUTES ObjectAttributes
;
1113 PWINSTATION_OBJECT WinStaObject
;
1114 UNICODE_STRING DesktopName
;
1115 UNICODE_STRING SafeDesktopName
;
1119 DECLARE_RETURN(HDESK
);
1121 DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName
);
1122 UserEnterExclusive();
1125 * Validate the window station handle and compose the fully
1126 * qualified desktop name
1129 WinSta
= UserGetProcessWindowStation();
1130 Status
= IntValidateWindowStationHandle(
1136 if (!NT_SUCCESS(Status
))
1138 DPRINT1("Failed validation of window station handle (0x%X)\n", WinSta
);
1139 SetLastNtError(Status
);
1143 if(lpszDesktopName
!= NULL
)
1145 Status
= IntSafeCopyUnicodeString(&SafeDesktopName
, lpszDesktopName
);
1146 if(!NT_SUCCESS(Status
))
1148 SetLastNtError(Status
);
1154 RtlInitUnicodeString(&SafeDesktopName
, NULL
);
1157 Result
= IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
1160 if (lpszDesktopName
)
1161 ExFreePoolWithTag(SafeDesktopName
.Buffer
, TAG_STRING
);
1162 ObDereferenceObject(WinStaObject
);
1167 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
1172 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName
);
1174 /* Initialize ObjectAttributes for the desktop object */
1175 InitializeObjectAttributes(
1182 Status
= ObOpenObjectByName(
1184 ExDesktopObjectType
,
1191 if (!NT_SUCCESS(Status
))
1193 SetLastNtError(Status
);
1194 ExFreePool(DesktopName
.Buffer
);
1198 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
1199 ExFreePool(DesktopName
.Buffer
);
1204 DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_
);
1210 * NtUserOpenInputDesktop
1212 * Opens the input (interactive) desktop.
1216 * Interaction flags.
1219 * Inheritance option.
1222 * Requested type of access.
1225 * Handle to the input desktop or zero on failure.
1232 NtUserOpenInputDesktop(
1235 ACCESS_MASK dwDesiredAccess
)
1240 DECLARE_RETURN(HDESK
);
1242 DPRINT("Enter NtUserOpenInputDesktop\n");
1243 UserEnterExclusive();
1245 DPRINT("About to open input desktop\n");
1247 /* Get a pointer to the desktop object */
1249 Status
= IntValidateDesktopHandle(
1255 if (!NT_SUCCESS(Status
))
1257 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop
);
1261 /* Create a new handle to the object */
1263 Status
= ObOpenObjectByPointer(
1268 ExDesktopObjectType
,
1272 ObDereferenceObject(Object
);
1274 if (NT_SUCCESS(Status
))
1276 DPRINT("Successfully opened input desktop\n");
1277 RETURN((HDESK
)Desktop
);
1280 SetLastNtError(Status
);
1284 DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_
);
1290 * NtUserCloseDesktop
1292 * Closes a desktop handle.
1296 * Handle to the desktop.
1302 * The desktop handle can be created with NtUserCreateDesktop or
1303 * NtUserOpenDesktop. This function will fail if any thread in the calling
1304 * process is using the specified desktop handle or if the handle refers
1305 * to the initial desktop of the calling process.
1312 NtUserCloseDesktop(HDESK hDesktop
)
1316 DECLARE_RETURN(BOOL
);
1318 DPRINT("Enter NtUserCloseDesktop\n");
1319 UserEnterExclusive();
1321 DPRINT("About to close desktop handle (0x%X)\n", hDesktop
);
1323 Status
= IntValidateDesktopHandle(
1329 if (!NT_SUCCESS(Status
))
1331 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1335 ObDereferenceObject(Object
);
1337 DPRINT("Closing desktop handle (0x%X)\n", hDesktop
);
1339 Status
= ZwClose(hDesktop
);
1340 if (!NT_SUCCESS(Status
))
1342 SetLastNtError(Status
);
1349 DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_
);
1358 * NtUserPaintDesktop
1360 * The NtUserPaintDesktop function fills the clipping region in the
1361 * specified device context with the desktop pattern or wallpaper. The
1362 * function is provided primarily for shell desktops.
1366 * Handle to the device context.
1373 NtUserPaintDesktop(HDC hDC
)
1376 HBRUSH DesktopBrush
, PreviousBrush
;
1378 BOOL doPatBlt
= TRUE
;
1379 PWINDOW_OBJECT WndDesktop
;
1384 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1385 PWINSTATION_OBJECT WinSta
= pti
->Desktop
->WindowStation
;
1386 DECLARE_RETURN(BOOL
);
1388 UserEnterExclusive();
1389 DPRINT("Enter NtUserPaintDesktop\n");
1391 GdiGetClipBox(hDC
, &Rect
);
1393 hWndDesktop
= IntGetDesktopWindow();
1395 WndDesktop
= UserGetWindowObject(hWndDesktop
);
1401 DesktopBrush
= (HBRUSH
)UserGetClassLongPtr(WndDesktop
->Wnd
->Class
, GCL_HBRBACKGROUND
, FALSE
);
1405 * Paint desktop background
1408 if (WinSta
->hbmWallpaper
!= NULL
)
1410 PWINDOW_OBJECT DeskWin
;
1412 DeskWin
= UserGetWindowObject(hWndDesktop
);
1420 sz
.cx
= DeskWin
->Wnd
->WindowRect
.right
- DeskWin
->Wnd
->WindowRect
.left
;
1421 sz
.cy
= DeskWin
->Wnd
->WindowRect
.bottom
- DeskWin
->Wnd
->WindowRect
.top
;
1423 if (WinSta
->WallpaperMode
== wmStretch
||
1424 WinSta
->WallpaperMode
== wmTile
)
1431 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
1432 x
= (sz
.cx
/ 2) - (WinSta
->cxWallpaper
/ 2);
1433 y
= (sz
.cy
/ 2) - (WinSta
->cyWallpaper
/ 2);
1436 hWallpaperDC
= NtGdiCreateCompatibleDC(hDC
);
1437 if(hWallpaperDC
!= NULL
)
1441 /* fill in the area that the bitmap is not going to cover */
1444 /* FIXME - clip out the bitmap
1445 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1446 once we support DSTINVERT */
1447 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1448 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1449 NtGdiSelectBrush(hDC
, PreviousBrush
);
1452 /*Do not fill the background after it is painted no matter the size of the picture */
1455 hOldBitmap
= NtGdiSelectBitmap(hWallpaperDC
, WinSta
->hbmWallpaper
);
1457 if (WinSta
->WallpaperMode
== wmStretch
)
1459 if(Rect
.right
&& Rect
.bottom
)
1460 NtGdiStretchBlt(hDC
,
1468 WinSta
->cxWallpaper
,
1469 WinSta
->cyWallpaper
,
1474 else if (WinSta
->WallpaperMode
== wmTile
)
1476 /* paint the bitmap across the screen then down */
1477 for(y
= 0; y
< Rect
.bottom
; y
+= WinSta
->cyWallpaper
)
1479 for(x
= 0; x
< Rect
.right
; x
+= WinSta
->cxWallpaper
)
1484 WinSta
->cxWallpaper
,
1485 WinSta
->cyWallpaper
,
1500 WinSta
->cxWallpaper
,
1501 WinSta
->cyWallpaper
,
1509 NtGdiSelectBitmap(hWallpaperDC
, hOldBitmap
);
1510 NtGdiDeleteObjectApp(hWallpaperDC
);
1515 /* Back ground is set to none, clear the screen */
1518 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1519 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1520 NtGdiSelectBrush(hDC
, PreviousBrush
);
1524 * Display system version on the desktop background
1527 if (g_PaintDesktopVersion
)
1529 static WCHAR s_wszVersion
[256] = {0};
1534 len
= wcslen(s_wszVersion
);
1538 len
= GetSystemVersionString(s_wszVersion
);
1543 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
1545 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1546 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1549 color_old
= IntGdiSetTextColor(hDC
, RGB(255,255,255));
1550 align_old
= IntGdiSetTextAlign(hDC
, TA_RIGHT
);
1551 mode_old
= IntGdiSetBkMode(hDC
, TRANSPARENT
);
1553 GreExtTextOutW(hDC
, rect
.right
-16, rect
.bottom
-48, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1555 IntGdiSetBkMode(hDC
, mode_old
);
1556 IntGdiSetTextAlign(hDC
, align_old
);
1557 IntGdiSetTextColor(hDC
, color_old
);
1564 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_
);
1571 * NtUserSwitchDesktop
1573 * Sets the current input (interactive) desktop.
1577 * Handle to desktop.
1587 NtUserSwitchDesktop(HDESK hDesktop
)
1589 PDESKTOP DesktopObject
;
1591 DECLARE_RETURN(BOOL
);
1593 UserEnterExclusive();
1594 DPRINT("Enter NtUserSwitchDesktop\n");
1596 DPRINT("About to switch desktop (0x%X)\n", hDesktop
);
1598 Status
= IntValidateDesktopHandle(
1604 if (!NT_SUCCESS(Status
))
1606 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1611 * Don't allow applications switch the desktop if it's locked, unless the caller
1612 * is the logon application itself
1614 if((DesktopObject
->WindowStation
->Flags
& WSS_LOCKED
) &&
1615 LogonProcess
!= NULL
&& LogonProcess
!= PsGetCurrentProcessWin32Process())
1617 ObDereferenceObject(DesktopObject
);
1618 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop
);
1622 /* FIXME: Fail if the desktop belong to an invisible window station */
1623 /* FIXME: Fail if the process is associated with a secured
1624 desktop such as Winlogon or Screen-Saver */
1625 /* FIXME: Connect to input device */
1627 /* Set the active desktop in the desktop's window station. */
1628 DesktopObject
->WindowStation
->ActiveDesktop
= DesktopObject
;
1630 /* Set the global state. */
1631 InputDesktop
= DesktopObject
;
1632 InputDesktopHandle
= hDesktop
;
1633 InputWindowStation
= DesktopObject
->WindowStation
;
1635 ObDereferenceObject(DesktopObject
);
1640 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_
);
1646 * NtUserResolveDesktopForWOW
1653 NtUserResolveDesktopForWOW(DWORD Unknown0
)
1660 * NtUserGetThreadDesktop
1667 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1671 PDESKTOP DesktopObject
;
1672 HDESK Ret
, hThreadDesktop
;
1673 OBJECT_HANDLE_INFORMATION HandleInformation
;
1674 DECLARE_RETURN(HDESK
);
1676 UserEnterExclusive();
1677 DPRINT("Enter NtUserGetThreadDesktop\n");
1681 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1685 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)dwThreadId
, &Thread
);
1686 if(!NT_SUCCESS(Status
))
1688 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1692 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1694 /* just return the handle, we queried the desktop handle of a thread running
1695 in the same context */
1696 Ret
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hDesktop
;
1697 ObDereferenceObject(Thread
);
1701 /* get the desktop handle and the desktop of the thread */
1702 if(!(hThreadDesktop
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hDesktop
) ||
1703 !(DesktopObject
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->Desktop
))
1705 ObDereferenceObject(Thread
);
1706 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1710 /* we could just use DesktopObject instead of looking up the handle, but latter
1711 may be a bit safer (e.g. when the desktop is being destroyed */
1712 /* switch into the context of the thread we're trying to get the desktop from,
1713 so we can use the handle */
1714 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1715 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1717 ExDesktopObjectType
,
1719 (PVOID
*)&DesktopObject
,
1720 &HandleInformation
);
1723 /* the handle couldn't be found, there's nothing to get... */
1724 if(!NT_SUCCESS(Status
))
1726 ObDereferenceObject(Thread
);
1730 /* lookup our handle table if we can find a handle to the desktop object,
1731 if not, create one */
1732 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1734 /* all done, we got a valid handle to the desktop */
1735 ObDereferenceObject(DesktopObject
);
1736 ObDereferenceObject(Thread
);
1740 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_
);
1746 IntUnmapDesktopView(IN PDESKTOP DesktopObject
)
1749 PW32PROCESS CurrentWin32Process
;
1750 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1751 NTSTATUS Status
= STATUS_SUCCESS
;
1755 CurrentWin32Process
= PsGetCurrentProcessWin32Process();
1756 PrevLink
= &CurrentWin32Process
->HeapMappings
.Next
;
1758 /* unmap if we're the last thread using the desktop */
1759 HeapMapping
= *PrevLink
;
1760 while (HeapMapping
!= NULL
)
1762 if (HeapMapping
->KernelMapping
== (PVOID
)DesktopObject
->pheapDesktop
)
1764 if (--HeapMapping
->Count
== 0)
1766 *PrevLink
= HeapMapping
->Next
;
1768 Status
= MmUnmapViewOfSection(PsGetCurrentProcess(),
1769 HeapMapping
->UserMapping
);
1771 ObDereferenceObject(DesktopObject
);
1773 UserHeapFree(HeapMapping
);
1778 PrevLink
= &HeapMapping
->Next
;
1779 HeapMapping
= HeapMapping
->Next
;
1782 ti
= GetW32ThreadInfo();
1785 if (ti
->Desktop
== DesktopObject
->DesktopInfo
)
1789 GetWin32ClientInfo()->pDeskInfo
= NULL
;
1791 GetWin32ClientInfo()->ulClientDelta
= 0;
1797 IntMapDesktopView(IN PDESKTOP DesktopObject
)
1800 PW32PROCESS CurrentWin32Process
;
1801 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1802 PVOID UserBase
= NULL
;
1803 SIZE_T ViewSize
= 0;
1804 LARGE_INTEGER Offset
;
1807 CurrentWin32Process
= PsGetCurrentProcessWin32Process();
1808 PrevLink
= &CurrentWin32Process
->HeapMappings
.Next
;
1810 /* find out if another thread already mapped the desktop heap */
1811 HeapMapping
= *PrevLink
;
1812 while (HeapMapping
!= NULL
)
1814 if (HeapMapping
->KernelMapping
== (PVOID
)DesktopObject
->pheapDesktop
)
1816 HeapMapping
->Count
++;
1817 return STATUS_SUCCESS
;
1820 PrevLink
= &HeapMapping
->Next
;
1821 HeapMapping
= HeapMapping
->Next
;
1824 /* we're the first, map the heap */
1825 DPRINT("Noone mapped the desktop heap %p yet, so - map it!\n", DesktopObject
->pheapDesktop
);
1826 Offset
.QuadPart
= 0;
1827 Status
= MmMapViewOfSection(DesktopObject
->DesktopHeapSection
,
1828 PsGetCurrentProcess(),
1836 PAGE_EXECUTE_READ
); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
1837 if (!NT_SUCCESS(Status
))
1839 DPRINT1("Failed to map desktop\n");
1843 /* add the mapping */
1844 HeapMapping
= UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING
));
1845 if (HeapMapping
== NULL
)
1847 MmUnmapViewOfSection(PsGetCurrentProcess(),
1849 DPRINT1("UserHeapAlloc() failed!\n");
1850 return STATUS_NO_MEMORY
;
1853 HeapMapping
->Next
= NULL
;
1854 HeapMapping
->KernelMapping
= (PVOID
)DesktopObject
->pheapDesktop
;
1855 HeapMapping
->UserMapping
= UserBase
;
1856 HeapMapping
->Limit
= ViewSize
;
1857 HeapMapping
->Count
= 1;
1858 *PrevLink
= HeapMapping
;
1860 ObReferenceObject(DesktopObject
);
1862 /* create a W32THREADINFO structure if not already done, or update it */
1863 ti
= GetW32ThreadInfo();
1864 GetWin32ClientInfo()->ulClientDelta
= DesktopHeapGetUserDelta();
1867 if (ti
->Desktop
== NULL
)
1869 ti
->Desktop
= DesktopObject
->DesktopInfo
;
1870 GetWin32ClientInfo()->pDeskInfo
=
1871 (PVOID
)((ULONG_PTR
)ti
->Desktop
- GetWin32ClientInfo()->ulClientDelta
);
1875 return STATUS_SUCCESS
;
1879 IntSetThreadDesktop(IN PDESKTOP DesktopObject
,
1880 IN BOOL FreeOnFailure
)
1882 PDESKTOP OldDesktop
;
1883 PTHREADINFO W32Thread
;
1887 DPRINT("IntSetThreadDesktop() DO=%p, FOF=%d\n", DesktopObject
, FreeOnFailure
);
1888 MapHeap
= (PsGetCurrentProcess() != PsInitialSystemProcess
);
1889 W32Thread
= PsGetCurrentThreadWin32Thread();
1891 if (W32Thread
->Desktop
!= DesktopObject
)
1893 OldDesktop
= W32Thread
->Desktop
;
1895 if (!IsListEmpty(&W32Thread
->WindowListHead
))
1897 DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
1898 SetLastWin32Error(ERROR_BUSY
);
1902 W32Thread
->Desktop
= DesktopObject
;
1904 if (MapHeap
&& DesktopObject
!= NULL
)
1906 Status
= IntMapDesktopView(DesktopObject
);
1907 if (!NT_SUCCESS(Status
))
1909 SetLastNtError(Status
);
1914 if (W32Thread
->Desktop
== NULL
)
1916 PW32THREADINFO ti
= GetW32ThreadInfo();
1923 /* Hack for system threads */
1926 PCLIENTINFO pci
= GetWin32ClientInfo();
1927 pci
->ulClientDelta
= DesktopHeapGetUserDelta();
1930 pci
->pDeskInfo
= (PVOID
)((ULONG_PTR
)DesktopObject
->DesktopInfo
- pci
->ulClientDelta
);
1934 if (OldDesktop
!= NULL
&&
1935 !IntCheckProcessDesktopClasses(OldDesktop
,
1938 DPRINT1("Failed to move process classes to shared heap!\n");
1940 /* failed to move desktop classes to the shared heap,
1941 unmap the view and return the error */
1942 if (MapHeap
&& DesktopObject
!= NULL
)
1943 IntUnmapDesktopView(DesktopObject
);
1948 /* Remove the thread from the old desktop's list */
1949 RemoveEntryList(&W32Thread
->PtiLink
);
1951 if (DesktopObject
!= NULL
)
1953 ObReferenceObject(DesktopObject
);
1954 /* Insert into new desktop's list */
1955 InsertTailList(&DesktopObject
->PtiList
, &W32Thread
->PtiLink
);
1958 if (OldDesktop
!= NULL
)
1962 IntUnmapDesktopView(OldDesktop
);
1965 ObDereferenceObject(OldDesktop
);
1973 * NtUserSetThreadDesktop
1980 NtUserSetThreadDesktop(HDESK hDesktop
)
1982 PDESKTOP DesktopObject
;
1984 DECLARE_RETURN(BOOL
);
1986 UserEnterExclusive();
1987 DPRINT("Enter NtUserSetThreadDesktop\n");
1989 /* Validate the new desktop. */
1990 Status
= IntValidateDesktopHandle(
1996 if (!NT_SUCCESS(Status
))
1998 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
2002 /* FIXME: Should check here to see if the thread has any windows. */
2004 if (!IntSetThreadDesktop(DesktopObject
,
2013 DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_
);