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 /* These can be changed via csrss startup, these are defaults */
29 DWORD gdwDesktopSectionSize
= 512;
30 DWORD gdwNOIOSectionSize
= 128; // A guess, for one or more of the first three system desktops.
32 /* Currently active desktop */
33 PDESKTOP gpdeskInputDesktop
= NULL
;
34 HDC ScreenDeviceContext
= NULL
;
35 PTHREADINFO gptiDesktopThread
= NULL
;
36 HCURSOR gDesktopCursor
= NULL
;
38 /* OBJECT CALLBACKS **********************************************************/
42 IntDesktopObjectParse(IN PVOID ParseObject
,
44 IN OUT PACCESS_STATE AccessState
,
45 IN KPROCESSOR_MODE AccessMode
,
47 IN OUT PUNICODE_STRING CompleteName
,
48 IN OUT PUNICODE_STRING RemainingName
,
49 IN OUT PVOID Context OPTIONAL
,
50 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
55 OBJECT_ATTRIBUTES ObjectAttributes
;
56 PLIST_ENTRY NextEntry
, ListHead
;
57 PWINSTATION_OBJECT WinStaObject
= (PWINSTATION_OBJECT
)ParseObject
;
58 UNICODE_STRING DesktopName
;
59 PBOOLEAN pContext
= (PBOOLEAN
) Context
;
64 /* Set the list pointers and loop the window station */
65 ListHead
= &WinStaObject
->DesktopListHead
;
66 NextEntry
= ListHead
->Flink
;
67 while (NextEntry
!= ListHead
)
69 /* Get the current desktop */
70 Desktop
= CONTAINING_RECORD(NextEntry
, DESKTOP
, ListEntry
);
72 /* Get the desktop name */
73 ASSERT(Desktop
->pDeskInfo
!= NULL
);
74 RtlInitUnicodeString(&DesktopName
, Desktop
->pDeskInfo
->szDesktopName
);
76 /* Compare the name */
77 if (RtlEqualUnicodeString(RemainingName
,
79 (Attributes
& OBJ_CASE_INSENSITIVE
) != 0))
81 /* We found a match. Did this come from a create? */
84 /* Unless OPEN_IF was given, fail with an error */
85 if (!(Attributes
& OBJ_OPENIF
))
88 return STATUS_OBJECT_NAME_COLLISION
;
92 /* Otherwise, return with a warning only */
93 Status
= STATUS_OBJECT_NAME_EXISTS
;
98 /* This was a real open, so this is OK */
99 Status
= STATUS_SUCCESS
;
102 /* Reference the desktop and return it */
103 ObReferenceObject(Desktop
);
108 /* Go to the next desktop */
109 NextEntry
= NextEntry
->Flink
;
112 /* If we got here but this isn't a create, then fail */
113 if (!Context
) return STATUS_OBJECT_NAME_NOT_FOUND
;
115 /* Create the desktop object */
116 InitializeObjectAttributes(&ObjectAttributes
, RemainingName
, 0, NULL
, NULL
);
117 Status
= ObCreateObject(KernelMode
,
126 if (!NT_SUCCESS(Status
)) return Status
;
128 /* Initialize the desktop */
129 Status
= UserInitializeDesktop(Desktop
, RemainingName
, WinStaObject
);
130 if (!NT_SUCCESS(Status
))
132 ObDereferenceObject(Desktop
);
136 /* Set the desktop object and return success */
139 return STATUS_SUCCESS
;
144 IntDesktopObjectDelete(
145 _In_ PVOID Parameters
)
147 PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters
= Parameters
;
148 PDESKTOP pdesk
= (PDESKTOP
)DeleteParameters
->Object
;
150 TRACE("Deleting desktop object 0x%p\n", pdesk
);
152 ASSERT(pdesk
->pDeskInfo
->spwnd
->spwndChild
== NULL
);
154 if (pdesk
->pDeskInfo
->spwnd
)
155 co_UserDestroyWindow(pdesk
->pDeskInfo
->spwnd
);
157 if (pdesk
->spwndMessage
)
158 co_UserDestroyWindow(pdesk
->spwndMessage
);
160 /* Remove the desktop from the window station's list of associcated desktops */
161 RemoveEntryList(&pdesk
->ListEntry
);
164 IntFreeDesktopHeap(pdesk
);
165 return STATUS_SUCCESS
;
171 _In_ PVOID Parameters
)
173 PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters
= Parameters
;
174 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
178 /* This happens when we leak desktop handles */
179 return STATUS_SUCCESS
;
182 /* Do not allow the current desktop or the initial desktop to be closed */
183 if( OkToCloseParameters
->Handle
== pti
->ppi
->hdeskStartup
||
184 OkToCloseParameters
->Handle
== pti
->hdesk
)
186 return STATUS_ACCESS_DENIED
;
189 return STATUS_SUCCESS
;
194 IntDesktopObjectOpen(
195 _In_ PVOID Parameters
)
197 PWIN32_OPENMETHOD_PARAMETERS OpenParameters
= Parameters
;
198 PPROCESSINFO ppi
= PsGetProcessWin32Process(OpenParameters
->Process
);
200 return STATUS_SUCCESS
;
202 return IntMapDesktopView((PDESKTOP
)OpenParameters
->Object
);
207 IntDesktopObjectClose(
208 _In_ PVOID Parameters
)
210 PWIN32_CLOSEMETHOD_PARAMETERS CloseParameters
= Parameters
;
211 PPROCESSINFO ppi
= PsGetProcessWin32Process(CloseParameters
->Process
);
214 /* This happens when the process leaks desktop handles.
215 * At this point the PPROCESSINFO is already destroyed */
216 return STATUS_SUCCESS
;
219 return IntUnmapDesktopView((PDESKTOP
)CloseParameters
->Object
);
223 /* PRIVATE FUNCTIONS **********************************************************/
228 InitDesktopImpl(VOID
)
230 GENERIC_MAPPING IntDesktopMapping
= { DESKTOP_READ
,
235 /* Set Desktop Object Attributes */
236 ExDesktopObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(DESKTOP
);
237 ExDesktopObjectType
->TypeInfo
.GenericMapping
= IntDesktopMapping
;
238 ExDesktopObjectType
->TypeInfo
.ValidAccessMask
= DESKTOP_ALL_ACCESS
;
239 return STATUS_SUCCESS
;
242 static int GetSystemVersionString(LPWSTR buffer
)
244 RTL_OSVERSIONINFOEXW versionInfo
;
247 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
249 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
252 if (versionInfo
.dwMajorVersion
<= 4)
253 len
= swprintf(buffer
,
254 L
"ReactOS Version %lu.%lu %s Build %lu",
255 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
256 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
258 len
= swprintf(buffer
,
259 L
"ReactOS %s (Build %lu)",
260 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
267 IntParseDesktopPath(PEPROCESS Process
,
268 PUNICODE_STRING DesktopPath
,
272 OBJECT_ATTRIBUTES ObjectAttributes
;
273 UNICODE_STRING ObjectName
;
275 WCHAR wstrWinstaFullName
[MAX_PATH
], *pwstrWinsta
= NULL
, *pwstrDesktop
= NULL
;
284 if(DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
287 * Parse the desktop path string which can be in the form "WinSta\Desktop"
288 * or just "Desktop". In latter case WinSta0 will be used.
291 pwstrDesktop
= wcschr(DesktopPath
->Buffer
, L
'\\');
292 if(pwstrDesktop
!= NULL
)
296 pwstrWinsta
= DesktopPath
->Buffer
;
300 pwstrDesktop
= DesktopPath
->Buffer
;
304 TRACE("IntParseDesktopPath pwstrWinsta:%S pwstrDesktop:%S\n", pwstrWinsta
, pwstrDesktop
);
308 /* Search the process handle table for (inherited) window station
309 handles, use a more appropriate one than WinSta0 if possible. */
310 if (!ObFindHandleForObject(Process
,
312 ExWindowStationObjectType
,
317 /* We had no luck searching for opened handles, use WinSta0 now */
319 pwstrWinsta
= L
"WinSta0";
323 /* Search the process handle table for (inherited) desktop
324 handles, use a more appropriate one than Default if possible. */
325 if (!ObFindHandleForObject(Process
,
332 /* We had no luck searching for opened handles, use Desktop now */
334 pwstrDesktop
= L
"Default";
339 swprintf(wstrWinstaFullName
, L
"%wZ\\%ws", &gustrWindowStationsDir
, pwstrWinsta
);
340 RtlInitUnicodeString( &ObjectName
, wstrWinstaFullName
);
342 TRACE("parsed initial winsta: %wZ\n", &ObjectName
);
344 /* Open the window station */
345 InitializeObjectAttributes(&ObjectAttributes
,
347 OBJ_CASE_INSENSITIVE
,
351 Status
= ObOpenObjectByName(&ObjectAttributes
,
352 ExWindowStationObjectType
,
359 if(!NT_SUCCESS(Status
))
361 SetLastNtError(Status
);
362 ERR("Failed to reference window station %wZ PID: --!\n", &ObjectName
);
367 if(*hDesktop
== NULL
)
369 RtlInitUnicodeString(&ObjectName
, pwstrDesktop
);
371 TRACE("parsed initial desktop: %wZ\n", &ObjectName
);
373 /* Open the desktop object */
374 InitializeObjectAttributes(&ObjectAttributes
,
376 OBJ_CASE_INSENSITIVE
,
380 Status
= ObOpenObjectByName(&ObjectAttributes
,
388 if(!NT_SUCCESS(Status
))
393 SetLastNtError(Status
);
394 ERR("Failed to reference desktop %wZ PID: --!\n", &ObjectName
);
398 return STATUS_SUCCESS
;
402 * IntValidateDesktopHandle
404 * Validates the desktop handle.
407 * If the function succeeds, the handle remains referenced. If the
408 * fucntion fails, last error is set.
412 IntValidateDesktopHandle(
414 KPROCESSOR_MODE AccessMode
,
415 ACCESS_MASK DesiredAccess
,
420 Status
= ObReferenceObjectByHandle(
428 TRACE("IntValidateDesktopHandle: handle:0x%p obj:0x%p access:0x%x Status:0x%lx\n",
429 Desktop
, *Object
, DesiredAccess
, Status
);
431 if (!NT_SUCCESS(Status
))
432 SetLastNtError(Status
);
438 IntGetActiveDesktop(VOID
)
440 return gpdeskInputDesktop
;
444 * Returns or creates a handle to the desktop object
447 IntGetDesktopObjectHandle(PDESKTOP DesktopObject
)
452 ASSERT(DesktopObject
);
454 if (!ObFindHandleForObject(PsGetCurrentProcess(),
460 Status
= ObOpenObjectByPointer(DesktopObject
,
467 if(!NT_SUCCESS(Status
))
469 /* Unable to create a handle */
470 ERR("Unable to create a desktop handle\n");
476 TRACE("Got handle: %p\n", Ret
);
482 PUSER_MESSAGE_QUEUE FASTCALL
483 IntGetFocusMessageQueue(VOID
)
485 PDESKTOP pdo
= IntGetActiveDesktop();
488 TRACE("No active desktop\n");
491 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
495 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
497 PUSER_MESSAGE_QUEUE Old
;
498 PDESKTOP pdo
= IntGetActiveDesktop();
501 TRACE("No active desktop\n");
506 if(NewQueue
->Desktop
!= NULL
)
508 TRACE("Message Queue already attached to another desktop!\n");
511 IntReferenceMessageQueue(NewQueue
);
512 (void)InterlockedExchangePointer((PVOID
*)&NewQueue
->Desktop
, pdo
);
514 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchangePointer((PVOID
*)&pdo
->ActiveMessageQueue
, NewQueue
);
517 (void)InterlockedExchangePointer((PVOID
*)&Old
->Desktop
, 0);
518 IntDereferenceMessageQueue(Old
);
519 gpqForegroundPrev
= Old
;
521 // Only one Q can have active foreground even when there are more than one desktop.
524 gpqForeground
= pdo
->ActiveMessageQueue
;
528 gpqForeground
= NULL
;
529 ERR("ptiLastInput is CLEARED!!\n");
530 ptiLastInput
= NULL
; // ReactOS hacks,,,, should check for process death.
535 IntGetThreadDesktopWindow(PTHREADINFO pti
)
537 if (!pti
) pti
= PsGetCurrentThreadWin32Thread();
538 if (pti
->pDeskInfo
) return pti
->pDeskInfo
->spwnd
;
542 PWND FASTCALL
co_GetDesktopWindow(PWND pWnd
)
544 if (pWnd
->head
.rpdesk
&&
545 pWnd
->head
.rpdesk
->pDeskInfo
)
546 return pWnd
->head
.rpdesk
->pDeskInfo
->spwnd
;
550 HWND FASTCALL
IntGetDesktopWindow(VOID
)
552 PDESKTOP pdo
= IntGetActiveDesktop();
555 TRACE("No active desktop\n");
558 return pdo
->DesktopWindow
;
561 PWND FASTCALL
UserGetDesktopWindow(VOID
)
563 PDESKTOP pdo
= IntGetActiveDesktop();
567 TRACE("No active desktop\n");
570 // return pdo->pDeskInfo->spwnd;
571 return UserGetWindowObject(pdo
->DesktopWindow
);
574 HWND FASTCALL
IntGetMessageWindow(VOID
)
576 PDESKTOP pdo
= IntGetActiveDesktop();
580 TRACE("No active desktop\n");
583 return pdo
->spwndMessage
->head
.h
;
586 PWND FASTCALL
UserGetMessageWindow(VOID
)
588 PDESKTOP pdo
= IntGetActiveDesktop();
592 TRACE("No active desktop\n");
595 return pdo
->spwndMessage
;
598 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
600 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
601 PDESKTOP pdo
= pti
->rpdesk
;
604 ERR("Thread doesn't have a desktop\n");
607 return pdo
->DesktopWindow
;
610 /* PUBLIC FUNCTIONS ***********************************************************/
613 DesktopWindowProc(PWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*lResult
)
617 //ERR("DesktopWindowProc\n");
626 Wnd
->fnid
= FNID_DESKTOP
;
628 *lResult
= (LRESULT
)TRUE
;
632 Value
= HandleToULong(PsGetCurrentProcessId());
634 co_UserSetWindowLong(UserHMGetHandle(Wnd
), DT_GWL_PROCESSID
, Value
, FALSE
);
635 Value
= HandleToULong(PsGetCurrentThreadId());
637 co_UserSetWindowLong(UserHMGetHandle(Wnd
), DT_GWL_THREADID
, Value
, FALSE
);
641 case WM_DISPLAYCHANGE
:
642 co_WinPosSetWindowPos(Wnd
, 0, 0, 0, LOWORD(lParam
), HIWORD(lParam
), SWP_NOZORDER
| SWP_NOACTIVATE
);
646 IntPaintDesktop((HDC
)wParam
);
652 if (IntBeginPaint(Wnd
, &Ps
))
654 IntEndPaint(Wnd
, &Ps
);
658 case WM_SYSCOLORCHANGE
:
659 co_UserRedrawWindow(Wnd
, NULL
, NULL
, RDW_INVALIDATE
|RDW_ERASE
|RDW_ALLCHILDREN
);
663 PCURICON_OBJECT pcurOld
, pcurNew
;
664 pcurNew
= UserGetCurIconObject(gDesktopCursor
);
669 #ifdef NEW_CURSORICON
670 pcurNew
->CURSORF_flags
|= CURSORF_CURRENT
;
672 pcurOld
= UserSetCursor(pcurNew
, FALSE
);
675 #ifdef NEW_CURSORICON
676 pcurOld
->CURSORF_flags
&= ~CURSORF_CURRENT
;
678 UserDereferenceObject(pcurOld
);
683 case WM_WINDOWPOSCHANGING
:
685 PWINDOWPOS pWindowPos
= (PWINDOWPOS
)lParam
;
686 if((pWindowPos
->flags
& SWP_SHOWWINDOW
) != 0)
688 HDESK hdesk
= IntGetDesktopObjectHandle(gpdeskInputDesktop
);
689 IntSetThreadDesktop(hdesk
, FALSE
);
694 return TRUE
; /* We are done. Do not do any callbacks to user mode */
698 UserMessageWindowProc(PWND pwnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*lResult
)
705 pwnd
->fnid
|= FNID_MESSAGEWND
;
706 *lResult
= (LRESULT
)TRUE
;
709 pwnd
->fnid
|= FNID_DESTROY
;
713 return TRUE
; /* We are done. Do not do any callbacks to user mode */
716 VOID NTAPI
DesktopThreadMain()
721 gptiDesktopThread
= PsGetCurrentThreadWin32Thread();
723 UserEnterExclusive();
725 /* Register system classes. This thread does not belong to any desktop so the
726 classes will be allocated from the shared heap */
727 UserRegisterSystemClasses();
731 Ret
= co_IntGetPeekMessage(&Msg
, 0, 0, 0, PM_REMOVE
, TRUE
);
734 IntDispatchMessage(&Msg
);
742 UserGetDesktopDC(ULONG DcType
, BOOL EmptyDC
, BOOL ValidatehWnd
)
744 PWND DesktopObject
= 0;
747 if (DcType
== DC_TYPE_DIRECT
)
749 DesktopObject
= UserGetDesktopWindow();
750 DesktopHDC
= (HDC
)UserGetWindowDC(DesktopObject
);
754 PMONITOR pMonitor
= UserGetPrimaryMonitor();
755 DesktopHDC
= IntGdiCreateDisplayDC(pMonitor
->hDev
, DcType
, EmptyDC
);
767 Window
= UserGetDesktopWindow();
768 Rgn
= IntSysCreateRectpRgnIndirect(&Window
->rcWindow
);
770 IntInvalidateWindows( Window
,
782 co_IntShowDesktop(PDESKTOP Desktop
, ULONG Width
, ULONG Height
, BOOL bRedraw
)
784 PWND pwnd
= Desktop
->pDeskInfo
->spwnd
;
785 UINT flags
= SWP_NOACTIVATE
|SWP_NOZORDER
|SWP_SHOWWINDOW
;
789 flags
|= SWP_NOREDRAW
;
791 co_WinPosSetWindowPos(pwnd
, NULL
, 0, 0, Width
, Height
, flags
);
794 co_UserRedrawWindow( pwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
| RDW_INVALIDATE
);
796 return STATUS_SUCCESS
;
800 IntHideDesktop(PDESKTOP Desktop
)
804 DesktopWnd
= IntGetWindowObject(Desktop
->DesktopWindow
);
807 return ERROR_INVALID_WINDOW_HANDLE
;
809 DesktopWnd
->style
&= ~WS_VISIBLE
;
811 return STATUS_SUCCESS
;
816 UserBuildShellHookHwndList(PDESKTOP Desktop
)
819 PLIST_ENTRY ListEntry
;
820 PSHELL_HOOK_WINDOW Current
;
823 /* FIXME: If we save nb elements in desktop, we dont have to loop to find nb entries */
824 ListEntry
= Desktop
->ShellHookWindows
.Flink
;
825 while (ListEntry
!= &Desktop
->ShellHookWindows
)
827 ListEntry
= ListEntry
->Flink
;
831 if (!entries
) return NULL
;
833 list
= ExAllocatePoolWithTag(PagedPool
, sizeof(HWND
) * (entries
+ 1), USERTAG_WINDOWLIST
); /* alloc one extra for nullterm */
838 ListEntry
= Desktop
->ShellHookWindows
.Flink
;
839 while (ListEntry
!= &Desktop
->ShellHookWindows
)
841 Current
= CONTAINING_RECORD(ListEntry
, SHELL_HOOK_WINDOW
, ListEntry
);
842 ListEntry
= ListEntry
->Flink
;
843 *cursor
++ = Current
->hWnd
;
846 *cursor
= NULL
; /* Nullterm list */
853 * Send the Message to the windows registered for ShellHook
854 * notifications. The lParam contents depend on the Message. See
855 * MSDN for more details (RegisterShellHookWindow)
857 VOID
co_IntShellHookNotify(WPARAM Message
, WPARAM wParam
, LPARAM lParam
)
859 PDESKTOP Desktop
= IntGetActiveDesktop();
862 if (!gpsi
->uiShellMsg
)
864 gpsi
->uiShellMsg
= IntAddAtom(L
"SHELLHOOK");
866 TRACE("MsgType = %x\n", gpsi
->uiShellMsg
);
867 if (!gpsi
->uiShellMsg
)
868 ERR("LastError: %x\n", EngGetLastError());
873 TRACE("IntShellHookNotify: No desktop!\n");
877 // Allow other devices have a shot at foreground.
878 if (Message
== HSHELL_APPCOMMAND
) ptiLastInput
= NULL
;
880 // FIXME: System Tray Support.
882 HwndList
= UserBuildShellHookHwndList(Desktop
);
885 HWND
* cursor
= HwndList
;
887 for (; *cursor
; cursor
++)
889 TRACE("Sending notify\n");
890 UserPostMessage(*cursor
,
893 (Message
== HSHELL_LANGUAGE
? lParam
: (LPARAM
)wParam
) );
894 /* co_IntPostOrSendMessage(*cursor,
897 (Message == HSHELL_LANGUAGE ? lParam : (LPARAM)wParam) );*/
900 ExFreePoolWithTag(HwndList
, USERTAG_WINDOWLIST
);
903 if (ISITHOOKED(WH_SHELL
))
905 co_HOOK_CallHooks(WH_SHELL
, Message
, wParam
, lParam
);
910 * Add the window to the ShellHookWindows list. The windows
911 * on that list get notifications that are important to shell
914 * TODO: Validate the window? I'm not sure if sending these messages to
915 * an unsuspecting application that is not your own is a nice thing to do.
917 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
919 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
920 PDESKTOP Desktop
= pti
->rpdesk
;
921 PSHELL_HOOK_WINDOW Entry
;
923 TRACE("IntRegisterShellHookWindow\n");
925 /* First deregister the window, so we can be sure it's never twice in the
928 IntDeRegisterShellHookWindow(hWnd
);
930 Entry
= ExAllocatePoolWithTag(PagedPool
,
931 sizeof(SHELL_HOOK_WINDOW
),
939 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
945 * Remove the window from the ShellHookWindows list. The windows
946 * on that list get notifications that are important to shell
949 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
951 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
952 PDESKTOP Desktop
= pti
->rpdesk
;
953 PLIST_ENTRY ListEntry
;
954 PSHELL_HOOK_WINDOW Current
;
956 ListEntry
= Desktop
->ShellHookWindows
.Flink
;
957 while (ListEntry
!= &Desktop
->ShellHookWindows
)
959 Current
= CONTAINING_RECORD(ListEntry
, SHELL_HOOK_WINDOW
, ListEntry
);
960 ListEntry
= ListEntry
->Flink
;
961 if (Current
->hWnd
== hWnd
)
963 RemoveEntryList(&Current
->ListEntry
);
964 ExFreePoolWithTag(Current
, TAG_WINSTA
);
973 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop
)
975 /* FIXME: Disable until unmapping works in mm */
977 if (Desktop
->pheapDesktop
!= NULL
)
979 MmUnmapViewInSessionSpace(Desktop
->pheapDesktop
);
980 Desktop
->pheapDesktop
= NULL
;
983 if (Desktop
->hsectionDesktop
!= NULL
)
985 ObDereferenceObject(Desktop
->hsectionDesktop
);
986 Desktop
->hsectionDesktop
= NULL
;
992 IntPaintDesktop(HDC hDC
)
995 HBRUSH DesktopBrush
, PreviousBrush
;
997 BOOL doPatBlt
= TRUE
;
999 static WCHAR s_wszSafeMode
[] = L
"Safe Mode";
1005 GdiGetClipBox(hDC
, &Rect
);
1007 hWndDesktop
= IntGetDesktopWindow(); // rpdesk->DesktopWindow;
1009 WndDesktop
= UserGetWindowObject(hWndDesktop
); // rpdesk->pDeskInfo->spwnd;
1015 if (!UserGetSystemMetrics(SM_CLEANBOOT
))
1017 DesktopBrush
= (HBRUSH
)WndDesktop
->pcls
->hbrBackground
;
1020 * Paint desktop background
1022 if (gspv
.hbmWallpaper
!= NULL
)
1028 sz
.cx
= WndDesktop
->rcWindow
.right
- WndDesktop
->rcWindow
.left
;
1029 sz
.cy
= WndDesktop
->rcWindow
.bottom
- WndDesktop
->rcWindow
.top
;
1031 if (gspv
.WallpaperMode
== wmStretch
||
1032 gspv
.WallpaperMode
== wmTile
)
1039 /* Find the upper left corner, can be negative if the bitmap is bigger then the screen */
1040 x
= (sz
.cx
/ 2) - (gspv
.cxWallpaper
/ 2);
1041 y
= (sz
.cy
/ 2) - (gspv
.cyWallpaper
/ 2);
1044 hWallpaperDC
= NtGdiCreateCompatibleDC(hDC
);
1045 if(hWallpaperDC
!= NULL
)
1049 /* Fill in the area that the bitmap is not going to cover */
1052 /* FIXME: Clip out the bitmap
1053 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1054 once we support DSTINVERT */
1055 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1056 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1057 NtGdiSelectBrush(hDC
, PreviousBrush
);
1060 /* Do not fill the background after it is painted no matter the size of the picture */
1063 hOldBitmap
= NtGdiSelectBitmap(hWallpaperDC
, gspv
.hbmWallpaper
);
1065 if (gspv
.WallpaperMode
== wmStretch
)
1067 if(Rect
.right
&& Rect
.bottom
)
1068 NtGdiStretchBlt(hDC
,
1082 else if (gspv
.WallpaperMode
== wmTile
)
1084 /* Paint the bitmap across the screen then down */
1085 for(y
= 0; y
< Rect
.bottom
; y
+= gspv
.cyWallpaper
)
1087 for(x
= 0; x
< Rect
.right
; x
+= gspv
.cxWallpaper
)
1117 NtGdiSelectBitmap(hWallpaperDC
, hOldBitmap
);
1118 NtGdiDeleteObjectApp(hWallpaperDC
);
1124 /* Black desktop background in Safe Mode */
1125 DesktopBrush
= StockObjects
[BLACK_BRUSH
];
1127 /* Back ground is set to none, clear the screen */
1130 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1131 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1132 NtGdiSelectBrush(hDC
, PreviousBrush
);
1136 * Display system version on the desktop background
1139 if (g_PaintDesktopVersion
|| UserGetSystemMetrics(SM_CLEANBOOT
))
1141 static WCHAR s_wszVersion
[256] = {0};
1146 len
= wcslen(s_wszVersion
);
1150 len
= GetSystemVersionString(s_wszVersion
);
1155 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
1157 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1158 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1161 color_old
= IntGdiSetTextColor(hDC
, RGB(255,255,255));
1162 align_old
= IntGdiSetTextAlign(hDC
, TA_RIGHT
);
1163 mode_old
= IntGdiSetBkMode(hDC
, TRANSPARENT
);
1165 if(!UserGetSystemMetrics(SM_CLEANBOOT
))
1167 GreExtTextOutW(hDC
, rect
.right
- 16, rect
.bottom
- 48, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1173 /* Version information text in top center */
1174 IntGdiSetTextAlign(hDC
, TA_CENTER
| TA_TOP
);
1175 GreExtTextOutW(hDC
, (rect
.right
+ rect
.left
)/2, rect
.top
+ 3, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1177 /* Safe Mode text in corners */
1178 len
= wcslen(s_wszSafeMode
);
1179 IntGdiSetTextAlign(hDC
, TA_LEFT
| TA_TOP
);
1180 GreExtTextOutW(hDC
, rect
.left
, rect
.top
+ 3, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1181 IntGdiSetTextAlign(hDC
, TA_RIGHT
| TA_TOP
);
1182 GreExtTextOutW(hDC
, rect
.right
, rect
.top
+ 3, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1183 IntGdiSetTextAlign(hDC
, TA_LEFT
| TA_BASELINE
);
1184 GreExtTextOutW(hDC
, rect
.left
, rect
.bottom
- 5, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1185 IntGdiSetTextAlign(hDC
, TA_RIGHT
| TA_BASELINE
);
1186 GreExtTextOutW(hDC
, rect
.right
, rect
.bottom
- 5, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1189 IntGdiSetBkMode(hDC
, mode_old
);
1190 IntGdiSetTextAlign(hDC
, align_old
);
1191 IntGdiSetTextColor(hDC
, color_old
);
1198 UserInitializeDesktop(PDESKTOP pdesk
, PUNICODE_STRING DesktopName
, PWINSTATION_OBJECT pwinsta
)
1200 PVOID DesktopHeapSystemBase
= NULL
;
1201 ULONG_PTR HeapSize
= gdwDesktopSectionSize
* 1024;
1202 SIZE_T DesktopInfoSize
;
1205 TRACE("UserInitializeDesktop desktop 0x%p with name %wZ\n", pdesk
, DesktopName
);
1207 RtlZeroMemory(pdesk
, sizeof(DESKTOP
));
1209 /* Link the desktop with the parent window station */
1210 pdesk
->rpwinstaParent
= pwinsta
;
1211 InsertTailList(&pwinsta
->DesktopListHead
, &pdesk
->ListEntry
);
1213 /* Create the desktop heap */
1214 pdesk
->hsectionDesktop
= NULL
;
1215 pdesk
->pheapDesktop
= UserCreateHeap(&pdesk
->hsectionDesktop
,
1216 &DesktopHeapSystemBase
,
1218 if (pdesk
->pheapDesktop
== NULL
)
1220 ERR("Failed to create desktop heap!\n");
1221 return STATUS_NO_MEMORY
;
1224 /* Create DESKTOPINFO */
1225 DesktopInfoSize
= sizeof(DESKTOPINFO
) + DesktopName
->Length
+ sizeof(WCHAR
);
1226 pdesk
->pDeskInfo
= RtlAllocateHeap(pdesk
->pheapDesktop
,
1227 HEAP_NO_SERIALIZE
| HEAP_ZERO_MEMORY
,
1229 if (pdesk
->pDeskInfo
== NULL
)
1231 ERR("Failed to create the DESKTOP structure!\n");
1232 return STATUS_NO_MEMORY
;
1235 /* Initialize the DESKTOPINFO */
1236 pdesk
->pDeskInfo
->pvDesktopBase
= DesktopHeapSystemBase
;
1237 pdesk
->pDeskInfo
->pvDesktopLimit
= (PVOID
)((ULONG_PTR
)DesktopHeapSystemBase
+ HeapSize
);
1238 RtlCopyMemory(pdesk
->pDeskInfo
->szDesktopName
,
1239 DesktopName
->Buffer
,
1240 DesktopName
->Length
+ sizeof(WCHAR
));
1241 for (i
= 0; i
< NB_HOOKS
; i
++)
1243 InitializeListHead(&pdesk
->pDeskInfo
->aphkStart
[i
]);
1246 InitializeListHead(&pdesk
->ShellHookWindows
);
1247 InitializeListHead(&pdesk
->PtiList
);
1249 return STATUS_SUCCESS
;
1252 /* SYSCALLS *******************************************************************/
1255 * NtUserCreateDesktop
1257 * Creates a new desktop.
1261 * Object Attributes.
1264 * Name of the device.
1270 * Interaction flags.
1273 * Requested type of access.
1277 * If the function succeeds, the return value is a handle to the newly
1278 * created desktop. If the specified desktop already exists, the function
1279 * succeeds and returns a handle to the existing desktop. When you are
1280 * finished using the handle, call the CloseDesktop function to close it.
1281 * If the function fails, the return value is NULL.
1288 NtUserCreateDesktop(
1289 POBJECT_ATTRIBUTES ObjectAttributes
,
1290 PUNICODE_STRING lpszDesktopDevice
,
1293 ACCESS_MASK dwDesiredAccess
)
1295 PDESKTOP pdesk
= NULL
;
1296 NTSTATUS Status
= STATUS_SUCCESS
;
1299 UNICODE_STRING ClassName
;
1300 LARGE_STRING WindowName
;
1301 BOOL NoHooks
= FALSE
;
1304 PTHREADINFO ptiCurrent
;
1307 DECLARE_RETURN(HDESK
);
1309 TRACE("Enter NtUserCreateDesktop\n");
1310 UserEnterExclusive();
1312 ptiCurrent
= PsGetCurrentThreadWin32Thread();
1314 ASSERT(gptiDesktopThread
);
1316 /* Turn off hooks when calling any CreateWindowEx from inside win32k. */
1317 NoHooks
= (ptiCurrent
->TIF_flags
& TIF_DISABLEHOOKS
);
1318 ptiCurrent
->TIF_flags
|= TIF_DISABLEHOOKS
;
1319 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
1322 * Try to open already existing desktop
1324 Status
= ObOpenObjectByName(
1326 ExDesktopObjectType
,
1332 if (!NT_SUCCESS(Status
))
1334 ERR("ObOpenObjectByName failed to open/create desktop\n");
1335 SetLastNtError(Status
);
1339 /* In case the object was not created (eg if it existed), return now */
1340 if (Context
== FALSE
)
1342 TRACE("NtUserCreateDesktop opened desktop %wZ\n", ObjectAttributes
->ObjectName
);
1346 /* Reference the desktop */
1347 Status
= ObReferenceObjectByHandle(hdesk
,
1349 ExDesktopObjectType
,
1353 if (!NT_SUCCESS(Status
))
1355 ERR("Failed to reference desktop object\n");
1356 SetLastNtError(Status
);
1360 /* Get the desktop window class. The thread desktop does not belong to any desktop
1361 * so the classes created there (including the desktop class) are allocated in the shared heap
1362 * It would cause problems if we used a class that belongs to the caller
1364 ClassName
.Buffer
= WC_DESKTOP
;
1365 ClassName
.Length
= 0;
1366 pcls
= IntGetAndReferenceClass(&ClassName
, 0, TRUE
);
1373 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1374 RtlZeroMemory(&Cs
, sizeof(Cs
));
1375 Cs
.x
= UserGetSystemMetrics(SM_XVIRTUALSCREEN
),
1376 Cs
.y
= UserGetSystemMetrics(SM_YVIRTUALSCREEN
),
1377 Cs
.cx
= UserGetSystemMetrics(SM_CXVIRTUALSCREEN
),
1378 Cs
.cy
= UserGetSystemMetrics(SM_CYVIRTUALSCREEN
),
1379 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1380 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
1381 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1382 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1384 /* Use IntCreateWindow instead of co_UserCreateWindowEx cause the later expects a thread with a desktop */
1385 pWnd
= IntCreateWindow(&Cs
, &WindowName
, pcls
, NULL
, NULL
, NULL
, pdesk
);
1388 ERR("Failed to create desktop window for the new desktop\n");
1392 pdesk
->dwSessionId
= PsGetCurrentProcessSessionId();
1393 pdesk
->DesktopWindow
= pWnd
->head
.h
;
1394 pdesk
->pDeskInfo
->spwnd
= pWnd
;
1395 pWnd
->fnid
= FNID_DESKTOP
;
1397 ClassName
.Buffer
= MAKEINTATOM(gpsi
->atomSysClass
[ICLS_HWNDMESSAGE
]);
1398 ClassName
.Length
= 0;
1399 pcls
= IntGetAndReferenceClass(&ClassName
, 0, TRUE
);
1406 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1407 RtlZeroMemory(&Cs
, sizeof(Cs
));
1408 Cs
.cx
= Cs
.cy
= 100;
1409 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1410 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
1411 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1412 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1413 pWnd
= IntCreateWindow(&Cs
, &WindowName
, pcls
, NULL
, NULL
, NULL
, pdesk
);
1416 ERR("Failed to create message window for the new desktop\n");
1420 pdesk
->spwndMessage
= pWnd
;
1421 pWnd
->fnid
= FNID_MESSAGEWND
;
1424 if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki)
1425 Create Tooltip. Saved in DesktopObject->spwndTooltip.
1426 Tooltip dwExStyle: WS_EX_TOOLWINDOW|WS_EX_TOPMOST
1427 hWndParent are spwndMessage. Use hModuleWin for server side winproc!
1428 The rest is same as message window.
1429 http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx
1436 ObDereferenceObject(pdesk
);
1438 if (_ret_
== NULL
&& hdesk
!= NULL
)
1440 ObCloseHandle(hdesk
, UserMode
);
1444 ptiCurrent
->TIF_flags
&= ~TIF_DISABLEHOOKS
;
1445 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
1447 TRACE("Leave NtUserCreateDesktop, ret=%p\n",_ret_
);
1455 * Opens an existing desktop.
1459 * Name of the existing desktop.
1462 * Interaction flags.
1465 * Requested type of access.
1468 * Handle to the desktop or zero on failure.
1476 POBJECT_ATTRIBUTES ObjectAttributes
,
1478 ACCESS_MASK dwDesiredAccess
)
1483 Status
= ObOpenObjectByName(
1485 ExDesktopObjectType
,
1492 if (!NT_SUCCESS(Status
))
1494 ERR("Failed to open desktop\n");
1495 SetLastNtError(Status
);
1499 TRACE("Opened desktop %S with handle 0x%p\n", ObjectAttributes
->ObjectName
->Buffer
, Desktop
);
1505 * NtUserOpenInputDesktop
1507 * Opens the input (interactive) desktop.
1511 * Interaction flags.
1514 * Inheritance option.
1517 * Requested type of access.
1520 * Handle to the input desktop or zero on failure.
1527 NtUserOpenInputDesktop(
1530 ACCESS_MASK dwDesiredAccess
)
1534 ULONG HandleAttributes
= 0;
1536 UserEnterExclusive();
1537 TRACE("Enter NtUserOpenInputDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop
);
1539 if(fInherit
) HandleAttributes
= OBJ_INHERIT
;
1541 /* Create a new handle to the object */
1542 Status
= ObOpenObjectByPointer(
1547 ExDesktopObjectType
,
1551 if (!NT_SUCCESS(Status
))
1553 ERR("Failed to open input desktop object\n");
1554 SetLastNtError(Status
);
1557 TRACE("NtUserOpenInputDesktop returning 0x%p\n",hdesk
);
1563 * NtUserCloseDesktop
1565 * Closes a desktop handle.
1569 * Handle to the desktop.
1575 * The desktop handle can be created with NtUserCreateDesktop or
1576 * NtUserOpenDesktop. This function will fail if any thread in the calling
1577 * process is using the specified desktop handle or if the handle refers
1578 * to the initial desktop of the calling process.
1585 NtUserCloseDesktop(HDESK hDesktop
)
1589 DECLARE_RETURN(BOOL
);
1591 TRACE("NtUserCloseDesktop called (0x%p)\n", hDesktop
);
1592 UserEnterExclusive();
1594 if( hDesktop
== gptiCurrent
->hdesk
|| hDesktop
== gptiCurrent
->ppi
->hdeskStartup
)
1596 ERR("Attempted to close thread desktop\n");
1597 EngSetLastError(ERROR_BUSY
);
1601 Status
= IntValidateDesktopHandle( hDesktop
, UserMode
, 0, &pdesk
);
1602 if (!NT_SUCCESS(Status
))
1604 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop
);
1608 ObDereferenceObject(pdesk
);
1610 Status
= ZwClose(hDesktop
);
1611 if (!NT_SUCCESS(Status
))
1613 ERR("Failed to close desktop handle 0x%p\n", hDesktop
);
1614 SetLastNtError(Status
);
1621 TRACE("Leave NtUserCloseDesktop, ret=%i\n",_ret_
);
1627 * NtUserPaintDesktop
1629 * The NtUserPaintDesktop function fills the clipping region in the
1630 * specified device context with the desktop pattern or wallpaper. The
1631 * function is provided primarily for shell desktops.
1635 * Handle to the device context.
1642 NtUserPaintDesktop(HDC hDC
)
1645 UserEnterExclusive();
1646 TRACE("Enter NtUserPaintDesktop\n");
1647 Ret
= IntPaintDesktop(hDC
);
1648 TRACE("Leave NtUserPaintDesktop, ret=%i\n",Ret
);
1654 * NtUserSwitchDesktop
1656 * Sets the current input (interactive) desktop.
1660 * Handle to desktop.
1670 NtUserSwitchDesktop(HDESK hdesk
)
1674 BOOL bRedrawDesktop
;
1675 DECLARE_RETURN(BOOL
);
1677 UserEnterExclusive();
1678 TRACE("Enter NtUserSwitchDesktop(0x%p)\n", hdesk
);
1680 Status
= IntValidateDesktopHandle( hdesk
, UserMode
, 0, &pdesk
);
1681 if (!NT_SUCCESS(Status
))
1683 ERR("Validation of desktop handle (0x%p) failed\n", hdesk
);
1687 if (PsGetCurrentProcessSessionId() != pdesk
->rpwinstaParent
->dwSessionId
)
1689 ERR("NtUserSwitchDesktop called for a desktop of a different session\n");
1693 if(pdesk
== gpdeskInputDesktop
)
1695 WARN("NtUserSwitchDesktop called for active desktop\n");
1700 * Don't allow applications switch the desktop if it's locked, unless the caller
1701 * is the logon application itself
1703 if((pdesk
->rpwinstaParent
->Flags
& WSS_LOCKED
) &&
1704 gpidLogon
!= PsGetCurrentProcessId())
1706 ObDereferenceObject(pdesk
);
1707 ERR("Switching desktop 0x%p denied because the window station is locked!\n", hdesk
);
1711 if(pdesk
->rpwinstaParent
!= InputWindowStation
)
1713 ObDereferenceObject(pdesk
);
1714 ERR("Switching desktop 0x%p denied because desktop doesn't belong to the interactive winsta!\n", hdesk
);
1718 /* FIXME: Fail if the process is associated with a secured
1719 desktop such as Winlogon or Screen-Saver */
1720 /* FIXME: Connect to input device */
1722 TRACE("Switching from desktop 0x%p to 0x%p\n", gpdeskInputDesktop
, pdesk
);
1724 bRedrawDesktop
= FALSE
;
1726 /* The first time SwitchDesktop is called, gpdeskInputDesktop is NULL */
1727 if(gpdeskInputDesktop
!= NULL
)
1729 if((gpdeskInputDesktop
->pDeskInfo
->spwnd
->style
& WS_VISIBLE
) == WS_VISIBLE
)
1730 bRedrawDesktop
= TRUE
;
1732 /* Hide the previous desktop window */
1733 IntHideDesktop(gpdeskInputDesktop
);
1736 /* Set the active desktop in the desktop's window station. */
1737 InputWindowStation
->ActiveDesktop
= pdesk
;
1739 /* Set the global state. */
1740 gpdeskInputDesktop
= pdesk
;
1742 /* Show the new desktop window */
1743 co_IntShowDesktop(pdesk
, UserGetSystemMetrics(SM_CXSCREEN
), UserGetSystemMetrics(SM_CYSCREEN
), bRedrawDesktop
);
1745 TRACE("SwitchDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop
);
1746 ObDereferenceObject(pdesk
);
1751 TRACE("Leave NtUserSwitchDesktop, ret=%i\n",_ret_
);
1757 * NtUserGetThreadDesktop
1764 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1768 PDESKTOP DesktopObject
;
1769 HDESK Ret
, hThreadDesktop
;
1770 OBJECT_HANDLE_INFORMATION HandleInformation
;
1771 DECLARE_RETURN(HDESK
);
1773 UserEnterExclusive();
1774 TRACE("Enter NtUserGetThreadDesktop\n");
1778 EngSetLastError(ERROR_INVALID_PARAMETER
);
1782 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)dwThreadId
, &Thread
);
1783 if(!NT_SUCCESS(Status
))
1785 EngSetLastError(ERROR_INVALID_PARAMETER
);
1789 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1791 /* Just return the handle, we queried the desktop handle of a thread running
1792 in the same context */
1793 Ret
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
;
1794 ObDereferenceObject(Thread
);
1798 /* Get the desktop handle and the desktop of the thread */
1799 if(!(hThreadDesktop
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
) ||
1800 !(DesktopObject
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->rpdesk
))
1802 ObDereferenceObject(Thread
);
1803 ERR("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1807 /* We could just use DesktopObject instead of looking up the handle, but latter
1808 may be a bit safer (e.g. when the desktop is being destroyed */
1809 /* Switch into the context of the thread we're trying to get the desktop from,
1810 so we can use the handle */
1811 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1812 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1814 ExDesktopObjectType
,
1816 (PVOID
*)&DesktopObject
,
1817 &HandleInformation
);
1820 /* The handle couldn't be found, there's nothing to get... */
1821 if(!NT_SUCCESS(Status
))
1823 ObDereferenceObject(Thread
);
1827 /* Lookup our handle table if we can find a handle to the desktop object,
1828 if not, create one */
1829 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1831 /* All done, we got a valid handle to the desktop */
1832 ObDereferenceObject(DesktopObject
);
1833 ObDereferenceObject(Thread
);
1837 TRACE("Leave NtUserGetThreadDesktop, ret=%p\n",_ret_
);
1843 IntUnmapDesktopView(IN PDESKTOP pdesk
)
1846 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1847 NTSTATUS Status
= STATUS_SUCCESS
;
1849 TRACE("IntUnmapDesktopView called for desktop object %p\n", pdesk
);
1851 ppi
= PsGetCurrentProcessWin32Process();
1852 PrevLink
= &ppi
->HeapMappings
.Next
;
1854 /* Unmap if we're the last thread using the desktop */
1855 HeapMapping
= *PrevLink
;
1856 while (HeapMapping
!= NULL
)
1858 if (HeapMapping
->KernelMapping
== (PVOID
)pdesk
->pheapDesktop
)
1860 if (--HeapMapping
->Count
== 0)
1862 *PrevLink
= HeapMapping
->Next
;
1864 TRACE("ppi 0x%p unmapped heap of desktop 0x%p\n", ppi
, pdesk
);
1865 Status
= MmUnmapViewOfSection(PsGetCurrentProcess(),
1866 HeapMapping
->UserMapping
);
1868 ObDereferenceObject(pdesk
);
1870 UserHeapFree(HeapMapping
);
1875 PrevLink
= &HeapMapping
->Next
;
1876 HeapMapping
= HeapMapping
->Next
;
1883 IntMapDesktopView(IN PDESKTOP pdesk
)
1886 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1887 PVOID UserBase
= NULL
;
1888 SIZE_T ViewSize
= 0;
1889 LARGE_INTEGER Offset
;
1892 TRACE("IntMapDesktopView called for desktop object 0x%p\n", pdesk
);
1894 ppi
= PsGetCurrentProcessWin32Process();
1895 PrevLink
= &ppi
->HeapMappings
.Next
;
1897 /* Find out if another thread already mapped the desktop heap */
1898 HeapMapping
= *PrevLink
;
1899 while (HeapMapping
!= NULL
)
1901 if (HeapMapping
->KernelMapping
== (PVOID
)pdesk
->pheapDesktop
)
1903 HeapMapping
->Count
++;
1904 return STATUS_SUCCESS
;
1907 PrevLink
= &HeapMapping
->Next
;
1908 HeapMapping
= HeapMapping
->Next
;
1911 /* We're the first, map the heap */
1912 Offset
.QuadPart
= 0;
1913 Status
= MmMapViewOfSection(pdesk
->hsectionDesktop
,
1914 PsGetCurrentProcess(),
1922 PAGE_EXECUTE_READ
); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
1923 if (!NT_SUCCESS(Status
))
1925 ERR("Failed to map desktop\n");
1929 TRACE("ppi 0x%p mapped heap of desktop 0x%p\n", ppi
, pdesk
);
1931 /* Add the mapping */
1932 HeapMapping
= UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING
));
1933 if (HeapMapping
== NULL
)
1935 MmUnmapViewOfSection(PsGetCurrentProcess(), UserBase
);
1936 ERR("UserHeapAlloc() failed!\n");
1937 return STATUS_NO_MEMORY
;
1940 HeapMapping
->Next
= NULL
;
1941 HeapMapping
->KernelMapping
= (PVOID
)pdesk
->pheapDesktop
;
1942 HeapMapping
->UserMapping
= UserBase
;
1943 HeapMapping
->Limit
= ViewSize
;
1944 HeapMapping
->Count
= 1;
1945 *PrevLink
= HeapMapping
;
1947 ObReferenceObject(pdesk
);
1949 return STATUS_SUCCESS
;
1953 IntSetThreadDesktop(IN HDESK hDesktop
,
1954 IN BOOL FreeOnFailure
)
1956 PDESKTOP pdesk
= NULL
, pdeskOld
;
1960 PCLIENTTHREADINFO pctiOld
, pctiNew
= NULL
;
1963 ASSERT(NtCurrentTeb());
1965 TRACE("IntSetThreadDesktop hDesktop:0x%p, FOF:%i\n",hDesktop
, FreeOnFailure
);
1967 pti
= PsGetCurrentThreadWin32Thread();
1968 pci
= pti
->pClientInfo
;
1970 /* If the caller gave us a desktop, ensure it is valid */
1971 if(hDesktop
!= NULL
)
1973 /* Validate the new desktop. */
1974 Status
= IntValidateDesktopHandle( hDesktop
, UserMode
, 0, &pdesk
);
1975 if (!NT_SUCCESS(Status
))
1977 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop
);
1981 if (pti
->rpdesk
== pdesk
)
1984 ObDereferenceObject(pdesk
);
1989 /* Make sure that we don't own any window in the current desktop */
1990 if (!IsListEmpty(&pti
->WindowListHead
))
1993 ObDereferenceObject(pdesk
);
1994 ERR("Attempted to change thread desktop although the thread has windows!\n");
1995 EngSetLastError(ERROR_BUSY
);
1999 /* Desktop is being re-set so clear out foreground. */
2000 if (pti
->rpdesk
!= pdesk
&& pti
->MessageQueue
== gpqForeground
)
2002 // Like above, there shouldn't be any windows, hooks or anything active on this threads desktop!
2003 IntSetFocusMessageQueue(NULL
);
2006 /* Before doing the switch, map the new desktop heap and allocate the new pcti */
2009 Status
= IntMapDesktopView(pdesk
);
2010 if (!NT_SUCCESS(Status
))
2012 ERR("Failed to map desktop heap!\n");
2013 ObDereferenceObject(pdesk
);
2014 SetLastNtError(Status
);
2018 pctiNew
= DesktopHeapAlloc( pdesk
, sizeof(CLIENTTHREADINFO
));
2021 ERR("Failed to allocate new pcti\n");
2022 IntUnmapDesktopView(pdesk
);
2023 ObDereferenceObject(pdesk
);
2024 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2029 /* free all classes or move them to the shared heap */
2030 if(pti
->rpdesk
!= NULL
)
2032 if(!IntCheckProcessDesktopClasses(pti
->rpdesk
, FreeOnFailure
))
2034 ERR("Failed to move process classes to shared heap!\n");
2037 DesktopHeapFree(pdesk
, pctiNew
);
2038 IntUnmapDesktopView(pdesk
);
2039 ObDereferenceObject(pdesk
);
2045 pdeskOld
= pti
->rpdesk
;
2046 hdeskOld
= pti
->hdesk
;
2047 if (pti
->pcti
!= &pti
->cti
)
2048 pctiOld
= pti
->pcti
;
2055 pti
->rpdesk
= pdesk
;
2056 pti
->hdesk
= hDesktop
;
2057 pti
->pDeskInfo
= pti
->rpdesk
->pDeskInfo
;
2058 pti
->pcti
= pctiNew
;
2060 pci
->ulClientDelta
= DesktopHeapGetUserDelta();
2061 pci
->pDeskInfo
= (PVOID
)((ULONG_PTR
)pti
->pDeskInfo
- pci
->ulClientDelta
);
2062 pci
->pClientThreadInfo
= (PVOID
)((ULONG_PTR
)pti
->pcti
- pci
->ulClientDelta
);
2064 /* initialize the new pcti */
2067 RtlCopyMemory(pctiNew
, pctiOld
, sizeof(CLIENTTHREADINFO
));
2071 RtlZeroMemory(pctiNew
, sizeof(CLIENTTHREADINFO
));
2072 pci
->fsHooks
= pti
->fsHooks
;
2073 pci
->dwTIFlags
= pti
->TIF_flags
;
2080 pti
->pDeskInfo
= NULL
;
2081 pti
->pcti
= &pti
->cti
; // Always point inside so there will be no crash when posting or sending msg's!
2082 pci
->ulClientDelta
= 0;
2083 pci
->pDeskInfo
= NULL
;
2084 pci
->pClientThreadInfo
= NULL
;
2087 /* clean up the old desktop */
2088 if(pdeskOld
!= NULL
)
2090 RemoveEntryList(&pti
->PtiLink
);
2091 if (pctiOld
) DesktopHeapFree(pdeskOld
, pctiOld
);
2092 IntUnmapDesktopView(pdeskOld
);
2093 ObDereferenceObject(pdeskOld
);
2099 InsertTailList(&pdesk
->PtiList
, &pti
->PtiLink
);
2102 TRACE("IntSetThreadDesktop: pti 0x%p ppi 0x%p switched from object 0x%p to 0x%p\n", pti
, pti
->ppi
, pdeskOld
, pdesk
);
2108 * NtUserSetThreadDesktop
2115 NtUserSetThreadDesktop(HDESK hDesktop
)
2119 UserEnterExclusive();
2121 // FIXME: IntSetThreadDesktop validates the desktop handle, it should happen
2122 // here too and set the NT error level. Q. Is it necessary to have the validation
2123 // in IntSetThreadDesktop? Is it needed there too?
2124 if (hDesktop
|| (!hDesktop
&& PsGetCurrentProcess() == gpepCSRSS
))
2125 ret
= IntSetThreadDesktop(hDesktop
, FALSE
);