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));
101 KeInitializeSpinLock(&Desktop
->Lock
);
102 InitializeListHead(&Desktop
->ShellHookWindows
);
104 Desktop
->WindowStation
= (PWINSTATION_OBJECT
)Parent
;
106 /* Put the desktop on the window station's list of associcated desktops */
107 ExInterlockedInsertTailList(
108 &Desktop
->WindowStation
->DesktopListHead
,
110 &Desktop
->WindowStation
->Lock
);
112 return RtlCreateUnicodeString(&Desktop
->Name
, UnicodeString
.Buffer
);
116 IntDesktopObjectDelete(PVOID DeletedObject
)
118 PDESKTOP_OBJECT Desktop
= (PDESKTOP_OBJECT
)DeletedObject
;
121 DPRINT("Deleting desktop (0x%X)\n", Desktop
);
123 /* Remove the desktop from the window station's list of associcated desktops */
124 KeAcquireSpinLock(&Desktop
->WindowStation
->Lock
, &OldIrql
);
125 RemoveEntryList(&Desktop
->ListEntry
);
126 KeReleaseSpinLock(&Desktop
->WindowStation
->Lock
, OldIrql
);
128 RtlFreeUnicodeString(&Desktop
->Name
);
131 /* PRIVATE FUNCTIONS **********************************************************/
134 IntParseDesktopPath(PEPROCESS Process
,
135 PUNICODE_STRING DesktopPath
,
139 OBJECT_ATTRIBUTES ObjectAttributes
;
140 UNICODE_STRING WinSta
, Desktop
, FullName
;
141 BOOL DesktopPresent
= FALSE
;
142 BOOL WinStaPresent
= FALSE
;
154 RtlInitUnicodeString(&WinSta
, NULL
);
155 RtlInitUnicodeString(&Desktop
, NULL
);
157 if(DesktopPath
!= NULL
&& DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
159 PWCHAR c
= DesktopPath
->Buffer
;
161 USHORT l
= DesktopPath
->Length
;
164 * Parse the desktop path string which can be in the form "WinSta\Desktop"
165 * or just "Desktop". In latter case WinSta0 will be used.
172 wl
= (ULONG_PTR
)c
- (ULONG_PTR
)DesktopPath
->Buffer
;
182 WinSta
.MaximumLength
= wl
+ sizeof(WCHAR
);
183 WinSta
.Buffer
= DesktopPath
->Buffer
;
185 WinStaPresent
= TRUE
;
189 Desktop
.Length
= DesktopPath
->Length
- wl
;
192 Desktop
.Length
-= sizeof(WCHAR
);
194 if(Desktop
.Length
> 0)
196 Desktop
.MaximumLength
= Desktop
.Length
+ sizeof(WCHAR
);
197 Desktop
.Buffer
= ((wl
> 0) ? c
: DesktopPath
->Buffer
);
198 DesktopPresent
= TRUE
;
204 /* search the process handle table for (inherited) window station
205 handles, use a more appropriate one than WinSta0 if possible. */
206 Status
= ObFindHandleForObject(Process
,
208 ExWindowStationObjectType
,
211 if(!NT_SUCCESS(Status
))
213 /* we had no luck searching for opened handles, use WinSta0 now */
214 RtlInitUnicodeString(&WinSta
, L
"WinSta0");
218 if(!DesktopPresent
&& hDesktop
!= NULL
)
220 /* search the process handle table for (inherited) desktop
221 handles, use a more appropriate one than Default if possible. */
222 Status
= ObFindHandleForObject(Process
,
227 if(!NT_SUCCESS(Status
))
229 /* we had no luck searching for opened handles, use Desktop now */
230 RtlInitUnicodeString(&Desktop
, L
"Default");
236 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, NULL
))
238 return STATUS_INSUFFICIENT_RESOURCES
;
241 /* open the window station */
242 InitializeObjectAttributes(&ObjectAttributes
,
244 OBJ_CASE_INSENSITIVE
,
248 Status
= ObOpenObjectByName(&ObjectAttributes
,
249 ExWindowStationObjectType
,
256 RtlFreeUnicodeString(&FullName
);
258 if(!NT_SUCCESS(Status
))
260 SetLastNtError(Status
);
261 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta
, PsGetCurrentProcessId());
266 if(hDesktop
!= NULL
&& *hDesktop
== NULL
)
268 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, &Desktop
))
272 return STATUS_INSUFFICIENT_RESOURCES
;
275 /* open the desktop object */
276 InitializeObjectAttributes(&ObjectAttributes
,
278 OBJ_CASE_INSENSITIVE
,
282 Status
= ObOpenObjectByName(&ObjectAttributes
,
290 RtlFreeUnicodeString(&FullName
);
292 if(!NT_SUCCESS(Status
))
297 SetLastNtError(Status
);
298 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop
, PsGetCurrentProcessId());
303 return STATUS_SUCCESS
;
307 * IntValidateDesktopHandle
309 * Validates the desktop handle.
312 * If the function succeeds, the handle remains referenced. If the
313 * fucntion fails, last error is set.
317 IntValidateDesktopHandle(
319 KPROCESSOR_MODE AccessMode
,
320 ACCESS_MASK DesiredAccess
,
321 PDESKTOP_OBJECT
*Object
)
325 Status
= ObReferenceObjectByHandle(
333 if (!NT_SUCCESS(Status
))
334 SetLastNtError(Status
);
340 IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop
, PRECT Rect
)
346 Ret
= &Desktop
->WorkArea
;
347 if((Ret
->right
== -1) && ScreenDeviceContext
)
350 BITMAPOBJ
*BitmapObj
;
351 dc
= DC_LockDc(ScreenDeviceContext
);
352 /* FIXME - Handle dc == NULL!!!! */
353 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
356 Ret
->right
= BitmapObj
->SurfObj
.sizlBitmap
.cx
;
357 Ret
->bottom
= BitmapObj
->SurfObj
.sizlBitmap
.cy
;
358 BITMAPOBJ_UnlockBitmap(BitmapObj
);
369 PDESKTOP_OBJECT FASTCALL
370 IntGetActiveDesktop(VOID
)
376 * returns or creates a handle to the desktop object
379 IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject
)
384 ASSERT(DesktopObject
);
386 Status
= ObFindHandleForObject(PsGetCurrentProcess(),
392 if(!NT_SUCCESS(Status
))
394 Status
= ObOpenObjectByPointer(DesktopObject
,
401 if(!NT_SUCCESS(Status
))
403 /* unable to create a handle */
404 DPRINT1("Unable to create a desktop handle\n");
412 PUSER_MESSAGE_QUEUE FASTCALL
413 IntGetFocusMessageQueue(VOID
)
415 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
418 DPRINT("No active desktop\n");
421 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
425 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
427 PUSER_MESSAGE_QUEUE Old
;
428 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
431 DPRINT("No active desktop\n");
436 if(NewQueue
->Desktop
!= NULL
)
438 DPRINT("Message Queue already attached to another desktop!\n");
441 IntReferenceMessageQueue(NewQueue
);
442 InterlockedExchange((LONG
*)&NewQueue
->Desktop
, (LONG
)pdo
);
444 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchange((LONG
*)&pdo
->ActiveMessageQueue
, (LONG
)NewQueue
);
447 InterlockedExchange((LONG
*)&Old
->Desktop
, 0);
448 IntDereferenceMessageQueue(Old
);
452 HWND FASTCALL
IntGetDesktopWindow(VOID
)
454 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
457 DPRINT("No active desktop\n");
460 return pdo
->DesktopWindow
;
463 PWINDOW_OBJECT FASTCALL
UserGetDesktopWindow(VOID
)
465 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
469 DPRINT("No active desktop\n");
473 return UserGetWindowObject(pdo
->DesktopWindow
);
477 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
479 PDESKTOP_OBJECT pdo
= PsGetWin32Thread()->Desktop
;
482 DPRINT1("Thread doesn't have a desktop\n");
485 return pdo
->DesktopWindow
;
488 BOOL FASTCALL
IntDesktopUpdatePerUserSettings(BOOL bEnable
)
492 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
495 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
497 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
498 QueryTable
[0].Name
= L
"PaintDesktopVersion";
499 QueryTable
[0].EntryContext
= &g_PaintDesktopVersion
;
501 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
502 Status
= RtlQueryRegistryValues(RTL_REGISTRY_USER
,
503 L
"Control Panel\\Desktop",
504 QueryTable
, NULL
, NULL
);
505 if (!NT_SUCCESS(Status
))
507 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
509 g_PaintDesktopVersion
= FALSE
;
513 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion
);
519 g_PaintDesktopVersion
= FALSE
;
524 /* PUBLIC FUNCTIONS ***********************************************************/
527 co_IntShowDesktop(PDESKTOP_OBJECT Desktop
, ULONG Width
, ULONG Height
)
529 CSR_API_MESSAGE Request
;
531 Request
.Type
= MAKE_CSR_API(SHOW_DESKTOP
, CSR_GUI
);
532 Request
.Data
.ShowDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
533 Request
.Data
.ShowDesktopRequest
.Width
= Width
;
534 Request
.Data
.ShowDesktopRequest
.Height
= Height
;
536 return co_CsrNotify(&Request
);
540 IntHideDesktop(PDESKTOP_OBJECT Desktop
)
543 CSRSS_API_REQUEST Request
;
544 CSRSS_API_REPLY Reply
;
546 Request
.Type
= CSRSS_HIDE_DESKTOP
;
547 Request
.Data
.HideDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
549 return NotifyCsrss(&Request
, &Reply
);
552 PWINDOW_OBJECT DesktopWindow
;
554 DesktopWindow
= IntGetWindowObject(Desktop
->DesktopWindow
);
557 return ERROR_INVALID_WINDOW_HANDLE
;
559 DesktopWindow
->Style
&= ~WS_VISIBLE
;
561 return STATUS_SUCCESS
;
566 * Send the Message to the windows registered for ShellHook
567 * notifications. The lParam contents depend on the Message. See
568 * MSDN for more details (RegisterShellHookWindow)
570 VOID
co_IntShellHookNotify(WPARAM Message
, LPARAM lParam
)
572 PDESKTOP_OBJECT Desktop
= IntGetActiveDesktop();
573 PLIST_ENTRY Entry
, Entry2
;
574 PSHELL_HOOK_WINDOW Current
;
577 static UINT MsgType
= 0;
582 /* Too bad, this doesn't work.*/
585 RtlInitUnicodeString(&Str
, L
"SHELLHOOK");
586 MsgType
= UserRegisterWindowMessage(&Str
);
589 MsgType
= IntAddAtom(L
"SHELLHOOK");
591 DPRINT("MsgType = %x\n", MsgType
);
593 DPRINT1("LastError: %x\n", GetLastNtError());
598 DPRINT1("IntShellHookNotify: No desktop!\n");
602 /* We have to do some tricks because the list could change
603 * between calls, and we can't keep the lock during the call
606 KeAcquireSpinLock(&Desktop
->Lock
, &OldLevel
);
607 Entry
= Desktop
->ShellHookWindows
.Flink
;
608 while (Entry
!= &Desktop
->ShellHookWindows
)
610 Current
= CONTAINING_RECORD(Entry
, SHELL_HOOK_WINDOW
, ListEntry
);
611 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
613 DPRINT("Sending notify\n");
614 co_IntPostOrSendMessage(Current
->hWnd
,
619 /* Loop again to find the window we were sending to. If it doesn't
620 * exist anymore, we just stop. This could leave an infinite loop
621 * if a window is removed and readded to the list. That's quite
625 KeAcquireSpinLock(&Desktop
->Lock
, &OldLevel
);
626 Entry2
= Desktop
->ShellHookWindows
.Flink
;
627 while (Entry2
!= Entry
&&
628 Entry2
!= &Desktop
->ShellHookWindows
)
630 Entry2
= Entry2
->Flink
;
634 Entry
= Entry
->Flink
;
638 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
642 * Add the window to the ShellHookWindows list. The windows
643 * on that list get notifications that are important to shell
646 * TODO: Validate the window? I'm not sure if sending these messages to
647 * an unsuspecting application that is not your own is a nice thing to do.
649 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
651 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
;
652 PSHELL_HOOK_WINDOW Entry
;
655 DPRINT("IntRegisterShellHookWindow\n");
657 /* First deregister the window, so we can be sure it's never twice in the
660 IntDeRegisterShellHookWindow(hWnd
);
662 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
663 sizeof(SHELL_HOOK_WINDOW
),
665 /* We have to walk this structure with while holding a spinlock, so we
666 * need NonPagedPool */
673 KeAcquireSpinLock(&Desktop
->Lock
, &OldLevel
);
674 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
675 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
681 * Remove the window from the ShellHookWindows list. The windows
682 * on that list get notifications that are important to shell
685 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
687 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
;
689 PSHELL_HOOK_WINDOW Current
;
692 KeAcquireSpinLock(&Desktop
->Lock
, &OldLevel
);
694 Entry
= Desktop
->ShellHookWindows
.Flink
;
695 while (Entry
!= &Desktop
->ShellHookWindows
)
697 Current
= CONTAINING_RECORD(Entry
, SHELL_HOOK_WINDOW
, ListEntry
);
698 if (Current
->hWnd
== hWnd
)
700 RemoveEntryList(Entry
);
701 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
705 Entry
= Entry
->Flink
;
708 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
714 * NtUserCreateDesktop
716 * Creates a new desktop.
720 * Name of the new desktop.
726 * Requested type of access.
729 * Security descriptor.
732 * Handle to window station on which to create the desktop.
735 * If the function succeeds, the return value is a handle to the newly
736 * created desktop. If the specified desktop already exists, the function
737 * succeeds and returns a handle to the existing desktop. When you are
738 * finished using the handle, call the CloseDesktop function to close it.
739 * If the function fails, the return value is NULL.
747 PUNICODE_STRING lpszDesktopName
,
749 ACCESS_MASK dwDesiredAccess
,
750 LPSECURITY_ATTRIBUTES lpSecurity
,
751 HWINSTA hWindowStation
)
753 OBJECT_ATTRIBUTES ObjectAttributes
;
754 PWINSTATION_OBJECT WinStaObject
;
755 PDESKTOP_OBJECT DesktopObject
;
756 UNICODE_STRING DesktopName
;
759 CSR_API_MESSAGE Request
;
760 DECLARE_RETURN(HDESK
);
762 DPRINT("Enter CreateDesktop: %wZ\n", lpszDesktopName
);
763 UserEnterExclusive();
765 Status
= IntValidateWindowStationHandle(
768 0, /* FIXME - WINSTA_CREATEDESKTOP */
771 if (! NT_SUCCESS(Status
))
773 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
774 hWindowStation
, lpszDesktopName
);
775 SetLastNtError(Status
);
779 if (! IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
782 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
783 ObDereferenceObject(WinStaObject
);
787 ObDereferenceObject(WinStaObject
);
790 * Try to open already existing desktop
793 DPRINT1("Trying to open desktop (%wZ)\n", &DesktopName
);
795 /* Initialize ObjectAttributes for the desktop object */
796 InitializeObjectAttributes(
803 Status
= ObOpenObjectByName(
812 if (NT_SUCCESS(Status
))
814 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
815 ExFreePool(DesktopName
.Buffer
);
820 * No existing desktop found, try to create new one
823 Status
= ObCreateObject(
829 sizeof(DESKTOP_OBJECT
),
832 (PVOID
*)&DesktopObject
);
834 if (! NT_SUCCESS(Status
))
836 DPRINT1("Failed creating desktop (%wZ)\n", &DesktopName
);
837 ExFreePool(DesktopName
.Buffer
);
838 SetLastNtError(STATUS_UNSUCCESSFUL
);
843 DesktopObject
->WorkArea
.left
= 0;
844 DesktopObject
->WorkArea
.top
= 0;
845 DesktopObject
->WorkArea
.right
= -1;
846 DesktopObject
->WorkArea
.bottom
= -1;
847 IntGetDesktopWorkArea(DesktopObject
, NULL
);
849 /* Initialize some local (to win32k) desktop state. */
850 DesktopObject
->ActiveMessageQueue
= NULL
;
852 Status
= ObInsertObject(
853 (PVOID
)DesktopObject
,
855 STANDARD_RIGHTS_REQUIRED
,
860 ObDereferenceObject(DesktopObject
);
861 ExFreePool(DesktopName
.Buffer
);
863 if (! NT_SUCCESS(Status
))
865 DPRINT1("Failed to create desktop handle\n");
866 SetLastNtError(Status
);
871 * Create a handle for CSRSS and notify CSRSS
873 Request
.Type
= MAKE_CSR_API(CREATE_DESKTOP
, CSR_GUI
);
874 Status
= CsrInsertObject(Desktop
,
876 (HANDLE
*)&Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
877 if (! NT_SUCCESS(Status
))
879 DPRINT1("Failed to create desktop handle for CSRSS\n");
881 SetLastNtError(Status
);
885 Status
= co_CsrNotify(&Request
);
886 if (! NT_SUCCESS(Status
))
888 CsrCloseHandle(Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
889 DPRINT1("Failed to notify CSRSS about new desktop\n");
891 SetLastNtError(Status
);
898 DPRINT("Leave NtUserCreateDesktop, ret=%i\n",_ret_
);
906 * Opens an existing desktop.
910 * Name of the existing desktop.
916 * Requested type of access.
919 * Handle to the desktop or zero on failure.
927 PUNICODE_STRING lpszDesktopName
,
929 ACCESS_MASK dwDesiredAccess
)
931 OBJECT_ATTRIBUTES ObjectAttributes
;
932 PWINSTATION_OBJECT WinStaObject
;
933 UNICODE_STRING DesktopName
;
936 DECLARE_RETURN(HDESK
);
938 DPRINT("Enter NtUserOpenDesktop: %wZ\n", lpszDesktopName
);
939 UserEnterExclusive();
942 * Validate the window station handle and compose the fully
943 * qualified desktop name
946 Status
= IntValidateWindowStationHandle(
947 PsGetCurrentProcess()->Win32WindowStation
,
952 if (!NT_SUCCESS(Status
))
954 DPRINT1("Failed validation of window station handle (0x%X)\n",
955 PsGetCurrentProcess()->Win32WindowStation
);
956 SetLastNtError(Status
);
960 if (!IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
963 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
964 ObDereferenceObject(WinStaObject
);
968 ObDereferenceObject(WinStaObject
);
970 DPRINT1("Trying to open desktop (%wZ)\n", &DesktopName
);
972 /* Initialize ObjectAttributes for the desktop object */
973 InitializeObjectAttributes(
980 Status
= ObOpenObjectByName(
989 if (!NT_SUCCESS(Status
))
991 SetLastNtError(Status
);
992 ExFreePool(DesktopName
.Buffer
);
996 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
997 ExFreePool(DesktopName
.Buffer
);
1002 DPRINT("Leave NtUserOpenDesktop, ret=%i\n",_ret_
);
1008 * NtUserOpenInputDesktop
1010 * Opens the input (interactive) desktop.
1014 * Interaction flags.
1017 * Inheritance option.
1020 * Requested type of access.
1023 * Handle to the input desktop or zero on failure.
1030 NtUserOpenInputDesktop(
1033 ACCESS_MASK dwDesiredAccess
)
1035 PDESKTOP_OBJECT Object
;
1039 DPRINT("About to open input desktop\n");
1041 /* Get a pointer to the desktop object */
1043 Status
= IntValidateDesktopHandle(
1049 if (!NT_SUCCESS(Status
))
1051 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop
);
1055 /* Create a new handle to the object */
1057 Status
= ObOpenObjectByPointer(
1062 ExDesktopObjectType
,
1066 ObDereferenceObject(Object
);
1068 if (NT_SUCCESS(Status
))
1070 DPRINT("Successfully opened input desktop\n");
1071 return (HDESK
)Desktop
;
1074 SetLastNtError(Status
);
1079 * NtUserCloseDesktop
1081 * Closes a desktop handle.
1085 * Handle to the desktop.
1091 * The desktop handle can be created with NtUserCreateDesktop or
1092 * NtUserOpenDesktop. This function will fail if any thread in the calling
1093 * process is using the specified desktop handle or if the handle refers
1094 * to the initial desktop of the calling process.
1101 NtUserCloseDesktop(HDESK hDesktop
)
1103 PDESKTOP_OBJECT Object
;
1106 DPRINT("About to close desktop handle (0x%X)\n", hDesktop
);
1108 Status
= IntValidateDesktopHandle(
1114 if (!NT_SUCCESS(Status
))
1116 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1120 ObDereferenceObject(Object
);
1122 DPRINT("Closing desktop handle (0x%X)\n", hDesktop
);
1124 Status
= ZwClose(hDesktop
);
1125 if (!NT_SUCCESS(Status
))
1127 SetLastNtError(Status
);
1135 static int GetSystemVersionString(LPWSTR buffer
)
1137 RTL_OSVERSIONINFOEXW versionInfo
;
1140 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
1142 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
1145 if (versionInfo
.dwMajorVersion
<= 4)
1146 len
= swprintf(buffer
,
1147 L
"ReactOS Version %d.%d %s Build %d",
1148 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
1149 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
1151 len
= swprintf(buffer
,
1152 L
"ReactOS %s (Build %d)",
1153 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
1159 * NtUserPaintDesktop
1161 * The NtUserPaintDesktop function fills the clipping region in the
1162 * specified device context with the desktop pattern or wallpaper. The
1163 * function is provided primarily for shell desktops.
1167 * Handle to the device context.
1174 NtUserPaintDesktop(HDC hDC
)
1177 HBRUSH DesktopBrush
, PreviousBrush
;
1179 BOOL doPatBlt
= TRUE
;
1180 PWINDOW_OBJECT WndDesktop
;
1183 PWINSTATION_OBJECT WinSta
= PsGetWin32Thread()->Desktop
->WindowStation
;
1185 IntGdiGetClipBox(hDC
, &Rect
);
1187 hWndDesktop
= IntGetDesktopWindow();
1188 if (!(WndDesktop
= UserGetWindowObject(hWndDesktop
)))
1191 DesktopBrush
= (HBRUSH
)IntGetClassLong(WndDesktop
, GCL_HBRBACKGROUND
, FALSE
); //fixme: verify retval
1195 * Paint desktop background
1198 if(WinSta
->hbmWallpaper
!= NULL
)
1200 PWINDOW_OBJECT DeskWin
;
1202 if((DeskWin
= UserGetWindowObject(hWndDesktop
)))
1208 sz
.cx
= DeskWin
->WindowRect
.right
- DeskWin
->WindowRect
.left
;
1209 sz
.cy
= DeskWin
->WindowRect
.bottom
- DeskWin
->WindowRect
.top
;
1212 x
= (sz
.cx
/ 2) - (WinSta
->cxWallpaper
/ 2);
1213 y
= (sz
.cy
/ 2) - (WinSta
->cyWallpaper
/ 2);
1215 hWallpaperDC
= NtGdiCreateCompatableDC(hDC
);
1216 if(hWallpaperDC
!= NULL
)
1222 /* FIXME - clip out the bitmap */
1223 PreviousBrush
= NtGdiSelectObject(hDC
, DesktopBrush
);
1224 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1225 NtGdiSelectObject(hDC
, PreviousBrush
);
1230 hOldBitmap
= NtGdiSelectObject(hWallpaperDC
, WinSta
->hbmWallpaper
);
1231 NtGdiBitBlt(hDC
, x
, y
, WinSta
->cxWallpaper
, WinSta
->cyWallpaper
, hWallpaperDC
, 0, 0, SRCCOPY
);
1232 NtGdiSelectObject(hWallpaperDC
, hOldBitmap
);
1234 NtGdiDeleteDC(hWallpaperDC
);
1241 PreviousBrush
= NtGdiSelectObject(hDC
, DesktopBrush
);
1242 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1243 NtGdiSelectObject(hDC
, PreviousBrush
);
1247 * Display system version on the desktop background
1250 if (g_PaintDesktopVersion
)
1252 static WCHAR s_wszVersion
[256] = {0};
1256 len
= wcslen(s_wszVersion
);
1258 len
= GetSystemVersionString(s_wszVersion
);
1262 if (!UserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0))
1264 rect
.right
= UserGetSystemMetrics(SM_CXSCREEN
);
1265 rect
.bottom
= UserGetSystemMetrics(SM_CYSCREEN
);
1268 COLORREF color_old
= NtGdiSetTextColor(hDC
, RGB(255,255,255));
1269 UINT align_old
= NtGdiSetTextAlign(hDC
, TA_RIGHT
);
1270 int mode_old
= NtGdiSetBkMode(hDC
, TRANSPARENT
);
1272 NtGdiTextOut(hDC
, rect
.right
-16, rect
.bottom
-48, s_wszVersion
, len
);
1274 NtGdiSetBkMode(hDC
, mode_old
);
1275 NtGdiSetTextAlign(hDC
, align_old
);
1276 NtGdiSetTextColor(hDC
, color_old
);
1285 * NtUserSwitchDesktop
1287 * Sets the current input (interactive) desktop.
1291 * Handle to desktop.
1301 NtUserSwitchDesktop(HDESK hDesktop
)
1303 PDESKTOP_OBJECT DesktopObject
;
1306 DPRINT("About to switch desktop (0x%X)\n", hDesktop
);
1308 Status
= IntValidateDesktopHandle(
1314 if (!NT_SUCCESS(Status
))
1316 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1321 * Don't allow applications switch the desktop if it's locked, unless the caller
1322 * is the logon application itself
1324 if((DesktopObject
->WindowStation
->Flags
& WSS_LOCKED
) &&
1325 LogonProcess
!= NULL
&& LogonProcess
!= PsGetWin32Process())
1327 ObDereferenceObject(DesktopObject
);
1328 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop
);
1332 /* FIXME: Fail if the desktop belong to an invisible window station */
1333 /* FIXME: Fail if the process is associated with a secured
1334 desktop such as Winlogon or Screen-Saver */
1335 /* FIXME: Connect to input device */
1337 /* Set the active desktop in the desktop's window station. */
1338 DesktopObject
->WindowStation
->ActiveDesktop
= DesktopObject
;
1340 /* Set the global state. */
1341 InputDesktop
= DesktopObject
;
1342 InputDesktopHandle
= hDesktop
;
1343 InputWindowStation
= DesktopObject
->WindowStation
;
1345 ObDereferenceObject(DesktopObject
);
1351 * NtUserResolveDesktopForWOW
1358 NtUserResolveDesktopForWOW(DWORD Unknown0
)
1365 * NtUserGetThreadDesktop
1372 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1376 PDESKTOP_OBJECT DesktopObject
;
1377 HDESK Ret
, hThreadDesktop
;
1378 OBJECT_HANDLE_INFORMATION HandleInformation
;
1382 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1386 Status
= PsLookupThreadByThreadId((HANDLE
)dwThreadId
, &Thread
);
1387 if(!NT_SUCCESS(Status
))
1389 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1393 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1395 /* just return the handle, we queried the desktop handle of a thread running
1396 in the same context */
1397 Ret
= Thread
->Tcb
.Win32Thread
->hDesktop
;
1398 ObDereferenceObject(Thread
);
1402 /* get the desktop handle and the desktop of the thread */
1403 if(!(hThreadDesktop
= Thread
->Tcb
.Win32Thread
->hDesktop
) ||
1404 !(DesktopObject
= Thread
->Tcb
.Win32Thread
->Desktop
))
1406 ObDereferenceObject(Thread
);
1407 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1411 /* we could just use DesktopObject instead of looking up the handle, but latter
1412 may be a bit safer (e.g. when the desktop is being destroyed */
1413 /* switch into the context of the thread we're trying to get the desktop from,
1414 so we can use the handle */
1415 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1416 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1418 ExDesktopObjectType
,
1420 (PVOID
*)&DesktopObject
,
1421 &HandleInformation
);
1424 /* the handle couldn't be found, there's nothing to get... */
1425 if(!NT_SUCCESS(Status
))
1427 ObDereferenceObject(Thread
);
1431 /* lookup our handle table if we can find a handle to the desktop object,
1432 if not, create one */
1433 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1435 /* all done, we got a valid handle to the desktop */
1436 ObDereferenceObject(DesktopObject
);
1437 ObDereferenceObject(Thread
);
1442 * NtUserSetThreadDesktop
1449 NtUserSetThreadDesktop(HDESK hDesktop
)
1451 PW32THREAD W32Thread
;
1452 PDESKTOP_OBJECT DesktopObject
;
1455 /* Validate the new desktop. */
1456 Status
= IntValidateDesktopHandle(
1462 if (!NT_SUCCESS(Status
))
1464 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1468 W32Thread
= PsGetWin32Thread();
1470 /* FIXME: Should check here to see if the thread has any windows. */
1472 if (W32Thread
->Desktop
!= NULL
)
1474 ObDereferenceObject(W32Thread
->Desktop
);
1477 W32Thread
->Desktop
= DesktopObject
;
1478 W32Thread
->hDesktop
= hDesktop
;