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 ******************************************************************/
33 /* GLOBALS *******************************************************************/
35 /* Currently active desktop */
36 PDESKTOP_OBJECT InputDesktop
= NULL
;
37 HDESK InputDesktopHandle
= NULL
;
38 HDC ScreenDeviceContext
= NULL
;
40 BOOL g_PaintDesktopVersion
= FALSE
;
42 /* INITALIZATION FUNCTIONS ****************************************************/
47 return STATUS_SUCCESS
;
51 CleanupDesktopImpl(VOID
)
53 return STATUS_SUCCESS
;
56 /* OBJECT CALLBACKS **********************************************************/
59 IntDesktopObjectCreate(PVOID ObjectBody
,
62 struct _OBJECT_ATTRIBUTES
* ObjectAttributes
)
64 PDESKTOP_OBJECT Desktop
= (PDESKTOP_OBJECT
)ObjectBody
;
65 UNICODE_STRING UnicodeString
;
67 DPRINT("Creating desktop (0x%X) Name (%S)\n", Desktop
, RemainingPath
);
68 if (RemainingPath
== NULL
)
70 return STATUS_SUCCESS
;
73 if (wcschr((RemainingPath
+ 1), '\\') != NULL
)
75 return STATUS_UNSUCCESSFUL
;
78 RtlInitUnicodeString(&UnicodeString
, (RemainingPath
+ 1));
82 KeInitializeSpinLock(&Desktop
->Lock
);
83 InitializeListHead(&Desktop
->ShellHookWindows
);
85 Desktop
->WindowStation
= (PWINSTATION_OBJECT
)Parent
;
87 /* Put the desktop on the window station's list of associcated desktops */
88 ExInterlockedInsertTailList(
89 &Desktop
->WindowStation
->DesktopListHead
,
91 &Desktop
->WindowStation
->Lock
);
93 return RtlCreateUnicodeString(&Desktop
->Name
, UnicodeString
.Buffer
);
97 IntDesktopObjectDelete(PVOID DeletedObject
)
99 PDESKTOP_OBJECT Desktop
= (PDESKTOP_OBJECT
)DeletedObject
;
102 DPRINT("Deleting desktop (0x%X)\n", Desktop
);
104 /* Remove the desktop from the window station's list of associcated desktops */
105 KeAcquireSpinLock(&Desktop
->WindowStation
->Lock
, &OldIrql
);
106 RemoveEntryList(&Desktop
->ListEntry
);
107 KeReleaseSpinLock(&Desktop
->WindowStation
->Lock
, OldIrql
);
109 RtlFreeUnicodeString(&Desktop
->Name
);
112 /* PRIVATE FUNCTIONS **********************************************************/
115 IntParseDesktopPath(PEPROCESS Process
,
116 PUNICODE_STRING DesktopPath
,
120 OBJECT_ATTRIBUTES ObjectAttributes
;
121 UNICODE_STRING WinSta
, Desktop
, FullName
;
122 BOOL DesktopPresent
= FALSE
;
123 BOOL WinStaPresent
= FALSE
;
135 RtlInitUnicodeString(&WinSta
, NULL
);
136 RtlInitUnicodeString(&Desktop
, NULL
);
138 if(DesktopPath
!= NULL
&& DesktopPath
->Buffer
!= NULL
&& DesktopPath
->Length
> sizeof(WCHAR
))
140 PWCHAR c
= DesktopPath
->Buffer
;
142 USHORT l
= DesktopPath
->Length
;
145 * Parse the desktop path string which can be in the form "WinSta\Desktop"
146 * or just "Desktop". In latter case WinSta0 will be used.
153 wl
= (ULONG_PTR
)c
- (ULONG_PTR
)DesktopPath
->Buffer
;
163 WinSta
.MaximumLength
= wl
+ sizeof(WCHAR
);
164 WinSta
.Buffer
= DesktopPath
->Buffer
;
166 WinStaPresent
= TRUE
;
170 Desktop
.Length
= DesktopPath
->Length
- wl
;
173 Desktop
.Length
-= sizeof(WCHAR
);
175 if(Desktop
.Length
> 0)
177 Desktop
.MaximumLength
= Desktop
.Length
+ sizeof(WCHAR
);
178 Desktop
.Buffer
= ((wl
> 0) ? c
: DesktopPath
->Buffer
);
179 DesktopPresent
= TRUE
;
185 /* search the process handle table for (inherited) window station
186 handles, use a more appropriate one than WinSta0 if possible. */
187 Status
= ObFindHandleForObject(Process
,
189 ExWindowStationObjectType
,
192 if(!NT_SUCCESS(Status
))
194 /* we had no luck searching for opened handles, use WinSta0 now */
195 RtlInitUnicodeString(&WinSta
, L
"WinSta0");
199 if(!DesktopPresent
&& hDesktop
!= NULL
)
201 /* search the process handle table for (inherited) desktop
202 handles, use a more appropriate one than Default if possible. */
203 Status
= ObFindHandleForObject(Process
,
208 if(!NT_SUCCESS(Status
))
210 /* we had no luck searching for opened handles, use Desktop now */
211 RtlInitUnicodeString(&Desktop
, L
"Default");
217 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, NULL
))
219 return STATUS_INSUFFICIENT_RESOURCES
;
222 /* open the window station */
223 InitializeObjectAttributes(&ObjectAttributes
,
225 OBJ_CASE_INSENSITIVE
,
229 Status
= ObOpenObjectByName(&ObjectAttributes
,
230 ExWindowStationObjectType
,
237 RtlFreeUnicodeString(&FullName
);
239 if(!NT_SUCCESS(Status
))
241 SetLastNtError(Status
);
242 DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta
, PsGetCurrentProcessId());
247 if(hDesktop
!= NULL
&& *hDesktop
== NULL
)
249 if(!IntGetFullWindowStationName(&FullName
, &WinSta
, &Desktop
))
253 return STATUS_INSUFFICIENT_RESOURCES
;
256 /* open the desktop object */
257 InitializeObjectAttributes(&ObjectAttributes
,
259 OBJ_CASE_INSENSITIVE
,
263 Status
= ObOpenObjectByName(&ObjectAttributes
,
271 RtlFreeUnicodeString(&FullName
);
273 if(!NT_SUCCESS(Status
))
278 SetLastNtError(Status
);
279 DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop
, PsGetCurrentProcessId());
284 return STATUS_SUCCESS
;
288 * IntValidateDesktopHandle
290 * Validates the desktop handle.
293 * If the function succeeds, the handle remains referenced. If the
294 * fucntion fails, last error is set.
298 IntValidateDesktopHandle(
300 KPROCESSOR_MODE AccessMode
,
301 ACCESS_MASK DesiredAccess
,
302 PDESKTOP_OBJECT
*Object
)
306 Status
= ObReferenceObjectByHandle(
314 if (!NT_SUCCESS(Status
))
315 SetLastNtError(Status
);
321 IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop
, PRECT Rect
)
327 Ret
= &Desktop
->WorkArea
;
328 if((Ret
->right
== -1) && ScreenDeviceContext
)
331 BITMAPOBJ
*BitmapObj
;
332 dc
= DC_LockDc(ScreenDeviceContext
);
333 /* FIXME - Handle dc == NULL!!!! */
334 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
337 Ret
->right
= BitmapObj
->SurfObj
.sizlBitmap
.cx
;
338 Ret
->bottom
= BitmapObj
->SurfObj
.sizlBitmap
.cy
;
339 BITMAPOBJ_UnlockBitmap(BitmapObj
);
350 PDESKTOP_OBJECT FASTCALL
351 IntGetActiveDesktop(VOID
)
357 * returns or creates a handle to the desktop object
360 IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject
)
365 ASSERT(DesktopObject
);
367 Status
= ObFindHandleForObject(PsGetCurrentProcess(),
373 if(!NT_SUCCESS(Status
))
375 Status
= ObOpenObjectByPointer(DesktopObject
,
382 if(!NT_SUCCESS(Status
))
384 /* unable to create a handle */
385 DPRINT1("Unable to create a desktop handle\n");
393 PUSER_MESSAGE_QUEUE FASTCALL
394 IntGetFocusMessageQueue(VOID
)
396 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
399 DPRINT("No active desktop\n");
402 return (PUSER_MESSAGE_QUEUE
)pdo
->ActiveMessageQueue
;
406 IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue
)
408 PUSER_MESSAGE_QUEUE Old
;
409 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
412 DPRINT("No active desktop\n");
417 if(NewQueue
->Desktop
!= NULL
)
419 DPRINT("Message Queue already attached to another desktop!\n");
422 IntReferenceMessageQueue(NewQueue
);
423 InterlockedExchange((LONG
*)&NewQueue
->Desktop
, (LONG
)pdo
);
425 Old
= (PUSER_MESSAGE_QUEUE
)InterlockedExchange((LONG
*)&pdo
->ActiveMessageQueue
, (LONG
)NewQueue
);
428 InterlockedExchange((LONG
*)&Old
->Desktop
, 0);
429 IntDereferenceMessageQueue(Old
);
433 HWND FASTCALL
IntGetDesktopWindow(VOID
)
435 PDESKTOP_OBJECT pdo
= IntGetActiveDesktop();
438 DPRINT("No active desktop\n");
441 return pdo
->DesktopWindow
;
444 HWND FASTCALL
IntGetCurrentThreadDesktopWindow(VOID
)
446 PDESKTOP_OBJECT pdo
= PsGetWin32Thread()->Desktop
;
449 DPRINT1("Thread doesn't have a desktop\n");
452 return pdo
->DesktopWindow
;
455 BOOL FASTCALL
IntDesktopUpdatePerUserSettings(BOOL bEnable
)
459 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
462 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
464 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
465 QueryTable
[0].Name
= L
"PaintDesktopVersion";
466 QueryTable
[0].EntryContext
= &g_PaintDesktopVersion
;
468 /* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
469 Status
= RtlQueryRegistryValues(RTL_REGISTRY_USER
,
470 L
"Control Panel\\Desktop",
471 QueryTable
, NULL
, NULL
);
472 if (!NT_SUCCESS(Status
))
474 DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
476 g_PaintDesktopVersion
= FALSE
;
480 DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion
);
486 g_PaintDesktopVersion
= FALSE
;
491 /* PUBLIC FUNCTIONS ***********************************************************/
494 IntShowDesktop(PDESKTOP_OBJECT Desktop
, ULONG Width
, ULONG Height
)
496 CSR_API_MESSAGE Request
;
498 Request
.Type
= MAKE_CSR_API(SHOW_DESKTOP
, CSR_GUI
);
499 Request
.Data
.ShowDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
500 Request
.Data
.ShowDesktopRequest
.Width
= Width
;
501 Request
.Data
.ShowDesktopRequest
.Height
= Height
;
503 return CsrNotify(&Request
);
507 IntHideDesktop(PDESKTOP_OBJECT Desktop
)
510 CSRSS_API_REQUEST Request
;
511 CSRSS_API_REPLY Reply
;
513 Request
.Type
= CSRSS_HIDE_DESKTOP
;
514 Request
.Data
.HideDesktopRequest
.DesktopWindow
= Desktop
->DesktopWindow
;
516 return NotifyCsrss(&Request
, &Reply
);
518 PWINDOW_OBJECT DesktopWindow
;
520 DesktopWindow
= IntGetWindowObject(Desktop
->DesktopWindow
);
523 return ERROR_INVALID_WINDOW_HANDLE
;
525 DesktopWindow
->Style
&= ~WS_VISIBLE
;
527 return STATUS_SUCCESS
;
532 * Send the Message to the windows registered for ShellHook
533 * notifications. The lParam contents depend on the Message. See
534 * MSDN for more details (RegisterShellHookWindow)
536 VOID
IntShellHookNotify(WPARAM Message
, LPARAM lParam
)
538 PDESKTOP_OBJECT Desktop
= IntGetActiveDesktop();
539 PLIST_ENTRY Entry
, Entry2
;
540 PSHELL_HOOK_WINDOW Current
;
543 static UINT MsgType
= 0;
547 /* Too bad, this doesn't work.*/
550 RtlInitUnicodeString(&Str
, L
"SHELLHOOK");
551 MsgType
= NtUserRegisterWindowMessage(&Str
);
553 MsgType
= IntAddAtom(L
"SHELLHOOK");
555 DPRINT("MsgType = %x\n", MsgType
);
557 DPRINT1("LastError: %x\n", GetLastNtError());
561 DPRINT1("IntShellHookNotify: No desktop!\n");
565 /* We have to do some tricks because the list could change
566 * between calls, and we can't keep the lock during the call
569 KeAcquireSpinLock(&Desktop
->Lock
, &OldLevel
);
570 Entry
= Desktop
->ShellHookWindows
.Flink
;
571 while (Entry
!= &Desktop
->ShellHookWindows
) {
572 Current
= CONTAINING_RECORD(Entry
, SHELL_HOOK_WINDOW
, ListEntry
);
573 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
575 DPRINT("Sending notify\n");
576 IntPostOrSendMessage(Current
->hWnd
,
581 /* Loop again to find the window we were sending to. If it doesn't
582 * exist anymore, we just stop. This could leave an infinite loop
583 * if a window is removed and readded to the list. That's quite
587 KeAcquireSpinLock(&Desktop
->Lock
, &OldLevel
);
588 Entry2
= Desktop
->ShellHookWindows
.Flink
;
589 while (Entry2
!= Entry
&&
590 Entry2
!= &Desktop
->ShellHookWindows
) {
591 Entry2
= Entry2
->Flink
;
595 Entry
= Entry
->Flink
;
599 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
603 * Add the window to the ShellHookWindows list. The windows
604 * on that list get notifications that are important to shell
607 * TODO: Validate the window? I'm not sure if sending these messages to
608 * an unsuspecting application that is not your own is a nice thing to do.
610 BOOL
IntRegisterShellHookWindow(HWND hWnd
)
612 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
;
613 PSHELL_HOOK_WINDOW Entry
;
616 DPRINT("IntRegisterShellHookWindow\n");
618 /* First deregister the window, so we can be sure it's never twice in the
621 IntDeRegisterShellHookWindow(hWnd
);
623 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
624 sizeof(SHELL_HOOK_WINDOW
),
626 /* We have to walk this structure with while holding a spinlock, so we
627 * need NonPagedPool */
634 KeAcquireSpinLock(&Desktop
->Lock
, &OldLevel
);
635 InsertTailList(&Desktop
->ShellHookWindows
, &Entry
->ListEntry
);
636 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
642 * Remove the window from the ShellHookWindows list. The windows
643 * on that list get notifications that are important to shell
646 BOOL
IntDeRegisterShellHookWindow(HWND hWnd
)
648 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
;
650 PSHELL_HOOK_WINDOW Current
;
653 KeAcquireSpinLock(&Desktop
->Lock
, &OldLevel
);
655 Entry
= Desktop
->ShellHookWindows
.Flink
;
656 while (Entry
!= &Desktop
->ShellHookWindows
) {
657 Current
= CONTAINING_RECORD(Entry
, SHELL_HOOK_WINDOW
, ListEntry
);
658 if (Current
->hWnd
== hWnd
) {
659 RemoveEntryList(Entry
);
660 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
664 Entry
= Entry
->Flink
;
667 KeReleaseSpinLock(&Desktop
->Lock
, OldLevel
);
673 * NtUserCreateDesktop
675 * Creates a new desktop.
679 * Name of the new desktop.
685 * Requested type of access.
688 * Security descriptor.
691 * Handle to window station on which to create the desktop.
694 * If the function succeeds, the return value is a handle to the newly
695 * created desktop. If the specified desktop already exists, the function
696 * succeeds and returns a handle to the existing desktop. When you are
697 * finished using the handle, call the CloseDesktop function to close it.
698 * If the function fails, the return value is NULL.
706 PUNICODE_STRING lpszDesktopName
,
708 ACCESS_MASK dwDesiredAccess
,
709 LPSECURITY_ATTRIBUTES lpSecurity
,
710 HWINSTA hWindowStation
)
712 OBJECT_ATTRIBUTES ObjectAttributes
;
713 PWINSTATION_OBJECT WinStaObject
;
714 PDESKTOP_OBJECT DesktopObject
;
715 UNICODE_STRING DesktopName
;
718 CSR_API_MESSAGE Request
;
720 DPRINT("CreateDesktop: %wZ\n", lpszDesktopName
);
722 Status
= IntValidateWindowStationHandle(
725 0, /* FIXME - WINSTA_CREATEDESKTOP */
728 if (! NT_SUCCESS(Status
))
730 DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
731 hWindowStation
, lpszDesktopName
);
732 SetLastNtError(Status
);
736 if (! IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
739 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
740 ObDereferenceObject(WinStaObject
);
744 ObDereferenceObject(WinStaObject
);
747 * Try to open already existing desktop
750 DPRINT("Trying to open desktop (%wZ)\n", &DesktopName
);
752 /* Initialize ObjectAttributes for the desktop object */
753 InitializeObjectAttributes(
760 Status
= ObOpenObjectByName(
769 if (NT_SUCCESS(Status
))
771 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
772 ExFreePool(DesktopName
.Buffer
);
777 * No existing desktop found, try to create new one
780 Status
= ObCreateObject(
786 sizeof(DESKTOP_OBJECT
),
789 (PVOID
*)&DesktopObject
);
791 if (! NT_SUCCESS(Status
))
793 DPRINT1("Failed creating desktop (%wZ)\n", &DesktopName
);
794 ExFreePool(DesktopName
.Buffer
);
795 SetLastNtError(STATUS_UNSUCCESSFUL
);
800 DesktopObject
->WorkArea
.left
= 0;
801 DesktopObject
->WorkArea
.top
= 0;
802 DesktopObject
->WorkArea
.right
= -1;
803 DesktopObject
->WorkArea
.bottom
= -1;
804 IntGetDesktopWorkArea(DesktopObject
, NULL
);
806 /* Initialize some local (to win32k) desktop state. */
807 DesktopObject
->ActiveMessageQueue
= NULL
;
809 Status
= ObInsertObject(
810 (PVOID
)DesktopObject
,
812 STANDARD_RIGHTS_REQUIRED
,
817 ObDereferenceObject(DesktopObject
);
818 ExFreePool(DesktopName
.Buffer
);
820 if (! NT_SUCCESS(Status
))
822 DPRINT1("Failed to create desktop handle\n");
823 SetLastNtError(Status
);
828 * Create a handle for CSRSS and notify CSRSS
830 Request
.Type
= MAKE_CSR_API(CREATE_DESKTOP
, CSR_GUI
);
831 Status
= CsrInsertObject(Desktop
,
833 (HANDLE
*)&Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
834 if (! NT_SUCCESS(Status
))
836 DPRINT1("Failed to create desktop handle for CSRSS\n");
838 SetLastNtError(Status
);
842 Status
= CsrNotify(&Request
);
843 if (! NT_SUCCESS(Status
))
845 CsrCloseHandle(Request
.Data
.CreateDesktopRequest
.DesktopHandle
);
846 DPRINT1("Failed to notify CSRSS about new desktop\n");
848 SetLastNtError(Status
);
858 * Opens an existing desktop.
862 * Name of the existing desktop.
868 * Requested type of access.
871 * Handle to the desktop or zero on failure.
879 PUNICODE_STRING lpszDesktopName
,
881 ACCESS_MASK dwDesiredAccess
)
883 OBJECT_ATTRIBUTES ObjectAttributes
;
884 PWINSTATION_OBJECT WinStaObject
;
885 UNICODE_STRING DesktopName
;
890 * Validate the window station handle and compose the fully
891 * qualified desktop name
894 Status
= IntValidateWindowStationHandle(
895 PsGetCurrentProcess()->Win32WindowStation
,
900 if (!NT_SUCCESS(Status
))
902 DPRINT1("Failed validation of window station handle (0x%X)\n",
903 PsGetCurrentProcess()->Win32WindowStation
);
904 SetLastNtError(Status
);
908 if (!IntGetFullWindowStationName(&DesktopName
, &WinStaObject
->Name
,
911 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES
);
912 ObDereferenceObject(WinStaObject
);
916 ObDereferenceObject(WinStaObject
);
918 DPRINT1("Trying to open desktop (%wZ)\n", &DesktopName
);
920 /* Initialize ObjectAttributes for the desktop object */
921 InitializeObjectAttributes(
928 Status
= ObOpenObjectByName(
937 if (!NT_SUCCESS(Status
))
939 SetLastNtError(Status
);
940 ExFreePool(DesktopName
.Buffer
);
944 DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName
);
945 ExFreePool(DesktopName
.Buffer
);
951 * NtUserOpenInputDesktop
953 * Opens the input (interactive) desktop.
960 * Inheritance option.
963 * Requested type of access.
966 * Handle to the input desktop or zero on failure.
973 NtUserOpenInputDesktop(
976 ACCESS_MASK dwDesiredAccess
)
978 PDESKTOP_OBJECT Object
;
982 DPRINT("About to open input desktop\n");
984 /* Get a pointer to the desktop object */
986 Status
= IntValidateDesktopHandle(
992 if (!NT_SUCCESS(Status
))
994 DPRINT("Validation of input desktop handle (0x%X) failed\n", InputDesktop
);
998 /* Create a new handle to the object */
1000 Status
= ObOpenObjectByPointer(
1005 ExDesktopObjectType
,
1009 ObDereferenceObject(Object
);
1011 if (NT_SUCCESS(Status
))
1013 DPRINT("Successfully opened input desktop\n");
1014 return (HDESK
)Desktop
;
1017 SetLastNtError(Status
);
1022 * NtUserCloseDesktop
1024 * Closes a desktop handle.
1028 * Handle to the desktop.
1034 * The desktop handle can be created with NtUserCreateDesktop or
1035 * NtUserOpenDesktop. This function will fail if any thread in the calling
1036 * process is using the specified desktop handle or if the handle refers
1037 * to the initial desktop of the calling process.
1044 NtUserCloseDesktop(HDESK hDesktop
)
1046 PDESKTOP_OBJECT Object
;
1049 DPRINT("About to close desktop handle (0x%X)\n", hDesktop
);
1051 Status
= IntValidateDesktopHandle(
1057 if (!NT_SUCCESS(Status
))
1059 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1063 ObDereferenceObject(Object
);
1065 DPRINT("Closing desktop handle (0x%X)\n", hDesktop
);
1067 Status
= ZwClose(hDesktop
);
1068 if (!NT_SUCCESS(Status
))
1070 SetLastNtError(Status
);
1078 static int GetSystemVersionString(LPWSTR buffer
)
1080 RTL_OSVERSIONINFOEXW versionInfo
;
1083 versionInfo
.dwOSVersionInfoSize
= sizeof(RTL_OSVERSIONINFOEXW
);
1085 if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW
)&versionInfo
)))
1088 if (versionInfo
.dwMajorVersion
<= 4)
1089 len
= swprintf(buffer
,
1090 L
"ReactOS Version %d.%d %s Build %d",
1091 versionInfo
.dwMajorVersion
, versionInfo
.dwMinorVersion
,
1092 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
1094 len
= swprintf(buffer
,
1095 L
"ReactOS %s (Build %d)",
1096 versionInfo
.szCSDVersion
, versionInfo
.dwBuildNumber
&0xFFFF);
1102 * NtUserPaintDesktop
1104 * The NtUserPaintDesktop function fills the clipping region in the
1105 * specified device context with the desktop pattern or wallpaper. The
1106 * function is provided primarily for shell desktops.
1110 * Handle to the device context.
1117 NtUserPaintDesktop(HDC hDC
)
1120 HBRUSH DesktopBrush
, PreviousBrush
;
1122 BOOL doPatBlt
= TRUE
;
1125 PWINSTATION_OBJECT WinSta
= PsGetWin32Thread()->Desktop
->WindowStation
;
1127 IntGdiGetClipBox(hDC
, &Rect
);
1129 hWndDesktop
= IntGetDesktopWindow();
1130 DesktopBrush
= (HBRUSH
)NtUserGetClassLong(hWndDesktop
, GCL_HBRBACKGROUND
, FALSE
);
1133 * Paint desktop background
1136 if(WinSta
->hbmWallpaper
!= NULL
)
1138 PWINDOW_OBJECT DeskWin
;
1140 if((DeskWin
= IntGetWindowObject(hWndDesktop
)))
1146 sz
.cx
= DeskWin
->WindowRect
.right
- DeskWin
->WindowRect
.left
;
1147 sz
.cy
= DeskWin
->WindowRect
.bottom
- DeskWin
->WindowRect
.top
;
1148 IntReleaseWindowObject(DeskWin
);
1150 x
= (sz
.cx
/ 2) - (WinSta
->cxWallpaper
/ 2);
1151 y
= (sz
.cy
/ 2) - (WinSta
->cyWallpaper
/ 2);
1153 hWallpaperDC
= NtGdiCreateCompatableDC(hDC
);
1154 if(hWallpaperDC
!= NULL
)
1160 /* FIXME - clip out the bitmap */
1161 PreviousBrush
= NtGdiSelectObject(hDC
, DesktopBrush
);
1162 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1163 NtGdiSelectObject(hDC
, PreviousBrush
);
1168 hOldBitmap
= NtGdiSelectObject(hWallpaperDC
, WinSta
->hbmWallpaper
);
1169 NtGdiBitBlt(hDC
, x
, y
, WinSta
->cxWallpaper
, WinSta
->cyWallpaper
, hWallpaperDC
, 0, 0, SRCCOPY
);
1170 NtGdiSelectObject(hWallpaperDC
, hOldBitmap
);
1172 NtGdiDeleteDC(hWallpaperDC
);
1178 PreviousBrush
= NtGdiSelectObject(hDC
, DesktopBrush
);
1179 NtGdiPatBlt(hDC
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
, PATCOPY
);
1180 NtGdiSelectObject(hDC
, PreviousBrush
);
1184 * Display system version on the desktop background
1187 if (g_PaintDesktopVersion
) {
1188 static WCHAR s_wszVersion
[256] = {0};
1192 len
= wcslen(s_wszVersion
);
1194 len
= GetSystemVersionString(s_wszVersion
);
1197 if (!NtUserSystemParametersInfo(SPI_GETWORKAREA
, 0, &rect
, 0)) {
1198 rect
.right
= NtUserGetSystemMetrics(SM_CXSCREEN
);
1199 rect
.bottom
= NtUserGetSystemMetrics(SM_CYSCREEN
);
1202 COLORREF color_old
= NtGdiSetTextColor(hDC
, RGB(255,255,255));
1203 UINT align_old
= NtGdiSetTextAlign(hDC
, TA_RIGHT
);
1204 int mode_old
= NtGdiSetBkMode(hDC
, TRANSPARENT
);
1206 NtGdiTextOut(hDC
, rect
.right
-16, rect
.bottom
-48, s_wszVersion
, len
);
1208 NtGdiSetBkMode(hDC
, mode_old
);
1209 NtGdiSetTextAlign(hDC
, align_old
);
1210 NtGdiSetTextColor(hDC
, color_old
);
1219 * NtUserSwitchDesktop
1221 * Sets the current input (interactive) desktop.
1225 * Handle to desktop.
1235 NtUserSwitchDesktop(HDESK hDesktop
)
1237 PDESKTOP_OBJECT DesktopObject
;
1240 DPRINT("About to switch desktop (0x%X)\n", hDesktop
);
1242 Status
= IntValidateDesktopHandle(
1248 if (!NT_SUCCESS(Status
))
1250 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1255 * Don't allow applications switch the desktop if it's locked, unless the caller
1256 * is the logon application itself
1258 if((DesktopObject
->WindowStation
->Flags
& WSS_LOCKED
) &&
1259 LogonProcess
!= NULL
&& LogonProcess
!= PsGetWin32Process())
1261 ObDereferenceObject(DesktopObject
);
1262 DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop
);
1266 /* FIXME: Fail if the desktop belong to an invisible window station */
1267 /* FIXME: Fail if the process is associated with a secured
1268 desktop such as Winlogon or Screen-Saver */
1269 /* FIXME: Connect to input device */
1271 /* Set the active desktop in the desktop's window station. */
1272 DesktopObject
->WindowStation
->ActiveDesktop
= DesktopObject
;
1274 /* Set the global state. */
1275 InputDesktop
= DesktopObject
;
1276 InputDesktopHandle
= hDesktop
;
1277 InputWindowStation
= DesktopObject
->WindowStation
;
1279 ObDereferenceObject(DesktopObject
);
1285 * NtUserResolveDesktopForWOW
1292 NtUserResolveDesktopForWOW(DWORD Unknown0
)
1299 * NtUserGetThreadDesktop
1306 NtUserGetThreadDesktop(DWORD dwThreadId
, DWORD Unknown1
)
1310 PDESKTOP_OBJECT DesktopObject
;
1311 HDESK Ret
, hThreadDesktop
;
1312 OBJECT_HANDLE_INFORMATION HandleInformation
;
1316 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1320 Status
= PsLookupThreadByThreadId((HANDLE
)dwThreadId
, &Thread
);
1321 if(!NT_SUCCESS(Status
))
1323 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1327 if(Thread
->ThreadsProcess
== PsGetCurrentProcess())
1329 /* just return the handle, we queried the desktop handle of a thread running
1330 in the same context */
1331 Ret
= Thread
->Tcb
.Win32Thread
->hDesktop
;
1332 ObDereferenceObject(Thread
);
1336 /* get the desktop handle and the desktop of the thread */
1337 if(!(hThreadDesktop
= Thread
->Tcb
.Win32Thread
->hDesktop
) ||
1338 !(DesktopObject
= Thread
->Tcb
.Win32Thread
->Desktop
))
1340 ObDereferenceObject(Thread
);
1341 DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId
);
1345 /* we could just use DesktopObject instead of looking up the handle, but latter
1346 may be a bit safer (e.g. when the desktop is being destroyed */
1347 /* switch into the context of the thread we're trying to get the desktop from,
1348 so we can use the handle */
1349 KeAttachProcess(&Thread
->ThreadsProcess
->Pcb
);
1350 Status
= ObReferenceObjectByHandle(hThreadDesktop
,
1352 ExDesktopObjectType
,
1354 (PVOID
*)&DesktopObject
,
1355 &HandleInformation
);
1358 /* the handle couldn't be found, there's nothing to get... */
1359 if(!NT_SUCCESS(Status
))
1361 ObDereferenceObject(Thread
);
1365 /* lookup our handle table if we can find a handle to the desktop object,
1366 if not, create one */
1367 Ret
= IntGetDesktopObjectHandle(DesktopObject
);
1369 /* all done, we got a valid handle to the desktop */
1370 ObDereferenceObject(DesktopObject
);
1371 ObDereferenceObject(Thread
);
1376 * NtUserSetThreadDesktop
1383 NtUserSetThreadDesktop(HDESK hDesktop
)
1385 PW32THREAD W32Thread
;
1386 PDESKTOP_OBJECT DesktopObject
;
1389 /* Validate the new desktop. */
1390 Status
= IntValidateDesktopHandle(
1396 if (!NT_SUCCESS(Status
))
1398 DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop
);
1402 W32Thread
= PsGetWin32Thread();
1404 /* FIXME: Should check here to see if the thread has any windows. */
1406 if (W32Thread
->Desktop
!= NULL
)
1408 ObDereferenceObject(W32Thread
->Desktop
);
1411 W32Thread
->Desktop
= DesktopObject
;
1412 W32Thread
->hDesktop
= hDesktop
;