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 ******************************************************************/
37 /* GLOBALS *******************************************************************/
39 /* Currently active desktop */
40 PDESKTOP_OBJECT InputDesktop
= NULL
;
41 HDESK InputDesktopHandle
= NULL
;
42 HDC ScreenDeviceContext
= NULL
;
44 BOOL g_PaintDesktopVersion
= FALSE
;
46 /* INITALIZATION FUNCTIONS ****************************************************/
48 static GENERIC_MAPPING IntDesktopMapping
=
50 STANDARD_RIGHTS_READ
| DESKTOP_ENUMERATE
| DESKTOP_READOBJECTS
,
51 STANDARD_RIGHTS_WRITE
| DESKTOP_CREATEMENU
| DESKTOP_CREATEWINDOW
| DESKTOP_HOOKCONTROL
|
52 DESKTOP_JOURNALPLAYBACK
| DESKTOP_JOURNALRECORD
| DESKTOP_WRITEOBJECTS
,
53 STANDARD_RIGHTS_EXECUTE
| DESKTOP_SWITCHDESKTOP
,
54 STANDARD_RIGHTS_REQUIRED
| DESKTOP_CREATEMENU
| DESKTOP_CREATEWINDOW
| DESKTOP_ENUMERATE
|
55 DESKTOP_HOOKCONTROL
| DESKTOP_JOURNALPLAYBACK
| DESKTOP_JOURNALRECORD
|
56 DESKTOP_READOBJECTS
| DESKTOP_SWITCHDESKTOP
| DESKTOP_WRITEOBJECTS
62 /* Set Desktop Object Attributes */
63 ExDesktopObjectType
->TypeInfo
.DefaultNonPagedPoolCharge
= sizeof(DESKTOP_OBJECT
);
64 ExDesktopObjectType
->TypeInfo
.GenericMapping
= IntDesktopMapping
;
66 return STATUS_SUCCESS
;
70 CleanupDesktopImpl(VOID
)
72 return STATUS_SUCCESS
;
75 /* OBJECT CALLBACKS **********************************************************/
78 IntDesktopObjectCreate(PVOID ObjectBody
,
81 struct _OBJECT_ATTRIBUTES
* ObjectAttributes
)
83 PDESKTOP_OBJECT Desktop
= (PDESKTOP_OBJECT
)ObjectBody
;
84 UNICODE_STRING UnicodeString
;
86 DPRINT("Creating desktop (0x%X) Name (%S)\n", Desktop
, RemainingPath
);
87 if (RemainingPath
== NULL
)
89 return STATUS_SUCCESS
;
92 if (wcschr((RemainingPath
+ 1), '\\') != NULL
)
94 return STATUS_UNSUCCESSFUL
;
97 RtlInitUnicodeString(&UnicodeString
, (RemainingPath
+ 1));
99 InitializeListHead(&Desktop
->ShellHookWindows
);
101 Desktop
->WindowStation
= (PWINSTATION_OBJECT
)Parent
;
103 /* Put the desktop on the window station's list of associcated desktops */
106 &Desktop
->WindowStation
->DesktopListHead
,
107 &Desktop
->ListEntry
);//,
108 // &Desktop->WindowStation->Lock);
110 return RtlCreateUnicodeString(&Desktop
->Name
, UnicodeString
.Buffer
);
114 IntDesktopObjectDelete(PVOID DeletedObject
)
116 PDESKTOP_OBJECT Desktop
= (PDESKTOP_OBJECT
)DeletedObject
;
118 DPRINT("Deleting desktop (0x%X)\n", Desktop
);
120 /* Remove the desktop from the window station's list of associcated desktops */
121 RemoveEntryList(&Desktop
->ListEntry
);
123 RtlFreeUnicodeString(&Desktop
->Name
);
126 /* PRIVATE FUNCTIONS **********************************************************/
128 static int GetSystemVersionString(LPWSTR buffer
)
130 RTL_OSVERSIONINFOEXW versionInfo
;
133 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
135 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
138 if (versionInfo
.dwMajorVersion
<= 4)
139 len
= swprintf(buffer
,
140 L
"ReactOS Version %d.%d %s Build %d",
141 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
142 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
144 len
= swprintf(buffer
,
145 L
"ReactOS %s (Build %d)",
146 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
153 IntParseDesktopPath(PEPROCESS Process
,
154 PUNICODE_STRING DesktopPath
,
158 OBJECT_ATTRIBUTES ObjectAttributes
;
159 UNICODE_STRING WinSta
, Desktop
, FullName
;
160 BOOL DesktopPresent
= FALSE
;
161 BOOL WinStaPresent
= FALSE
;
173 RtlInitUnicodeString(&WinSta
, NULL
);
174 RtlInitUnicodeString(&Desktop
, NULL
);
176 if(DesktopPath
!= NULL
&& DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
178 PWCHAR c
= DesktopPath
->Buffer
;
180 USHORT l
= DesktopPath
->Length
;
183 * Parse the desktop path string which can be in the form "WinSta\Desktop"
184 * or just "Desktop". In latter case WinSta0 will be used.
191 wl
= (ULONG_PTR
)c
- (ULONG_PTR
)DesktopPath
->Buffer
;
201 WinSta
.MaximumLength
= wl
+ sizeof(WCHAR
);
202 WinSta
.Buffer
= DesktopPath
->Buffer
;
204 WinStaPresent
= TRUE
;
208 Desktop
.Length
= DesktopPath
->Length
- wl
;
211 Desktop
.Length
-= sizeof(WCHAR
);
213 if(Desktop
.Length
> 0)
215 Desktop
.MaximumLength
= Desktop
.Length
+ sizeof(WCHAR
);
216 Desktop
.Buffer
= ((wl
> 0) ? c
: DesktopPath
->Buffer
);
217 DesktopPresent
= TRUE
;
223 /* search the process handle table for (inherited) window station
224 handles, use a more appropriate one than WinSta0 if possible. */
225 Status
= ObFindHandleForObject(Process
,
227 ExWindowStationObjectType
,
230 if(!NT_SUCCESS(Status
))
232 /* we had no luck searching for opened handles, use WinSta0 now */
233 RtlInitUnicodeString(&WinSta
, L
"WinSta0");
237 if(!DesktopPresent
&& hDesktop
!= NULL
)
239 /* search the process handle table for (inherited) desktop
240 handles, use a more appropriate one than Default if possible. */
241 Status
= ObFindHandleForObject(Process
,
246 if(!NT_SUCCESS(Status
))
248 /* we had no luck searching for opened handles, use Desktop now */
249 RtlInitUnicodeString(&Desktop
, L
"Default");
255 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, NULL
))
257 return STATUS_INSUFFICIENT_RESOURCES
;
260 /* open the window station */
261 InitializeObjectAttributes(&ObjectAttributes
,
263 OBJ_CASE_INSENSITIVE
,
267 Status
= ObOpenObjectByName(&ObjectAttributes
,
268 ExWindowStationObjectType
,
275 RtlFreeUnicodeString(&FullName
);
277 if(!NT_SUCCESS(Status
))
279 SetLastNtError(Status
);
280 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta
, PsGetCurrentProcessId());
285 if(hDesktop
!= NULL
&& *hDesktop
== NULL
)
287 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, &Desktop
))
291 return STATUS_INSUFFICIENT_RESOURCES
;
294 /* open the desktop object */
295 InitializeObjectAttributes(&ObjectAttributes
,
297 OBJ_CASE_INSENSITIVE
,
301 Status
= ObOpenObjectByName(&ObjectAttributes
,
309 RtlFreeUnicodeString(&FullName
);
311 if(!NT_SUCCESS(Status
))
316 SetLastNtError(Status
);
317 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop
, PsGetCurrentProcessId());
322 return STATUS_SUCCESS
;
326 * IntValidateDesktopHandle
328 * Validates the desktop handle.
331 * If the function succeeds, the handle remains referenced. If the
332 * fucntion fails, last error is set.
336 IntValidateDesktopHandle(
338 KPROCESSOR_MODE AccessMode
,
339 ACCESS_MASK DesiredAccess
,
340 PDESKTOP_OBJECT
*Object
)
344 Status
= ObReferenceObjectByHandle(
352 if (!NT_SUCCESS(Status
))
353 SetLastNtError(Status
);
359 IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop
, PRECT Rect
)
365 Ret
= &Desktop
->WorkArea
;
366 if((Ret
->right
== -1) && ScreenDeviceContext
)
369 BITMAPOBJ
*BitmapObj
;
370 dc
= DC_LockDc(ScreenDeviceContext
);
371 /* FIXME - Handle dc == NULL!!!! */
372 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
375 Ret
->right
= BitmapObj
->SurfObj
.sizlBitmap
.cx
;
376 Ret
->bottom
= BitmapObj
->SurfObj
.sizlBitmap
.cy
;
377 BITMAPOBJ_UnlockBitmap(BitmapObj
);
388 PDESKTOP_OBJECT FASTCALL
389 IntGetActiveDesktop(VOID
)
395 * returns or creates a handle to the desktop object
398 IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject
)
403 ASSERT(DesktopObject
);
405 Status
= ObFindHandleForObject(PsGetCurrentProcess(),
411 if(!NT_SUCCESS(Status
))
413 Status
= ObOpenObjectByPointer(DesktopObject
,
420 if(!NT_SUCCESS(Status
))
422 /* unable to create a handle */
423 DPRINT1("Unable to create a desktop handle\n");
431 PUSER_MESSAGE_QUEUE FASTCALL
432 IntGetFocusMessageQueue(VOID
)
434 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
437 DPRINT("No active desktop\n");
440 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
444 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
446 PUSER_MESSAGE_QUEUE Old
;
447 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
450 DPRINT("No active desktop\n");
455 if(NewQueue
->Desktop
!= NULL
)
457 DPRINT("Message Queue already attached to another desktop!\n");
460 IntReferenceMessageQueue(NewQueue
);
461 InterlockedExchange((LONG
*)&NewQueue
->Desktop
, (LONG
)pdo
);
463 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchange((LONG
*)&pdo
->ActiveMessageQueue
, (LONG
)NewQueue
);
466 InterlockedExchange((LONG
*)&Old
->Desktop
, 0);
467 IntDereferenceMessageQueue(Old
);
471 HWND FASTCALL
IntGetDesktopWindow(VOID
)
473 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
476 DPRINT("No active desktop\n");
479 return pdo
->DesktopWindow
;
482 PWINDOW_OBJECT FASTCALL
UserGetDesktopWindow(VOID
)
484 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
488 DPRINT("No active desktop\n");
492 return UserGetWindowObject(pdo
->DesktopWindow
);
496 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
498 PDESKTOP_OBJECT pdo
= PsGetWin32Thread()->Desktop
;
501 DPRINT1("Thread doesn't have a desktop\n");
504 return pdo
->DesktopWindow
;
507 BOOL FASTCALL
IntDesktopUpdatePerUserSettings(BOOL bEnable
)
511 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
514 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
516 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
517 QueryTable
[0].Name
= L
"PaintDesktopVersion";
518 QueryTable
[0].EntryContext
= &g_PaintDesktopVersion
;
520 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
521 Status
= RtlQueryRegistryValues(RTL_REGISTRY_USER
,
522 L
"Control Panel\\Desktop",
523 QueryTable
, NULL
, NULL
);
524 if (!NT_SUCCESS(Status
))
526 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
528 g_PaintDesktopVersion
= FALSE
;
532 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion
);
538 g_PaintDesktopVersion
= FALSE
;
543 /* PUBLIC FUNCTIONS ***********************************************************/
546 co_IntShowDesktop(PDESKTOP_OBJECT Desktop
, ULONG Width
, ULONG Height
)
548 CSR_API_MESSAGE Request
;
550 Request
.Type
= MAKE_CSR_API(SHOW_DESKTOP
, CSR_GUI
);
551 Request
.Data
.ShowDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
552 Request
.Data
.ShowDesktopRequest
.Width
= Width
;
553 Request
.Data
.ShowDesktopRequest
.Height
= Height
;
555 return co_CsrNotify(&Request
);
559 IntHideDesktop(PDESKTOP_OBJECT Desktop
)
562 CSRSS_API_REQUEST Request
;
563 CSRSS_API_REPLY Reply
;
565 Request
.Type
= CSRSS_HIDE_DESKTOP
;
566 Request
.Data
.HideDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
568 return NotifyCsrss(&Request
, &Reply
);
571 PWINDOW_OBJECT DesktopWindow
;
573 DesktopWindow
= IntGetWindowObject(Desktop
->DesktopWindow
);
576 return ERROR_INVALID_WINDOW_HANDLE
;
578 DesktopWindow
->Style
&= ~WS_VISIBLE
;
580 return STATUS_SUCCESS
;
589 UserBuildShellHookHwndList(PDESKTOP_OBJECT Desktop
)
592 PSHELL_HOOK_WINDOW Current
;
595 /* fixme: if we save nb elements in desktop, we dont have to loop to find nb entries */
596 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
599 if (!entries
) return NULL
;
601 list
= ExAllocatePool(PagedPool
, sizeof(HWND
) * (entries
+ 1)); /* alloc one extra for nullterm */
606 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
607 *cursor
++ = Current
->hWnd
;
609 *cursor
= NULL
; /* nullterm list */
616 * Send the Message to the windows registered for ShellHook
617 * notifications. The lParam contents depend on the Message. See
618 * MSDN for more details (RegisterShellHookWindow)
620 VOID
co_IntShellHookNotify(WPARAM Message
, LPARAM lParam
)
622 PDESKTOP_OBJECT Desktop
= IntGetActiveDesktop();
625 static UINT MsgType
= 0;
630 /* Too bad, this doesn't work.*/
633 RtlInitUnicodeString(&Str
, L
"SHELLHOOK");
634 MsgType
= UserRegisterWindowMessage(&Str
);
637 MsgType
= IntAddAtom(L
"SHELLHOOK");
639 DPRINT("MsgType = %x\n", MsgType
);
641 DPRINT1("LastError: %x\n", GetLastNtError());
646 DPRINT1("IntShellHookNotify: No desktop!\n");
650 HwndList
= UserBuildShellHookHwndList(Desktop
);
653 HWND
* cursor
= HwndList
;
655 for (; *cursor
; cursor
++)
657 DPRINT("Sending notify\n");
658 co_IntPostOrSendMessage(*cursor
,
664 ExFreePool(HwndList
);
670 * Add the window to the ShellHookWindows list. The windows
671 * on that list get notifications that are important to shell
674 * TODO: Validate the window? I'm not sure if sending these messages to
675 * an unsuspecting application that is not your own is a nice thing to do.
677 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
679 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
;
680 PSHELL_HOOK_WINDOW Entry
;
682 DPRINT("IntRegisterShellHookWindow\n");
684 /* First deregister the window, so we can be sure it's never twice in the
687 IntDeRegisterShellHookWindow(hWnd
);
689 Entry
= ExAllocatePoolWithTag(PagedPool
,
690 sizeof(SHELL_HOOK_WINDOW
),
698 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
704 * Remove the window from the ShellHookWindows list. The windows
705 * on that list get notifications that are important to shell
708 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
710 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
;
711 PSHELL_HOOK_WINDOW Current
;
713 LIST_FOR_EACH(Current
, &Desktop
->ShellHookWindows
, SHELL_HOOK_WINDOW
, ListEntry
)
715 if (Current
->hWnd
== hWnd
)
717 RemoveEntryList(&Current
->ListEntry
);
729 /* SYSCALLS *******************************************************************/
733 * NtUserCreateDesktop
735 * Creates a new desktop.
739 * Name of the new desktop.
745 * Requested type of access.
748 * Security descriptor.
751 * Handle to window station on which to create the desktop.
754 * If the function succeeds, the return value is a handle to the newly
755 * created desktop. If the specified desktop already exists, the function
756 * succeeds and returns a handle to the existing desktop. When you are
757 * finished using the handle, call the CloseDesktop function to close it.
758 * If the function fails, the return value is NULL.
766 PUNICODE_STRING lpszDesktopName
,
768 ACCESS_MASK dwDesiredAccess
,
769 LPSECURITY_ATTRIBUTES lpSecurity
,
770 HWINSTA hWindowStation
)
772 OBJECT_ATTRIBUTES ObjectAttributes
;
773 PWINSTATION_OBJECT WinStaObject
;
774 PDESKTOP_OBJECT DesktopObject
;
775 UNICODE_STRING DesktopName
;
778 CSR_API_MESSAGE Request
;
779 DECLARE_RETURN(HDESK
);
781 DPRINT("Enter NtUserCreateDesktop: %wZ\n", lpszDesktopName
);
782 UserEnterExclusive();
784 Status
= IntValidateWindowStationHandle(
787 0, /* FIXME - WINSTA_CREATEDESKTOP */
790 if (! NT_SUCCESS(Status
))
792 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
793 hWindowStation
, lpszDesktopName
);
794 SetLastNtError(Status
);
798 if (! IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
801 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
802 ObDereferenceObject(WinStaObject
);
806 ObDereferenceObject(WinStaObject
);
809 * Try to open already existing desktop
812 DPRINT1("Trying to open desktop (%wZ)\n", &DesktopName
);
814 /* Initialize ObjectAttributes for the desktop object */
815 InitializeObjectAttributes(
822 Status
= ObOpenObjectByName(
831 if (NT_SUCCESS(Status
))
833 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
834 ExFreePool(DesktopName
.Buffer
);
839 * No existing desktop found, try to create new one
842 Status
= ObCreateObject(
848 sizeof(DESKTOP_OBJECT
),
851 (PVOID
*)&DesktopObject
);
853 if (! NT_SUCCESS(Status
))
855 DPRINT1("Failed creating desktop (%wZ)\n", &DesktopName
);
856 ExFreePool(DesktopName
.Buffer
);
857 SetLastNtError(STATUS_UNSUCCESSFUL
);
862 DesktopObject
->WorkArea
.left
= 0;
863 DesktopObject
->WorkArea
.top
= 0;
864 DesktopObject
->WorkArea
.right
= -1;
865 DesktopObject
->WorkArea
.bottom
= -1;
866 IntGetDesktopWorkArea(DesktopObject
, NULL
);
868 /* Initialize some local (to win32k) desktop state. */
869 DesktopObject
->ActiveMessageQueue
= NULL
;
871 Status
= ObInsertObject(
872 (PVOID
)DesktopObject
,
874 STANDARD_RIGHTS_REQUIRED
,
879 ObDereferenceObject(DesktopObject
);
880 ExFreePool(DesktopName
.Buffer
);
882 if (! NT_SUCCESS(Status
))
884 DPRINT1("Failed to create desktop handle\n");
885 SetLastNtError(Status
);
890 * Create a handle for CSRSS and notify CSRSS
892 Request
.Type
= MAKE_CSR_API(CREATE_DESKTOP
, CSR_GUI
);
893 Status
= CsrInsertObject(Desktop
,
895 (HANDLE
*)&Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
896 if (! NT_SUCCESS(Status
))
898 DPRINT1("Failed to create desktop handle for CSRSS\n");
900 SetLastNtError(Status
);
904 Status
= co_CsrNotify(&Request
);
905 if (! NT_SUCCESS(Status
))
907 CsrCloseHandle(Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
908 DPRINT1("Failed to notify CSRSS about new desktop\n");
910 SetLastNtError(Status
);
917 DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_
);
925 * Opens an existing desktop.
929 * Name of the existing desktop.
935 * Requested type of access.
938 * Handle to the desktop or zero on failure.
946 PUNICODE_STRING lpszDesktopName
,
948 ACCESS_MASK dwDesiredAccess
)
950 OBJECT_ATTRIBUTES ObjectAttributes
;
951 PWINSTATION_OBJECT WinStaObject
;
952 UNICODE_STRING DesktopName
;
955 DECLARE_RETURN(HDESK
);
957 DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName
);
958 UserEnterExclusive();
961 * Validate the window station handle and compose the fully
962 * qualified desktop name
965 Status
= IntValidateWindowStationHandle(
966 PsGetCurrentProcess()->Win32WindowStation
,
971 if (!NT_SUCCESS(Status
))
973 DPRINT1("Failed validation of window station handle (0x%X)\n",
974 PsGetCurrentProcess()->Win32WindowStation
);
975 SetLastNtError(Status
);
979 if (!IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
982 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
983 ObDereferenceObject(WinStaObject
);
987 ObDereferenceObject(WinStaObject
);
989 DPRINT1("Trying to open desktop (%wZ)\n", &DesktopName
);
991 /* Initialize ObjectAttributes for the desktop object */
992 InitializeObjectAttributes(
999 Status
= ObOpenObjectByName(
1001 ExDesktopObjectType
,
1008 if (!NT_SUCCESS(Status
))
1010 SetLastNtError(Status
);
1011 ExFreePool(DesktopName
.Buffer
);
1015 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
1016 ExFreePool(DesktopName
.Buffer
);
1021 DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_
);
1027 * NtUserOpenInputDesktop
1029 * Opens the input (interactive) desktop.
1033 * Interaction flags.
1036 * Inheritance option.
1039 * Requested type of access.
1042 * Handle to the input desktop or zero on failure.
1049 NtUserOpenInputDesktop(
1052 ACCESS_MASK dwDesiredAccess
)
1054 PDESKTOP_OBJECT Object
;
1057 DECLARE_RETURN(HDESK
);
1059 DPRINT("Enter NtUserOpenInputDesktop\n");
1060 UserEnterExclusive();
1062 DPRINT("About to open input desktop\n");
1064 /* Get a pointer to the desktop object */
1066 Status
= IntValidateDesktopHandle(
1072 if (!NT_SUCCESS(Status
))
1074 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop
);
1078 /* Create a new handle to the object */
1080 Status
= ObOpenObjectByPointer(
1085 ExDesktopObjectType
,
1089 ObDereferenceObject(Object
);
1091 if (NT_SUCCESS(Status
))
1093 DPRINT("Successfully opened input desktop\n");
1094 RETURN((HDESK
)Desktop
);
1097 SetLastNtError(Status
);
1101 DPRINT("Leave NtUserOpenInputDesktop, ret=%i\n",_ret_
);
1107 * NtUserCloseDesktop
1109 * Closes a desktop handle.
1113 * Handle to the desktop.
1119 * The desktop handle can be created with NtUserCreateDesktop or
1120 * NtUserOpenDesktop. This function will fail if any thread in the calling
1121 * process is using the specified desktop handle or if the handle refers
1122 * to the initial desktop of the calling process.
1129 NtUserCloseDesktop(HDESK hDesktop
)
1131 PDESKTOP_OBJECT Object
;
1133 DECLARE_RETURN(BOOL
);
1135 DPRINT("Enter NtUserCloseDesktop\n");
1136 UserEnterExclusive();
1138 DPRINT("About to close desktop handle (0x%X)\n", hDesktop
);
1140 Status
= IntValidateDesktopHandle(
1146 if (!NT_SUCCESS(Status
))
1148 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1152 ObDereferenceObject(Object
);
1154 DPRINT("Closing desktop handle (0x%X)\n", hDesktop
);
1156 Status
= ZwClose(hDesktop
);
1157 if (!NT_SUCCESS(Status
))
1159 SetLastNtError(Status
);
1166 DPRINT("Leave NtUserCloseDesktop, ret=%i\n",_ret_
);
1175 * NtUserPaintDesktop
1177 * The NtUserPaintDesktop function fills the clipping region in the
1178 * specified device context with the desktop pattern or wallpaper. The
1179 * function is provided primarily for shell desktops.
1183 * Handle to the device context.
1190 NtUserPaintDesktop(HDC hDC
)
1193 HBRUSH DesktopBrush
, PreviousBrush
;
1195 BOOL doPatBlt
= TRUE
;
1196 PWINDOW_OBJECT WndDesktop
;
1198 DECLARE_RETURN(BOOL
);
1200 UserEnterExclusive();
1201 DPRINT("Enter NtUserPaintDesktop\n");
1203 PWINSTATION_OBJECT WinSta
= PsGetWin32Thread()->Desktop
->WindowStation
;
1205 IntGdiGetClipBox(hDC
, &Rect
);
1207 hWndDesktop
= IntGetDesktopWindow();
1208 if (!(WndDesktop
= UserGetWindowObject(hWndDesktop
)))
1211 DesktopBrush
= (HBRUSH
)IntGetClassLong(WndDesktop
, GCL_HBRBACKGROUND
, FALSE
); //fixme: verify retval
1215 * Paint desktop background
1218 if(WinSta
->hbmWallpaper
!= NULL
)
1220 PWINDOW_OBJECT DeskWin
;
1222 if((DeskWin
= UserGetWindowObject(hWndDesktop
)))
1228 sz
.cx
= DeskWin
->WindowRect
.right
- DeskWin
->WindowRect
.left
;
1229 sz
.cy
= DeskWin
->WindowRect
.bottom
- DeskWin
->WindowRect
.top
;
1232 x
= (sz
.cx
/ 2) - (WinSta
->cxWallpaper
/ 2);
1233 y
= (sz
.cy
/ 2) - (WinSta
->cyWallpaper
/ 2);
1235 hWallpaperDC
= NtGdiCreateCompatableDC(hDC
);
1236 if(hWallpaperDC
!= NULL
)
1242 /* FIXME - clip out the bitmap */
1243 PreviousBrush
= NtGdiSelectObject(hDC
, DesktopBrush
);
1244 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1245 NtGdiSelectObject(hDC
, PreviousBrush
);
1250 hOldBitmap
= NtGdiSelectObject(hWallpaperDC
, WinSta
->hbmWallpaper
);
1251 NtGdiBitBlt(hDC
, x
, y
, WinSta
->cxWallpaper
, WinSta
->cyWallpaper
, hWallpaperDC
, 0, 0, SRCCOPY
);
1252 NtGdiSelectObject(hWallpaperDC
, hOldBitmap
);
1254 NtGdiDeleteDC(hWallpaperDC
);
1261 PreviousBrush
= NtGdiSelectObject(hDC
, DesktopBrush
);
1262 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1263 NtGdiSelectObject(hDC
, PreviousBrush
);
1267 * Display system version on the desktop background
1270 if (g_PaintDesktopVersion
)
1272 static WCHAR s_wszVersion
[256] = {0};
1276 len
= wcslen(s_wszVersion
);
1278 len
= GetSystemVersionString(s_wszVersion
);
1282 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
1284 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1285 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1288 COLORREF color_old
= NtGdiSetTextColor(hDC
, RGB(255,255,255));
1289 UINT align_old
= NtGdiSetTextAlign(hDC
, TA_RIGHT
);
1290 int mode_old
= NtGdiSetBkMode(hDC
, TRANSPARENT
);
1292 NtGdiTextOut(hDC
, rect
.right
-16, rect
.bottom
-48, s_wszVersion
, len
);
1294 NtGdiSetBkMode(hDC
, mode_old
);
1295 NtGdiSetTextAlign(hDC
, align_old
);
1296 NtGdiSetTextColor(hDC
, color_old
);
1303 DPRINT("Leave NtUserPaintDesktop, ret=%i\n",_ret_
);
1310 * NtUserSwitchDesktop
1312 * Sets the current input (interactive) desktop.
1316 * Handle to desktop.
1326 NtUserSwitchDesktop(HDESK hDesktop
)
1328 PDESKTOP_OBJECT DesktopObject
;
1330 DECLARE_RETURN(BOOL
);
1332 UserEnterExclusive();
1333 DPRINT("Enter NtUserSwitchDesktop\n");
1335 DPRINT("About to switch desktop (0x%X)\n", hDesktop
);
1337 Status
= IntValidateDesktopHandle(
1343 if (!NT_SUCCESS(Status
))
1345 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1350 * Don't allow applications switch the desktop if it's locked, unless the caller
1351 * is the logon application itself
1353 if((DesktopObject
->WindowStation
->Flags
& WSS_LOCKED
) &&
1354 LogonProcess
!= NULL
&& LogonProcess
!= PsGetWin32Process())
1356 ObDereferenceObject(DesktopObject
);
1357 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop
);
1361 /* FIXME: Fail if the desktop belong to an invisible window station */
1362 /* FIXME: Fail if the process is associated with a secured
1363 desktop such as Winlogon or Screen-Saver */
1364 /* FIXME: Connect to input device */
1366 /* Set the active desktop in the desktop's window station. */
1367 DesktopObject
->WindowStation
->ActiveDesktop
= DesktopObject
;
1369 /* Set the global state. */
1370 InputDesktop
= DesktopObject
;
1371 InputDesktopHandle
= hDesktop
;
1372 InputWindowStation
= DesktopObject
->WindowStation
;
1374 ObDereferenceObject(DesktopObject
);
1379 DPRINT("Leave NtUserSwitchDesktop, ret=%i\n",_ret_
);
1385 * NtUserResolveDesktopForWOW
1392 NtUserResolveDesktopForWOW(DWORD Unknown0
)
1399 * NtUserGetThreadDesktop
1406 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1410 PDESKTOP_OBJECT DesktopObject
;
1411 HDESK Ret
, hThreadDesktop
;
1412 OBJECT_HANDLE_INFORMATION HandleInformation
;
1413 DECLARE_RETURN(HDESK
);
1415 UserEnterExclusive();
1416 DPRINT("Enter NtUserGetThreadDesktop\n");
1420 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1424 Status
= PsLookupThreadByThreadId((HANDLE
)dwThreadId
, &Thread
);
1425 if(!NT_SUCCESS(Status
))
1427 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1431 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1433 /* just return the handle, we queried the desktop handle of a thread running
1434 in the same context */
1435 Ret
= Thread
->Tcb
.Win32Thread
->hDesktop
;
1436 ObDereferenceObject(Thread
);
1440 /* get the desktop handle and the desktop of the thread */
1441 if(!(hThreadDesktop
= Thread
->Tcb
.Win32Thread
->hDesktop
) ||
1442 !(DesktopObject
= Thread
->Tcb
.Win32Thread
->Desktop
))
1444 ObDereferenceObject(Thread
);
1445 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1449 /* we could just use DesktopObject instead of looking up the handle, but latter
1450 may be a bit safer (e.g. when the desktop is being destroyed */
1451 /* switch into the context of the thread we're trying to get the desktop from,
1452 so we can use the handle */
1453 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1454 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1456 ExDesktopObjectType
,
1458 (PVOID
*)&DesktopObject
,
1459 &HandleInformation
);
1462 /* the handle couldn't be found, there's nothing to get... */
1463 if(!NT_SUCCESS(Status
))
1465 ObDereferenceObject(Thread
);
1469 /* lookup our handle table if we can find a handle to the desktop object,
1470 if not, create one */
1471 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1473 /* all done, we got a valid handle to the desktop */
1474 ObDereferenceObject(DesktopObject
);
1475 ObDereferenceObject(Thread
);
1479 DPRINT("Leave NtUserGetThreadDesktop, ret=%i\n",_ret_
);
1485 * NtUserSetThreadDesktop
1492 NtUserSetThreadDesktop(HDESK hDesktop
)
1494 PW32THREAD W32Thread
;
1495 PDESKTOP_OBJECT DesktopObject
;
1497 DECLARE_RETURN(BOOL
);
1499 UserEnterExclusive();
1500 DPRINT("Enter NtUserSetThreadDesktop\n");
1502 /* Validate the new desktop. */
1503 Status
= IntValidateDesktopHandle(
1509 if (!NT_SUCCESS(Status
))
1511 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1515 W32Thread
= PsGetWin32Thread();
1517 /* FIXME: Should check here to see if the thread has any windows. */
1519 if (W32Thread
->Desktop
!= NULL
)
1521 ObDereferenceObject(W32Thread
->Desktop
);
1524 W32Thread
->Desktop
= DesktopObject
;
1525 W32Thread
->hDesktop
= hDesktop
;
1530 DPRINT("Leave NtUserSetThreadDesktop, ret=%i\n",_ret_
);