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
);
15 UserInitializeDesktop(PDESKTOP pdesk
, PUNICODE_STRING DesktopName
, PWINSTATION_OBJECT pwinsta
);
18 IntMapDesktopView(IN PDESKTOP pdesk
);
21 IntUnmapDesktopView(IN PDESKTOP pdesk
);
24 IntFreeDesktopHeap(IN PDESKTOP pdesk
);
26 /* GLOBALS *******************************************************************/
28 /* Currently active desktop */
29 PDESKTOP gpdeskInputDesktop
= NULL
;
30 HDC ScreenDeviceContext
= NULL
;
31 PTHREADINFO gptiDesktopThread
;
32 HCURSOR gDesktopCursor
= NULL
;
34 /* OBJECT CALLBACKS **********************************************************/
38 IntDesktopObjectParse(IN PVOID ParseObject
,
40 IN OUT PACCESS_STATE AccessState
,
41 IN KPROCESSOR_MODE AccessMode
,
43 IN OUT PUNICODE_STRING CompleteName
,
44 IN OUT PUNICODE_STRING RemainingName
,
45 IN OUT PVOID Context OPTIONAL
,
46 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
51 OBJECT_ATTRIBUTES ObjectAttributes
;
52 PLIST_ENTRY NextEntry
, ListHead
;
53 PWINSTATION_OBJECT WinStaObject
= (PWINSTATION_OBJECT
)ParseObject
;
54 PUNICODE_STRING DesktopName
;
55 PBOOLEAN pContext
= (PBOOLEAN
) Context
;
60 /* Set the list pointers and loop the window station */
61 ListHead
= &WinStaObject
->DesktopListHead
;
62 NextEntry
= ListHead
->Flink
;
63 while (NextEntry
!= ListHead
)
65 /* Get the current desktop */
66 Desktop
= CONTAINING_RECORD(NextEntry
, DESKTOP
, ListEntry
);
68 /// @todo Don't mess around with the object headers!
70 _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR
)
71 DesktopName
= GET_DESKTOP_NAME(Desktop
);
74 /* Compare the name */
75 if (RtlEqualUnicodeString(RemainingName
,
77 (Attributes
& OBJ_CASE_INSENSITIVE
)))
79 /* We found a match. Did this come from a create? */
82 /* Unless OPEN_IF was given, fail with an error */
83 if (!(Attributes
& OBJ_OPENIF
))
86 return STATUS_OBJECT_NAME_COLLISION
;
90 /* Otherwise, return with a warning only */
91 Status
= STATUS_OBJECT_NAME_EXISTS
;
96 /* This was a real open, so this is OK */
97 Status
= STATUS_SUCCESS
;
100 /* Reference the desktop and return it */
101 ObReferenceObject(Desktop
);
107 /* Go to the next desktop */
108 NextEntry
= NextEntry
->Flink
;
111 /* If we got here but this isn't a create, then fail */
112 if (!Context
) return STATUS_OBJECT_NAME_NOT_FOUND
;
114 /* Create the desktop object */
115 InitializeObjectAttributes(&ObjectAttributes
, RemainingName
, 0, NULL
, NULL
);
116 Status
= ObCreateObject(KernelMode
,
125 if (!NT_SUCCESS(Status
)) return Status
;
127 /* Initialize the desktop */
128 Status
= UserInitializeDesktop(Desktop
, RemainingName
, WinStaObject
);
129 if (!NT_SUCCESS(Status
))
131 ObDereferenceObject(Desktop
);
135 /* Set the desktop object and return success */
138 return STATUS_SUCCESS
;
142 IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
144 PDESKTOP pdesk
= (PDESKTOP
)Parameters
->Object
;
146 TRACE("Deleting desktop object 0x%p\n", pdesk
);
148 ASSERT(pdesk
->pDeskInfo
->spwnd
->spwndChild
== NULL
);
150 if (pdesk
->pDeskInfo
->spwnd
)
151 co_UserDestroyWindow(pdesk
->pDeskInfo
->spwnd
);
153 if (pdesk
->spwndMessage
)
154 co_UserDestroyWindow(pdesk
->spwndMessage
);
156 /* Remove the desktop from the window station's list of associcated desktops */
157 RemoveEntryList(&pdesk
->ListEntry
);
160 IntFreeDesktopHeap(pdesk
);
164 IntDesktopOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters
)
166 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
170 /* This happens when we leak desktop handles */
171 return STATUS_SUCCESS
;
174 /* Do not allow the current desktop or the initial desktop to be closed */
175 if( Parameters
->Handle
== pti
->ppi
->hdeskStartup
||
176 Parameters
->Handle
== pti
->hdesk
)
178 return STATUS_ACCESS_DENIED
;
181 return STATUS_SUCCESS
;
184 NTSTATUS NTAPI
IntDesktopObjectOpen(PWIN32_OPENMETHOD_PARAMETERS Parameters
)
186 PPROCESSINFO ppi
= PsGetProcessWin32Process(Parameters
->Process
);
188 return STATUS_SUCCESS
;
190 return IntMapDesktopView((PDESKTOP
)Parameters
->Object
);
193 NTSTATUS NTAPI
IntDesktopObjectClose(PWIN32_CLOSEMETHOD_PARAMETERS Parameters
)
195 PPROCESSINFO ppi
= PsGetProcessWin32Process(Parameters
->Process
);
198 /* This happens when the process leaks desktop handles.
199 * At this point the PPROCESSINFO is already destroyed */
200 return STATUS_SUCCESS
;
203 return IntUnmapDesktopView((PDESKTOP
)Parameters
->Object
);
207 /* PRIVATE FUNCTIONS **********************************************************/
212 InitDesktopImpl(VOID
)
214 GENERIC_MAPPING IntDesktopMapping
= { DESKTOP_READ
,
219 /* Set Desktop Object Attributes */
220 ExDesktopObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(DESKTOP
);
221 ExDesktopObjectType
->TypeInfo
.GenericMapping
= IntDesktopMapping
;
222 ExDesktopObjectType
->TypeInfo
.ValidAccessMask
= DESKTOP_ALL_ACCESS
;
223 return STATUS_SUCCESS
;
226 static int GetSystemVersionString(LPWSTR buffer
)
228 RTL_OSVERSIONINFOEXW versionInfo
;
231 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
233 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
236 if (versionInfo
.dwMajorVersion
<= 4)
237 len
= swprintf(buffer
,
238 L
"ReactOS Version %lu.%lu %s Build %lu",
239 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
240 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
242 len
= swprintf(buffer
,
243 L
"ReactOS %s (Build %lu)",
244 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
251 IntParseDesktopPath(PEPROCESS Process
,
252 PUNICODE_STRING DesktopPath
,
256 OBJECT_ATTRIBUTES ObjectAttributes
;
257 UNICODE_STRING ObjectName
;
259 WCHAR wstrWinstaFullName
[MAX_PATH
], *pwstrWinsta
= NULL
, *pwstrDesktop
= NULL
;
268 if(DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
271 * Parse the desktop path string which can be in the form "WinSta\Desktop"
272 * or just "Desktop". In latter case WinSta0 will be used.
275 pwstrDesktop
= wcschr(DesktopPath
->Buffer
, L
'\\');
276 if(pwstrDesktop
!= NULL
)
280 pwstrWinsta
= DesktopPath
->Buffer
;
284 pwstrDesktop
= DesktopPath
->Buffer
;
288 TRACE("IntParseDesktopPath pwstrWinsta:%S pwstrDesktop:%S\n", pwstrWinsta
, pwstrDesktop
);
292 /* Search the process handle table for (inherited) window station
293 handles, use a more appropriate one than WinSta0 if possible. */
294 if (!ObFindHandleForObject(Process
,
296 ExWindowStationObjectType
,
301 /* We had no luck searching for opened handles, use WinSta0 now */
303 pwstrWinsta
= L
"WinSta0";
307 /* Search the process handle table for (inherited) desktop
308 handles, use a more appropriate one than Default if possible. */
309 if (!ObFindHandleForObject(Process
,
316 /* We had no luck searching for opened handles, use Desktop now */
318 pwstrDesktop
= L
"Default";
323 swprintf(wstrWinstaFullName
, L
"%wZ\\%ws", &gustrWindowStationsDir
, pwstrWinsta
);
324 RtlInitUnicodeString( &ObjectName
, wstrWinstaFullName
);
326 TRACE("parsed initial winsta: %wZ\n", &ObjectName
);
328 /* Open the window station */
329 InitializeObjectAttributes(&ObjectAttributes
,
331 OBJ_CASE_INSENSITIVE
,
335 Status
= ObOpenObjectByName(&ObjectAttributes
,
336 ExWindowStationObjectType
,
343 if(!NT_SUCCESS(Status
))
345 SetLastNtError(Status
);
346 ERR("Failed to reference window station %wZ PID: --!\n", &ObjectName
);
351 if(*hDesktop
== NULL
)
353 RtlInitUnicodeString(&ObjectName
, pwstrDesktop
);
355 TRACE("parsed initial desktop: %wZ\n", &ObjectName
);
357 /* Open the desktop object */
358 InitializeObjectAttributes(&ObjectAttributes
,
360 OBJ_CASE_INSENSITIVE
,
364 Status
= ObOpenObjectByName(&ObjectAttributes
,
372 if(!NT_SUCCESS(Status
))
377 SetLastNtError(Status
);
378 ERR("Failed to reference desktop %wZ PID: --!\n", &ObjectName
);
382 return STATUS_SUCCESS
;
386 * IntValidateDesktopHandle
388 * Validates the desktop handle.
391 * If the function succeeds, the handle remains referenced. If the
392 * fucntion fails, last error is set.
396 IntValidateDesktopHandle(
398 KPROCESSOR_MODE AccessMode
,
399 ACCESS_MASK DesiredAccess
,
404 Status
= ObReferenceObjectByHandle(
412 TRACE("IntValidateDesktopHandle: handle:0x%p obj:0x%p access:0x%x Status:0x%lx\n",
413 Desktop
, *Object
, DesiredAccess
, Status
);
415 if (!NT_SUCCESS(Status
))
416 SetLastNtError(Status
);
422 IntGetActiveDesktop(VOID
)
424 return gpdeskInputDesktop
;
428 * Returns or creates a handle to the desktop object
431 IntGetDesktopObjectHandle(PDESKTOP DesktopObject
)
436 ASSERT(DesktopObject
);
438 if (!ObFindHandleForObject(PsGetCurrentProcess(),
444 Status
= ObOpenObjectByPointer(DesktopObject
,
451 if(!NT_SUCCESS(Status
))
453 /* Unable to create a handle */
454 ERR("Unable to create a desktop handle\n");
460 ERR("Got handle: %p\n", Ret
);
466 PUSER_MESSAGE_QUEUE FASTCALL
467 IntGetFocusMessageQueue(VOID
)
469 PDESKTOP pdo
= IntGetActiveDesktop();
472 TRACE("No active desktop\n");
475 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
479 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
481 PUSER_MESSAGE_QUEUE Old
;
482 PDESKTOP pdo
= IntGetActiveDesktop();
485 TRACE("No active desktop\n");
490 if(NewQueue
->Desktop
!= NULL
)
492 TRACE("Message Queue already attached to another desktop!\n");
495 IntReferenceMessageQueue(NewQueue
);
496 (void)InterlockedExchangePointer((PVOID
*)&NewQueue
->Desktop
, pdo
);
498 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchangePointer((PVOID
*)&pdo
->ActiveMessageQueue
, NewQueue
);
501 (void)InterlockedExchangePointer((PVOID
*)&Old
->Desktop
, 0);
502 IntDereferenceMessageQueue(Old
);
503 gpqForegroundPrev
= Old
;
505 // Only one Q can have active foreground even when there are more than one desktop.
506 if (NewQueue
) gpqForeground
= pdo
->ActiveMessageQueue
;
507 else gpqForeground
= NULL
;
511 IntGetThreadDesktopWindow(PTHREADINFO pti
)
513 if (!pti
) pti
= PsGetCurrentThreadWin32Thread();
514 if (pti
->pDeskInfo
) return pti
->pDeskInfo
->spwnd
;
518 PWND FASTCALL
co_GetDesktopWindow(PWND pWnd
)
520 if (pWnd
->head
.rpdesk
&&
521 pWnd
->head
.rpdesk
->pDeskInfo
)
522 return pWnd
->head
.rpdesk
->pDeskInfo
->spwnd
;
526 HWND FASTCALL
IntGetDesktopWindow(VOID
)
528 PDESKTOP pdo
= IntGetActiveDesktop();
531 TRACE("No active desktop\n");
534 return pdo
->DesktopWindow
;
537 PWND FASTCALL
UserGetDesktopWindow(VOID
)
539 PDESKTOP pdo
= IntGetActiveDesktop();
543 TRACE("No active desktop\n");
546 // return pdo->pDeskInfo->spwnd;
547 return UserGetWindowObject(pdo
->DesktopWindow
);
550 HWND FASTCALL
IntGetMessageWindow(VOID
)
552 PDESKTOP pdo
= IntGetActiveDesktop();
556 TRACE("No active desktop\n");
559 return pdo
->spwndMessage
->head
.h
;
562 PWND FASTCALL
UserGetMessageWindow(VOID
)
564 PDESKTOP pdo
= IntGetActiveDesktop();
568 TRACE("No active desktop\n");
571 return pdo
->spwndMessage
;
574 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
576 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
577 PDESKTOP pdo
= pti
->rpdesk
;
580 ERR("Thread doesn't have a desktop\n");
583 return pdo
->DesktopWindow
;
586 /* PUBLIC FUNCTIONS ***********************************************************/
589 DesktopWindowProc(PWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*lResult
)
593 //ERR("DesktopWindowProc\n");
602 Wnd
->fnid
= FNID_DESKTOP
;
604 *lResult
= (LRESULT
)TRUE
;
608 Value
= HandleToULong(PsGetCurrentProcessId());
610 co_UserSetWindowLong(UserHMGetHandle(Wnd
), DT_GWL_PROCESSID
, Value
, FALSE
);
611 Value
= HandleToULong(PsGetCurrentThreadId());
613 co_UserSetWindowLong(UserHMGetHandle(Wnd
), DT_GWL_THREADID
, Value
, FALSE
);
617 case WM_DISPLAYCHANGE
:
618 co_WinPosSetWindowPos(Wnd
, 0, 0, 0, LOWORD(lParam
), HIWORD(lParam
), SWP_NOZORDER
| SWP_NOACTIVATE
);
622 IntPaintDesktop((HDC
)wParam
);
628 if (IntBeginPaint(Wnd
, &Ps
))
630 IntEndPaint(Wnd
, &Ps
);
634 case WM_SYSCOLORCHANGE
:
635 co_UserRedrawWindow(Wnd
, NULL
, NULL
, RDW_INVALIDATE
|RDW_ERASE
|RDW_ALLCHILDREN
);
639 PCURICON_OBJECT pcurOld
, pcurNew
;
640 pcurNew
= UserGetCurIconObject(gDesktopCursor
);
645 pcurOld
= UserSetCursor(pcurNew
, FALSE
);
648 UserDereferenceObject(pcurOld
);
653 case WM_WINDOWPOSCHANGING
:
655 PWINDOWPOS pWindowPos
= (PWINDOWPOS
)lParam
;
656 if((pWindowPos
->flags
& SWP_SHOWWINDOW
) != 0)
658 HDESK hdesk
= IntGetDesktopObjectHandle(gpdeskInputDesktop
);
659 IntSetThreadDesktop(hdesk
, FALSE
);
664 return TRUE
; /* We are done. Do not do any callbacks to user mode */
668 UserMessageWindowProc(PWND pwnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*lResult
)
675 pwnd
->fnid
|= FNID_MESSAGEWND
;
676 *lResult
= (LRESULT
)TRUE
;
679 pwnd
->fnid
|= FNID_DESTROY
;
683 return TRUE
; /* We are done. Do not do any callbacks to user mode */
686 VOID NTAPI
DesktopThreadMain()
691 gptiDesktopThread
= PsGetCurrentThreadWin32Thread();
693 UserEnterExclusive();
695 /* Register system classes. This thread does not belong to any desktop so the
696 classes will be allocated from the shared heap */
697 UserRegisterSystemClasses();
701 Ret
= co_IntGetPeekMessage(&Msg
, 0, 0, 0, PM_REMOVE
, TRUE
);
704 IntDispatchMessage(&Msg
);
712 UserGetDesktopDC(ULONG DcType
, BOOL EmptyDC
, BOOL ValidatehWnd
)
714 PWND DesktopObject
= 0;
717 if (DcType
== DC_TYPE_DIRECT
)
719 DesktopObject
= UserGetDesktopWindow();
720 DesktopHDC
= (HDC
)UserGetWindowDC(DesktopObject
);
724 PMONITOR pMonitor
= UserGetPrimaryMonitor();
725 DesktopHDC
= IntGdiCreateDisplayDC(pMonitor
->hDev
, DcType
, EmptyDC
);
737 Window
= UserGetDesktopWindow();
738 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcWindow
);
740 IntInvalidateWindows( Window
,
747 GreDeleteObject(hRgn
);
752 co_IntShowDesktop(PDESKTOP Desktop
, ULONG Width
, ULONG Height
, BOOL bRedraw
)
754 PWND pwnd
= Desktop
->pDeskInfo
->spwnd
;
755 UINT flags
= SWP_NOACTIVATE
|SWP_NOZORDER
|SWP_SHOWWINDOW
;
759 flags
|= SWP_NOREDRAW
;
761 co_WinPosSetWindowPos(pwnd
, NULL
, 0, 0, Width
, Height
, flags
);
764 co_UserRedrawWindow( pwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
| RDW_INVALIDATE
);
766 return STATUS_SUCCESS
;
770 IntHideDesktop(PDESKTOP Desktop
)
774 DesktopWnd
= IntGetWindowObject(Desktop
->DesktopWindow
);
777 return ERROR_INVALID_WINDOW_HANDLE
;
779 DesktopWnd
->style
&= ~WS_VISIBLE
;
781 return STATUS_SUCCESS
;
786 UserBuildShellHookHwndList(PDESKTOP Desktop
)
789 PSHELL_HOOK_WINDOW Current
;
792 /* FIXME: If we save nb elements in desktop, we dont have to loop to find nb entries */
793 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
796 if (!entries
) return NULL
;
798 list
= ExAllocatePoolWithTag(PagedPool
, sizeof(HWND
) * (entries
+ 1), USERTAG_WINDOWLIST
); /* alloc one extra for nullterm */
803 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
804 *cursor
++ = Current
->hWnd
;
806 *cursor
= NULL
; /* Nullterm list */
813 * Send the Message to the windows registered for ShellHook
814 * notifications. The lParam contents depend on the Message. See
815 * MSDN for more details (RegisterShellHookWindow)
817 VOID
co_IntShellHookNotify(WPARAM Message
, WPARAM wParam
, LPARAM lParam
)
819 PDESKTOP Desktop
= IntGetActiveDesktop();
822 if (!gpsi
->uiShellMsg
)
824 gpsi
->uiShellMsg
= IntAddAtom(L
"SHELLHOOK");
826 TRACE("MsgType = %x\n", gpsi
->uiShellMsg
);
827 if (!gpsi
->uiShellMsg
)
828 ERR("LastError: %x\n", EngGetLastError());
833 TRACE("IntShellHookNotify: No desktop!\n");
837 // FIXME: System Tray Support.
839 HwndList
= UserBuildShellHookHwndList(Desktop
);
842 HWND
* cursor
= HwndList
;
844 for (; *cursor
; cursor
++)
846 TRACE("Sending notify\n");
847 co_IntPostOrSendMessage(*cursor
,
850 (Message
== HSHELL_LANGUAGE
? lParam
: (LPARAM
)wParam
) );
853 ExFreePoolWithTag(HwndList
, USERTAG_WINDOWLIST
);
856 if (ISITHOOKED(WH_SHELL
))
858 co_HOOK_CallHooks(WH_SHELL
, Message
, wParam
, lParam
);
863 * Add the window to the ShellHookWindows list. The windows
864 * on that list get notifications that are important to shell
867 * TODO: Validate the window? I'm not sure if sending these messages to
868 * an unsuspecting application that is not your own is a nice thing to do.
870 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
872 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
873 PDESKTOP Desktop
= pti
->rpdesk
;
874 PSHELL_HOOK_WINDOW Entry
;
876 TRACE("IntRegisterShellHookWindow\n");
878 /* First deregister the window, so we can be sure it's never twice in the
881 IntDeRegisterShellHookWindow(hWnd
);
883 Entry
= ExAllocatePoolWithTag(PagedPool
,
884 sizeof(SHELL_HOOK_WINDOW
),
892 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
898 * Remove the window from the ShellHookWindows list. The windows
899 * on that list get notifications that are important to shell
902 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
904 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
905 PDESKTOP Desktop
= pti
->rpdesk
;
906 PSHELL_HOOK_WINDOW Current
;
908 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
910 if (Current
->hWnd
== hWnd
)
912 RemoveEntryList(&Current
->ListEntry
);
913 ExFreePoolWithTag(Current
, TAG_WINSTA
);
922 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop
)
924 /* FIXME: Disable until unmapping works in mm */
926 if (Desktop
->pheapDesktop
!= NULL
)
928 MmUnmapViewInSessionSpace(Desktop
->pheapDesktop
);
929 Desktop
->pheapDesktop
= NULL
;
932 if (Desktop
->hsectionDesktop
!= NULL
)
934 ObDereferenceObject(Desktop
->hsectionDesktop
);
935 Desktop
->hsectionDesktop
= NULL
;
941 IntPaintDesktop(HDC hDC
)
944 HBRUSH DesktopBrush
, PreviousBrush
;
946 BOOL doPatBlt
= TRUE
;
948 static WCHAR s_wszSafeMode
[] = L
"Safe Mode";
954 GdiGetClipBox(hDC
, &Rect
);
956 hWndDesktop
= IntGetDesktopWindow(); // rpdesk->DesktopWindow;
958 WndDesktop
= UserGetWindowObject(hWndDesktop
); // rpdesk->pDeskInfo->spwnd;
964 if (!UserGetSystemMetrics(SM_CLEANBOOT
))
966 DesktopBrush
= (HBRUSH
)WndDesktop
->pcls
->hbrBackground
;
969 * Paint desktop background
971 if (gspv
.hbmWallpaper
!= NULL
)
977 sz
.cx
= WndDesktop
->rcWindow
.right
- WndDesktop
->rcWindow
.left
;
978 sz
.cy
= WndDesktop
->rcWindow
.bottom
- WndDesktop
->rcWindow
.top
;
980 if (gspv
.WallpaperMode
== wmStretch
||
981 gspv
.WallpaperMode
== wmTile
)
988 /* Find the upper left corner, can be negative if the bitmap is bigger then the screen */
989 x
= (sz
.cx
/ 2) - (gspv
.cxWallpaper
/ 2);
990 y
= (sz
.cy
/ 2) - (gspv
.cyWallpaper
/ 2);
993 hWallpaperDC
= NtGdiCreateCompatibleDC(hDC
);
994 if(hWallpaperDC
!= NULL
)
998 /* Fill in the area that the bitmap is not going to cover */
1001 /* FIXME: Clip out the bitmap
1002 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1003 once we support DSTINVERT */
1004 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1005 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1006 NtGdiSelectBrush(hDC
, PreviousBrush
);
1009 /* Do not fill the background after it is painted no matter the size of the picture */
1012 hOldBitmap
= NtGdiSelectBitmap(hWallpaperDC
, gspv
.hbmWallpaper
);
1014 if (gspv
.WallpaperMode
== wmStretch
)
1016 if(Rect
.right
&& Rect
.bottom
)
1017 NtGdiStretchBlt(hDC
,
1031 else if (gspv
.WallpaperMode
== wmTile
)
1033 /* Paint the bitmap across the screen then down */
1034 for(y
= 0; y
< Rect
.bottom
; y
+= gspv
.cyWallpaper
)
1036 for(x
= 0; x
< Rect
.right
; x
+= gspv
.cxWallpaper
)
1066 NtGdiSelectBitmap(hWallpaperDC
, hOldBitmap
);
1067 NtGdiDeleteObjectApp(hWallpaperDC
);
1073 /* Black desktop background in Safe Mode */
1074 DesktopBrush
= StockObjects
[BLACK_BRUSH
];
1076 /* Back ground is set to none, clear the screen */
1079 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1080 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1081 NtGdiSelectBrush(hDC
, PreviousBrush
);
1085 * Display system version on the desktop background
1088 if (g_PaintDesktopVersion
|| UserGetSystemMetrics(SM_CLEANBOOT
))
1090 static WCHAR s_wszVersion
[256] = {0};
1095 len
= wcslen(s_wszVersion
);
1099 len
= GetSystemVersionString(s_wszVersion
);
1104 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
1106 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1107 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1110 color_old
= IntGdiSetTextColor(hDC
, RGB(255,255,255));
1111 align_old
= IntGdiSetTextAlign(hDC
, TA_RIGHT
);
1112 mode_old
= IntGdiSetBkMode(hDC
, TRANSPARENT
);
1114 if(!UserGetSystemMetrics(SM_CLEANBOOT
))
1116 GreExtTextOutW(hDC
, rect
.right
- 16, rect
.bottom
- 48, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1122 /* Version information text in top center */
1123 IntGdiSetTextAlign(hDC
, TA_CENTER
| TA_TOP
);
1124 GreExtTextOutW(hDC
, (rect
.right
+ rect
.left
)/2, rect
.top
+ 3, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1126 /* Safe Mode text in corners */
1127 len
= wcslen(s_wszSafeMode
);
1128 IntGdiSetTextAlign(hDC
, TA_LEFT
| TA_TOP
);
1129 GreExtTextOutW(hDC
, rect
.left
, rect
.top
+ 3, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1130 IntGdiSetTextAlign(hDC
, TA_RIGHT
| TA_TOP
);
1131 GreExtTextOutW(hDC
, rect
.right
, rect
.top
+ 3, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1132 IntGdiSetTextAlign(hDC
, TA_LEFT
| TA_BASELINE
);
1133 GreExtTextOutW(hDC
, rect
.left
, rect
.bottom
- 5, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1134 IntGdiSetTextAlign(hDC
, TA_RIGHT
| TA_BASELINE
);
1135 GreExtTextOutW(hDC
, rect
.right
, rect
.bottom
- 5, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1138 IntGdiSetBkMode(hDC
, mode_old
);
1139 IntGdiSetTextAlign(hDC
, align_old
);
1140 IntGdiSetTextColor(hDC
, color_old
);
1147 UserInitializeDesktop(PDESKTOP pdesk
, PUNICODE_STRING DesktopName
, PWINSTATION_OBJECT pwinsta
)
1149 PVOID DesktopHeapSystemBase
= NULL
;
1150 ULONG_PTR HeapSize
= 400 * 1024;
1151 SIZE_T DesktopInfoSize
;
1154 TRACE("UserInitializeDesktop desktop 0x%p with name %wZ\n", pdesk
, DesktopName
);
1156 RtlZeroMemory(pdesk
, sizeof(DESKTOP
));
1158 /* Link the desktop with the parent window station */
1159 pdesk
->rpwinstaParent
= pwinsta
;
1160 InsertTailList(&pwinsta
->DesktopListHead
, &pdesk
->ListEntry
);
1162 /* Create the desktop heap */
1163 pdesk
->hsectionDesktop
= NULL
;
1164 pdesk
->pheapDesktop
= UserCreateHeap(&pdesk
->hsectionDesktop
,
1165 &DesktopHeapSystemBase
,
1167 if (pdesk
->pheapDesktop
== NULL
)
1169 ERR("Failed to create desktop heap!\n");
1170 return STATUS_NO_MEMORY
;
1173 /* Create DESKTOPINFO */
1174 DesktopInfoSize
= sizeof(DESKTOPINFO
) + DesktopName
->Length
+ sizeof(WCHAR
);
1175 pdesk
->pDeskInfo
= RtlAllocateHeap(pdesk
->pheapDesktop
,
1176 HEAP_NO_SERIALIZE
| HEAP_ZERO_MEMORY
,
1178 if (pdesk
->pDeskInfo
== NULL
)
1180 ERR("Failed to create the DESKTOP structure!\n");
1181 return STATUS_NO_MEMORY
;
1184 /* Initialize the DESKTOPINFO */
1185 pdesk
->pDeskInfo
->pvDesktopBase
= DesktopHeapSystemBase
;
1186 pdesk
->pDeskInfo
->pvDesktopLimit
= (PVOID
)((ULONG_PTR
)DesktopHeapSystemBase
+ HeapSize
);
1187 RtlCopyMemory(pdesk
->pDeskInfo
->szDesktopName
,
1188 DesktopName
->Buffer
,
1189 DesktopName
->Length
+ sizeof(WCHAR
));
1190 for (i
= 0; i
< NB_HOOKS
; i
++)
1192 InitializeListHead(&pdesk
->pDeskInfo
->aphkStart
[i
]);
1195 InitializeListHead(&pdesk
->ShellHookWindows
);
1196 InitializeListHead(&pdesk
->PtiList
);
1198 return STATUS_SUCCESS
;
1201 /* SYSCALLS *******************************************************************/
1204 * NtUserCreateDesktop
1206 * Creates a new desktop.
1210 * Object Attributes.
1213 * Name of the device.
1219 * Interaction flags.
1222 * Requested type of access.
1226 * If the function succeeds, the return value is a handle to the newly
1227 * created desktop. If the specified desktop already exists, the function
1228 * succeeds and returns a handle to the existing desktop. When you are
1229 * finished using the handle, call the CloseDesktop function to close it.
1230 * If the function fails, the return value is NULL.
1237 NtUserCreateDesktop(
1238 POBJECT_ATTRIBUTES ObjectAttributes
,
1239 PUNICODE_STRING lpszDesktopDevice
,
1242 ACCESS_MASK dwDesiredAccess
)
1244 PDESKTOP pdesk
= NULL
;
1245 NTSTATUS Status
= STATUS_SUCCESS
;
1248 UNICODE_STRING ClassName
;
1249 LARGE_STRING WindowName
;
1250 BOOL NoHooks
= FALSE
;
1253 PTHREADINFO ptiCurrent
;
1256 DECLARE_RETURN(HDESK
);
1258 TRACE("Enter NtUserCreateDesktop\n");
1259 UserEnterExclusive();
1261 ptiCurrent
= PsGetCurrentThreadWin32Thread();
1263 ASSERT(gptiDesktopThread
);
1265 /* Turn off hooks when calling any CreateWindowEx from inside win32k. */
1266 NoHooks
= (ptiCurrent
->TIF_flags
& TIF_DISABLEHOOKS
);
1267 ptiCurrent
->TIF_flags
|= TIF_DISABLEHOOKS
;
1268 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
1271 * Try to open already existing desktop
1273 Status
= ObOpenObjectByName(
1275 ExDesktopObjectType
,
1281 if (!NT_SUCCESS(Status
))
1283 ERR("ObOpenObjectByName failed to open/create desktop\n");
1284 SetLastNtError(Status
);
1288 /* In case the object was not created (eg if it existed), return now */
1289 if (Context
== FALSE
)
1291 TRACE("NtUserCreateDesktop opened desktop %wZ\n", ObjectAttributes
->ObjectName
);
1295 /* Reference the desktop */
1296 Status
= ObReferenceObjectByHandle(hdesk
,
1298 ExDesktopObjectType
,
1302 if (!NT_SUCCESS(Status
))
1304 ERR("Failed to reference desktop object\n");
1305 SetLastNtError(Status
);
1309 /* Get the desktop window class. The thread desktop does not belong to any desktop
1310 * so the classes created there (including the desktop class) are allocated in the shared heap
1311 * It would cause problems if we used a class that belongs to the caller
1313 ClassName
.Buffer
= WC_DESKTOP
;
1314 ClassName
.Length
= 0;
1315 pcls
= IntGetAndReferenceClass(&ClassName
, 0, TRUE
);
1322 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1323 RtlZeroMemory(&Cs
, sizeof(Cs
));
1324 Cs
.x
= UserGetSystemMetrics(SM_XVIRTUALSCREEN
),
1325 Cs
.y
= UserGetSystemMetrics(SM_YVIRTUALSCREEN
),
1326 Cs
.cx
= UserGetSystemMetrics(SM_CXVIRTUALSCREEN
),
1327 Cs
.cy
= UserGetSystemMetrics(SM_CYVIRTUALSCREEN
),
1328 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1329 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
1330 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1331 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1333 /* Use IntCreateWindow instead of co_UserCreateWindowEx cause the later expects a thread with a desktop */
1334 pWnd
= IntCreateWindow(&Cs
, &WindowName
, pcls
, NULL
, NULL
, NULL
, pdesk
);
1337 ERR("Failed to create desktop window for the new desktop\n");
1341 pdesk
->DesktopWindow
= pWnd
->head
.h
;
1342 pdesk
->pDeskInfo
->spwnd
= pWnd
;
1343 pWnd
->fnid
= FNID_DESKTOP
;
1345 ClassName
.Buffer
= MAKEINTATOM(gpsi
->atomSysClass
[ICLS_HWNDMESSAGE
]);
1346 ClassName
.Length
= 0;
1347 pcls
= IntGetAndReferenceClass(&ClassName
, 0, TRUE
);
1354 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1355 RtlZeroMemory(&Cs
, sizeof(Cs
));
1356 Cs
.cx
= Cs
.cy
= 100;
1357 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1358 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
1359 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1360 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1361 pWnd
= IntCreateWindow(&Cs
, &WindowName
, pcls
, NULL
, NULL
, NULL
, pdesk
);
1364 ERR("Failed to create message window for the new desktop\n");
1368 pdesk
->spwndMessage
= pWnd
;
1369 pWnd
->fnid
= FNID_MESSAGEWND
;
1372 if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki)
1373 Create Tooltip. Saved in DesktopObject->spwndTooltip.
1374 Tooltip dwExStyle: WS_EX_TOOLWINDOW|WS_EX_TOPMOST
1375 hWndParent are spwndMessage. Use hModuleWin for server side winproc!
1376 The rest is same as message window.
1377 http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx
1384 ObDereferenceObject(pdesk
);
1386 if (_ret_
== NULL
&& hdesk
!= NULL
)
1388 ObCloseHandle(hdesk
, UserMode
);
1392 ptiCurrent
->TIF_flags
&= ~TIF_DISABLEHOOKS
;
1393 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
1395 TRACE("Leave NtUserCreateDesktop, ret=%p\n",_ret_
);
1403 * Opens an existing desktop.
1407 * Name of the existing desktop.
1410 * Interaction flags.
1413 * Requested type of access.
1416 * Handle to the desktop or zero on failure.
1424 POBJECT_ATTRIBUTES ObjectAttributes
,
1426 ACCESS_MASK dwDesiredAccess
)
1431 Status
= ObOpenObjectByName(
1433 ExDesktopObjectType
,
1440 if (!NT_SUCCESS(Status
))
1442 ERR("Failed to open desktop\n");
1443 SetLastNtError(Status
);
1447 TRACE("Opened desktop %S with handle 0x%p\n", ObjectAttributes
->ObjectName
->Buffer
, Desktop
);
1453 * NtUserOpenInputDesktop
1455 * Opens the input (interactive) desktop.
1459 * Interaction flags.
1462 * Inheritance option.
1465 * Requested type of access.
1468 * Handle to the input desktop or zero on failure.
1475 NtUserOpenInputDesktop(
1478 ACCESS_MASK dwDesiredAccess
)
1482 ULONG HandleAttributes
= 0;
1484 UserEnterExclusive();
1485 TRACE("Enter NtUserOpenInputDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop
);
1487 if(fInherit
) HandleAttributes
= OBJ_INHERIT
;
1489 /* Create a new handle to the object */
1490 Status
= ObOpenObjectByPointer(
1495 ExDesktopObjectType
,
1499 if (!NT_SUCCESS(Status
))
1501 ERR("Failed to open input desktop object\n");
1502 SetLastNtError(Status
);
1505 TRACE("NtUserOpenInputDesktop returning 0x%p\n",hdesk
);
1511 * NtUserCloseDesktop
1513 * Closes a desktop handle.
1517 * Handle to the desktop.
1523 * The desktop handle can be created with NtUserCreateDesktop or
1524 * NtUserOpenDesktop. This function will fail if any thread in the calling
1525 * process is using the specified desktop handle or if the handle refers
1526 * to the initial desktop of the calling process.
1533 NtUserCloseDesktop(HDESK hDesktop
)
1537 DECLARE_RETURN(BOOL
);
1539 TRACE("NtUserCloseDesktop called (0x%p)\n", hDesktop
);
1540 UserEnterExclusive();
1542 if( hDesktop
== gptiCurrent
->hdesk
|| hDesktop
== gptiCurrent
->ppi
->hdeskStartup
)
1544 ERR("Attempted to close thread desktop\n");
1545 EngSetLastError(ERROR_BUSY
);
1549 Status
= IntValidateDesktopHandle( hDesktop
, UserMode
, 0, &pdesk
);
1550 if (!NT_SUCCESS(Status
))
1552 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop
);
1556 ObDereferenceObject(pdesk
);
1558 Status
= ZwClose(hDesktop
);
1559 if (!NT_SUCCESS(Status
))
1561 ERR("Failed to close desktop handle 0x%p\n", hDesktop
);
1562 SetLastNtError(Status
);
1569 TRACE("Leave NtUserCloseDesktop, ret=%i\n",_ret_
);
1575 * NtUserPaintDesktop
1577 * The NtUserPaintDesktop function fills the clipping region in the
1578 * specified device context with the desktop pattern or wallpaper. The
1579 * function is provided primarily for shell desktops.
1583 * Handle to the device context.
1590 NtUserPaintDesktop(HDC hDC
)
1593 UserEnterExclusive();
1594 TRACE("Enter NtUserPaintDesktop\n");
1595 Ret
= IntPaintDesktop(hDC
);
1596 TRACE("Leave NtUserPaintDesktop, ret=%i\n",Ret
);
1602 * NtUserSwitchDesktop
1604 * Sets the current input (interactive) desktop.
1608 * Handle to desktop.
1618 NtUserSwitchDesktop(HDESK hdesk
)
1622 BOOL bRedrawDesktop
;
1623 DECLARE_RETURN(BOOL
);
1625 UserEnterExclusive();
1626 TRACE("Enter NtUserSwitchDesktop(0x%p)\n", hdesk
);
1628 Status
= IntValidateDesktopHandle( hdesk
, UserMode
, 0, &pdesk
);
1629 if (!NT_SUCCESS(Status
))
1631 ERR("Validation of desktop handle (0x%p) failed\n", hdesk
);
1635 if (PsGetCurrentProcessSessionId() != pdesk
->rpwinstaParent
->dwSessionId
)
1637 ERR("NtUserSwitchDesktop called for a desktop of a different session\n");
1641 if(pdesk
== gpdeskInputDesktop
)
1643 WARN("NtUserSwitchDesktop called for active desktop\n");
1648 * Don't allow applications switch the desktop if it's locked, unless the caller
1649 * is the logon application itself
1651 if((pdesk
->rpwinstaParent
->Flags
& WSS_LOCKED
) &&
1652 LogonProcess
!= PsGetCurrentProcessWin32Process())
1654 ObDereferenceObject(pdesk
);
1655 ERR("Switching desktop 0x%p denied because the window station is locked!\n", hdesk
);
1659 if(pdesk
->rpwinstaParent
!= InputWindowStation
)
1661 ObDereferenceObject(pdesk
);
1662 ERR("Switching desktop 0x%p denied because desktop doesn't belong to the interactive winsta!\n", hdesk
);
1666 /* FIXME: Fail if the process is associated with a secured
1667 desktop such as Winlogon or Screen-Saver */
1668 /* FIXME: Connect to input device */
1670 TRACE("Switching from desktop 0x%p to 0x%p\n", gpdeskInputDesktop
, pdesk
);
1672 bRedrawDesktop
= FALSE
;
1674 /* The first time SwitchDesktop is called, gpdeskInputDesktop is NULL */
1675 if(gpdeskInputDesktop
!= NULL
)
1677 if((gpdeskInputDesktop
->pDeskInfo
->spwnd
->style
& WS_VISIBLE
) == WS_VISIBLE
)
1678 bRedrawDesktop
= TRUE
;
1680 /* Hide the previous desktop window */
1681 IntHideDesktop(gpdeskInputDesktop
);
1684 /* Set the active desktop in the desktop's window station. */
1685 InputWindowStation
->ActiveDesktop
= pdesk
;
1687 /* Set the global state. */
1688 gpdeskInputDesktop
= pdesk
;
1690 /* Show the new desktop window */
1691 co_IntShowDesktop(pdesk
, UserGetSystemMetrics(SM_CXSCREEN
), UserGetSystemMetrics(SM_CYSCREEN
), bRedrawDesktop
);
1693 TRACE("SwitchDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop
);
1694 ObDereferenceObject(pdesk
);
1699 TRACE("Leave NtUserSwitchDesktop, ret=%i\n",_ret_
);
1705 * NtUserGetThreadDesktop
1712 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1716 PDESKTOP DesktopObject
;
1717 HDESK Ret
, hThreadDesktop
;
1718 OBJECT_HANDLE_INFORMATION HandleInformation
;
1719 DECLARE_RETURN(HDESK
);
1721 UserEnterExclusive();
1722 TRACE("Enter NtUserGetThreadDesktop\n");
1726 EngSetLastError(ERROR_INVALID_PARAMETER
);
1730 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)dwThreadId
, &Thread
);
1731 if(!NT_SUCCESS(Status
))
1733 EngSetLastError(ERROR_INVALID_PARAMETER
);
1737 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1739 /* Just return the handle, we queried the desktop handle of a thread running
1740 in the same context */
1741 Ret
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
;
1742 ObDereferenceObject(Thread
);
1746 /* Get the desktop handle and the desktop of the thread */
1747 if(!(hThreadDesktop
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
) ||
1748 !(DesktopObject
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->rpdesk
))
1750 ObDereferenceObject(Thread
);
1751 ERR("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1755 /* We could just use DesktopObject instead of looking up the handle, but latter
1756 may be a bit safer (e.g. when the desktop is being destroyed */
1757 /* Switch into the context of the thread we're trying to get the desktop from,
1758 so we can use the handle */
1759 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1760 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1762 ExDesktopObjectType
,
1764 (PVOID
*)&DesktopObject
,
1765 &HandleInformation
);
1768 /* The handle couldn't be found, there's nothing to get... */
1769 if(!NT_SUCCESS(Status
))
1771 ObDereferenceObject(Thread
);
1775 /* Lookup our handle table if we can find a handle to the desktop object,
1776 if not, create one */
1777 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1779 /* All done, we got a valid handle to the desktop */
1780 ObDereferenceObject(DesktopObject
);
1781 ObDereferenceObject(Thread
);
1785 TRACE("Leave NtUserGetThreadDesktop, ret=%p\n",_ret_
);
1791 IntUnmapDesktopView(IN PDESKTOP pdesk
)
1794 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1795 NTSTATUS Status
= STATUS_SUCCESS
;
1797 TRACE("IntUnmapDesktopView called for desktop object %p\n", pdesk
);
1799 ppi
= PsGetCurrentProcessWin32Process();
1800 PrevLink
= &ppi
->HeapMappings
.Next
;
1802 /* Unmap if we're the last thread using the desktop */
1803 HeapMapping
= *PrevLink
;
1804 while (HeapMapping
!= NULL
)
1806 if (HeapMapping
->KernelMapping
== (PVOID
)pdesk
->pheapDesktop
)
1808 if (--HeapMapping
->Count
== 0)
1810 *PrevLink
= HeapMapping
->Next
;
1812 TRACE("ppi 0x%p unmapped heap of desktop 0x%p\n", ppi
, pdesk
);
1813 Status
= MmUnmapViewOfSection(PsGetCurrentProcess(),
1814 HeapMapping
->UserMapping
);
1816 ObDereferenceObject(pdesk
);
1818 UserHeapFree(HeapMapping
);
1823 PrevLink
= &HeapMapping
->Next
;
1824 HeapMapping
= HeapMapping
->Next
;
1831 IntMapDesktopView(IN PDESKTOP pdesk
)
1834 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1835 PVOID UserBase
= NULL
;
1836 SIZE_T ViewSize
= 0;
1837 LARGE_INTEGER Offset
;
1840 TRACE("IntMapDesktopView called for desktop object 0x%p\n", pdesk
);
1842 ppi
= PsGetCurrentProcessWin32Process();
1843 PrevLink
= &ppi
->HeapMappings
.Next
;
1845 /* Find out if another thread already mapped the desktop heap */
1846 HeapMapping
= *PrevLink
;
1847 while (HeapMapping
!= NULL
)
1849 if (HeapMapping
->KernelMapping
== (PVOID
)pdesk
->pheapDesktop
)
1851 HeapMapping
->Count
++;
1852 return STATUS_SUCCESS
;
1855 PrevLink
= &HeapMapping
->Next
;
1856 HeapMapping
= HeapMapping
->Next
;
1859 /* We're the first, map the heap */
1860 Offset
.QuadPart
= 0;
1861 Status
= MmMapViewOfSection(pdesk
->hsectionDesktop
,
1862 PsGetCurrentProcess(),
1870 PAGE_EXECUTE_READ
); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
1871 if (!NT_SUCCESS(Status
))
1873 ERR("Failed to map desktop\n");
1877 TRACE("ppi 0x%p mapped heap of desktop 0x%p\n", ppi
, pdesk
);
1879 /* Add the mapping */
1880 HeapMapping
= UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING
));
1881 if (HeapMapping
== NULL
)
1883 MmUnmapViewOfSection(PsGetCurrentProcess(), UserBase
);
1884 ERR("UserHeapAlloc() failed!\n");
1885 return STATUS_NO_MEMORY
;
1888 HeapMapping
->Next
= NULL
;
1889 HeapMapping
->KernelMapping
= (PVOID
)pdesk
->pheapDesktop
;
1890 HeapMapping
->UserMapping
= UserBase
;
1891 HeapMapping
->Limit
= ViewSize
;
1892 HeapMapping
->Count
= 1;
1893 *PrevLink
= HeapMapping
;
1895 ObReferenceObject(pdesk
);
1897 return STATUS_SUCCESS
;
1901 IntSetThreadDesktop(IN HDESK hDesktop
,
1902 IN BOOL FreeOnFailure
)
1904 PDESKTOP pdesk
= NULL
, pdeskOld
;
1908 PCLIENTTHREADINFO pctiOld
, pctiNew
= NULL
;
1911 ASSERT(NtCurrentTeb());
1913 TRACE("IntSetThreadDesktop hDesktop:0x%p, FOF:%i\n",hDesktop
, FreeOnFailure
);
1915 pti
= PsGetCurrentThreadWin32Thread();
1916 pci
= pti
->pClientInfo
;
1918 /* If the caller gave us a desktop, ensure it is valid */
1919 if(hDesktop
!= NULL
)
1921 /* Validate the new desktop. */
1922 Status
= IntValidateDesktopHandle( hDesktop
, UserMode
, 0, &pdesk
);
1923 if (!NT_SUCCESS(Status
))
1925 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop
);
1929 if (pti
->rpdesk
== pdesk
)
1932 ObDereferenceObject(pdesk
);
1937 /* Make sure that we don't own any window in the current desktop */
1938 if (!IsListEmpty(&pti
->WindowListHead
))
1941 ObDereferenceObject(pdesk
);
1942 ERR("Attempted to change thread desktop although the thread has windows!\n");
1943 EngSetLastError(ERROR_BUSY
);
1947 /* Desktop is being re-set so clear out foreground. */
1948 if (pti
->rpdesk
!= pdesk
&& pti
->MessageQueue
== gpqForeground
)
1950 // Like above, there shouldn't be any windows, hooks or anything active on this threads desktop!
1951 IntSetFocusMessageQueue(NULL
);
1954 /* Before doing the switch, map the new desktop heap and allocate the new pcti */
1957 Status
= IntMapDesktopView(pdesk
);
1958 if (!NT_SUCCESS(Status
))
1960 ERR("Failed to map desktop heap!\n");
1961 ObDereferenceObject(pdesk
);
1962 SetLastNtError(Status
);
1966 pctiNew
= DesktopHeapAlloc( pdesk
, sizeof(CLIENTTHREADINFO
));
1969 ERR("Failed to allocate new pcti\n");
1970 IntUnmapDesktopView(pdesk
);
1971 ObDereferenceObject(pdesk
);
1972 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1977 /* free all classes or move them to the shared heap */
1978 if(pti
->rpdesk
!= NULL
)
1980 if(!IntCheckProcessDesktopClasses(pti
->rpdesk
, FreeOnFailure
))
1982 ERR("Failed to move process classes to shared heap!\n");
1985 DesktopHeapFree(pdesk
, pctiNew
);
1986 IntUnmapDesktopView(pdesk
);
1987 ObDereferenceObject(pdesk
);
1993 pdeskOld
= pti
->rpdesk
;
1994 hdeskOld
= pti
->hdesk
;
1995 if (pti
->pcti
!= &pti
->cti
)
1996 pctiOld
= pti
->pcti
;
2003 pti
->rpdesk
= pdesk
;
2004 pti
->hdesk
= hDesktop
;
2005 pti
->pDeskInfo
= pti
->rpdesk
->pDeskInfo
;
2006 pti
->pcti
= pctiNew
;
2008 pci
->ulClientDelta
= DesktopHeapGetUserDelta();
2009 pci
->pDeskInfo
= (PVOID
)((ULONG_PTR
)pti
->pDeskInfo
- pci
->ulClientDelta
);
2010 pci
->pClientThreadInfo
= (PVOID
)((ULONG_PTR
)pti
->pcti
- pci
->ulClientDelta
);
2012 /* initialize the new pcti */
2015 RtlCopyMemory(pctiNew
, pctiOld
, sizeof(CLIENTTHREADINFO
));
2019 RtlZeroMemory(pctiNew
, sizeof(CLIENTTHREADINFO
));
2020 pci
->fsHooks
= pti
->fsHooks
;
2021 pci
->dwTIFlags
= pti
->TIF_flags
;
2028 pti
->pDeskInfo
= NULL
;
2029 pti
->pcti
= &pti
->cti
; // Always point inside so there will be no crash when posting or sending msg's!
2030 pci
->ulClientDelta
= 0;
2031 pci
->pDeskInfo
= NULL
;
2032 pci
->pClientThreadInfo
= NULL
;
2035 /* clean up the old desktop */
2036 if(pdeskOld
!= NULL
)
2038 RemoveEntryList(&pti
->PtiLink
);
2039 if (pctiOld
) DesktopHeapFree(pdeskOld
, pctiOld
);
2040 IntUnmapDesktopView(pdeskOld
);
2041 ObDereferenceObject(pdeskOld
);
2047 InsertTailList(&pdesk
->PtiList
, &pti
->PtiLink
);
2050 TRACE("IntSetThreadDesktop: pti 0x%p ppi 0x%p switched from object 0x%p to 0x%p\n", pti
, pti
->ppi
, pdeskOld
, pdesk
);
2056 * NtUserSetThreadDesktop
2063 NtUserSetThreadDesktop(HDESK hDesktop
)
2067 UserEnterExclusive();
2069 // FIXME: IntSetThreadDesktop validates the desktop handle, it should happen
2070 // here too and set the NT error level. Q. Is it necessary to have the validation
2071 // in IntSetThreadDesktop? Is it needed there too?
2072 if (hDesktop
|| (!hDesktop
&& PsGetCurrentProcess() == gpepCSRSS
))
2073 ret
= IntSetThreadDesktop(hDesktop
, FALSE
);