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
);
670 PCURICON_OBJECT pcurOld
, pcurNew
;
671 pcurNew
= UserGetCurIconObject(gDesktopCursor
);
677 pcurNew
->CURSORF_flags
|= CURSORF_CURRENT
;
678 pcurOld
= UserSetCursor(pcurNew
, FALSE
);
681 pcurOld
->CURSORF_flags
&= ~CURSORF_CURRENT
;
682 UserDereferenceObject(pcurOld
);
687 case WM_WINDOWPOSCHANGING
:
689 PWINDOWPOS pWindowPos
= (PWINDOWPOS
)lParam
;
690 if((pWindowPos
->flags
& SWP_SHOWWINDOW
) != 0)
692 HDESK hdesk
= IntGetDesktopObjectHandle(gpdeskInputDesktop
);
693 IntSetThreadDesktop(hdesk
, FALSE
);
698 TRACE("DWP calling IDWP Msg %d\n",Msg
);
699 //*lResult = IntDefWindowProc(Wnd, Msg, wParam, lParam, FALSE);
701 return TRUE
; /* We are done. Do not do any callbacks to user mode */
705 UserMessageWindowProc(PWND pwnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*lResult
)
712 pwnd
->fnid
|= FNID_MESSAGEWND
;
713 *lResult
= (LRESULT
)TRUE
;
716 pwnd
->fnid
|= FNID_DESTROY
;
719 ERR("UMWP calling IDWP\n");
720 *lResult
= IntDefWindowProc(pwnd
, Msg
, wParam
, lParam
, FALSE
);
723 return TRUE
; /* We are done. Do not do any callbacks to user mode */
726 VOID NTAPI
DesktopThreadMain(VOID
)
731 gptiDesktopThread
= PsGetCurrentThreadWin32Thread();
733 UserEnterExclusive();
735 /* Register system classes. This thread does not belong to any desktop so the
736 classes will be allocated from the shared heap */
737 UserRegisterSystemClasses();
741 Ret
= co_IntGetPeekMessage(&Msg
, 0, 0, 0, PM_REMOVE
, TRUE
);
744 IntDispatchMessage(&Msg
);
752 UserGetDesktopDC(ULONG DcType
, BOOL EmptyDC
, BOOL ValidatehWnd
)
754 PWND DesktopObject
= 0;
757 if (DcType
== DC_TYPE_DIRECT
)
759 DesktopObject
= UserGetDesktopWindow();
760 DesktopHDC
= (HDC
)UserGetWindowDC(DesktopObject
);
764 PMONITOR pMonitor
= UserGetPrimaryMonitor();
765 DesktopHDC
= IntGdiCreateDisplayDC(pMonitor
->hDev
, DcType
, EmptyDC
);
772 UserRedrawDesktop(VOID
)
777 Window
= UserGetDesktopWindow();
778 Rgn
= IntSysCreateRectpRgnIndirect(&Window
->rcWindow
);
780 IntInvalidateWindows( Window
,
792 co_IntShowDesktop(PDESKTOP Desktop
, ULONG Width
, ULONG Height
, BOOL bRedraw
)
794 PWND pwnd
= Desktop
->pDeskInfo
->spwnd
;
795 UINT flags
= SWP_NOACTIVATE
|SWP_NOZORDER
|SWP_SHOWWINDOW
;
799 flags
|= SWP_NOREDRAW
;
801 co_WinPosSetWindowPos(pwnd
, NULL
, 0, 0, Width
, Height
, flags
);
804 co_UserRedrawWindow( pwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
| RDW_INVALIDATE
);
806 return STATUS_SUCCESS
;
810 IntHideDesktop(PDESKTOP Desktop
)
814 DesktopWnd
= IntGetWindowObject(Desktop
->DesktopWindow
);
817 return ERROR_INVALID_WINDOW_HANDLE
;
819 DesktopWnd
->style
&= ~WS_VISIBLE
;
821 return STATUS_SUCCESS
;
826 UserBuildShellHookHwndList(PDESKTOP Desktop
)
829 PLIST_ENTRY ListEntry
;
830 PSHELL_HOOK_WINDOW Current
;
833 /* FIXME: If we save nb elements in desktop, we don't have to loop to find nb entries */
834 ListEntry
= Desktop
->ShellHookWindows
.Flink
;
835 while (ListEntry
!= &Desktop
->ShellHookWindows
)
837 ListEntry
= ListEntry
->Flink
;
841 if (!entries
) return NULL
;
843 list
= ExAllocatePoolWithTag(PagedPool
, sizeof(HWND
) * (entries
+ 1), USERTAG_WINDOWLIST
); /* alloc one extra for nullterm */
848 ListEntry
= Desktop
->ShellHookWindows
.Flink
;
849 while (ListEntry
!= &Desktop
->ShellHookWindows
)
851 Current
= CONTAINING_RECORD(ListEntry
, SHELL_HOOK_WINDOW
, ListEntry
);
852 ListEntry
= ListEntry
->Flink
;
853 *cursor
++ = Current
->hWnd
;
856 *cursor
= NULL
; /* Nullterm list */
863 * Send the Message to the windows registered for ShellHook
864 * notifications. The lParam contents depend on the Message. See
865 * MSDN for more details (RegisterShellHookWindow)
867 VOID
co_IntShellHookNotify(WPARAM Message
, WPARAM wParam
, LPARAM lParam
)
869 PDESKTOP Desktop
= IntGetActiveDesktop();
872 if (!gpsi
->uiShellMsg
)
874 gpsi
->uiShellMsg
= IntAddAtom(L
"SHELLHOOK");
876 TRACE("MsgType = %x\n", gpsi
->uiShellMsg
);
877 if (!gpsi
->uiShellMsg
)
878 ERR("LastError: %x\n", EngGetLastError());
883 TRACE("IntShellHookNotify: No desktop!\n");
887 // Allow other devices have a shot at foreground.
888 if (Message
== HSHELL_APPCOMMAND
) ptiLastInput
= NULL
;
890 // FIXME: System Tray Support.
892 HwndList
= UserBuildShellHookHwndList(Desktop
);
895 HWND
* cursor
= HwndList
;
897 for (; *cursor
; cursor
++)
899 TRACE("Sending notify\n");
900 UserPostMessage(*cursor
,
903 (Message
== HSHELL_LANGUAGE
? lParam
: (LPARAM
)wParam
) );
904 /* co_IntPostOrSendMessage(*cursor,
907 (Message == HSHELL_LANGUAGE ? lParam : (LPARAM)wParam) );*/
910 ExFreePoolWithTag(HwndList
, USERTAG_WINDOWLIST
);
913 if (ISITHOOKED(WH_SHELL
))
915 co_HOOK_CallHooks(WH_SHELL
, Message
, wParam
, lParam
);
920 * Add the window to the ShellHookWindows list. The windows
921 * on that list get notifications that are important to shell
924 * TODO: Validate the window? I'm not sure if sending these messages to
925 * an unsuspecting application that is not your own is a nice thing to do.
927 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
929 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
930 PDESKTOP Desktop
= pti
->rpdesk
;
931 PSHELL_HOOK_WINDOW Entry
;
933 TRACE("IntRegisterShellHookWindow\n");
935 /* First deregister the window, so we can be sure it's never twice in the
938 IntDeRegisterShellHookWindow(hWnd
);
940 Entry
= ExAllocatePoolWithTag(PagedPool
,
941 sizeof(SHELL_HOOK_WINDOW
),
949 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
955 * Remove the window from the ShellHookWindows list. The windows
956 * on that list get notifications that are important to shell
959 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
961 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
962 PDESKTOP Desktop
= pti
->rpdesk
;
963 PLIST_ENTRY ListEntry
;
964 PSHELL_HOOK_WINDOW Current
;
966 ListEntry
= Desktop
->ShellHookWindows
.Flink
;
967 while (ListEntry
!= &Desktop
->ShellHookWindows
)
969 Current
= CONTAINING_RECORD(ListEntry
, SHELL_HOOK_WINDOW
, ListEntry
);
970 ListEntry
= ListEntry
->Flink
;
971 if (Current
->hWnd
== hWnd
)
973 RemoveEntryList(&Current
->ListEntry
);
974 ExFreePoolWithTag(Current
, TAG_WINSTA
);
983 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop
)
985 /* FIXME: Disable until unmapping works in mm */
987 if (Desktop
->pheapDesktop
!= NULL
)
989 MmUnmapViewInSessionSpace(Desktop
->pheapDesktop
);
990 Desktop
->pheapDesktop
= NULL
;
993 if (Desktop
->hsectionDesktop
!= NULL
)
995 ObDereferenceObject(Desktop
->hsectionDesktop
);
996 Desktop
->hsectionDesktop
= NULL
;
1002 IntPaintDesktop(HDC hDC
)
1005 HBRUSH DesktopBrush
, PreviousBrush
;
1007 BOOL doPatBlt
= TRUE
;
1009 static WCHAR s_wszSafeMode
[] = L
"Safe Mode";
1015 if (GdiGetClipBox(hDC
, &Rect
) == ERROR
)
1018 hWndDesktop
= IntGetDesktopWindow(); // rpdesk->DesktopWindow;
1020 WndDesktop
= UserGetWindowObject(hWndDesktop
); // rpdesk->pDeskInfo->spwnd;
1024 if (!UserGetSystemMetrics(SM_CLEANBOOT
))
1026 DesktopBrush
= (HBRUSH
)WndDesktop
->pcls
->hbrBackground
;
1029 * Paint desktop background
1031 if (gspv
.hbmWallpaper
!= NULL
)
1037 sz
.cx
= WndDesktop
->rcWindow
.right
- WndDesktop
->rcWindow
.left
;
1038 sz
.cy
= WndDesktop
->rcWindow
.bottom
- WndDesktop
->rcWindow
.top
;
1040 if (gspv
.WallpaperMode
== wmStretch
||
1041 gspv
.WallpaperMode
== wmTile
)
1048 /* Find the upper left corner, can be negative if the bitmap is bigger then the screen */
1049 x
= (sz
.cx
/ 2) - (gspv
.cxWallpaper
/ 2);
1050 y
= (sz
.cy
/ 2) - (gspv
.cyWallpaper
/ 2);
1053 hWallpaperDC
= NtGdiCreateCompatibleDC(hDC
);
1054 if(hWallpaperDC
!= NULL
)
1058 /* Fill in the area that the bitmap is not going to cover */
1061 /* FIXME: Clip out the bitmap
1062 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1063 once we support DSTINVERT */
1064 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1065 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1066 NtGdiSelectBrush(hDC
, PreviousBrush
);
1069 /* Do not fill the background after it is painted no matter the size of the picture */
1072 hOldBitmap
= NtGdiSelectBitmap(hWallpaperDC
, gspv
.hbmWallpaper
);
1074 if (gspv
.WallpaperMode
== wmStretch
)
1076 if(Rect
.right
&& Rect
.bottom
)
1077 NtGdiStretchBlt(hDC
,
1090 else if (gspv
.WallpaperMode
== wmTile
)
1092 /* Paint the bitmap across the screen then down */
1093 for(y
= 0; y
< Rect
.bottom
; y
+= gspv
.cyWallpaper
)
1095 for(x
= 0; x
< Rect
.right
; x
+= gspv
.cxWallpaper
)
1125 NtGdiSelectBitmap(hWallpaperDC
, hOldBitmap
);
1126 NtGdiDeleteObjectApp(hWallpaperDC
);
1132 /* Black desktop background in Safe Mode */
1133 DesktopBrush
= StockObjects
[BLACK_BRUSH
];
1135 /* Background is set to none, clear the screen */
1138 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1139 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1140 NtGdiSelectBrush(hDC
, PreviousBrush
);
1144 * Display system version on the desktop background
1147 if (g_PaintDesktopVersion
|| UserGetSystemMetrics(SM_CLEANBOOT
))
1149 static WCHAR s_wszVersion
[256] = {0};
1154 len
= wcslen(s_wszVersion
);
1158 len
= GetSystemVersionString(s_wszVersion
);
1163 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
1165 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1166 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1169 color_old
= IntGdiSetTextColor(hDC
, RGB(255,255,255));
1170 align_old
= IntGdiSetTextAlign(hDC
, TA_RIGHT
);
1171 mode_old
= IntGdiSetBkMode(hDC
, TRANSPARENT
);
1173 if(!UserGetSystemMetrics(SM_CLEANBOOT
))
1175 GreExtTextOutW(hDC
, rect
.right
- 16, rect
.bottom
- 48, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1181 /* Version information text in top center */
1182 IntGdiSetTextAlign(hDC
, TA_CENTER
| TA_TOP
);
1183 GreExtTextOutW(hDC
, (rect
.right
+ rect
.left
)/2, rect
.top
+ 3, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1185 /* Safe Mode text in corners */
1186 len
= wcslen(s_wszSafeMode
);
1187 IntGdiSetTextAlign(hDC
, TA_LEFT
| TA_TOP
);
1188 GreExtTextOutW(hDC
, rect
.left
, rect
.top
+ 3, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1189 IntGdiSetTextAlign(hDC
, TA_RIGHT
| TA_TOP
);
1190 GreExtTextOutW(hDC
, rect
.right
, rect
.top
+ 3, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1191 IntGdiSetTextAlign(hDC
, TA_LEFT
| TA_BASELINE
);
1192 GreExtTextOutW(hDC
, rect
.left
, rect
.bottom
- 5, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1193 IntGdiSetTextAlign(hDC
, TA_RIGHT
| TA_BASELINE
);
1194 GreExtTextOutW(hDC
, rect
.right
, rect
.bottom
- 5, 0, NULL
, s_wszSafeMode
, len
, NULL
, 0);
1197 IntGdiSetBkMode(hDC
, mode_old
);
1198 IntGdiSetTextAlign(hDC
, align_old
);
1199 IntGdiSetTextColor(hDC
, color_old
);
1206 UserInitializeDesktop(PDESKTOP pdesk
, PUNICODE_STRING DesktopName
, PWINSTATION_OBJECT pwinsta
)
1208 PVOID DesktopHeapSystemBase
= NULL
;
1209 ULONG_PTR HeapSize
= gdwDesktopSectionSize
* 1024;
1210 SIZE_T DesktopInfoSize
;
1213 TRACE("UserInitializeDesktop desktop 0x%p with name %wZ\n", pdesk
, DesktopName
);
1215 RtlZeroMemory(pdesk
, sizeof(DESKTOP
));
1217 /* Link the desktop with the parent window station */
1218 pdesk
->rpwinstaParent
= pwinsta
;
1219 InsertTailList(&pwinsta
->DesktopListHead
, &pdesk
->ListEntry
);
1221 /* Create the desktop heap */
1222 pdesk
->hsectionDesktop
= NULL
;
1223 pdesk
->pheapDesktop
= UserCreateHeap(&pdesk
->hsectionDesktop
,
1224 &DesktopHeapSystemBase
,
1226 if (pdesk
->pheapDesktop
== NULL
)
1228 ERR("Failed to create desktop heap!\n");
1229 return STATUS_NO_MEMORY
;
1232 /* Create DESKTOPINFO */
1233 DesktopInfoSize
= sizeof(DESKTOPINFO
) + DesktopName
->Length
+ sizeof(WCHAR
);
1234 pdesk
->pDeskInfo
= RtlAllocateHeap(pdesk
->pheapDesktop
,
1235 HEAP_NO_SERIALIZE
| HEAP_ZERO_MEMORY
,
1237 if (pdesk
->pDeskInfo
== NULL
)
1239 ERR("Failed to create the DESKTOP structure!\n");
1240 return STATUS_NO_MEMORY
;
1243 /* Initialize the DESKTOPINFO */
1244 pdesk
->pDeskInfo
->pvDesktopBase
= DesktopHeapSystemBase
;
1245 pdesk
->pDeskInfo
->pvDesktopLimit
= (PVOID
)((ULONG_PTR
)DesktopHeapSystemBase
+ HeapSize
);
1246 RtlCopyMemory(pdesk
->pDeskInfo
->szDesktopName
,
1247 DesktopName
->Buffer
,
1248 DesktopName
->Length
+ sizeof(WCHAR
));
1249 for (i
= 0; i
< NB_HOOKS
; i
++)
1251 InitializeListHead(&pdesk
->pDeskInfo
->aphkStart
[i
]);
1254 InitializeListHead(&pdesk
->ShellHookWindows
);
1255 InitializeListHead(&pdesk
->PtiList
);
1257 return STATUS_SUCCESS
;
1260 /* SYSCALLS *******************************************************************/
1263 * NtUserCreateDesktop
1265 * Creates a new desktop.
1269 * Object Attributes.
1272 * Name of the device.
1278 * Interaction flags.
1281 * Requested type of access.
1285 * If the function succeeds, the return value is a handle to the newly
1286 * created desktop. If the specified desktop already exists, the function
1287 * succeeds and returns a handle to the existing desktop. When you are
1288 * finished using the handle, call the CloseDesktop function to close it.
1289 * If the function fails, the return value is NULL.
1296 NtUserCreateDesktop(
1297 POBJECT_ATTRIBUTES ObjectAttributes
,
1298 PUNICODE_STRING lpszDesktopDevice
,
1301 ACCESS_MASK dwDesiredAccess
)
1303 PDESKTOP pdesk
= NULL
;
1304 NTSTATUS Status
= STATUS_SUCCESS
;
1306 BOOLEAN Context
= FALSE
;
1307 UNICODE_STRING ClassName
;
1308 LARGE_STRING WindowName
;
1309 BOOL NoHooks
= FALSE
;
1312 PTHREADINFO ptiCurrent
;
1315 DECLARE_RETURN(HDESK
);
1317 TRACE("Enter NtUserCreateDesktop\n");
1318 UserEnterExclusive();
1320 ptiCurrent
= PsGetCurrentThreadWin32Thread();
1322 ASSERT(gptiDesktopThread
);
1324 /* Turn off hooks when calling any CreateWindowEx from inside win32k. */
1325 NoHooks
= (ptiCurrent
->TIF_flags
& TIF_DISABLEHOOKS
);
1326 ptiCurrent
->TIF_flags
|= TIF_DISABLEHOOKS
;
1327 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
1330 * Try to open already existing desktop
1332 Status
= ObOpenObjectByName(
1334 ExDesktopObjectType
,
1340 if (!NT_SUCCESS(Status
))
1342 ERR("ObOpenObjectByName failed to open/create desktop\n");
1343 SetLastNtError(Status
);
1347 /* In case the object was not created (eg if it existed), return now */
1348 if (Context
== FALSE
)
1350 TRACE("NtUserCreateDesktop opened desktop %wZ\n", ObjectAttributes
->ObjectName
);
1354 /* Reference the desktop */
1355 Status
= ObReferenceObjectByHandle(hdesk
,
1357 ExDesktopObjectType
,
1361 if (!NT_SUCCESS(Status
))
1363 ERR("Failed to reference desktop object\n");
1364 SetLastNtError(Status
);
1368 /* Get the desktop window class. The thread desktop does not belong to any desktop
1369 * so the classes created there (including the desktop class) are allocated in the shared heap
1370 * It would cause problems if we used a class that belongs to the caller
1372 ClassName
.Buffer
= WC_DESKTOP
;
1373 ClassName
.Length
= 0;
1374 pcls
= IntGetAndReferenceClass(&ClassName
, 0, TRUE
);
1381 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1382 RtlZeroMemory(&Cs
, sizeof(Cs
));
1383 Cs
.x
= UserGetSystemMetrics(SM_XVIRTUALSCREEN
),
1384 Cs
.y
= UserGetSystemMetrics(SM_YVIRTUALSCREEN
),
1385 Cs
.cx
= UserGetSystemMetrics(SM_CXVIRTUALSCREEN
),
1386 Cs
.cy
= UserGetSystemMetrics(SM_CYVIRTUALSCREEN
),
1387 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1388 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
1389 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1390 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1392 /* Use IntCreateWindow instead of co_UserCreateWindowEx cause the later expects a thread with a desktop */
1393 pWnd
= IntCreateWindow(&Cs
, &WindowName
, pcls
, NULL
, NULL
, NULL
, pdesk
);
1396 ERR("Failed to create desktop window for the new desktop\n");
1400 pdesk
->dwSessionId
= PsGetCurrentProcessSessionId();
1401 pdesk
->DesktopWindow
= pWnd
->head
.h
;
1402 pdesk
->pDeskInfo
->spwnd
= pWnd
;
1403 pWnd
->fnid
= FNID_DESKTOP
;
1405 ClassName
.Buffer
= MAKEINTATOM(gpsi
->atomSysClass
[ICLS_HWNDMESSAGE
]);
1406 ClassName
.Length
= 0;
1407 pcls
= IntGetAndReferenceClass(&ClassName
, 0, TRUE
);
1414 RtlZeroMemory(&WindowName
, sizeof(WindowName
));
1415 RtlZeroMemory(&Cs
, sizeof(Cs
));
1416 Cs
.cx
= Cs
.cy
= 100;
1417 Cs
.style
= WS_POPUP
|WS_CLIPCHILDREN
;
1418 Cs
.hInstance
= hModClient
; // hModuleWin; // Server side winproc!
1419 Cs
.lpszName
= (LPCWSTR
) &WindowName
;
1420 Cs
.lpszClass
= (LPCWSTR
) &ClassName
;
1421 pWnd
= IntCreateWindow(&Cs
, &WindowName
, pcls
, NULL
, NULL
, NULL
, pdesk
);
1424 ERR("Failed to create message window for the new desktop\n");
1428 pdesk
->spwndMessage
= pWnd
;
1429 pWnd
->fnid
= FNID_MESSAGEWND
;
1432 if !(WinStaObject->Flags & WSF_NOIO) is (not set) for desktop input output mode (see wiki)
1433 Create Tooltip. Saved in DesktopObject->spwndTooltip.
1434 Tooltip dwExStyle: WS_EX_TOOLWINDOW|WS_EX_TOPMOST
1435 hWndParent are spwndMessage. Use hModuleWin for server side winproc!
1436 The rest is same as message window.
1437 http://msdn.microsoft.com/en-us/library/bb760250(VS.85).aspx
1444 ObDereferenceObject(pdesk
);
1446 if (_ret_
== NULL
&& hdesk
!= NULL
)
1448 ObCloseHandle(hdesk
, UserMode
);
1452 ptiCurrent
->TIF_flags
&= ~TIF_DISABLEHOOKS
;
1453 ptiCurrent
->pClientInfo
->dwTIFlags
= ptiCurrent
->TIF_flags
;
1455 TRACE("Leave NtUserCreateDesktop, ret=%p\n",_ret_
);
1463 * Opens an existing desktop.
1467 * Name of the existing desktop.
1470 * Interaction flags.
1473 * Requested type of access.
1476 * Handle to the desktop or zero on failure.
1484 POBJECT_ATTRIBUTES ObjectAttributes
,
1486 ACCESS_MASK dwDesiredAccess
)
1491 Status
= ObOpenObjectByName(
1493 ExDesktopObjectType
,
1500 if (!NT_SUCCESS(Status
))
1502 ERR("Failed to open desktop\n");
1503 SetLastNtError(Status
);
1507 TRACE("Opened desktop %S with handle 0x%p\n", ObjectAttributes
->ObjectName
->Buffer
, Desktop
);
1513 * NtUserOpenInputDesktop
1515 * Opens the input (interactive) desktop.
1519 * Interaction flags.
1522 * Inheritance option.
1525 * Requested type of access.
1528 * Handle to the input desktop or zero on failure.
1535 NtUserOpenInputDesktop(
1538 ACCESS_MASK dwDesiredAccess
)
1542 ULONG HandleAttributes
= 0;
1544 UserEnterExclusive();
1545 TRACE("Enter NtUserOpenInputDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop
);
1547 if(fInherit
) HandleAttributes
= OBJ_INHERIT
;
1549 /* Create a new handle to the object */
1550 Status
= ObOpenObjectByPointer(
1555 ExDesktopObjectType
,
1559 if (!NT_SUCCESS(Status
))
1561 ERR("Failed to open input desktop object\n");
1562 SetLastNtError(Status
);
1565 TRACE("NtUserOpenInputDesktop returning 0x%p\n",hdesk
);
1571 * NtUserCloseDesktop
1573 * Closes a desktop handle.
1577 * Handle to the desktop.
1583 * The desktop handle can be created with NtUserCreateDesktop or
1584 * NtUserOpenDesktop. This function will fail if any thread in the calling
1585 * process is using the specified desktop handle or if the handle refers
1586 * to the initial desktop of the calling process.
1593 NtUserCloseDesktop(HDESK hDesktop
)
1597 DECLARE_RETURN(BOOL
);
1599 TRACE("NtUserCloseDesktop called (0x%p)\n", hDesktop
);
1600 UserEnterExclusive();
1602 if( hDesktop
== gptiCurrent
->hdesk
|| hDesktop
== gptiCurrent
->ppi
->hdeskStartup
)
1604 ERR("Attempted to close thread desktop\n");
1605 EngSetLastError(ERROR_BUSY
);
1609 Status
= IntValidateDesktopHandle( hDesktop
, UserMode
, 0, &pdesk
);
1610 if (!NT_SUCCESS(Status
))
1612 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop
);
1616 ObDereferenceObject(pdesk
);
1618 Status
= ZwClose(hDesktop
);
1619 if (!NT_SUCCESS(Status
))
1621 ERR("Failed to close desktop handle 0x%p\n", hDesktop
);
1622 SetLastNtError(Status
);
1629 TRACE("Leave NtUserCloseDesktop, ret=%i\n",_ret_
);
1635 * NtUserPaintDesktop
1637 * The NtUserPaintDesktop function fills the clipping region in the
1638 * specified device context with the desktop pattern or wallpaper. The
1639 * function is provided primarily for shell desktops.
1643 * Handle to the device context.
1650 NtUserPaintDesktop(HDC hDC
)
1653 UserEnterExclusive();
1654 TRACE("Enter NtUserPaintDesktop\n");
1655 Ret
= IntPaintDesktop(hDC
);
1656 TRACE("Leave NtUserPaintDesktop, ret=%i\n",Ret
);
1662 * NtUserResolveDesktop
1664 * The NtUserResolveDesktop function retrieves handles to the desktop and
1665 * the window station specified by the desktop path string.
1669 * Handle to a user process.
1672 * The desktop path string.
1675 * Handle to the desktop (direct return value) and
1676 * handle to the associated window station (by pointer).
1677 * NULL in case of failure.
1680 * Callable by CSRSS only.
1688 NtUserResolveDesktop(
1689 IN HANDLE ProcessHandle
,
1690 IN PUNICODE_STRING DesktopPath
,
1692 OUT HWINSTA
* phWinSta
)
1695 PEPROCESS Process
= NULL
;
1696 HWINSTA hWinSta
= NULL
;
1697 HDESK hDesktop
= NULL
;
1699 /* Allow only the Console Server to perform this operation (via CSRSS) */
1700 if (PsGetCurrentProcess() != gpepCSRSS
)
1703 /* Get the process object the user handle was referencing */
1704 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1705 PROCESS_QUERY_INFORMATION
,
1710 if (!NT_SUCCESS(Status
)) return NULL
;
1712 // UserEnterShared();
1716 UNICODE_STRING CapturedDesktopPath
;
1718 /* Capture the user desktop path string */
1719 Status
= IntSafeCopyUnicodeStringTerminateNULL(&CapturedDesktopPath
,
1721 if (!NT_SUCCESS(Status
)) _SEH2_YIELD(goto Quit
);
1723 /* Call the internal function */
1724 Status
= IntParseDesktopPath(Process
,
1725 &CapturedDesktopPath
,
1728 if (!NT_SUCCESS(Status
))
1730 ERR("IntParseDesktopPath failed, Status = 0x%08lx\n", Status
);
1735 /* Return the window station handle */
1736 *phWinSta
= hWinSta
;
1738 /* Free the captured string */
1739 if (CapturedDesktopPath
.Buffer
)
1740 ExFreePoolWithTag(CapturedDesktopPath
.Buffer
, TAG_STRING
);
1742 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1744 Status
= _SEH2_GetExceptionCode();
1751 /* Dereference the process object */
1752 ObDereferenceObject(Process
);
1754 /* Return the desktop handle */
1759 * NtUserSwitchDesktop
1761 * Sets the current input (interactive) desktop.
1765 * Handle to desktop.
1775 NtUserSwitchDesktop(HDESK hdesk
)
1779 BOOL bRedrawDesktop
;
1780 DECLARE_RETURN(BOOL
);
1782 UserEnterExclusive();
1783 TRACE("Enter NtUserSwitchDesktop(0x%p)\n", hdesk
);
1785 Status
= IntValidateDesktopHandle( hdesk
, UserMode
, 0, &pdesk
);
1786 if (!NT_SUCCESS(Status
))
1788 ERR("Validation of desktop handle (0x%p) failed\n", hdesk
);
1792 if (PsGetCurrentProcessSessionId() != pdesk
->rpwinstaParent
->dwSessionId
)
1794 ERR("NtUserSwitchDesktop called for a desktop of a different session\n");
1798 if(pdesk
== gpdeskInputDesktop
)
1800 WARN("NtUserSwitchDesktop called for active desktop\n");
1805 * Don't allow applications switch the desktop if it's locked, unless the caller
1806 * is the logon application itself
1808 if((pdesk
->rpwinstaParent
->Flags
& WSS_LOCKED
) &&
1809 gpidLogon
!= PsGetCurrentProcessId())
1811 ObDereferenceObject(pdesk
);
1812 ERR("Switching desktop 0x%p denied because the window station is locked!\n", hdesk
);
1816 if(pdesk
->rpwinstaParent
!= InputWindowStation
)
1818 ObDereferenceObject(pdesk
);
1819 ERR("Switching desktop 0x%p denied because desktop doesn't belong to the interactive winsta!\n", hdesk
);
1823 /* FIXME: Fail if the process is associated with a secured
1824 desktop such as Winlogon or Screen-Saver */
1825 /* FIXME: Connect to input device */
1827 TRACE("Switching from desktop 0x%p to 0x%p\n", gpdeskInputDesktop
, pdesk
);
1829 bRedrawDesktop
= FALSE
;
1831 /* The first time SwitchDesktop is called, gpdeskInputDesktop is NULL */
1832 if(gpdeskInputDesktop
!= NULL
)
1834 if((gpdeskInputDesktop
->pDeskInfo
->spwnd
->style
& WS_VISIBLE
) == WS_VISIBLE
)
1835 bRedrawDesktop
= TRUE
;
1837 /* Hide the previous desktop window */
1838 IntHideDesktop(gpdeskInputDesktop
);
1841 /* Set the active desktop in the desktop's window station. */
1842 InputWindowStation
->ActiveDesktop
= pdesk
;
1844 /* Set the global state. */
1845 gpdeskInputDesktop
= pdesk
;
1847 /* Show the new desktop window */
1848 co_IntShowDesktop(pdesk
, UserGetSystemMetrics(SM_CXSCREEN
), UserGetSystemMetrics(SM_CYSCREEN
), bRedrawDesktop
);
1850 TRACE("SwitchDesktop gpdeskInputDesktop 0x%p\n",gpdeskInputDesktop
);
1851 ObDereferenceObject(pdesk
);
1856 TRACE("Leave NtUserSwitchDesktop, ret=%i\n",_ret_
);
1862 * NtUserGetThreadDesktop
1869 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1873 PDESKTOP DesktopObject
;
1874 HDESK Ret
, hThreadDesktop
;
1875 OBJECT_HANDLE_INFORMATION HandleInformation
;
1876 DECLARE_RETURN(HDESK
);
1878 UserEnterExclusive();
1879 TRACE("Enter NtUserGetThreadDesktop\n");
1883 EngSetLastError(ERROR_INVALID_PARAMETER
);
1887 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)dwThreadId
, &Thread
);
1888 if(!NT_SUCCESS(Status
))
1890 EngSetLastError(ERROR_INVALID_PARAMETER
);
1894 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1896 /* Just return the handle, we queried the desktop handle of a thread running
1897 in the same context */
1898 Ret
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
;
1899 ObDereferenceObject(Thread
);
1903 /* Get the desktop handle and the desktop of the thread */
1904 if(!(hThreadDesktop
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hdesk
) ||
1905 !(DesktopObject
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->rpdesk
))
1907 ObDereferenceObject(Thread
);
1908 ERR("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1912 /* We could just use DesktopObject instead of looking up the handle, but latter
1913 may be a bit safer (e.g. when the desktop is being destroyed */
1914 /* Switch into the context of the thread we're trying to get the desktop from,
1915 so we can use the handle */
1916 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1917 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1919 ExDesktopObjectType
,
1921 (PVOID
*)&DesktopObject
,
1922 &HandleInformation
);
1925 /* The handle couldn't be found, there's nothing to get... */
1926 if(!NT_SUCCESS(Status
))
1928 ObDereferenceObject(Thread
);
1932 /* Lookup our handle table if we can find a handle to the desktop object,
1933 if not, create one */
1934 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1936 /* All done, we got a valid handle to the desktop */
1937 ObDereferenceObject(DesktopObject
);
1938 ObDereferenceObject(Thread
);
1942 TRACE("Leave NtUserGetThreadDesktop, ret=%p\n",_ret_
);
1948 IntUnmapDesktopView(IN PDESKTOP pdesk
)
1951 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1952 NTSTATUS Status
= STATUS_SUCCESS
;
1954 TRACE("IntUnmapDesktopView called for desktop object %p\n", pdesk
);
1956 ppi
= PsGetCurrentProcessWin32Process();
1959 * Unmap if we're the last thread using the desktop.
1960 * Start the search at the next mapping: skip the first entry
1961 * as it must be the global user heap mapping.
1963 PrevLink
= &ppi
->HeapMappings
.Next
;
1964 HeapMapping
= *PrevLink
;
1965 while (HeapMapping
!= NULL
)
1967 if (HeapMapping
->KernelMapping
== (PVOID
)pdesk
->pheapDesktop
)
1969 if (--HeapMapping
->Count
== 0)
1971 *PrevLink
= HeapMapping
->Next
;
1973 TRACE("ppi 0x%p unmapped heap of desktop 0x%p\n", ppi
, pdesk
);
1974 Status
= MmUnmapViewOfSection(PsGetCurrentProcess(),
1975 HeapMapping
->UserMapping
);
1977 ObDereferenceObject(pdesk
);
1979 UserHeapFree(HeapMapping
);
1984 PrevLink
= &HeapMapping
->Next
;
1985 HeapMapping
= HeapMapping
->Next
;
1992 IntMapDesktopView(IN PDESKTOP pdesk
)
1995 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1996 PVOID UserBase
= NULL
;
1997 SIZE_T ViewSize
= 0;
1998 LARGE_INTEGER Offset
;
2001 TRACE("IntMapDesktopView called for desktop object 0x%p\n", pdesk
);
2003 ppi
= PsGetCurrentProcessWin32Process();
2006 * Find out if another thread already mapped the desktop heap.
2007 * Start the search at the next mapping: skip the first entry
2008 * as it must be the global user heap mapping.
2010 PrevLink
= &ppi
->HeapMappings
.Next
;
2011 HeapMapping
= *PrevLink
;
2012 while (HeapMapping
!= NULL
)
2014 if (HeapMapping
->KernelMapping
== (PVOID
)pdesk
->pheapDesktop
)
2016 HeapMapping
->Count
++;
2017 return STATUS_SUCCESS
;
2020 PrevLink
= &HeapMapping
->Next
;
2021 HeapMapping
= HeapMapping
->Next
;
2024 /* We're the first, map the heap */
2025 Offset
.QuadPart
= 0;
2026 Status
= MmMapViewOfSection(pdesk
->hsectionDesktop
,
2027 PsGetCurrentProcess(),
2035 PAGE_EXECUTE_READ
); /* Would prefer PAGE_READONLY, but thanks to RTL heaps... */
2036 if (!NT_SUCCESS(Status
))
2038 ERR("Failed to map desktop\n");
2042 TRACE("ppi 0x%p mapped heap of desktop 0x%p\n", ppi
, pdesk
);
2044 /* Add the mapping */
2045 HeapMapping
= UserHeapAlloc(sizeof(*HeapMapping
));
2046 if (HeapMapping
== NULL
)
2048 MmUnmapViewOfSection(PsGetCurrentProcess(), UserBase
);
2049 ERR("UserHeapAlloc() failed!\n");
2050 return STATUS_NO_MEMORY
;
2053 HeapMapping
->Next
= NULL
;
2054 HeapMapping
->KernelMapping
= (PVOID
)pdesk
->pheapDesktop
;
2055 HeapMapping
->UserMapping
= UserBase
;
2056 HeapMapping
->Limit
= ViewSize
;
2057 HeapMapping
->Count
= 1;
2058 *PrevLink
= HeapMapping
;
2060 ObReferenceObject(pdesk
);
2062 return STATUS_SUCCESS
;
2066 IntSetThreadDesktop(IN HDESK hDesktop
,
2067 IN BOOL FreeOnFailure
)
2069 PDESKTOP pdesk
= NULL
, pdeskOld
;
2073 PCLIENTTHREADINFO pctiOld
, pctiNew
= NULL
;
2076 ASSERT(NtCurrentTeb());
2078 TRACE("IntSetThreadDesktop hDesktop:0x%p, FOF:%i\n",hDesktop
, FreeOnFailure
);
2080 pti
= PsGetCurrentThreadWin32Thread();
2081 pci
= pti
->pClientInfo
;
2083 /* If the caller gave us a desktop, ensure it is valid */
2084 if(hDesktop
!= NULL
)
2086 /* Validate the new desktop. */
2087 Status
= IntValidateDesktopHandle( hDesktop
, UserMode
, 0, &pdesk
);
2088 if (!NT_SUCCESS(Status
))
2090 ERR("Validation of desktop handle (0x%p) failed\n", hDesktop
);
2094 if (pti
->rpdesk
== pdesk
)
2097 ObDereferenceObject(pdesk
);
2102 /* Make sure that we don't own any window in the current desktop */
2103 if (!IsListEmpty(&pti
->WindowListHead
))
2106 ObDereferenceObject(pdesk
);
2107 ERR("Attempted to change thread desktop although the thread has windows!\n");
2108 EngSetLastError(ERROR_BUSY
);
2112 /* Desktop is being re-set so clear out foreground. */
2113 if (pti
->rpdesk
!= pdesk
&& pti
->MessageQueue
== gpqForeground
)
2115 // Like above, there shouldn't be any windows, hooks or anything active on this threads desktop!
2116 IntSetFocusMessageQueue(NULL
);
2119 /* Before doing the switch, map the new desktop heap and allocate the new pcti */
2122 Status
= IntMapDesktopView(pdesk
);
2123 if (!NT_SUCCESS(Status
))
2125 ERR("Failed to map desktop heap!\n");
2126 ObDereferenceObject(pdesk
);
2127 SetLastNtError(Status
);
2131 pctiNew
= DesktopHeapAlloc( pdesk
, sizeof(CLIENTTHREADINFO
));
2134 ERR("Failed to allocate new pcti\n");
2135 IntUnmapDesktopView(pdesk
);
2136 ObDereferenceObject(pdesk
);
2137 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2142 /* free all classes or move them to the shared heap */
2143 if(pti
->rpdesk
!= NULL
)
2145 if(!IntCheckProcessDesktopClasses(pti
->rpdesk
, FreeOnFailure
))
2147 ERR("Failed to move process classes to shared heap!\n");
2150 DesktopHeapFree(pdesk
, pctiNew
);
2151 IntUnmapDesktopView(pdesk
);
2152 ObDereferenceObject(pdesk
);
2158 pdeskOld
= pti
->rpdesk
;
2159 hdeskOld
= pti
->hdesk
;
2160 if (pti
->pcti
!= &pti
->cti
)
2161 pctiOld
= pti
->pcti
;
2168 pti
->rpdesk
= pdesk
;
2169 pti
->hdesk
= hDesktop
;
2170 pti
->pDeskInfo
= pti
->rpdesk
->pDeskInfo
;
2171 pti
->pcti
= pctiNew
;
2173 pci
->ulClientDelta
= DesktopHeapGetUserDelta();
2174 pci
->pDeskInfo
= (PVOID
)((ULONG_PTR
)pti
->pDeskInfo
- pci
->ulClientDelta
);
2175 pci
->pClientThreadInfo
= (PVOID
)((ULONG_PTR
)pti
->pcti
- pci
->ulClientDelta
);
2177 /* initialize the new pcti */
2180 RtlCopyMemory(pctiNew
, pctiOld
, sizeof(CLIENTTHREADINFO
));
2184 RtlZeroMemory(pctiNew
, sizeof(CLIENTTHREADINFO
));
2185 pci
->fsHooks
= pti
->fsHooks
;
2186 pci
->dwTIFlags
= pti
->TIF_flags
;
2193 pti
->pDeskInfo
= NULL
;
2194 pti
->pcti
= &pti
->cti
; // Always point inside so there will be no crash when posting or sending msg's!
2195 pci
->ulClientDelta
= 0;
2196 pci
->pDeskInfo
= NULL
;
2197 pci
->pClientThreadInfo
= NULL
;
2200 /* clean up the old desktop */
2201 if(pdeskOld
!= NULL
)
2203 RemoveEntryList(&pti
->PtiLink
);
2204 if (pctiOld
) DesktopHeapFree(pdeskOld
, pctiOld
);
2205 IntUnmapDesktopView(pdeskOld
);
2206 ObDereferenceObject(pdeskOld
);
2212 InsertTailList(&pdesk
->PtiList
, &pti
->PtiLink
);
2215 TRACE("IntSetThreadDesktop: pti 0x%p ppi 0x%p switched from object 0x%p to 0x%p\n", pti
, pti
->ppi
, pdeskOld
, pdesk
);
2221 * NtUserSetThreadDesktop
2228 NtUserSetThreadDesktop(HDESK hDesktop
)
2232 UserEnterExclusive();
2234 // FIXME: IntSetThreadDesktop validates the desktop handle, it should happen
2235 // here too and set the NT error level. Q. Is it necessary to have the validation
2236 // in IntSetThreadDesktop? Is it needed there too?
2237 if (hDesktop
|| (!hDesktop
&& PsGetCurrentProcess() == gpepCSRSS
))
2238 ret
= IntSetThreadDesktop(hDesktop
, FALSE
);