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 InputDesktop
= NULL
;
30 HDESK InputDesktopHandle
= NULL
;
31 HDC ScreenDeviceContext
= NULL
;
32 PTHREADINFO gptiDesktopThread
;
33 HCURSOR gDesktopCursor
= NULL
;
35 /* OBJECT CALLBACKS **********************************************************/
39 IntDesktopObjectParse(IN PVOID ParseObject
,
41 IN OUT PACCESS_STATE AccessState
,
42 IN KPROCESSOR_MODE AccessMode
,
44 IN OUT PUNICODE_STRING CompleteName
,
45 IN OUT PUNICODE_STRING RemainingName
,
46 IN OUT PVOID Context OPTIONAL
,
47 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
52 OBJECT_ATTRIBUTES ObjectAttributes
;
53 PLIST_ENTRY NextEntry
, ListHead
;
54 PWINSTATION_OBJECT WinStaObject
= (PWINSTATION_OBJECT
)ParseObject
;
55 PUNICODE_STRING DesktopName
;
56 PBOOLEAN pContext
= (PBOOLEAN
) Context
;
61 /* Set the list pointers and loop the window station */
62 ListHead
= &WinStaObject
->DesktopListHead
;
63 NextEntry
= ListHead
->Flink
;
64 while (NextEntry
!= ListHead
)
66 /* Get the current desktop */
67 Desktop
= CONTAINING_RECORD(NextEntry
, DESKTOP
, ListEntry
);
70 DesktopName
= GET_DESKTOP_NAME(Desktop
);
73 /* Compare the name */
74 if (RtlEqualUnicodeString(RemainingName
,
76 (Attributes
& OBJ_CASE_INSENSITIVE
)))
78 /* We found a match. Did this come from a create? */
81 /* Unless OPEN_IF was given, fail with an error */
82 if (!(Attributes
& OBJ_OPENIF
))
85 return STATUS_OBJECT_NAME_COLLISION
;
89 /* Otherwise, return with a warning only */
90 Status
= STATUS_OBJECT_NAME_EXISTS
;
95 /* This was a real open, so this is OK */
96 Status
= STATUS_SUCCESS
;
99 /* Reference the desktop and return it */
100 ObReferenceObject(Desktop
);
106 /* Go to the next desktop */
107 NextEntry
= NextEntry
->Flink
;
110 /* If we got here but this isn't a create, then fail */
111 if (!Context
) return STATUS_OBJECT_NAME_NOT_FOUND
;
113 /* Create the desktop object */
114 InitializeObjectAttributes(&ObjectAttributes
, RemainingName
, 0, NULL
, NULL
);
115 Status
= ObCreateObject(KernelMode
,
124 if (!NT_SUCCESS(Status
)) return Status
;
126 /* Initialize the desktop */
127 Status
= UserInitializeDesktop(Desktop
, RemainingName
, WinStaObject
);
128 if (!NT_SUCCESS(Status
))
130 ObDereferenceObject(Desktop
);
134 /* Set the desktop object and return success */
137 return STATUS_SUCCESS
;
141 IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
143 PDESKTOP pdesk
= (PDESKTOP
)Parameters
->Object
;
145 TRACE("Deleting desktop object 0x%p\n", pdesk
);
147 ASSERT(pdesk
->pDeskInfo
->spwnd
->spwndChild
== NULL
);
149 if (pdesk
->pDeskInfo
->spwnd
)
150 co_UserDestroyWindow(pdesk
->pDeskInfo
->spwnd
);
152 if (pdesk
->spwndMessage
)
153 co_UserDestroyWindow(pdesk
->spwndMessage
);
155 /* Remove the desktop from the window station's list of associcated desktops */
156 RemoveEntryList(&pdesk
->ListEntry
);
159 IntFreeDesktopHeap(pdesk
);
163 IntDesktopOkToClose(PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS Parameters
)
165 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
169 /* This happens when we leak desktop handles */
170 return STATUS_SUCCESS
;
173 /* Do not allow the current desktop or the initial desktop to be closed */
174 if( Parameters
->Handle
== pti
->ppi
->hdeskStartup
||
175 Parameters
->Handle
== pti
->hdesk
)
177 return STATUS_ACCESS_DENIED
;
180 return STATUS_SUCCESS
;
183 NTSTATUS NTAPI
IntDesktopObjectOpen(PWIN32_OPENMETHOD_PARAMETERS Parameters
)
185 PPROCESSINFO ppi
= PsGetProcessWin32Process(Parameters
->Process
);
187 return STATUS_SUCCESS
;
189 return IntMapDesktopView((PDESKTOP
)Parameters
->Object
);
192 NTSTATUS NTAPI
IntDesktopObjectClose(PWIN32_CLOSEMETHOD_PARAMETERS Parameters
)
194 PPROCESSINFO ppi
= PsGetProcessWin32Process(Parameters
->Process
);
197 /* This happens when the process leaks desktop handles.
198 * At this point the PPROCESSINFO is already destroyed */
199 return STATUS_SUCCESS
;
202 return IntUnmapDesktopView((PDESKTOP
)Parameters
->Object
);
206 /* PRIVATE FUNCTIONS **********************************************************/
211 InitDesktopImpl(VOID
)
213 GENERIC_MAPPING IntDesktopMapping
= { DESKTOP_READ
,
218 /* Set Desktop Object Attributes */
219 ExDesktopObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(DESKTOP
);
220 ExDesktopObjectType
->TypeInfo
.GenericMapping
= IntDesktopMapping
;
221 ExDesktopObjectType
->TypeInfo
.ValidAccessMask
= DESKTOP_ALL_ACCESS
;
222 return STATUS_SUCCESS
;
225 static int GetSystemVersionString(LPWSTR buffer
)
227 RTL_OSVERSIONINFOEXW versionInfo
;
230 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
232 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
235 if (versionInfo
.dwMajorVersion
<= 4)
236 len
= swprintf(buffer
,
237 L
"ReactOS Version %d.%d %s Build %d",
238 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
239 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
241 len
= swprintf(buffer
,
242 L
"ReactOS %s (Build %d)",
243 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
250 IntParseDesktopPath(PEPROCESS Process
,
251 PUNICODE_STRING DesktopPath
,
255 OBJECT_ATTRIBUTES ObjectAttributes
;
256 UNICODE_STRING ObjectName
;
258 WCHAR wstrWinstaFullName
[MAX_PATH
], *pwstrWinsta
= NULL
, *pwstrDesktop
= NULL
;
267 if(DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
270 * Parse the desktop path string which can be in the form "WinSta\Desktop"
271 * or just "Desktop". In latter case WinSta0 will be used.
274 pwstrDesktop
= wcschr(DesktopPath
->Buffer
, L
'\\');
275 if(pwstrDesktop
!= NULL
)
279 pwstrWinsta
= DesktopPath
->Buffer
;
283 pwstrDesktop
= DesktopPath
->Buffer
;
287 TRACE("IntParseDesktopPath pwstrWinsta:%S pwstrDesktop:%S\n", pwstrWinsta
, pwstrDesktop
);
291 /* Search the process handle table for (inherited) window station
292 handles, use a more appropriate one than WinSta0 if possible. */
293 if (!ObFindHandleForObject(Process
,
295 ExWindowStationObjectType
,
300 /* We had no luck searching for opened handles, use WinSta0 now */
302 pwstrWinsta
= L
"WinSta0";
306 /* Search the process handle table for (inherited) desktop
307 handles, use a more appropriate one than Default if possible. */
308 if (!ObFindHandleForObject(Process
,
315 /* We had no luck searching for opened handles, use Desktop now */
317 pwstrDesktop
= L
"Default";
322 swprintf(wstrWinstaFullName
, L
"%wZ\\%ws", &gustrWindowStationsDir
, pwstrWinsta
);
323 RtlInitUnicodeString( &ObjectName
, wstrWinstaFullName
);
325 TRACE("parsed initial winsta: %wZ\n", &ObjectName
);
327 /* Open the window station */
328 InitializeObjectAttributes(&ObjectAttributes
,
330 OBJ_CASE_INSENSITIVE
,
334 Status
= ObOpenObjectByName(&ObjectAttributes
,
335 ExWindowStationObjectType
,
342 if(!NT_SUCCESS(Status
))
344 SetLastNtError(Status
);
345 ERR("Failed to reference window station %wZ PID: --!\n", &ObjectName
);
350 if(*hDesktop
== NULL
)
352 RtlInitUnicodeString(&ObjectName
, pwstrDesktop
);
354 TRACE("parsed initial desktop: %wZ\n", &ObjectName
);
356 /* Open the desktop object */
357 InitializeObjectAttributes(&ObjectAttributes
,
359 OBJ_CASE_INSENSITIVE
,
363 Status
= ObOpenObjectByName(&ObjectAttributes
,
371 if(!NT_SUCCESS(Status
))
376 SetLastNtError(Status
);
377 ERR("Failed to reference desktop %wZ PID: --!\n", &ObjectName
);
381 return STATUS_SUCCESS
;
385 * IntValidateDesktopHandle
387 * Validates the desktop handle.
390 * If the function succeeds, the handle remains referenced. If the
391 * fucntion fails, last error is set.
395 IntValidateDesktopHandle(
397 KPROCESSOR_MODE AccessMode
,
398 ACCESS_MASK DesiredAccess
,
403 Status
= ObReferenceObjectByHandle(
411 TRACE("IntValidateDesktopHandle: handle:0x%p obj:0x%p access:0x%x Status:0x%lx\n",
412 Desktop
, *Object
, DesiredAccess
, Status
);
414 if (!NT_SUCCESS(Status
))
415 SetLastNtError(Status
);
421 IntGetActiveDesktop(VOID
)
427 * Returns or creates a handle to the desktop object
430 IntGetDesktopObjectHandle(PDESKTOP DesktopObject
)
435 ASSERT(DesktopObject
);
437 if (!ObFindHandleForObject(PsGetCurrentProcess(),
443 Status
= ObOpenObjectByPointer(DesktopObject
,
450 if(!NT_SUCCESS(Status
))
452 /* Unable to create a handle */
453 ERR("Unable to create a desktop handle\n");
459 ERR("Got handle: %p\n", Ret
);
465 PUSER_MESSAGE_QUEUE FASTCALL
466 IntGetFocusMessageQueue(VOID
)
468 PDESKTOP pdo
= IntGetActiveDesktop();
471 TRACE("No active desktop\n");
474 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
478 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
480 PUSER_MESSAGE_QUEUE Old
;
481 PDESKTOP pdo
= IntGetActiveDesktop();
484 TRACE("No active desktop\n");
489 if(NewQueue
->Desktop
!= NULL
)
491 TRACE("Message Queue already attached to another desktop!\n");
494 IntReferenceMessageQueue(NewQueue
);
495 (void)InterlockedExchangePointer((PVOID
*)&NewQueue
->Desktop
, pdo
);
497 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchangePointer((PVOID
*)&pdo
->ActiveMessageQueue
, NewQueue
);
500 (void)InterlockedExchangePointer((PVOID
*)&Old
->Desktop
, 0);
501 IntDereferenceMessageQueue(Old
);
502 gpqForegroundPrev
= Old
;
504 // Only one Q can have active foreground even when there are more than one desktop.
505 if (NewQueue
) gpqForeground
= pdo
->ActiveMessageQueue
;
506 else gpqForeground
= NULL
;
510 IntGetThreadDesktopWindow(PTHREADINFO pti
)
512 if (!pti
) pti
= PsGetCurrentThreadWin32Thread();
513 if (pti
->pDeskInfo
) return pti
->pDeskInfo
->spwnd
;
517 PWND FASTCALL
co_GetDesktopWindow(PWND pWnd
)
519 if (pWnd
->head
.rpdesk
&&
520 pWnd
->head
.rpdesk
->pDeskInfo
)
521 return pWnd
->head
.rpdesk
->pDeskInfo
->spwnd
;
525 HWND FASTCALL
IntGetDesktopWindow(VOID
)
527 PDESKTOP pdo
= IntGetActiveDesktop();
530 TRACE("No active desktop\n");
533 return pdo
->DesktopWindow
;
536 PWND FASTCALL
UserGetDesktopWindow(VOID
)
538 PDESKTOP pdo
= IntGetActiveDesktop();
542 TRACE("No active desktop\n");
545 // return pdo->pDeskInfo->spwnd;
546 return UserGetWindowObject(pdo
->DesktopWindow
);
549 HWND FASTCALL
IntGetMessageWindow(VOID
)
551 PDESKTOP pdo
= IntGetActiveDesktop();
555 TRACE("No active desktop\n");
558 return pdo
->spwndMessage
->head
.h
;
561 PWND FASTCALL
UserGetMessageWindow(VOID
)
563 PDESKTOP pdo
= IntGetActiveDesktop();
567 TRACE("No active desktop\n");
570 return pdo
->spwndMessage
;
573 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
575 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
576 PDESKTOP pdo
= pti
->rpdesk
;
579 ERR("Thread doesn't have a desktop\n");
582 return pdo
->DesktopWindow
;
585 /* PUBLIC FUNCTIONS ***********************************************************/
588 DesktopWindowProc(PWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*lResult
)
592 //ERR("DesktopWindowProc\n");
601 Wnd
->fnid
= FNID_DESKTOP
;
603 *lResult
= (LRESULT
)TRUE
;
607 Value
= HandleToULong(PsGetCurrentProcessId());
609 co_UserSetWindowLong(UserHMGetHandle(Wnd
), DT_GWL_PROCESSID
, Value
, FALSE
);
610 Value
= HandleToULong(PsGetCurrentThreadId());
612 co_UserSetWindowLong(UserHMGetHandle(Wnd
), DT_GWL_THREADID
, Value
, FALSE
);
616 case WM_DISPLAYCHANGE
:
617 co_WinPosSetWindowPos(Wnd
, 0, 0, 0, LOWORD(lParam
), HIWORD(lParam
), SWP_NOZORDER
| SWP_NOACTIVATE
);
621 IntPaintDesktop((HDC
)wParam
);
627 if (IntBeginPaint(Wnd
, &Ps
))
629 IntEndPaint(Wnd
, &Ps
);
633 case WM_SYSCOLORCHANGE
:
634 co_UserRedrawWindow(Wnd
, NULL
, NULL
, RDW_INVALIDATE
|RDW_ERASE
|RDW_ALLCHILDREN
);
638 PCURICON_OBJECT pcurOld
, pcurNew
;
639 pcurNew
= UserGetCurIconObject(gDesktopCursor
);
644 pcurOld
= UserSetCursor(pcurNew
, FALSE
);
647 UserDereferenceObject(pcurOld
);
651 return TRUE
; /* We are done. Do not do any callbacks to user mode */
655 UserMessageWindowProc(PWND pwnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*lResult
)
662 pwnd
->fnid
|= FNID_MESSAGEWND
;
663 *lResult
= (LRESULT
)TRUE
;
666 pwnd
->fnid
|= FNID_DESTROY
;
670 return TRUE
; /* We are done. Do not do any callbacks to user mode */
673 VOID NTAPI
DesktopThreadMain()
678 gptiDesktopThread
= PsGetCurrentThreadWin32Thread();
680 UserEnterExclusive();
682 /* Register system classes. This thread does not belong to any desktop so the
683 classes will be allocated from the shared heap */
684 UserRegisterSystemClasses();
688 Ret
= co_IntGetPeekMessage(&Msg
, 0, 0, 0, PM_REMOVE
, TRUE
);
691 IntDispatchMessage(&Msg
);
699 UserGetDesktopDC(ULONG DcType
, BOOL EmptyDC
, BOOL ValidatehWnd
)
701 PWND DesktopObject
= 0;
704 if (DcType
== DC_TYPE_DIRECT
)
706 DesktopObject
= UserGetDesktopWindow();
707 DesktopHDC
= (HDC
)UserGetWindowDC(DesktopObject
);
711 PMONITOR pMonitor
= UserGetPrimaryMonitor();
712 DesktopHDC
= IntGdiCreateDisplayDC(pMonitor
->hDev
, DcType
, EmptyDC
);
724 Window
= UserGetDesktopWindow();
725 hRgn
= IntSysCreateRectRgnIndirect(&Window
->rcWindow
);
727 IntInvalidateWindows( Window
,
734 GreDeleteObject(hRgn
);
739 co_IntShowDesktop(PDESKTOP Desktop
, ULONG Width
, ULONG Height
)
743 Window
= IntGetWindowObject(Desktop
->DesktopWindow
);
747 ERR("No Desktop window.\n");
748 return STATUS_UNSUCCESSFUL
;
750 co_WinPosSetWindowPos(Window
, NULL
, 0, 0, Width
, Height
, SWP_NOACTIVATE
|SWP_NOZORDER
|SWP_SHOWWINDOW
);
752 co_UserRedrawWindow( Window
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
);
753 return STATUS_SUCCESS
;
757 IntHideDesktop(PDESKTOP Desktop
)
761 DesktopWnd
= IntGetWindowObject(Desktop
->DesktopWindow
);
764 return ERROR_INVALID_WINDOW_HANDLE
;
766 DesktopWnd
->style
&= ~WS_VISIBLE
;
768 return STATUS_SUCCESS
;
773 UserBuildShellHookHwndList(PDESKTOP Desktop
)
776 PSHELL_HOOK_WINDOW Current
;
779 /* FIXME: If we save nb elements in desktop, we dont have to loop to find nb entries */
780 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
783 if (!entries
) return NULL
;
785 list
= ExAllocatePoolWithTag(PagedPool
, sizeof(HWND
) * (entries
+ 1), USERTAG_WINDOWLIST
); /* alloc one extra for nullterm */
790 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
791 *cursor
++ = Current
->hWnd
;
793 *cursor
= NULL
; /* Nullterm list */
800 * Send the Message to the windows registered for ShellHook
801 * notifications. The lParam contents depend on the Message. See
802 * MSDN for more details (RegisterShellHookWindow)
804 VOID
co_IntShellHookNotify(WPARAM Message
, WPARAM wParam
, LPARAM lParam
)
806 PDESKTOP Desktop
= IntGetActiveDesktop();
809 if (!gpsi
->uiShellMsg
)
811 gpsi
->uiShellMsg
= IntAddAtom(L
"SHELLHOOK");
813 TRACE("MsgType = %x\n", gpsi
->uiShellMsg
);
814 if (!gpsi
->uiShellMsg
)
815 ERR("LastError: %x\n", EngGetLastError());
820 TRACE("IntShellHookNotify: No desktop!\n");
824 // FIXME: System Tray Support.
826 HwndList
= UserBuildShellHookHwndList(Desktop
);
829 HWND
* cursor
= HwndList
;
831 for (; *cursor
; cursor
++)
833 TRACE("Sending notify\n");
834 co_IntPostOrSendMessage(*cursor
,
837 (Message
== HSHELL_LANGUAGE
? lParam
: (LPARAM
)wParam
) );
840 ExFreePoolWithTag(HwndList
, USERTAG_WINDOWLIST
);
843 if (ISITHOOKED(WH_SHELL
))
845 co_HOOK_CallHooks(WH_SHELL
, Message
, wParam
, lParam
);
850 * Add the window to the ShellHookWindows list. The windows
851 * on that list get notifications that are important to shell
854 * TODO: Validate the window? I'm not sure if sending these messages to
855 * an unsuspecting application that is not your own is a nice thing to do.
857 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
859 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
860 PDESKTOP Desktop
= pti
->rpdesk
;
861 PSHELL_HOOK_WINDOW Entry
;
863 TRACE("IntRegisterShellHookWindow\n");
865 /* First deregister the window, so we can be sure it's never twice in the
868 IntDeRegisterShellHookWindow(hWnd
);
870 Entry
= ExAllocatePoolWithTag(PagedPool
,
871 sizeof(SHELL_HOOK_WINDOW
),
879 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
885 * Remove the window from the ShellHookWindows list. The windows
886 * on that list get notifications that are important to shell
889 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
891 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
892 PDESKTOP Desktop
= pti
->rpdesk
;
893 PSHELL_HOOK_WINDOW Current
;
895 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
897 if (Current
->hWnd
== hWnd
)
899 RemoveEntryList(&Current
->ListEntry
);
900 ExFreePoolWithTag(Current
, TAG_WINSTA
);
909 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop
)
911 /* FIXME: Disable until unmapping works in mm */
913 if (Desktop
->pheapDesktop
!= NULL
)
915 MmUnmapViewInSessionSpace(Desktop
->pheapDesktop
);
916 Desktop
->pheapDesktop
= NULL
;
919 if (Desktop
->hsectionDesktop
!= NULL
)
921 ObDereferenceObject(Desktop
->hsectionDesktop
);
922 Desktop
->hsectionDesktop
= NULL
;
928 IntPaintDesktop(HDC hDC
)
931 HBRUSH DesktopBrush
, PreviousBrush
;
933 BOOL doPatBlt
= TRUE
;
935 static WCHAR s_wszSafeMode
[] = L
"Safe Mode";
941 GdiGetClipBox(hDC
, &Rect
);
943 hWndDesktop
= IntGetDesktopWindow(); // rpdesk->DesktopWindow;
945 WndDesktop
= UserGetWindowObject(hWndDesktop
); // rpdesk->pDeskInfo->spwnd;
951 if (!UserGetSystemMetrics(SM_CLEANBOOT
))
953 DesktopBrush
= (HBRUSH
)WndDesktop
->pcls
->hbrBackground
;
956 * Paint desktop background
958 if (gspv
.hbmWallpaper
!= NULL
)
964 sz
.cx
= WndDesktop
->rcWindow
.right
- WndDesktop
->rcWindow
.left
;
965 sz
.cy
= WndDesktop
->rcWindow
.bottom
- WndDesktop
->rcWindow
.top
;
967 if (gspv
.WallpaperMode
== wmStretch
||
968 gspv
.WallpaperMode
== wmTile
)
975 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
976 x
= (sz
.cx
/ 2) - (gspv
.cxWallpaper
/ 2);
977 y
= (sz
.cy
/ 2) - (gspv
.cyWallpaper
/ 2);
980 hWallpaperDC
= NtGdiCreateCompatibleDC(hDC
);
981 if(hWallpaperDC
!= NULL
)
985 /* Fill in the area that the bitmap is not going to cover */
988 /* FIXME: Clip out the bitmap
989 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
990 once we support DSTINVERT */
991 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
992 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
993 NtGdiSelectBrush(hDC
, PreviousBrush
);
996 /*Do not fill the background after it is painted no matter the size of the picture */
999 hOldBitmap
= NtGdiSelectBitmap(hWallpaperDC
, gspv
.hbmWallpaper
);
1001 if (gspv
.WallpaperMode
== wmStretch
)
1003 if(Rect
.right
&& Rect
.bottom
)
1004 NtGdiStretchBlt(hDC
,
1018 else if (gspv
.WallpaperMode
== wmTile
)
1020 /* Paint the bitmap across the screen then down */
1021 for(y
= 0; y
< Rect
.bottom
; y
+= gspv
.cyWallpaper
)
1023 for(x
= 0; x
< Rect
.right
; x
+= gspv
.cxWallpaper
)
1053 NtGdiSelectBitmap(hWallpaperDC
, hOldBitmap
);
1054 NtGdiDeleteObjectApp(hWallpaperDC
);
1060 /* Black desktop background in Safe Mode */
1061 DesktopBrush
= StockObjects
[BLACK_BRUSH
];
1063 /* Back ground is set to none, clear the screen */
1066 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1067 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1068 NtGdiSelectBrush(hDC
, PreviousBrush
);
1072 * Display system version on the desktop background
1075 if (g_PaintDesktopVersion
||UserGetSystemMetrics(SM_CLEANBOOT
))
1077 static WCHAR s_wszVersion
[256] = {0};
1082 len
= wcslen(s_wszVersion
);
1086 len
= GetSystemVersionString(s_wszVersion
);
1091 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
1093 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1094 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1097 color_old
= IntGdiSetTextColor(hDC
, RGB(255,255,255));
1098 align_old
= IntGdiSetTextAlign(hDC
, TA_RIGHT
);
1099 mode_old
= IntGdiSetBkMode(hDC
, TRANSPARENT
);
1101 if(!UserGetSystemMetrics(SM_CLEANBOOT
))
1103 GreExtTextOutW(hDC
, rect
.right
-16, rect
.bottom
-48, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1108 /* Version information text in top center */
1109 IntGdiSetTextAlign(hDC
, TA_CENTER
|TA_TOP
);
1110 GreExtTextOutW(hDC
, (rect
.right
+rect
.left
)/2, rect
.top
, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1111 /* Safe Mode text in corners */
1112 len
= wcslen(s_wszSafeMode
);
1113 IntGdiSetTextAlign(hDC
, TA_RIGHT
|TA_TOP
);
1114 GreExtTextOutW(hDC
, rect
.right
, rect
.top
, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1115 IntGdiSetTextAlign(hDC
, TA_RIGHT
|TA_BASELINE
);
1116 GreExtTextOutW(hDC
, rect
.right
, rect
.bottom
, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1117 IntGdiSetTextAlign(hDC
, TA_LEFT
|TA_TOP
);
1118 GreExtTextOutW(hDC
, rect
.left
, rect
.top
, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1119 IntGdiSetTextAlign(hDC
, TA_LEFT
|TA_BASELINE
);
1120 GreExtTextOutW(hDC
, rect
.left
, rect
.bottom
, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1123 IntGdiSetBkMode(hDC
, mode_old
);
1124 IntGdiSetTextAlign(hDC
, align_old
);
1125 IntGdiSetTextColor(hDC
, color_old
);
1132 UserInitializeDesktop(PDESKTOP pdesk
, PUNICODE_STRING DesktopName
, PWINSTATION_OBJECT pwinsta
)
1134 PVOID DesktopHeapSystemBase
= NULL
;
1135 ULONG_PTR HeapSize
= 400 * 1024;
1136 SIZE_T DesktopInfoSize
;
1139 TRACE("UserInitializeDesktop desktop 0x%p with name %wZ\n", pdesk
, DesktopName
);
1141 RtlZeroMemory(pdesk
, sizeof(DESKTOP
));
1143 /* Link the desktop with the parent window station */
1144 pdesk
->rpwinstaParent
= pwinsta
;
1145 InsertTailList(&pwinsta
->DesktopListHead
, &pdesk
->ListEntry
);
1147 /* Create the desktop heap */
1148 pdesk
->hsectionDesktop
= NULL
;
1149 pdesk
->pheapDesktop
= UserCreateHeap(&pdesk
->hsectionDesktop
,
1150 &DesktopHeapSystemBase
,
1152 if (pdesk
->pheapDesktop
== NULL
)
1154 ERR("Failed to create desktop heap!\n");
1155 return STATUS_NO_MEMORY
;
1158 /* Create DESKTOPINFO */
1159 DesktopInfoSize
= sizeof(DESKTOPINFO
) + DesktopName
->Length
+ sizeof(WCHAR
);
1160 pdesk
->pDeskInfo
= RtlAllocateHeap(pdesk
->pheapDesktop
,
1161 HEAP_NO_SERIALIZE
| HEAP_ZERO_MEMORY
,
1163 if (pdesk
->pDeskInfo
== NULL
)
1165 ERR("Failed to create the DESKTOP structure!\n");
1166 return STATUS_NO_MEMORY
;
1169 /* Initialize the DESKTOPINFO */
1170 pdesk
->pDeskInfo
->pvDesktopBase
= DesktopHeapSystemBase
;
1171 pdesk
->pDeskInfo
->pvDesktopLimit
= (PVOID
)((ULONG_PTR
)DesktopHeapSystemBase
+ HeapSize
);
1172 RtlCopyMemory(pdesk
->pDeskInfo
->szDesktopName
,
1173 DesktopName
->Buffer
,
1174 DesktopName
->Length
+ sizeof(WCHAR
));
1175 for (i
= 0; i
< NB_HOOKS
; i
++)
1177 InitializeListHead(&pdesk
->pDeskInfo
->aphkStart
[i
]);
1180 InitializeListHead(&pdesk
->ShellHookWindows
);
1181 InitializeListHead(&pdesk
->PtiList
);
1183 return STATUS_SUCCESS
;
1186 /* SYSCALLS *******************************************************************/
1189 * NtUserCreateDesktop
1191 * Creates a new desktop.
1195 * Object Attributes.
1198 * Name of the device.
1204 * Interaction flags.
1207 * Requested type of access.
1211 * If the function succeeds, the return value is a handle to the newly
1212 * created desktop. If the specified desktop already exists, the function
1213 * succeeds and returns a handle to the existing desktop. When you are
1214 * finished using the handle, call the CloseDesktop function to close it.
1215 * If the function fails, the return value is NULL.
1222 NtUserCreateDesktop(
1223 POBJECT_ATTRIBUTES ObjectAttributes
,
1224 PUNICODE_STRING lpszDesktopDevice
,
1227 ACCESS_MASK dwDesiredAccess
)
1229 PDESKTOP pdesk
= NULL
;
1230 NTSTATUS Status
= STATUS_SUCCESS
;
1233 UNICODE_STRING ClassName
;
1234 LARGE_STRING WindowName
;
1235 BOOL NoHooks
= FALSE
;
1238 PTHREADINFO ptiCurrent
;
1241 DECLARE_RETURN(HDESK
);
1243 TRACE("Enter NtUserCreateDesktop\n");
1244 UserEnterExclusive();
1246 ptiCurrent
= PsGetCurrentThreadWin32Thread();
1248 ASSERT(gptiDesktopThread
);
1250 /* Turn off hooks when calling any CreateWindowEx from inside win32k. */
1251 NoHooks
= (ptiCurrent
->TIF_flags
& TIF_DISABLEHOOKS
);
1252 ptiCurrent
->TIF_flags
|= TIF_DISABLEHOOKS
;
1253 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
1256 * Try to open already existing desktop
1258 Status
= ObOpenObjectByName(
1260 ExDesktopObjectType
,
1266 if (!NT_SUCCESS(Status
))
1268 ERR("ObOpenObjectByName failed to open/create desktop\n");
1269 SetLastNtError(Status
);
1273 /* In case the object was not created (eg if it existed), return now */
1274 if (Context
== FALSE
)
1276 TRACE("NtUserCreateDesktop opened desktop %wZ\n", ObjectAttributes
->ObjectName
);
1280 /* Reference the desktop */
1281 Status
= ObReferenceObjectByHandle(hdesk
,
1283 ExDesktopObjectType
,
1287 if (!NT_SUCCESS(Status
))
1289 ERR("Failed to reference desktop object\n");
1290 SetLastNtError(Status
);
1294 if (!ptiCurrent
->rpdesk
) IntSetThreadDesktop(hdesk
,FALSE
);
1296 /* Get the desktop window class. The thread desktop does not belong to any desktop
1297 * so the classes created there (including the desktop class) are allocated in the shared heap
1298 * It would cause problems if we used a class that belongs to the caller
1300 ClassName
.Buffer
= WC_DESKTOP
;
1301 ClassName
.Length
= 0;
1302 pcls
= IntGetAndReferenceClass(&ClassName
, 0, TRUE
);
1309 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1310 RtlZeroMemory(&Cs
, sizeof(Cs
));
1311 Cs
.x
= UserGetSystemMetrics(SM_XVIRTUALSCREEN
),
1312 Cs
.y
= UserGetSystemMetrics(SM_YVIRTUALSCREEN
),
1313 Cs
.cx
= UserGetSystemMetrics(SM_CXVIRTUALSCREEN
),
1314 Cs
.cy
= UserGetSystemMetrics(SM_CYVIRTUALSCREEN
),
1315 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1316 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
1317 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1318 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1320 /* Use IntCreateWindow instead of co_UserCreateWindowEx cause the later expects a thread with a desktop */
1321 pWnd
= IntCreateWindow(&Cs
, &WindowName
, pcls
, NULL
, NULL
, NULL
, pdesk
);
1324 ERR("Failed to create desktop window for the new desktop\n");
1328 pdesk
->DesktopWindow
= pWnd
->head
.h
;
1329 pdesk
->pDeskInfo
->spwnd
= pWnd
;
1330 pWnd
->fnid
= FNID_DESKTOP
;
1332 ClassName
.Buffer
= MAKEINTATOM(gpsi
->atomSysClass
[ICLS_HWNDMESSAGE
]);
1333 ClassName
.Length
= 0;
1334 pcls
= IntGetAndReferenceClass(&ClassName
, 0, TRUE
);
1341 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1342 RtlZeroMemory(&Cs
, sizeof(Cs
));
1343 Cs
.cx
= Cs
.cy
= 100;
1344 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1345 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
1346 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1347 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1348 pWnd
= IntCreateWindow(&Cs
, &WindowName
, pcls
, NULL
, NULL
, NULL
, pdesk
);
1351 ERR("Failed to create message window for the new desktop\n");
1355 pdesk
->spwndMessage
= pWnd
;
1356 pWnd
->fnid
= FNID_MESSAGEWND
;
1359 if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki)
1360 Create Tooltip. Saved in DesktopObject->spwndTooltip.
1361 Tooltip dwExStyle: WS_EX_TOOLWINDOW|WS_EX_TOPMOST
1362 hWndParent are spwndMessage. Use hModuleWin for server side winproc!
1363 The rest is same as message window.
1364 http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx
1371 ObDereferenceObject(pdesk
);
1373 if (_ret_
== NULL
&& hdesk
!= NULL
)
1375 ObCloseHandle(hdesk
, UserMode
);
1379 ptiCurrent
->TIF_flags
&= ~TIF_DISABLEHOOKS
;
1380 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
1382 TRACE("Leave NtUserCreateDesktop, ret=%p\n",_ret_
);
1390 * Opens an existing desktop.
1394 * Name of the existing desktop.
1397 * Interaction flags.
1400 * Requested type of access.
1403 * Handle to the desktop or zero on failure.
1411 POBJECT_ATTRIBUTES ObjectAttributes
,
1413 ACCESS_MASK dwDesiredAccess
)
1418 Status
= ObOpenObjectByName(
1420 ExDesktopObjectType
,
1427 if (!NT_SUCCESS(Status
))
1429 ERR("Failed to open desktop\n");
1430 SetLastNtError(Status
);
1434 TRACE("Opened desktop %S with handle 0x%p\n", ObjectAttributes
->ObjectName
->Buffer
, Desktop
);
1440 * NtUserOpenInputDesktop
1442 * Opens the input (interactive) desktop.
1446 * Interaction flags.
1449 * Inheritance option.
1452 * Requested type of access.
1455 * Handle to the input desktop or zero on failure.
1462 NtUserOpenInputDesktop(
1465 ACCESS_MASK dwDesiredAccess
)
1471 UserEnterExclusive();
1472 TRACE("Enter NtUserOpenInputDesktop InputDesktopHandle 0x%p\n",InputDesktopHandle
);
1474 /* Get a pointer to the desktop object */
1475 Status
= IntValidateDesktopHandle(InputDesktopHandle
, UserMode
, 0, &pdesk
);
1476 if (!NT_SUCCESS(Status
))
1478 ERR("Validation of input desktop handle (0x%p) failed\n", InputDesktopHandle
);
1482 /* Create a new handle to the object */
1483 Status
= ObOpenObjectByPointer(
1488 ExDesktopObjectType
,
1492 ObDereferenceObject(pdesk
);
1494 if (!NT_SUCCESS(Status
))
1496 ERR("Failed to open input desktop object\n");
1497 SetLastNtError(Status
);
1501 TRACE("NtUserOpenInputDesktop returning 0x%p\n",hdesk
);
1507 * NtUserCloseDesktop
1509 * Closes a desktop handle.
1513 * Handle to the desktop.
1519 * The desktop handle can be created with NtUserCreateDesktop or
1520 * NtUserOpenDesktop. This function will fail if any thread in the calling
1521 * process is using the specified desktop handle or if the handle refers
1522 * to the initial desktop of the calling process.
1529 NtUserCloseDesktop(HDESK hDesktop
)
1533 DECLARE_RETURN(BOOL
);
1535 TRACE("NtUserCloseDesktop called (0x%p)\n", hDesktop
);
1536 UserEnterExclusive();
1538 if( hDesktop
== gptiCurrent
->hdesk
|| hDesktop
== gptiCurrent
->ppi
->hdeskStartup
)
1540 ERR("Attempted to close thread desktop\n");
1541 EngSetLastError(ERROR_BUSY
);
1545 Status
= IntValidateDesktopHandle( hDesktop
, UserMode
, 0, &pdesk
);
1546 if (!NT_SUCCESS(Status
))
1548 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop
);
1552 ObDereferenceObject(pdesk
);
1554 Status
= ZwClose(hDesktop
);
1555 if (!NT_SUCCESS(Status
))
1557 ERR("Failed to close desktop handle 0x%p\n", hDesktop
);
1558 SetLastNtError(Status
);
1565 TRACE("Leave NtUserCloseDesktop, ret=%i\n",_ret_
);
1571 * NtUserPaintDesktop
1573 * The NtUserPaintDesktop function fills the clipping region in the
1574 * specified device context with the desktop pattern or wallpaper. The
1575 * function is provided primarily for shell desktops.
1579 * Handle to the device context.
1586 NtUserPaintDesktop(HDC hDC
)
1589 UserEnterExclusive();
1590 TRACE("Enter NtUserPaintDesktop\n");
1591 Ret
= IntPaintDesktop(hDC
);
1592 TRACE("Leave NtUserPaintDesktop, ret=%i\n",Ret
);
1598 * NtUserSwitchDesktop
1600 * Sets the current input (interactive) desktop.
1604 * Handle to desktop.
1614 NtUserSwitchDesktop(HDESK hdesk
)
1618 DECLARE_RETURN(BOOL
);
1620 UserEnterExclusive();
1621 TRACE("Enter NtUserSwitchDesktop(0x%p)\n", hdesk
);
1623 Status
= IntValidateDesktopHandle( hdesk
, UserMode
, 0, &pdesk
);
1624 if (!NT_SUCCESS(Status
))
1626 ERR("Validation of desktop handle (0x%p) failed\n", hdesk
);
1631 * Don't allow applications switch the desktop if it's locked, unless the caller
1632 * is the logon application itself
1634 if((pdesk
->rpwinstaParent
->Flags
& WSS_LOCKED
) &&
1635 LogonProcess
!= PsGetCurrentProcessWin32Process())
1637 ObDereferenceObject(pdesk
);
1638 ERR("Switching desktop 0x%p denied because the window station is locked!\n", hdesk
);
1642 if(pdesk
->rpwinstaParent
!= InputWindowStation
)
1644 ObDereferenceObject(pdesk
);
1645 ERR("Switching desktop 0x%p denied because desktop doesn't belong to the interactive winsta!\n", hdesk
);
1649 /* FIXME: Fail if the process is associated with a secured
1650 desktop such as Winlogon or Screen-Saver */
1651 /* FIXME: Connect to input device */
1653 /* Set the active desktop in the desktop's window station. */
1654 InputWindowStation
->ActiveDesktop
= pdesk
;
1656 /* Set the global state. */
1657 InputDesktop
= pdesk
;
1658 InputDesktopHandle
= hdesk
;
1659 TRACE("SwitchDesktop InputDesktopHandle 0x%p\n",InputDesktopHandle
);
1660 ObDereferenceObject(pdesk
);
1665 TRACE("Leave NtUserSwitchDesktop, ret=%i\n",_ret_
);
1671 * NtUserGetThreadDesktop
1678 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1682 PDESKTOP DesktopObject
;
1683 HDESK Ret
, hThreadDesktop
;
1684 OBJECT_HANDLE_INFORMATION HandleInformation
;
1685 DECLARE_RETURN(HDESK
);
1687 UserEnterExclusive();
1688 TRACE("Enter NtUserGetThreadDesktop\n");
1692 EngSetLastError(ERROR_INVALID_PARAMETER
);
1696 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)dwThreadId
, &Thread
);
1697 if(!NT_SUCCESS(Status
))
1699 EngSetLastError(ERROR_INVALID_PARAMETER
);
1703 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1705 /* Just return the handle, we queried the desktop handle of a thread running
1706 in the same context */
1707 Ret
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
;
1708 ObDereferenceObject(Thread
);
1712 /* Get the desktop handle and the desktop of the thread */
1713 if(!(hThreadDesktop
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
) ||
1714 !(DesktopObject
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->rpdesk
))
1716 ObDereferenceObject(Thread
);
1717 ERR("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1721 /* We could just use DesktopObject instead of looking up the handle, but latter
1722 may be a bit safer (e.g. when the desktop is being destroyed */
1723 /* Switch into the context of the thread we're trying to get the desktop from,
1724 so we can use the handle */
1725 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1726 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1728 ExDesktopObjectType
,
1730 (PVOID
*)&DesktopObject
,
1731 &HandleInformation
);
1734 /* The handle couldn't be found, there's nothing to get... */
1735 if(!NT_SUCCESS(Status
))
1737 ObDereferenceObject(Thread
);
1741 /* Lookup our handle table if we can find a handle to the desktop object,
1742 if not, create one */
1743 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1745 /* All done, we got a valid handle to the desktop */
1746 ObDereferenceObject(DesktopObject
);
1747 ObDereferenceObject(Thread
);
1751 TRACE("Leave NtUserGetThreadDesktop, ret=%p\n",_ret_
);
1757 IntUnmapDesktopView(IN PDESKTOP pdesk
)
1760 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1761 NTSTATUS Status
= STATUS_SUCCESS
;
1763 TRACE("IntUnmapDesktopView called for desktop object %p\n", pdesk
);
1765 ppi
= PsGetCurrentProcessWin32Process();
1766 PrevLink
= &ppi
->HeapMappings
.Next
;
1768 /* Unmap if we're the last thread using the desktop */
1769 HeapMapping
= *PrevLink
;
1770 while (HeapMapping
!= NULL
)
1772 if (HeapMapping
->KernelMapping
== (PVOID
)pdesk
->pheapDesktop
)
1774 if (--HeapMapping
->Count
== 0)
1776 *PrevLink
= HeapMapping
->Next
;
1778 TRACE("ppi 0x%p unmapped heap of desktop 0x%p\n", ppi
, pdesk
);
1779 Status
= MmUnmapViewOfSection(PsGetCurrentProcess(),
1780 HeapMapping
->UserMapping
);
1782 ObDereferenceObject(pdesk
);
1784 UserHeapFree(HeapMapping
);
1789 PrevLink
= &HeapMapping
->Next
;
1790 HeapMapping
= HeapMapping
->Next
;
1797 IntMapDesktopView(IN PDESKTOP pdesk
)
1800 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1801 PVOID UserBase
= NULL
;
1802 SIZE_T ViewSize
= 0;
1803 LARGE_INTEGER Offset
;
1806 TRACE("IntMapDesktopView called for desktop object 0x%p\n", pdesk
);
1808 ppi
= PsGetCurrentProcessWin32Process();
1809 PrevLink
= &ppi
->HeapMappings
.Next
;
1811 /* Find out if another thread already mapped the desktop heap */
1812 HeapMapping
= *PrevLink
;
1813 while (HeapMapping
!= NULL
)
1815 if (HeapMapping
->KernelMapping
== (PVOID
)pdesk
->pheapDesktop
)
1817 HeapMapping
->Count
++;
1818 return STATUS_SUCCESS
;
1821 PrevLink
= &HeapMapping
->Next
;
1822 HeapMapping
= HeapMapping
->Next
;
1825 /* We're the first, map the heap */
1826 Offset
.QuadPart
= 0;
1827 Status
= MmMapViewOfSection(pdesk
->hsectionDesktop
,
1828 PsGetCurrentProcess(),
1836 PAGE_EXECUTE_READ
); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
1837 if (!NT_SUCCESS(Status
))
1839 ERR("Failed to map desktop\n");
1843 TRACE("ppi 0x%p mapped heap of desktop 0x%p\n", ppi
, pdesk
);
1845 /* Add the mapping */
1846 HeapMapping
= UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING
));
1847 if (HeapMapping
== NULL
)
1849 MmUnmapViewOfSection(PsGetCurrentProcess(), UserBase
);
1850 ERR("UserHeapAlloc() failed!\n");
1851 return STATUS_NO_MEMORY
;
1854 HeapMapping
->Next
= NULL
;
1855 HeapMapping
->KernelMapping
= (PVOID
)pdesk
->pheapDesktop
;
1856 HeapMapping
->UserMapping
= UserBase
;
1857 HeapMapping
->Limit
= ViewSize
;
1858 HeapMapping
->Count
= 1;
1859 *PrevLink
= HeapMapping
;
1861 ObReferenceObject(pdesk
);
1863 return STATUS_SUCCESS
;
1867 IntSetThreadDesktop(IN HDESK hDesktop
,
1868 IN BOOL FreeOnFailure
)
1870 PDESKTOP pdesk
= NULL
, pdeskOld
;
1874 PCLIENTTHREADINFO pctiOld
, pctiNew
= NULL
;
1877 ASSERT(NtCurrentTeb());
1879 TRACE("IntSetThreadDesktop hDesktop:0x%p, FOF:%i\n",hDesktop
, FreeOnFailure
);
1881 pti
= PsGetCurrentThreadWin32Thread();
1882 pci
= pti
->pClientInfo
;
1884 /* If the caller gave us a desktop, ensure it is valid */
1885 if(hDesktop
!= NULL
)
1887 /* Validate the new desktop. */
1888 Status
= IntValidateDesktopHandle( hDesktop
, UserMode
, 0, &pdesk
);
1889 if (!NT_SUCCESS(Status
))
1891 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop
);
1895 if (pti
->rpdesk
== pdesk
)
1898 ObDereferenceObject(pdesk
);
1903 /* Make sure that we don't own any window in the current desktop */
1904 if (!IsListEmpty(&pti
->WindowListHead
))
1907 ObDereferenceObject(pdesk
);
1908 ERR("Attempted to change thread desktop although the thread has windows!\n");
1909 EngSetLastError(ERROR_BUSY
);
1913 /* Desktop is being re-set so clear out foreground. */
1914 if (pti
->rpdesk
!= pdesk
&& pti
->MessageQueue
== gpqForeground
)
1916 // Like above, there shouldn't be any windows, hooks or anything active on this threads desktop!
1917 IntSetFocusMessageQueue(NULL
);
1920 /* Before doing the switch, map the new desktop heap and allocate the new pcti */
1923 Status
= IntMapDesktopView(pdesk
);
1924 if (!NT_SUCCESS(Status
))
1926 ERR("Failed to map desktop heap!\n");
1927 ObDereferenceObject(pdesk
);
1928 SetLastNtError(Status
);
1932 pctiNew
= DesktopHeapAlloc( pdesk
, sizeof(CLIENTTHREADINFO
));
1935 ERR("Failed to allocate new pcti\n");
1936 IntUnmapDesktopView(pdesk
);
1937 ObDereferenceObject(pdesk
);
1938 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1943 /* free all classes or move them to the shared heap */
1944 if(pti
->rpdesk
!= NULL
)
1946 if(!IntCheckProcessDesktopClasses(pti
->rpdesk
, FreeOnFailure
))
1948 ERR("Failed to move process classes to shared heap!\n");
1951 DesktopHeapFree(pdesk
, pctiNew
);
1952 IntUnmapDesktopView(pdesk
);
1953 ObDereferenceObject(pdesk
);
1959 pdeskOld
= pti
->rpdesk
;
1960 hdeskOld
= pti
->hdesk
;
1961 if (pti
->pcti
!= &pti
->cti
)
1962 pctiOld
= pti
->pcti
;
1969 pti
->rpdesk
= pdesk
;
1970 pti
->hdesk
= hDesktop
;
1971 pti
->pDeskInfo
= pti
->rpdesk
->pDeskInfo
;
1972 pti
->pcti
= pctiNew
;
1974 pci
->ulClientDelta
= DesktopHeapGetUserDelta();
1975 pci
->pDeskInfo
= (PVOID
)((ULONG_PTR
)pti
->pDeskInfo
- pci
->ulClientDelta
);
1976 pci
->pClientThreadInfo
= (PVOID
)((ULONG_PTR
)pti
->pcti
- pci
->ulClientDelta
);
1978 /* initialize the new pcti */
1981 RtlCopyMemory(pctiNew
, pctiOld
, sizeof(CLIENTTHREADINFO
));
1985 RtlZeroMemory(pctiNew
, sizeof(CLIENTTHREADINFO
));
1986 pci
->fsHooks
= pti
->fsHooks
;
1987 pci
->dwTIFlags
= pti
->TIF_flags
;
1994 pti
->pDeskInfo
= NULL
;
1995 pti
->pcti
= &pti
->cti
; // Always point inside so there will be no crash when posting or sending msg's!
1996 pci
->ulClientDelta
= 0;
1997 pci
->pDeskInfo
= NULL
;
1998 pci
->pClientThreadInfo
= NULL
;
2001 /* clean up the old desktop */
2002 if(pdeskOld
!= NULL
)
2004 RemoveEntryList(&pti
->PtiLink
);
2005 if (pctiOld
) DesktopHeapFree(pdeskOld
, pctiOld
);
2006 IntUnmapDesktopView(pdeskOld
);
2007 ObDereferenceObject(pdeskOld
);
2013 InsertTailList(&pdesk
->PtiList
, &pti
->PtiLink
);
2016 TRACE("IntSetThreadDesktop: pti 0x%p ppi 0x%p switched from object 0x%p to 0x%p\n", pti
, pti
->ppi
, pdeskOld
, pdesk
);
2022 * NtUserSetThreadDesktop
2029 NtUserSetThreadDesktop(HDESK hDesktop
)
2033 UserEnterExclusive();
2035 // FIXME: IntSetThreadDesktop validates the desktop handle, it should happen
2036 // here too and set the NT error level. Q. Is it necessary to have the validation
2037 // in IntSetThreadDesktop? Is it needed there too?
2038 if (hDesktop
|| (!hDesktop
&& CsrProcess
== PsGetCurrentProcess()))
2039 ret
= IntSetThreadDesktop(hDesktop
, FALSE
);