2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
5 * FILE: subsystems/win32/win32k/ntuser/desktop.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
9 /* INCLUDES ******************************************************************/
12 DBG_DEFAULT_CHANNEL(UserDesktop
);
17 IN OUT PDESKTOP Desktop
20 /* GLOBALS *******************************************************************/
22 /* Currently active desktop */
23 PDESKTOP InputDesktop
= NULL
;
24 HDESK InputDesktopHandle
= NULL
;
25 HDC ScreenDeviceContext
= NULL
;
26 BOOL g_PaintDesktopVersion
= FALSE
;
28 GENERIC_MAPPING IntDesktopMapping
=
30 STANDARD_RIGHTS_READ
| DESKTOP_ENUMERATE
|
32 STANDARD_RIGHTS_WRITE
| DESKTOP_CREATEMENU
|
33 DESKTOP_CREATEWINDOW
|
35 DESKTOP_JOURNALPLAYBACK
|
36 DESKTOP_JOURNALRECORD
|
38 STANDARD_RIGHTS_EXECUTE
| DESKTOP_SWITCHDESKTOP
,
39 STANDARD_RIGHTS_REQUIRED
| DESKTOP_CREATEMENU
|
40 DESKTOP_CREATEWINDOW
|
43 DESKTOP_JOURNALPLAYBACK
|
44 DESKTOP_JOURNALRECORD
|
46 DESKTOP_SWITCHDESKTOP
|
50 /* OBJECT CALLBACKS **********************************************************/
54 IntDesktopObjectParse(IN PVOID ParseObject
,
56 IN OUT PACCESS_STATE AccessState
,
57 IN KPROCESSOR_MODE AccessMode
,
59 IN OUT PUNICODE_STRING CompleteName
,
60 IN OUT PUNICODE_STRING RemainingName
,
61 IN OUT PVOID Context OPTIONAL
,
62 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
67 OBJECT_ATTRIBUTES ObjectAttributes
;
68 PLIST_ENTRY NextEntry
, ListHead
;
69 PWINSTATION_OBJECT WinStaObject
= (PWINSTATION_OBJECT
)ParseObject
;
70 PUNICODE_STRING DesktopName
;
72 /* Set the list pointers and loop the window station */
73 ListHead
= &WinStaObject
->DesktopListHead
;
74 NextEntry
= ListHead
->Flink
;
75 while (NextEntry
!= ListHead
)
77 /* Get the current desktop */
78 Desktop
= CONTAINING_RECORD(NextEntry
, DESKTOP
, ListEntry
);
81 DesktopName
= GET_DESKTOP_NAME(Desktop
);
84 /* Compare the name */
85 if (RtlEqualUnicodeString(RemainingName
,
87 (Attributes
& OBJ_CASE_INSENSITIVE
)))
89 /* We found a match. Did this come from a create? */
92 /* Unless OPEN_IF was given, fail with an error */
93 if (!(Attributes
& OBJ_OPENIF
))
96 return STATUS_OBJECT_NAME_COLLISION
;
100 /* Otherwise, return with a warning only */
101 Status
= STATUS_OBJECT_NAME_EXISTS
;
106 /* This was a real open, so this is OK */
107 Status
= STATUS_SUCCESS
;
110 /* Reference the desktop and return it */
111 ObReferenceObject(Desktop
);
117 /* Go to the next desktop */
118 NextEntry
= NextEntry
->Flink
;
121 /* If we got here but this isn't a create, then fail */
122 if (!Context
) return STATUS_OBJECT_NAME_NOT_FOUND
;
124 /* Create the desktop object */
125 InitializeObjectAttributes(&ObjectAttributes
, RemainingName
, 0, NULL
, NULL
);
126 Status
= ObCreateObject(KernelMode
,
135 if (!NT_SUCCESS(Status
)) return Status
;
137 /* Initialize shell hook window list and set the parent */
138 RtlZeroMemory(Desktop
, sizeof(DESKTOP
));
139 InitializeListHead(&Desktop
->ShellHookWindows
);
140 Desktop
->rpwinstaParent
= (PWINSTATION_OBJECT
)ParseObject
;
142 /* Put the desktop on the window station's list of associated desktops */
143 InsertTailList(&Desktop
->rpwinstaParent
->DesktopListHead
,
144 &Desktop
->ListEntry
);
146 /* Set the desktop object and return success */
148 return STATUS_SUCCESS
;
152 IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
154 PDESKTOP Desktop
= (PDESKTOP
)Parameters
->Object
;
156 TRACE("Deleting desktop (0x%X)\n", Desktop
);
158 /* Remove the desktop from the window station's list of associcated desktops */
159 RemoveEntryList(&Desktop
->ListEntry
);
161 IntFreeDesktopHeap(Desktop
);
165 IntDesktopOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters
)
169 pti
= PsGetCurrentThreadWin32Thread();
173 /* This happens when we leak desktop handles */
174 return STATUS_SUCCESS
;
177 /* Do not allow the current desktop or the initial desktop to be closed */
178 if( Parameters
->Handle
== pti
->ppi
->hdeskStartup
||
179 Parameters
->Handle
== pti
->hdesk
)
181 return STATUS_ACCESS_DENIED
;
184 return STATUS_SUCCESS
;
187 /* PRIVATE FUNCTIONS **********************************************************/
192 InitDesktopImpl(VOID
)
194 /* Set Desktop Object Attributes */
195 ExDesktopObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(DESKTOP
);
196 ExDesktopObjectType
->TypeInfo
.GenericMapping
= IntDesktopMapping
;
197 return STATUS_SUCCESS
;
202 CleanupDesktopImpl(VOID
)
204 return STATUS_SUCCESS
;
207 static int GetSystemVersionString(LPWSTR buffer
)
209 RTL_OSVERSIONINFOEXW versionInfo
;
212 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
214 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
217 if (versionInfo
.dwMajorVersion
<= 4)
218 len
= swprintf(buffer
,
219 L
"ReactOS Version %d.%d %s Build %d",
220 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
221 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
223 len
= swprintf(buffer
,
224 L
"ReactOS %s (Build %d)",
225 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
232 IntParseDesktopPath(PEPROCESS Process
,
233 PUNICODE_STRING DesktopPath
,
237 OBJECT_ATTRIBUTES ObjectAttributes
;
238 UNICODE_STRING WinSta
, Desktop
, FullName
;
239 BOOL DesktopPresent
= FALSE
;
240 BOOL WinStaPresent
= FALSE
;
252 RtlInitUnicodeString(&WinSta
, NULL
);
253 RtlInitUnicodeString(&Desktop
, NULL
);
255 if(DesktopPath
!= NULL
&& DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
257 PWCHAR c
= DesktopPath
->Buffer
;
259 USHORT l
= DesktopPath
->Length
;
262 * Parse the desktop path string which can be in the form "WinSta\Desktop"
263 * or just "Desktop". In latter case WinSta0 will be used.
270 wl
= (ULONG_PTR
)c
- (ULONG_PTR
)DesktopPath
->Buffer
;
280 WinSta
.MaximumLength
= wl
+ sizeof(WCHAR
);
281 WinSta
.Buffer
= DesktopPath
->Buffer
;
283 WinStaPresent
= TRUE
;
287 Desktop
.Length
= DesktopPath
->Length
- wl
;
290 Desktop
.Length
-= sizeof(WCHAR
);
292 if(Desktop
.Length
> 0)
294 Desktop
.MaximumLength
= Desktop
.Length
+ sizeof(WCHAR
);
295 Desktop
.Buffer
= ((wl
> 0) ? c
: DesktopPath
->Buffer
);
296 DesktopPresent
= TRUE
;
303 /* Search the process handle table for (inherited) window station
304 handles, use a more appropriate one than WinSta0 if possible. */
305 if (!ObFindHandleForObject(Process
,
307 ExWindowStationObjectType
,
312 /* We had no luck searching for opened handles, use WinSta0 now */
313 RtlInitUnicodeString(&WinSta
, L
"WinSta0");
317 if(!DesktopPresent
&& hDesktop
!= NULL
)
320 /* Search the process handle table for (inherited) desktop
321 handles, use a more appropriate one than Default if possible. */
322 if (!ObFindHandleForObject(Process
,
329 /* We had no luck searching for opened handles, use Desktop now */
330 RtlInitUnicodeString(&Desktop
, L
"Default");
336 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, NULL
))
338 return STATUS_INSUFFICIENT_RESOURCES
;
341 /* Open the window station */
342 InitializeObjectAttributes(&ObjectAttributes
,
344 OBJ_CASE_INSENSITIVE
,
348 Status
= ObOpenObjectByName(&ObjectAttributes
,
349 ExWindowStationObjectType
,
356 ExFreePoolWithTag(FullName
.Buffer
, TAG_STRING
);
358 if(!NT_SUCCESS(Status
))
360 SetLastNtError(Status
);
361 TRACE("Failed to reference window station %wZ PID: %d!\n", &WinSta
, PsGetCurrentProcessId());
366 if(hDesktop
!= NULL
&& *hDesktop
== NULL
)
368 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, &Desktop
))
372 return STATUS_INSUFFICIENT_RESOURCES
;
375 /* Open the desktop object */
376 InitializeObjectAttributes(&ObjectAttributes
,
378 OBJ_CASE_INSENSITIVE
,
382 Status
= ObOpenObjectByName(&ObjectAttributes
,
390 ExFreePoolWithTag(FullName
.Buffer
, TAG_STRING
);
392 if(!NT_SUCCESS(Status
))
397 SetLastNtError(Status
);
398 TRACE("Failed to reference desktop %wZ PID: %d!\n", &Desktop
, PsGetCurrentProcessId());
403 return STATUS_SUCCESS
;
407 * IntValidateDesktopHandle
409 * Validates the desktop handle.
412 * If the function succeeds, the handle remains referenced. If the
413 * fucntion fails, last error is set.
417 IntValidateDesktopHandle(
419 KPROCESSOR_MODE AccessMode
,
420 ACCESS_MASK DesiredAccess
,
425 Status
= ObReferenceObjectByHandle(
433 if (!NT_SUCCESS(Status
))
434 SetLastNtError(Status
);
440 IntGetActiveDesktop(VOID
)
446 * Returns or creates a handle to the desktop object
449 IntGetDesktopObjectHandle(PDESKTOP DesktopObject
)
454 ASSERT(DesktopObject
);
456 if (!ObFindHandleForObject(PsGetCurrentProcess(),
462 Status
= ObOpenObjectByPointer(DesktopObject
,
469 if(!NT_SUCCESS(Status
))
471 /* Unable to create a handle */
472 ERR("Unable to create a desktop handle\n");
478 ERR("Got handle: %lx\n", Ret
);
484 PUSER_MESSAGE_QUEUE FASTCALL
485 IntGetFocusMessageQueue(VOID
)
487 PDESKTOP pdo
= IntGetActiveDesktop();
490 TRACE("No active desktop\n");
493 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
497 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
499 PUSER_MESSAGE_QUEUE Old
;
500 PDESKTOP pdo
= IntGetActiveDesktop();
503 TRACE("No active desktop\n");
508 if(NewQueue
->Desktop
!= NULL
)
510 TRACE("Message Queue already attached to another desktop!\n");
513 IntReferenceMessageQueue(NewQueue
);
514 (void)InterlockedExchangePointer((PVOID
*)&NewQueue
->Desktop
, pdo
);
516 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchangePointer((PVOID
*)&pdo
->ActiveMessageQueue
, NewQueue
);
519 (void)InterlockedExchangePointer((PVOID
*)&Old
->Desktop
, 0);
520 IntDereferenceMessageQueue(Old
);
524 HWND FASTCALL
IntGetDesktopWindow(VOID
)
526 PDESKTOP pdo
= IntGetActiveDesktop();
529 TRACE("No active desktop\n");
532 return pdo
->DesktopWindow
;
535 PWND FASTCALL
UserGetDesktopWindow(VOID
)
537 PDESKTOP pdo
= IntGetActiveDesktop();
541 TRACE("No active desktop\n");
545 return UserGetWindowObject(pdo
->DesktopWindow
);
548 HWND FASTCALL
IntGetMessageWindow(VOID
)
550 PDESKTOP pdo
= IntGetActiveDesktop();
554 TRACE("No active desktop\n");
557 return pdo
->spwndMessage
->head
.h
;
560 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
562 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
563 PDESKTOP pdo
= pti
->rpdesk
;
566 ERR("Thread doesn't have a desktop\n");
569 return pdo
->DesktopWindow
;
572 BOOL FASTCALL
IntDesktopUpdatePerUserSettings(BOOL bEnable
)
576 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
579 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
581 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
582 QueryTable
[0].Name
= L
"PaintDesktopVersion";
583 QueryTable
[0].EntryContext
= &g_PaintDesktopVersion
;
585 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
586 Status
= RtlQueryRegistryValues(RTL_REGISTRY_USER
,
587 L
"Control Panel\\Desktop",
588 QueryTable
, NULL
, NULL
);
589 if (!NT_SUCCESS(Status
))
591 TRACE("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
593 g_PaintDesktopVersion
= FALSE
;
597 TRACE("PaintDesktopVersion = %d\n", g_PaintDesktopVersion
);
603 g_PaintDesktopVersion
= FALSE
;
608 /* PUBLIC FUNCTIONS ***********************************************************/
611 UserGetDesktopDC(ULONG DcType
, BOOL EmptyDC
, BOOL ValidatehWnd
)
613 PWND DesktopObject
= 0;
616 if (DcType
== DC_TYPE_DIRECT
)
618 DesktopObject
= UserGetDesktopWindow();
619 DesktopHDC
= (HDC
)UserGetWindowDC(DesktopObject
);
624 hDev
= (HDEV
)pPrimarySurface
;
625 DesktopHDC
= IntGdiCreateDisplayDC(hDev
, DcType
, EmptyDC
);
637 Window
= UserGetDesktopWindow();
638 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcWindow
);
640 IntInvalidateWindows( Window
,
647 GreDeleteObject(hRgn
);
652 co_IntShowDesktop(PDESKTOP Desktop
, ULONG Width
, ULONG Height
)
654 CSR_API_MESSAGE Request
;
656 Request
.Type
= MAKE_CSR_API(SHOW_DESKTOP
, CSR_GUI
);
657 Request
.Data
.ShowDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
658 Request
.Data
.ShowDesktopRequest
.Width
= Width
;
659 Request
.Data
.ShowDesktopRequest
.Height
= Height
;
661 return co_CsrNotify(&Request
);
665 IntHideDesktop(PDESKTOP Desktop
)
668 CSRSS_API_REQUEST Request
;
669 CSRSS_API_REPLY Reply
;
671 Request
.Type
= CSRSS_HIDE_DESKTOP
;
672 Request
.Data
.HideDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
674 return NotifyCsrss(&Request
, &Reply
);
679 DesktopWnd
= IntGetWindowObject(Desktop
->DesktopWindow
);
682 return ERROR_INVALID_WINDOW_HANDLE
;
684 DesktopWnd
->style
&= ~WS_VISIBLE
;
686 return STATUS_SUCCESS
;
695 UserBuildShellHookHwndList(PDESKTOP Desktop
)
698 PSHELL_HOOK_WINDOW Current
;
701 /* FIXME: If we save nb elements in desktop, we dont have to loop to find nb entries */
702 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
705 if (!entries
) return NULL
;
707 list
= ExAllocatePoolWithTag(PagedPool
, sizeof(HWND
) * (entries
+ 1), USERTAG_WINDOWLIST
); /* alloc one extra for nullterm */
712 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
713 *cursor
++ = Current
->hWnd
;
715 *cursor
= NULL
; /* Nullterm list */
722 * Send the Message to the windows registered for ShellHook
723 * notifications. The lParam contents depend on the Message. See
724 * MSDN for more details (RegisterShellHookWindow)
726 VOID
co_IntShellHookNotify(WPARAM Message
, LPARAM lParam
)
728 PDESKTOP Desktop
= IntGetActiveDesktop();
731 if (!gpsi
->uiShellMsg
)
734 /* Too bad, this doesn't work. */
737 RtlInitUnicodeString(&Str
, L
"SHELLHOOK");
738 gpsi
->uiShellMsg
= UserRegisterWindowMessage(&Str
);
741 gpsi
->uiShellMsg
= IntAddAtom(L
"SHELLHOOK");
743 TRACE("MsgType = %x\n", gpsi
->uiShellMsg
);
744 if (!gpsi
->uiShellMsg
)
745 ERR("LastError: %x\n", EngGetLastError());
750 TRACE("IntShellHookNotify: No desktop!\n");
754 HwndList
= UserBuildShellHookHwndList(Desktop
);
757 HWND
* cursor
= HwndList
;
759 for (; *cursor
; cursor
++)
761 TRACE("Sending notify\n");
762 co_IntPostOrSendMessage(*cursor
,
768 ExFreePool(HwndList
);
774 * Add the window to the ShellHookWindows list. The windows
775 * on that list get notifications that are important to shell
778 * TODO: Validate the window? I'm not sure if sending these messages to
779 * an unsuspecting application that is not your own is a nice thing to do.
781 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
783 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
784 PDESKTOP Desktop
= pti
->rpdesk
;
785 PSHELL_HOOK_WINDOW Entry
;
787 TRACE("IntRegisterShellHookWindow\n");
789 /* First deregister the window, so we can be sure it's never twice in the
792 IntDeRegisterShellHookWindow(hWnd
);
794 Entry
= ExAllocatePoolWithTag(PagedPool
,
795 sizeof(SHELL_HOOK_WINDOW
),
803 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
809 * Remove the window from the ShellHookWindows list. The windows
810 * on that list get notifications that are important to shell
813 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
815 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
816 PDESKTOP Desktop
= pti
->rpdesk
;
817 PSHELL_HOOK_WINDOW Current
;
819 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
821 if (Current
->hWnd
== hWnd
)
823 RemoveEntryList(&Current
->ListEntry
);
833 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop
)
835 if (Desktop
->hsectionDesktop
!= NULL
)
837 ObDereferenceObject(Desktop
->hsectionDesktop
);
838 Desktop
->hsectionDesktop
= NULL
;
841 /* SYSCALLS *******************************************************************/
844 * NtUserCreateDesktop
846 * Creates a new desktop.
853 * Name of the device.
862 * Requested type of access.
866 * If the function succeeds, the return value is a handle to the newly
867 * created desktop. If the specified desktop already exists, the function
868 * succeeds and returns a handle to the existing desktop. When you are
869 * finished using the handle, call the CloseDesktop function to close it.
870 * If the function fails, the return value is NULL.
878 POBJECT_ATTRIBUTES ObjectAttributes
,
879 PUNICODE_STRING lpszDesktopDevice
,
882 ACCESS_MASK dwDesiredAccess
)
884 PDESKTOP DesktopObject
;
885 UNICODE_STRING DesktopName
;
886 NTSTATUS Status
= STATUS_SUCCESS
;
888 CSR_API_MESSAGE Request
;
889 PVOID DesktopHeapSystemBase
= NULL
;
890 SIZE_T DesktopInfoSize
;
892 ULONG_PTR HeapSize
= 4 * 1024 * 1024; /* FIXME */
893 UNICODE_STRING ClassName
;
894 LARGE_STRING WindowName
;
895 BOOL NoHooks
= FALSE
;
899 PTHREADINFO ptiCurrent
;
900 DECLARE_RETURN(HDESK
);
902 TRACE("Enter NtUserCreateDesktop\n");
903 UserEnterExclusive();
905 ptiCurrent
= PsGetCurrentThreadWin32Thread();
908 /* Turn off hooks when calling any CreateWindowEx from inside win32k. */
909 NoHooks
= (ptiCurrent
->TIF_flags
& TIF_DISABLEHOOKS
);
910 ptiCurrent
->TIF_flags
|= TIF_DISABLEHOOKS
;
912 DesktopName
.Buffer
= NULL
;
915 * Try to open already existing desktop
918 TRACE("Trying to open desktop (%wZ)\n", &DesktopName
);
920 Status
= ObOpenObjectByName(
926 (PVOID
)&DummyContext
,
928 if (!NT_SUCCESS(Status
)) RETURN(NULL
);
929 if (Status
== STATUS_OBJECT_NAME_EXISTS
)
934 /* Capture desktop name */
937 ProbeForRead( ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), 1);
939 Status
= IntSafeCopyUnicodeString(&DesktopName
, ObjectAttributes
->ObjectName
);
941 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
943 Status
= _SEH2_GetExceptionCode();
947 if (! NT_SUCCESS(Status
))
949 ERR("Failed reading Object Attributes from user space.\n");
950 SetLastNtError(Status
);
954 /* Reference the desktop */
955 Status
= ObReferenceObjectByHandle(Desktop
,
959 (PVOID
)&DesktopObject
,
961 if (!NT_SUCCESS(Status
)) RETURN(NULL
);
963 DesktopObject
->hsectionDesktop
= NULL
;
964 DesktopObject
->pheapDesktop
= UserCreateHeap(&DesktopObject
->hsectionDesktop
,
965 &DesktopHeapSystemBase
,
967 if (DesktopObject
->pheapDesktop
== NULL
)
969 ObDereferenceObject(DesktopObject
);
970 ERR("Failed to create desktop heap!\n");
974 DesktopInfoSize
= sizeof(DESKTOPINFO
) + DesktopName
.Length
;
976 DesktopObject
->pDeskInfo
= RtlAllocateHeap(DesktopObject
->pheapDesktop
,
980 if (DesktopObject
->pDeskInfo
== NULL
)
982 ObDereferenceObject(DesktopObject
);
983 ERR("Failed to create the DESKTOP structure!\n");
987 RtlZeroMemory(DesktopObject
->pDeskInfo
,
990 DesktopObject
->pDeskInfo
->pvDesktopBase
= DesktopHeapSystemBase
;
991 DesktopObject
->pDeskInfo
->pvDesktopLimit
= (PVOID
)((ULONG_PTR
)DesktopHeapSystemBase
+ HeapSize
);
992 RtlCopyMemory(DesktopObject
->pDeskInfo
->szDesktopName
,
996 /* Initialize some local (to win32k) desktop state. */
997 InitializeListHead(&DesktopObject
->PtiList
);
998 DesktopObject
->ActiveMessageQueue
= NULL
;
999 /* Setup Global Hooks. */
1000 for (i
= 0; i
< NB_HOOKS
; i
++)
1002 InitializeListHead(&DesktopObject
->pDeskInfo
->aphkStart
[i
]);
1005 //// Why is this here?
1007 if (! NT_SUCCESS(Status
))
1009 ERR("Failed to create desktop handle\n");
1010 SetLastNtError(Status
);
1017 * Create a handle for CSRSS and notify CSRSS for Creating Desktop Window.
1019 * Honestly, I believe this is a cleverly written hack that allowed ReactOS
1020 * to function at the beginning of the project by ramroding the GUI into
1021 * operation and making the desktop window work from user space.
1024 Request
.Type
= MAKE_CSR_API(CREATE_DESKTOP
, CSR_GUI
);
1025 Status
= CsrInsertObject(Desktop
,
1027 (HANDLE
*)&Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
1028 if (! NT_SUCCESS(Status
))
1030 ERR("Failed to create desktop handle for CSRSS\n");
1032 SetLastNtError(Status
);
1036 Status
= co_CsrNotify(&Request
);
1037 if (! NT_SUCCESS(Status
))
1039 CsrCloseHandle(Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
1040 ERR("Failed to notify CSRSS about new desktop\n");
1042 SetLastNtError(Status
);
1045 #if 0 // Turn on when server side proc is ready.
1047 // Create desktop window.
1049 ClassName
.Buffer
= ((PWSTR
)((ULONG_PTR
)(WORD
)(gpsi
->atomSysClass
[ICLS_DESKTOP
])));
1050 ClassName
.Length
= 0;
1051 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1053 RtlZeroMemory(&Cs
, sizeof(Cs
));
1054 Cs
.x
= UserGetSystemMetrics(SM_XVIRTUALSCREEN
);
1055 Cs
.y
= UserGetSystemMetrics(SM_YVIRTUALSCREEN
);
1056 Cs
.cx
= UserGetSystemMetrics(SM_CXVIRTUALSCREEN
);
1057 Cs
.cy
= UserGetSystemMetrics(SM_CYVIRTUALSCREEN
);
1058 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1059 Cs
.hInstance
= hModClient
; // Experimental mode... Move csr stuff to User32. hModuleWin; // Server side winproc!
1060 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1061 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1063 pWndDesktop
= co_UserCreateWindowEx(&Cs
, &ClassName
, &WindowName
, NULL
);
1066 ERR("Failed to create Desktop window handle\n");
1070 DesktopObject
->pDeskInfo
->spwnd
= pWndDesktop
;
1074 if (!ptiCurrent
->rpdesk
) IntSetThreadDesktop(Desktop
,FALSE
);
1077 Based on wine/server/window.c in get_desktop_window.
1080 ClassName
.Buffer
= ((PWSTR
)((ULONG_PTR
)(WORD
)(gpsi
->atomSysClass
[ICLS_HWNDMESSAGE
])));
1081 ClassName
.Length
= 0;
1082 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1084 RtlZeroMemory(&Cs
, sizeof(Cs
));
1085 Cs
.cx
= Cs
.cy
= 100;
1086 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1087 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc! Leave it to Timo to not pass on notes!
1088 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1089 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1091 pWnd
= co_UserCreateWindowEx(&Cs
, &ClassName
, &WindowName
, NULL
);
1094 ERR("Failed to create Message window handle\n");
1098 DesktopObject
->spwndMessage
= pWnd
;
1102 if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki)
1103 Create Tooltip. Saved in DesktopObject->spwndTooltip.
1104 Tooltip dwExStyle: WS_EX_TOOLWINDOW|WS_EX_TOPMOST
1105 hWndParent are spwndMessage. Use hModuleWin for server side winproc!
1106 The rest is same as message window.
1107 http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx
1112 if(DesktopName
.Buffer
!= NULL
)
1114 ExFreePoolWithTag(DesktopName
.Buffer
, TAG_STRING
);
1116 if (!NoHooks
&& ptiCurrent
) ptiCurrent
->TIF_flags
&= ~TIF_DISABLEHOOKS
;
1117 TRACE("Leave NtUserCreateDesktop, ret=%i\n",_ret_
);
1125 * Opens an existing desktop.
1129 * Name of the existing desktop.
1132 * Interaction flags.
1135 * Requested type of access.
1138 * Handle to the desktop or zero on failure.
1146 POBJECT_ATTRIBUTES ObjectAttributes
,
1148 ACCESS_MASK dwDesiredAccess
)
1153 Status
= ObOpenObjectByName(
1155 ExDesktopObjectType
,
1162 if (!NT_SUCCESS(Status
))
1164 SetLastNtError(Status
);
1172 * NtUserOpenInputDesktop
1174 * Opens the input (interactive) desktop.
1178 * Interaction flags.
1181 * Inheritance option.
1184 * Requested type of access.
1187 * Handle to the input desktop or zero on failure.
1194 NtUserOpenInputDesktop(
1197 ACCESS_MASK dwDesiredAccess
)
1202 DECLARE_RETURN(HDESK
);
1204 TRACE("Enter NtUserOpenInputDesktop\n");
1205 UserEnterExclusive();
1207 TRACE("About to open input desktop\n");
1209 /* Get a pointer to the desktop object */
1211 Status
= IntValidateDesktopHandle(
1217 if (!NT_SUCCESS(Status
))
1219 TRACE("Validation of input desktop handle (0x%X) failed\n", InputDesktop
);
1223 /* Create a new handle to the object */
1225 Status
= ObOpenObjectByPointer(
1230 ExDesktopObjectType
,
1234 ObDereferenceObject(Object
);
1236 if (NT_SUCCESS(Status
))
1238 TRACE("Successfully opened input desktop\n");
1239 RETURN((HDESK
)Desktop
);
1242 SetLastNtError(Status
);
1246 TRACE("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_
);
1252 * NtUserCloseDesktop
1254 * Closes a desktop handle.
1258 * Handle to the desktop.
1264 * The desktop handle can be created with NtUserCreateDesktop or
1265 * NtUserOpenDesktop. This function will fail if any thread in the calling
1266 * process is using the specified desktop handle or if the handle refers
1267 * to the initial desktop of the calling process.
1274 NtUserCloseDesktop(HDESK hDesktop
)
1278 DECLARE_RETURN(BOOL
);
1280 TRACE("Enter NtUserCloseDesktop\n");
1281 UserEnterExclusive();
1283 TRACE("About to close desktop handle (0x%X)\n", hDesktop
);
1285 Status
= IntValidateDesktopHandle(
1291 if (!NT_SUCCESS(Status
))
1293 TRACE("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1297 ObDereferenceObject(Object
);
1299 TRACE("Closing desktop handle (0x%X)\n", hDesktop
);
1301 Status
= ZwClose(hDesktop
);
1302 if (!NT_SUCCESS(Status
))
1304 SetLastNtError(Status
);
1311 TRACE("Leave NtUserCloseDesktop, ret=%i\n",_ret_
);
1320 * NtUserPaintDesktop
1322 * The NtUserPaintDesktop function fills the clipping region in the
1323 * specified device context with the desktop pattern or wallpaper. The
1324 * function is provided primarily for shell desktops.
1328 * Handle to the device context.
1335 NtUserPaintDesktop(HDC hDC
)
1338 HBRUSH DesktopBrush
, PreviousBrush
;
1340 BOOL doPatBlt
= TRUE
;
1342 static WCHAR s_wszSafeMode
[] = L
"Safe Mode";
1347 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1348 PWINSTATION_OBJECT WinSta
= pti
->rpdesk
->rpwinstaParent
;
1349 DECLARE_RETURN(BOOL
);
1351 UserEnterExclusive();
1352 TRACE("Enter NtUserPaintDesktop\n");
1354 GdiGetClipBox(hDC
, &Rect
);
1356 hWndDesktop
= IntGetDesktopWindow();
1358 WndDesktop
= UserGetWindowObject(hWndDesktop
);
1364 if (!UserGetSystemMetrics(SM_CLEANBOOT
))
1366 DesktopBrush
= (HBRUSH
)WndDesktop
->pcls
->hbrBackground
;
1369 * Paint desktop background
1371 if (WinSta
->hbmWallpaper
!= NULL
)
1377 sz
.cx
= WndDesktop
->rcWindow
.right
- WndDesktop
->rcWindow
.left
;
1378 sz
.cy
= WndDesktop
->rcWindow
.bottom
- WndDesktop
->rcWindow
.top
;
1380 if (WinSta
->WallpaperMode
== wmStretch
||
1381 WinSta
->WallpaperMode
== wmTile
)
1388 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
1389 x
= (sz
.cx
/ 2) - (WinSta
->cxWallpaper
/ 2);
1390 y
= (sz
.cy
/ 2) - (WinSta
->cyWallpaper
/ 2);
1393 hWallpaperDC
= NtGdiCreateCompatibleDC(hDC
);
1394 if(hWallpaperDC
!= NULL
)
1398 /* Fill in the area that the bitmap is not going to cover */
1401 /* FIXME: Clip out the bitmap
1402 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1403 once we support DSTINVERT */
1404 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1405 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1406 NtGdiSelectBrush(hDC
, PreviousBrush
);
1409 /*Do not fill the background after it is painted no matter the size of the picture */
1412 hOldBitmap
= NtGdiSelectBitmap(hWallpaperDC
, WinSta
->hbmWallpaper
);
1414 if (WinSta
->WallpaperMode
== wmStretch
)
1416 if(Rect
.right
&& Rect
.bottom
)
1417 NtGdiStretchBlt(hDC
,
1425 WinSta
->cxWallpaper
,
1426 WinSta
->cyWallpaper
,
1431 else if (WinSta
->WallpaperMode
== wmTile
)
1433 /* Paint the bitmap across the screen then down */
1434 for(y
= 0; y
< Rect
.bottom
; y
+= WinSta
->cyWallpaper
)
1436 for(x
= 0; x
< Rect
.right
; x
+= WinSta
->cxWallpaper
)
1441 WinSta
->cxWallpaper
,
1442 WinSta
->cyWallpaper
,
1457 WinSta
->cxWallpaper
,
1458 WinSta
->cyWallpaper
,
1466 NtGdiSelectBitmap(hWallpaperDC
, hOldBitmap
);
1467 NtGdiDeleteObjectApp(hWallpaperDC
);
1473 /* Black desktop background in Safe Mode */
1474 DesktopBrush
= StockObjects
[BLACK_BRUSH
];
1477 /* Back ground is set to none, clear the screen */
1480 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1481 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1482 NtGdiSelectBrush(hDC
, PreviousBrush
);
1486 * Display system version on the desktop background
1489 if (g_PaintDesktopVersion
||UserGetSystemMetrics(SM_CLEANBOOT
))
1491 static WCHAR s_wszVersion
[256] = {0};
1496 len
= wcslen(s_wszVersion
);
1500 len
= GetSystemVersionString(s_wszVersion
);
1505 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
1507 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1508 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1511 color_old
= IntGdiSetTextColor(hDC
, RGB(255,255,255));
1512 align_old
= IntGdiSetTextAlign(hDC
, TA_RIGHT
);
1513 mode_old
= IntGdiSetBkMode(hDC
, TRANSPARENT
);
1515 if(!UserGetSystemMetrics(SM_CLEANBOOT
))
1517 GreExtTextOutW(hDC
, rect
.right
-16, rect
.bottom
-48, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1522 /* Version information text in top center */
1523 IntGdiSetTextAlign(hDC
, TA_CENTER
|TA_TOP
);
1524 GreExtTextOutW(hDC
, (rect
.right
+rect
.left
)/2, rect
.top
, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1525 /* Safe Mode text in corners */
1526 len
= wcslen(s_wszSafeMode
);
1527 IntGdiSetTextAlign(hDC
, TA_RIGHT
|TA_TOP
);
1528 GreExtTextOutW(hDC
, rect
.right
, rect
.top
, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1529 IntGdiSetTextAlign(hDC
, TA_RIGHT
|TA_BASELINE
);
1530 GreExtTextOutW(hDC
, rect
.right
, rect
.bottom
, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1531 IntGdiSetTextAlign(hDC
, TA_LEFT
|TA_TOP
);
1532 GreExtTextOutW(hDC
, rect
.left
, rect
.top
, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1533 IntGdiSetTextAlign(hDC
, TA_LEFT
|TA_BASELINE
);
1534 GreExtTextOutW(hDC
, rect
.left
, rect
.bottom
, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1539 IntGdiSetBkMode(hDC
, mode_old
);
1540 IntGdiSetTextAlign(hDC
, align_old
);
1541 IntGdiSetTextColor(hDC
, color_old
);
1548 TRACE("Leave NtUserPaintDesktop, ret=%i\n",_ret_
);
1555 * NtUserSwitchDesktop
1557 * Sets the current input (interactive) desktop.
1561 * Handle to desktop.
1571 NtUserSwitchDesktop(HDESK hDesktop
)
1573 PDESKTOP DesktopObject
;
1575 DECLARE_RETURN(BOOL
);
1577 UserEnterExclusive();
1578 TRACE("Enter NtUserSwitchDesktop\n");
1580 TRACE("About to switch desktop (0x%X)\n", hDesktop
);
1582 Status
= IntValidateDesktopHandle(
1588 if (!NT_SUCCESS(Status
))
1590 TRACE("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1595 * Don't allow applications switch the desktop if it's locked, unless the caller
1596 * is the logon application itself
1598 if((DesktopObject
->rpwinstaParent
->Flags
& WSS_LOCKED
) &&
1599 LogonProcess
!= NULL
&& LogonProcess
!= PsGetCurrentProcessWin32Process())
1601 ObDereferenceObject(DesktopObject
);
1602 ERR("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop
);
1606 if(DesktopObject
->rpwinstaParent
!= InputWindowStation
)
1608 ObDereferenceObject(DesktopObject
);
1609 ERR("Switching desktop 0x%x denied because desktop doesn't belong to the interactive winsta!\n", hDesktop
);
1613 /* FIXME: Fail if the process is associated with a secured
1614 desktop such as Winlogon or Screen-Saver */
1615 /* FIXME: Connect to input device */
1617 /* Set the active desktop in the desktop's window station. */
1618 InputWindowStation
->ActiveDesktop
= DesktopObject
;
1620 /* Set the global state. */
1621 InputDesktop
= DesktopObject
;
1622 InputDesktopHandle
= hDesktop
;
1624 ObDereferenceObject(DesktopObject
);
1629 TRACE("Leave NtUserSwitchDesktop, ret=%i\n",_ret_
);
1635 * NtUserGetThreadDesktop
1642 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1646 PDESKTOP DesktopObject
;
1647 HDESK Ret
, hThreadDesktop
;
1648 OBJECT_HANDLE_INFORMATION HandleInformation
;
1649 DECLARE_RETURN(HDESK
);
1651 UserEnterExclusive();
1652 TRACE("Enter NtUserGetThreadDesktop\n");
1656 EngSetLastError(ERROR_INVALID_PARAMETER
);
1660 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)dwThreadId
, &Thread
);
1661 if(!NT_SUCCESS(Status
))
1663 EngSetLastError(ERROR_INVALID_PARAMETER
);
1667 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1669 /* Just return the handle, we queried the desktop handle of a thread running
1670 in the same context */
1671 Ret
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
;
1672 ObDereferenceObject(Thread
);
1676 /* Get the desktop handle and the desktop of the thread */
1677 if(!(hThreadDesktop
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
) ||
1678 !(DesktopObject
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->rpdesk
))
1680 ObDereferenceObject(Thread
);
1681 ERR("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1685 /* We could just use DesktopObject instead of looking up the handle, but latter
1686 may be a bit safer (e.g. when the desktop is being destroyed */
1687 /* Switch into the context of the thread we're trying to get the desktop from,
1688 so we can use the handle */
1689 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1690 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1692 ExDesktopObjectType
,
1694 (PVOID
*)&DesktopObject
,
1695 &HandleInformation
);
1698 /* The handle couldn't be found, there's nothing to get... */
1699 if(!NT_SUCCESS(Status
))
1701 ObDereferenceObject(Thread
);
1705 /* Lookup our handle table if we can find a handle to the desktop object,
1706 if not, create one */
1707 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1709 /* All done, we got a valid handle to the desktop */
1710 ObDereferenceObject(DesktopObject
);
1711 ObDereferenceObject(Thread
);
1715 TRACE("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_
);
1721 IntUnmapDesktopView(IN PDESKTOP DesktopObject
)
1724 PPROCESSINFO CurrentWin32Process
;
1725 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1726 NTSTATUS Status
= STATUS_SUCCESS
;
1730 CurrentWin32Process
= PsGetCurrentProcessWin32Process();
1731 PrevLink
= &CurrentWin32Process
->HeapMappings
.Next
;
1733 /* Unmap if we're the last thread using the desktop */
1734 HeapMapping
= *PrevLink
;
1735 while (HeapMapping
!= NULL
)
1737 if (HeapMapping
->KernelMapping
== (PVOID
)DesktopObject
->pheapDesktop
)
1739 if (--HeapMapping
->Count
== 0)
1741 *PrevLink
= HeapMapping
->Next
;
1743 Status
= MmUnmapViewOfSection(PsGetCurrentProcess(),
1744 HeapMapping
->UserMapping
);
1746 ObDereferenceObject(DesktopObject
);
1748 UserHeapFree(HeapMapping
);
1753 PrevLink
= &HeapMapping
->Next
;
1754 HeapMapping
= HeapMapping
->Next
;
1757 ti
= GetW32ThreadInfo();
1760 GetWin32ClientInfo()->pDeskInfo
= NULL
;
1762 GetWin32ClientInfo()->ulClientDelta
= 0;
1768 IntMapDesktopView(IN PDESKTOP DesktopObject
)
1770 PPROCESSINFO CurrentWin32Process
;
1771 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1772 PVOID UserBase
= NULL
;
1773 SIZE_T ViewSize
= 0;
1774 LARGE_INTEGER Offset
;
1777 CurrentWin32Process
= PsGetCurrentProcessWin32Process();
1778 PrevLink
= &CurrentWin32Process
->HeapMappings
.Next
;
1780 /* Find out if another thread already mapped the desktop heap */
1781 HeapMapping
= *PrevLink
;
1782 while (HeapMapping
!= NULL
)
1784 if (HeapMapping
->KernelMapping
== (PVOID
)DesktopObject
->pheapDesktop
)
1786 HeapMapping
->Count
++;
1787 return STATUS_SUCCESS
;
1790 PrevLink
= &HeapMapping
->Next
;
1791 HeapMapping
= HeapMapping
->Next
;
1794 /* We're the first, map the heap */
1795 TRACE("Noone mapped the desktop heap %p yet, so - map it!\n", DesktopObject
->pheapDesktop
);
1796 Offset
.QuadPart
= 0;
1797 Status
= MmMapViewOfSection(DesktopObject
->hsectionDesktop
,
1798 PsGetCurrentProcess(),
1806 PAGE_EXECUTE_READ
); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
1807 if (!NT_SUCCESS(Status
))
1809 ERR("Failed to map desktop\n");
1813 /* Add the mapping */
1814 HeapMapping
= UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING
));
1815 if (HeapMapping
== NULL
)
1817 MmUnmapViewOfSection(PsGetCurrentProcess(),
1819 ERR("UserHeapAlloc() failed!\n");
1820 return STATUS_NO_MEMORY
;
1823 HeapMapping
->Next
= NULL
;
1824 HeapMapping
->KernelMapping
= (PVOID
)DesktopObject
->pheapDesktop
;
1825 HeapMapping
->UserMapping
= UserBase
;
1826 HeapMapping
->Limit
= ViewSize
;
1827 HeapMapping
->Count
= 1;
1828 *PrevLink
= HeapMapping
;
1830 ObReferenceObject(DesktopObject
);
1832 return STATUS_SUCCESS
;
1836 IntSetThreadDesktop(IN HDESK hDesktop
,
1837 IN BOOL FreeOnFailure
)
1839 PDESKTOP DesktopObject
= NULL
, OldDesktop
;
1841 PTHREADINFO W32Thread
;
1844 CLIENTTHREADINFO ctiSave
;
1846 TRACE("IntSetThreadDesktop() , FOF=%d\n", FreeOnFailure
);
1847 MapHeap
= (PsGetCurrentProcess() != PsInitialSystemProcess
);
1848 W32Thread
= PsGetCurrentThreadWin32Thread();
1850 if(hDesktop
!= NULL
)
1852 /* Validate the new desktop. */
1853 Status
= IntValidateDesktopHandle(
1859 if (!NT_SUCCESS(Status
))
1861 ERR("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1865 if (W32Thread
->rpdesk
== DesktopObject
)
1868 ObDereferenceObject(DesktopObject
);
1874 if (!IsListEmpty(&W32Thread
->WindowListHead
))
1876 ERR("Attempted to change thread desktop although the thread has windows!\n");
1877 EngSetLastError(ERROR_BUSY
);
1881 OldDesktop
= W32Thread
->rpdesk
;
1882 hOldDesktop
= W32Thread
->hdesk
;
1884 W32Thread
->rpdesk
= DesktopObject
;
1885 W32Thread
->hdesk
= hDesktop
;
1887 if (MapHeap
&& DesktopObject
!= NULL
)
1889 Status
= IntMapDesktopView(DesktopObject
);
1890 if (!NT_SUCCESS(Status
))
1892 SetLastNtError(Status
);
1895 W32Thread
->pDeskInfo
= DesktopObject
->pDeskInfo
;
1898 RtlZeroMemory(&ctiSave
, sizeof(CLIENTTHREADINFO
));
1900 if (W32Thread
->pcti
&& OldDesktop
&& NtCurrentTeb())
1902 RtlCopyMemory(&ctiSave
, W32Thread
->pcti
, sizeof(CLIENTTHREADINFO
));
1903 TRACE("Free ClientThreadInfo\n");
1904 DesktopHeapFree(OldDesktop
, W32Thread
->pcti
);
1905 W32Thread
->pcti
= NULL
;
1908 if (!W32Thread
->pcti
&& DesktopObject
&& NtCurrentTeb())
1910 TRACE("Allocate ClientThreadInfo\n");
1911 W32Thread
->pcti
= DesktopHeapAlloc( DesktopObject
,
1912 sizeof(CLIENTTHREADINFO
));
1913 RtlCopyMemory(W32Thread
->pcti
, &ctiSave
, sizeof(CLIENTTHREADINFO
));
1918 PCLIENTINFO pci
= GetWin32ClientInfo();
1919 pci
->ulClientDelta
= DesktopHeapGetUserDelta();
1922 pci
->pDeskInfo
= (PVOID
)((ULONG_PTR
)DesktopObject
->pDeskInfo
- pci
->ulClientDelta
);
1923 if (W32Thread
->pcti
) pci
->pClientThreadInfo
= (PVOID
)((ULONG_PTR
)W32Thread
->pcti
- pci
->ulClientDelta
);
1927 if (OldDesktop
!= NULL
&&
1928 !IntCheckProcessDesktopClasses(OldDesktop
,
1931 ERR("Failed to move process classes to shared heap!\n");
1933 /* Failed to move desktop classes to the shared heap,
1934 unmap the view and return the error */
1935 if (MapHeap
&& DesktopObject
!= NULL
)
1936 IntUnmapDesktopView(DesktopObject
);
1941 /* Remove the thread from the old desktop's list */
1942 RemoveEntryList(&W32Thread
->PtiLink
);
1944 if (DesktopObject
!= NULL
)
1946 ObReferenceObject(DesktopObject
);
1947 /* Insert into new desktop's list */
1948 InsertTailList(&DesktopObject
->PtiList
, &W32Thread
->PtiLink
);
1951 /* Close the old desktop */
1952 if (OldDesktop
!= NULL
)
1956 IntUnmapDesktopView(OldDesktop
);
1959 ObDereferenceObject(OldDesktop
);
1962 if (hOldDesktop
!= NULL
)
1964 ZwClose(hOldDesktop
);
1971 * NtUserSetThreadDesktop
1978 NtUserSetThreadDesktop(HDESK hDesktop
)
1982 UserEnterExclusive();
1984 ret
= IntSetThreadDesktop(hDesktop
, FALSE
);