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
;
27 /* OBJECT CALLBACKS **********************************************************/
31 IntDesktopObjectParse(IN PVOID ParseObject
,
33 IN OUT PACCESS_STATE AccessState
,
34 IN KPROCESSOR_MODE AccessMode
,
36 IN OUT PUNICODE_STRING CompleteName
,
37 IN OUT PUNICODE_STRING RemainingName
,
38 IN OUT PVOID Context OPTIONAL
,
39 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
44 OBJECT_ATTRIBUTES ObjectAttributes
;
45 PLIST_ENTRY NextEntry
, ListHead
;
46 PWINSTATION_OBJECT WinStaObject
= (PWINSTATION_OBJECT
)ParseObject
;
47 PUNICODE_STRING DesktopName
;
48 PBOOLEAN pContext
= (PBOOLEAN
) Context
;
53 /* Set the list pointers and loop the window station */
54 ListHead
= &WinStaObject
->DesktopListHead
;
55 NextEntry
= ListHead
->Flink
;
56 while (NextEntry
!= ListHead
)
58 /* Get the current desktop */
59 Desktop
= CONTAINING_RECORD(NextEntry
, DESKTOP
, ListEntry
);
62 DesktopName
= GET_DESKTOP_NAME(Desktop
);
65 /* Compare the name */
66 if (RtlEqualUnicodeString(RemainingName
,
68 (Attributes
& OBJ_CASE_INSENSITIVE
)))
70 /* We found a match. Did this come from a create? */
73 /* Unless OPEN_IF was given, fail with an error */
74 if (!(Attributes
& OBJ_OPENIF
))
77 return STATUS_OBJECT_NAME_COLLISION
;
81 /* Otherwise, return with a warning only */
82 Status
= STATUS_OBJECT_NAME_EXISTS
;
87 /* This was a real open, so this is OK */
88 Status
= STATUS_SUCCESS
;
91 /* Reference the desktop and return it */
92 ObReferenceObject(Desktop
);
98 /* Go to the next desktop */
99 NextEntry
= NextEntry
->Flink
;
102 /* If we got here but this isn't a create, then fail */
103 if (!Context
) return STATUS_OBJECT_NAME_NOT_FOUND
;
105 /* Create the desktop object */
106 InitializeObjectAttributes(&ObjectAttributes
, RemainingName
, 0, NULL
, NULL
);
107 Status
= ObCreateObject(KernelMode
,
116 if (!NT_SUCCESS(Status
)) return Status
;
118 /* Initialize shell hook window list and set the parent */
119 RtlZeroMemory(Desktop
, sizeof(DESKTOP
));
120 InitializeListHead(&Desktop
->ShellHookWindows
);
121 Desktop
->rpwinstaParent
= (PWINSTATION_OBJECT
)ParseObject
;
123 /* Put the desktop on the window station's list of associated desktops */
124 InsertTailList(&Desktop
->rpwinstaParent
->DesktopListHead
,
125 &Desktop
->ListEntry
);
127 /* Set the desktop object and return success */
130 return STATUS_SUCCESS
;
134 IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
136 PDESKTOP Desktop
= (PDESKTOP
)Parameters
->Object
;
138 TRACE("Deleting desktop object 0x%p\n", Desktop
);
140 /* Remove the desktop from the window station's list of associcated desktops */
141 RemoveEntryList(&Desktop
->ListEntry
);
143 IntFreeDesktopHeap(Desktop
);
147 IntDesktopOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters
)
151 pti
= PsGetCurrentThreadWin32Thread();
155 /* This happens when we leak desktop handles */
156 return STATUS_SUCCESS
;
159 /* Do not allow the current desktop or the initial desktop to be closed */
160 if( Parameters
->Handle
== pti
->ppi
->hdeskStartup
||
161 Parameters
->Handle
== pti
->hdesk
)
163 return STATUS_ACCESS_DENIED
;
166 return STATUS_SUCCESS
;
169 /* PRIVATE FUNCTIONS **********************************************************/
174 InitDesktopImpl(VOID
)
176 GENERIC_MAPPING IntDesktopMapping
= { DESKTOP_READ
,
181 /* Set Desktop Object Attributes */
182 ExDesktopObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(DESKTOP
);
183 ExDesktopObjectType
->TypeInfo
.GenericMapping
= IntDesktopMapping
;
184 ExDesktopObjectType
->TypeInfo
.ValidAccessMask
= DESKTOP_ALL_ACCESS
;
185 return STATUS_SUCCESS
;
188 static int GetSystemVersionString(LPWSTR buffer
)
190 RTL_OSVERSIONINFOEXW versionInfo
;
193 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
195 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
198 if (versionInfo
.dwMajorVersion
<= 4)
199 len
= swprintf(buffer
,
200 L
"ReactOS Version %d.%d %s Build %d",
201 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
202 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
204 len
= swprintf(buffer
,
205 L
"ReactOS %s (Build %d)",
206 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
213 IntParseDesktopPath(PEPROCESS Process
,
214 PUNICODE_STRING DesktopPath
,
218 OBJECT_ATTRIBUTES ObjectAttributes
;
219 UNICODE_STRING ObjectName
;
221 WCHAR wstrWinstaFullName
[MAX_PATH
], *pwstrWinsta
= NULL
, *pwstrDesktop
= NULL
;
230 if(DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
233 * Parse the desktop path string which can be in the form "WinSta\Desktop"
234 * or just "Desktop". In latter case WinSta0 will be used.
237 pwstrDesktop
= wcschr(DesktopPath
->Buffer
, L
'\\');
238 if(pwstrDesktop
!= NULL
)
242 pwstrWinsta
= DesktopPath
->Buffer
;
246 pwstrDesktop
= DesktopPath
->Buffer
;
250 TRACE("IntParseDesktopPath pwstrWinsta:%S pwstrDesktop:%S\n", pwstrWinsta
, pwstrDesktop
);
254 /* Search the process handle table for (inherited) window station
255 handles, use a more appropriate one than WinSta0 if possible. */
256 if (!ObFindHandleForObject(Process
,
258 ExWindowStationObjectType
,
263 /* We had no luck searching for opened handles, use WinSta0 now */
265 pwstrWinsta
= L
"WinSta0";
269 /* Search the process handle table for (inherited) desktop
270 handles, use a more appropriate one than Default if possible. */
271 if (!ObFindHandleForObject(Process
,
278 /* We had no luck searching for opened handles, use Desktop now */
280 pwstrDesktop
= L
"Default";
285 swprintf(wstrWinstaFullName
, L
"%wZ\\%ws", &gustrWindowStationsDir
, pwstrWinsta
);
286 RtlInitUnicodeString( &ObjectName
, wstrWinstaFullName
);
288 TRACE("parsed initial winsta: %wZ\n", &ObjectName
);
290 /* Open the window station */
291 InitializeObjectAttributes(&ObjectAttributes
,
293 OBJ_CASE_INSENSITIVE
,
297 Status
= ObOpenObjectByName(&ObjectAttributes
,
298 ExWindowStationObjectType
,
305 if(!NT_SUCCESS(Status
))
307 SetLastNtError(Status
);
308 ERR("Failed to reference window station %wZ PID: --!\n", &ObjectName
);
313 if(*hDesktop
== NULL
)
315 RtlInitUnicodeString(&ObjectName
, pwstrDesktop
);
317 TRACE("parsed initial desktop: %wZ\n", &ObjectName
);
319 /* Open the desktop object */
320 InitializeObjectAttributes(&ObjectAttributes
,
322 OBJ_CASE_INSENSITIVE
,
326 Status
= ObOpenObjectByName(&ObjectAttributes
,
334 if(!NT_SUCCESS(Status
))
339 SetLastNtError(Status
);
340 ERR("Failed to reference desktop %wZ PID: --!\n", &ObjectName
);
344 return STATUS_SUCCESS
;
348 * IntValidateDesktopHandle
350 * Validates the desktop handle.
353 * If the function succeeds, the handle remains referenced. If the
354 * fucntion fails, last error is set.
358 IntValidateDesktopHandle(
360 KPROCESSOR_MODE AccessMode
,
361 ACCESS_MASK DesiredAccess
,
366 Status
= ObReferenceObjectByHandle(
374 TRACE("IntValidateDesktopHandle: handle:0x%p obj:0x%p access:0x%x Status:0x%lx\n",
375 Desktop
, *Object
, DesiredAccess
, Status
);
377 if (!NT_SUCCESS(Status
))
378 SetLastNtError(Status
);
384 IntGetActiveDesktop(VOID
)
390 * Returns or creates a handle to the desktop object
393 IntGetDesktopObjectHandle(PDESKTOP DesktopObject
)
398 ASSERT(DesktopObject
);
400 if (!ObFindHandleForObject(PsGetCurrentProcess(),
406 Status
= ObOpenObjectByPointer(DesktopObject
,
413 if(!NT_SUCCESS(Status
))
415 /* Unable to create a handle */
416 ERR("Unable to create a desktop handle\n");
422 ERR("Got handle: %p\n", Ret
);
428 PUSER_MESSAGE_QUEUE FASTCALL
429 IntGetFocusMessageQueue(VOID
)
431 PDESKTOP pdo
= IntGetActiveDesktop();
434 TRACE("No active desktop\n");
437 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
441 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
443 PUSER_MESSAGE_QUEUE Old
;
444 PDESKTOP pdo
= IntGetActiveDesktop();
447 TRACE("No active desktop\n");
452 if(NewQueue
->Desktop
!= NULL
)
454 TRACE("Message Queue already attached to another desktop!\n");
457 IntReferenceMessageQueue(NewQueue
);
458 (void)InterlockedExchangePointer((PVOID
*)&NewQueue
->Desktop
, pdo
);
460 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchangePointer((PVOID
*)&pdo
->ActiveMessageQueue
, NewQueue
);
463 (void)InterlockedExchangePointer((PVOID
*)&Old
->Desktop
, 0);
464 IntDereferenceMessageQueue(Old
);
465 gpqForegroundPrev
= Old
;
467 // Only one Q can have active foreground even when there are more than one desktop.
468 if (NewQueue
) gpqForeground
= pdo
->ActiveMessageQueue
;
469 else gpqForeground
= NULL
;
473 IntGetThreadDesktopWindow(PTHREADINFO pti
)
475 if (!pti
) pti
= PsGetCurrentThreadWin32Thread();
476 if (pti
->pDeskInfo
) return pti
->pDeskInfo
->spwnd
;
480 PWND FASTCALL
co_GetDesktopWindow(PWND pWnd
)
482 if (pWnd
->head
.rpdesk
&&
483 pWnd
->head
.rpdesk
->pDeskInfo
)
484 return pWnd
->head
.rpdesk
->pDeskInfo
->spwnd
;
488 HWND FASTCALL
IntGetDesktopWindow(VOID
)
490 PDESKTOP pdo
= IntGetActiveDesktop();
493 TRACE("No active desktop\n");
496 return pdo
->DesktopWindow
;
499 PWND FASTCALL
UserGetDesktopWindow(VOID
)
501 PDESKTOP pdo
= IntGetActiveDesktop();
505 TRACE("No active desktop\n");
508 // return pdo->pDeskInfo->spwnd;
509 return UserGetWindowObject(pdo
->DesktopWindow
);
512 HWND FASTCALL
IntGetMessageWindow(VOID
)
514 PDESKTOP pdo
= IntGetActiveDesktop();
518 TRACE("No active desktop\n");
521 return pdo
->spwndMessage
->head
.h
;
524 PWND FASTCALL
UserGetMessageWindow(VOID
)
526 PDESKTOP pdo
= IntGetActiveDesktop();
530 TRACE("No active desktop\n");
533 return pdo
->spwndMessage
;
536 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
538 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
539 PDESKTOP pdo
= pti
->rpdesk
;
542 ERR("Thread doesn't have a desktop\n");
545 return pdo
->DesktopWindow
;
548 /* PUBLIC FUNCTIONS ***********************************************************/
551 DesktopWindowProc(PWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*lResult
)
555 //ERR("DesktopWindowProc\n");
564 Wnd
->fnid
= FNID_DESKTOP
;
566 *lResult
= (LRESULT
)TRUE
;
570 Value
= HandleToULong(PsGetCurrentProcessId());
572 co_UserSetWindowLong(UserHMGetHandle(Wnd
), DT_GWL_PROCESSID
, Value
, FALSE
);
573 Value
= HandleToULong(PsGetCurrentThreadId());
575 co_UserSetWindowLong(UserHMGetHandle(Wnd
), DT_GWL_THREADID
, Value
, FALSE
);
579 case WM_DISPLAYCHANGE
:
580 co_WinPosSetWindowPos(Wnd
, 0, 0, 0, LOWORD(lParam
), HIWORD(lParam
), SWP_NOZORDER
| SWP_NOACTIVATE
);
584 IntPaintDesktop((HDC
)wParam
);
590 if (IntBeginPaint(Wnd
, &Ps
))
592 IntEndPaint(Wnd
, &Ps
);
596 case WM_SYSCOLORCHANGE
:
597 co_UserRedrawWindow(Wnd
, NULL
, NULL
, RDW_INVALIDATE
|RDW_ERASE
|RDW_ALLCHILDREN
);
600 return FALSE
; // Not processed so go with callback.
604 UserGetDesktopDC(ULONG DcType
, BOOL EmptyDC
, BOOL ValidatehWnd
)
606 PWND DesktopObject
= 0;
609 if (DcType
== DC_TYPE_DIRECT
)
611 DesktopObject
= UserGetDesktopWindow();
612 DesktopHDC
= (HDC
)UserGetWindowDC(DesktopObject
);
616 PMONITOR pMonitor
= UserGetPrimaryMonitor();
617 DesktopHDC
= IntGdiCreateDisplayDC(pMonitor
->hDev
, DcType
, EmptyDC
);
629 Window
= UserGetDesktopWindow();
630 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcWindow
);
632 IntInvalidateWindows( Window
,
639 GreDeleteObject(hRgn
);
644 co_IntShowDesktop(PDESKTOP Desktop
, ULONG Width
, ULONG Height
)
648 Window
= IntGetWindowObject(Desktop
->DesktopWindow
);
652 ERR("No Desktop window.\n");
653 return STATUS_UNSUCCESSFUL
;
655 co_WinPosSetWindowPos(Window
, NULL
, 0, 0, Width
, Height
, SWP_NOACTIVATE
|SWP_NOZORDER
|SWP_SHOWWINDOW
);
657 co_UserRedrawWindow( Window
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
);
658 return STATUS_SUCCESS
;
662 IntHideDesktop(PDESKTOP Desktop
)
666 DesktopWnd
= IntGetWindowObject(Desktop
->DesktopWindow
);
669 return ERROR_INVALID_WINDOW_HANDLE
;
671 DesktopWnd
->style
&= ~WS_VISIBLE
;
673 return STATUS_SUCCESS
;
678 UserBuildShellHookHwndList(PDESKTOP Desktop
)
681 PSHELL_HOOK_WINDOW Current
;
684 /* FIXME: If we save nb elements in desktop, we dont have to loop to find nb entries */
685 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
688 if (!entries
) return NULL
;
690 list
= ExAllocatePoolWithTag(PagedPool
, sizeof(HWND
) * (entries
+ 1), USERTAG_WINDOWLIST
); /* alloc one extra for nullterm */
695 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
696 *cursor
++ = Current
->hWnd
;
698 *cursor
= NULL
; /* Nullterm list */
705 * Send the Message to the windows registered for ShellHook
706 * notifications. The lParam contents depend on the Message. See
707 * MSDN for more details (RegisterShellHookWindow)
709 VOID
co_IntShellHookNotify(WPARAM Message
, WPARAM wParam
, LPARAM lParam
)
711 PDESKTOP Desktop
= IntGetActiveDesktop();
714 if (!gpsi
->uiShellMsg
)
716 gpsi
->uiShellMsg
= IntAddAtom(L
"SHELLHOOK");
718 TRACE("MsgType = %x\n", gpsi
->uiShellMsg
);
719 if (!gpsi
->uiShellMsg
)
720 ERR("LastError: %x\n", EngGetLastError());
725 TRACE("IntShellHookNotify: No desktop!\n");
729 // FIXME: System Tray Support.
731 HwndList
= UserBuildShellHookHwndList(Desktop
);
734 HWND
* cursor
= HwndList
;
736 for (; *cursor
; cursor
++)
738 TRACE("Sending notify\n");
739 co_IntPostOrSendMessage(*cursor
,
742 (Message
== HSHELL_LANGUAGE
? lParam
: (LPARAM
)wParam
) );
745 ExFreePoolWithTag(HwndList
, USERTAG_WINDOWLIST
);
748 if (ISITHOOKED(WH_SHELL
))
750 co_HOOK_CallHooks(WH_SHELL
, Message
, wParam
, lParam
);
755 * Add the window to the ShellHookWindows list. The windows
756 * on that list get notifications that are important to shell
759 * TODO: Validate the window? I'm not sure if sending these messages to
760 * an unsuspecting application that is not your own is a nice thing to do.
762 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
764 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
765 PDESKTOP Desktop
= pti
->rpdesk
;
766 PSHELL_HOOK_WINDOW Entry
;
768 TRACE("IntRegisterShellHookWindow\n");
770 /* First deregister the window, so we can be sure it's never twice in the
773 IntDeRegisterShellHookWindow(hWnd
);
775 Entry
= ExAllocatePoolWithTag(PagedPool
,
776 sizeof(SHELL_HOOK_WINDOW
),
784 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
790 * Remove the window from the ShellHookWindows list. The windows
791 * on that list get notifications that are important to shell
794 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
796 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
797 PDESKTOP Desktop
= pti
->rpdesk
;
798 PSHELL_HOOK_WINDOW Current
;
800 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
802 if (Current
->hWnd
== hWnd
)
804 RemoveEntryList(&Current
->ListEntry
);
805 ExFreePoolWithTag(Current
, TAG_WINSTA
);
814 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop
)
816 if (Desktop
->pheapDesktop
!= NULL
)
818 MmUnmapViewInSessionSpace(Desktop
->pheapDesktop
);
819 Desktop
->pheapDesktop
= NULL
;
822 if (Desktop
->hsectionDesktop
!= NULL
)
824 ObDereferenceObject(Desktop
->hsectionDesktop
);
825 Desktop
->hsectionDesktop
= NULL
;
830 IntPaintDesktop(HDC hDC
)
833 HBRUSH DesktopBrush
, PreviousBrush
;
835 BOOL doPatBlt
= TRUE
;
837 static WCHAR s_wszSafeMode
[] = L
"Safe Mode";
843 GdiGetClipBox(hDC
, &Rect
);
845 hWndDesktop
= IntGetDesktopWindow(); // rpdesk->DesktopWindow;
847 WndDesktop
= UserGetWindowObject(hWndDesktop
); // rpdesk->pDeskInfo->spwnd;
853 if (!UserGetSystemMetrics(SM_CLEANBOOT
))
855 DesktopBrush
= (HBRUSH
)WndDesktop
->pcls
->hbrBackground
;
858 * Paint desktop background
860 if (gspv
.hbmWallpaper
!= NULL
)
866 sz
.cx
= WndDesktop
->rcWindow
.right
- WndDesktop
->rcWindow
.left
;
867 sz
.cy
= WndDesktop
->rcWindow
.bottom
- WndDesktop
->rcWindow
.top
;
869 if (gspv
.WallpaperMode
== wmStretch
||
870 gspv
.WallpaperMode
== wmTile
)
877 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
878 x
= (sz
.cx
/ 2) - (gspv
.cxWallpaper
/ 2);
879 y
= (sz
.cy
/ 2) - (gspv
.cyWallpaper
/ 2);
882 hWallpaperDC
= NtGdiCreateCompatibleDC(hDC
);
883 if(hWallpaperDC
!= NULL
)
887 /* Fill in the area that the bitmap is not going to cover */
890 /* FIXME: Clip out the bitmap
891 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
892 once we support DSTINVERT */
893 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
894 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
895 NtGdiSelectBrush(hDC
, PreviousBrush
);
898 /*Do not fill the background after it is painted no matter the size of the picture */
901 hOldBitmap
= NtGdiSelectBitmap(hWallpaperDC
, gspv
.hbmWallpaper
);
903 if (gspv
.WallpaperMode
== wmStretch
)
905 if(Rect
.right
&& Rect
.bottom
)
920 else if (gspv
.WallpaperMode
== wmTile
)
922 /* Paint the bitmap across the screen then down */
923 for(y
= 0; y
< Rect
.bottom
; y
+= gspv
.cyWallpaper
)
925 for(x
= 0; x
< Rect
.right
; x
+= gspv
.cxWallpaper
)
955 NtGdiSelectBitmap(hWallpaperDC
, hOldBitmap
);
956 NtGdiDeleteObjectApp(hWallpaperDC
);
962 /* Black desktop background in Safe Mode */
963 DesktopBrush
= StockObjects
[BLACK_BRUSH
];
965 /* Back ground is set to none, clear the screen */
968 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
969 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
970 NtGdiSelectBrush(hDC
, PreviousBrush
);
974 * Display system version on the desktop background
977 if (g_PaintDesktopVersion
||UserGetSystemMetrics(SM_CLEANBOOT
))
979 static WCHAR s_wszVersion
[256] = {0};
984 len
= wcslen(s_wszVersion
);
988 len
= GetSystemVersionString(s_wszVersion
);
993 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
995 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
996 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
999 color_old
= IntGdiSetTextColor(hDC
, RGB(255,255,255));
1000 align_old
= IntGdiSetTextAlign(hDC
, TA_RIGHT
);
1001 mode_old
= IntGdiSetBkMode(hDC
, TRANSPARENT
);
1003 if(!UserGetSystemMetrics(SM_CLEANBOOT
))
1005 GreExtTextOutW(hDC
, rect
.right
-16, rect
.bottom
-48, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1010 /* Version information text in top center */
1011 IntGdiSetTextAlign(hDC
, TA_CENTER
|TA_TOP
);
1012 GreExtTextOutW(hDC
, (rect
.right
+rect
.left
)/2, rect
.top
, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1013 /* Safe Mode text in corners */
1014 len
= wcslen(s_wszSafeMode
);
1015 IntGdiSetTextAlign(hDC
, TA_RIGHT
|TA_TOP
);
1016 GreExtTextOutW(hDC
, rect
.right
, rect
.top
, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1017 IntGdiSetTextAlign(hDC
, TA_RIGHT
|TA_BASELINE
);
1018 GreExtTextOutW(hDC
, rect
.right
, rect
.bottom
, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1019 IntGdiSetTextAlign(hDC
, TA_LEFT
|TA_TOP
);
1020 GreExtTextOutW(hDC
, rect
.left
, rect
.top
, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1021 IntGdiSetTextAlign(hDC
, TA_LEFT
|TA_BASELINE
);
1022 GreExtTextOutW(hDC
, rect
.left
, rect
.bottom
, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1025 IntGdiSetBkMode(hDC
, mode_old
);
1026 IntGdiSetTextAlign(hDC
, align_old
);
1027 IntGdiSetTextColor(hDC
, color_old
);
1033 /* SYSCALLS *******************************************************************/
1036 * NtUserCreateDesktop
1038 * Creates a new desktop.
1042 * Object Attributes.
1045 * Name of the device.
1051 * Interaction flags.
1054 * Requested type of access.
1058 * If the function succeeds, the return value is a handle to the newly
1059 * created desktop. If the specified desktop already exists, the function
1060 * succeeds and returns a handle to the existing desktop. When you are
1061 * finished using the handle, call the CloseDesktop function to close it.
1062 * If the function fails, the return value is NULL.
1069 NtUserCreateDesktop(
1070 POBJECT_ATTRIBUTES ObjectAttributes
,
1071 PUNICODE_STRING lpszDesktopDevice
,
1074 ACCESS_MASK dwDesiredAccess
)
1076 PDESKTOP DesktopObject
;
1077 UNICODE_STRING DesktopName
;
1078 NTSTATUS Status
= STATUS_SUCCESS
;
1080 CSR_API_MESSAGE Request
;
1081 PVOID DesktopHeapSystemBase
= NULL
;
1082 SIZE_T DesktopInfoSize
;
1084 ULONG_PTR HeapSize
= 400 * 1024; /* FIXME: Windows uses 200KB by default */
1085 UNICODE_STRING ClassName
;
1086 LARGE_STRING WindowName
;
1087 BOOL NoHooks
= FALSE
;
1091 PTHREADINFO ptiCurrent
;
1092 DECLARE_RETURN(HDESK
);
1094 TRACE("Enter NtUserCreateDesktop\n");
1095 UserEnterExclusive();
1097 ptiCurrent
= PsGetCurrentThreadWin32Thread();
1100 /* Turn off hooks when calling any CreateWindowEx from inside win32k. */
1101 NoHooks
= (ptiCurrent
->TIF_flags
& TIF_DISABLEHOOKS
);
1102 ptiCurrent
->TIF_flags
|= TIF_DISABLEHOOKS
;
1103 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
1106 {ERR("NtUserCreateDesktop: No ptiCurrent\n");}*/
1107 DesktopName
.Buffer
= NULL
;
1110 * Try to open already existing desktop
1113 Status
= ObOpenObjectByName(
1115 ExDesktopObjectType
,
1121 if (!NT_SUCCESS(Status
)) RETURN(NULL
);
1123 /* In case the object was not created (eg if it existed), return now */
1124 if (Context
== FALSE
)
1126 TRACE("NtUserCreateDesktop opened desktop %wZ\n", ObjectAttributes
->ObjectName
);
1130 /* Capture desktop name */
1133 ProbeForRead( ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
), 1);
1135 Status
= IntSafeCopyUnicodeStringTerminateNULL(&DesktopName
, ObjectAttributes
->ObjectName
);
1137 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1139 Status
= _SEH2_GetExceptionCode();
1143 if (! NT_SUCCESS(Status
))
1145 ERR("Failed reading Object Attributes from user space.\n");
1146 SetLastNtError(Status
);
1150 /* Reference the desktop */
1151 Status
= ObReferenceObjectByHandle(Desktop
,
1153 ExDesktopObjectType
,
1155 (PVOID
)&DesktopObject
,
1157 if (!NT_SUCCESS(Status
))
1159 ERR("Failed to reference desktop object\n");
1163 TRACE("NtUserCreateDesktop created desktop 0x%p with name %wZ\n", DesktopObject
, &DesktopName
);
1165 DesktopObject
->hsectionDesktop
= NULL
;
1166 DesktopObject
->pheapDesktop
= UserCreateHeap(&DesktopObject
->hsectionDesktop
,
1167 &DesktopHeapSystemBase
,
1169 if (DesktopObject
->pheapDesktop
== NULL
)
1171 ObDereferenceObject(DesktopObject
);
1172 ERR("Failed to create desktop heap!\n");
1176 DesktopInfoSize
= sizeof(DESKTOPINFO
) + DesktopName
.Length
+ sizeof(WCHAR
);
1178 DesktopObject
->pDeskInfo
= RtlAllocateHeap(DesktopObject
->pheapDesktop
,
1182 if (DesktopObject
->pDeskInfo
== NULL
)
1184 ObDereferenceObject(DesktopObject
);
1185 ERR("Failed to create the DESKTOP structure!\n");
1189 RtlZeroMemory(DesktopObject
->pDeskInfo
,
1192 DesktopObject
->pDeskInfo
->pvDesktopBase
= DesktopHeapSystemBase
;
1193 DesktopObject
->pDeskInfo
->pvDesktopLimit
= (PVOID
)((ULONG_PTR
)DesktopHeapSystemBase
+ HeapSize
);
1194 RtlCopyMemory(DesktopObject
->pDeskInfo
->szDesktopName
,
1196 DesktopName
.Length
+ sizeof(WCHAR
));
1198 /* Initialize some local (to win32k) desktop state. */
1199 InitializeListHead(&DesktopObject
->PtiList
);
1200 DesktopObject
->ActiveMessageQueue
= NULL
;
1202 /* Setup Global Hooks. */
1203 for (i
= 0; i
< NB_HOOKS
; i
++)
1205 InitializeListHead(&DesktopObject
->pDeskInfo
->aphkStart
[i
]);
1209 * Create a handle for CSRSS and notify CSRSS for Creating Desktop Background Windows and Threads.
1211 Request
.ApiNumber
= CSR_CREATE_API_NUMBER(CSR_GUI
, CREATE_DESKTOP
);
1212 Status
= CsrInsertObject(Desktop
,
1214 (HANDLE
*)&Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
1215 if (! NT_SUCCESS(Status
))
1217 ERR("Failed to create desktop handle for CSRSS\n");
1219 SetLastNtError(Status
);
1223 Status
= co_CsrNotify((PCSR_API_MESSAGE
)&Request
,
1224 sizeof(CSR_API_MESSAGE
));
1225 if (! NT_SUCCESS(Status
))
1227 CsrCloseHandle(Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
1228 ERR("Failed to notify CSRSS about new desktop\n");
1230 SetLastNtError(Status
);
1234 if (ptiCurrent
&& !ptiCurrent
->rpdesk
) IntSetThreadDesktop(Desktop
,FALSE
);
1236 ClassName
.Buffer
= ((PWSTR
)((ULONG_PTR
)(WORD
)(gpsi
->atomSysClass
[ICLS_HWNDMESSAGE
])));
1237 ClassName
.Length
= 0;
1238 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1240 RtlZeroMemory(&Cs
, sizeof(Cs
));
1241 Cs
.cx
= Cs
.cy
= 100;
1242 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1243 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc! Leave it to Timo to not pass on notes!
1244 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1245 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1247 pWnd
= co_UserCreateWindowEx(&Cs
, &ClassName
, &WindowName
, NULL
);
1250 ERR("Failed to create Message window handle\n");
1254 DesktopObject
->spwndMessage
= pWnd
;
1258 if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki)
1259 Create Tooltip. Saved in DesktopObject->spwndTooltip.
1260 Tooltip dwExStyle: WS_EX_TOOLWINDOW|WS_EX_TOPMOST
1261 hWndParent are spwndMessage. Use hModuleWin for server side winproc!
1262 The rest is same as message window.
1263 http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx
1268 if(DesktopName
.Buffer
!= NULL
)
1270 ExFreePoolWithTag(DesktopName
.Buffer
, TAG_STRING
);
1272 if (!NoHooks
&& ptiCurrent
)
1274 ptiCurrent
->TIF_flags
&= ~TIF_DISABLEHOOKS
;
1275 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
1277 TRACE("Leave NtUserCreateDesktop, ret=%p\n",_ret_
);
1285 * Opens an existing desktop.
1289 * Name of the existing desktop.
1292 * Interaction flags.
1295 * Requested type of access.
1298 * Handle to the desktop or zero on failure.
1306 POBJECT_ATTRIBUTES ObjectAttributes
,
1308 ACCESS_MASK dwDesiredAccess
)
1313 Status
= ObOpenObjectByName(
1315 ExDesktopObjectType
,
1322 if (!NT_SUCCESS(Status
))
1324 ERR("Failed to open desktop\n");
1325 SetLastNtError(Status
);
1329 TRACE("Opened desktop %S with handle 0x%p\n", ObjectAttributes
->ObjectName
->Buffer
, Desktop
);
1335 * NtUserOpenInputDesktop
1337 * Opens the input (interactive) desktop.
1341 * Interaction flags.
1344 * Inheritance option.
1347 * Requested type of access.
1350 * Handle to the input desktop or zero on failure.
1357 NtUserOpenInputDesktop(
1360 ACCESS_MASK dwDesiredAccess
)
1366 UserEnterExclusive();
1367 TRACE("Enter NtUserOpenInputDesktop InputDesktopHandle 0x%p\n",InputDesktopHandle
);
1369 /* Get a pointer to the desktop object */
1370 Status
= IntValidateDesktopHandle(InputDesktopHandle
, UserMode
, 0, &pdesk
);
1371 if (!NT_SUCCESS(Status
))
1373 ERR("Validation of input desktop handle (0x%p) failed\n", InputDesktopHandle
);
1377 /* Create a new handle to the object */
1378 Status
= ObOpenObjectByPointer(
1383 ExDesktopObjectType
,
1387 ObDereferenceObject(pdesk
);
1389 if (!NT_SUCCESS(Status
))
1391 ERR("Failed to open input desktop object\n");
1392 SetLastNtError(Status
);
1396 TRACE("NtUserOpenInputDesktop returning 0x%p\n",hdesk
);
1402 * NtUserCloseDesktop
1404 * Closes a desktop handle.
1408 * Handle to the desktop.
1414 * The desktop handle can be created with NtUserCreateDesktop or
1415 * NtUserOpenDesktop. This function will fail if any thread in the calling
1416 * process is using the specified desktop handle or if the handle refers
1417 * to the initial desktop of the calling process.
1424 NtUserCloseDesktop(HDESK hDesktop
)
1428 DECLARE_RETURN(BOOL
);
1430 TRACE("NtUserCloseDesktop called (0x%p)\n", hDesktop
);
1431 UserEnterExclusive();
1433 if( hDesktop
== gptiCurrent
->hdesk
|| hDesktop
== gptiCurrent
->ppi
->hdeskStartup
)
1435 ERR("Attempted to close thread desktop\n");
1436 EngSetLastError(ERROR_BUSY
);
1440 Status
= IntValidateDesktopHandle( hDesktop
, UserMode
, 0, &pdesk
);
1441 if (!NT_SUCCESS(Status
))
1443 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop
);
1447 ObDereferenceObject(pdesk
);
1449 Status
= ZwClose(hDesktop
);
1450 if (!NT_SUCCESS(Status
))
1452 ERR("Failed to close desktop handle 0x%p\n", hDesktop
);
1453 SetLastNtError(Status
);
1460 TRACE("Leave NtUserCloseDesktop, ret=%i\n",_ret_
);
1466 * NtUserPaintDesktop
1468 * The NtUserPaintDesktop function fills the clipping region in the
1469 * specified device context with the desktop pattern or wallpaper. The
1470 * function is provided primarily for shell desktops.
1474 * Handle to the device context.
1481 NtUserPaintDesktop(HDC hDC
)
1484 UserEnterExclusive();
1485 TRACE("Enter NtUserPaintDesktop\n");
1486 Ret
= IntPaintDesktop(hDC
);
1487 TRACE("Leave NtUserPaintDesktop, ret=%i\n",Ret
);
1493 * NtUserSwitchDesktop
1495 * Sets the current input (interactive) desktop.
1499 * Handle to desktop.
1509 NtUserSwitchDesktop(HDESK hdesk
)
1513 DECLARE_RETURN(BOOL
);
1515 UserEnterExclusive();
1516 TRACE("Enter NtUserSwitchDesktop(0x%p)\n", hdesk
);
1518 Status
= IntValidateDesktopHandle( hdesk
, UserMode
, 0, &pdesk
);
1519 if (!NT_SUCCESS(Status
))
1521 ERR("Validation of desktop handle (0x%p) failed\n", hdesk
);
1526 * Don't allow applications switch the desktop if it's locked, unless the caller
1527 * is the logon application itself
1529 if((pdesk
->rpwinstaParent
->Flags
& WSS_LOCKED
) &&
1530 LogonProcess
!= PsGetCurrentProcessWin32Process())
1532 ObDereferenceObject(pdesk
);
1533 ERR("Switching desktop 0x%p denied because the window station is locked!\n", hdesk
);
1537 if(pdesk
->rpwinstaParent
!= InputWindowStation
)
1539 ObDereferenceObject(pdesk
);
1540 ERR("Switching desktop 0x%p denied because desktop doesn't belong to the interactive winsta!\n", hdesk
);
1544 /* FIXME: Fail if the process is associated with a secured
1545 desktop such as Winlogon or Screen-Saver */
1546 /* FIXME: Connect to input device */
1548 /* Set the active desktop in the desktop's window station. */
1549 InputWindowStation
->ActiveDesktop
= pdesk
;
1551 /* Set the global state. */
1552 InputDesktop
= pdesk
;
1553 InputDesktopHandle
= hdesk
;
1554 TRACE("SwitchDesktop InputDesktopHandle 0x%p\n",InputDesktopHandle
);
1555 ObDereferenceObject(pdesk
);
1560 TRACE("Leave NtUserSwitchDesktop, ret=%i\n",_ret_
);
1566 * NtUserGetThreadDesktop
1573 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1577 PDESKTOP DesktopObject
;
1578 HDESK Ret
, hThreadDesktop
;
1579 OBJECT_HANDLE_INFORMATION HandleInformation
;
1580 DECLARE_RETURN(HDESK
);
1582 UserEnterExclusive();
1583 TRACE("Enter NtUserGetThreadDesktop\n");
1587 EngSetLastError(ERROR_INVALID_PARAMETER
);
1591 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)dwThreadId
, &Thread
);
1592 if(!NT_SUCCESS(Status
))
1594 EngSetLastError(ERROR_INVALID_PARAMETER
);
1598 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1600 /* Just return the handle, we queried the desktop handle of a thread running
1601 in the same context */
1602 Ret
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
;
1603 ObDereferenceObject(Thread
);
1607 /* Get the desktop handle and the desktop of the thread */
1608 if(!(hThreadDesktop
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
) ||
1609 !(DesktopObject
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->rpdesk
))
1611 ObDereferenceObject(Thread
);
1612 ERR("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1616 /* We could just use DesktopObject instead of looking up the handle, but latter
1617 may be a bit safer (e.g. when the desktop is being destroyed */
1618 /* Switch into the context of the thread we're trying to get the desktop from,
1619 so we can use the handle */
1620 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1621 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1623 ExDesktopObjectType
,
1625 (PVOID
*)&DesktopObject
,
1626 &HandleInformation
);
1629 /* The handle couldn't be found, there's nothing to get... */
1630 if(!NT_SUCCESS(Status
))
1632 ObDereferenceObject(Thread
);
1636 /* Lookup our handle table if we can find a handle to the desktop object,
1637 if not, create one */
1638 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1640 /* All done, we got a valid handle to the desktop */
1641 ObDereferenceObject(DesktopObject
);
1642 ObDereferenceObject(Thread
);
1646 TRACE("Leave NtUserGetThreadDesktop, ret=%p\n",_ret_
);
1652 IntUnmapDesktopView(IN PDESKTOP pdesk
)
1655 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1656 NTSTATUS Status
= STATUS_SUCCESS
;
1658 TRACE("IntUnmapDesktopView called for desktop object %p\n", pdesk
);
1660 ppi
= PsGetCurrentProcessWin32Process();
1661 PrevLink
= &ppi
->HeapMappings
.Next
;
1663 /* Unmap if we're the last thread using the desktop */
1664 HeapMapping
= *PrevLink
;
1665 while (HeapMapping
!= NULL
)
1667 if (HeapMapping
->KernelMapping
== (PVOID
)pdesk
->pheapDesktop
)
1669 if (--HeapMapping
->Count
== 0)
1671 *PrevLink
= HeapMapping
->Next
;
1673 TRACE("ppi 0x%p unmapped heap of desktop 0x%p\n", ppi
, pdesk
);
1674 Status
= MmUnmapViewOfSection(PsGetCurrentProcess(),
1675 HeapMapping
->UserMapping
);
1677 ObDereferenceObject(pdesk
);
1679 UserHeapFree(HeapMapping
);
1684 PrevLink
= &HeapMapping
->Next
;
1685 HeapMapping
= HeapMapping
->Next
;
1692 IntMapDesktopView(IN PDESKTOP pdesk
)
1695 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1696 PVOID UserBase
= NULL
;
1697 SIZE_T ViewSize
= 0;
1698 LARGE_INTEGER Offset
;
1701 TRACE("IntMapDesktopView called for desktop object 0x%p\n", pdesk
);
1703 ppi
= PsGetCurrentProcessWin32Process();
1704 PrevLink
= &ppi
->HeapMappings
.Next
;
1706 /* Find out if another thread already mapped the desktop heap */
1707 HeapMapping
= *PrevLink
;
1708 while (HeapMapping
!= NULL
)
1710 if (HeapMapping
->KernelMapping
== (PVOID
)pdesk
->pheapDesktop
)
1712 HeapMapping
->Count
++;
1713 return STATUS_SUCCESS
;
1716 PrevLink
= &HeapMapping
->Next
;
1717 HeapMapping
= HeapMapping
->Next
;
1720 /* We're the first, map the heap */
1721 Offset
.QuadPart
= 0;
1722 Status
= MmMapViewOfSection(pdesk
->hsectionDesktop
,
1723 PsGetCurrentProcess(),
1731 PAGE_EXECUTE_READ
); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
1732 if (!NT_SUCCESS(Status
))
1734 ERR("Failed to map desktop\n");
1738 TRACE("ppi 0x%p mapped heap of desktop 0x%p\n", ppi
, pdesk
);
1740 /* Add the mapping */
1741 HeapMapping
= UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING
));
1742 if (HeapMapping
== NULL
)
1744 MmUnmapViewOfSection(PsGetCurrentProcess(), UserBase
);
1745 ERR("UserHeapAlloc() failed!\n");
1746 return STATUS_NO_MEMORY
;
1749 HeapMapping
->Next
= NULL
;
1750 HeapMapping
->KernelMapping
= (PVOID
)pdesk
->pheapDesktop
;
1751 HeapMapping
->UserMapping
= UserBase
;
1752 HeapMapping
->Limit
= ViewSize
;
1753 HeapMapping
->Count
= 1;
1754 *PrevLink
= HeapMapping
;
1756 ObReferenceObject(pdesk
);
1758 return STATUS_SUCCESS
;
1762 IntSetThreadDesktop(IN HDESK hDesktop
,
1763 IN BOOL FreeOnFailure
)
1765 PDESKTOP pdesk
= NULL
, pdeskOld
;
1769 PCLIENTTHREADINFO pctiOld
, pctiNew
= NULL
;
1772 ASSERT(NtCurrentTeb());
1774 TRACE("IntSetThreadDesktop hDesktop:0x%p, FOF:%i\n",hDesktop
, FreeOnFailure
);
1776 pti
= PsGetCurrentThreadWin32Thread();
1777 pci
= pti
->pClientInfo
;
1779 /* If the caller gave us a desktop, ensure it is valid */
1780 if(hDesktop
!= NULL
)
1782 /* Validate the new desktop. */
1783 Status
= IntValidateDesktopHandle( hDesktop
, UserMode
, 0, &pdesk
);
1784 if (!NT_SUCCESS(Status
))
1786 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop
);
1790 if (pti
->rpdesk
== pdesk
)
1793 ObDereferenceObject(pdesk
);
1798 /* Make sure that we don't own any window in the current desktop */
1799 if (!IsListEmpty(&pti
->WindowListHead
))
1802 ObDereferenceObject(pdesk
);
1803 ERR("Attempted to change thread desktop although the thread has windows!\n");
1804 EngSetLastError(ERROR_BUSY
);
1808 /* Desktop is being re-set so clear out foreground. */
1809 if (pti
->rpdesk
!= pdesk
&& pti
->MessageQueue
== gpqForeground
)
1811 // Like above, there shouldn't be any windows, hooks or anything active on this threads desktop!
1812 IntSetFocusMessageQueue(NULL
);
1815 /* Before doing the switch, map the new desktop heap and allocate the new pcti */
1818 Status
= IntMapDesktopView(pdesk
);
1819 if (!NT_SUCCESS(Status
))
1821 ERR("Failed to map desktop heap!\n");
1822 ObDereferenceObject(pdesk
);
1823 SetLastNtError(Status
);
1827 pctiNew
= DesktopHeapAlloc( pdesk
, sizeof(CLIENTTHREADINFO
));
1830 ERR("Failed to allocate new pcti\n");
1831 IntUnmapDesktopView(pdesk
);
1832 ObDereferenceObject(pdesk
);
1833 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1838 /* free all classes or move them to the shared heap */
1839 if(pti
->rpdesk
!= NULL
)
1841 if(!IntCheckProcessDesktopClasses(pti
->rpdesk
, FreeOnFailure
))
1843 ERR("Failed to move process classes to shared heap!\n");
1846 DesktopHeapFree(pdesk
, pctiNew
);
1847 IntUnmapDesktopView(pdesk
);
1848 ObDereferenceObject(pdesk
);
1854 pdeskOld
= pti
->rpdesk
;
1855 hdeskOld
= pti
->hdesk
;
1856 if (pti
->pcti
!= &pti
->cti
)
1857 pctiOld
= pti
->pcti
;
1864 pti
->rpdesk
= pdesk
;
1865 pti
->hdesk
= hDesktop
;
1866 pti
->pDeskInfo
= pti
->rpdesk
->pDeskInfo
;
1867 pti
->pcti
= pctiNew
;
1869 pci
->ulClientDelta
= DesktopHeapGetUserDelta();
1870 pci
->pDeskInfo
= (PVOID
)((ULONG_PTR
)pti
->pDeskInfo
- pci
->ulClientDelta
);
1871 pci
->pClientThreadInfo
= (PVOID
)((ULONG_PTR
)pti
->pcti
- pci
->ulClientDelta
);
1873 /* initialize the new pcti */
1876 RtlCopyMemory(pctiNew
, pctiOld
, sizeof(CLIENTTHREADINFO
));
1880 RtlZeroMemory(pctiNew
, sizeof(CLIENTTHREADINFO
));
1881 pci
->fsHooks
= pti
->fsHooks
;
1882 pci
->dwTIFlags
= pti
->TIF_flags
;
1889 pti
->pDeskInfo
= NULL
;
1890 pti
->pcti
= &pti
->cti
; // Always point inside so there will be no crash when posting or sending msg's!
1891 pci
->ulClientDelta
= 0;
1892 pci
->pDeskInfo
= NULL
;
1893 pci
->pClientThreadInfo
= NULL
;
1896 /* clean up the old desktop */
1897 if(pdeskOld
!= NULL
)
1899 RemoveEntryList(&pti
->PtiLink
);
1900 if (pctiOld
) DesktopHeapFree(pdeskOld
, pctiOld
);
1901 IntUnmapDesktopView(pdeskOld
);
1902 ObDereferenceObject(pdeskOld
);
1908 InsertTailList(&pdesk
->PtiList
, &pti
->PtiLink
);
1911 TRACE("IntSetThreadDesktop: pti 0x%p ppi 0x%p switched from object 0x%p to 0x%p\n", pti
, pti
->ppi
, pdeskOld
, pdesk
);
1917 * NtUserSetThreadDesktop
1924 NtUserSetThreadDesktop(HDESK hDesktop
)
1928 UserEnterExclusive();
1930 // FIXME: IntSetThreadDesktop validates the desktop handle, it should happen
1931 // here too and set the NT error level. Q. Is it necessary to have the validation
1932 // in IntSetThreadDesktop? Is it needed there too?
1933 if (hDesktop
|| (!hDesktop
&& CsrProcess
== PsGetCurrentProcess()))
1934 ret
= IntSetThreadDesktop(hDesktop
, FALSE
);