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 ******************************************************************/
34 /* not yet defined in w32api... */
36 ObFindHandleForObject(IN PEPROCESS Process
,
38 IN POBJECT_TYPE ObjectType
,
39 IN POBJECT_HANDLE_INFORMATION HandleInformation
,
42 #define ObFindHandleForObject(Process, Object, ObjectType, HandleInformation, Handle) \
46 /* GLOBALS *******************************************************************/
48 /* Currently active desktop */
49 PDESKTOP_OBJECT InputDesktop
= NULL
;
50 HDESK InputDesktopHandle
= NULL
;
51 HDC ScreenDeviceContext
= NULL
;
53 BOOL g_PaintDesktopVersion
= FALSE
;
55 /* INITALIZATION FUNCTIONS ****************************************************/
60 return STATUS_SUCCESS
;
64 CleanupDesktopImpl(VOID
)
66 return STATUS_SUCCESS
;
69 /* OBJECT CALLBACKS **********************************************************/
72 IntDesktopObjectCreate(PVOID ObjectBody
,
75 struct _OBJECT_ATTRIBUTES
* ObjectAttributes
)
77 PDESKTOP_OBJECT Desktop
= (PDESKTOP_OBJECT
)ObjectBody
;
78 UNICODE_STRING UnicodeString
;
80 if (RemainingPath
== NULL
)
82 return STATUS_SUCCESS
;
85 if (wcschr((RemainingPath
+ 1), '\\') != NULL
)
87 return STATUS_UNSUCCESSFUL
;
90 RtlInitUnicodeString(&UnicodeString
, (RemainingPath
+ 1));
92 DPRINT("Creating desktop (0x%X) Name (%wZ)\n", Desktop
, &UnicodeString
);
94 KeInitializeSpinLock(&Desktop
->Lock
);
95 InitializeListHead(&Desktop
->ShellHookWindows
);
97 Desktop
->WindowStation
= (PWINSTATION_OBJECT
)Parent
;
99 /* Put the desktop on the window station's list of associcated desktops */
100 ExInterlockedInsertTailList(
101 &Desktop
->WindowStation
->DesktopListHead
,
103 &Desktop
->WindowStation
->Lock
);
105 return RtlCreateUnicodeString(&Desktop
->Name
, UnicodeString
.Buffer
);
109 IntDesktopObjectDelete(PVOID DeletedObject
)
111 PDESKTOP_OBJECT Desktop
= (PDESKTOP_OBJECT
)DeletedObject
;
114 DPRINT("Deleting desktop (0x%X)\n", Desktop
);
116 /* Remove the desktop from the window station's list of associcated desktops */
117 KeAcquireSpinLock(&Desktop
->WindowStation
->Lock
, &OldIrql
);
118 RemoveEntryList(&Desktop
->ListEntry
);
119 KeReleaseSpinLock(&Desktop
->WindowStation
->Lock
, OldIrql
);
121 RtlFreeUnicodeString(&Desktop
->Name
);
124 /* PRIVATE FUNCTIONS **********************************************************/
127 IntParseDesktopPath(PEPROCESS Process
,
128 PUNICODE_STRING DesktopPath
,
132 OBJECT_ATTRIBUTES ObjectAttributes
;
133 UNICODE_STRING WinSta
, Desktop
, FullName
;
134 BOOL DesktopPresent
= FALSE
;
135 BOOL WinStaPresent
= FALSE
;
147 RtlInitUnicodeString(&WinSta
, NULL
);
148 RtlInitUnicodeString(&Desktop
, NULL
);
150 if(DesktopPath
!= NULL
&& DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
152 PWCHAR c
= DesktopPath
->Buffer
;
154 USHORT l
= DesktopPath
->Length
;
157 * Parse the desktop path string which can be in the form "WinSta\Desktop"
158 * or just "Desktop". In latter case WinSta0 will be used.
165 wl
= (ULONG_PTR
)c
- (ULONG_PTR
)DesktopPath
->Buffer
;
175 WinSta
.MaximumLength
= wl
+ sizeof(WCHAR
);
176 WinSta
.Buffer
= DesktopPath
->Buffer
;
178 WinStaPresent
= TRUE
;
182 Desktop
.Length
= DesktopPath
->Length
- wl
;
185 Desktop
.Length
-= sizeof(WCHAR
);
187 if(Desktop
.Length
> 0)
189 Desktop
.MaximumLength
= Desktop
.Length
+ sizeof(WCHAR
);
190 Desktop
.Buffer
= ((wl
> 0) ? c
: DesktopPath
->Buffer
);
191 DesktopPresent
= TRUE
;
197 /* search the process handle table for (inherited) window station
198 handles, use a more appropriate one than WinSta0 if possible. */
199 Status
= ObFindHandleForObject(Process
,
201 ExWindowStationObjectType
,
204 if(!NT_SUCCESS(Status
))
206 /* we had no luck searching for opened handles, use WinSta0 now */
207 RtlInitUnicodeString(&WinSta
, L
"WinSta0");
211 if(!DesktopPresent
&& hDesktop
!= NULL
)
213 /* search the process handle table for (inherited) desktop
214 handles, use a more appropriate one than Default if possible. */
215 Status
= ObFindHandleForObject(Process
,
220 if(!NT_SUCCESS(Status
))
222 /* we had no luck searching for opened handles, use Desktop now */
223 RtlInitUnicodeString(&Desktop
, L
"Default");
229 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, NULL
))
231 return STATUS_INSUFFICIENT_RESOURCES
;
234 /* open the window station */
235 InitializeObjectAttributes(&ObjectAttributes
,
237 OBJ_CASE_INSENSITIVE
,
241 Status
= ObOpenObjectByName(&ObjectAttributes
,
242 ExWindowStationObjectType
,
249 RtlFreeUnicodeString(&FullName
);
251 if(!NT_SUCCESS(Status
))
253 SetLastNtError(Status
);
254 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta
, PsGetCurrentProcessId());
259 if(hDesktop
!= NULL
&& *hDesktop
== NULL
)
261 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, &Desktop
))
265 return STATUS_INSUFFICIENT_RESOURCES
;
268 /* open the desktop object */
269 InitializeObjectAttributes(&ObjectAttributes
,
271 OBJ_CASE_INSENSITIVE
,
275 Status
= ObOpenObjectByName(&ObjectAttributes
,
283 RtlFreeUnicodeString(&FullName
);
285 if(!NT_SUCCESS(Status
))
290 SetLastNtError(Status
);
291 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop
, PsGetCurrentProcessId());
296 return STATUS_SUCCESS
;
300 * IntValidateDesktopHandle
302 * Validates the desktop handle.
305 * If the function succeeds, the handle remains referenced. If the
306 * fucntion fails, last error is set.
310 IntValidateDesktopHandle(
312 KPROCESSOR_MODE AccessMode
,
313 ACCESS_MASK DesiredAccess
,
314 PDESKTOP_OBJECT
*Object
)
318 Status
= ObReferenceObjectByHandle(
326 if (!NT_SUCCESS(Status
))
327 SetLastNtError(Status
);
333 IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop
, PRECT Rect
)
339 Ret
= &Desktop
->WorkArea
;
340 if((Ret
->right
== -1) && ScreenDeviceContext
)
343 BITMAPOBJ
*BitmapObj
;
344 dc
= DC_LockDc(ScreenDeviceContext
);
345 /* FIXME - Handle dc == NULL!!!! */
346 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
349 Ret
->right
= BitmapObj
->SurfObj
.sizlBitmap
.cx
;
350 Ret
->bottom
= BitmapObj
->SurfObj
.sizlBitmap
.cy
;
351 BITMAPOBJ_UnlockBitmap(dc
->w
.hBitmap
);
353 DC_UnlockDc(ScreenDeviceContext
);
362 PDESKTOP_OBJECT FASTCALL
363 IntGetActiveDesktop(VOID
)
369 * returns or creates a handle to the desktop object
372 IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject
)
377 ASSERT(DesktopObject
);
379 Status
= ObFindHandleForObject(PsGetCurrentProcess(),
385 if(!NT_SUCCESS(Status
))
387 Status
= ObOpenObjectByPointer(DesktopObject
,
394 if(!NT_SUCCESS(Status
))
396 /* unable to create a handle */
397 DPRINT1("Unable to create a desktop handle\n");
405 PUSER_MESSAGE_QUEUE FASTCALL
406 IntGetFocusMessageQueue(VOID
)
408 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
411 DPRINT("No active desktop\n");
414 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
418 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
420 PUSER_MESSAGE_QUEUE Old
;
421 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
424 DPRINT("No active desktop\n");
429 if(NewQueue
->Desktop
!= NULL
)
431 DPRINT("Message Queue already attached to another desktop!\n");
434 IntReferenceMessageQueue(NewQueue
);
435 InterlockedExchange((LONG
*)&NewQueue
->Desktop
, (LONG
)pdo
);
437 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchange((LONG
*)&pdo
->ActiveMessageQueue
, (LONG
)NewQueue
);
440 InterlockedExchange((LONG
*)&Old
->Desktop
, 0);
441 IntDereferenceMessageQueue(Old
);
445 HWND FASTCALL
IntGetDesktopWindow(VOID
)
447 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
450 DPRINT("No active desktop\n");
453 return pdo
->DesktopWindow
;
456 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
458 PDESKTOP_OBJECT pdo
= PsGetWin32Thread()->Desktop
;
461 DPRINT1("Thread doesn't have a desktop\n");
464 return pdo
->DesktopWindow
;
467 BOOL FASTCALL
IntDesktopUpdatePerUserSettings(BOOL bEnable
)
471 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
474 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
476 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
477 QueryTable
[0].Name
= L
"PaintDesktopVersion";
478 QueryTable
[0].EntryContext
= &g_PaintDesktopVersion
;
480 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
481 Status
= RtlQueryRegistryValues(RTL_REGISTRY_USER
,
482 L
"Control Panel\\Desktop",
483 QueryTable
, NULL
, NULL
);
484 if (!NT_SUCCESS(Status
))
486 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
488 g_PaintDesktopVersion
= FALSE
;
492 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion
);
498 g_PaintDesktopVersion
= FALSE
;
503 /* PUBLIC FUNCTIONS ***********************************************************/
506 IntShowDesktop(PDESKTOP_OBJECT Desktop
, ULONG Width
, ULONG Height
)
508 CSRSS_API_REQUEST Request
;
509 CSRSS_API_REPLY Reply
;
511 Request
.Type
= CSRSS_SHOW_DESKTOP
;
512 Request
.Data
.ShowDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
513 Request
.Data
.ShowDesktopRequest
.Width
= Width
;
514 Request
.Data
.ShowDesktopRequest
.Height
= Height
;
516 return CsrNotify(&Request
, &Reply
);
520 IntHideDesktop(PDESKTOP_OBJECT Desktop
)
523 CSRSS_API_REQUEST Request
;
524 CSRSS_API_REPLY Reply
;
526 Request
.Type
= CSRSS_HIDE_DESKTOP
;
527 Request
.Data
.HideDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
529 return NotifyCsrss(&Request
, &Reply
);
531 PWINDOW_OBJECT DesktopWindow
;
533 DesktopWindow
= IntGetWindowObject(Desktop
->DesktopWindow
);
536 return ERROR_INVALID_WINDOW_HANDLE
;
538 DesktopWindow
->Style
&= ~WS_VISIBLE
;
540 return STATUS_SUCCESS
;
545 * Send the Message to the windows registered for ShellHook
546 * notifications. The lParam contents depend on the Message. See
547 * MSDN for more details (RegisterShellHookWindow)
549 VOID
IntShellHookNotify(WPARAM Message
, LPARAM lParam
)
551 PDESKTOP_OBJECT Desktop
= IntGetActiveDesktop();
552 PLIST_ENTRY Entry
, Entry2
;
553 PSHELL_HOOK_WINDOW Current
;
556 static UINT MsgType
= 0;
560 /* Too bad, this doesn't work.*/
563 RtlInitUnicodeString(&Str
, L
"SHELLHOOK");
564 MsgType
= NtUserRegisterWindowMessage(&Str
);
566 MsgType
= IntAddAtom(L
"SHELLHOOK");
568 DPRINT("MsgType = %x\n", MsgType
);
570 DPRINT1("LastError: %x\n", GetLastNtError());
574 DPRINT1("IntShellHookNotify: No desktop!\n");
578 /* We have to do some tricks because the list could change
579 * between calls, and we can't keep the lock during the call
582 KeAcquireSpinLock(&Desktop
->Lock
, &OldLevel
);
583 Entry
= Desktop
->ShellHookWindows
.Flink
;
584 while (Entry
!= &Desktop
->ShellHookWindows
) {
585 Current
= CONTAINING_RECORD(Entry
, SHELL_HOOK_WINDOW
, ListEntry
);
586 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
588 DPRINT("Sending notify\n");
589 IntPostOrSendMessage(Current
->hWnd
,
594 /* Loop again to find the window we were sending to. If it doesn't
595 * exist anymore, we just stop. This could leave an infinite loop
596 * if a window is removed and readded to the list. That's quite
600 KeAcquireSpinLock(&Desktop
->Lock
, &OldLevel
);
601 Entry2
= Desktop
->ShellHookWindows
.Flink
;
602 while (Entry2
!= Entry
&&
603 Entry2
!= &Desktop
->ShellHookWindows
) {
604 Entry2
= Entry2
->Flink
;
608 Entry
= Entry
->Flink
;
612 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
616 * Add the window to the ShellHookWindows list. The windows
617 * on that list get notifications that are important to shell
620 * TODO: Validate the window? I'm not sure if sending these messages to
621 * an unsuspecting application that is not your own is a nice thing to do.
623 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
625 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
;
626 PSHELL_HOOK_WINDOW Entry
;
629 DPRINT("IntRegisterShellHookWindow\n");
631 /* First deregister the window, so we can be sure it's never twice in the
634 IntDeRegisterShellHookWindow(hWnd
);
636 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
637 sizeof(SHELL_HOOK_WINDOW
),
639 /* We have to walk this structure with while holding a spinlock, so we
640 * need NonPagedPool */
647 KeAcquireSpinLock(&Desktop
->Lock
, &OldLevel
);
648 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
649 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
655 * Remove the window from the ShellHookWindows list. The windows
656 * on that list get notifications that are important to shell
659 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
661 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
;
663 PSHELL_HOOK_WINDOW Current
;
666 KeAcquireSpinLock(&Desktop
->Lock
, &OldLevel
);
668 Entry
= Desktop
->ShellHookWindows
.Flink
;
669 while (Entry
!= &Desktop
->ShellHookWindows
) {
670 Current
= CONTAINING_RECORD(Entry
, SHELL_HOOK_WINDOW
, ListEntry
);
671 if (Current
->hWnd
== hWnd
) {
672 RemoveEntryList(Entry
);
673 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
677 Entry
= Entry
->Flink
;
680 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
686 * NtUserCreateDesktop
688 * Creates a new desktop.
692 * Name of the new desktop.
698 * Requested type of access.
701 * Security descriptor.
704 * Handle to window station on which to create the desktop.
707 * If the function succeeds, the return value is a handle to the newly
708 * created desktop. If the specified desktop already exists, the function
709 * succeeds and returns a handle to the existing desktop. When you are
710 * finished using the handle, call the CloseDesktop function to close it.
711 * If the function fails, the return value is NULL.
719 PUNICODE_STRING lpszDesktopName
,
721 ACCESS_MASK dwDesiredAccess
,
722 LPSECURITY_ATTRIBUTES lpSecurity
,
723 HWINSTA hWindowStation
)
725 OBJECT_ATTRIBUTES ObjectAttributes
;
726 PWINSTATION_OBJECT WinStaObject
;
727 PDESKTOP_OBJECT DesktopObject
;
728 UNICODE_STRING DesktopName
;
731 CSRSS_API_REQUEST Request
;
732 CSRSS_API_REPLY Reply
;
734 DPRINT("CreateDesktop: %wZ\n", lpszDesktopName
);
736 Status
= IntValidateWindowStationHandle(
739 0, /* FIXME - WINSTA_CREATEDESKTOP */
742 if (! NT_SUCCESS(Status
))
744 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
745 hWindowStation
, lpszDesktopName
);
746 SetLastNtError(Status
);
750 if (! IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
753 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
754 ObDereferenceObject(WinStaObject
);
758 ObDereferenceObject(WinStaObject
);
761 * Try to open already existing desktop
764 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName
);
766 /* Initialize ObjectAttributes for the desktop object */
767 InitializeObjectAttributes(
774 Status
= ObOpenObjectByName(
783 if (NT_SUCCESS(Status
))
785 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
786 ExFreePool(DesktopName
.Buffer
);
791 * No existing desktop found, try to create new one
794 Status
= ObCreateObject(
800 sizeof(DESKTOP_OBJECT
),
803 (PVOID
*)&DesktopObject
);
805 if (! NT_SUCCESS(Status
))
807 DPRINT1("Failed creating desktop (%wZ)\n", &DesktopName
);
808 ExFreePool(DesktopName
.Buffer
);
809 SetLastNtError(STATUS_UNSUCCESSFUL
);
814 DesktopObject
->WorkArea
.left
= 0;
815 DesktopObject
->WorkArea
.top
= 0;
816 DesktopObject
->WorkArea
.right
= -1;
817 DesktopObject
->WorkArea
.bottom
= -1;
818 IntGetDesktopWorkArea(DesktopObject
, NULL
);
820 /* Initialize some local (to win32k) desktop state. */
821 DesktopObject
->ActiveMessageQueue
= NULL
;
823 Status
= ObInsertObject(
824 (PVOID
)DesktopObject
,
826 STANDARD_RIGHTS_REQUIRED
,
831 ObDereferenceObject(DesktopObject
);
832 ExFreePool(DesktopName
.Buffer
);
834 if (! NT_SUCCESS(Status
))
836 DPRINT1("Failed to create desktop handle\n");
837 SetLastNtError(Status
);
842 * Create a handle for CSRSS and notify CSRSS
844 Request
.Type
= CSRSS_CREATE_DESKTOP
;
845 Status
= CsrInsertObject((PVOID
)DesktopObject
,
850 (HANDLE
*)&Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
851 if (! NT_SUCCESS(Status
))
853 DPRINT1("Failed to create desktop handle for CSRSS\n");
855 SetLastNtError(Status
);
859 Status
= CsrNotify(&Request
, &Reply
);
860 if (! NT_SUCCESS(Status
))
862 CsrCloseHandle(Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
863 DPRINT1("Failed to notify CSRSS about new desktop\n");
865 SetLastNtError(Status
);
875 * Opens an existing desktop.
879 * Name of the existing desktop.
885 * Requested type of access.
888 * Handle to the desktop or zero on failure.
896 PUNICODE_STRING lpszDesktopName
,
898 ACCESS_MASK dwDesiredAccess
)
900 OBJECT_ATTRIBUTES ObjectAttributes
;
901 PWINSTATION_OBJECT WinStaObject
;
902 UNICODE_STRING DesktopName
;
907 * Validate the window station handle and compose the fully
908 * qualified desktop name
911 Status
= IntValidateWindowStationHandle(
912 PsGetCurrentProcess()->Win32WindowStation
,
917 if (!NT_SUCCESS(Status
))
919 DPRINT1("Failed validation of window station handle (0x%X)\n",
920 PsGetCurrentProcess()->Win32WindowStation
);
921 SetLastNtError(Status
);
925 if (!IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
928 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
929 ObDereferenceObject(WinStaObject
);
933 ObDereferenceObject(WinStaObject
);
935 DPRINT1("Trying to open desktop (%wZ)\n", &DesktopName
);
937 /* Initialize ObjectAttributes for the desktop object */
938 InitializeObjectAttributes(
945 Status
= ObOpenObjectByName(
954 if (!NT_SUCCESS(Status
))
956 SetLastNtError(Status
);
957 ExFreePool(DesktopName
.Buffer
);
961 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
962 ExFreePool(DesktopName
.Buffer
);
968 * NtUserOpenInputDesktop
970 * Opens the input (interactive) desktop.
977 * Inheritance option.
980 * Requested type of access.
983 * Handle to the input desktop or zero on failure.
990 NtUserOpenInputDesktop(
993 ACCESS_MASK dwDesiredAccess
)
995 PDESKTOP_OBJECT Object
;
999 DPRINT("About to open input desktop\n");
1001 /* Get a pointer to the desktop object */
1003 Status
= IntValidateDesktopHandle(
1009 if (!NT_SUCCESS(Status
))
1011 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop
);
1015 /* Create a new handle to the object */
1017 Status
= ObOpenObjectByPointer(
1022 ExDesktopObjectType
,
1026 ObDereferenceObject(Object
);
1028 if (NT_SUCCESS(Status
))
1030 DPRINT("Successfully opened input desktop\n");
1031 return (HDESK
)Desktop
;
1034 SetLastNtError(Status
);
1039 * NtUserCloseDesktop
1041 * Closes a desktop handle.
1045 * Handle to the desktop.
1051 * The desktop handle can be created with NtUserCreateDesktop or
1052 * NtUserOpenDesktop. This function will fail if any thread in the calling
1053 * process is using the specified desktop handle or if the handle refers
1054 * to the initial desktop of the calling process.
1061 NtUserCloseDesktop(HDESK hDesktop
)
1063 PDESKTOP_OBJECT Object
;
1066 DPRINT("About to close desktop handle (0x%X)\n", hDesktop
);
1068 Status
= IntValidateDesktopHandle(
1074 if (!NT_SUCCESS(Status
))
1076 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1080 ObDereferenceObject(Object
);
1082 DPRINT("Closing desktop handle (0x%X)\n", hDesktop
);
1084 Status
= ZwClose(hDesktop
);
1085 if (!NT_SUCCESS(Status
))
1087 SetLastNtError(Status
);
1095 static int GetSystemVersionString(LPWSTR buffer
)
1097 RTL_OSVERSIONINFOEXW versionInfo
;
1100 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
1102 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
1105 if (versionInfo
.dwMajorVersion
<= 4)
1106 len
= swprintf(buffer
,
1107 L
"ReactOS Version %d.%d %s Build %d",
1108 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
1109 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
1111 len
= swprintf(buffer
,
1112 L
"ReactOS %s (Build %d)",
1113 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
1119 * NtUserPaintDesktop
1121 * The NtUserPaintDesktop function fills the clipping region in the
1122 * specified device context with the desktop pattern or wallpaper. The
1123 * function is provided primarily for shell desktops.
1127 * Handle to the device context.
1134 NtUserPaintDesktop(HDC hDC
)
1137 HBRUSH DesktopBrush
, PreviousBrush
;
1139 BOOL doPatBlt
= TRUE
;
1142 PWINSTATION_OBJECT WinSta
= PsGetWin32Thread()->Desktop
->WindowStation
;
1144 IntGdiGetClipBox(hDC
, &Rect
);
1146 hWndDesktop
= IntGetDesktopWindow();
1147 DesktopBrush
= (HBRUSH
)NtUserGetClassLong(hWndDesktop
, GCL_HBRBACKGROUND
, FALSE
);
1150 * Paint desktop background
1153 if(WinSta
->hbmWallpaper
!= NULL
)
1155 PWINDOW_OBJECT DeskWin
;
1157 if((DeskWin
= IntGetWindowObject(hWndDesktop
)))
1163 sz
.cx
= DeskWin
->WindowRect
.right
- DeskWin
->WindowRect
.left
;
1164 sz
.cy
= DeskWin
->WindowRect
.bottom
- DeskWin
->WindowRect
.top
;
1165 IntReleaseWindowObject(DeskWin
);
1167 x
= (sz
.cx
/ 2) - (WinSta
->cxWallpaper
/ 2);
1168 y
= (sz
.cy
/ 2) - (WinSta
->cyWallpaper
/ 2);
1170 hWallpaperDC
= NtGdiCreateCompatableDC(hDC
);
1171 if(hWallpaperDC
!= NULL
)
1177 /* FIXME - clip out the bitmap */
1178 PreviousBrush
= NtGdiSelectObject(hDC
, DesktopBrush
);
1179 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1180 NtGdiSelectObject(hDC
, PreviousBrush
);
1185 hOldBitmap
= NtGdiSelectObject(hWallpaperDC
, WinSta
->hbmWallpaper
);
1186 NtGdiBitBlt(hDC
, x
, y
, WinSta
->cxWallpaper
, WinSta
->cyWallpaper
, hWallpaperDC
, 0, 0, SRCCOPY
);
1187 NtGdiSelectObject(hWallpaperDC
, hOldBitmap
);
1189 NtGdiDeleteDC(hWallpaperDC
);
1195 PreviousBrush
= NtGdiSelectObject(hDC
, DesktopBrush
);
1196 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1197 NtGdiSelectObject(hDC
, PreviousBrush
);
1201 * Display system version on the desktop background
1204 if (g_PaintDesktopVersion
) {
1205 static WCHAR s_wszVersion
[256] = {0};
1209 len
= wcslen(s_wszVersion
);
1211 len
= GetSystemVersionString(s_wszVersion
);
1214 if (!NtUserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0)) {
1215 rect
.right
= NtUserGetSystemMetrics(SM_CXSCREEN
);
1216 rect
.bottom
= NtUserGetSystemMetrics(SM_CYSCREEN
);
1219 COLORREF color_old
= NtGdiSetTextColor(hDC
, RGB(255,255,255));
1220 UINT align_old
= NtGdiSetTextAlign(hDC
, TA_RIGHT
);
1221 int mode_old
= NtGdiSetBkMode(hDC
, TRANSPARENT
);
1223 NtGdiTextOut(hDC
, rect
.right
-16, rect
.bottom
-48, s_wszVersion
, len
);
1225 NtGdiSetBkMode(hDC
, mode_old
);
1226 NtGdiSetTextAlign(hDC
, align_old
);
1227 NtGdiSetTextColor(hDC
, color_old
);
1236 * NtUserSwitchDesktop
1238 * Sets the current input (interactive) desktop.
1242 * Handle to desktop.
1252 NtUserSwitchDesktop(HDESK hDesktop
)
1254 PDESKTOP_OBJECT DesktopObject
;
1257 DPRINT("About to switch desktop (0x%X)\n", hDesktop
);
1259 Status
= IntValidateDesktopHandle(
1265 if (!NT_SUCCESS(Status
))
1267 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1272 * Don't allow applications switch the desktop if it's locked, unless the caller
1273 * is the logon application itself
1275 if((DesktopObject
->WindowStation
->Flags
& WSS_LOCKED
) &&
1276 LogonProcess
!= NULL
&& LogonProcess
!= PsGetWin32Process())
1278 ObDereferenceObject(DesktopObject
);
1279 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop
);
1283 /* FIXME: Fail if the desktop belong to an invisible window station */
1284 /* FIXME: Fail if the process is associated with a secured
1285 desktop such as Winlogon or Screen-Saver */
1286 /* FIXME: Connect to input device */
1288 /* Set the active desktop in the desktop's window station. */
1289 DesktopObject
->WindowStation
->ActiveDesktop
= DesktopObject
;
1291 /* Set the global state. */
1292 InputDesktop
= DesktopObject
;
1293 InputDesktopHandle
= hDesktop
;
1294 InputWindowStation
= DesktopObject
->WindowStation
;
1296 ObDereferenceObject(DesktopObject
);
1302 * NtUserResolveDesktopForWOW
1309 NtUserResolveDesktopForWOW(DWORD Unknown0
)
1316 * NtUserGetThreadDesktop
1323 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1327 PDESKTOP_OBJECT DesktopObject
;
1328 HDESK Ret
, hThreadDesktop
;
1329 OBJECT_HANDLE_INFORMATION HandleInformation
;
1333 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1337 Status
= PsLookupThreadByThreadId((HANDLE
)dwThreadId
, &Thread
);
1338 if(!NT_SUCCESS(Status
))
1340 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1344 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1346 /* just return the handle, we queried the desktop handle of a thread running
1347 in the same context */
1348 Ret
= Thread
->Tcb
.Win32Thread
->hDesktop
;
1349 ObDereferenceObject(Thread
);
1353 /* get the desktop handle and the desktop of the thread */
1354 if(!(hThreadDesktop
= Thread
->Tcb
.Win32Thread
->hDesktop
) ||
1355 !(DesktopObject
= Thread
->Tcb
.Win32Thread
->Desktop
))
1357 ObDereferenceObject(Thread
);
1358 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1362 /* we could just use DesktopObject instead of looking up the handle, but latter
1363 may be a bit safer (e.g. when the desktop is being destroyed */
1364 /* switch into the context of the thread we're trying to get the desktop from,
1365 so we can use the handle */
1366 KeAttachProcess(Thread
->ThreadsProcess
);
1367 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1369 ExDesktopObjectType
,
1371 (PVOID
*)&DesktopObject
,
1372 &HandleInformation
);
1375 /* the handle couldn't be found, there's nothing to get... */
1376 if(!NT_SUCCESS(Status
))
1378 ObDereferenceObject(Thread
);
1382 /* lookup our handle table if we can find a handle to the desktop object,
1383 if not, create one */
1384 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1386 /* all done, we got a valid handle to the desktop */
1387 ObDereferenceObject(DesktopObject
);
1388 ObDereferenceObject(Thread
);
1393 * NtUserSetThreadDesktop
1400 NtUserSetThreadDesktop(HDESK hDesktop
)
1402 PW32THREAD W32Thread
;
1403 PDESKTOP_OBJECT DesktopObject
;
1406 /* Validate the new desktop. */
1407 Status
= IntValidateDesktopHandle(
1413 if (!NT_SUCCESS(Status
))
1415 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1419 W32Thread
= PsGetWin32Thread();
1421 /* FIXME: Should check here to see if the thread has any windows. */
1423 if (W32Thread
->Desktop
!= NULL
)
1425 ObDereferenceObject(W32Thread
->Desktop
);
1428 W32Thread
->Desktop
= DesktopObject
;
1429 W32Thread
->hDesktop
= hDesktop
;