reactos/reactos/subsys/win32k/ntuser/desktop.c

1287 lines
31 KiB
C
Raw Normal View History

/*
* ReactOS W32 Subsystem
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: desktop.c,v 1.29 2004/12/21 21:38:27 weiden Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Desktops
* FILE: subsys/win32k/ntuser/desktop.c
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* REVISION HISTORY:
* 06-06-2001 CSH Created
*/
/* INCLUDES ******************************************************************/
#include <w32k.h>
#if 0
/* not yet defined in w32api... */
NTSTATUS STDCALL
ObFindHandleForObject(IN PEPROCESS Process,
IN PVOID Object,
IN POBJECT_TYPE ObjectType,
IN POBJECT_HANDLE_INFORMATION HandleInformation,
OUT PHANDLE Handle);
#else
#define ObFindHandleForObject(Process, Object, ObjectType, HandleInformation, Handle) \
(STATUS_UNSUCCESSFUL)
#endif
/* GLOBALS *******************************************************************/
/* Currently active desktop */
PDESKTOP_OBJECT InputDesktop = NULL;
HDC ScreenDeviceContext = NULL;
BOOL g_PaintDesktopVersion = FALSE;
/* INITALIZATION FUNCTIONS ****************************************************/
NTSTATUS FASTCALL
InitDesktopImpl(VOID)
{
return STATUS_SUCCESS;
}
NTSTATUS FASTCALL
CleanupDesktopImpl(VOID)
{
return STATUS_SUCCESS;
}
/* PRIVATE FUNCTIONS **********************************************************/
NTSTATUS FASTCALL
IntParseDesktopPath(PEPROCESS Process,
PUNICODE_STRING DesktopPath,
HWINSTA *hWinSta,
HDESK *hDesktop)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING WinSta, Desktop, FullName;
BOOL DesktopPresent = FALSE;
BOOL WinStaPresent = FALSE;
NTSTATUS Status;
ASSERT(hWinSta);
*hWinSta = NULL;
if(hDesktop != NULL)
{
*hDesktop = NULL;
}
RtlInitUnicodeString(&WinSta, NULL);
RtlInitUnicodeString(&Desktop, NULL);
if(DesktopPath != NULL && DesktopPath->Buffer != NULL && DesktopPath->Length > sizeof(WCHAR))
{
PWCHAR c = DesktopPath->Buffer;
USHORT wl = 0;
USHORT l = DesktopPath->Length;
/*
* Parse the desktop path string which can be in the form "WinSta\Desktop"
* or just "Desktop". In latter case WinSta0 will be used.
*/
while(l > 0)
{
if(*c == L'\\')
{
wl = (ULONG_PTR)c - (ULONG_PTR)DesktopPath->Buffer;
break;
}
l -= sizeof(WCHAR);
c++;
}
if(wl > 0)
{
WinSta.Length = wl;
WinSta.MaximumLength = wl + sizeof(WCHAR);
WinSta.Buffer = DesktopPath->Buffer;
WinStaPresent = TRUE;
c++;
}
Desktop.Length = DesktopPath->Length - wl;
if(wl > 0)
{
Desktop.Length -= sizeof(WCHAR);
}
if(Desktop.Length > 0)
{
Desktop.MaximumLength = Desktop.Length + sizeof(WCHAR);
Desktop.Buffer = ((wl > 0) ? c : DesktopPath->Buffer);
DesktopPresent = TRUE;
}
}
if(!WinStaPresent)
{
/* search the process handle table for (inherited) window station
handles, use a more appropriate one than WinSta0 if possible. */
Status = ObFindHandleForObject(Process,
NULL,
ExWindowStationObjectType,
NULL,
(PHANDLE)hWinSta);
if(!NT_SUCCESS(Status))
{
/* we had no luck searching for opened handles, use WinSta0 now */
RtlInitUnicodeString(&WinSta, L"WinSta0");
}
}
if(!DesktopPresent && hDesktop != NULL)
{
/* search the process handle table for (inherited) desktop
handles, use a more appropriate one than Default if possible. */
Status = ObFindHandleForObject(Process,
NULL,
ExDesktopObjectType,
NULL,
(PHANDLE)hDesktop);
if(!NT_SUCCESS(Status))
{
/* we had no luck searching for opened handles, use Desktop now */
RtlInitUnicodeString(&Desktop, L"Default");
}
}
if(*hWinSta == NULL)
{
if(!IntGetFullWindowStationName(&FullName, &WinSta, NULL))
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* open the window station */
InitializeObjectAttributes(&ObjectAttributes,
&FullName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ObOpenObjectByName(&ObjectAttributes,
ExWindowStationObjectType,
NULL,
UserMode,
0,
NULL,
(HANDLE*)hWinSta);
RtlFreeUnicodeString(&FullName);
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
DPRINT("Failed to reference window station %wZ PID: %d!\n", &WinSta, PsGetCurrentProcessId());
return Status;
}
}
if(hDesktop != NULL && *hDesktop == NULL)
{
if(!IntGetFullWindowStationName(&FullName, &WinSta, &Desktop))
{
NtClose(*hWinSta);
*hWinSta = NULL;
return STATUS_INSUFFICIENT_RESOURCES;
}
/* open the desktop object */
InitializeObjectAttributes(&ObjectAttributes,
&FullName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ObOpenObjectByName(&ObjectAttributes,
ExDesktopObjectType,
NULL,
UserMode,
0,
NULL,
(HANDLE*)hDesktop);
RtlFreeUnicodeString(&FullName);
if(!NT_SUCCESS(Status))
{
*hDesktop = NULL;
NtClose(*hWinSta);
*hWinSta = NULL;
SetLastNtError(Status);
DPRINT("Failed to reference desktop %wZ PID: %d!\n", &Desktop, PsGetCurrentProcessId());
return Status;
}
}
return STATUS_SUCCESS;
}
/*
* IntValidateDesktopHandle
*
* Validates the desktop handle.
*
* Remarks
* If the function succeeds, the handle remains referenced. If the
* fucntion fails, last error is set.
*/
NTSTATUS FASTCALL
IntValidateDesktopHandle(
HDESK Desktop,
KPROCESSOR_MODE AccessMode,
ACCESS_MASK DesiredAccess,
PDESKTOP_OBJECT *Object)
{
NTSTATUS Status;
Status = ObReferenceObjectByHandle(
Desktop,
DesiredAccess,
ExDesktopObjectType,
AccessMode,
(PVOID*)Object,
NULL);
if (!NT_SUCCESS(Status))
SetLastNtError(Status);
return Status;
}
VOID FASTCALL
IntGetDesktopWorkArea(PDESKTOP_OBJECT Desktop, PRECT Rect)
{
PRECT Ret;
ASSERT(Desktop);
Ret = &Desktop->WorkArea;
if((Ret->right == -1) && ScreenDeviceContext)
{
PDC dc;
[Sorry for too many changes in one patch, but it's nearly impossible to separate it without breaking the functionality] - Remove the eng/brush.h header and all occurrences of BRUSHINST. - Remove eng/nls.c and make the NLS functions forward exports to ntoskrnl. - Remove DDBITMAP definition. - Overall cleanup of eng/xlate.c. - Stop processing if exact match is found in ClosestColorMatch. - Move SURFGDI->PointerStatus to GDIDEVICE structure. - Remove the GDIDEVICE->DriverLock. - Replace BITMAP by SURFOBJ in BITMAPOBJ structure and added two new members (Flags and Hooks). - Replace function pointers to driver functions in SURFGDI with flHooks variable specifying the bitmask of hooked functions. - Added two new macros: GDIDEV and GDIDEVFUNCS. - Fixed locking in NtGdiGetBitmapBits. - Removed IntCopyBitmap and replaced it's usage by BITMAPOBJ_CopyBitmap. - Fixed setting of SURFOBJ->pvBits and SURFOBJ->pvScan0 in EngCreateBitmap for bottom-up surfaces. - Fix DPRINTs. - Remove unused definitions from eng/objects.h. - Call IntEngBitBlt instead of EngBitBlt from EngCopyBits. - Correctly set the SURFOBJ->hsurf field. - Merge Engine surface handling with the GDI one and remove DC->Surface, SURFGDI, BitmapToSurf. - Support for bottom-up mouse cursors in the Eng* cursor emulation routines. - Fix locking in error cases of NtGdiRestoreDC (get Primitives demo to start). - Fix BitmapFormat to return 0 for unknown bit depth. - Move code from EngCreateBitmap to IntCreateBitmap and use this function in EngCreateBitmap, NtGdiCreateBitmap and DIB_CreateDIBSection. - New implementation of NtGdiGetDIBits. svn path=/trunk/; revision=9977
2004-07-03 13:55:37 +00:00
BITMAPOBJ *BitmapObj;
dc = DC_LockDc(ScreenDeviceContext);
/* FIXME - Handle dc == NULL!!!! */
[Sorry for too many changes in one patch, but it's nearly impossible to separate it without breaking the functionality] - Remove the eng/brush.h header and all occurrences of BRUSHINST. - Remove eng/nls.c and make the NLS functions forward exports to ntoskrnl. - Remove DDBITMAP definition. - Overall cleanup of eng/xlate.c. - Stop processing if exact match is found in ClosestColorMatch. - Move SURFGDI->PointerStatus to GDIDEVICE structure. - Remove the GDIDEVICE->DriverLock. - Replace BITMAP by SURFOBJ in BITMAPOBJ structure and added two new members (Flags and Hooks). - Replace function pointers to driver functions in SURFGDI with flHooks variable specifying the bitmask of hooked functions. - Added two new macros: GDIDEV and GDIDEVFUNCS. - Fixed locking in NtGdiGetBitmapBits. - Removed IntCopyBitmap and replaced it's usage by BITMAPOBJ_CopyBitmap. - Fixed setting of SURFOBJ->pvBits and SURFOBJ->pvScan0 in EngCreateBitmap for bottom-up surfaces. - Fix DPRINTs. - Remove unused definitions from eng/objects.h. - Call IntEngBitBlt instead of EngBitBlt from EngCopyBits. - Correctly set the SURFOBJ->hsurf field. - Merge Engine surface handling with the GDI one and remove DC->Surface, SURFGDI, BitmapToSurf. - Support for bottom-up mouse cursors in the Eng* cursor emulation routines. - Fix locking in error cases of NtGdiRestoreDC (get Primitives demo to start). - Fix BitmapFormat to return 0 for unknown bit depth. - Move code from EngCreateBitmap to IntCreateBitmap and use this function in EngCreateBitmap, NtGdiCreateBitmap and DIB_CreateDIBSection. - New implementation of NtGdiGetDIBits. svn path=/trunk/; revision=9977
2004-07-03 13:55:37 +00:00
BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
if(BitmapObj)
{
[Sorry for too many changes in one patch, but it's nearly impossible to separate it without breaking the functionality] - Remove the eng/brush.h header and all occurrences of BRUSHINST. - Remove eng/nls.c and make the NLS functions forward exports to ntoskrnl. - Remove DDBITMAP definition. - Overall cleanup of eng/xlate.c. - Stop processing if exact match is found in ClosestColorMatch. - Move SURFGDI->PointerStatus to GDIDEVICE structure. - Remove the GDIDEVICE->DriverLock. - Replace BITMAP by SURFOBJ in BITMAPOBJ structure and added two new members (Flags and Hooks). - Replace function pointers to driver functions in SURFGDI with flHooks variable specifying the bitmask of hooked functions. - Added two new macros: GDIDEV and GDIDEVFUNCS. - Fixed locking in NtGdiGetBitmapBits. - Removed IntCopyBitmap and replaced it's usage by BITMAPOBJ_CopyBitmap. - Fixed setting of SURFOBJ->pvBits and SURFOBJ->pvScan0 in EngCreateBitmap for bottom-up surfaces. - Fix DPRINTs. - Remove unused definitions from eng/objects.h. - Call IntEngBitBlt instead of EngBitBlt from EngCopyBits. - Correctly set the SURFOBJ->hsurf field. - Merge Engine surface handling with the GDI one and remove DC->Surface, SURFGDI, BitmapToSurf. - Support for bottom-up mouse cursors in the Eng* cursor emulation routines. - Fix locking in error cases of NtGdiRestoreDC (get Primitives demo to start). - Fix BitmapFormat to return 0 for unknown bit depth. - Move code from EngCreateBitmap to IntCreateBitmap and use this function in EngCreateBitmap, NtGdiCreateBitmap and DIB_CreateDIBSection. - New implementation of NtGdiGetDIBits. svn path=/trunk/; revision=9977
2004-07-03 13:55:37 +00:00
Ret->right = BitmapObj->SurfObj.sizlBitmap.cx;
Ret->bottom = BitmapObj->SurfObj.sizlBitmap.cy;
BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
}
DC_UnlockDc(ScreenDeviceContext);
}
if(Rect)
{
*Rect = *Ret;
}
}
PDESKTOP_OBJECT FASTCALL
IntGetActiveDesktop(VOID)
{
return InputDesktop;
}
/*
* returns or creates a handle to the desktop object
*/
HDESK FASTCALL
IntGetDesktopObjectHandle(PDESKTOP_OBJECT DesktopObject)
{
NTSTATUS Status;
HDESK Ret;
ASSERT(DesktopObject);
Status = ObFindHandleForObject(PsGetCurrentProcess(),
DesktopObject,
ExDesktopObjectType,
NULL,
(PHANDLE)&Ret);
if(!NT_SUCCESS(Status))
{
Status = ObOpenObjectByPointer(DesktopObject,
0,
NULL,
0,
ExDesktopObjectType,
UserMode,
(PHANDLE)&Ret);
if(!NT_SUCCESS(Status))
{
/* unable to create a handle */
DPRINT1("Unable to create a desktop handle\n");
return NULL;
}
}
return Ret;
}
PUSER_MESSAGE_QUEUE FASTCALL
IntGetFocusMessageQueue(VOID)
{
PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
if (!pdo)
{
DPRINT("No active desktop\n");
return(NULL);
}
return (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
}
VOID FASTCALL
IntSetFocusMessageQueue(PUSER_MESSAGE_QUEUE NewQueue)
{
PUSER_MESSAGE_QUEUE Old;
PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
if (!pdo)
{
DPRINT("No active desktop\n");
return;
}
if(NewQueue != NULL)
{
if(NewQueue->Desktop != NULL)
{
DPRINT("Message Queue already attached to another desktop!\n");
return;
}
IntReferenceMessageQueue(NewQueue);
InterlockedExchange((LONG*)&NewQueue->Desktop, (LONG)pdo);
}
Old = (PUSER_MESSAGE_QUEUE)InterlockedExchange((LONG*)&pdo->ActiveMessageQueue, (LONG)NewQueue);
if(Old != NULL)
{
InterlockedExchange((LONG*)&Old->Desktop, 0);
IntDereferenceMessageQueue(Old);
}
}
HWND FASTCALL IntGetDesktopWindow(VOID)
{
PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
if (!pdo)
{
DPRINT("No active desktop\n");
return NULL;
}
return pdo->DesktopWindow;
}
HWND FASTCALL IntGetCurrentThreadDesktopWindow(VOID)
{
PDESKTOP_OBJECT pdo = PsGetWin32Thread()->Desktop;
if (NULL == pdo)
{
DPRINT1("Thread doesn't have a desktop\n");
return NULL;
}
return pdo->DesktopWindow;
}
BOOL FASTCALL IntDesktopUpdatePerUserSettings(BOOL bEnable)
{
if (bEnable)
{
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
NTSTATUS Status;
RtlZeroMemory(QueryTable, sizeof(QueryTable));
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
QueryTable[0].Name = L"PaintDesktopVersion";
QueryTable[0].EntryContext = &g_PaintDesktopVersion;
/* Query the "PaintDesktopVersion" flag in the "Control Panel\Desktop" key */
Status = RtlQueryRegistryValues(RTL_REGISTRY_USER,
L"Control Panel\\Desktop",
QueryTable, NULL, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("RtlQueryRegistryValues failed for PaintDesktopVersion (%x)\n",
Status);
g_PaintDesktopVersion = FALSE;
return FALSE;
}
DPRINT("PaintDesktopVersion = %d\n", g_PaintDesktopVersion);
return TRUE;
}
else
{
g_PaintDesktopVersion = FALSE;
return TRUE;
}
}
/* PUBLIC FUNCTIONS ***********************************************************/
NTSTATUS FASTCALL
IntShowDesktop(PDESKTOP_OBJECT Desktop)
{
CSRSS_API_REQUEST Request;
CSRSS_API_REPLY Reply;
NTSTATUS Status;
SIZEL DesktopSize;
PDC dc;
HDC hDC;
IntGraphicsCheck(TRUE);
hDC = IntGetScreenDC();
if(hDC != NULL && (dc = DC_LockDc(hDC)))
{
BITMAPOBJ *BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
if(BitmapObj != NULL)
{
DesktopSize.cx = BitmapObj->SurfObj.sizlBitmap.cx;
DesktopSize.cy = BitmapObj->SurfObj.sizlBitmap.cy;
BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
}
DC_UnlockDc(hDC);
}
else
{
DPRINT1("Failed to query screen size!\n");
IntGraphicsCheck(FALSE);
return STATUS_UNSUCCESSFUL;
}
DPRINT1("IntShowDesktop: 0x%x, %d, %d\n", Desktop->DesktopWindow, DesktopSize.cx, DesktopSize.cy);
Status = CsrInsertObject((PVOID)Desktop,
NULL,
GENERIC_ALL,
0,
NULL,
(HANDLE*)&Request.Data.ShowDesktopRequest.hDesktop);
if (NT_SUCCESS(Status))
{
Request.Type = CSRSS_SHOW_DESKTOP;
Request.Data.ShowDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
Request.Data.ShowDesktopRequest.Width = DesktopSize.cx;
Request.Data.ShowDesktopRequest.Height = DesktopSize.cy;
Status = CsrNotify(&Request, &Reply);
CsrCloseHandle(Request.Data.ShowDesktopRequest.hDesktop);
}
if(!NT_SUCCESS(Status))
{
DPRINT1("IntShowDesktop: Failed to notify CSRSS!\n");
IntGraphicsCheck(FALSE);
}
return Status;
}
NTSTATUS FASTCALL
IntHideDesktop(PDESKTOP_OBJECT Desktop)
{
CSRSS_API_REQUEST Request;
CSRSS_API_REPLY Reply;
NTSTATUS Status;
Status = CsrInsertObject((PVOID)Desktop,
NULL,
GENERIC_ALL,
0,
NULL,
(HANDLE*)&Request.Data.HideDesktopRequest.hDesktop);
if(NT_SUCCESS(Status))
{
Request.Type = CSRSS_HIDE_DESKTOP;
Request.Data.HideDesktopRequest.DesktopWindow = Desktop->DesktopWindow;
Status = CsrNotify(&Request, &Reply);
CsrCloseHandle(Request.Data.HideDesktopRequest.hDesktop);
}
if(NT_SUCCESS(Status))
{
IntGraphicsCheck(FALSE);
}
return Status;
}
/*
* NtUserCreateDesktop
*
* Creates a new desktop.
*
* Parameters
* lpszDesktopName
* Name of the new desktop.
*
* dwFlags
* Interaction flags.
*
* dwDesiredAccess
* Requested type of access.
*
* lpSecurity
* Security descriptor.
*
* hWindowStation
* Handle to window station on which to create the desktop.
*
* Return Value
* If the function succeeds, the return value is a handle to the newly
* created desktop. If the specified desktop already exists, the function
* succeeds and returns a handle to the existing desktop. When you are
* finished using the handle, call the CloseDesktop function to close it.
* If the function fails, the return value is NULL.
*
* Status
* @implemented
*/
HDESK STDCALL
NtUserCreateDesktop(
PUNICODE_STRING lpszDesktopName,
DWORD dwFlags,
ACCESS_MASK dwDesiredAccess,
LPSECURITY_ATTRIBUTES lpSecurity,
HWINSTA hWindowStation)
{
OBJECT_ATTRIBUTES ObjectAttributes;
PWINSTATION_OBJECT WinStaObject;
PDESKTOP_OBJECT DesktopObject;
UNICODE_STRING DesktopName;
NTSTATUS Status;
HDESK Desktop;
CSRSS_API_REQUEST Request;
CSRSS_API_REPLY Reply;
DPRINT("CreateDesktop: %wZ\n", lpszDesktopName);
Status = IntValidateWindowStationHandle(
hWindowStation,
KernelMode,
0, /* FIXME - WINSTA_CREATEDESKTOP */
&WinStaObject);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed validation of window station handle (0x%X), cannot create desktop %wZ\n",
hWindowStation, lpszDesktopName);
SetLastNtError(Status);
return NULL;
}
if (! IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
lpszDesktopName))
{
SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
ObDereferenceObject(WinStaObject);
return NULL;
}
ObDereferenceObject(WinStaObject);
/*
* Try to open already existing desktop
*/
DPRINT("Trying to open desktop (%wZ)\n", &DesktopName);
/* Initialize ObjectAttributes for the desktop object */
InitializeObjectAttributes(
&ObjectAttributes,
&DesktopName,
0,
NULL,
NULL);
Status = ObOpenObjectByName(
&ObjectAttributes,
ExDesktopObjectType,
NULL,
UserMode,
dwDesiredAccess,
NULL,
(HANDLE*)&Desktop);
if (NT_SUCCESS(Status))
{
DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
ExFreePool(DesktopName.Buffer);
return Desktop;
}
/*
* No existing desktop found, try to create new one
*/
Status = ObCreateObject(
ExGetPreviousMode(),
ExDesktopObjectType,
&ObjectAttributes,
ExGetPreviousMode(),
NULL,
sizeof(DESKTOP_OBJECT),
0,
0,
(PVOID*)&DesktopObject);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed creating desktop (%wZ)\n", &DesktopName);
ExFreePool(DesktopName.Buffer);
SetLastNtError(STATUS_UNSUCCESSFUL);
return NULL;
}
// init desktop area
DesktopObject->WorkArea.left = 0;
DesktopObject->WorkArea.top = 0;
DesktopObject->WorkArea.right = -1;
DesktopObject->WorkArea.bottom = -1;
IntGetDesktopWorkArea(DesktopObject, NULL);
/* Initialize some local (to win32k) desktop state. */
DesktopObject->ActiveMessageQueue = NULL;
Status = ObInsertObject(
(PVOID)DesktopObject,
NULL,
STANDARD_RIGHTS_REQUIRED,
0,
NULL,
(HANDLE*)&Desktop);
ObDereferenceObject(DesktopObject);
ExFreePool(DesktopName.Buffer);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to create desktop handle\n");
SetLastNtError(Status);
return NULL;
}
/*
* Create a handle for CSRSS and notify CSRSS
*/
Request.Type = CSRSS_CREATE_DESKTOP;
Status = CsrInsertObject((PVOID)DesktopObject,
NULL,
GENERIC_ALL,
0,
NULL,
(HANDLE*)&Request.Data.CreateDesktopRequest.DesktopHandle);
if (! NT_SUCCESS(Status))
{
DPRINT1("Failed to create desktop handle for CSRSS\n");
ZwClose(Desktop);
SetLastNtError(Status);
return NULL;
}
Status = CsrNotify(&Request, &Reply);
if (! NT_SUCCESS(Status))
{
CsrCloseHandle(Request.Data.CreateDesktopRequest.DesktopHandle);
DPRINT1("Failed to notify CSRSS about new desktop\n");
ZwClose(Desktop);
SetLastNtError(Status);
return NULL;
}
return Desktop;
}
/*
* NtUserOpenDesktop
*
* Opens an existing desktop.
*
* Parameters
* lpszDesktopName
* Name of the existing desktop.
*
* dwFlags
* Interaction flags.
*
* dwDesiredAccess
* Requested type of access.
*
* Return Value
* Handle to the desktop or zero on failure.
*
* Status
* @implemented
*/
HDESK STDCALL
NtUserOpenDesktop(
PUNICODE_STRING lpszDesktopName,
DWORD dwFlags,
ACCESS_MASK dwDesiredAccess)
{
OBJECT_ATTRIBUTES ObjectAttributes;
PWINSTATION_OBJECT WinStaObject;
UNICODE_STRING DesktopName;
NTSTATUS Status;
HDESK Desktop;
/*
* Validate the window station handle and compose the fully
* qualified desktop name
*/
Status = IntValidateWindowStationHandle(
PsGetCurrentProcess()->Win32WindowStation,
KernelMode,
0,
&WinStaObject);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed validation of window station handle (0x%X)\n",
PsGetCurrentProcess()->Win32WindowStation);
SetLastNtError(Status);
return 0;
}
if (!IntGetFullWindowStationName(&DesktopName, &WinStaObject->Name,
lpszDesktopName))
{
SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
ObDereferenceObject(WinStaObject);
return 0;
}
ObDereferenceObject(WinStaObject);
DPRINT1("Trying to open desktop (%wZ)\n", &DesktopName);
/* Initialize ObjectAttributes for the desktop object */
InitializeObjectAttributes(
&ObjectAttributes,
&DesktopName,
0,
NULL,
NULL);
Status = ObOpenObjectByName(
&ObjectAttributes,
ExDesktopObjectType,
NULL,
UserMode,
dwDesiredAccess,
NULL,
(HANDLE*)&Desktop);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
ExFreePool(DesktopName.Buffer);
return 0;
}
DPRINT("Successfully opened desktop (%wZ)\n", &DesktopName);
ExFreePool(DesktopName.Buffer);
return Desktop;
}
/*
* NtUserOpenInputDesktop
*
* Opens the input (interactive) desktop.
*
* Parameters
* dwFlags
* Interaction flags.
*
* fInherit
* Inheritance option.
*
* dwDesiredAccess
* Requested type of access.
*
* Return Value
* Handle to the input desktop or zero on failure.
*
* Status
* @implemented
*/
HDESK STDCALL
NtUserOpenInputDesktop(
DWORD dwFlags,
BOOL fInherit,
ACCESS_MASK dwDesiredAccess)
{
NTSTATUS Status;
HDESK Desktop;
DPRINT("About to open input desktop\n");
/* Create a new handle to the object */
Status = ObOpenObjectByPointer(
InputDesktop,
0,
NULL,
dwDesiredAccess,
ExDesktopObjectType,
UserMode,
(HANDLE*)&Desktop);
if (NT_SUCCESS(Status))
{
DPRINT("Successfully opened input desktop\n");
return (HDESK)Desktop;
}
SetLastNtError(Status);
return (HDESK)0;
}
/*
* NtUserCloseDesktop
*
* Closes a desktop handle.
*
* Parameters
* hDesktop
* Handle to the desktop.
*
* Return Value
* Status
*
* Remarks
* The desktop handle can be created with NtUserCreateDesktop or
* NtUserOpenDesktop. This function will fail if any thread in the calling
* process is using the specified desktop handle or if the handle refers
* to the initial desktop of the calling process.
*
* Status
* @implemented
*/
BOOL STDCALL
NtUserCloseDesktop(HDESK hDesktop)
{
PDESKTOP_OBJECT Object;
NTSTATUS Status;
DPRINT("About to close desktop handle (0x%X)\n", hDesktop);
Status = IntValidateDesktopHandle(
hDesktop,
UserMode,
0,
&Object);
if (!NT_SUCCESS(Status))
{
DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
return FALSE;
}
ObDereferenceObject(Object);
DPRINT("Closing desktop handle (0x%X)\n", hDesktop);
Status = ZwClose(hDesktop);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
return FALSE;
}
return TRUE;
}
static int GetSystemVersionString(LPWSTR buffer)
{
RTL_OSVERSIONINFOEXW versionInfo;
int len;
versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
if (!NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo)))
return 0;
if (versionInfo.dwMajorVersion <= 4)
len = swprintf(buffer,
L"ReactOS Version %d.%d %s Build %d",
versionInfo.dwMajorVersion, versionInfo.dwMinorVersion,
versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
else
len = swprintf(buffer,
L"ReactOS %s (Build %d)",
versionInfo.szCSDVersion, versionInfo.dwBuildNumber&0xFFFF);
return len;
}
/*
* NtUserPaintDesktop
*
* The NtUserPaintDesktop function fills the clipping region in the
* specified device context with the desktop pattern or wallpaper. The
* function is provided primarily for shell desktops.
*
* Parameters
* hDC
* Handle to the device context.
*
* Status
* @implemented
*/
BOOL STDCALL
NtUserPaintDesktop(HDC hDC)
{
RECT Rect;
HBRUSH DesktopBrush, PreviousBrush;
HWND hWndDesktop;
BOOL doPatBlt = TRUE;
int len;
PWINSTATION_OBJECT WinSta = PsGetWin32Thread()->Desktop->WindowStation;
IntGdiGetClipBox(hDC, &Rect);
hWndDesktop = IntGetDesktopWindow();
DesktopBrush = (HBRUSH)NtUserGetClassLong(hWndDesktop, GCL_HBRBACKGROUND, FALSE);
/*
* Paint desktop background
*/
if(WinSta->hbmWallpaper != NULL)
{
PWINDOW_OBJECT DeskWin;
if((DeskWin = IntGetWindowObject(hWndDesktop)))
{
SIZE sz;
int x, y;
HDC hWallpaperDC;
sz.cx = DeskWin->WindowRect.right - DeskWin->WindowRect.left;
sz.cy = DeskWin->WindowRect.bottom - DeskWin->WindowRect.top;
IntReleaseWindowObject(DeskWin);
x = (sz.cx / 2) - (WinSta->cxWallpaper / 2);
y = (sz.cy / 2) - (WinSta->cyWallpaper / 2);
hWallpaperDC = NtGdiCreateCompatableDC(hDC);
if(hWallpaperDC != NULL)
{
HBITMAP hOldBitmap;
if(x > 0 || y > 0)
{
/* FIXME - clip out the bitmap */
PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
NtGdiSelectObject(hDC, PreviousBrush);
}
else
doPatBlt = FALSE;
hOldBitmap = NtGdiSelectObject(hWallpaperDC, WinSta->hbmWallpaper);
NtGdiBitBlt(hDC, x, y, WinSta->cxWallpaper, WinSta->cyWallpaper, hWallpaperDC, 0, 0, SRCCOPY);
NtGdiSelectObject(hWallpaperDC, hOldBitmap);
NtGdiDeleteDC(hWallpaperDC);
}
}
}
if (doPatBlt) {
PreviousBrush = NtGdiSelectObject(hDC, DesktopBrush);
NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right, Rect.bottom, PATCOPY);
NtGdiSelectObject(hDC, PreviousBrush);
}
/*
* Display system version on the desktop background
*/
if (g_PaintDesktopVersion) {
static WCHAR s_wszVersion[256] = {0};
RECT rect;
if (*s_wszVersion)
len = wcslen(s_wszVersion);
else
len = GetSystemVersionString(s_wszVersion);
if (len) {
if (!NtUserSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0)) {
rect.right = NtUserGetSystemMetrics(SM_CXSCREEN);
rect.bottom = NtUserGetSystemMetrics(SM_CYSCREEN);
}
COLORREF color_old = NtGdiSetTextColor(hDC, RGB(255,255,255));
UINT align_old = NtGdiSetTextAlign(hDC, TA_RIGHT);
int mode_old = NtGdiSetBkMode(hDC, TRANSPARENT);
NtGdiTextOut(hDC, rect.right-16, rect.bottom-48, s_wszVersion, len);
NtGdiSetBkMode(hDC, mode_old);
NtGdiSetTextAlign(hDC, align_old);
NtGdiSetTextColor(hDC, color_old);
}
}
return TRUE;
}
/*
* NtUserSwitchDesktop
*
* Sets the current input (interactive) desktop.
*
* Parameters
* hDesktop
* Handle to desktop.
*
* Return Value
* Status
*
* Status
* @unimplemented
*/
BOOL STDCALL
NtUserSwitchDesktop(HDESK hDesktop)
{
PDESKTOP_OBJECT DesktopObject, PreviousDesktop;
NTSTATUS Status;
DPRINT("About to switch desktop (0x%X)\n", hDesktop);
Status = IntValidateDesktopHandle(
hDesktop,
UserMode,
0,
&DesktopObject);
if (!NT_SUCCESS(Status))
{
DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
return FALSE;
}
/*
* Don't allow applications switch the desktop if it's locked, unless the caller
* is the logon application itself
*/
if((DesktopObject->WindowStation->Flags & WSS_LOCKED) &&
LogonProcess != NULL && LogonProcess != PsGetWin32Process())
{
ObDereferenceObject(DesktopObject);
DPRINT1("Switching desktop 0x%x denied because the work station is locked!\n", hDesktop);
return FALSE;
}
/* FIXME: Fail if the desktop belong to an invisible window station */
/* FIXME: Fail if the process is associated with a secured
desktop such as Winlogon or Screen-Saver */
/* FIXME: Connect to input device */
/* Set the active desktop in the desktop's window station. */
PreviousDesktop = InterlockedExchangePointer(&DesktopObject->WindowStation->ActiveDesktop, DesktopObject);
if(PreviousDesktop != DesktopObject)
{
/* FIXME - nasty hack... */
if(PreviousDesktop != NULL)
{
IntHideDesktop(PreviousDesktop);
}
/* Set the global state. */
InputDesktop = DesktopObject;
InputWindowStation = DesktopObject->WindowStation;
/* FIXME - HACK! This is only because we want GUI on demand! */
if(IntIsGUIActive())
{
IntShowDesktop(DesktopObject);
}
}
ObDereferenceObject(DesktopObject);
return TRUE;
}
/*
* NtUserResolveDesktopForWOW
*
* Status
* @unimplemented
*/
DWORD STDCALL
NtUserResolveDesktopForWOW(DWORD Unknown0)
{
UNIMPLEMENTED
return 0;
}
/*
* NtUserGetThreadDesktop
*
* Status
* @implemented
*/
HDESK STDCALL
NtUserGetThreadDesktop(DWORD dwThreadId, DWORD Unknown1)
{
NTSTATUS Status;
PETHREAD Thread;
PDESKTOP_OBJECT DesktopObject;
HDESK Ret, hThreadDesktop;
OBJECT_HANDLE_INFORMATION HandleInformation;
if(!dwThreadId)
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return 0;
}
Status = PsLookupThreadByThreadId((PVOID)dwThreadId, &Thread);
if(!NT_SUCCESS(Status))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return 0;
}
if(Thread->ThreadsProcess == PsGetCurrentProcess())
{
/* just return the handle, we queried the desktop handle of a thread running
in the same context */
Ret = Thread->Tcb.Win32Thread->hDesktop;
ObDereferenceObject(Thread);
return Ret;
}
/* get the desktop handle and the desktop of the thread */
if(!(hThreadDesktop = Thread->Tcb.Win32Thread->hDesktop) ||
!(DesktopObject = Thread->Tcb.Win32Thread->Desktop))
{
ObDereferenceObject(Thread);
DPRINT1("Desktop information of thread 0x%x broken!?\n", dwThreadId);
return NULL;
}
/* we could just use DesktopObject instead of looking up the handle, but latter
may be a bit safer (e.g. when the desktop is being destroyed */
/* switch into the context of the thread we're trying to get the desktop from,
so we can use the handle */
KeAttachProcess(Thread->ThreadsProcess);
Status = ObReferenceObjectByHandle(hThreadDesktop,
GENERIC_ALL,
ExDesktopObjectType,
UserMode,
(PVOID*)&DesktopObject,
&HandleInformation);
KeDetachProcess();
/* the handle couldn't be found, there's nothing to get... */
if(!NT_SUCCESS(Status))
{
ObDereferenceObject(Thread);
return NULL;
}
/* lookup our handle table if we can find a handle to the desktop object,
if not, create one */
Ret = IntGetDesktopObjectHandle(DesktopObject);
/* all done, we got a valid handle to the desktop */
ObDereferenceObject(DesktopObject);
ObDereferenceObject(Thread);
return Ret;
}
/*
* NtUserSetThreadDesktop
*
* Status
* @implemented
*/
BOOL STDCALL
NtUserSetThreadDesktop(HDESK hDesktop)
{
PW32THREAD W32Thread;
PDESKTOP_OBJECT DesktopObject;
NTSTATUS Status;
/* Validate the new desktop. */
Status = IntValidateDesktopHandle(
hDesktop,
UserMode,
0,
&DesktopObject);
if (!NT_SUCCESS(Status))
{
DPRINT("Validation of desktop handle (0x%X) failed\n", hDesktop);
return FALSE;
}
W32Thread = PsGetWin32Thread();
/* FIXME: Should check here to see if the thread has any windows. */
if (W32Thread->Desktop != NULL)
{
ObDereferenceObject(W32Thread->Desktop);
}
W32Thread->Desktop = DesktopObject;
W32Thread->hDesktop = hDesktop;
return TRUE;
}
/* EOF */