2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
5 * FILE: subsystems/win32/win32k/ntuser/desktop.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * 06-06-2001 CSH Created
11 /* INCLUDES ******************************************************************/
24 IN OUT PDESKTOP Desktop
27 /* GLOBALS *******************************************************************/
29 /* Currently active desktop */
30 PDESKTOP InputDesktop
= NULL
;
31 HDESK InputDesktopHandle
= NULL
;
32 HDC ScreenDeviceContext
= NULL
;
33 BOOL g_PaintDesktopVersion
= FALSE
;
35 GENERIC_MAPPING IntDesktopMapping
=
37 STANDARD_RIGHTS_READ
| DESKTOP_ENUMERATE
|
39 STANDARD_RIGHTS_WRITE
| DESKTOP_CREATEMENU
|
40 DESKTOP_CREATEWINDOW
|
42 DESKTOP_JOURNALPLAYBACK
|
43 DESKTOP_JOURNALRECORD
|
45 STANDARD_RIGHTS_EXECUTE
| DESKTOP_SWITCHDESKTOP
,
46 STANDARD_RIGHTS_REQUIRED
| DESKTOP_CREATEMENU
|
47 DESKTOP_CREATEWINDOW
|
50 DESKTOP_JOURNALPLAYBACK
|
51 DESKTOP_JOURNALRECORD
|
53 DESKTOP_SWITCHDESKTOP
|
57 /* OBJECT CALLBACKS **********************************************************/
61 IntDesktopObjectParse(IN PVOID ParseObject
,
63 IN OUT PACCESS_STATE AccessState
,
64 IN KPROCESSOR_MODE AccessMode
,
66 IN OUT PUNICODE_STRING CompleteName
,
67 IN OUT PUNICODE_STRING RemainingName
,
68 IN OUT PVOID Context OPTIONAL
,
69 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
74 OBJECT_ATTRIBUTES ObjectAttributes
;
75 PLIST_ENTRY NextEntry
, ListHead
;
76 PWINSTATION_OBJECT WinStaObject
= (PWINSTATION_OBJECT
)ParseObject
;
77 PUNICODE_STRING DesktopName
;
79 /* Set the list pointers and loop the window station */
80 ListHead
= &WinStaObject
->DesktopListHead
;
81 NextEntry
= ListHead
->Flink
;
82 while (NextEntry
!= ListHead
)
84 /* Get the current desktop */
85 Desktop
= CONTAINING_RECORD(NextEntry
, DESKTOP
, ListEntry
);
88 DesktopName
= GET_DESKTOP_NAME(Desktop
);
91 /* Compare the name */
92 if (RtlEqualUnicodeString(RemainingName
,
94 (Attributes
& OBJ_CASE_INSENSITIVE
)))
96 /* We found a match. Did this come from a create? */
99 /* Unless OPEN_IF was given, fail with an error */
100 if (!(Attributes
& OBJ_OPENIF
))
103 return STATUS_OBJECT_NAME_COLLISION
;
107 /* Otherwise, return with a warning only */
108 Status
= STATUS_OBJECT_NAME_EXISTS
;
113 /* This was a real open, so this is OK */
114 Status
= STATUS_SUCCESS
;
117 /* Reference the desktop and return it */
118 ObReferenceObject(Desktop
);
124 /* Go to the next desktop */
125 NextEntry
= NextEntry
->Flink
;
128 /* If we got here but this isn't a create, then fail */
129 if (!Context
) return STATUS_OBJECT_NAME_NOT_FOUND
;
131 /* Create the desktop object */
132 InitializeObjectAttributes(&ObjectAttributes
, RemainingName
, 0, NULL
, NULL
);
133 Status
= ObCreateObject(KernelMode
,
142 if (!NT_SUCCESS(Status
)) return Status
;
144 /* Initialize shell hook window list and set the parent */
145 RtlZeroMemory(Desktop
, sizeof(DESKTOP
));
146 InitializeListHead(&Desktop
->ShellHookWindows
);
147 Desktop
->rpwinstaParent
= (PWINSTATION_OBJECT
)ParseObject
;
149 /* Put the desktop on the window station's list of associated desktops */
150 InsertTailList(&Desktop
->rpwinstaParent
->DesktopListHead
,
151 &Desktop
->ListEntry
);
153 /* Set the desktop object and return success */
155 return STATUS_SUCCESS
;
159 IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
161 PDESKTOP Desktop
= (PDESKTOP
)Parameters
->Object
;
163 DPRINT("Deleting desktop (0x%X)\n", Desktop
);
165 /* Remove the desktop from the window station's list of associcated desktops */
166 RemoveEntryList(&Desktop
->ListEntry
);
168 IntFreeDesktopHeap(Desktop
);
172 IntDesktopOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters
)
176 pti
= PsGetCurrentThreadWin32Thread();
180 /* This happens when we leak desktop handles */
184 /* Do not allow the current desktop or the initial desktop to be closed */
185 if( Parameters
->Handle
== pti
->ppi
->hdeskStartup
||
186 Parameters
->Handle
== pti
->hdesk
)
194 /* PRIVATE FUNCTIONS **********************************************************/
199 InitDesktopImpl(VOID
)
201 /* Set Desktop Object Attributes */
202 ExDesktopObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(DESKTOP
);
203 ExDesktopObjectType
->TypeInfo
.GenericMapping
= IntDesktopMapping
;
204 return STATUS_SUCCESS
;
209 CleanupDesktopImpl(VOID
)
211 return STATUS_SUCCESS
;
214 static int GetSystemVersionString(LPWSTR buffer
)
216 RTL_OSVERSIONINFOEXW versionInfo
;
219 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
221 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
224 if (versionInfo
.dwMajorVersion
<= 4)
225 len
= swprintf(buffer
,
226 L
"ReactOS Version %d.%d %s Build %d",
227 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
228 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
230 len
= swprintf(buffer
,
231 L
"ReactOS %s (Build %d)",
232 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
239 IntParseDesktopPath(PEPROCESS Process
,
240 PUNICODE_STRING DesktopPath
,
244 OBJECT_ATTRIBUTES ObjectAttributes
;
245 UNICODE_STRING WinSta
, Desktop
, FullName
;
246 BOOL DesktopPresent
= FALSE
;
247 BOOL WinStaPresent
= FALSE
;
259 RtlInitUnicodeString(&WinSta
, NULL
);
260 RtlInitUnicodeString(&Desktop
, NULL
);
262 if(DesktopPath
!= NULL
&& DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
264 PWCHAR c
= DesktopPath
->Buffer
;
266 USHORT l
= DesktopPath
->Length
;
269 * Parse the desktop path string which can be in the form "WinSta\Desktop"
270 * or just "Desktop". In latter case WinSta0 will be used.
277 wl
= (ULONG_PTR
)c
- (ULONG_PTR
)DesktopPath
->Buffer
;
287 WinSta
.MaximumLength
= wl
+ sizeof(WCHAR
);
288 WinSta
.Buffer
= DesktopPath
->Buffer
;
290 WinStaPresent
= TRUE
;
294 Desktop
.Length
= DesktopPath
->Length
- wl
;
297 Desktop
.Length
-= sizeof(WCHAR
);
299 if(Desktop
.Length
> 0)
301 Desktop
.MaximumLength
= Desktop
.Length
+ sizeof(WCHAR
);
302 Desktop
.Buffer
= ((wl
> 0) ? c
: DesktopPath
->Buffer
);
303 DesktopPresent
= TRUE
;
310 /* search the process handle table for (inherited) window station
311 handles, use a more appropriate one than WinSta0 if possible. */
312 if (!ObFindHandleForObject(Process
,
314 ExWindowStationObjectType
,
319 /* we had no luck searching for opened handles, use WinSta0 now */
320 RtlInitUnicodeString(&WinSta
, L
"WinSta0");
324 if(!DesktopPresent
&& hDesktop
!= NULL
)
327 /* search the process handle table for (inherited) desktop
328 handles, use a more appropriate one than Default if possible. */
329 if (!ObFindHandleForObject(Process
,
336 /* we had no luck searching for opened handles, use Desktop now */
337 RtlInitUnicodeString(&Desktop
, L
"Default");
343 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, NULL
))
345 return STATUS_INSUFFICIENT_RESOURCES
;
348 /* open the window station */
349 InitializeObjectAttributes(&ObjectAttributes
,
351 OBJ_CASE_INSENSITIVE
,
355 Status
= ObOpenObjectByName(&ObjectAttributes
,
356 ExWindowStationObjectType
,
363 ExFreePoolWithTag(FullName
.Buffer
, TAG_STRING
);
365 if(!NT_SUCCESS(Status
))
367 SetLastNtError(Status
);
368 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta
, PsGetCurrentProcessId());
373 if(hDesktop
!= NULL
&& *hDesktop
== NULL
)
375 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, &Desktop
))
379 return STATUS_INSUFFICIENT_RESOURCES
;
382 /* open the desktop object */
383 InitializeObjectAttributes(&ObjectAttributes
,
385 OBJ_CASE_INSENSITIVE
,
389 Status
= ObOpenObjectByName(&ObjectAttributes
,
397 ExFreePoolWithTag(FullName
.Buffer
, TAG_STRING
);
399 if(!NT_SUCCESS(Status
))
404 SetLastNtError(Status
);
405 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop
, PsGetCurrentProcessId());
410 return STATUS_SUCCESS
;
414 * IntValidateDesktopHandle
416 * Validates the desktop handle.
419 * If the function succeeds, the handle remains referenced. If the
420 * fucntion fails, last error is set.
424 IntValidateDesktopHandle(
426 KPROCESSOR_MODE AccessMode
,
427 ACCESS_MASK DesiredAccess
,
432 Status
= ObReferenceObjectByHandle(
440 if (!NT_SUCCESS(Status
))
441 SetLastNtError(Status
);
447 IntGetActiveDesktop(VOID
)
453 * returns or creates a handle to the desktop object
456 IntGetDesktopObjectHandle(PDESKTOP DesktopObject
)
461 ASSERT(DesktopObject
);
463 if (!ObFindHandleForObject(PsGetCurrentProcess(),
469 Status
= ObOpenObjectByPointer(DesktopObject
,
476 if(!NT_SUCCESS(Status
))
478 /* unable to create a handle */
479 DPRINT1("Unable to create a desktop handle\n");
485 DPRINT1("Got handle: %lx\n", Ret
);
491 PUSER_MESSAGE_QUEUE FASTCALL
492 IntGetFocusMessageQueue(VOID
)
494 PDESKTOP pdo
= IntGetActiveDesktop();
497 DPRINT("No active desktop\n");
500 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
504 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
506 PUSER_MESSAGE_QUEUE Old
;
507 PDESKTOP pdo
= IntGetActiveDesktop();
510 DPRINT("No active desktop\n");
515 if(NewQueue
->Desktop
!= NULL
)
517 DPRINT("Message Queue already attached to another desktop!\n");
520 IntReferenceMessageQueue(NewQueue
);
521 (void)InterlockedExchangePointer((PVOID
*)&NewQueue
->Desktop
, pdo
);
523 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchangePointer((PVOID
*)&pdo
->ActiveMessageQueue
, NewQueue
);
526 (void)InterlockedExchangePointer((PVOID
*)&Old
->Desktop
, 0);
527 IntDereferenceMessageQueue(Old
);
531 HWND FASTCALL
IntGetDesktopWindow(VOID
)
533 PDESKTOP pdo
= IntGetActiveDesktop();
536 DPRINT("No active desktop\n");
539 return pdo
->DesktopWindow
;
542 PWND FASTCALL
UserGetDesktopWindow(VOID
)
544 PDESKTOP pdo
= IntGetActiveDesktop();
548 DPRINT("No active desktop\n");
552 return UserGetWindowObject(pdo
->DesktopWindow
);
555 HWND FASTCALL
IntGetMessageWindow(VOID
)
557 PDESKTOP pdo
= IntGetActiveDesktop();
561 DPRINT("No active desktop\n");
564 return pdo
->spwndMessage
->head
.h
;
567 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
569 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
570 PDESKTOP pdo
= pti
->rpdesk
;
573 DPRINT1("Thread doesn't have a desktop\n");
576 return pdo
->DesktopWindow
;
579 BOOL FASTCALL
IntDesktopUpdatePerUserSettings(BOOL bEnable
)
583 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
586 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
588 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
589 QueryTable
[0].Name
= L
"PaintDesktopVersion";
590 QueryTable
[0].EntryContext
= &g_PaintDesktopVersion
;
592 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
593 Status
= RtlQueryRegistryValues(RTL_REGISTRY_USER
,
594 L
"Control Panel\\Desktop",
595 QueryTable
, NULL
, NULL
);
596 if (!NT_SUCCESS(Status
))
598 DPRINT("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
600 g_PaintDesktopVersion
= FALSE
;
604 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion
);
610 g_PaintDesktopVersion
= FALSE
;
615 /* PUBLIC FUNCTIONS ***********************************************************/
618 UserGetDesktopDC(ULONG DcType
, BOOL EmptyDC
, BOOL ValidatehWnd
)
620 PWND DesktopObject
= 0;
623 if (DcType
== DC_TYPE_DIRECT
)
625 DesktopObject
= UserGetDesktopWindow();
626 DesktopHDC
= (HDC
)UserGetWindowDC(DesktopObject
);
631 hDev
= (HDEV
)pPrimarySurface
;
632 DesktopHDC
= IntGdiCreateDisplayDC(hDev
, DcType
, EmptyDC
);
644 Window
= UserGetDesktopWindow();
645 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcWindow
);
647 IntInvalidateWindows( Window
,
654 REGION_FreeRgnByHandle(hRgn
);
659 co_IntShowDesktop(PDESKTOP Desktop
, ULONG Width
, ULONG Height
)
661 CSR_API_MESSAGE Request
;
663 Request
.Type
= MAKE_CSR_API(SHOW_DESKTOP
, CSR_GUI
);
664 Request
.Data
.ShowDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
665 Request
.Data
.ShowDesktopRequest
.Width
= Width
;
666 Request
.Data
.ShowDesktopRequest
.Height
= Height
;
668 return co_CsrNotify(&Request
);
672 IntHideDesktop(PDESKTOP Desktop
)
675 CSRSS_API_REQUEST Request
;
676 CSRSS_API_REPLY Reply
;
678 Request
.Type
= CSRSS_HIDE_DESKTOP
;
679 Request
.Data
.HideDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
681 return NotifyCsrss(&Request
, &Reply
);
686 DesktopWnd
= IntGetWindowObject(Desktop
->DesktopWindow
);
689 return ERROR_INVALID_WINDOW_HANDLE
;
691 DesktopWnd
->style
&= ~WS_VISIBLE
;
693 return STATUS_SUCCESS
;
702 UserBuildShellHookHwndList(PDESKTOP Desktop
)
705 PSHELL_HOOK_WINDOW Current
;
708 /* fixme: if we save nb elements in desktop, we dont have to loop to find nb entries */
709 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
712 if (!entries
) return NULL
;
714 list
= ExAllocatePoolWithTag(PagedPool
, sizeof(HWND
) * (entries
+ 1), USERTAG_WINDOWLIST
); /* alloc one extra for nullterm */
719 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
720 *cursor
++ = Current
->hWnd
;
722 *cursor
= NULL
; /* nullterm list */
729 * Send the Message to the windows registered for ShellHook
730 * notifications. The lParam contents depend on the Message. See
731 * MSDN for more details (RegisterShellHookWindow)
733 VOID
co_IntShellHookNotify(WPARAM Message
, LPARAM lParam
)
735 PDESKTOP Desktop
= IntGetActiveDesktop();
738 if (!gpsi
->uiShellMsg
)
741 /* Too bad, this doesn't work.*/
744 RtlInitUnicodeString(&Str
, L
"SHELLHOOK");
745 gpsi
->uiShellMsg
= UserRegisterWindowMessage(&Str
);
748 gpsi
->uiShellMsg
= IntAddAtom(L
"SHELLHOOK");
750 DPRINT("MsgType = %x\n", gpsi
->uiShellMsg
);
751 if (!gpsi
->uiShellMsg
)
752 DPRINT1("LastError: %x\n", EngGetLastError());
757 DPRINT("IntShellHookNotify: No desktop!\n");
761 HwndList
= UserBuildShellHookHwndList(Desktop
);
764 HWND
* cursor
= HwndList
;
766 for (; *cursor
; cursor
++)
768 DPRINT("Sending notify\n");
769 co_IntPostOrSendMessage(*cursor
,
775 ExFreePool(HwndList
);
781 * Add the window to the ShellHookWindows list. The windows
782 * on that list get notifications that are important to shell
785 * TODO: Validate the window? I'm not sure if sending these messages to
786 * an unsuspecting application that is not your own is a nice thing to do.
788 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
790 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
791 PDESKTOP Desktop
= pti
->rpdesk
;
792 PSHELL_HOOK_WINDOW Entry
;
794 DPRINT("IntRegisterShellHookWindow\n");
796 /* First deregister the window, so we can be sure it's never twice in the
799 IntDeRegisterShellHookWindow(hWnd
);
801 Entry
= ExAllocatePoolWithTag(PagedPool
,
802 sizeof(SHELL_HOOK_WINDOW
),
810 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
816 * Remove the window from the ShellHookWindows list. The windows
817 * on that list get notifications that are important to shell
820 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
822 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
823 PDESKTOP Desktop
= pti
->rpdesk
;
824 PSHELL_HOOK_WINDOW Current
;
826 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
828 if (Current
->hWnd
== hWnd
)
830 RemoveEntryList(&Current
->ListEntry
);
840 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop
)
842 if (Desktop
->hsectionDesktop
!= NULL
)
844 ObDereferenceObject(Desktop
->hsectionDesktop
);
845 Desktop
->hsectionDesktop
= NULL
;
848 /* SYSCALLS *******************************************************************/
851 * NtUserCreateDesktop
853 * Creates a new desktop.
860 * Name of the device.
869 * Requested type of access.
873 * If the function succeeds, the return value is a handle to the newly
874 * created desktop. If the specified desktop already exists, the function
875 * succeeds and returns a handle to the existing desktop. When you are
876 * finished using the handle, call the CloseDesktop function to close it.
877 * If the function fails, the return value is NULL.
885 POBJECT_ATTRIBUTES ObjectAttributes
,
886 PUNICODE_STRING lpszDesktopDevice
,
889 ACCESS_MASK dwDesiredAccess
)
891 PDESKTOP DesktopObject
;
892 UNICODE_STRING DesktopName
;
893 NTSTATUS Status
= STATUS_SUCCESS
;
895 CSR_API_MESSAGE Request
;
896 PVOID DesktopHeapSystemBase
= NULL
;
897 SIZE_T DesktopInfoSize
;
899 ULONG_PTR HeapSize
= 4 * 1024 * 1024; /* FIXME */
900 UNICODE_STRING ClassName
;
901 LARGE_STRING WindowName
;
902 BOOL NoHooks
= FALSE
;
906 PTHREADINFO ptiCurrent
;
907 DECLARE_RETURN(HDESK
);
909 DPRINT("Enter NtUserCreateDesktop\n");
910 UserEnterExclusive();
912 ptiCurrent
= PsGetCurrentThreadWin32Thread();
915 /* Turn off hooks when calling any CreateWindowEx from inside win32k. */
916 NoHooks
= (ptiCurrent
->TIF_flags
& TIF_DISABLEHOOKS
);
917 ptiCurrent
->TIF_flags
|= TIF_DISABLEHOOKS
;
919 DesktopName
.Buffer
= NULL
;
922 * Try to open already existing desktop
925 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName
);
927 Status
= ObOpenObjectByName(
933 (PVOID
)&DummyContext
,
935 if (!NT_SUCCESS(Status
)) RETURN(NULL
);
936 if (Status
== STATUS_OBJECT_NAME_EXISTS
)
941 /* Capture desktop name */
944 ProbeForRead( ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), 1);
946 Status
= IntSafeCopyUnicodeString(&DesktopName
, ObjectAttributes
->ObjectName
);
948 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
950 Status
= _SEH2_GetExceptionCode();
954 if (! NT_SUCCESS(Status
))
956 DPRINT1("Failed reading Object Attributes from user space.\n");
957 SetLastNtError(Status
);
961 /* Reference the desktop */
962 Status
= ObReferenceObjectByHandle(Desktop
,
966 (PVOID
)&DesktopObject
,
968 if (!NT_SUCCESS(Status
)) RETURN(NULL
);
970 DesktopObject
->hsectionDesktop
= NULL
;
971 DesktopObject
->pheapDesktop
= UserCreateHeap(&DesktopObject
->hsectionDesktop
,
972 &DesktopHeapSystemBase
,
974 if (DesktopObject
->pheapDesktop
== NULL
)
976 ObDereferenceObject(DesktopObject
);
977 DPRINT1("Failed to create desktop heap!\n");
981 DesktopInfoSize
= sizeof(DESKTOPINFO
) + DesktopName
.Length
;
983 DesktopObject
->pDeskInfo
= RtlAllocateHeap(DesktopObject
->pheapDesktop
,
987 if (DesktopObject
->pDeskInfo
== NULL
)
989 ObDereferenceObject(DesktopObject
);
990 DPRINT1("Failed to create the DESKTOP structure!\n");
994 RtlZeroMemory(DesktopObject
->pDeskInfo
,
997 DesktopObject
->pDeskInfo
->pvDesktopBase
= DesktopHeapSystemBase
;
998 DesktopObject
->pDeskInfo
->pvDesktopLimit
= (PVOID
)((ULONG_PTR
)DesktopHeapSystemBase
+ HeapSize
);
999 RtlCopyMemory(DesktopObject
->pDeskInfo
->szDesktopName
,
1001 DesktopName
.Length
);
1003 /* Initialize some local (to win32k) desktop state. */
1004 InitializeListHead(&DesktopObject
->PtiList
);
1005 DesktopObject
->ActiveMessageQueue
= NULL
;
1006 /* Setup Global Hooks. */
1007 for (i
= 0; i
< NB_HOOKS
; i
++)
1009 InitializeListHead(&DesktopObject
->pDeskInfo
->aphkStart
[i
]);
1012 //// why is this here?
1014 if (! NT_SUCCESS(Status
))
1016 DPRINT1("Failed to create desktop handle\n");
1017 SetLastNtError(Status
);
1024 * Create a handle for CSRSS and notify CSRSS for Creating Desktop Window.
1026 * Honestly, I believe this is a cleverly written hack that allowed ReactOS
1027 * to function at the beginning of the project by ramroding the GUI into
1028 * operation and making the desktop window work from user space.
1031 Request
.Type
= MAKE_CSR_API(CREATE_DESKTOP
, CSR_GUI
);
1032 Status
= CsrInsertObject(Desktop
,
1034 (HANDLE
*)&Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
1035 if (! NT_SUCCESS(Status
))
1037 DPRINT1("Failed to create desktop handle for CSRSS\n");
1039 SetLastNtError(Status
);
1043 Status
= co_CsrNotify(&Request
);
1044 if (! NT_SUCCESS(Status
))
1046 CsrCloseHandle(Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
1047 DPRINT1("Failed to notify CSRSS about new desktop\n");
1049 SetLastNtError(Status
);
1052 #if 0 // Turn on when server side proc is ready.
1054 // Create desktop window.
1056 ClassName
.Buffer
= ((PWSTR
)((ULONG_PTR
)(WORD
)(gpsi
->atomSysClass
[ICLS_DESKTOP
])));
1057 ClassName
.Length
= 0;
1058 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1060 RtlZeroMemory(&Cs
, sizeof(Cs
));
1061 Cs
.x
= UserGetSystemMetrics(SM_XVIRTUALSCREEN
);
1062 Cs
.y
= UserGetSystemMetrics(SM_YVIRTUALSCREEN
);
1063 Cs
.cx
= UserGetSystemMetrics(SM_CXVIRTUALSCREEN
);
1064 Cs
.cy
= UserGetSystemMetrics(SM_CYVIRTUALSCREEN
);
1065 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1066 Cs
.hInstance
= hModClient
; // Experimental mode... Move csr stuff to User32. hModuleWin; // Server side winproc!
1067 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1068 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1070 pWndDesktop
= co_UserCreateWindowEx(&Cs
, &ClassName
, &WindowName
);
1073 DPRINT1("Failed to create Desktop window handle\n");
1077 DesktopObject
->pDeskInfo
->spwnd
= pWndDesktop
;
1081 if (!ptiCurrent
->rpdesk
) IntSetThreadDesktop(Desktop
,FALSE
);
1084 Based on wine/server/window.c in get_desktop_window.
1087 ClassName
.Buffer
= ((PWSTR
)((ULONG_PTR
)(WORD
)(gpsi
->atomSysClass
[ICLS_HWNDMESSAGE
])));
1088 ClassName
.Length
= 0;
1089 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1091 RtlZeroMemory(&Cs
, sizeof(Cs
));
1092 Cs
.cx
= Cs
.cy
= 100;
1093 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1094 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc! Leave it to Timo to not pass on notes!
1095 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1096 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1098 pWnd
= co_UserCreateWindowEx(&Cs
, &ClassName
, &WindowName
);
1101 DPRINT1("Failed to create Message window handle\n");
1105 DesktopObject
->spwndMessage
= pWnd
;
1109 if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki)
1110 Create Tooltip. Saved in DesktopObject->spwndTooltip.
1111 Tooltip dwExStyle: WS_EX_TOOLWINDOW|WS_EX_TOPMOST
1112 hWndParent are spwndMessage. Use hModuleWin for server side winproc!
1113 The rest is same as message window.
1114 http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx
1119 if(DesktopName
.Buffer
!= NULL
)
1121 ExFreePoolWithTag(DesktopName
.Buffer
, TAG_STRING
);
1123 if (!NoHooks
&& ptiCurrent
) ptiCurrent
->TIF_flags
&= ~TIF_DISABLEHOOKS
;
1124 DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_
);
1132 * Opens an existing desktop.
1136 * Name of the existing desktop.
1139 * Interaction flags.
1142 * Requested type of access.
1145 * Handle to the desktop or zero on failure.
1153 POBJECT_ATTRIBUTES ObjectAttributes
,
1155 ACCESS_MASK dwDesiredAccess
)
1160 Status
= ObOpenObjectByName(
1162 ExDesktopObjectType
,
1169 if (!NT_SUCCESS(Status
))
1171 SetLastNtError(Status
);
1179 * NtUserOpenInputDesktop
1181 * Opens the input (interactive) desktop.
1185 * Interaction flags.
1188 * Inheritance option.
1191 * Requested type of access.
1194 * Handle to the input desktop or zero on failure.
1201 NtUserOpenInputDesktop(
1204 ACCESS_MASK dwDesiredAccess
)
1209 DECLARE_RETURN(HDESK
);
1211 DPRINT("Enter NtUserOpenInputDesktop\n");
1212 UserEnterExclusive();
1214 DPRINT("About to open input desktop\n");
1216 /* Get a pointer to the desktop object */
1218 Status
= IntValidateDesktopHandle(
1224 if (!NT_SUCCESS(Status
))
1226 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop
);
1230 /* Create a new handle to the object */
1232 Status
= ObOpenObjectByPointer(
1237 ExDesktopObjectType
,
1241 ObDereferenceObject(Object
);
1243 if (NT_SUCCESS(Status
))
1245 DPRINT("Successfully opened input desktop\n");
1246 RETURN((HDESK
)Desktop
);
1249 SetLastNtError(Status
);
1253 DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_
);
1259 * NtUserCloseDesktop
1261 * Closes a desktop handle.
1265 * Handle to the desktop.
1271 * The desktop handle can be created with NtUserCreateDesktop or
1272 * NtUserOpenDesktop. This function will fail if any thread in the calling
1273 * process is using the specified desktop handle or if the handle refers
1274 * to the initial desktop of the calling process.
1281 NtUserCloseDesktop(HDESK hDesktop
)
1285 DECLARE_RETURN(BOOL
);
1287 DPRINT("Enter NtUserCloseDesktop\n");
1288 UserEnterExclusive();
1290 DPRINT("About to close desktop handle (0x%X)\n", hDesktop
);
1292 Status
= IntValidateDesktopHandle(
1298 if (!NT_SUCCESS(Status
))
1300 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1304 ObDereferenceObject(Object
);
1306 DPRINT("Closing desktop handle (0x%X)\n", hDesktop
);
1308 Status
= ZwClose(hDesktop
);
1309 if (!NT_SUCCESS(Status
))
1311 SetLastNtError(Status
);
1318 DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_
);
1327 * NtUserPaintDesktop
1329 * The NtUserPaintDesktop function fills the clipping region in the
1330 * specified device context with the desktop pattern or wallpaper. The
1331 * function is provided primarily for shell desktops.
1335 * Handle to the device context.
1342 NtUserPaintDesktop(HDC hDC
)
1345 HBRUSH DesktopBrush
, PreviousBrush
;
1347 BOOL doPatBlt
= TRUE
;
1353 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1354 PWINSTATION_OBJECT WinSta
= pti
->rpdesk
->rpwinstaParent
;
1355 DECLARE_RETURN(BOOL
);
1357 UserEnterExclusive();
1358 DPRINT("Enter NtUserPaintDesktop\n");
1360 GdiGetClipBox(hDC
, &Rect
);
1362 hWndDesktop
= IntGetDesktopWindow();
1364 WndDesktop
= UserGetWindowObject(hWndDesktop
);
1370 DesktopBrush
= (HBRUSH
)WndDesktop
->pcls
->hbrBackground
;
1374 * Paint desktop background
1377 if (WinSta
->hbmWallpaper
!= NULL
)
1381 DeskWin
= UserGetWindowObject(hWndDesktop
);
1389 sz
.cx
= DeskWin
->rcWindow
.right
- DeskWin
->rcWindow
.left
;
1390 sz
.cy
= DeskWin
->rcWindow
.bottom
- DeskWin
->rcWindow
.top
;
1392 if (WinSta
->WallpaperMode
== wmStretch
||
1393 WinSta
->WallpaperMode
== wmTile
)
1400 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
1401 x
= (sz
.cx
/ 2) - (WinSta
->cxWallpaper
/ 2);
1402 y
= (sz
.cy
/ 2) - (WinSta
->cyWallpaper
/ 2);
1405 hWallpaperDC
= NtGdiCreateCompatibleDC(hDC
);
1406 if(hWallpaperDC
!= NULL
)
1410 /* fill in the area that the bitmap is not going to cover */
1413 /* FIXME - clip out the bitmap
1414 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1415 once we support DSTINVERT */
1416 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1417 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1418 NtGdiSelectBrush(hDC
, PreviousBrush
);
1421 /*Do not fill the background after it is painted no matter the size of the picture */
1424 hOldBitmap
= NtGdiSelectBitmap(hWallpaperDC
, WinSta
->hbmWallpaper
);
1426 if (WinSta
->WallpaperMode
== wmStretch
)
1428 if(Rect
.right
&& Rect
.bottom
)
1429 NtGdiStretchBlt(hDC
,
1437 WinSta
->cxWallpaper
,
1438 WinSta
->cyWallpaper
,
1443 else if (WinSta
->WallpaperMode
== wmTile
)
1445 /* paint the bitmap across the screen then down */
1446 for(y
= 0; y
< Rect
.bottom
; y
+= WinSta
->cyWallpaper
)
1448 for(x
= 0; x
< Rect
.right
; x
+= WinSta
->cxWallpaper
)
1453 WinSta
->cxWallpaper
,
1454 WinSta
->cyWallpaper
,
1469 WinSta
->cxWallpaper
,
1470 WinSta
->cyWallpaper
,
1478 NtGdiSelectBitmap(hWallpaperDC
, hOldBitmap
);
1479 NtGdiDeleteObjectApp(hWallpaperDC
);
1484 /* Back ground is set to none, clear the screen */
1487 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1488 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1489 NtGdiSelectBrush(hDC
, PreviousBrush
);
1493 * Display system version on the desktop background
1496 if (g_PaintDesktopVersion
)
1498 static WCHAR s_wszVersion
[256] = {0};
1503 len
= wcslen(s_wszVersion
);
1507 len
= GetSystemVersionString(s_wszVersion
);
1512 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
1514 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1515 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1518 color_old
= IntGdiSetTextColor(hDC
, RGB(255,255,255));
1519 align_old
= IntGdiSetTextAlign(hDC
, TA_RIGHT
);
1520 mode_old
= IntGdiSetBkMode(hDC
, TRANSPARENT
);
1522 GreExtTextOutW(hDC
, rect
.right
-16, rect
.bottom
-48, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1524 IntGdiSetBkMode(hDC
, mode_old
);
1525 IntGdiSetTextAlign(hDC
, align_old
);
1526 IntGdiSetTextColor(hDC
, color_old
);
1533 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_
);
1540 * NtUserSwitchDesktop
1542 * Sets the current input (interactive) desktop.
1546 * Handle to desktop.
1556 NtUserSwitchDesktop(HDESK hDesktop
)
1558 PDESKTOP DesktopObject
;
1560 DECLARE_RETURN(BOOL
);
1562 UserEnterExclusive();
1563 DPRINT("Enter NtUserSwitchDesktop\n");
1565 DPRINT("About to switch desktop (0x%X)\n", hDesktop
);
1567 Status
= IntValidateDesktopHandle(
1573 if (!NT_SUCCESS(Status
))
1575 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1580 * Don't allow applications switch the desktop if it's locked, unless the caller
1581 * is the logon application itself
1583 if((DesktopObject
->rpwinstaParent
->Flags
& WSS_LOCKED
) &&
1584 LogonProcess
!= NULL
&& LogonProcess
!= PsGetCurrentProcessWin32Process())
1586 ObDereferenceObject(DesktopObject
);
1587 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop
);
1591 if(DesktopObject
->rpwinstaParent
!= InputWindowStation
)
1593 ObDereferenceObject(DesktopObject
);
1594 DPRINT1("Switching desktop 0x%x denied because desktop doesn't belong to the interactive winsta!\n", hDesktop
);
1598 /* FIXME: Fail if the process is associated with a secured
1599 desktop such as Winlogon or Screen-Saver */
1600 /* FIXME: Connect to input device */
1602 /* Set the active desktop in the desktop's window station. */
1603 InputWindowStation
->ActiveDesktop
= DesktopObject
;
1605 /* Set the global state. */
1606 InputDesktop
= DesktopObject
;
1607 InputDesktopHandle
= hDesktop
;
1609 ObDereferenceObject(DesktopObject
);
1614 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_
);
1620 * NtUserGetThreadDesktop
1627 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1631 PDESKTOP DesktopObject
;
1632 HDESK Ret
, hThreadDesktop
;
1633 OBJECT_HANDLE_INFORMATION HandleInformation
;
1634 DECLARE_RETURN(HDESK
);
1636 UserEnterExclusive();
1637 DPRINT("Enter NtUserGetThreadDesktop\n");
1641 EngSetLastError(ERROR_INVALID_PARAMETER
);
1645 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)dwThreadId
, &Thread
);
1646 if(!NT_SUCCESS(Status
))
1648 EngSetLastError(ERROR_INVALID_PARAMETER
);
1652 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1654 /* just return the handle, we queried the desktop handle of a thread running
1655 in the same context */
1656 Ret
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
;
1657 ObDereferenceObject(Thread
);
1661 /* get the desktop handle and the desktop of the thread */
1662 if(!(hThreadDesktop
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
) ||
1663 !(DesktopObject
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->rpdesk
))
1665 ObDereferenceObject(Thread
);
1666 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1670 /* we could just use DesktopObject instead of looking up the handle, but latter
1671 may be a bit safer (e.g. when the desktop is being destroyed */
1672 /* switch into the context of the thread we're trying to get the desktop from,
1673 so we can use the handle */
1674 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1675 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1677 ExDesktopObjectType
,
1679 (PVOID
*)&DesktopObject
,
1680 &HandleInformation
);
1683 /* the handle couldn't be found, there's nothing to get... */
1684 if(!NT_SUCCESS(Status
))
1686 ObDereferenceObject(Thread
);
1690 /* lookup our handle table if we can find a handle to the desktop object,
1691 if not, create one */
1692 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1694 /* all done, we got a valid handle to the desktop */
1695 ObDereferenceObject(DesktopObject
);
1696 ObDereferenceObject(Thread
);
1700 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_
);
1706 IntUnmapDesktopView(IN PDESKTOP DesktopObject
)
1709 PPROCESSINFO CurrentWin32Process
;
1710 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1711 NTSTATUS Status
= STATUS_SUCCESS
;
1715 CurrentWin32Process
= PsGetCurrentProcessWin32Process();
1716 PrevLink
= &CurrentWin32Process
->HeapMappings
.Next
;
1718 /* unmap if we're the last thread using the desktop */
1719 HeapMapping
= *PrevLink
;
1720 while (HeapMapping
!= NULL
)
1722 if (HeapMapping
->KernelMapping
== (PVOID
)DesktopObject
->pheapDesktop
)
1724 if (--HeapMapping
->Count
== 0)
1726 *PrevLink
= HeapMapping
->Next
;
1728 Status
= MmUnmapViewOfSection(PsGetCurrentProcess(),
1729 HeapMapping
->UserMapping
);
1731 ObDereferenceObject(DesktopObject
);
1733 UserHeapFree(HeapMapping
);
1738 PrevLink
= &HeapMapping
->Next
;
1739 HeapMapping
= HeapMapping
->Next
;
1742 ti
= GetW32ThreadInfo();
1745 GetWin32ClientInfo()->pDeskInfo
= NULL
;
1747 GetWin32ClientInfo()->ulClientDelta
= 0;
1753 IntMapDesktopView(IN PDESKTOP DesktopObject
)
1755 PPROCESSINFO CurrentWin32Process
;
1756 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1757 PVOID UserBase
= NULL
;
1758 SIZE_T ViewSize
= 0;
1759 LARGE_INTEGER Offset
;
1762 CurrentWin32Process
= PsGetCurrentProcessWin32Process();
1763 PrevLink
= &CurrentWin32Process
->HeapMappings
.Next
;
1765 /* find out if another thread already mapped the desktop heap */
1766 HeapMapping
= *PrevLink
;
1767 while (HeapMapping
!= NULL
)
1769 if (HeapMapping
->KernelMapping
== (PVOID
)DesktopObject
->pheapDesktop
)
1771 HeapMapping
->Count
++;
1772 return STATUS_SUCCESS
;
1775 PrevLink
= &HeapMapping
->Next
;
1776 HeapMapping
= HeapMapping
->Next
;
1779 /* we're the first, map the heap */
1780 DPRINT("Noone mapped the desktop heap %p yet, so - map it!\n", DesktopObject
->pheapDesktop
);
1781 Offset
.QuadPart
= 0;
1782 Status
= MmMapViewOfSection(DesktopObject
->hsectionDesktop
,
1783 PsGetCurrentProcess(),
1791 PAGE_EXECUTE_READ
); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
1792 if (!NT_SUCCESS(Status
))
1794 DPRINT1("Failed to map desktop\n");
1798 /* add the mapping */
1799 HeapMapping
= UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING
));
1800 if (HeapMapping
== NULL
)
1802 MmUnmapViewOfSection(PsGetCurrentProcess(),
1804 DPRINT1("UserHeapAlloc() failed!\n");
1805 return STATUS_NO_MEMORY
;
1808 HeapMapping
->Next
= NULL
;
1809 HeapMapping
->KernelMapping
= (PVOID
)DesktopObject
->pheapDesktop
;
1810 HeapMapping
->UserMapping
= UserBase
;
1811 HeapMapping
->Limit
= ViewSize
;
1812 HeapMapping
->Count
= 1;
1813 *PrevLink
= HeapMapping
;
1815 ObReferenceObject(DesktopObject
);
1817 return STATUS_SUCCESS
;
1821 IntSetThreadDesktop(IN HDESK hDesktop
,
1822 IN BOOL FreeOnFailure
)
1824 PDESKTOP DesktopObject
= NULL
, OldDesktop
;
1826 PTHREADINFO W32Thread
;
1829 CLIENTTHREADINFO ctiSave
;
1831 DPRINT("IntSetThreadDesktop() , FOF=%d\n", FreeOnFailure
);
1832 MapHeap
= (PsGetCurrentProcess() != PsInitialSystemProcess
);
1833 W32Thread
= PsGetCurrentThreadWin32Thread();
1835 if(hDesktop
!= NULL
)
1837 /* Validate the new desktop. */
1838 Status
= IntValidateDesktopHandle(
1844 if (!NT_SUCCESS(Status
))
1846 DPRINT1("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1850 if (W32Thread
->rpdesk
== DesktopObject
)
1853 ObDereferenceObject(DesktopObject
);
1859 if (!IsListEmpty(&W32Thread
->WindowListHead
))
1861 DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
1862 EngSetLastError(ERROR_BUSY
);
1866 OldDesktop
= W32Thread
->rpdesk
;
1867 hOldDesktop
= W32Thread
->hdesk
;
1869 W32Thread
->rpdesk
= DesktopObject
;
1870 W32Thread
->hdesk
= hDesktop
;
1872 if (MapHeap
&& DesktopObject
!= NULL
)
1874 Status
= IntMapDesktopView(DesktopObject
);
1875 if (!NT_SUCCESS(Status
))
1877 SetLastNtError(Status
);
1880 W32Thread
->pDeskInfo
= DesktopObject
->pDeskInfo
;
1883 RtlZeroMemory(&ctiSave
, sizeof(CLIENTTHREADINFO
));
1885 if (W32Thread
->pcti
&& OldDesktop
&& NtCurrentTeb())
1887 RtlCopyMemory(&ctiSave
, W32Thread
->pcti
, sizeof(CLIENTTHREADINFO
));
1888 DPRINT("Free ClientThreadInfo\n");
1889 DesktopHeapFree(OldDesktop
, W32Thread
->pcti
);
1890 W32Thread
->pcti
= NULL
;
1893 if (!W32Thread
->pcti
&& DesktopObject
&& NtCurrentTeb())
1895 DPRINT("Allocate ClientThreadInfo\n");
1896 W32Thread
->pcti
= DesktopHeapAlloc( DesktopObject
,
1897 sizeof(CLIENTTHREADINFO
));
1898 RtlCopyMemory(W32Thread
->pcti
, &ctiSave
, sizeof(CLIENTTHREADINFO
));
1903 PCLIENTINFO pci
= GetWin32ClientInfo();
1904 pci
->ulClientDelta
= DesktopHeapGetUserDelta();
1907 pci
->pDeskInfo
= (PVOID
)((ULONG_PTR
)DesktopObject
->pDeskInfo
- pci
->ulClientDelta
);
1908 if (W32Thread
->pcti
) pci
->pClientThreadInfo
= (PVOID
)((ULONG_PTR
)W32Thread
->pcti
- pci
->ulClientDelta
);
1912 if (OldDesktop
!= NULL
&&
1913 !IntCheckProcessDesktopClasses(OldDesktop
,
1916 DPRINT1("Failed to move process classes to shared heap!\n");
1918 /* failed to move desktop classes to the shared heap,
1919 unmap the view and return the error */
1920 if (MapHeap
&& DesktopObject
!= NULL
)
1921 IntUnmapDesktopView(DesktopObject
);
1926 /* Remove the thread from the old desktop's list */
1927 RemoveEntryList(&W32Thread
->PtiLink
);
1929 if (DesktopObject
!= NULL
)
1931 ObReferenceObject(DesktopObject
);
1932 /* Insert into new desktop's list */
1933 InsertTailList(&DesktopObject
->PtiList
, &W32Thread
->PtiLink
);
1936 /* Close the old desktop */
1937 if (OldDesktop
!= NULL
)
1941 IntUnmapDesktopView(OldDesktop
);
1944 ObDereferenceObject(OldDesktop
);
1947 if (hOldDesktop
!= NULL
)
1949 ZwClose(hOldDesktop
);
1956 * NtUserSetThreadDesktop
1963 NtUserSetThreadDesktop(HDESK hDesktop
)
1967 UserEnterExclusive();
1969 ret
= IntSetThreadDesktop(hDesktop
, FALSE
);