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
);
14 #include <reactos/buildno.h>
17 UserInitializeDesktop(PDESKTOP pdesk
, PUNICODE_STRING DesktopName
, PWINSTATION_OBJECT pwinsta
);
20 IntMapDesktopView(IN PDESKTOP pdesk
);
23 IntUnmapDesktopView(IN PDESKTOP pdesk
);
26 IntFreeDesktopHeap(IN PDESKTOP pdesk
);
28 /* GLOBALS *******************************************************************/
30 /* These can be changed via csrss startup, these are defaults */
31 DWORD gdwDesktopSectionSize
= 512;
32 DWORD gdwNOIOSectionSize
= 128; // A guess, for one or more of the first three system desktops.
34 /* Currently active desktop */
35 PDESKTOP gpdeskInputDesktop
= NULL
;
36 HDC ScreenDeviceContext
= NULL
;
37 PTHREADINFO gptiDesktopThread
= NULL
;
38 HCURSOR gDesktopCursor
= NULL
;
40 /* OBJECT CALLBACKS **********************************************************/
44 IntDesktopObjectParse(IN PVOID ParseObject
,
46 IN OUT PACCESS_STATE AccessState
,
47 IN KPROCESSOR_MODE AccessMode
,
49 IN OUT PUNICODE_STRING CompleteName
,
50 IN OUT PUNICODE_STRING RemainingName
,
51 IN OUT PVOID Context OPTIONAL
,
52 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
57 OBJECT_ATTRIBUTES ObjectAttributes
;
58 PLIST_ENTRY NextEntry
, ListHead
;
59 PWINSTATION_OBJECT WinStaObject
= (PWINSTATION_OBJECT
)ParseObject
;
60 UNICODE_STRING DesktopName
;
61 PBOOLEAN pContext
= (PBOOLEAN
) Context
;
66 /* Set the list pointers and loop the window station */
67 ListHead
= &WinStaObject
->DesktopListHead
;
68 NextEntry
= ListHead
->Flink
;
69 while (NextEntry
!= ListHead
)
71 /* Get the current desktop */
72 Desktop
= CONTAINING_RECORD(NextEntry
, DESKTOP
, ListEntry
);
74 /* Get the desktop name */
75 ASSERT(Desktop
->pDeskInfo
!= NULL
);
76 RtlInitUnicodeString(&DesktopName
, Desktop
->pDeskInfo
->szDesktopName
);
78 /* Compare the name */
79 if (RtlEqualUnicodeString(RemainingName
,
81 (Attributes
& OBJ_CASE_INSENSITIVE
) != 0))
83 /* We found a match. Did this come from a create? */
86 /* Unless OPEN_IF was given, fail with an error */
87 if (!(Attributes
& OBJ_OPENIF
))
90 return STATUS_OBJECT_NAME_COLLISION
;
94 /* Otherwise, return with a warning only */
95 Status
= STATUS_OBJECT_NAME_EXISTS
;
100 /* This was a real open, so this is OK */
101 Status
= STATUS_SUCCESS
;
104 /* Reference the desktop and return it */
105 ObReferenceObject(Desktop
);
110 /* Go to the next desktop */
111 NextEntry
= NextEntry
->Flink
;
114 /* If we got here but this isn't a create, then fail */
115 if (!Context
) return STATUS_OBJECT_NAME_NOT_FOUND
;
117 /* Create the desktop object */
118 InitializeObjectAttributes(&ObjectAttributes
, RemainingName
, 0, NULL
, NULL
);
119 Status
= ObCreateObject(KernelMode
,
128 if (!NT_SUCCESS(Status
)) return Status
;
130 /* Initialize the desktop */
131 Status
= UserInitializeDesktop(Desktop
, RemainingName
, WinStaObject
);
132 if (!NT_SUCCESS(Status
))
134 ObDereferenceObject(Desktop
);
138 /* Set the desktop object and return success */
141 return STATUS_SUCCESS
;
146 IntDesktopObjectDelete(
147 _In_ PVOID Parameters
)
149 PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters
= Parameters
;
150 PDESKTOP pdesk
= (PDESKTOP
)DeleteParameters
->Object
;
152 TRACE("Deleting desktop object 0x%p\n", pdesk
);
154 ASSERT(pdesk
->pDeskInfo
->spwnd
->spwndChild
== NULL
);
156 if (pdesk
->pDeskInfo
->spwnd
)
157 co_UserDestroyWindow(pdesk
->pDeskInfo
->spwnd
);
159 if (pdesk
->spwndMessage
)
160 co_UserDestroyWindow(pdesk
->spwndMessage
);
162 /* Remove the desktop from the window station's list of associcated desktops */
163 RemoveEntryList(&pdesk
->ListEntry
);
166 IntFreeDesktopHeap(pdesk
);
167 return STATUS_SUCCESS
;
173 _In_ PVOID Parameters
)
175 PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters
= Parameters
;
176 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
180 /* This happens when we leak desktop handles */
181 return STATUS_SUCCESS
;
184 /* Do not allow the current desktop or the initial desktop to be closed */
185 if( OkToCloseParameters
->Handle
== pti
->ppi
->hdeskStartup
||
186 OkToCloseParameters
->Handle
== pti
->hdesk
)
188 return STATUS_ACCESS_DENIED
;
191 return STATUS_SUCCESS
;
196 IntDesktopObjectOpen(
197 _In_ PVOID Parameters
)
199 PWIN32_OPENMETHOD_PARAMETERS OpenParameters
= Parameters
;
200 PPROCESSINFO ppi
= PsGetProcessWin32Process(OpenParameters
->Process
);
202 return STATUS_SUCCESS
;
204 return IntMapDesktopView((PDESKTOP
)OpenParameters
->Object
);
209 IntDesktopObjectClose(
210 _In_ PVOID Parameters
)
212 PWIN32_CLOSEMETHOD_PARAMETERS CloseParameters
= Parameters
;
213 PPROCESSINFO ppi
= PsGetProcessWin32Process(CloseParameters
->Process
);
216 /* This happens when the process leaks desktop handles.
217 * At this point the PPROCESSINFO is already destroyed */
218 return STATUS_SUCCESS
;
221 return IntUnmapDesktopView((PDESKTOP
)CloseParameters
->Object
);
225 /* PRIVATE FUNCTIONS **********************************************************/
230 InitDesktopImpl(VOID
)
232 GENERIC_MAPPING IntDesktopMapping
= { DESKTOP_READ
,
237 /* Set Desktop Object Attributes */
238 ExDesktopObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(DESKTOP
);
239 ExDesktopObjectType
->TypeInfo
.GenericMapping
= IntDesktopMapping
;
240 ExDesktopObjectType
->TypeInfo
.ValidAccessMask
= DESKTOP_ALL_ACCESS
;
241 return STATUS_SUCCESS
;
244 static int GetSystemVersionString(LPWSTR buffer
)
247 #if 0 // Disabled until versioning in win32k gets correctly implemented (hbelusca).
248 RTL_OSVERSIONINFOEXW versionInfo
;
250 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
252 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
255 if (versionInfo
.dwMajorVersion
<= 4)
256 len
= swprintf(buffer
,
257 L
"ReactOS Version %lu.%lu %s Build %lu",
258 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
259 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
& 0xFFFF);
261 len
= swprintf(buffer
,
262 L
"ReactOS %s (Build %lu)",
263 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
& 0xFFFF);
265 len
= swprintf(buffer
, L
"ReactOS Version %S %S", KERNEL_VERSION_STR
, KERNEL_VERSION_BUILD_STR
);
273 IntParseDesktopPath(PEPROCESS Process
,
274 PUNICODE_STRING DesktopPath
,
278 OBJECT_ATTRIBUTES ObjectAttributes
;
279 UNICODE_STRING ObjectName
;
281 WCHAR wstrWinstaFullName
[MAX_PATH
], *pwstrWinsta
= NULL
, *pwstrDesktop
= NULL
;
290 if(DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
293 * Parse the desktop path string which can be in the form "WinSta\Desktop"
294 * or just "Desktop". In latter case WinSta0 will be used.
297 pwstrDesktop
= wcschr(DesktopPath
->Buffer
, L
'\\');
298 if(pwstrDesktop
!= NULL
)
302 pwstrWinsta
= DesktopPath
->Buffer
;
306 pwstrDesktop
= DesktopPath
->Buffer
;
310 TRACE("IntParseDesktopPath pwstrWinsta:%S pwstrDesktop:%S\n", pwstrWinsta
, pwstrDesktop
);
314 /* Search the process handle table for (inherited) window station
315 handles, use a more appropriate one than WinSta0 if possible. */
316 if (!ObFindHandleForObject(Process
,
318 ExWindowStationObjectType
,
323 /* We had no luck searching for opened handles, use WinSta0 now */
325 pwstrWinsta
= L
"WinSta0";
329 /* Search the process handle table for (inherited) desktop
330 handles, use a more appropriate one than Default if possible. */
331 if (!ObFindHandleForObject(Process
,
338 /* We had no luck searching for opened handles, use Desktop now */
340 pwstrDesktop
= L
"Default";
345 swprintf(wstrWinstaFullName
, L
"%wZ\\%ws", &gustrWindowStationsDir
, pwstrWinsta
);
346 RtlInitUnicodeString( &ObjectName
, wstrWinstaFullName
);
348 TRACE("parsed initial winsta: %wZ\n", &ObjectName
);
350 /* Open the window station */
351 InitializeObjectAttributes(&ObjectAttributes
,
353 OBJ_CASE_INSENSITIVE
,
357 Status
= ObOpenObjectByName(&ObjectAttributes
,
358 ExWindowStationObjectType
,
365 if(!NT_SUCCESS(Status
))
367 SetLastNtError(Status
);
368 ERR("Failed to reference window station %wZ PID: --!\n", &ObjectName
);
373 if(*hDesktop
== NULL
)
375 RtlInitUnicodeString(&ObjectName
, pwstrDesktop
);
377 TRACE("parsed initial desktop: %wZ\n", &ObjectName
);
379 /* Open the desktop object */
380 InitializeObjectAttributes(&ObjectAttributes
,
382 OBJ_CASE_INSENSITIVE
,
386 Status
= ObOpenObjectByName(&ObjectAttributes
,
394 if(!NT_SUCCESS(Status
))
399 SetLastNtError(Status
);
400 ERR("Failed to reference desktop %wZ PID: --!\n", &ObjectName
);
404 return STATUS_SUCCESS
;
408 * IntValidateDesktopHandle
410 * Validates the desktop handle.
413 * If the function succeeds, the handle remains referenced. If the
414 * fucntion fails, last error is set.
418 IntValidateDesktopHandle(
420 KPROCESSOR_MODE AccessMode
,
421 ACCESS_MASK DesiredAccess
,
426 Status
= ObReferenceObjectByHandle(
434 TRACE("IntValidateDesktopHandle: handle:0x%p obj:0x%p access:0x%x Status:0x%lx\n",
435 Desktop
, *Object
, DesiredAccess
, Status
);
437 if (!NT_SUCCESS(Status
))
438 SetLastNtError(Status
);
444 IntGetActiveDesktop(VOID
)
446 return gpdeskInputDesktop
;
450 * Returns or creates a handle to the desktop object
453 IntGetDesktopObjectHandle(PDESKTOP DesktopObject
)
458 ASSERT(DesktopObject
);
460 if (!ObFindHandleForObject(PsGetCurrentProcess(),
466 Status
= ObOpenObjectByPointer(DesktopObject
,
473 if(!NT_SUCCESS(Status
))
475 /* Unable to create a handle */
476 ERR("Unable to create a desktop handle\n");
482 TRACE("Got handle: %p\n", Ret
);
488 PUSER_MESSAGE_QUEUE FASTCALL
489 IntGetFocusMessageQueue(VOID
)
491 PDESKTOP pdo
= IntGetActiveDesktop();
494 TRACE("No active desktop\n");
497 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
501 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
503 PUSER_MESSAGE_QUEUE Old
;
504 PDESKTOP pdo
= IntGetActiveDesktop();
507 TRACE("No active desktop\n");
512 if(NewQueue
->Desktop
!= NULL
)
514 TRACE("Message Queue already attached to another desktop!\n");
517 IntReferenceMessageQueue(NewQueue
);
518 (void)InterlockedExchangePointer((PVOID
*)&NewQueue
->Desktop
, pdo
);
520 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchangePointer((PVOID
*)&pdo
->ActiveMessageQueue
, NewQueue
);
523 (void)InterlockedExchangePointer((PVOID
*)&Old
->Desktop
, 0);
524 gpqForegroundPrev
= Old
;
525 IntDereferenceMessageQueue(Old
);
527 // Only one Q can have active foreground even when there are more than one desktop.
530 gpqForeground
= pdo
->ActiveMessageQueue
;
534 gpqForeground
= NULL
;
535 ERR("ptiLastInput is CLEARED!!\n");
536 ptiLastInput
= NULL
; // ReactOS hacks,,,, should check for process death.
541 IntGetThreadDesktopWindow(PTHREADINFO pti
)
543 if (!pti
) pti
= PsGetCurrentThreadWin32Thread();
544 if (pti
->pDeskInfo
) return pti
->pDeskInfo
->spwnd
;
548 PWND FASTCALL
co_GetDesktopWindow(PWND pWnd
)
550 if (pWnd
->head
.rpdesk
&&
551 pWnd
->head
.rpdesk
->pDeskInfo
)
552 return pWnd
->head
.rpdesk
->pDeskInfo
->spwnd
;
556 HWND FASTCALL
IntGetDesktopWindow(VOID
)
558 PDESKTOP pdo
= IntGetActiveDesktop();
561 TRACE("No active desktop\n");
564 return pdo
->DesktopWindow
;
567 PWND FASTCALL
UserGetDesktopWindow(VOID
)
569 PDESKTOP pdo
= IntGetActiveDesktop();
573 TRACE("No active desktop\n");
576 // return pdo->pDeskInfo->spwnd;
577 return UserGetWindowObject(pdo
->DesktopWindow
);
580 HWND FASTCALL
IntGetMessageWindow(VOID
)
582 PDESKTOP pdo
= IntGetActiveDesktop();
586 TRACE("No active desktop\n");
589 return pdo
->spwndMessage
->head
.h
;
592 PWND FASTCALL
UserGetMessageWindow(VOID
)
594 PDESKTOP pdo
= IntGetActiveDesktop();
598 TRACE("No active desktop\n");
601 return pdo
->spwndMessage
;
604 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
606 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
607 PDESKTOP pdo
= pti
->rpdesk
;
610 ERR("Thread doesn't have a desktop\n");
613 return pdo
->DesktopWindow
;
616 /* PUBLIC FUNCTIONS ***********************************************************/
619 DesktopWindowProc(PWND Wnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*lResult
)
623 //ERR("DesktopWindowProc\n");
632 Wnd
->fnid
= FNID_DESKTOP
;
634 *lResult
= (LRESULT
)TRUE
;
638 Value
= HandleToULong(PsGetCurrentProcessId());
640 co_UserSetWindowLong(UserHMGetHandle(Wnd
), DT_GWL_PROCESSID
, Value
, FALSE
);
641 Value
= HandleToULong(PsGetCurrentThreadId());
643 co_UserSetWindowLong(UserHMGetHandle(Wnd
), DT_GWL_THREADID
, Value
, FALSE
);
647 case WM_DISPLAYCHANGE
:
648 co_WinPosSetWindowPos(Wnd
, 0, 0, 0, LOWORD(lParam
), HIWORD(lParam
), SWP_NOZORDER
| SWP_NOACTIVATE
);
652 IntPaintDesktop((HDC
)wParam
);
658 if (IntBeginPaint(Wnd
, &Ps
))
660 IntEndPaint(Wnd
, &Ps
);
664 case WM_SYSCOLORCHANGE
:
665 co_UserRedrawWindow(Wnd
, NULL
, NULL
, RDW_INVALIDATE
|RDW_ERASE
|RDW_ALLCHILDREN
);
669 PCURICON_OBJECT pcurOld
, pcurNew
;
670 pcurNew
= UserGetCurIconObject(gDesktopCursor
);
676 pcurNew
->CURSORF_flags
|= CURSORF_CURRENT
;
677 pcurOld
= UserSetCursor(pcurNew
, FALSE
);
680 pcurOld
->CURSORF_flags
&= ~CURSORF_CURRENT
;
681 UserDereferenceObject(pcurOld
);
686 case WM_WINDOWPOSCHANGING
:
688 PWINDOWPOS pWindowPos
= (PWINDOWPOS
)lParam
;
689 if((pWindowPos
->flags
& SWP_SHOWWINDOW
) != 0)
691 HDESK hdesk
= IntGetDesktopObjectHandle(gpdeskInputDesktop
);
692 IntSetThreadDesktop(hdesk
, FALSE
);
697 return TRUE
; /* We are done. Do not do any callbacks to user mode */
701 UserMessageWindowProc(PWND pwnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*lResult
)
708 pwnd
->fnid
|= FNID_MESSAGEWND
;
709 *lResult
= (LRESULT
)TRUE
;
712 pwnd
->fnid
|= FNID_DESTROY
;
716 return TRUE
; /* We are done. Do not do any callbacks to user mode */
719 VOID NTAPI
DesktopThreadMain()
724 gptiDesktopThread
= PsGetCurrentThreadWin32Thread();
726 UserEnterExclusive();
728 /* Register system classes. This thread does not belong to any desktop so the
729 classes will be allocated from the shared heap */
730 UserRegisterSystemClasses();
734 Ret
= co_IntGetPeekMessage(&Msg
, 0, 0, 0, PM_REMOVE
, TRUE
);
737 IntDispatchMessage(&Msg
);
745 UserGetDesktopDC(ULONG DcType
, BOOL EmptyDC
, BOOL ValidatehWnd
)
747 PWND DesktopObject
= 0;
750 if (DcType
== DC_TYPE_DIRECT
)
752 DesktopObject
= UserGetDesktopWindow();
753 DesktopHDC
= (HDC
)UserGetWindowDC(DesktopObject
);
757 PMONITOR pMonitor
= UserGetPrimaryMonitor();
758 DesktopHDC
= IntGdiCreateDisplayDC(pMonitor
->hDev
, DcType
, EmptyDC
);
770 Window
= UserGetDesktopWindow();
771 Rgn
= IntSysCreateRectpRgnIndirect(&Window
->rcWindow
);
773 IntInvalidateWindows( Window
,
785 co_IntShowDesktop(PDESKTOP Desktop
, ULONG Width
, ULONG Height
, BOOL bRedraw
)
787 PWND pwnd
= Desktop
->pDeskInfo
->spwnd
;
788 UINT flags
= SWP_NOACTIVATE
|SWP_NOZORDER
|SWP_SHOWWINDOW
;
792 flags
|= SWP_NOREDRAW
;
794 co_WinPosSetWindowPos(pwnd
, NULL
, 0, 0, Width
, Height
, flags
);
797 co_UserRedrawWindow( pwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
| RDW_INVALIDATE
);
799 return STATUS_SUCCESS
;
803 IntHideDesktop(PDESKTOP Desktop
)
807 DesktopWnd
= IntGetWindowObject(Desktop
->DesktopWindow
);
810 return ERROR_INVALID_WINDOW_HANDLE
;
812 DesktopWnd
->style
&= ~WS_VISIBLE
;
814 return STATUS_SUCCESS
;
819 UserBuildShellHookHwndList(PDESKTOP Desktop
)
822 PLIST_ENTRY ListEntry
;
823 PSHELL_HOOK_WINDOW Current
;
826 /* FIXME: If we save nb elements in desktop, we dont have to loop to find nb entries */
827 ListEntry
= Desktop
->ShellHookWindows
.Flink
;
828 while (ListEntry
!= &Desktop
->ShellHookWindows
)
830 ListEntry
= ListEntry
->Flink
;
834 if (!entries
) return NULL
;
836 list
= ExAllocatePoolWithTag(PagedPool
, sizeof(HWND
) * (entries
+ 1), USERTAG_WINDOWLIST
); /* alloc one extra for nullterm */
841 ListEntry
= Desktop
->ShellHookWindows
.Flink
;
842 while (ListEntry
!= &Desktop
->ShellHookWindows
)
844 Current
= CONTAINING_RECORD(ListEntry
, SHELL_HOOK_WINDOW
, ListEntry
);
845 ListEntry
= ListEntry
->Flink
;
846 *cursor
++ = Current
->hWnd
;
849 *cursor
= NULL
; /* Nullterm list */
856 * Send the Message to the windows registered for ShellHook
857 * notifications. The lParam contents depend on the Message. See
858 * MSDN for more details (RegisterShellHookWindow)
860 VOID
co_IntShellHookNotify(WPARAM Message
, WPARAM wParam
, LPARAM lParam
)
862 PDESKTOP Desktop
= IntGetActiveDesktop();
865 if (!gpsi
->uiShellMsg
)
867 gpsi
->uiShellMsg
= IntAddAtom(L
"SHELLHOOK");
869 TRACE("MsgType = %x\n", gpsi
->uiShellMsg
);
870 if (!gpsi
->uiShellMsg
)
871 ERR("LastError: %x\n", EngGetLastError());
876 TRACE("IntShellHookNotify: No desktop!\n");
880 // Allow other devices have a shot at foreground.
881 if (Message
== HSHELL_APPCOMMAND
) ptiLastInput
= NULL
;
883 // FIXME: System Tray Support.
885 HwndList
= UserBuildShellHookHwndList(Desktop
);
888 HWND
* cursor
= HwndList
;
890 for (; *cursor
; cursor
++)
892 TRACE("Sending notify\n");
893 UserPostMessage(*cursor
,
896 (Message
== HSHELL_LANGUAGE
? lParam
: (LPARAM
)wParam
) );
897 /* co_IntPostOrSendMessage(*cursor,
900 (Message == HSHELL_LANGUAGE ? lParam : (LPARAM)wParam) );*/
903 ExFreePoolWithTag(HwndList
, USERTAG_WINDOWLIST
);
906 if (ISITHOOKED(WH_SHELL
))
908 co_HOOK_CallHooks(WH_SHELL
, Message
, wParam
, lParam
);
913 * Add the window to the ShellHookWindows list. The windows
914 * on that list get notifications that are important to shell
917 * TODO: Validate the window? I'm not sure if sending these messages to
918 * an unsuspecting application that is not your own is a nice thing to do.
920 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
922 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
923 PDESKTOP Desktop
= pti
->rpdesk
;
924 PSHELL_HOOK_WINDOW Entry
;
926 TRACE("IntRegisterShellHookWindow\n");
928 /* First deregister the window, so we can be sure it's never twice in the
931 IntDeRegisterShellHookWindow(hWnd
);
933 Entry
= ExAllocatePoolWithTag(PagedPool
,
934 sizeof(SHELL_HOOK_WINDOW
),
942 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
948 * Remove the window from the ShellHookWindows list. The windows
949 * on that list get notifications that are important to shell
952 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
954 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
955 PDESKTOP Desktop
= pti
->rpdesk
;
956 PLIST_ENTRY ListEntry
;
957 PSHELL_HOOK_WINDOW Current
;
959 ListEntry
= Desktop
->ShellHookWindows
.Flink
;
960 while (ListEntry
!= &Desktop
->ShellHookWindows
)
962 Current
= CONTAINING_RECORD(ListEntry
, SHELL_HOOK_WINDOW
, ListEntry
);
963 ListEntry
= ListEntry
->Flink
;
964 if (Current
->hWnd
== hWnd
)
966 RemoveEntryList(&Current
->ListEntry
);
967 ExFreePoolWithTag(Current
, TAG_WINSTA
);
976 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop
)
978 /* FIXME: Disable until unmapping works in mm */
980 if (Desktop
->pheapDesktop
!= NULL
)
982 MmUnmapViewInSessionSpace(Desktop
->pheapDesktop
);
983 Desktop
->pheapDesktop
= NULL
;
986 if (Desktop
->hsectionDesktop
!= NULL
)
988 ObDereferenceObject(Desktop
->hsectionDesktop
);
989 Desktop
->hsectionDesktop
= NULL
;
995 IntPaintDesktop(HDC hDC
)
998 HBRUSH DesktopBrush
, PreviousBrush
;
1000 BOOL doPatBlt
= TRUE
;
1002 static WCHAR s_wszSafeMode
[] = L
"Safe Mode";
1008 if (GdiGetClipBox(hDC
, &Rect
) == ERROR
)
1011 hWndDesktop
= IntGetDesktopWindow(); // rpdesk->DesktopWindow;
1013 WndDesktop
= UserGetWindowObject(hWndDesktop
); // rpdesk->pDeskInfo->spwnd;
1017 if (!UserGetSystemMetrics(SM_CLEANBOOT
))
1019 DesktopBrush
= (HBRUSH
)WndDesktop
->pcls
->hbrBackground
;
1022 * Paint desktop background
1024 if (gspv
.hbmWallpaper
!= NULL
)
1030 sz
.cx
= WndDesktop
->rcWindow
.right
- WndDesktop
->rcWindow
.left
;
1031 sz
.cy
= WndDesktop
->rcWindow
.bottom
- WndDesktop
->rcWindow
.top
;
1033 if (gspv
.WallpaperMode
== wmStretch
||
1034 gspv
.WallpaperMode
== wmTile
)
1041 /* Find the upper left corner, can be negative if the bitmap is bigger then the screen */
1042 x
= (sz
.cx
/ 2) - (gspv
.cxWallpaper
/ 2);
1043 y
= (sz
.cy
/ 2) - (gspv
.cyWallpaper
/ 2);
1046 hWallpaperDC
= NtGdiCreateCompatibleDC(hDC
);
1047 if(hWallpaperDC
!= NULL
)
1051 /* Fill in the area that the bitmap is not going to cover */
1054 /* FIXME: Clip out the bitmap
1055 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1056 once we support DSTINVERT */
1057 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1058 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1059 NtGdiSelectBrush(hDC
, PreviousBrush
);
1062 /* Do not fill the background after it is painted no matter the size of the picture */
1065 hOldBitmap
= NtGdiSelectBitmap(hWallpaperDC
, gspv
.hbmWallpaper
);
1067 if (gspv
.WallpaperMode
== wmStretch
)
1069 if(Rect
.right
&& Rect
.bottom
)
1070 NtGdiStretchBlt(hDC
,
1083 else if (gspv
.WallpaperMode
== wmTile
)
1085 /* Paint the bitmap across the screen then down */
1086 for(y
= 0; y
< Rect
.bottom
; y
+= gspv
.cyWallpaper
)
1088 for(x
= 0; x
< Rect
.right
; x
+= gspv
.cxWallpaper
)
1118 NtGdiSelectBitmap(hWallpaperDC
, hOldBitmap
);
1119 NtGdiDeleteObjectApp(hWallpaperDC
);
1125 /* Black desktop background in Safe Mode */
1126 DesktopBrush
= StockObjects
[BLACK_BRUSH
];
1128 /* Background is set to none, clear the screen */
1131 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1132 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1133 NtGdiSelectBrush(hDC
, PreviousBrush
);
1137 * Display system version on the desktop background
1140 if (g_PaintDesktopVersion
|| UserGetSystemMetrics(SM_CLEANBOOT
))
1142 static WCHAR s_wszVersion
[256] = {0};
1147 len
= wcslen(s_wszVersion
);
1151 len
= GetSystemVersionString(s_wszVersion
);
1156 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
1158 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1159 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1162 color_old
= IntGdiSetTextColor(hDC
, RGB(255,255,255));
1163 align_old
= IntGdiSetTextAlign(hDC
, TA_RIGHT
);
1164 mode_old
= IntGdiSetBkMode(hDC
, TRANSPARENT
);
1166 if(!UserGetSystemMetrics(SM_CLEANBOOT
))
1168 GreExtTextOutW(hDC
, rect
.right
- 16, rect
.bottom
- 48, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1174 /* Version information text in top center */
1175 IntGdiSetTextAlign(hDC
, TA_CENTER
| TA_TOP
);
1176 GreExtTextOutW(hDC
, (rect
.right
+ rect
.left
)/2, rect
.top
+ 3, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1178 /* Safe Mode text in corners */
1179 len
= wcslen(s_wszSafeMode
);
1180 IntGdiSetTextAlign(hDC
, TA_LEFT
| TA_TOP
);
1181 GreExtTextOutW(hDC
, rect
.left
, rect
.top
+ 3, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1182 IntGdiSetTextAlign(hDC
, TA_RIGHT
| TA_TOP
);
1183 GreExtTextOutW(hDC
, rect
.right
, rect
.top
+ 3, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1184 IntGdiSetTextAlign(hDC
, TA_LEFT
| TA_BASELINE
);
1185 GreExtTextOutW(hDC
, rect
.left
, rect
.bottom
- 5, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1186 IntGdiSetTextAlign(hDC
, TA_RIGHT
| TA_BASELINE
);
1187 GreExtTextOutW(hDC
, rect
.right
, rect
.bottom
- 5, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1190 IntGdiSetBkMode(hDC
, mode_old
);
1191 IntGdiSetTextAlign(hDC
, align_old
);
1192 IntGdiSetTextColor(hDC
, color_old
);
1199 UserInitializeDesktop(PDESKTOP pdesk
, PUNICODE_STRING DesktopName
, PWINSTATION_OBJECT pwinsta
)
1201 PVOID DesktopHeapSystemBase
= NULL
;
1202 ULONG_PTR HeapSize
= gdwDesktopSectionSize
* 1024;
1203 SIZE_T DesktopInfoSize
;
1206 TRACE("UserInitializeDesktop desktop 0x%p with name %wZ\n", pdesk
, DesktopName
);
1208 RtlZeroMemory(pdesk
, sizeof(DESKTOP
));
1210 /* Link the desktop with the parent window station */
1211 pdesk
->rpwinstaParent
= pwinsta
;
1212 InsertTailList(&pwinsta
->DesktopListHead
, &pdesk
->ListEntry
);
1214 /* Create the desktop heap */
1215 pdesk
->hsectionDesktop
= NULL
;
1216 pdesk
->pheapDesktop
= UserCreateHeap(&pdesk
->hsectionDesktop
,
1217 &DesktopHeapSystemBase
,
1219 if (pdesk
->pheapDesktop
== NULL
)
1221 ERR("Failed to create desktop heap!\n");
1222 return STATUS_NO_MEMORY
;
1225 /* Create DESKTOPINFO */
1226 DesktopInfoSize
= sizeof(DESKTOPINFO
) + DesktopName
->Length
+ sizeof(WCHAR
);
1227 pdesk
->pDeskInfo
= RtlAllocateHeap(pdesk
->pheapDesktop
,
1228 HEAP_NO_SERIALIZE
| HEAP_ZERO_MEMORY
,
1230 if (pdesk
->pDeskInfo
== NULL
)
1232 ERR("Failed to create the DESKTOP structure!\n");
1233 return STATUS_NO_MEMORY
;
1236 /* Initialize the DESKTOPINFO */
1237 pdesk
->pDeskInfo
->pvDesktopBase
= DesktopHeapSystemBase
;
1238 pdesk
->pDeskInfo
->pvDesktopLimit
= (PVOID
)((ULONG_PTR
)DesktopHeapSystemBase
+ HeapSize
);
1239 RtlCopyMemory(pdesk
->pDeskInfo
->szDesktopName
,
1240 DesktopName
->Buffer
,
1241 DesktopName
->Length
+ sizeof(WCHAR
));
1242 for (i
= 0; i
< NB_HOOKS
; i
++)
1244 InitializeListHead(&pdesk
->pDeskInfo
->aphkStart
[i
]);
1247 InitializeListHead(&pdesk
->ShellHookWindows
);
1248 InitializeListHead(&pdesk
->PtiList
);
1250 return STATUS_SUCCESS
;
1253 /* SYSCALLS *******************************************************************/
1256 * NtUserCreateDesktop
1258 * Creates a new desktop.
1262 * Object Attributes.
1265 * Name of the device.
1271 * Interaction flags.
1274 * Requested type of access.
1278 * If the function succeeds, the return value is a handle to the newly
1279 * created desktop. If the specified desktop already exists, the function
1280 * succeeds and returns a handle to the existing desktop. When you are
1281 * finished using the handle, call the CloseDesktop function to close it.
1282 * If the function fails, the return value is NULL.
1289 NtUserCreateDesktop(
1290 POBJECT_ATTRIBUTES ObjectAttributes
,
1291 PUNICODE_STRING lpszDesktopDevice
,
1294 ACCESS_MASK dwDesiredAccess
)
1296 PDESKTOP pdesk
= NULL
;
1297 NTSTATUS Status
= STATUS_SUCCESS
;
1299 BOOLEAN Context
= FALSE
;
1300 UNICODE_STRING ClassName
;
1301 LARGE_STRING WindowName
;
1302 BOOL NoHooks
= FALSE
;
1305 PTHREADINFO ptiCurrent
;
1308 DECLARE_RETURN(HDESK
);
1310 TRACE("Enter NtUserCreateDesktop\n");
1311 UserEnterExclusive();
1313 ptiCurrent
= PsGetCurrentThreadWin32Thread();
1315 ASSERT(gptiDesktopThread
);
1317 /* Turn off hooks when calling any CreateWindowEx from inside win32k. */
1318 NoHooks
= (ptiCurrent
->TIF_flags
& TIF_DISABLEHOOKS
);
1319 ptiCurrent
->TIF_flags
|= TIF_DISABLEHOOKS
;
1320 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
1323 * Try to open already existing desktop
1325 Status
= ObOpenObjectByName(
1327 ExDesktopObjectType
,
1333 if (!NT_SUCCESS(Status
))
1335 ERR("ObOpenObjectByName failed to open/create desktop\n");
1336 SetLastNtError(Status
);
1340 /* In case the object was not created (eg if it existed), return now */
1341 if (Context
== FALSE
)
1343 TRACE("NtUserCreateDesktop opened desktop %wZ\n", ObjectAttributes
->ObjectName
);
1347 /* Reference the desktop */
1348 Status
= ObReferenceObjectByHandle(hdesk
,
1350 ExDesktopObjectType
,
1354 if (!NT_SUCCESS(Status
))
1356 ERR("Failed to reference desktop object\n");
1357 SetLastNtError(Status
);
1361 /* Get the desktop window class. The thread desktop does not belong to any desktop
1362 * so the classes created there (including the desktop class) are allocated in the shared heap
1363 * It would cause problems if we used a class that belongs to the caller
1365 ClassName
.Buffer
= WC_DESKTOP
;
1366 ClassName
.Length
= 0;
1367 pcls
= IntGetAndReferenceClass(&ClassName
, 0, TRUE
);
1374 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1375 RtlZeroMemory(&Cs
, sizeof(Cs
));
1376 Cs
.x
= UserGetSystemMetrics(SM_XVIRTUALSCREEN
),
1377 Cs
.y
= UserGetSystemMetrics(SM_YVIRTUALSCREEN
),
1378 Cs
.cx
= UserGetSystemMetrics(SM_CXVIRTUALSCREEN
),
1379 Cs
.cy
= UserGetSystemMetrics(SM_CYVIRTUALSCREEN
),
1380 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1381 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
1382 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1383 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1385 /* Use IntCreateWindow instead of co_UserCreateWindowEx cause the later expects a thread with a desktop */
1386 pWnd
= IntCreateWindow(&Cs
, &WindowName
, pcls
, NULL
, NULL
, NULL
, pdesk
);
1389 ERR("Failed to create desktop window for the new desktop\n");
1393 pdesk
->dwSessionId
= PsGetCurrentProcessSessionId();
1394 pdesk
->DesktopWindow
= pWnd
->head
.h
;
1395 pdesk
->pDeskInfo
->spwnd
= pWnd
;
1396 pWnd
->fnid
= FNID_DESKTOP
;
1398 ClassName
.Buffer
= MAKEINTATOM(gpsi
->atomSysClass
[ICLS_HWNDMESSAGE
]);
1399 ClassName
.Length
= 0;
1400 pcls
= IntGetAndReferenceClass(&ClassName
, 0, TRUE
);
1407 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1408 RtlZeroMemory(&Cs
, sizeof(Cs
));
1409 Cs
.cx
= Cs
.cy
= 100;
1410 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1411 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
1412 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1413 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1414 pWnd
= IntCreateWindow(&Cs
, &WindowName
, pcls
, NULL
, NULL
, NULL
, pdesk
);
1417 ERR("Failed to create message window for the new desktop\n");
1421 pdesk
->spwndMessage
= pWnd
;
1422 pWnd
->fnid
= FNID_MESSAGEWND
;
1425 if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki)
1426 Create Tooltip. Saved in DesktopObject->spwndTooltip.
1427 Tooltip dwExStyle: WS_EX_TOOLWINDOW|WS_EX_TOPMOST
1428 hWndParent are spwndMessage. Use hModuleWin for server side winproc!
1429 The rest is same as message window.
1430 http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx
1437 ObDereferenceObject(pdesk
);
1439 if (_ret_
== NULL
&& hdesk
!= NULL
)
1441 ObCloseHandle(hdesk
, UserMode
);
1445 ptiCurrent
->TIF_flags
&= ~TIF_DISABLEHOOKS
;
1446 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
1448 TRACE("Leave NtUserCreateDesktop, ret=%p\n",_ret_
);
1456 * Opens an existing desktop.
1460 * Name of the existing desktop.
1463 * Interaction flags.
1466 * Requested type of access.
1469 * Handle to the desktop or zero on failure.
1477 POBJECT_ATTRIBUTES ObjectAttributes
,
1479 ACCESS_MASK dwDesiredAccess
)
1484 Status
= ObOpenObjectByName(
1486 ExDesktopObjectType
,
1493 if (!NT_SUCCESS(Status
))
1495 ERR("Failed to open desktop\n");
1496 SetLastNtError(Status
);
1500 TRACE("Opened desktop %S with handle 0x%p\n", ObjectAttributes
->ObjectName
->Buffer
, Desktop
);
1506 * NtUserOpenInputDesktop
1508 * Opens the input (interactive) desktop.
1512 * Interaction flags.
1515 * Inheritance option.
1518 * Requested type of access.
1521 * Handle to the input desktop or zero on failure.
1528 NtUserOpenInputDesktop(
1531 ACCESS_MASK dwDesiredAccess
)
1535 ULONG HandleAttributes
= 0;
1537 UserEnterExclusive();
1538 TRACE("Enter NtUserOpenInputDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop
);
1540 if(fInherit
) HandleAttributes
= OBJ_INHERIT
;
1542 /* Create a new handle to the object */
1543 Status
= ObOpenObjectByPointer(
1548 ExDesktopObjectType
,
1552 if (!NT_SUCCESS(Status
))
1554 ERR("Failed to open input desktop object\n");
1555 SetLastNtError(Status
);
1558 TRACE("NtUserOpenInputDesktop returning 0x%p\n",hdesk
);
1564 * NtUserCloseDesktop
1566 * Closes a desktop handle.
1570 * Handle to the desktop.
1576 * The desktop handle can be created with NtUserCreateDesktop or
1577 * NtUserOpenDesktop. This function will fail if any thread in the calling
1578 * process is using the specified desktop handle or if the handle refers
1579 * to the initial desktop of the calling process.
1586 NtUserCloseDesktop(HDESK hDesktop
)
1590 DECLARE_RETURN(BOOL
);
1592 TRACE("NtUserCloseDesktop called (0x%p)\n", hDesktop
);
1593 UserEnterExclusive();
1595 if( hDesktop
== gptiCurrent
->hdesk
|| hDesktop
== gptiCurrent
->ppi
->hdeskStartup
)
1597 ERR("Attempted to close thread desktop\n");
1598 EngSetLastError(ERROR_BUSY
);
1602 Status
= IntValidateDesktopHandle( hDesktop
, UserMode
, 0, &pdesk
);
1603 if (!NT_SUCCESS(Status
))
1605 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop
);
1609 ObDereferenceObject(pdesk
);
1611 Status
= ZwClose(hDesktop
);
1612 if (!NT_SUCCESS(Status
))
1614 ERR("Failed to close desktop handle 0x%p\n", hDesktop
);
1615 SetLastNtError(Status
);
1622 TRACE("Leave NtUserCloseDesktop, ret=%i\n",_ret_
);
1628 * NtUserPaintDesktop
1630 * The NtUserPaintDesktop function fills the clipping region in the
1631 * specified device context with the desktop pattern or wallpaper. The
1632 * function is provided primarily for shell desktops.
1636 * Handle to the device context.
1643 NtUserPaintDesktop(HDC hDC
)
1646 UserEnterExclusive();
1647 TRACE("Enter NtUserPaintDesktop\n");
1648 Ret
= IntPaintDesktop(hDC
);
1649 TRACE("Leave NtUserPaintDesktop, ret=%i\n",Ret
);
1655 * NtUserResolveDesktop
1657 * The NtUserResolveDesktop function retrieves handles to the desktop and
1658 * the window station specified by the desktop path string.
1662 * Handle to a user process.
1665 * The desktop path string.
1668 * Handle to the desktop (direct return value) and
1669 * handle to the associated window station (by pointer).
1670 * NULL in case of failure.
1673 * Callable by CSRSS only.
1681 NtUserResolveDesktop(
1682 IN HANDLE ProcessHandle
,
1683 IN PUNICODE_STRING DesktopPath
,
1685 OUT HWINSTA
* phWinSta
)
1688 PEPROCESS Process
= NULL
;
1689 HWINSTA hWinSta
= NULL
;
1690 HDESK hDesktop
= NULL
;
1692 /* Allow only the Console Server to perform this operation (via CSRSS) */
1693 if (PsGetCurrentProcess() != gpepCSRSS
)
1696 /* Get the process object the user handle was referencing */
1697 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1698 PROCESS_QUERY_INFORMATION
,
1703 if (!NT_SUCCESS(Status
)) return NULL
;
1705 // UserEnterShared();
1709 UNICODE_STRING CapturedDesktopPath
;
1711 /* Capture the user desktop path string */
1712 Status
= IntSafeCopyUnicodeStringTerminateNULL(&CapturedDesktopPath
,
1714 if (!NT_SUCCESS(Status
)) _SEH2_YIELD(goto Quit
);
1716 /* Call the internal function */
1717 Status
= IntParseDesktopPath(Process
,
1718 &CapturedDesktopPath
,
1721 if (!NT_SUCCESS(Status
))
1723 ERR("IntParseDesktopPath failed, Status = 0x%08lx\n", Status
);
1728 /* Return the window station handle */
1729 *phWinSta
= hWinSta
;
1731 /* Free the captured string */
1732 if (CapturedDesktopPath
.Buffer
)
1733 ExFreePoolWithTag(CapturedDesktopPath
.Buffer
, TAG_STRING
);
1735 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1737 Status
= _SEH2_GetExceptionCode();
1744 /* Dereference the process object */
1745 ObDereferenceObject(Process
);
1747 /* Return the desktop handle */
1752 * NtUserSwitchDesktop
1754 * Sets the current input (interactive) desktop.
1758 * Handle to desktop.
1768 NtUserSwitchDesktop(HDESK hdesk
)
1772 BOOL bRedrawDesktop
;
1773 DECLARE_RETURN(BOOL
);
1775 UserEnterExclusive();
1776 TRACE("Enter NtUserSwitchDesktop(0x%p)\n", hdesk
);
1778 Status
= IntValidateDesktopHandle( hdesk
, UserMode
, 0, &pdesk
);
1779 if (!NT_SUCCESS(Status
))
1781 ERR("Validation of desktop handle (0x%p) failed\n", hdesk
);
1785 if (PsGetCurrentProcessSessionId() != pdesk
->rpwinstaParent
->dwSessionId
)
1787 ERR("NtUserSwitchDesktop called for a desktop of a different session\n");
1791 if(pdesk
== gpdeskInputDesktop
)
1793 WARN("NtUserSwitchDesktop called for active desktop\n");
1798 * Don't allow applications switch the desktop if it's locked, unless the caller
1799 * is the logon application itself
1801 if((pdesk
->rpwinstaParent
->Flags
& WSS_LOCKED
) &&
1802 gpidLogon
!= PsGetCurrentProcessId())
1804 ObDereferenceObject(pdesk
);
1805 ERR("Switching desktop 0x%p denied because the window station is locked!\n", hdesk
);
1809 if(pdesk
->rpwinstaParent
!= InputWindowStation
)
1811 ObDereferenceObject(pdesk
);
1812 ERR("Switching desktop 0x%p denied because desktop doesn't belong to the interactive winsta!\n", hdesk
);
1816 /* FIXME: Fail if the process is associated with a secured
1817 desktop such as Winlogon or Screen-Saver */
1818 /* FIXME: Connect to input device */
1820 TRACE("Switching from desktop 0x%p to 0x%p\n", gpdeskInputDesktop
, pdesk
);
1822 bRedrawDesktop
= FALSE
;
1824 /* The first time SwitchDesktop is called, gpdeskInputDesktop is NULL */
1825 if(gpdeskInputDesktop
!= NULL
)
1827 if((gpdeskInputDesktop
->pDeskInfo
->spwnd
->style
& WS_VISIBLE
) == WS_VISIBLE
)
1828 bRedrawDesktop
= TRUE
;
1830 /* Hide the previous desktop window */
1831 IntHideDesktop(gpdeskInputDesktop
);
1834 /* Set the active desktop in the desktop's window station. */
1835 InputWindowStation
->ActiveDesktop
= pdesk
;
1837 /* Set the global state. */
1838 gpdeskInputDesktop
= pdesk
;
1840 /* Show the new desktop window */
1841 co_IntShowDesktop(pdesk
, UserGetSystemMetrics(SM_CXSCREEN
), UserGetSystemMetrics(SM_CYSCREEN
), bRedrawDesktop
);
1843 TRACE("SwitchDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop
);
1844 ObDereferenceObject(pdesk
);
1849 TRACE("Leave NtUserSwitchDesktop, ret=%i\n",_ret_
);
1855 * NtUserGetThreadDesktop
1862 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1866 PDESKTOP DesktopObject
;
1867 HDESK Ret
, hThreadDesktop
;
1868 OBJECT_HANDLE_INFORMATION HandleInformation
;
1869 DECLARE_RETURN(HDESK
);
1871 UserEnterExclusive();
1872 TRACE("Enter NtUserGetThreadDesktop\n");
1876 EngSetLastError(ERROR_INVALID_PARAMETER
);
1880 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)dwThreadId
, &Thread
);
1881 if(!NT_SUCCESS(Status
))
1883 EngSetLastError(ERROR_INVALID_PARAMETER
);
1887 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1889 /* Just return the handle, we queried the desktop handle of a thread running
1890 in the same context */
1891 Ret
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
;
1892 ObDereferenceObject(Thread
);
1896 /* Get the desktop handle and the desktop of the thread */
1897 if(!(hThreadDesktop
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
) ||
1898 !(DesktopObject
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->rpdesk
))
1900 ObDereferenceObject(Thread
);
1901 ERR("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1905 /* We could just use DesktopObject instead of looking up the handle, but latter
1906 may be a bit safer (e.g. when the desktop is being destroyed */
1907 /* Switch into the context of the thread we're trying to get the desktop from,
1908 so we can use the handle */
1909 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1910 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1912 ExDesktopObjectType
,
1914 (PVOID
*)&DesktopObject
,
1915 &HandleInformation
);
1918 /* The handle couldn't be found, there's nothing to get... */
1919 if(!NT_SUCCESS(Status
))
1921 ObDereferenceObject(Thread
);
1925 /* Lookup our handle table if we can find a handle to the desktop object,
1926 if not, create one */
1927 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1929 /* All done, we got a valid handle to the desktop */
1930 ObDereferenceObject(DesktopObject
);
1931 ObDereferenceObject(Thread
);
1935 TRACE("Leave NtUserGetThreadDesktop, ret=%p\n",_ret_
);
1941 IntUnmapDesktopView(IN PDESKTOP pdesk
)
1944 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1945 NTSTATUS Status
= STATUS_SUCCESS
;
1947 TRACE("IntUnmapDesktopView called for desktop object %p\n", pdesk
);
1949 ppi
= PsGetCurrentProcessWin32Process();
1952 * Unmap if we're the last thread using the desktop.
1953 * Start the search at the next mapping: skip the first entry
1954 * as it must be the global user heap mapping.
1956 PrevLink
= &ppi
->HeapMappings
.Next
;
1957 HeapMapping
= *PrevLink
;
1958 while (HeapMapping
!= NULL
)
1960 if (HeapMapping
->KernelMapping
== (PVOID
)pdesk
->pheapDesktop
)
1962 if (--HeapMapping
->Count
== 0)
1964 *PrevLink
= HeapMapping
->Next
;
1966 TRACE("ppi 0x%p unmapped heap of desktop 0x%p\n", ppi
, pdesk
);
1967 Status
= MmUnmapViewOfSection(PsGetCurrentProcess(),
1968 HeapMapping
->UserMapping
);
1970 ObDereferenceObject(pdesk
);
1972 UserHeapFree(HeapMapping
);
1977 PrevLink
= &HeapMapping
->Next
;
1978 HeapMapping
= HeapMapping
->Next
;
1985 IntMapDesktopView(IN PDESKTOP pdesk
)
1988 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1989 PVOID UserBase
= NULL
;
1990 SIZE_T ViewSize
= 0;
1991 LARGE_INTEGER Offset
;
1994 TRACE("IntMapDesktopView called for desktop object 0x%p\n", pdesk
);
1996 ppi
= PsGetCurrentProcessWin32Process();
1999 * Find out if another thread already mapped the desktop heap.
2000 * Start the search at the next mapping: skip the first entry
2001 * as it must be the global user heap mapping.
2003 PrevLink
= &ppi
->HeapMappings
.Next
;
2004 HeapMapping
= *PrevLink
;
2005 while (HeapMapping
!= NULL
)
2007 if (HeapMapping
->KernelMapping
== (PVOID
)pdesk
->pheapDesktop
)
2009 HeapMapping
->Count
++;
2010 return STATUS_SUCCESS
;
2013 PrevLink
= &HeapMapping
->Next
;
2014 HeapMapping
= HeapMapping
->Next
;
2017 /* We're the first, map the heap */
2018 Offset
.QuadPart
= 0;
2019 Status
= MmMapViewOfSection(pdesk
->hsectionDesktop
,
2020 PsGetCurrentProcess(),
2028 PAGE_EXECUTE_READ
); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
2029 if (!NT_SUCCESS(Status
))
2031 ERR("Failed to map desktop\n");
2035 TRACE("ppi 0x%p mapped heap of desktop 0x%p\n", ppi
, pdesk
);
2037 /* Add the mapping */
2038 HeapMapping
= UserHeapAlloc(sizeof(*HeapMapping
));
2039 if (HeapMapping
== NULL
)
2041 MmUnmapViewOfSection(PsGetCurrentProcess(), UserBase
);
2042 ERR("UserHeapAlloc() failed!\n");
2043 return STATUS_NO_MEMORY
;
2046 HeapMapping
->Next
= NULL
;
2047 HeapMapping
->KernelMapping
= (PVOID
)pdesk
->pheapDesktop
;
2048 HeapMapping
->UserMapping
= UserBase
;
2049 HeapMapping
->Limit
= ViewSize
;
2050 HeapMapping
->Count
= 1;
2051 *PrevLink
= HeapMapping
;
2053 ObReferenceObject(pdesk
);
2055 return STATUS_SUCCESS
;
2059 IntSetThreadDesktop(IN HDESK hDesktop
,
2060 IN BOOL FreeOnFailure
)
2062 PDESKTOP pdesk
= NULL
, pdeskOld
;
2066 PCLIENTTHREADINFO pctiOld
, pctiNew
= NULL
;
2069 ASSERT(NtCurrentTeb());
2071 TRACE("IntSetThreadDesktop hDesktop:0x%p, FOF:%i\n",hDesktop
, FreeOnFailure
);
2073 pti
= PsGetCurrentThreadWin32Thread();
2074 pci
= pti
->pClientInfo
;
2076 /* If the caller gave us a desktop, ensure it is valid */
2077 if(hDesktop
!= NULL
)
2079 /* Validate the new desktop. */
2080 Status
= IntValidateDesktopHandle( hDesktop
, UserMode
, 0, &pdesk
);
2081 if (!NT_SUCCESS(Status
))
2083 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop
);
2087 if (pti
->rpdesk
== pdesk
)
2090 ObDereferenceObject(pdesk
);
2095 /* Make sure that we don't own any window in the current desktop */
2096 if (!IsListEmpty(&pti
->WindowListHead
))
2099 ObDereferenceObject(pdesk
);
2100 ERR("Attempted to change thread desktop although the thread has windows!\n");
2101 EngSetLastError(ERROR_BUSY
);
2105 /* Desktop is being re-set so clear out foreground. */
2106 if (pti
->rpdesk
!= pdesk
&& pti
->MessageQueue
== gpqForeground
)
2108 // Like above, there shouldn't be any windows, hooks or anything active on this threads desktop!
2109 IntSetFocusMessageQueue(NULL
);
2112 /* Before doing the switch, map the new desktop heap and allocate the new pcti */
2115 Status
= IntMapDesktopView(pdesk
);
2116 if (!NT_SUCCESS(Status
))
2118 ERR("Failed to map desktop heap!\n");
2119 ObDereferenceObject(pdesk
);
2120 SetLastNtError(Status
);
2124 pctiNew
= DesktopHeapAlloc( pdesk
, sizeof(CLIENTTHREADINFO
));
2127 ERR("Failed to allocate new pcti\n");
2128 IntUnmapDesktopView(pdesk
);
2129 ObDereferenceObject(pdesk
);
2130 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2135 /* free all classes or move them to the shared heap */
2136 if(pti
->rpdesk
!= NULL
)
2138 if(!IntCheckProcessDesktopClasses(pti
->rpdesk
, FreeOnFailure
))
2140 ERR("Failed to move process classes to shared heap!\n");
2143 DesktopHeapFree(pdesk
, pctiNew
);
2144 IntUnmapDesktopView(pdesk
);
2145 ObDereferenceObject(pdesk
);
2151 pdeskOld
= pti
->rpdesk
;
2152 hdeskOld
= pti
->hdesk
;
2153 if (pti
->pcti
!= &pti
->cti
)
2154 pctiOld
= pti
->pcti
;
2161 pti
->rpdesk
= pdesk
;
2162 pti
->hdesk
= hDesktop
;
2163 pti
->pDeskInfo
= pti
->rpdesk
->pDeskInfo
;
2164 pti
->pcti
= pctiNew
;
2166 pci
->ulClientDelta
= DesktopHeapGetUserDelta();
2167 pci
->pDeskInfo
= (PVOID
)((ULONG_PTR
)pti
->pDeskInfo
- pci
->ulClientDelta
);
2168 pci
->pClientThreadInfo
= (PVOID
)((ULONG_PTR
)pti
->pcti
- pci
->ulClientDelta
);
2170 /* initialize the new pcti */
2173 RtlCopyMemory(pctiNew
, pctiOld
, sizeof(CLIENTTHREADINFO
));
2177 RtlZeroMemory(pctiNew
, sizeof(CLIENTTHREADINFO
));
2178 pci
->fsHooks
= pti
->fsHooks
;
2179 pci
->dwTIFlags
= pti
->TIF_flags
;
2186 pti
->pDeskInfo
= NULL
;
2187 pti
->pcti
= &pti
->cti
; // Always point inside so there will be no crash when posting or sending msg's!
2188 pci
->ulClientDelta
= 0;
2189 pci
->pDeskInfo
= NULL
;
2190 pci
->pClientThreadInfo
= NULL
;
2193 /* clean up the old desktop */
2194 if(pdeskOld
!= NULL
)
2196 RemoveEntryList(&pti
->PtiLink
);
2197 if (pctiOld
) DesktopHeapFree(pdeskOld
, pctiOld
);
2198 IntUnmapDesktopView(pdeskOld
);
2199 ObDereferenceObject(pdeskOld
);
2205 InsertTailList(&pdesk
->PtiList
, &pti
->PtiLink
);
2208 TRACE("IntSetThreadDesktop: pti 0x%p ppi 0x%p switched from object 0x%p to 0x%p\n", pti
, pti
->ppi
, pdeskOld
, pdesk
);
2214 * NtUserSetThreadDesktop
2221 NtUserSetThreadDesktop(HDESK hDesktop
)
2225 UserEnterExclusive();
2227 // FIXME: IntSetThreadDesktop validates the desktop handle, it should happen
2228 // here too and set the NT error level. Q. Is it necessary to have the validation
2229 // in IntSetThreadDesktop? Is it needed there too?
2230 if (hDesktop
|| (!hDesktop
&& PsGetCurrentProcess() == gpepCSRSS
))
2231 ret
= IntSetThreadDesktop(hDesktop
, FALSE
);