2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
5 * FILE: subsystems/win32/win32k/ntuser/desktop.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * 06-06-2001 CSH Created
11 /* INCLUDES ******************************************************************/
24 IN OUT PDESKTOP Desktop
27 /* GLOBALS *******************************************************************/
29 /* Currently active desktop */
30 PDESKTOP InputDesktop
= NULL
;
31 HDESK InputDesktopHandle
= NULL
;
32 HDC ScreenDeviceContext
= NULL
;
33 BOOL g_PaintDesktopVersion
= FALSE
;
35 GENERIC_MAPPING IntDesktopMapping
=
37 STANDARD_RIGHTS_READ
| DESKTOP_ENUMERATE
|
39 STANDARD_RIGHTS_WRITE
| DESKTOP_CREATEMENU
|
40 DESKTOP_CREATEWINDOW
|
42 DESKTOP_JOURNALPLAYBACK
|
43 DESKTOP_JOURNALRECORD
|
45 STANDARD_RIGHTS_EXECUTE
| DESKTOP_SWITCHDESKTOP
,
46 STANDARD_RIGHTS_REQUIRED
| DESKTOP_CREATEMENU
|
47 DESKTOP_CREATEWINDOW
|
50 DESKTOP_JOURNALPLAYBACK
|
51 DESKTOP_JOURNALRECORD
|
53 DESKTOP_SWITCHDESKTOP
|
57 /* OBJECT CALLBACKS **********************************************************/
61 IntDesktopObjectParse(IN PVOID ParseObject
,
63 IN OUT PACCESS_STATE AccessState
,
64 IN KPROCESSOR_MODE AccessMode
,
66 IN OUT PUNICODE_STRING CompleteName
,
67 IN OUT PUNICODE_STRING RemainingName
,
68 IN OUT PVOID Context OPTIONAL
,
69 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
74 OBJECT_ATTRIBUTES ObjectAttributes
;
75 PLIST_ENTRY NextEntry
, ListHead
;
76 PWINSTATION_OBJECT WinStaObject
= (PWINSTATION_OBJECT
)ParseObject
;
77 PUNICODE_STRING DesktopName
;
79 /* Set the list pointers and loop the window station */
80 ListHead
= &WinStaObject
->DesktopListHead
;
81 NextEntry
= ListHead
->Flink
;
82 while (NextEntry
!= ListHead
)
84 /* Get the current desktop */
85 Desktop
= CONTAINING_RECORD(NextEntry
, DESKTOP
, ListEntry
);
88 DesktopName
= GET_DESKTOP_NAME(Desktop
);
91 /* Compare the name */
92 if (RtlEqualUnicodeString(RemainingName
,
94 (Attributes
& OBJ_CASE_INSENSITIVE
)))
96 /* We found a match. Did this come from a create? */
99 /* Unless OPEN_IF was given, fail with an error */
100 if (!(Attributes
& OBJ_OPENIF
))
103 return STATUS_OBJECT_NAME_COLLISION
;
107 /* Otherwise, return with a warning only */
108 Status
= STATUS_OBJECT_NAME_EXISTS
;
113 /* This was a real open, so this is OK */
114 Status
= STATUS_SUCCESS
;
117 /* Reference the desktop and return it */
118 ObReferenceObject(Desktop
);
124 /* Go to the next desktop */
125 NextEntry
= NextEntry
->Flink
;
128 /* If we got here but this isn't a create, then fail */
129 if (!Context
) return STATUS_OBJECT_NAME_NOT_FOUND
;
131 /* Create the desktop object */
132 InitializeObjectAttributes(&ObjectAttributes
, RemainingName
, 0, NULL
, NULL
);
133 Status
= ObCreateObject(KernelMode
,
142 if (!NT_SUCCESS(Status
)) return Status
;
144 /* Initialize shell hook window list and set the parent */
145 InitializeListHead(&Desktop
->ShellHookWindows
);
146 Desktop
->WindowStation
= (PWINSTATION_OBJECT
)ParseObject
;
148 /* Put the desktop on the window station's list of associated desktops */
149 InsertTailList(&Desktop
->WindowStation
->DesktopListHead
,
150 &Desktop
->ListEntry
);
152 /* Set the desktop object and return success */
154 return STATUS_SUCCESS
;
158 IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
160 PDESKTOP Desktop
= (PDESKTOP
)Parameters
->Object
;
162 DPRINT("Deleting desktop (0x%X)\n", Desktop
);
164 /* Remove the desktop from the window station's list of associcated desktops */
165 RemoveEntryList(&Desktop
->ListEntry
);
167 IntFreeDesktopHeap(Desktop
);
170 /* PRIVATE FUNCTIONS **********************************************************/
174 InitDesktopImpl(VOID
)
176 /* Set Desktop Object Attributes */
177 ExDesktopObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(DESKTOP
);
178 ExDesktopObjectType
->TypeInfo
.GenericMapping
= IntDesktopMapping
;
179 return STATUS_SUCCESS
;
184 CleanupDesktopImpl(VOID
)
186 return STATUS_SUCCESS
;
189 static int GetSystemVersionString(LPWSTR buffer
)
191 RTL_OSVERSIONINFOEXW versionInfo
;
194 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
196 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
199 if (versionInfo
.dwMajorVersion
<= 4)
200 len
= swprintf(buffer
,
201 L
"ReactOS Version %d.%d %s Build %d",
202 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
203 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
205 len
= swprintf(buffer
,
206 L
"ReactOS %s (Build %d)",
207 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
214 IntParseDesktopPath(PEPROCESS Process
,
215 PUNICODE_STRING DesktopPath
,
219 OBJECT_ATTRIBUTES ObjectAttributes
;
220 UNICODE_STRING WinSta
, Desktop
, FullName
;
221 BOOL DesktopPresent
= FALSE
;
222 BOOL WinStaPresent
= FALSE
;
234 RtlInitUnicodeString(&WinSta
, NULL
);
235 RtlInitUnicodeString(&Desktop
, NULL
);
237 if(DesktopPath
!= NULL
&& DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
239 PWCHAR c
= DesktopPath
->Buffer
;
241 USHORT l
= DesktopPath
->Length
;
244 * Parse the desktop path string which can be in the form "WinSta\Desktop"
245 * or just "Desktop". In latter case WinSta0 will be used.
252 wl
= (ULONG_PTR
)c
- (ULONG_PTR
)DesktopPath
->Buffer
;
262 WinSta
.MaximumLength
= wl
+ sizeof(WCHAR
);
263 WinSta
.Buffer
= DesktopPath
->Buffer
;
265 WinStaPresent
= TRUE
;
269 Desktop
.Length
= DesktopPath
->Length
- wl
;
272 Desktop
.Length
-= sizeof(WCHAR
);
274 if(Desktop
.Length
> 0)
276 Desktop
.MaximumLength
= Desktop
.Length
+ sizeof(WCHAR
);
277 Desktop
.Buffer
= ((wl
> 0) ? c
: DesktopPath
->Buffer
);
278 DesktopPresent
= TRUE
;
285 /* search the process handle table for (inherited) window station
286 handles, use a more appropriate one than WinSta0 if possible. */
287 if (!ObFindHandleForObject(Process
,
289 ExWindowStationObjectType
,
294 /* we had no luck searching for opened handles, use WinSta0 now */
295 RtlInitUnicodeString(&WinSta
, L
"WinSta0");
299 if(!DesktopPresent
&& hDesktop
!= NULL
)
302 /* search the process handle table for (inherited) desktop
303 handles, use a more appropriate one than Default if possible. */
304 if (!ObFindHandleForObject(Process
,
311 /* we had no luck searching for opened handles, use Desktop now */
312 RtlInitUnicodeString(&Desktop
, L
"Default");
318 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, NULL
))
320 return STATUS_INSUFFICIENT_RESOURCES
;
323 /* open the window station */
324 InitializeObjectAttributes(&ObjectAttributes
,
326 OBJ_CASE_INSENSITIVE
,
330 Status
= ObOpenObjectByName(&ObjectAttributes
,
331 ExWindowStationObjectType
,
338 ExFreePoolWithTag(FullName
.Buffer
, TAG_STRING
);
340 if(!NT_SUCCESS(Status
))
342 SetLastNtError(Status
);
343 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta
, PsGetCurrentProcessId());
348 if(hDesktop
!= NULL
&& *hDesktop
== NULL
)
350 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, &Desktop
))
354 return STATUS_INSUFFICIENT_RESOURCES
;
357 /* open the desktop object */
358 InitializeObjectAttributes(&ObjectAttributes
,
360 OBJ_CASE_INSENSITIVE
,
364 Status
= ObOpenObjectByName(&ObjectAttributes
,
372 ExFreePoolWithTag(FullName
.Buffer
, TAG_STRING
);
374 if(!NT_SUCCESS(Status
))
379 SetLastNtError(Status
);
380 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop
, PsGetCurrentProcessId());
385 return STATUS_SUCCESS
;
389 * IntValidateDesktopHandle
391 * Validates the desktop handle.
394 * If the function succeeds, the handle remains referenced. If the
395 * fucntion fails, last error is set.
399 IntValidateDesktopHandle(
401 KPROCESSOR_MODE AccessMode
,
402 ACCESS_MASK DesiredAccess
,
407 Status
= ObReferenceObjectByHandle(
415 if (!NT_SUCCESS(Status
))
416 SetLastNtError(Status
);
422 IntGetDesktopWorkArea(PDESKTOP Desktop
, RECTL
*Rect
)
428 Ret
= &Desktop
->WorkArea
;
429 if((Ret
->right
== -1) && ScreenDeviceContext
)
433 dc
= DC_LockDc(ScreenDeviceContext
);
434 /* FIXME - Handle dc == NULL!!!! */
435 psurf
= dc
->dclevel
.pSurface
;
438 Ret
->right
= psurf
->SurfObj
.sizlBitmap
.cx
;
439 Ret
->bottom
= psurf
->SurfObj
.sizlBitmap
.cy
;
451 IntGetActiveDesktop(VOID
)
457 * returns or creates a handle to the desktop object
460 IntGetDesktopObjectHandle(PDESKTOP DesktopObject
)
465 ASSERT(DesktopObject
);
467 if (!ObFindHandleForObject(PsGetCurrentProcess(),
473 Status
= ObOpenObjectByPointer(DesktopObject
,
480 if(!NT_SUCCESS(Status
))
482 /* unable to create a handle */
483 DPRINT1("Unable to create a desktop handle\n");
489 DPRINT1("Got handle: %lx\n", Ret
);
495 PUSER_MESSAGE_QUEUE FASTCALL
496 IntGetFocusMessageQueue(VOID
)
498 PDESKTOP pdo
= IntGetActiveDesktop();
501 DPRINT("No active desktop\n");
504 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
508 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
510 PUSER_MESSAGE_QUEUE Old
;
511 PDESKTOP pdo
= IntGetActiveDesktop();
514 DPRINT("No active desktop\n");
519 if(NewQueue
->Desktop
!= NULL
)
521 DPRINT("Message Queue already attached to another desktop!\n");
524 IntReferenceMessageQueue(NewQueue
);
525 (void)InterlockedExchangePointer((PVOID
*)&NewQueue
->Desktop
, pdo
);
527 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchangePointer((PVOID
*)&pdo
->ActiveMessageQueue
, NewQueue
);
530 (void)InterlockedExchangePointer((PVOID
*)&Old
->Desktop
, 0);
531 IntDereferenceMessageQueue(Old
);
535 HWND FASTCALL
IntGetDesktopWindow(VOID
)
537 PDESKTOP pdo
= IntGetActiveDesktop();
540 DPRINT("No active desktop\n");
543 return pdo
->DesktopWindow
;
546 PWINDOW_OBJECT FASTCALL
UserGetDesktopWindow(VOID
)
548 PDESKTOP pdo
= IntGetActiveDesktop();
552 DPRINT("No active desktop\n");
556 return UserGetWindowObject(pdo
->DesktopWindow
);
560 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
562 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
563 PDESKTOP pdo
= pti
->Desktop
;
566 DPRINT1("Thread doesn't have a desktop\n");
569 return pdo
->DesktopWindow
;
572 BOOL FASTCALL
IntDesktopUpdatePerUserSettings(BOOL bEnable
)
576 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
579 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
581 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
582 QueryTable
[0].Name
= L
"PaintDesktopVersion";
583 QueryTable
[0].EntryContext
= &g_PaintDesktopVersion
;
585 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
586 Status
= RtlQueryRegistryValues(RTL_REGISTRY_USER
,
587 L
"Control Panel\\Desktop",
588 QueryTable
, NULL
, NULL
);
589 if (!NT_SUCCESS(Status
))
591 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
593 g_PaintDesktopVersion
= FALSE
;
597 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion
);
603 g_PaintDesktopVersion
= FALSE
;
608 /* PUBLIC FUNCTIONS ***********************************************************/
613 PWINDOW_OBJECT Window
= NULL
;
615 UserEnterExclusive();
617 Window
= UserGetDesktopWindow();
619 IntInvalidateWindows( Window
,
620 Window
->UpdateRegion
,
630 co_IntShowDesktop(PDESKTOP Desktop
, ULONG Width
, ULONG Height
)
632 CSR_API_MESSAGE Request
;
634 Request
.Type
= MAKE_CSR_API(SHOW_DESKTOP
, CSR_GUI
);
635 Request
.Data
.ShowDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
636 Request
.Data
.ShowDesktopRequest
.Width
= Width
;
637 Request
.Data
.ShowDesktopRequest
.Height
= Height
;
639 return co_CsrNotify(&Request
);
643 IntHideDesktop(PDESKTOP Desktop
)
646 CSRSS_API_REQUEST Request
;
647 CSRSS_API_REPLY Reply
;
649 Request
.Type
= CSRSS_HIDE_DESKTOP
;
650 Request
.Data
.HideDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
652 return NotifyCsrss(&Request
, &Reply
);
655 PWINDOW_OBJECT DesktopWindow
;
658 DesktopWindow
= IntGetWindowObject(Desktop
->DesktopWindow
);
661 return ERROR_INVALID_WINDOW_HANDLE
;
663 DesktopWnd
= DesktopWindow
->Wnd
;
664 DesktopWnd
->Style
&= ~WS_VISIBLE
;
666 return STATUS_SUCCESS
;
675 UserBuildShellHookHwndList(PDESKTOP Desktop
)
678 PSHELL_HOOK_WINDOW Current
;
681 /* fixme: if we save nb elements in desktop, we dont have to loop to find nb entries */
682 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
685 if (!entries
) return NULL
;
687 list
= ExAllocatePool(PagedPool
, sizeof(HWND
) * (entries
+ 1)); /* alloc one extra for nullterm */
692 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
693 *cursor
++ = Current
->hWnd
;
695 *cursor
= NULL
; /* nullterm list */
702 * Send the Message to the windows registered for ShellHook
703 * notifications. The lParam contents depend on the Message. See
704 * MSDN for more details (RegisterShellHookWindow)
706 VOID
co_IntShellHookNotify(WPARAM Message
, LPARAM lParam
)
708 PDESKTOP Desktop
= IntGetActiveDesktop();
711 static UINT MsgType
= 0;
716 /* Too bad, this doesn't work.*/
719 RtlInitUnicodeString(&Str
, L
"SHELLHOOK");
720 MsgType
= UserRegisterWindowMessage(&Str
);
723 MsgType
= IntAddAtom(L
"SHELLHOOK");
725 DPRINT("MsgType = %x\n", MsgType
);
727 DPRINT1("LastError: %x\n", GetLastNtError());
732 DPRINT("IntShellHookNotify: No desktop!\n");
736 HwndList
= UserBuildShellHookHwndList(Desktop
);
739 HWND
* cursor
= HwndList
;
741 for (; *cursor
; cursor
++)
743 DPRINT("Sending notify\n");
744 co_IntPostOrSendMessage(*cursor
,
750 ExFreePool(HwndList
);
756 * Add the window to the ShellHookWindows list. The windows
757 * on that list get notifications that are important to shell
760 * TODO: Validate the window? I'm not sure if sending these messages to
761 * an unsuspecting application that is not your own is a nice thing to do.
763 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
765 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
766 PDESKTOP Desktop
= pti
->Desktop
;
767 PSHELL_HOOK_WINDOW Entry
;
769 DPRINT("IntRegisterShellHookWindow\n");
771 /* First deregister the window, so we can be sure it's never twice in the
774 IntDeRegisterShellHookWindow(hWnd
);
776 Entry
= ExAllocatePoolWithTag(PagedPool
,
777 sizeof(SHELL_HOOK_WINDOW
),
785 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
791 * Remove the window from the ShellHookWindows list. The windows
792 * on that list get notifications that are important to shell
795 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
797 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
798 PDESKTOP Desktop
= pti
->Desktop
;
799 PSHELL_HOOK_WINDOW Current
;
801 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
803 if (Current
->hWnd
== hWnd
)
805 RemoveEntryList(&Current
->ListEntry
);
815 IntFreeDesktopHeap(IN OUT PDESKTOP Desktop
)
817 if (Desktop
->DesktopHeapSection
!= NULL
)
819 ObDereferenceObject(Desktop
->DesktopHeapSection
);
820 Desktop
->DesktopHeapSection
= NULL
;
823 /* SYSCALLS *******************************************************************/
827 * NtUserCreateDesktop
829 * Creates a new desktop.
833 * Name of the new desktop.
839 * Requested type of access.
842 * Security descriptor.
845 * Handle to window station on which to create the desktop.
848 * If the function succeeds, the return value is a handle to the newly
849 * created desktop. If the specified desktop already exists, the function
850 * succeeds and returns a handle to the existing desktop. When you are
851 * finished using the handle, call the CloseDesktop function to close it.
852 * If the function fails, the return value is NULL.
860 PUNICODE_STRING lpszDesktopName
,
862 ACCESS_MASK dwDesiredAccess
,
863 LPSECURITY_ATTRIBUTES lpSecurity
,
864 HWINSTA hWindowStation
)
866 OBJECT_ATTRIBUTES ObjectAttributes
;
867 PWINSTATION_OBJECT WinStaObject
;
868 PDESKTOP DesktopObject
;
869 UNICODE_STRING DesktopName
;
872 CSR_API_MESSAGE Request
;
873 PVOID DesktopHeapSystemBase
= NULL
;
874 SIZE_T DesktopInfoSize
;
875 UNICODE_STRING SafeDesktopName
;
877 ULONG_PTR HeapSize
= 4 * 1024 * 1024; /* FIXME */
878 DECLARE_RETURN(HDESK
);
881 DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName
);
882 UserEnterExclusive();
884 Status
= IntValidateWindowStationHandle(
887 0, /* FIXME - WINSTA_CREATEDESKTOP */
890 if (! NT_SUCCESS(Status
))
892 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
893 hWindowStation
, lpszDesktopName
);
894 SetLastNtError(Status
);
897 if(lpszDesktopName
!= NULL
)
899 Status
= IntSafeCopyUnicodeString(&SafeDesktopName
, lpszDesktopName
);
900 if(!NT_SUCCESS(Status
))
902 SetLastNtError(Status
);
908 RtlInitUnicodeString(&SafeDesktopName
, NULL
);
911 if (! IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
914 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
915 ObDereferenceObject(WinStaObject
);
917 ExFreePoolWithTag(SafeDesktopName
.Buffer
, TAG_STRING
);
921 ExFreePoolWithTag(SafeDesktopName
.Buffer
, TAG_STRING
);
922 ObDereferenceObject(WinStaObject
);
925 * Try to open already existing desktop
928 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName
);
930 /* Initialize ObjectAttributes for the desktop object */
931 InitializeObjectAttributes(
938 Status
= ObOpenObjectByName(
944 (PVOID
)&DummyContext
,
946 if (!NT_SUCCESS(Status
)) RETURN(NULL
);
947 if (Status
== STATUS_OBJECT_NAME_EXISTS
)
949 ExFreePoolWithTag(DesktopName
.Buffer
, TAG_STRING
);
953 /* Reference the desktop */
954 Status
= ObReferenceObjectByHandle(Desktop
,
958 (PVOID
)&DesktopObject
,
960 if (!NT_SUCCESS(Status
)) RETURN(NULL
);
962 DesktopObject
->DesktopHeapSection
= NULL
;
963 DesktopObject
->pheapDesktop
= UserCreateHeap(&DesktopObject
->DesktopHeapSection
,
964 &DesktopHeapSystemBase
,
966 if (DesktopObject
->pheapDesktop
== NULL
)
968 ObDereferenceObject(DesktopObject
);
969 DPRINT1("Failed to create desktop heap!\n");
973 DesktopInfoSize
= FIELD_OFFSET(DESKTOPINFO
,
974 szDesktopName
[(lpszDesktopName
->Length
/ sizeof(WCHAR
)) + 1]);
976 DesktopObject
->DesktopInfo
= RtlAllocateHeap(DesktopObject
->pheapDesktop
,
980 if (DesktopObject
->DesktopInfo
== NULL
)
982 ObDereferenceObject(DesktopObject
);
983 DPRINT1("Failed to create the DESKTOP structure!\n");
987 RtlZeroMemory(DesktopObject
->DesktopInfo
,
990 DesktopObject
->DesktopInfo
->pvDesktopBase
= DesktopHeapSystemBase
;
991 DesktopObject
->DesktopInfo
->pvDesktopLimit
= (PVOID
)((ULONG_PTR
)DesktopHeapSystemBase
+ HeapSize
);
992 RtlCopyMemory(DesktopObject
->DesktopInfo
->szDesktopName
,
993 lpszDesktopName
->Buffer
,
994 lpszDesktopName
->Length
);
997 DesktopObject
->WorkArea
.left
= 0;
998 DesktopObject
->WorkArea
.top
= 0;
999 DesktopObject
->WorkArea
.right
= -1;
1000 DesktopObject
->WorkArea
.bottom
= -1;
1001 IntGetDesktopWorkArea(DesktopObject
, NULL
);
1003 /* Initialize some local (to win32k) desktop state. */
1004 InitializeListHead(&DesktopObject
->PtiList
);
1005 DesktopObject
->ActiveMessageQueue
= NULL
;
1006 ExFreePoolWithTag(DesktopName
.Buffer
, TAG_STRING
);
1008 if (! NT_SUCCESS(Status
))
1010 DPRINT1("Failed to create desktop handle\n");
1011 SetLastNtError(Status
);
1016 * Create a handle for CSRSS and notify CSRSS
1018 Request
.Type
= MAKE_CSR_API(CREATE_DESKTOP
, CSR_GUI
);
1019 Status
= CsrInsertObject(Desktop
,
1021 (HANDLE
*)&Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
1022 if (! NT_SUCCESS(Status
))
1024 DPRINT1("Failed to create desktop handle for CSRSS\n");
1026 SetLastNtError(Status
);
1030 Status
= co_CsrNotify(&Request
);
1031 if (! NT_SUCCESS(Status
))
1033 CsrCloseHandle(Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
1034 DPRINT1("Failed to notify CSRSS about new desktop\n");
1036 SetLastNtError(Status
);
1043 DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_
);
1051 * Opens an existing desktop.
1055 * Name of the existing desktop.
1058 * Interaction flags.
1061 * Requested type of access.
1064 * Handle to the desktop or zero on failure.
1072 PUNICODE_STRING lpszDesktopName
,
1074 ACCESS_MASK dwDesiredAccess
)
1076 OBJECT_ATTRIBUTES ObjectAttributes
;
1078 PWINSTATION_OBJECT WinStaObject
;
1079 UNICODE_STRING DesktopName
;
1080 UNICODE_STRING SafeDesktopName
;
1084 DECLARE_RETURN(HDESK
);
1086 DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName
);
1087 UserEnterExclusive();
1090 * Validate the window station handle and compose the fully
1091 * qualified desktop name
1094 WinSta
= UserGetProcessWindowStation();
1095 Status
= IntValidateWindowStationHandle(
1101 if (!NT_SUCCESS(Status
))
1103 DPRINT1("Failed validation of window station handle (0x%X)\n", WinSta
);
1104 SetLastNtError(Status
);
1108 if(lpszDesktopName
!= NULL
)
1110 Status
= IntSafeCopyUnicodeString(&SafeDesktopName
, lpszDesktopName
);
1111 if(!NT_SUCCESS(Status
))
1113 SetLastNtError(Status
);
1119 RtlInitUnicodeString(&SafeDesktopName
, NULL
);
1122 Result
= IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
1125 if (lpszDesktopName
)
1126 ExFreePoolWithTag(SafeDesktopName
.Buffer
, TAG_STRING
);
1127 ObDereferenceObject(WinStaObject
);
1132 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
1137 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName
);
1139 /* Initialize ObjectAttributes for the desktop object */
1140 InitializeObjectAttributes(
1147 Status
= ObOpenObjectByName(
1149 ExDesktopObjectType
,
1156 if (!NT_SUCCESS(Status
))
1158 SetLastNtError(Status
);
1159 ExFreePool(DesktopName
.Buffer
);
1163 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
1164 ExFreePool(DesktopName
.Buffer
);
1169 DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_
);
1175 * NtUserOpenInputDesktop
1177 * Opens the input (interactive) desktop.
1181 * Interaction flags.
1184 * Inheritance option.
1187 * Requested type of access.
1190 * Handle to the input desktop or zero on failure.
1197 NtUserOpenInputDesktop(
1200 ACCESS_MASK dwDesiredAccess
)
1205 DECLARE_RETURN(HDESK
);
1207 DPRINT("Enter NtUserOpenInputDesktop\n");
1208 UserEnterExclusive();
1210 DPRINT("About to open input desktop\n");
1212 /* Get a pointer to the desktop object */
1214 Status
= IntValidateDesktopHandle(
1220 if (!NT_SUCCESS(Status
))
1222 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop
);
1226 /* Create a new handle to the object */
1228 Status
= ObOpenObjectByPointer(
1233 ExDesktopObjectType
,
1237 ObDereferenceObject(Object
);
1239 if (NT_SUCCESS(Status
))
1241 DPRINT("Successfully opened input desktop\n");
1242 RETURN((HDESK
)Desktop
);
1245 SetLastNtError(Status
);
1249 DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_
);
1255 * NtUserCloseDesktop
1257 * Closes a desktop handle.
1261 * Handle to the desktop.
1267 * The desktop handle can be created with NtUserCreateDesktop or
1268 * NtUserOpenDesktop. This function will fail if any thread in the calling
1269 * process is using the specified desktop handle or if the handle refers
1270 * to the initial desktop of the calling process.
1277 NtUserCloseDesktop(HDESK hDesktop
)
1281 DECLARE_RETURN(BOOL
);
1283 DPRINT("Enter NtUserCloseDesktop\n");
1284 UserEnterExclusive();
1286 DPRINT("About to close desktop handle (0x%X)\n", hDesktop
);
1288 Status
= IntValidateDesktopHandle(
1294 if (!NT_SUCCESS(Status
))
1296 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1300 ObDereferenceObject(Object
);
1302 DPRINT("Closing desktop handle (0x%X)\n", hDesktop
);
1304 Status
= ZwClose(hDesktop
);
1305 if (!NT_SUCCESS(Status
))
1307 SetLastNtError(Status
);
1314 DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_
);
1323 * NtUserPaintDesktop
1325 * The NtUserPaintDesktop function fills the clipping region in the
1326 * specified device context with the desktop pattern or wallpaper. The
1327 * function is provided primarily for shell desktops.
1331 * Handle to the device context.
1338 NtUserPaintDesktop(HDC hDC
)
1341 HBRUSH DesktopBrush
, PreviousBrush
;
1343 BOOL doPatBlt
= TRUE
;
1344 PWINDOW_OBJECT WndDesktop
;
1349 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1350 PWINSTATION_OBJECT WinSta
= pti
->Desktop
->WindowStation
;
1351 DECLARE_RETURN(BOOL
);
1353 UserEnterExclusive();
1354 DPRINT("Enter NtUserPaintDesktop\n");
1356 GdiGetClipBox(hDC
, &Rect
);
1358 hWndDesktop
= IntGetDesktopWindow();
1360 WndDesktop
= UserGetWindowObject(hWndDesktop
);
1366 DesktopBrush
= (HBRUSH
)UserGetClassLongPtr(WndDesktop
->Wnd
->Class
, GCL_HBRBACKGROUND
, FALSE
);
1370 * Paint desktop background
1373 if (WinSta
->hbmWallpaper
!= NULL
)
1375 PWINDOW_OBJECT DeskWin
;
1377 DeskWin
= UserGetWindowObject(hWndDesktop
);
1385 sz
.cx
= DeskWin
->Wnd
->WindowRect
.right
- DeskWin
->Wnd
->WindowRect
.left
;
1386 sz
.cy
= DeskWin
->Wnd
->WindowRect
.bottom
- DeskWin
->Wnd
->WindowRect
.top
;
1388 if (WinSta
->WallpaperMode
== wmStretch
||
1389 WinSta
->WallpaperMode
== wmTile
)
1396 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
1397 x
= (sz
.cx
/ 2) - (WinSta
->cxWallpaper
/ 2);
1398 y
= (sz
.cy
/ 2) - (WinSta
->cyWallpaper
/ 2);
1401 hWallpaperDC
= NtGdiCreateCompatibleDC(hDC
);
1402 if(hWallpaperDC
!= NULL
)
1406 /* fill in the area that the bitmap is not going to cover */
1409 /* FIXME - clip out the bitmap
1410 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1411 once we support DSTINVERT */
1412 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1413 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1414 NtGdiSelectBrush(hDC
, PreviousBrush
);
1417 /*Do not fill the background after it is painted no matter the size of the picture */
1420 hOldBitmap
= NtGdiSelectBitmap(hWallpaperDC
, WinSta
->hbmWallpaper
);
1422 if (WinSta
->WallpaperMode
== wmStretch
)
1424 if(Rect
.right
&& Rect
.bottom
)
1425 NtGdiStretchBlt(hDC
,
1433 WinSta
->cxWallpaper
,
1434 WinSta
->cyWallpaper
,
1439 else if (WinSta
->WallpaperMode
== wmTile
)
1441 /* paint the bitmap across the screen then down */
1442 for(y
= 0; y
< Rect
.bottom
; y
+= WinSta
->cyWallpaper
)
1444 for(x
= 0; x
< Rect
.right
; x
+= WinSta
->cxWallpaper
)
1449 WinSta
->cxWallpaper
,
1450 WinSta
->cyWallpaper
,
1465 WinSta
->cxWallpaper
,
1466 WinSta
->cyWallpaper
,
1474 NtGdiSelectBitmap(hWallpaperDC
, hOldBitmap
);
1475 NtGdiDeleteObjectApp(hWallpaperDC
);
1480 /* Back ground is set to none, clear the screen */
1483 PreviousBrush
= NtGdiSelectBrush(hDC
, DesktopBrush
);
1484 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1485 NtGdiSelectBrush(hDC
, PreviousBrush
);
1489 * Display system version on the desktop background
1492 if (g_PaintDesktopVersion
)
1494 static WCHAR s_wszVersion
[256] = {0};
1499 len
= wcslen(s_wszVersion
);
1503 len
= GetSystemVersionString(s_wszVersion
);
1508 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
1510 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1511 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1514 color_old
= IntGdiSetTextColor(hDC
, RGB(255,255,255));
1515 align_old
= IntGdiSetTextAlign(hDC
, TA_RIGHT
);
1516 mode_old
= IntGdiSetBkMode(hDC
, TRANSPARENT
);
1518 GreExtTextOutW(hDC
, rect
.right
-16, rect
.bottom
-48, 0, NULL
, s_wszVersion
, len
, NULL
, 0);
1520 IntGdiSetBkMode(hDC
, mode_old
);
1521 IntGdiSetTextAlign(hDC
, align_old
);
1522 IntGdiSetTextColor(hDC
, color_old
);
1529 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_
);
1536 * NtUserSwitchDesktop
1538 * Sets the current input (interactive) desktop.
1542 * Handle to desktop.
1552 NtUserSwitchDesktop(HDESK hDesktop
)
1554 PDESKTOP DesktopObject
;
1556 DECLARE_RETURN(BOOL
);
1558 UserEnterExclusive();
1559 DPRINT("Enter NtUserSwitchDesktop\n");
1561 DPRINT("About to switch desktop (0x%X)\n", hDesktop
);
1563 Status
= IntValidateDesktopHandle(
1569 if (!NT_SUCCESS(Status
))
1571 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1576 * Don't allow applications switch the desktop if it's locked, unless the caller
1577 * is the logon application itself
1579 if((DesktopObject
->WindowStation
->Flags
& WSS_LOCKED
) &&
1580 LogonProcess
!= NULL
&& LogonProcess
!= PsGetCurrentProcessWin32Process())
1582 ObDereferenceObject(DesktopObject
);
1583 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop
);
1587 /* FIXME: Fail if the desktop belong to an invisible window station */
1588 /* FIXME: Fail if the process is associated with a secured
1589 desktop such as Winlogon or Screen-Saver */
1590 /* FIXME: Connect to input device */
1592 /* Set the active desktop in the desktop's window station. */
1593 DesktopObject
->WindowStation
->ActiveDesktop
= DesktopObject
;
1595 /* Set the global state. */
1596 InputDesktop
= DesktopObject
;
1597 InputDesktopHandle
= hDesktop
;
1598 InputWindowStation
= DesktopObject
->WindowStation
;
1600 ObDereferenceObject(DesktopObject
);
1605 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_
);
1611 * NtUserResolveDesktopForWOW
1618 NtUserResolveDesktopForWOW(DWORD Unknown0
)
1625 * NtUserGetThreadDesktop
1632 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1636 PDESKTOP DesktopObject
;
1637 HDESK Ret
, hThreadDesktop
;
1638 OBJECT_HANDLE_INFORMATION HandleInformation
;
1639 DECLARE_RETURN(HDESK
);
1641 UserEnterExclusive();
1642 DPRINT("Enter NtUserGetThreadDesktop\n");
1646 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1650 Status
= PsLookupThreadByThreadId((HANDLE
)(DWORD_PTR
)dwThreadId
, &Thread
);
1651 if(!NT_SUCCESS(Status
))
1653 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1657 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1659 /* just return the handle, we queried the desktop handle of a thread running
1660 in the same context */
1661 Ret
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hDesktop
;
1662 ObDereferenceObject(Thread
);
1666 /* get the desktop handle and the desktop of the thread */
1667 if(!(hThreadDesktop
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->hDesktop
) ||
1668 !(DesktopObject
= ((PTHREADINFO
)Thread
->Tcb
.Win32Thread
)->Desktop
))
1670 ObDereferenceObject(Thread
);
1671 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1675 /* we could just use DesktopObject instead of looking up the handle, but latter
1676 may be a bit safer (e.g. when the desktop is being destroyed */
1677 /* switch into the context of the thread we're trying to get the desktop from,
1678 so we can use the handle */
1679 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1680 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1682 ExDesktopObjectType
,
1684 (PVOID
*)&DesktopObject
,
1685 &HandleInformation
);
1688 /* the handle couldn't be found, there's nothing to get... */
1689 if(!NT_SUCCESS(Status
))
1691 ObDereferenceObject(Thread
);
1695 /* lookup our handle table if we can find a handle to the desktop object,
1696 if not, create one */
1697 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1699 /* all done, we got a valid handle to the desktop */
1700 ObDereferenceObject(DesktopObject
);
1701 ObDereferenceObject(Thread
);
1705 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_
);
1711 IntUnmapDesktopView(IN PDESKTOP DesktopObject
)
1714 PW32PROCESS CurrentWin32Process
;
1715 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1716 NTSTATUS Status
= STATUS_SUCCESS
;
1720 CurrentWin32Process
= PsGetCurrentProcessWin32Process();
1721 PrevLink
= &CurrentWin32Process
->HeapMappings
.Next
;
1723 /* unmap if we're the last thread using the desktop */
1724 HeapMapping
= *PrevLink
;
1725 while (HeapMapping
!= NULL
)
1727 if (HeapMapping
->KernelMapping
== (PVOID
)DesktopObject
->pheapDesktop
)
1729 if (--HeapMapping
->Count
== 0)
1731 *PrevLink
= HeapMapping
->Next
;
1733 Status
= MmUnmapViewOfSection(PsGetCurrentProcess(),
1734 HeapMapping
->UserMapping
);
1736 ObDereferenceObject(DesktopObject
);
1738 UserHeapFree(HeapMapping
);
1743 PrevLink
= &HeapMapping
->Next
;
1744 HeapMapping
= HeapMapping
->Next
;
1747 ti
= GetW32ThreadInfo();
1750 if (ti
->pDeskInfo
== DesktopObject
->DesktopInfo
)
1752 ti
->pDeskInfo
= NULL
;
1754 GetWin32ClientInfo()->pDeskInfo
= NULL
;
1756 GetWin32ClientInfo()->ulClientDelta
= 0;
1762 IntMapDesktopView(IN PDESKTOP DesktopObject
)
1765 PW32PROCESS CurrentWin32Process
;
1766 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
;
1767 PVOID UserBase
= NULL
;
1768 SIZE_T ViewSize
= 0;
1769 LARGE_INTEGER Offset
;
1772 CurrentWin32Process
= PsGetCurrentProcessWin32Process();
1773 PrevLink
= &CurrentWin32Process
->HeapMappings
.Next
;
1775 /* find out if another thread already mapped the desktop heap */
1776 HeapMapping
= *PrevLink
;
1777 while (HeapMapping
!= NULL
)
1779 if (HeapMapping
->KernelMapping
== (PVOID
)DesktopObject
->pheapDesktop
)
1781 HeapMapping
->Count
++;
1782 return STATUS_SUCCESS
;
1785 PrevLink
= &HeapMapping
->Next
;
1786 HeapMapping
= HeapMapping
->Next
;
1789 /* we're the first, map the heap */
1790 DPRINT("Noone mapped the desktop heap %p yet, so - map it!\n", DesktopObject
->pheapDesktop
);
1791 Offset
.QuadPart
= 0;
1792 Status
= MmMapViewOfSection(DesktopObject
->DesktopHeapSection
,
1793 PsGetCurrentProcess(),
1801 PAGE_EXECUTE_READ
); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
1802 if (!NT_SUCCESS(Status
))
1804 DPRINT1("Failed to map desktop\n");
1808 /* add the mapping */
1809 HeapMapping
= UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING
));
1810 if (HeapMapping
== NULL
)
1812 MmUnmapViewOfSection(PsGetCurrentProcess(),
1814 DPRINT1("UserHeapAlloc() failed!\n");
1815 return STATUS_NO_MEMORY
;
1818 HeapMapping
->Next
= NULL
;
1819 HeapMapping
->KernelMapping
= (PVOID
)DesktopObject
->pheapDesktop
;
1820 HeapMapping
->UserMapping
= UserBase
;
1821 HeapMapping
->Limit
= ViewSize
;
1822 HeapMapping
->Count
= 1;
1823 *PrevLink
= HeapMapping
;
1825 ObReferenceObject(DesktopObject
);
1827 /* create a W32THREADINFO structure if not already done, or update it */
1828 ti
= GetW32ThreadInfo();
1829 GetWin32ClientInfo()->ulClientDelta
= DesktopHeapGetUserDelta();
1832 if (ti
->pDeskInfo
== NULL
)
1834 ti
->pDeskInfo
= DesktopObject
->DesktopInfo
;
1835 GetWin32ClientInfo()->pDeskInfo
=
1836 (PVOID
)((ULONG_PTR
)ti
->pDeskInfo
- GetWin32ClientInfo()->ulClientDelta
);
1840 return STATUS_SUCCESS
;
1844 IntSetThreadDesktop(IN PDESKTOP DesktopObject
,
1845 IN BOOL FreeOnFailure
)
1847 PDESKTOP OldDesktop
;
1848 PTHREADINFO W32Thread
;
1852 DPRINT("IntSetThreadDesktop() DO=%p, FOF=%d\n", DesktopObject
, FreeOnFailure
);
1853 MapHeap
= (PsGetCurrentProcess() != PsInitialSystemProcess
);
1854 W32Thread
= PsGetCurrentThreadWin32Thread();
1856 if (W32Thread
->Desktop
!= DesktopObject
)
1858 OldDesktop
= W32Thread
->Desktop
;
1860 if (!IsListEmpty(&W32Thread
->WindowListHead
))
1862 DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
1863 SetLastWin32Error(ERROR_BUSY
);
1867 W32Thread
->Desktop
= DesktopObject
;
1869 if (MapHeap
&& DesktopObject
!= NULL
)
1871 Status
= IntMapDesktopView(DesktopObject
);
1872 if (!NT_SUCCESS(Status
))
1874 SetLastNtError(Status
);
1879 if (W32Thread
->Desktop
== NULL
)
1881 PW32THREADINFO ti
= GetW32ThreadInfo();
1884 ti
->pDeskInfo
= NULL
;
1888 /* Hack for system threads */
1891 PCLIENTINFO pci
= GetWin32ClientInfo();
1892 pci
->ulClientDelta
= DesktopHeapGetUserDelta();
1895 pci
->pDeskInfo
= (PVOID
)((ULONG_PTR
)DesktopObject
->DesktopInfo
- pci
->ulClientDelta
);
1899 if (OldDesktop
!= NULL
&&
1900 !IntCheckProcessDesktopClasses(OldDesktop
,
1903 DPRINT1("Failed to move process classes to shared heap!\n");
1905 /* failed to move desktop classes to the shared heap,
1906 unmap the view and return the error */
1907 if (MapHeap
&& DesktopObject
!= NULL
)
1908 IntUnmapDesktopView(DesktopObject
);
1913 /* Remove the thread from the old desktop's list */
1914 RemoveEntryList(&W32Thread
->PtiLink
);
1916 if (DesktopObject
!= NULL
)
1918 ObReferenceObject(DesktopObject
);
1919 /* Insert into new desktop's list */
1920 InsertTailList(&DesktopObject
->PtiList
, &W32Thread
->PtiLink
);
1923 if (OldDesktop
!= NULL
)
1927 IntUnmapDesktopView(OldDesktop
);
1930 ObDereferenceObject(OldDesktop
);
1938 * NtUserSetThreadDesktop
1945 NtUserSetThreadDesktop(HDESK hDesktop
)
1947 PDESKTOP DesktopObject
;
1949 DECLARE_RETURN(BOOL
);
1951 UserEnterExclusive();
1952 DPRINT("Enter NtUserSetThreadDesktop\n");
1954 /* Validate the new desktop. */
1955 Status
= IntValidateDesktopHandle(
1961 if (!NT_SUCCESS(Status
))
1963 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1967 /* FIXME: Should check here to see if the thread has any windows. */
1969 if (!IntSetThreadDesktop(DesktopObject
,
1978 DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_
);