winsta.c

来自「一个类似windows」· C语言 代码 · 共 1,514 行 · 第 1/3 页

C
1,514
字号
/*
 *  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.
 *
 *  COPYRIGHT:        See COPYING in the top level directory
 *  PROJECT:          ReactOS kernel
 *  PURPOSE:          Window stations
 *  FILE:             subsys/win32k/ntuser/winsta.c
 *  PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
 *  REVISION HISTORY:
 *       06-06-2001  CSH  Created
 *  NOTES:            Exported functions set the Win32 last error value
 *                    on errors. The value can be retrieved with the Win32
 *                    function GetLastError().
 *  TODO:             The process window station is created on
 *                    the first USER32/GDI32 call not related
 *                    to window station/desktop handling
 */

/* INCLUDES ******************************************************************/

#include <w32k.h>

#define NDEBUG
#include <debug.h>

/* GLOBALS *******************************************************************/

/* Currently active window station */
PWINSTATION_OBJECT InputWindowStation = NULL;

/* INITALIZATION FUNCTIONS ****************************************************/

static GENERIC_MAPPING IntWindowStationMapping =
   {
      STANDARD_RIGHTS_READ     | WINSTA_ENUMDESKTOPS      | WINSTA_ENUMERATE         | WINSTA_READATTRIBUTES | WINSTA_READSCREEN,
      STANDARD_RIGHTS_WRITE    | WINSTA_ACCESSCLIPBOARD   | WINSTA_CREATEDESKTOP     | WINSTA_WRITEATTRIBUTES,
      STANDARD_RIGHTS_EXECUTE  | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS,
      STANDARD_RIGHTS_REQUIRED | WINSTA_ACCESSCLIPBOARD   | WINSTA_ACCESSGLOBALATOMS | WINSTA_CREATEDESKTOP  |
      WINSTA_ENUMDESKTOPS      | WINSTA_ENUMERATE         | WINSTA_EXITWINDOWS    |
      WINSTA_READATTRIBUTES    | WINSTA_READSCREEN        | WINSTA_WRITEATTRIBUTES
   };

NTSTATUS FASTCALL
InitWindowStationImpl(VOID)
{
   OBJECT_ATTRIBUTES ObjectAttributes;
   HANDLE WindowStationsDirectory;
   UNICODE_STRING UnicodeString;
   NTSTATUS Status;

   /*
    * Create the '\Windows\WindowStations' directory
    */

   RtlInitUnicodeString(&UnicodeString, WINSTA_ROOT_NAME);
   InitializeObjectAttributes(&ObjectAttributes, &UnicodeString,
                              0, NULL, NULL);
   Status = ZwCreateDirectoryObject(&WindowStationsDirectory, 0,
                                    &ObjectAttributes);
   if (!NT_SUCCESS(Status))
   {
      DPRINT("Could not create \\Windows\\WindowStations directory "
             "(Status 0x%X)\n", Status);
      return Status;
   }

   /* Set Winsta Object Attributes */
   ExWindowStationObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(WINSTATION_OBJECT);
   ExWindowStationObjectType->TypeInfo.GenericMapping = IntWindowStationMapping;

   return STATUS_SUCCESS;
}

NTSTATUS FASTCALL
CleanupWindowStationImpl(VOID)
{
   return STATUS_SUCCESS;
}

/* OBJECT CALLBACKS  **********************************************************/

NTSTATUS
STDCALL
IntWinStaObjectOpen(OB_OPEN_REASON Reason,
                    PVOID ObjectBody,
                    PEPROCESS Process,
                    ULONG HandleCount,
                    ACCESS_MASK GrantedAccess)
{
   PWINSTATION_OBJECT WinSta = (PWINSTATION_OBJECT)ObjectBody;
   NTSTATUS Status;

DPRINT1("IntWinStaObjectOpen\n");

   if (Reason == ObCreateHandle)
   {
      DPRINT("Creating window station (0x%X)\n", WinSta);

      KeInitializeSpinLock(&WinSta->Lock);

      InitializeListHead(&WinSta->DesktopListHead);

DPRINT1("Create winsta atomtable\n");
      WinSta->AtomTable = NULL;
      Status = RtlCreateAtomTable(37, &WinSta->AtomTable);
if (!NT_SUCCESS(Status)) DPRINT1("Error creating atom table\n");
      WinSta->SystemMenuTemplate = (HANDLE)0;

      DPRINT("Window station successfully created.\n");
   }

   return STATUS_SUCCESS;
}

VOID STDCALL
IntWinStaObjectDelete(PVOID DeletedObject)
{
   PWINSTATION_OBJECT WinSta = (PWINSTATION_OBJECT)DeletedObject;

   DPRINT("Deleting window station (0x%X)\n", WinSta);

   RtlDestroyAtomTable(WinSta->AtomTable);

   RtlFreeUnicodeString(&WinSta->Name);
}

PVOID STDCALL
IntWinStaObjectFind(PVOID Object,
                    PWSTR Name,
                    ULONG Attributes)
{
   PLIST_ENTRY Current;
   PDESKTOP_OBJECT CurrentObject;
   PWINSTATION_OBJECT WinStaObject = (PWINSTATION_OBJECT)Object;

   DPRINT("WinStaObject (0x%X)  Name (%wS)\n", WinStaObject, Name);

   if (Name[0] == 0)
   {
      return NULL;
   }

   Current = WinStaObject->DesktopListHead.Flink;
   while (Current != &WinStaObject->DesktopListHead)
   {
      CurrentObject = CONTAINING_RECORD(Current, DESKTOP_OBJECT, ListEntry);
      DPRINT("Scanning %wZ for %wS\n", &CurrentObject->Name, Name);
      if (Attributes & OBJ_CASE_INSENSITIVE)
      {
         if (_wcsicmp(CurrentObject->Name.Buffer, Name) == 0)
         {
            DPRINT("Found desktop at (0x%X)\n", CurrentObject);
            return CurrentObject;
         }
      }
      else
      {
         if (wcscmp(CurrentObject->Name.Buffer, Name) == 0)
         {
            DPRINT("Found desktop at (0x%X)\n", CurrentObject);
            return CurrentObject;
         }
      }
      Current = Current->Flink;
   }

   DPRINT("Returning NULL\n");

   return NULL;
}

NTSTATUS
STDCALL
IntWinStaObjectParse(PVOID Object,
                     PVOID *NextObject,
                     PUNICODE_STRING FullPath,
                     PWSTR *Path,
                     ULONG Attributes)
{
   PVOID FoundObject;
   NTSTATUS Status;
   PWSTR End;

   DPRINT("Object (0x%X)  Path (0x%X)  *Path (%wS)\n", Object, Path, *Path);

   *NextObject = NULL;

   if ((Path == NULL) || ((*Path) == NULL))
   {
      return STATUS_SUCCESS;
   }

   End = wcschr((*Path) + 1, '\\');
   if (End != NULL)
   {
      DPRINT("Name contains illegal characters\n");
      return STATUS_UNSUCCESSFUL;
   }

   FoundObject = IntWinStaObjectFind(Object, (*Path) + 1, Attributes);
   if (FoundObject == NULL)
   {
      DPRINT("Name was not found\n");
      return STATUS_UNSUCCESSFUL;
   }

   Status = ObReferenceObjectByPointer(
               FoundObject,
               STANDARD_RIGHTS_REQUIRED,
               NULL,
               UserMode);

   *NextObject = FoundObject;
   *Path = NULL;

   return Status;
}

/* PRIVATE FUNCTIONS **********************************************************/

/*
 * IntGetFullWindowStationName
 *
 * Get a full window station object name from a name specified in
 * NtUserCreateWindowStation, NtUserOpenWindowStation, NtUserCreateDesktop
 * or NtUserOpenDesktop.
 *
 * Return Value
 *    TRUE on success, FALSE on failure.
 */

BOOL FASTCALL
IntGetFullWindowStationName(
   OUT PUNICODE_STRING FullName,
   IN PUNICODE_STRING WinStaName,
   IN OPTIONAL PUNICODE_STRING DesktopName)
{
   PWCHAR Buffer;

   FullName->Length = WINSTA_ROOT_NAME_LENGTH * sizeof(WCHAR);
   if (WinStaName != NULL)
      FullName->Length += WinStaName->Length + sizeof(WCHAR);
   if (DesktopName != NULL)
      FullName->Length += DesktopName->Length + sizeof(WCHAR);
   FullName->MaximumLength = FullName->Length;
   FullName->Buffer = ExAllocatePoolWithTag(PagedPool, FullName->Length, TAG_STRING);
   if (FullName->Buffer == NULL)
   {
      return FALSE;
   }

   Buffer = FullName->Buffer;
   memcpy(Buffer, WINSTA_ROOT_NAME, WINSTA_ROOT_NAME_LENGTH * sizeof(WCHAR));
   Buffer += WINSTA_ROOT_NAME_LENGTH;
   if (WinStaName != NULL)
   {
      memcpy(Buffer, L"\\", sizeof(WCHAR));
      Buffer ++;
      memcpy(Buffer, WinStaName->Buffer, WinStaName->Length);

      if (DesktopName != NULL)
      {
         Buffer += WinStaName->Length / sizeof(WCHAR);
         memcpy(Buffer, L"\\", sizeof(WCHAR));
         Buffer ++;
         memcpy(Buffer, DesktopName->Buffer, DesktopName->Length);
      }
   }

   return TRUE;
}

/*
 * IntValidateWindowStationHandle
 *
 * Validates the window station handle.
 *
 * Remarks
 *    If the function succeeds, the handle remains referenced. If the
 *    fucntion fails, last error is set.
 */

NTSTATUS FASTCALL
IntValidateWindowStationHandle(
   HWINSTA WindowStation,
   KPROCESSOR_MODE AccessMode,
   ACCESS_MASK DesiredAccess,
   PWINSTATION_OBJECT *Object)
{
   NTSTATUS Status;

   if (WindowStation == NULL)
   {
      //      DPRINT1("Invalid window station handle\n");
      SetLastWin32Error(ERROR_INVALID_HANDLE);
      return STATUS_INVALID_HANDLE;
   }

   Status = ObReferenceObjectByHandle(
               WindowStation,
               DesiredAccess,
               ExWindowStationObjectType,
               AccessMode,
               (PVOID*)Object,
               NULL);

   if (!NT_SUCCESS(Status))
      SetLastNtError(Status);

   return Status;
}

BOOL FASTCALL
IntGetWindowStationObject(PWINSTATION_OBJECT Object)
{
   NTSTATUS Status;

   Status = ObReferenceObjectByPointer(
               Object,
               KernelMode,
               ExWindowStationObjectType,
               0);

   return NT_SUCCESS(Status);
}

BOOL FASTCALL
co_IntInitializeDesktopGraphics(VOID)
{
   UNICODE_STRING DriverName;
   if (! IntCreatePrimarySurface())
   {
      return FALSE;
   }
   RtlInitUnicodeString(&DriverName, L"DISPLAY");
   ScreenDeviceContext = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, FALSE);
   if (NULL == ScreenDeviceContext)
   {
      IntDestroyPrimarySurface();
      return FALSE;
   }
   DC_SetOwnership(ScreenDeviceContext, NULL);

   UserAcquireOrReleaseInputOwnership(FALSE);

   /* Setup the cursor */
   co_IntLoadDefaultCursors();

   return TRUE;
}

VOID FASTCALL
IntEndDesktopGraphics(VOID)
{
   UserAcquireOrReleaseInputOwnership(TRUE);
   if (NULL != ScreenDeviceContext)
   {
      DC_SetOwnership(ScreenDeviceContext, PsGetCurrentProcess());
      NtGdiDeleteObjectApp(ScreenDeviceContext);
      ScreenDeviceContext = NULL;
   }
   IntHideDesktop(IntGetActiveDesktop());
   IntDestroyPrimarySurface();
}

HDC FASTCALL
IntGetScreenDC(VOID)
{
   return ScreenDeviceContext;
}

/* PUBLIC FUNCTIONS ***********************************************************/

/*
 * NtUserCreateWindowStation
 *
 * Creates a new window station.
 *
 * Parameters
 *    lpszWindowStationName
 *       Pointer to a null-terminated string specifying the name of the
 *       window station to be created. Window station names are
 *       case-insensitive and cannot contain backslash characters (\).
 *       Only members of the Administrators group are allowed to specify a
 *       name.
 *
 *    dwDesiredAccess
 *       Requested type of access
 *
 *    lpSecurity
 *       Security descriptor
 *
 *    Unknown3, Unknown4, Unknown5
 *       Unused
 *
 * Return Value
 *    If the function succeeds, the return value is a handle to the newly
 *    created window station. If the specified window station already
 *    exists, the function succeeds and returns a handle to the existing
 *    window station. If the function fails, the return value is NULL.
 *
 * Todo
 *    Correct the prototype to match the Windows one (with 7 parameters
 *    on Windows XP).
 *
 * Status
 *    @implemented
 */

HWINSTA STDCALL
NtUserCreateWindowStation(
   PUNICODE_STRING lpszWindowStationName,
   ACCESS_MASK dwDesiredAccess,
   LPSECURITY_ATTRIBUTES lpSecurity,
   DWORD Unknown3,
   DWORD Unknown4,
   DWORD Unknown5)
{
   PSYSTEM_CURSORINFO CurInfo;
   UNICODE_STRING WindowStationName;
   UNICODE_STRING FullWindowStationName;
   PWINSTATION_OBJECT WindowStationObject;
   HWINSTA WindowStation;
   OBJECT_ATTRIBUTES ObjectAttributes;
   NTSTATUS Status;

   /*
    * Generate full window station name
    */
   Status = ProbeAndCaptureUnicodeString(&WindowStationName,
                                         UserMode,
                                         lpszWindowStationName);
   if (!NT_SUCCESS(Status))
   {
      DPRINT1("Failed to capture window station name (status 0x%08x)\n",
              Status);
      SetLastNtError(Status);
      return 0;
   }
   if (!IntGetFullWindowStationName(&FullWindowStationName,
                                    &WindowStationName,
                                    NULL))
   {
      ReleaseCapturedUnicodeString(&WindowStationName, UserMode);
      SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
      return 0;
   }

   /*
    * Try to open already existing window station
    */

   DPRINT("Trying to open window station (%wZ)\n", &FullWindowStationName);

   /* Initialize ObjectAttributes for the window station object */
   InitializeObjectAttributes(
      &ObjectAttributes,
      &FullWindowStationName,
      0,
      NULL,
      NULL);

   Status = ObOpenObjectByName(
               &ObjectAttributes,
               ExWindowStationObjectType,
               NULL,
               KernelMode,
               dwDesiredAccess,
               NULL,
               (PVOID*)&WindowStation);

   if (NT_SUCCESS(Status))
   {
      DPRINT("Successfully opened window station (%wZ)\n",
             FullWindowStationName);
      ExFreePool(FullWindowStationName.Buffer);
      ReleaseCapturedUnicodeString(&WindowStationName, UserMode);
      return (HWINSTA)WindowStation;
   }

   /*
    * No existing window station found, try to create new one
    */

   DPRINT("Creating window station (%wZ)\n", &FullWindowStationName);

   Status = ObCreateObject(
               KernelMode,
               ExWindowStationObjectType,
               &ObjectAttributes,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?