/* GLOBALS *******************************************************************/
-/* Currently active window station */
+/*
+ * The currently active window station. This is the
+ * only one interactive window station on the system.
+ */
PWINSTATION_OBJECT InputWindowStation = NULL;
/* Winlogon SAS window */
NTAPI
UserCreateWinstaDirectory(VOID)
{
- PPEB Peb;
NTSTATUS Status;
- WCHAR wstrWindowStationsDir[MAX_PATH];
+ PPEB Peb;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hWinstaDir;
+ WCHAR wstrWindowStationsDir[MAX_PATH];
/* Create the WindowStations directory and cache its path for later use */
Peb = NtCurrentPeb();
}
else
{
- swprintf(wstrWindowStationsDir,
- L"%ws\\%lu%ws",
- SESSION_DIR,
- Peb->SessionId,
- WINSTA_OBJ_DIR);
+ Status = RtlStringCbPrintfW(wstrWindowStationsDir,
+ sizeof(wstrWindowStationsDir),
+ L"%ws\\%lu%ws",
+ SESSION_DIR,
+ Peb->SessionId,
+ WINSTA_OBJ_DIR);
+ if (!NT_SUCCESS(Status))
+ return Status;
if (!RtlCreateUnicodeString(&gustrWindowStationsDir, wstrWindowStationsDir))
{
InitializeObjectAttributes(&ObjectAttributes,
&gustrWindowStationsDir,
- 0,
+ OBJ_KERNEL_HANDLE,
NULL,
NULL);
- Status = ZwCreateDirectoryObject(&hWinstaDir, 0, &ObjectAttributes);
+ Status = ZwCreateDirectoryObject(&hWinstaDir, DIRECTORY_CREATE_OBJECT, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir, Status);
return Status;
}
-/* OBJECT CALLBACKS **********************************************************/
+/* OBJECT CALLBACKS ***********************************************************/
NTSTATUS
NTAPI
PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters = Parameters;
PWINSTATION_OBJECT WinSta = (PWINSTATION_OBJECT)DeleteParameters->Object;
- TRACE("Deleting window station (0x%p)\n", WinSta);
+ TRACE("Deleting window station 0x%p\n", WinSta);
+
+ if (WinSta == InputWindowStation)
+ {
+ ERR("WARNING: Deleting the interactive window station '%wZ'!\n",
+ &(OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(InputWindowStation))->Name));
+
+ /* Only Winlogon can close and delete the interactive window station */
+ ASSERT(gpidLogon == PsGetCurrentProcessId());
+
+ InputWindowStation = NULL;
+ }
WinSta->Flags |= WSS_DYING;
RtlDestroyAtomTable(WinSta->AtomTable);
- RtlFreeUnicodeString(&WinSta->Name);
-
return STATUS_SUCCESS;
}
ppi = PsGetCurrentProcessWin32Process();
- if(ppi && (OkToCloseParameters->Handle == ppi->hwinsta))
+ if (ppi && (OkToCloseParameters->Handle == ppi->hwinsta))
{
return STATUS_ACCESS_DENIED;
}
}
GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_PUBLIC);
- if (! IntCreatePrimarySurface())
+ if (!IntCreatePrimarySurface())
{
return FALSE;
}
NtGdiSelectFont(hSystemBM, NtGdiGetStockObject(SYSTEM_FONT));
GreSetDCOwner(hSystemBM, GDI_OBJ_HMGR_PUBLIC);
+ /* Update the system metrics */
+ InitMetrics();
+
+ /* Set new size of the monitor */
+ UserUpdateMonitorSize((HDEV)gppdevPrimary);
+
/* Update the SERVERINFO */
gpsi->aiSysMet[SM_CXSCREEN] = gppdevPrimary->gdiinfo.ulHorzRes;
gpsi->aiSysMet[SM_CYSCREEN] = gppdevPrimary->gdiinfo.ulVertRes;
gpsi->PUSIFlags |= PUSIF_PALETTEDISPLAY;
}
else
+ {
gpsi->PUSIFlags &= ~PUSIF_PALETTEDISPLAY;
+ }
// Font is realized and this dc was previously set to internal DC_ATTR.
gpsi->cxSysFontChar = IntGetCharDimensions(hSystemBM, &tmw, (DWORD*)&gpsi->cySysFontChar);
gpsi->tmSysFont = tmw;
* @implemented
*/
-HWINSTA APIENTRY
-NtUserCreateWindowStation(
- POBJECT_ATTRIBUTES ObjectAttributes,
- ACCESS_MASK dwDesiredAccess,
+NTSTATUS
+FASTCALL
+IntCreateWindowStation(
+ OUT HWINSTA* phWinSta,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN KPROCESSOR_MODE AccessMode,
+ IN KPROCESSOR_MODE OwnerMode,
+ IN ACCESS_MASK dwDesiredAccess,
DWORD Unknown2,
DWORD Unknown3,
DWORD Unknown4,
DWORD Unknown5,
DWORD Unknown6)
{
- UNICODE_STRING WindowStationName;
- PWINSTATION_OBJECT WindowStationObject;
- HWINSTA WindowStation;
NTSTATUS Status;
+ HWINSTA hWinSta;
+ PWINSTATION_OBJECT WindowStation;
- TRACE("NtUserCreateWindowStation called\n");
+ TRACE("IntCreateWindowStation called\n");
+
+ ASSERT(phWinSta);
+ *phWinSta = NULL;
Status = ObOpenObjectByName(ObjectAttributes,
ExWindowStationObjectType,
- UserMode,
+ AccessMode,
NULL,
dwDesiredAccess,
NULL,
- (PVOID*)&WindowStation);
-
+ (PVOID*)&hWinSta);
if (NT_SUCCESS(Status))
{
- TRACE("NtUserCreateWindowStation opened window station %wZ\n", ObjectAttributes->ObjectName);
- return (HWINSTA)WindowStation;
+ TRACE("IntCreateWindowStation opened window station '%wZ'\n",
+ ObjectAttributes->ObjectName);
+ *phWinSta = hWinSta;
+ return Status;
}
/*
- * No existing window station found, try to create new one
+ * No existing window station found, try to create a new one.
*/
- /* Capture window station name */
- _SEH2_TRY
- {
- ProbeForRead( ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1);
- Status = IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName, ObjectAttributes->ObjectName);
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status =_SEH2_GetExceptionCode();
- }
- _SEH2_END
-
- if (! NT_SUCCESS(Status))
- {
- ERR("Failed reading capturing window station name\n");
- SetLastNtError(Status);
- return NULL;
- }
-
/* Create the window station object */
- Status = ObCreateObject(UserMode,
+ Status = ObCreateObject(AccessMode,
ExWindowStationObjectType,
ObjectAttributes,
- UserMode,
+ OwnerMode,
NULL,
sizeof(WINSTATION_OBJECT),
0,
0,
- (PVOID*)&WindowStationObject);
-
+ (PVOID*)&WindowStation);
if (!NT_SUCCESS(Status))
{
- ERR("ObCreateObject failed with %lx for window station %wZ\n", Status, &WindowStationName);
- ExFreePoolWithTag(WindowStationName.Buffer, TAG_STRING);
- SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
- return 0;
+ ERR("ObCreateObject failed for window station '%wZ', Status 0x%08lx\n",
+ ObjectAttributes->ObjectName, Status);
+ SetLastNtError(Status);
+ return Status;
}
/* Initialize the window station */
- RtlZeroMemory(WindowStationObject, sizeof(WINSTATION_OBJECT));
+ RtlZeroMemory(WindowStation, sizeof(WINSTATION_OBJECT));
- InitializeListHead(&WindowStationObject->DesktopListHead);
- WindowStationObject->Name = WindowStationName;
- WindowStationObject->dwSessionId = NtCurrentPeb()->SessionId;
- Status = RtlCreateAtomTable(37, &WindowStationObject->AtomTable);
+ InitializeListHead(&WindowStation->DesktopListHead);
+ WindowStation->dwSessionId = NtCurrentPeb()->SessionId;
+ Status = RtlCreateAtomTable(37, &WindowStation->AtomTable);
if (!NT_SUCCESS(Status))
{
- ERR("RtlCreateAtomTable failed with %lx for window station %wZ\n", Status, &WindowStationName);
- ObDereferenceObject(WindowStationObject);
- SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
- return 0;
+ ERR("RtlCreateAtomTable failed for window station '%wZ', Status 0x%08lx\n",
+ ObjectAttributes->ObjectName, Status);
+ ObDereferenceObject(WindowStation);
+ SetLastNtError(Status);
+ return Status;
}
- Status = ObInsertObject((PVOID)WindowStationObject,
+ Status = ObInsertObject(WindowStation,
NULL,
dwDesiredAccess,
0,
NULL,
- (PVOID*)&WindowStation);
-
+ (PVOID*)&hWinSta);
if (!NT_SUCCESS(Status))
{
- ERR("ObInsertObject failed with %lx for window station\n", Status);
- SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
- return 0;
+ ERR("ObInsertObject failed for window station, Status 0x%08lx\n", Status);
+ SetLastNtError(Status);
+ return Status;
}
+ // FIXME! TODO: Add this new window station to a linked list
+
if (InputWindowStation == NULL)
{
ERR("Initializing input window station\n");
- InputWindowStation = WindowStationObject;
- WindowStationObject->Flags &= ~WSS_NOIO;
+ /* Only Winlogon can create the interactive window station */
+ ASSERT(gpidLogon == PsGetCurrentProcessId());
+
+ InputWindowStation = WindowStation;
+ WindowStation->Flags &= ~WSS_NOIO;
InitCursorImpl();
+
+ UserCreateSystemThread(ST_DESKTOP_THREAD);
+ UserCreateSystemThread(ST_RIT);
+
+ /* Desktop functions require the desktop thread running so wait for it to initialize */
+ UserLeaveCo();
+ KeWaitForSingleObject(gpDesktopThreadStartedEvent,
+ UserRequest,
+ UserMode,
+ FALSE,
+ NULL);
+ UserEnterCo();
+ }
+ else
+ {
+ WindowStation->Flags |= WSS_NOIO;
+ }
+
+ TRACE("IntCreateWindowStation created window station '%wZ' object 0x%p handle 0x%p\n",
+ ObjectAttributes->ObjectName, WindowStation, hWinSta);
+
+ *phWinSta = hWinSta;
+ EngSetLastError(ERROR_SUCCESS);
+
+ return STATUS_SUCCESS;
+}
+
+static VOID
+FreeUserModeWindowStationName(
+ IN OUT PUNICODE_STRING WindowStationName,
+ IN PUNICODE_STRING TebStaticUnicodeString,
+ IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes OPTIONAL,
+ IN POBJECT_ATTRIBUTES LocalObjectAttributes OPTIONAL)
+{
+ SIZE_T MemSize = 0;
+
+ /* Try to restore the user's UserModeObjectAttributes */
+ if (UserModeObjectAttributes && LocalObjectAttributes)
+ {
+ _SEH2_TRY
+ {
+ ProbeForWrite(UserModeObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
+ *UserModeObjectAttributes = *LocalObjectAttributes;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ NOTHING;
+ }
+ _SEH2_END;
+ }
+
+ /* Free the user-mode memory */
+ if (WindowStationName && (WindowStationName != TebStaticUnicodeString))
+ {
+ ZwFreeVirtualMemory(ZwCurrentProcess(),
+ (PVOID*)&WindowStationName,
+ &MemSize,
+ MEM_RELEASE);
+ }
+}
+
+static NTSTATUS
+BuildUserModeWindowStationName(
+ IN OUT POBJECT_ATTRIBUTES UserModeObjectAttributes,
+ IN OUT POBJECT_ATTRIBUTES LocalObjectAttributes,
+ OUT PUNICODE_STRING* WindowStationName,
+ OUT PUNICODE_STRING* TebStaticUnicodeString)
+{
+ NTSTATUS Status;
+ SIZE_T MemSize;
+
+ LUID CallerLuid;
+ PTEB Teb;
+ USHORT StrSize;
+
+ *WindowStationName = NULL;
+ *TebStaticUnicodeString = NULL;
+
+ /* Retrieve the current process LUID */
+ Status = GetProcessLuid(NULL, NULL, &CallerLuid);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("Failed to retrieve the caller LUID, Status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ /* Compute the needed string size */
+ MemSize = _scwprintf(L"%wZ\\Service-0x%x-%x$",
+ &gustrWindowStationsDir,
+ CallerLuid.HighPart,
+ CallerLuid.LowPart);
+ MemSize = MemSize * sizeof(WCHAR) + sizeof(UNICODE_NULL);
+ if (MemSize > MAXUSHORT)
+ {
+ ERR("Window station name length is too long.\n");
+ return STATUS_NAME_TOO_LONG;
+ }
+ StrSize = (USHORT)MemSize;
+
+ /*
+ * Check whether it's short enough so that we can use the static buffer
+ * in the TEB. Otherwise continue with virtual memory allocation.
+ */
+ Teb = NtCurrentTeb();
+ if (Teb && (StrSize <= sizeof(Teb->StaticUnicodeBuffer)))
+ {
+ /* We can use the TEB's static unicode string */
+ ASSERT(Teb->StaticUnicodeString.Buffer == Teb->StaticUnicodeBuffer);
+ ASSERT(Teb->StaticUnicodeString.MaximumLength == sizeof(Teb->StaticUnicodeBuffer));
+
+ /* Remember the TEB's static unicode string address for later */
+ *TebStaticUnicodeString = &Teb->StaticUnicodeString;
+
+ *WindowStationName = *TebStaticUnicodeString;
+ (*WindowStationName)->Length = 0;
+ }
+ else
+ {
+ /* The TEB's static unicode string is too small, allocate some user-mode virtual memory */
+ MemSize += ALIGN_UP(sizeof(UNICODE_STRING), sizeof(PVOID));
+
+ /* Allocate the memory in user-mode */
+ Status = ZwAllocateVirtualMemory(ZwCurrentProcess(),
+ (PVOID*)WindowStationName,
+ 0,
+ &MemSize,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("ZwAllocateVirtualMemory() failed, Status 0x%08lx\n", Status);
+ return Status;
+ }
+
+ RtlInitEmptyUnicodeString(*WindowStationName,
+ (PWCHAR)((ULONG_PTR)*WindowStationName +
+ ALIGN_UP(sizeof(UNICODE_STRING), sizeof(PVOID))),
+ StrSize);
+ }
+
+ /* Build a valid window station name from the LUID */
+ Status = RtlStringCbPrintfW((*WindowStationName)->Buffer,
+ (*WindowStationName)->MaximumLength,
+ L"%wZ\\Service-0x%x-%x$",
+ &gustrWindowStationsDir,
+ CallerLuid.HighPart,
+ CallerLuid.LowPart);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("Impossible to build a valid window station name, Status 0x%08lx\n", Status);
+ goto Quit;
+ }
+ (*WindowStationName)->Length = (USHORT)(wcslen((*WindowStationName)->Buffer) * sizeof(WCHAR));
+
+ /* Try to update the user's UserModeObjectAttributes */
+ _SEH2_TRY
+ {
+ ProbeForWrite(UserModeObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
+ *LocalObjectAttributes = *UserModeObjectAttributes;
+
+ UserModeObjectAttributes->ObjectName = *WindowStationName;
+ UserModeObjectAttributes->RootDirectory = NULL;
+
+ Status = STATUS_SUCCESS;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+Quit:
+ if (!NT_SUCCESS(Status))
+ {
+ /* Release the window station name */
+ FreeUserModeWindowStationName(*WindowStationName,
+ *TebStaticUnicodeString,
+ NULL, NULL);
+ }
+
+ return Status;
+}
+
+HWINSTA
+APIENTRY
+NtUserCreateWindowStation(
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN ACCESS_MASK dwDesiredAccess,
+ DWORD Unknown2,
+ DWORD Unknown3,
+ DWORD Unknown4,
+ DWORD Unknown5,
+ DWORD Unknown6)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ HWINSTA hWinSta = NULL;
+ OBJECT_ATTRIBUTES LocalObjectAttributes;
+ PUNICODE_STRING WindowStationName = NULL;
+ PUNICODE_STRING TebStaticUnicodeString = NULL;
+ KPROCESSOR_MODE OwnerMode = UserMode;
+
+ TRACE("NtUserCreateWindowStation called\n");
+
+ /* Capture the object attributes and the window station name */
+ _SEH2_TRY
+ {
+ ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
+ LocalObjectAttributes = *ObjectAttributes;
+ if (LocalObjectAttributes.Length != sizeof(OBJECT_ATTRIBUTES))
+ {
+ ERR("Invalid ObjectAttributes length!\n");
+ Status = STATUS_INVALID_PARAMETER;
+ _SEH2_LEAVE;
+ }
+
+ /*
+ * Check whether the caller provided a window station name together
+ * with a RootDirectory handle.
+ *
+ * If the caller did not provide a window station name, build a new one
+ * based on the logon session identifier for the calling process.
+ * The new name is allocated in user-mode, as the rest of ObjectAttributes
+ * already is, so that the validation performed by the Object Manager
+ * can be done adequately.
+ */
+ if ((LocalObjectAttributes.ObjectName == NULL ||
+ LocalObjectAttributes.ObjectName->Buffer == NULL ||
+ LocalObjectAttributes.ObjectName->Length == 0 ||
+ LocalObjectAttributes.ObjectName->Buffer[0] == UNICODE_NULL)
+ /* &&
+ LocalObjectAttributes.RootDirectory == NULL */)
+ {
+ /* No, build the new window station name */
+ Status = BuildUserModeWindowStationName(ObjectAttributes,
+ &LocalObjectAttributes,
+ &WindowStationName,
+ &TebStaticUnicodeString);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status);
+ _SEH2_LEAVE;
+ }
+ OwnerMode = KernelMode;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status =_SEH2_GetExceptionCode();
+ ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status);
+ }
+ _SEH2_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ return NULL;
+ }
+
+ UserEnterExclusive();
+
+ /* Create the window station */
+ Status = IntCreateWindowStation(&hWinSta,
+ ObjectAttributes,
+ UserMode,
+ OwnerMode,
+ dwDesiredAccess,
+ Unknown2,
+ Unknown3,
+ Unknown4,
+ Unknown5,
+ Unknown6);
+ UserLeave();
+
+ if (NT_SUCCESS(Status))
+ {
+ TRACE("NtUserCreateWindowStation created window station '%wZ' with handle 0x%p\n",
+ ObjectAttributes->ObjectName, hWinSta);
}
else
{
- WindowStationObject->Flags |= WSS_NOIO;
+ ASSERT(hWinSta == NULL);
+ ERR("NtUserCreateWindowStation failed to create window station '%wZ', Status 0x%08lx\n",
+ ObjectAttributes->ObjectName, Status);
}
- TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n",
- WindowStation, &WindowStationObject->Name, WindowStation);
- return WindowStation;
+ /* Try to restore the user's ObjectAttributes and release the window station name */
+ FreeUserModeWindowStationName(WindowStationName,
+ TebStaticUnicodeString,
+ (OwnerMode == KernelMode ? ObjectAttributes : NULL),
+ &LocalObjectAttributes);
+
+ if (!NT_SUCCESS(Status))
+ {
+ ASSERT(hWinSta == NULL);
+ SetLastNtError(Status);
+ }
+
+ return hWinSta;
}
/*
* @implemented
*/
-HWINSTA APIENTRY
+HWINSTA
+APIENTRY
NtUserOpenWindowStation(
- POBJECT_ATTRIBUTES ObjectAttributes,
- ACCESS_MASK dwDesiredAccess)
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN ACCESS_MASK dwDesiredAccess)
{
- HWINSTA hwinsta;
- NTSTATUS Status;
+ NTSTATUS Status = STATUS_SUCCESS;
+ HWINSTA hWinSta = NULL;
+ OBJECT_ATTRIBUTES LocalObjectAttributes;
+ PUNICODE_STRING WindowStationName = NULL;
+ PUNICODE_STRING TebStaticUnicodeString = NULL;
+ KPROCESSOR_MODE OwnerMode = UserMode;
+ TRACE("NtUserOpenWindowStation called\n");
+
+ /* Capture the object attributes and the window station name */
+ _SEH2_TRY
+ {
+ ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG));
+ LocalObjectAttributes = *ObjectAttributes;
+ if (LocalObjectAttributes.Length != sizeof(OBJECT_ATTRIBUTES))
+ {
+ ERR("Invalid ObjectAttributes length!\n");
+ Status = STATUS_INVALID_PARAMETER;
+ _SEH2_LEAVE;
+ }
+
+ /*
+ * Check whether the caller did not provide a window station name,
+ * or provided the special "Service-0x00000000-00000000$" name.
+ *
+ * NOTE: On Windows, the special "Service-0x00000000-00000000$" string
+ * is used instead of an empty name (observed when API-monitoring
+ * OpenWindowStation() called with an empty window station name).
+ */
+ if ((LocalObjectAttributes.ObjectName == NULL ||
+ LocalObjectAttributes.ObjectName->Buffer == NULL ||
+ LocalObjectAttributes.ObjectName->Length == 0 ||
+ LocalObjectAttributes.ObjectName->Buffer[0] == UNICODE_NULL)
+ /* &&
+ LocalObjectAttributes.RootDirectory == NULL */)
+ {
+ /* No, remember that for later */
+ LocalObjectAttributes.ObjectName = NULL;
+ }
+ if (LocalObjectAttributes.ObjectName &&
+ LocalObjectAttributes.ObjectName->Length ==
+ sizeof(L"Service-0x00000000-00000000$") - sizeof(UNICODE_NULL) &&
+ _wcsnicmp(LocalObjectAttributes.ObjectName->Buffer,
+ L"Service-0x00000000-00000000$",
+ LocalObjectAttributes.ObjectName->Length / sizeof(WCHAR)) == 0)
+ {
+ /* No, remember that for later */
+ LocalObjectAttributes.ObjectName = NULL;
+ }
+
+ /*
+ * If the caller did not provide a window station name, build a new one
+ * based on the logon session identifier for the calling process.
+ * The new name is allocated in user-mode, as the rest of ObjectAttributes
+ * already is, so that the validation performed by the Object Manager
+ * can be done adequately.
+ */
+ if (!LocalObjectAttributes.ObjectName)
+ {
+ /* No, build the new window station name */
+ Status = BuildUserModeWindowStationName(ObjectAttributes,
+ &LocalObjectAttributes,
+ &WindowStationName,
+ &TebStaticUnicodeString);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("BuildUserModeWindowStationName() failed, Status 0x%08lx\n", Status);
+ _SEH2_LEAVE;
+ }
+ OwnerMode = KernelMode;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status =_SEH2_GetExceptionCode();
+ ERR("ObjectAttributes capture failed, Status 0x%08lx\n", Status);
+ }
+ _SEH2_END;
+
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ return NULL;
+ }
+
+ /* Open the window station */
Status = ObOpenObjectByName(ObjectAttributes,
ExWindowStationObjectType,
UserMode,
NULL,
dwDesiredAccess,
NULL,
- (PVOID*)&hwinsta);
+ (PVOID*)&hWinSta);
+ if (NT_SUCCESS(Status))
+ {
+ TRACE("NtUserOpenWindowStation opened window station '%wZ' with handle 0x%p\n",
+ ObjectAttributes->ObjectName, hWinSta);
+ }
+ else
+ {
+ ASSERT(hWinSta == NULL);
+ ERR("NtUserOpenWindowStation failed to open window station '%wZ', Status 0x%08lx\n",
+ ObjectAttributes->ObjectName, Status);
+ }
+
+ /* Try to restore the user's ObjectAttributes and release the window station name */
+ FreeUserModeWindowStationName(WindowStationName,
+ TebStaticUnicodeString,
+ (OwnerMode == KernelMode ? ObjectAttributes : NULL),
+ &LocalObjectAttributes);
if (!NT_SUCCESS(Status))
{
- ERR("NtUserOpenWindowStation failed\n");
+ ASSERT(hWinSta == NULL);
SetLastNtError(Status);
- return 0;
}
- TRACE("Opened window station %wZ with handle %p\n", ObjectAttributes->ObjectName, hwinsta);
-
- return hwinsta;
+ return hWinSta;
}
/*
*
* Remarks
* The window station handle can be created with NtUserCreateWindowStation
- * or NtUserOpenWindowStation. Attemps to close a handle to the window
+ * or NtUserOpenWindowStation. Attempts to close a handle to the window
* station assigned to the calling process will fail.
*
* Status
UserMode,
0,
&Object,
- 0);
-
+ NULL);
if (!NT_SUCCESS(Status))
{
ERR("Validation of window station handle (%p) failed\n", hWinSta);
NTSTATUS Status;
PWINSTATION_OBJECT WinStaObject = NULL;
PDESKTOP DesktopObject = NULL;
+ POBJECT_HEADER ObjectHeader;
+ POBJECT_HEADER_NAME_INFO NameInfo;
+ OBJECT_HANDLE_INFORMATION HandleInfo;
USEROBJECTFLAGS ObjectFlags;
+ PUNICODE_STRING pStrNameU = NULL;
PVOID pvData = NULL;
SIZE_T nDataSize = 0;
_SEH2_END;
/* Try window station */
- TRACE("Trying to open window station %p\n", hObject);
+ TRACE("Trying to open window station 0x%p\n", hObject);
Status = ObReferenceObjectByHandle(hObject,
0,
ExWindowStationObjectType,
UserMode,
(PVOID*)&WinStaObject,
- NULL);
+ &HandleInfo);
if (Status == STATUS_OBJECT_TYPE_MISMATCH)
{
{
case UOI_FLAGS:
{
- OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo;
- ULONG BytesWritten;
-
ObjectFlags.fReserved = FALSE;
-
- /* Check whether this handle is inheritable */
- Status = ZwQueryObject(hObject,
- ObjectHandleFlagInformation,
- &HandleInfo,
- sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION),
- &BytesWritten);
- if (!NT_SUCCESS(Status))
- {
- ERR("ZwQueryObject failed, Status 0x%08lx\n", Status);
- break;
- }
- ObjectFlags.fInherit = HandleInfo.Inherit;
+ ObjectFlags.fInherit = !!(HandleInfo.HandleAttributes & OBJ_INHERIT);
ObjectFlags.dwFlags = 0;
if (WinStaObject != NULL)
{
if (WinStaObject != NULL)
{
- pvData = WinStaObject->Name.Buffer;
- nDataSize = WinStaObject->Name.Length + sizeof(WCHAR);
+ ObjectHeader = OBJECT_TO_OBJECT_HEADER(WinStaObject);
+ NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
+
+ if (NameInfo && (NameInfo->Name.Length > 0))
+ {
+ /* Named window station */
+ pStrNameU = &NameInfo->Name;
+ nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
+ }
+ else
+ {
+ /* Unnamed window station (should never happen!) */
+ ASSERT(FALSE);
+ pStrNameU = NULL;
+ nDataSize = sizeof(UNICODE_NULL);
+ }
Status = STATUS_SUCCESS;
}
else if (DesktopObject != NULL)
{
if (WinStaObject != NULL)
{
- pvData = L"WindowStation";
- nDataSize = sizeof(L"WindowStation");
+ ObjectHeader = OBJECT_TO_OBJECT_HEADER(WinStaObject);
+ pStrNameU = &ObjectHeader->Type->Name;
+ nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
Status = STATUS_SUCCESS;
}
else if (DesktopObject != NULL)
{
- pvData = L"Desktop";
- nDataSize = sizeof(L"Desktop");
+ ObjectHeader = OBJECT_TO_OBJECT_HEADER(DesktopObject);
+ pStrNameU = &ObjectHeader->Type->Name;
+ nDataSize = pStrNameU->Length + sizeof(UNICODE_NULL);
Status = STATUS_SUCCESS;
}
else
*nLengthNeeded = nDataSize;
/* Try to copy data to caller */
- if (Status == STATUS_SUCCESS)
+ if (Status == STATUS_SUCCESS && (nDataSize > 0))
{
TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength, nDataSize);
- RtlCopyMemory(pvInformation, pvData, nDataSize);
+ if (pvData)
+ {
+ /* Copy the data */
+ RtlCopyMemory(pvInformation, pvData, nDataSize);
+ }
+ else if (pStrNameU)
+ {
+ /* Copy and NULL-terminate the string */
+ RtlCopyMemory(pvInformation, pStrNameU->Buffer, pStrNameU->Length);
+ ((PWCHAR)pvInformation)[pStrNameU->Length / sizeof(WCHAR)] = UNICODE_NULL;
+ }
+ else
+ {
+ /* Zero the memory */
+ RtlZeroMemory(pvInformation, nDataSize);
+ }
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
}
-
-
HWINSTA FASTCALL
UserGetProcessWindowStation(VOID)
{
BOOL FASTCALL
UserSetProcessWindowStation(HWINSTA hWindowStation)
{
- PPROCESSINFO ppi;
NTSTATUS Status;
- HWINSTA hwinstaOld;
+ PPROCESSINFO ppi;
OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
+ HWINSTA hCacheWinSta;
ppi = PsGetCurrentProcessWin32Process();
&ObjectHandleInfo);
if (!NT_SUCCESS(Status))
{
- TRACE("Validation of window station handle (%p) failed\n",
- hWindowStation);
+ TRACE("Validation of window station handle 0x%p failed\n", hWindowStation);
SetLastNtError(Status);
return FALSE;
}
}
OldWinSta = ppi->prpwinsta;
- hwinstaOld = PsGetProcessWin32WindowStation(ppi->peProcess);
+ hCacheWinSta = PsGetProcessWin32WindowStation(ppi->peProcess);
/* Dereference the previous window station */
if (OldWinSta != NULL)
ObDereferenceObject(OldWinSta);
}
- /* Check if we have a stale handle (it should happen for console apps) */
- if (hwinstaOld != ppi->hwinsta)
- {
- ObCloseHandle(hwinstaOld, UserMode);
- }
-
/*
- * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects.
+ * FIXME: Don't allow changing the window station if there are threads that are attached to desktops and own GUI objects?
*/
- PsSetProcessWindowStation(ppi->peProcess, hWindowStation);
+ /* Close the cached EPROCESS window station handle if needed */
+ if (hCacheWinSta != NULL)
+ {
+ /* Reference the window station */
+ Status = ObReferenceObjectByHandle(hCacheWinSta,
+ 0,
+ ExWindowStationObjectType,
+ UserMode,
+ (PVOID*)&OldWinSta,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("Failed to reference the inherited window station, Status 0x%08lx\n", Status);
+ /* We failed, reset the cache */
+ hCacheWinSta = NULL;
+ PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
+ }
+ else
+ {
+ /*
+ * Close the old handle and reset the cache only
+ * if we are setting a different window station.
+ */
+ if (NewWinSta != OldWinSta)
+ {
+ ObCloseHandle(hCacheWinSta, UserMode);
+ hCacheWinSta = NULL;
+ PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
+ }
+
+ /* Dereference the window station */
+ ObDereferenceObject(OldWinSta);
+ }
+ }
+
+ /* Duplicate and save a new cached EPROCESS window station handle */
+ if ((hCacheWinSta == NULL) && (hWindowStation != NULL))
+ {
+ Status = ZwDuplicateObject(ZwCurrentProcess(),
+ hWindowStation,
+ ZwCurrentProcess(),
+ (PHANDLE)&hCacheWinSta,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS);
+ if (!NT_SUCCESS(Status))
+ {
+ ERR("UserSetProcessWindowStation: Failed to duplicate the window station handle, Status 0x%08lx\n", Status);
+ }
+ else
+ {
+ PsSetProcessWindowStation(ppi->peProcess, hCacheWinSta);
+ }
+ }
ppi->prpwinsta = NewWinSta;
ppi->hwinsta = hWindowStation;
{
ppi->W32PF_flags |= W32PF_IOWINSTA;
}
- else // Might be closed if the handle is null.
+ else /* Might be closed if the handle is NULL */
{
ppi->W32PF_flags &= ~W32PF_IOWINSTA;
}
UserMode,
0,
&Object,
- 0);
+ NULL);
if (!NT_SUCCESS(Status))
{
TRACE("Validation of window station handle (%p) failed\n",
UserMode,
0,
&Object,
- 0);
+ NULL);
if (!NT_SUCCESS(Status))
{
TRACE("Validation of window station handle (%p) failed\n",
POBJECT_DIRECTORY_INFORMATION DirEntry;
WCHAR NullWchar;
+ //
+ // FIXME: Fully wrong! Since, by calling NtUserCreateWindowStation
+ // with judicious parameters one can create window stations elsewhere
+ // than in Windows\WindowStations directory, Win32k definitely MUST
+ // maintain a list of window stations it has created, and not rely
+ // on the enumeration of Windows\WindowStations !!!
+ //
+
/*
* Try to open the directory.
*/
UserMode,
0,
&WindowStation,
- 0);
+ NULL);
if (! NT_SUCCESS(Status))
{
return Status;
return Ret;
}
-
/* EOF */