2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
24 * FILE: subsys/win32k/ntuser/desktop.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
30 /* INCLUDES ******************************************************************/
35 #include <wine/debug.h>
40 IN OUT PDESKTOP_OBJECT Desktop
43 /* GLOBALS *******************************************************************/
45 /* Currently active desktop */
46 PDESKTOP_OBJECT InputDesktop
= NULL
;
47 HDESK InputDesktopHandle
= NULL
;
48 HDC ScreenDeviceContext
= NULL
;
49 BOOL g_PaintDesktopVersion
= FALSE
;
51 GENERIC_MAPPING IntDesktopMapping
=
53 STANDARD_RIGHTS_READ
| DESKTOP_ENUMERATE
|
55 STANDARD_RIGHTS_WRITE
| DESKTOP_CREATEMENU
|
56 DESKTOP_CREATEWINDOW
|
58 DESKTOP_JOURNALPLAYBACK
|
59 DESKTOP_JOURNALRECORD
|
61 STANDARD_RIGHTS_EXECUTE
| DESKTOP_SWITCHDESKTOP
,
62 STANDARD_RIGHTS_REQUIRED
| DESKTOP_CREATEMENU
|
63 DESKTOP_CREATEWINDOW
|
66 DESKTOP_JOURNALPLAYBACK
|
67 DESKTOP_JOURNALRECORD
|
69 DESKTOP_SWITCHDESKTOP
|
73 /* OBJECT CALLBACKS **********************************************************/
77 IntDesktopObjectParse(IN PVOID ParseObject
,
79 IN OUT PACCESS_STATE AccessState
,
80 IN KPROCESSOR_MODE AccessMode
,
82 IN OUT PUNICODE_STRING CompleteName
,
83 IN OUT PUNICODE_STRING RemainingName
,
84 IN OUT PVOID Context OPTIONAL
,
85 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
89 PDESKTOP_OBJECT Desktop
;
90 OBJECT_ATTRIBUTES ObjectAttributes
;
91 PLIST_ENTRY NextEntry
, ListHead
;
92 PWINSTATION_OBJECT WinStaObject
= (PWINSTATION_OBJECT
)ParseObject
;
93 PUNICODE_STRING DesktopName
;
95 /* Set the list pointers and loop the window station */
96 ListHead
= &WinStaObject
->DesktopListHead
;
97 NextEntry
= ListHead
->Flink
;
98 while (NextEntry
!= ListHead
)
100 /* Get the current desktop */
101 Desktop
= CONTAINING_RECORD(NextEntry
, DESKTOP_OBJECT
, ListEntry
);
104 DesktopName
= GET_DESKTOP_NAME(Desktop
);
107 /* Compare the name */
108 if (RtlEqualUnicodeString(RemainingName
,
110 (Attributes
& OBJ_CASE_INSENSITIVE
)))
112 /* We found a match. Did this come from a create? */
115 /* Unless OPEN_IF was given, fail with an error */
116 if (!(Attributes
& OBJ_OPENIF
))
119 return STATUS_OBJECT_NAME_COLLISION
;
123 /* Otherwise, return with a warning only */
124 Status
= STATUS_OBJECT_NAME_EXISTS
;
129 /* This was a real open, so this is OK */
130 Status
= STATUS_SUCCESS
;
133 /* Reference the desktop and return it */
134 ObReferenceObject(Desktop
);
140 /* Go to the next desktop */
141 NextEntry
= NextEntry
->Flink
;
144 /* If we got here but this isn't a create, then fail */
145 if (!Context
) return STATUS_OBJECT_NAME_NOT_FOUND
;
147 /* Create the desktop object */
148 InitializeObjectAttributes(&ObjectAttributes
, RemainingName
, 0, NULL
, NULL
);
149 Status
= ObCreateObject(KernelMode
,
154 sizeof(DESKTOP_OBJECT
),
158 if (!NT_SUCCESS(Status
)) return Status
;
160 /* Initialize shell hook window list and set the parent */
161 InitializeListHead(&Desktop
->ShellHookWindows
);
162 Desktop
->WindowStation
= (PWINSTATION_OBJECT
)ParseObject
;
164 /* Put the desktop on the window station's list of associated desktops */
165 InsertTailList(&Desktop
->WindowStation
->DesktopListHead
,
166 &Desktop
->ListEntry
);
168 /* Set the desktop object and return success */
170 return STATUS_SUCCESS
;
174 IntDesktopObjectDelete(PWIN32_DELETEMETHOD_PARAMETERS Parameters
)
176 PDESKTOP_OBJECT Desktop
= (PDESKTOP_OBJECT
)Parameters
->Object
;
178 DPRINT("Deleting desktop (0x%X)\n", Desktop
);
180 /* Remove the desktop from the window station's list of associcated desktops */
181 RemoveEntryList(&Desktop
->ListEntry
);
183 IntFreeDesktopHeap(Desktop
);
186 /* PRIVATE FUNCTIONS **********************************************************/
190 InitDesktopImpl(VOID
)
192 /* Set Desktop Object Attributes */
193 ExDesktopObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(DESKTOP_OBJECT
);
194 ExDesktopObjectType
->TypeInfo
.GenericMapping
= IntDesktopMapping
;
195 return STATUS_SUCCESS
;
200 CleanupDesktopImpl(VOID
)
202 return STATUS_SUCCESS
;
205 static int GetSystemVersionString(LPWSTR buffer
)
207 RTL_OSVERSIONINFOEXW versionInfo
;
210 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
212 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
215 if (versionInfo
.dwMajorVersion
<= 4)
216 len
= swprintf(buffer
,
217 L
"ReactOS Version %d.%d %s Build %d",
218 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
219 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
221 len
= swprintf(buffer
,
222 L
"ReactOS %s (Build %d)",
223 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
230 IntParseDesktopPath(PEPROCESS Process
,
231 PUNICODE_STRING DesktopPath
,
235 OBJECT_ATTRIBUTES ObjectAttributes
;
236 UNICODE_STRING WinSta
, Desktop
, FullName
;
237 BOOL DesktopPresent
= FALSE
;
238 BOOL WinStaPresent
= FALSE
;
250 RtlInitUnicodeString(&WinSta
, NULL
);
251 RtlInitUnicodeString(&Desktop
, NULL
);
253 if(DesktopPath
!= NULL
&& DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
255 PWCHAR c
= DesktopPath
->Buffer
;
257 USHORT l
= DesktopPath
->Length
;
260 * Parse the desktop path string which can be in the form "WinSta\Desktop"
261 * or just "Desktop". In latter case WinSta0 will be used.
268 wl
= (ULONG_PTR
)c
- (ULONG_PTR
)DesktopPath
->Buffer
;
278 WinSta
.MaximumLength
= wl
+ sizeof(WCHAR
);
279 WinSta
.Buffer
= DesktopPath
->Buffer
;
281 WinStaPresent
= TRUE
;
285 Desktop
.Length
= DesktopPath
->Length
- wl
;
288 Desktop
.Length
-= sizeof(WCHAR
);
290 if(Desktop
.Length
> 0)
292 Desktop
.MaximumLength
= Desktop
.Length
+ sizeof(WCHAR
);
293 Desktop
.Buffer
= ((wl
> 0) ? c
: DesktopPath
->Buffer
);
294 DesktopPresent
= TRUE
;
301 /* search the process handle table for (inherited) window station
302 handles, use a more appropriate one than WinSta0 if possible. */
303 if (!ObFindHandleForObject(Process
,
305 ExWindowStationObjectType
,
310 /* we had no luck searching for opened handles, use WinSta0 now */
311 RtlInitUnicodeString(&WinSta
, L
"WinSta0");
315 if(!DesktopPresent
&& hDesktop
!= NULL
)
318 /* search the process handle table for (inherited) desktop
319 handles, use a more appropriate one than Default if possible. */
320 if (!ObFindHandleForObject(Process
,
327 /* we had no luck searching for opened handles, use Desktop now */
328 RtlInitUnicodeString(&Desktop
, L
"Default");
334 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, NULL
))
336 return STATUS_INSUFFICIENT_RESOURCES
;
339 /* open the window station */
340 InitializeObjectAttributes(&ObjectAttributes
,
342 OBJ_CASE_INSENSITIVE
,
346 Status
= ObOpenObjectByName(&ObjectAttributes
,
347 ExWindowStationObjectType
,
354 RtlFreeUnicodeString(&FullName
);
356 if(!NT_SUCCESS(Status
))
358 SetLastNtError(Status
);
359 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta
, PsGetCurrentProcessId());
364 if(hDesktop
!= NULL
&& *hDesktop
== NULL
)
366 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, &Desktop
))
370 return STATUS_INSUFFICIENT_RESOURCES
;
373 /* open the desktop object */
374 InitializeObjectAttributes(&ObjectAttributes
,
376 OBJ_CASE_INSENSITIVE
,
380 Status
= ObOpenObjectByName(&ObjectAttributes
,
388 RtlFreeUnicodeString(&FullName
);
390 if(!NT_SUCCESS(Status
))
395 SetLastNtError(Status
);
396 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop
, PsGetCurrentProcessId());
401 return STATUS_SUCCESS
;
405 * IntValidateDesktopHandle
407 * Validates the desktop handle.
410 * If the function succeeds, the handle remains referenced. If the
411 * fucntion fails, last error is set.
415 IntValidateDesktopHandle(
417 KPROCESSOR_MODE AccessMode
,
418 ACCESS_MASK DesiredAccess
,
419 PDESKTOP_OBJECT
*Object
)
423 Status
= ObReferenceObjectByHandle(
431 if (!NT_SUCCESS(Status
))
432 SetLastNtError(Status
);
438 IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop
, PRECT Rect
)
444 Ret
= &Desktop
->WorkArea
;
445 if((Ret
->right
== -1) && ScreenDeviceContext
)
448 BITMAPOBJ
*BitmapObj
;
449 dc
= DC_LockDc(ScreenDeviceContext
);
450 /* FIXME - Handle dc == NULL!!!! */
451 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
454 Ret
->right
= BitmapObj
->SurfObj
.sizlBitmap
.cx
;
455 Ret
->bottom
= BitmapObj
->SurfObj
.sizlBitmap
.cy
;
456 BITMAPOBJ_UnlockBitmap(BitmapObj
);
467 PDESKTOP_OBJECT FASTCALL
468 IntGetActiveDesktop(VOID
)
474 * returns or creates a handle to the desktop object
477 IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject
)
482 ASSERT(DesktopObject
);
484 if (!ObFindHandleForObject(PsGetCurrentProcess(),
490 Status
= ObOpenObjectByPointer(DesktopObject
,
497 if(!NT_SUCCESS(Status
))
499 /* unable to create a handle */
500 DPRINT1("Unable to create a desktop handle\n");
506 DPRINT1("Got handle: %lx\n", Ret
);
512 PUSER_MESSAGE_QUEUE FASTCALL
513 IntGetFocusMessageQueue(VOID
)
515 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
518 DPRINT("No active desktop\n");
521 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
525 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
527 PUSER_MESSAGE_QUEUE Old
;
528 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
531 DPRINT("No active desktop\n");
536 if(NewQueue
->Desktop
!= NULL
)
538 DPRINT("Message Queue already attached to another desktop!\n");
541 IntReferenceMessageQueue(NewQueue
);
542 InterlockedExchange((LONG
*)&NewQueue
->Desktop
, (LONG
)pdo
);
544 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchange((LONG
*)&pdo
->ActiveMessageQueue
, (LONG
)NewQueue
);
547 InterlockedExchange((LONG
*)&Old
->Desktop
, 0);
548 IntDereferenceMessageQueue(Old
);
552 HWND FASTCALL
IntGetDesktopWindow(VOID
)
554 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
557 DPRINT("No active desktop\n");
560 return pdo
->DesktopWindow
;
563 PWINDOW_OBJECT FASTCALL
UserGetDesktopWindow(VOID
)
565 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
569 DPRINT("No active desktop\n");
573 return UserGetWindowObject(pdo
->DesktopWindow
);
577 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
579 PDESKTOP_OBJECT pdo
= PsGetCurrentThreadWin32Thread()->Desktop
;
582 DPRINT1("Thread doesn't have a desktop\n");
585 return pdo
->DesktopWindow
;
588 BOOL FASTCALL
IntDesktopUpdatePerUserSettings(BOOL bEnable
)
592 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
595 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
597 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
598 QueryTable
[0].Name
= L
"PaintDesktopVersion";
599 QueryTable
[0].EntryContext
= &g_PaintDesktopVersion
;
601 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
602 Status
= RtlQueryRegistryValues(RTL_REGISTRY_USER
,
603 L
"Control Panel\\Desktop",
604 QueryTable
, NULL
, NULL
);
605 if (!NT_SUCCESS(Status
))
607 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
609 g_PaintDesktopVersion
= FALSE
;
613 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion
);
619 g_PaintDesktopVersion
= FALSE
;
624 /* PUBLIC FUNCTIONS ***********************************************************/
627 co_IntShowDesktop(PDESKTOP_OBJECT Desktop
, ULONG Width
, ULONG Height
)
629 CSR_API_MESSAGE Request
;
631 Request
.Type
= MAKE_CSR_API(SHOW_DESKTOP
, CSR_GUI
);
632 Request
.Data
.ShowDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
633 Request
.Data
.ShowDesktopRequest
.Width
= Width
;
634 Request
.Data
.ShowDesktopRequest
.Height
= Height
;
636 return co_CsrNotify(&Request
);
640 IntHideDesktop(PDESKTOP_OBJECT Desktop
)
643 CSRSS_API_REQUEST Request
;
644 CSRSS_API_REPLY Reply
;
646 Request
.Type
= CSRSS_HIDE_DESKTOP
;
647 Request
.Data
.HideDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
649 return NotifyCsrss(&Request
, &Reply
);
652 PWINDOW_OBJECT DesktopWindow
;
654 DesktopWindow
= IntGetWindowObject(Desktop
->DesktopWindow
);
657 return ERROR_INVALID_WINDOW_HANDLE
;
659 DesktopWindow
->Style
&= ~WS_VISIBLE
;
661 return STATUS_SUCCESS
;
670 UserBuildShellHookHwndList(PDESKTOP_OBJECT Desktop
)
673 PSHELL_HOOK_WINDOW Current
;
676 /* fixme: if we save nb elements in desktop, we dont have to loop to find nb entries */
677 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
680 if (!entries
) return NULL
;
682 list
= ExAllocatePool(PagedPool
, sizeof(HWND
) * (entries
+ 1)); /* alloc one extra for nullterm */
687 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
688 *cursor
++ = Current
->hWnd
;
690 *cursor
= NULL
; /* nullterm list */
697 * Send the Message to the windows registered for ShellHook
698 * notifications. The lParam contents depend on the Message. See
699 * MSDN for more details (RegisterShellHookWindow)
701 VOID
co_IntShellHookNotify(WPARAM Message
, LPARAM lParam
)
703 PDESKTOP_OBJECT Desktop
= IntGetActiveDesktop();
706 static UINT MsgType
= 0;
711 /* Too bad, this doesn't work.*/
714 RtlInitUnicodeString(&Str
, L
"SHELLHOOK");
715 MsgType
= UserRegisterWindowMessage(&Str
);
718 MsgType
= IntAddAtom(L
"SHELLHOOK");
720 DPRINT("MsgType = %x\n", MsgType
);
722 DPRINT1("LastError: %x\n", GetLastNtError());
727 DPRINT("IntShellHookNotify: No desktop!\n");
731 HwndList
= UserBuildShellHookHwndList(Desktop
);
734 HWND
* cursor
= HwndList
;
736 for (; *cursor
; cursor
++)
738 DPRINT("Sending notify\n");
739 co_IntPostOrSendMessage(*cursor
,
745 ExFreePool(HwndList
);
751 * Add the window to the ShellHookWindows list. The windows
752 * on that list get notifications that are important to shell
755 * TODO: Validate the window? I'm not sure if sending these messages to
756 * an unsuspecting application that is not your own is a nice thing to do.
758 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
760 PDESKTOP_OBJECT Desktop
= PsGetCurrentThreadWin32Thread()->Desktop
;
761 PSHELL_HOOK_WINDOW Entry
;
763 DPRINT("IntRegisterShellHookWindow\n");
765 /* First deregister the window, so we can be sure it's never twice in the
768 IntDeRegisterShellHookWindow(hWnd
);
770 Entry
= ExAllocatePoolWithTag(PagedPool
,
771 sizeof(SHELL_HOOK_WINDOW
),
779 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
785 * Remove the window from the ShellHookWindows list. The windows
786 * on that list get notifications that are important to shell
789 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
791 PDESKTOP_OBJECT Desktop
= PsGetCurrentThreadWin32Thread()->Desktop
;
792 PSHELL_HOOK_WINDOW Current
;
794 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
796 if (Current
->hWnd
== hWnd
)
798 RemoveEntryList(&Current
->ListEntry
);
808 IntFreeDesktopHeap(IN OUT PDESKTOP_OBJECT Desktop
)
810 if (Desktop
->DesktopHeapSection
!= NULL
)
812 ObDereferenceObject(Desktop
->DesktopHeapSection
);
813 Desktop
->DesktopHeapSection
= NULL
;
816 /* SYSCALLS *******************************************************************/
820 * NtUserCreateDesktop
822 * Creates a new desktop.
826 * Name of the new desktop.
832 * Requested type of access.
835 * Security descriptor.
838 * Handle to window station on which to create the desktop.
841 * If the function succeeds, the return value is a handle to the newly
842 * created desktop. If the specified desktop already exists, the function
843 * succeeds and returns a handle to the existing desktop. When you are
844 * finished using the handle, call the CloseDesktop function to close it.
845 * If the function fails, the return value is NULL.
853 PUNICODE_STRING lpszDesktopName
,
855 ACCESS_MASK dwDesiredAccess
,
856 LPSECURITY_ATTRIBUTES lpSecurity
,
857 HWINSTA hWindowStation
)
859 OBJECT_ATTRIBUTES ObjectAttributes
;
860 PWINSTATION_OBJECT WinStaObject
;
861 PDESKTOP_OBJECT DesktopObject
;
862 UNICODE_STRING DesktopName
;
865 CSR_API_MESSAGE Request
;
866 PVOID DesktopHeapSystemBase
= NULL
;
867 SIZE_T DesktopInfoSize
;
868 UNICODE_STRING SafeDesktopName
;
870 DECLARE_RETURN(HDESK
);
873 DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName
);
874 UserEnterExclusive();
876 Status
= IntValidateWindowStationHandle(
879 0, /* FIXME - WINSTA_CREATEDESKTOP */
882 if (! NT_SUCCESS(Status
))
884 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
885 hWindowStation
, lpszDesktopName
);
886 SetLastNtError(Status
);
889 if(lpszDesktopName
!= NULL
)
891 Status
= IntSafeCopyUnicodeString(&SafeDesktopName
, lpszDesktopName
);
892 if(!NT_SUCCESS(Status
))
894 SetLastNtError(Status
);
900 RtlInitUnicodeString(&SafeDesktopName
, NULL
);
903 if (! IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
906 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
907 ObDereferenceObject(WinStaObject
);
908 RtlFreeUnicodeString(&SafeDesktopName
);
911 RtlFreeUnicodeString(&SafeDesktopName
);
912 ObDereferenceObject(WinStaObject
);
915 * Try to open already existing desktop
918 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName
);
920 /* Initialize ObjectAttributes for the desktop object */
921 InitializeObjectAttributes(
928 Status
= ObOpenObjectByName(
934 (PVOID
)&DummyContext
,
936 if (!NT_SUCCESS(Status
)) RETURN(NULL
);
937 if (Status
== STATUS_OBJECT_NAME_EXISTS
)
939 ExFreePool(DesktopName
.Buffer
);
943 /* Reference the desktop */
944 Status
= ObReferenceObjectByHandle(Desktop
,
948 (PVOID
)&DesktopObject
,
950 if (!NT_SUCCESS(Status
)) RETURN(NULL
);
952 DesktopObject
->DesktopHeapSection
= NULL
;
953 DesktopObject
->hDesktopHeap
= UserCreateHeap(&DesktopObject
->DesktopHeapSection
,
954 &DesktopHeapSystemBase
,
955 4 * 1024 * 1024); /* FIXME */
956 if (DesktopObject
->hDesktopHeap
== NULL
)
958 ObDereferenceObject(DesktopObject
);
959 DPRINT1("Failed to create desktop heap!\n");
963 DesktopInfoSize
= FIELD_OFFSET(DESKTOP
,
964 szDesktopName
[(lpszDesktopName
->Length
/ sizeof(WCHAR
)) + 1]);
966 DesktopObject
->DesktopInfo
= RtlAllocateHeap(DesktopObject
->hDesktopHeap
,
970 if (DesktopObject
->DesktopInfo
== NULL
)
972 ObDereferenceObject(DesktopObject
);
973 DPRINT1("Failed to create the DESKTOP structure!\n");
977 RtlZeroMemory(DesktopObject
->DesktopInfo
,
980 DesktopObject
->DesktopInfo
->hKernelHeap
= DesktopObject
->hDesktopHeap
;
981 RtlCopyMemory(DesktopObject
->DesktopInfo
->szDesktopName
,
982 lpszDesktopName
->Buffer
,
983 lpszDesktopName
->Length
);
986 DesktopObject
->WorkArea
.left
= 0;
987 DesktopObject
->WorkArea
.top
= 0;
988 DesktopObject
->WorkArea
.right
= -1;
989 DesktopObject
->WorkArea
.bottom
= -1;
990 IntGetDesktopWorkArea(DesktopObject
, NULL
);
992 /* Initialize some local (to win32k) desktop state. */
993 DesktopObject
->ActiveMessageQueue
= NULL
;
994 ExFreePool(DesktopName
.Buffer
);
996 if (! NT_SUCCESS(Status
))
998 DPRINT1("Failed to create desktop handle\n");
999 SetLastNtError(Status
);
1004 * Create a handle for CSRSS and notify CSRSS
1006 Request
.Type
= MAKE_CSR_API(CREATE_DESKTOP
, CSR_GUI
);
1007 Status
= CsrInsertObject(Desktop
,
1009 (HANDLE
*)&Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
1010 if (! NT_SUCCESS(Status
))
1012 DPRINT1("Failed to create desktop handle for CSRSS\n");
1014 SetLastNtError(Status
);
1018 Status
= co_CsrNotify(&Request
);
1019 if (! NT_SUCCESS(Status
))
1021 CsrCloseHandle(Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
1022 DPRINT1("Failed to notify CSRSS about new desktop\n");
1024 SetLastNtError(Status
);
1031 DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_
);
1039 * Opens an existing desktop.
1043 * Name of the existing desktop.
1046 * Interaction flags.
1049 * Requested type of access.
1052 * Handle to the desktop or zero on failure.
1060 PUNICODE_STRING lpszDesktopName
,
1062 ACCESS_MASK dwDesiredAccess
)
1064 OBJECT_ATTRIBUTES ObjectAttributes
;
1066 PWINSTATION_OBJECT WinStaObject
;
1067 UNICODE_STRING DesktopName
;
1068 UNICODE_STRING SafeDesktopName
;
1071 DECLARE_RETURN(HDESK
);
1073 DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName
);
1074 UserEnterExclusive();
1077 * Validate the window station handle and compose the fully
1078 * qualified desktop name
1081 WinSta
= UserGetProcessWindowStation();
1082 Status
= IntValidateWindowStationHandle(
1088 if (!NT_SUCCESS(Status
))
1090 DPRINT1("Failed validation of window station handle (0x%X)\n", WinSta
);
1091 SetLastNtError(Status
);
1095 if(lpszDesktopName
!= NULL
)
1097 Status
= IntSafeCopyUnicodeString(&SafeDesktopName
, lpszDesktopName
);
1098 if(!NT_SUCCESS(Status
))
1100 SetLastNtError(Status
);
1106 RtlInitUnicodeString(&SafeDesktopName
, NULL
);
1109 if (!IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
1112 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
1113 ObDereferenceObject(WinStaObject
);
1114 RtlFreeUnicodeString(&SafeDesktopName
);
1118 RtlFreeUnicodeString(&SafeDesktopName
);
1119 ObDereferenceObject(WinStaObject
);
1121 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName
);
1123 /* Initialize ObjectAttributes for the desktop object */
1124 InitializeObjectAttributes(
1131 Status
= ObOpenObjectByName(
1133 ExDesktopObjectType
,
1140 if (!NT_SUCCESS(Status
))
1142 SetLastNtError(Status
);
1143 ExFreePool(DesktopName
.Buffer
);
1147 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
1148 ExFreePool(DesktopName
.Buffer
);
1153 DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_
);
1159 * NtUserOpenInputDesktop
1161 * Opens the input (interactive) desktop.
1165 * Interaction flags.
1168 * Inheritance option.
1171 * Requested type of access.
1174 * Handle to the input desktop or zero on failure.
1181 NtUserOpenInputDesktop(
1184 ACCESS_MASK dwDesiredAccess
)
1186 PDESKTOP_OBJECT Object
;
1189 DECLARE_RETURN(HDESK
);
1191 DPRINT("Enter NtUserOpenInputDesktop\n");
1192 UserEnterExclusive();
1194 DPRINT("About to open input desktop\n");
1196 /* Get a pointer to the desktop object */
1198 Status
= IntValidateDesktopHandle(
1204 if (!NT_SUCCESS(Status
))
1206 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop
);
1210 /* Create a new handle to the object */
1212 Status
= ObOpenObjectByPointer(
1217 ExDesktopObjectType
,
1221 ObDereferenceObject(Object
);
1223 if (NT_SUCCESS(Status
))
1225 DPRINT("Successfully opened input desktop\n");
1226 RETURN((HDESK
)Desktop
);
1229 SetLastNtError(Status
);
1233 DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_
);
1239 * NtUserCloseDesktop
1241 * Closes a desktop handle.
1245 * Handle to the desktop.
1251 * The desktop handle can be created with NtUserCreateDesktop or
1252 * NtUserOpenDesktop. This function will fail if any thread in the calling
1253 * process is using the specified desktop handle or if the handle refers
1254 * to the initial desktop of the calling process.
1261 NtUserCloseDesktop(HDESK hDesktop
)
1263 PDESKTOP_OBJECT Object
;
1265 DECLARE_RETURN(BOOL
);
1267 DPRINT("Enter NtUserCloseDesktop\n");
1268 UserEnterExclusive();
1270 DPRINT("About to close desktop handle (0x%X)\n", hDesktop
);
1272 Status
= IntValidateDesktopHandle(
1278 if (!NT_SUCCESS(Status
))
1280 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1284 ObDereferenceObject(Object
);
1286 DPRINT("Closing desktop handle (0x%X)\n", hDesktop
);
1288 Status
= ZwClose(hDesktop
);
1289 if (!NT_SUCCESS(Status
))
1291 SetLastNtError(Status
);
1298 DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_
);
1307 * NtUserPaintDesktop
1309 * The NtUserPaintDesktop function fills the clipping region in the
1310 * specified device context with the desktop pattern or wallpaper. The
1311 * function is provided primarily for shell desktops.
1315 * Handle to the device context.
1322 NtUserPaintDesktop(HDC hDC
)
1325 HBRUSH DesktopBrush
, PreviousBrush
;
1327 BOOL doPatBlt
= TRUE
;
1328 PWINDOW_OBJECT WndDesktop
;
1333 PWINSTATION_OBJECT WinSta
= PsGetCurrentThreadWin32Thread()->Desktop
->WindowStation
;
1334 DECLARE_RETURN(BOOL
);
1336 UserEnterExclusive();
1337 DPRINT("Enter NtUserPaintDesktop\n");
1340 IntGdiGetClipBox(hDC
, &Rect
);
1342 hWndDesktop
= IntGetDesktopWindow();
1344 WndDesktop
= UserGetWindowObject(hWndDesktop
);
1350 DesktopBrush
= (HBRUSH
)UserGetClassLongPtr(WndDesktop
->Class
, GCL_HBRBACKGROUND
, FALSE
);
1354 * Paint desktop background
1357 if (WinSta
->hbmWallpaper
!= NULL
)
1359 PWINDOW_OBJECT DeskWin
;
1361 DeskWin
= UserGetWindowObject(hWndDesktop
);
1369 sz
.cx
= DeskWin
->WindowRect
.right
- DeskWin
->WindowRect
.left
;
1370 sz
.cy
= DeskWin
->WindowRect
.bottom
- DeskWin
->WindowRect
.top
;
1372 if (WinSta
->WallpaperMode
== wmStretch
||
1373 WinSta
->WallpaperMode
== wmTile
)
1380 /* Find the upper left corner, can be negtive if the bitmap is bigger then the screen */
1381 x
= (sz
.cx
/ 2) - (WinSta
->cxWallpaper
/ 2);
1382 y
= (sz
.cy
/ 2) - (WinSta
->cyWallpaper
/ 2);
1385 hWallpaperDC
= NtGdiCreateCompatibleDC(hDC
);
1386 if(hWallpaperDC
!= NULL
)
1390 /* fill in the area that the bitmap is not going to cover */
1393 /* FIXME - clip out the bitmap
1394 can be replaced with "NtGdiPatBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, PATCOPY | DSTINVERT);"
1395 once we support DSTINVERT */
1396 PreviousBrush
= NtGdiSelectObject(hDC
, DesktopBrush
);
1397 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1398 NtGdiSelectObject(hDC
, PreviousBrush
);
1401 /*Do not fill the background after it is painted no matter the size of the picture */
1404 hOldBitmap
= NtGdiSelectObject(hWallpaperDC
, WinSta
->hbmWallpaper
);
1406 if (WinSta
->WallpaperMode
== wmStretch
)
1408 if(Rect
.right
&& Rect
.bottom
)
1409 NtGdiStretchBlt(hDC
,
1417 WinSta
->cxWallpaper
,
1418 WinSta
->cyWallpaper
,
1423 else if (WinSta
->WallpaperMode
== wmTile
)
1425 /* paint the bitmap across the screen then down */
1426 for(y
= 0; y
< Rect
.bottom
; y
+= WinSta
->cyWallpaper
)
1428 for(x
= 0; x
< Rect
.right
; x
+= WinSta
->cxWallpaper
)
1433 WinSta
->cxWallpaper
,
1434 WinSta
->cyWallpaper
,
1449 WinSta
->cxWallpaper
,
1450 WinSta
->cyWallpaper
,
1458 NtGdiSelectObject(hWallpaperDC
, hOldBitmap
);
1459 NtGdiDeleteObjectApp(hWallpaperDC
);
1464 /* Back ground is set to none, clear the screen */
1467 PreviousBrush
= NtGdiSelectObject(hDC
, DesktopBrush
);
1468 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1469 NtGdiSelectObject(hDC
, PreviousBrush
);
1473 * Display system version on the desktop background
1476 if (g_PaintDesktopVersion
)
1478 static WCHAR s_wszVersion
[256] = {0};
1483 len
= wcslen(s_wszVersion
);
1487 len
= GetSystemVersionString(s_wszVersion
);
1492 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
1494 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1495 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1498 color_old
= NtGdiSetTextColor(hDC
, RGB(255,255,255));
1499 align_old
= NtGdiSetTextAlign(hDC
, TA_RIGHT
);
1500 mode_old
= NtGdiSetBkMode(hDC
, TRANSPARENT
);
1502 NtGdiTextOut(hDC
, rect
.right
-16, rect
.bottom
-48, s_wszVersion
, len
);
1504 NtGdiSetBkMode(hDC
, mode_old
);
1505 NtGdiSetTextAlign(hDC
, align_old
);
1506 NtGdiSetTextColor(hDC
, color_old
);
1513 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_
);
1520 * NtUserSwitchDesktop
1522 * Sets the current input (interactive) desktop.
1526 * Handle to desktop.
1536 NtUserSwitchDesktop(HDESK hDesktop
)
1538 PDESKTOP_OBJECT DesktopObject
;
1540 DECLARE_RETURN(BOOL
);
1542 UserEnterExclusive();
1543 DPRINT("Enter NtUserSwitchDesktop\n");
1545 DPRINT("About to switch desktop (0x%X)\n", hDesktop
);
1547 Status
= IntValidateDesktopHandle(
1553 if (!NT_SUCCESS(Status
))
1555 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1560 * Don't allow applications switch the desktop if it's locked, unless the caller
1561 * is the logon application itself
1563 if((DesktopObject
->WindowStation
->Flags
& WSS_LOCKED
) &&
1564 LogonProcess
!= NULL
&& LogonProcess
!= PsGetCurrentProcessWin32Process())
1566 ObDereferenceObject(DesktopObject
);
1567 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop
);
1571 /* FIXME: Fail if the desktop belong to an invisible window station */
1572 /* FIXME: Fail if the process is associated with a secured
1573 desktop such as Winlogon or Screen-Saver */
1574 /* FIXME: Connect to input device */
1576 /* Set the active desktop in the desktop's window station. */
1577 DesktopObject
->WindowStation
->ActiveDesktop
= DesktopObject
;
1579 /* Set the global state. */
1580 InputDesktop
= DesktopObject
;
1581 InputDesktopHandle
= hDesktop
;
1582 InputWindowStation
= DesktopObject
->WindowStation
;
1584 ObDereferenceObject(DesktopObject
);
1589 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_
);
1595 * NtUserResolveDesktopForWOW
1602 NtUserResolveDesktopForWOW(DWORD Unknown0
)
1609 * NtUserGetThreadDesktop
1616 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1620 PDESKTOP_OBJECT DesktopObject
;
1621 HDESK Ret
, hThreadDesktop
;
1622 OBJECT_HANDLE_INFORMATION HandleInformation
;
1623 DECLARE_RETURN(HDESK
);
1625 UserEnterExclusive();
1626 DPRINT("Enter NtUserGetThreadDesktop\n");
1630 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1634 Status
= PsLookupThreadByThreadId((HANDLE
)dwThreadId
, &Thread
);
1635 if(!NT_SUCCESS(Status
))
1637 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1641 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1643 /* just return the handle, we queried the desktop handle of a thread running
1644 in the same context */
1645 Ret
= ((PW32THREAD
)Thread
->Tcb
.Win32Thread
)->hDesktop
;
1646 ObDereferenceObject(Thread
);
1650 /* get the desktop handle and the desktop of the thread */
1651 if(!(hThreadDesktop
= ((PW32THREAD
)Thread
->Tcb
.Win32Thread
)->hDesktop
) ||
1652 !(DesktopObject
= ((PW32THREAD
)Thread
->Tcb
.Win32Thread
)->Desktop
))
1654 ObDereferenceObject(Thread
);
1655 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1659 /* we could just use DesktopObject instead of looking up the handle, but latter
1660 may be a bit safer (e.g. when the desktop is being destroyed */
1661 /* switch into the context of the thread we're trying to get the desktop from,
1662 so we can use the handle */
1663 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1664 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1666 ExDesktopObjectType
,
1668 (PVOID
*)&DesktopObject
,
1669 &HandleInformation
);
1672 /* the handle couldn't be found, there's nothing to get... */
1673 if(!NT_SUCCESS(Status
))
1675 ObDereferenceObject(Thread
);
1679 /* lookup our handle table if we can find a handle to the desktop object,
1680 if not, create one */
1681 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1683 /* all done, we got a valid handle to the desktop */
1684 ObDereferenceObject(DesktopObject
);
1685 ObDereferenceObject(Thread
);
1689 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_
);
1695 IntUnmapDesktopView(IN PDESKTOP_OBJECT DesktopObject
)
1698 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
= &PsGetCurrentProcessWin32Process()->HeapMappings
.Next
;
1699 NTSTATUS Status
= STATUS_SUCCESS
;
1703 /* unmap if we're the last thread using the desktop */
1704 HeapMapping
= *PrevLink
;
1705 while (HeapMapping
!= NULL
)
1707 if (HeapMapping
->KernelMapping
== (PVOID
)DesktopObject
->hDesktopHeap
)
1709 if (--HeapMapping
->Count
== 0)
1711 *PrevLink
= HeapMapping
->Next
;
1713 Status
= MmUnmapViewOfSection(PsGetCurrentProcess(),
1714 HeapMapping
->UserMapping
);
1716 ObDereferenceObject(DesktopObject
);
1718 UserHeapFree(HeapMapping
);
1723 PrevLink
= &HeapMapping
->Next
;
1724 HeapMapping
= HeapMapping
->Next
;
1727 ti
= GetW32ThreadInfo();
1730 if (ti
->Desktop
== DesktopObject
->DesktopInfo
)
1733 ti
->DesktopHeapDelta
= 0;
1741 IntMapDesktopView(IN PDESKTOP_OBJECT DesktopObject
)
1744 PW32HEAP_USER_MAPPING HeapMapping
, *PrevLink
= &PsGetCurrentProcessWin32Process()->HeapMappings
.Next
;
1745 PVOID UserBase
= NULL
;
1747 LARGE_INTEGER Offset
;
1750 /* find out if another thread already mapped the desktop heap */
1751 HeapMapping
= *PrevLink
;
1752 while (HeapMapping
!= NULL
)
1754 if (HeapMapping
->KernelMapping
== (PVOID
)DesktopObject
->hDesktopHeap
)
1756 HeapMapping
->Count
++;
1757 return STATUS_SUCCESS
;
1760 PrevLink
= &HeapMapping
->Next
;
1761 HeapMapping
= HeapMapping
->Next
;
1764 /* we're the first, map the heap */
1765 DPRINT("Noone mapped the desktop heap %p yet, so - map it!\n", DesktopObject
->hDesktopHeap
);
1766 Offset
.QuadPart
= 0;
1767 Status
= MmMapViewOfSection(DesktopObject
->DesktopHeapSection
,
1768 PsGetCurrentProcess(),
1776 PAGE_EXECUTE_READ
); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
1777 if (!NT_SUCCESS(Status
))
1779 DPRINT1("Failed to map desktop\n");
1783 /* add the mapping */
1784 HeapMapping
= UserHeapAlloc(sizeof(W32HEAP_USER_MAPPING
));
1785 if (HeapMapping
== NULL
)
1787 MmUnmapViewOfSection(PsGetCurrentProcess(),
1789 DPRINT1("UserHeapAlloc() failed!\n");
1790 return STATUS_NO_MEMORY
;
1793 HeapMapping
->Next
= NULL
;
1794 HeapMapping
->KernelMapping
= (PVOID
)DesktopObject
->hDesktopHeap
;
1795 HeapMapping
->UserMapping
= UserBase
;
1796 HeapMapping
->Count
= 1;
1797 *PrevLink
= HeapMapping
;
1799 ObReferenceObject(DesktopObject
);
1801 /* create a W32THREADINFO structure if not already done, or update it */
1802 ti
= GetW32ThreadInfo();
1805 if (ti
->Desktop
== NULL
)
1807 ti
->Desktop
= DesktopObject
->DesktopInfo
;
1808 ti
->DesktopHeapDelta
= DesktopHeapGetUserDelta();
1812 return STATUS_SUCCESS
;
1816 IntSetThreadDesktop(IN PDESKTOP_OBJECT DesktopObject
,
1817 IN BOOL FreeOnFailure
)
1819 PDESKTOP_OBJECT OldDesktop
;
1820 PW32THREAD W32Thread
;
1824 DPRINT("IntSetThreadDesktop() DO=%p, FOF=%d\n", DesktopObject
, FreeOnFailure
);
1825 MapHeap
= (PsGetCurrentProcess() != PsInitialSystemProcess
);
1826 W32Thread
= PsGetCurrentThreadWin32Thread();
1828 if (W32Thread
->Desktop
!= DesktopObject
)
1830 OldDesktop
= W32Thread
->Desktop
;
1832 if (!IsListEmpty(&W32Thread
->WindowListHead
))
1834 DPRINT1("Attempted to change thread desktop although the thread has windows!\n");
1835 SetLastWin32Error(ERROR_BUSY
);
1839 W32Thread
->Desktop
= DesktopObject
;
1841 if (MapHeap
&& DesktopObject
!= NULL
)
1843 Status
= IntMapDesktopView(DesktopObject
);
1844 if (!NT_SUCCESS(Status
))
1846 SetLastNtError(Status
);
1851 if (OldDesktop
!= NULL
&&
1852 !IntCheckProcessDesktopClasses(OldDesktop
->DesktopInfo
,
1855 DPRINT1("Failed to move process classes to shared heap!\n");
1857 /* failed to move desktop classes to the shared heap,
1858 unmap the view and return the error */
1859 if (MapHeap
&& DesktopObject
!= NULL
)
1860 IntUnmapDesktopView(DesktopObject
);
1865 if (DesktopObject
!= NULL
)
1867 ObReferenceObject(DesktopObject
);
1870 if (OldDesktop
!= NULL
)
1874 IntUnmapDesktopView(OldDesktop
);
1877 ObDereferenceObject(OldDesktop
);
1879 /* update the thread info */
1880 if (W32Thread
!= NULL
&& W32Thread
->ThreadInfo
!= NULL
&&
1881 W32Thread
->ThreadInfo
->Desktop
!= (DesktopObject
!= NULL
? DesktopObject
->DesktopInfo
: NULL
))
1883 if (DesktopObject
!= NULL
)
1885 W32Thread
->ThreadInfo
->Desktop
= DesktopObject
->DesktopInfo
;
1886 W32Thread
->ThreadInfo
->DesktopHeapDelta
= DesktopHeapGetUserDelta();
1890 W32Thread
->ThreadInfo
->Desktop
= NULL
;
1891 W32Thread
->ThreadInfo
->DesktopHeapDelta
= 0;
1901 * NtUserSetThreadDesktop
1908 NtUserSetThreadDesktop(HDESK hDesktop
)
1910 PDESKTOP_OBJECT DesktopObject
;
1912 DECLARE_RETURN(BOOL
);
1914 UserEnterExclusive();
1915 DPRINT("Enter NtUserSetThreadDesktop\n");
1917 /* Validate the new desktop. */
1918 Status
= IntValidateDesktopHandle(
1924 if (!NT_SUCCESS(Status
))
1926 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1930 /* FIXME: Should check here to see if the thread has any windows. */
1932 if (!IntSetThreadDesktop(DesktopObject
,
1941 DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_
);