📄 winsta.c
字号:
*
* Assigns a window station to the current process.
*
* Parameters
* hWinSta
* Handle to the window station.
*
* Return Value
* Status
*
* Status
* @implemented
*/
BOOL STDCALL
NtUserSetProcessWindowStation(HWINSTA hWindowStation)
{
HANDLE hOld;
PWINSTATION_OBJECT NewWinSta;
NTSTATUS Status;
DPRINT("About to set process window station with handle (0x%X)\n",
hWindowStation);
if(PsGetCurrentProcess() == CsrProcess)
{
DPRINT1("CSRSS is not allowed to change it's window station!!!\n");
SetLastWin32Error(ERROR_ACCESS_DENIED);
return FALSE;
}
Status = IntValidateWindowStationHandle(
hWindowStation,
KernelMode,
0,
&NewWinSta);
if (!NT_SUCCESS(Status))
{
DPRINT("Validation of window station handle (0x%X) failed\n",
hWindowStation);
SetLastNtError(Status);
return FALSE;
}
/*
* FIXME - don't allow changing the window station if there are threads that are attached to desktops and own gui objects
*/
/* FIXME - dereference the old window station, etc... */
hOld = InterlockedExchangePointer(&PsGetCurrentProcess()->Win32WindowStation, hWindowStation);
DPRINT("PsGetCurrentProcess()->Win32WindowStation 0x%X\n",
PsGetCurrentProcess()->Win32WindowStation);
return TRUE;
}
/*
* NtUserLockWindowStation
*
* Locks switching desktops. Only the logon application is allowed to call this function.
*
* Status
* @implemented
*/
BOOL STDCALL
NtUserLockWindowStation(HWINSTA hWindowStation)
{
PWINSTATION_OBJECT Object;
NTSTATUS Status;
DPRINT("About to set process window station with handle (0x%X)\n",
hWindowStation);
if(PsGetCurrentProcessWin32Process() != LogonProcess)
{
DPRINT1("Unauthorized process attempted to lock the window station!\n");
SetLastWin32Error(ERROR_ACCESS_DENIED);
return FALSE;
}
Status = IntValidateWindowStationHandle(
hWindowStation,
KernelMode,
0,
&Object);
if (!NT_SUCCESS(Status))
{
DPRINT("Validation of window station handle (0x%X) failed\n",
hWindowStation);
SetLastNtError(Status);
return FALSE;
}
Object->Flags |= WSS_LOCKED;
ObDereferenceObject(Object);
return TRUE;
}
/*
* NtUserUnlockWindowStation
*
* Unlocks switching desktops. Only the logon application is allowed to call this function.
*
* Status
* @implemented
*/
BOOL STDCALL
NtUserUnlockWindowStation(HWINSTA hWindowStation)
{
PWINSTATION_OBJECT Object;
NTSTATUS Status;
BOOL Ret;
DPRINT("About to set process window station with handle (0x%X)\n",
hWindowStation);
if(PsGetCurrentProcessWin32Process() != LogonProcess)
{
DPRINT1("Unauthorized process attempted to unlock the window station!\n");
SetLastWin32Error(ERROR_ACCESS_DENIED);
return FALSE;
}
Status = IntValidateWindowStationHandle(
hWindowStation,
KernelMode,
0,
&Object);
if (!NT_SUCCESS(Status))
{
DPRINT("Validation of window station handle (0x%X) failed\n",
hWindowStation);
SetLastNtError(Status);
return FALSE;
}
Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
Object->Flags &= ~WSS_LOCKED;
ObDereferenceObject(Object);
return Ret;
}
/*
* NtUserSetWindowStationUser
*
* Status
* @unimplemented
*/
DWORD STDCALL
NtUserSetWindowStationUser(
DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2,
DWORD Unknown3)
{
UNIMPLEMENTED
return 0;
}
static NTSTATUS FASTCALL
BuildWindowStationNameList(
ULONG dwSize,
PVOID lpBuffer,
PULONG pRequiredSize)
{
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
HANDLE DirectoryHandle;
UNICODE_STRING DirectoryName;
char InitialBuffer[256], *Buffer;
ULONG Context, ReturnLength, BufferSize;
DWORD EntryCount;
POBJECT_DIRECTORY_INFORMATION DirEntry;
WCHAR NullWchar;
/*
* Generate name of window station directory
*/
if (!IntGetFullWindowStationName(&DirectoryName, NULL, NULL))
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/*
* Try to open the directory.
*/
InitializeObjectAttributes(
&ObjectAttributes,
&DirectoryName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenDirectoryObject(
&DirectoryHandle,
DIRECTORY_QUERY,
&ObjectAttributes);
ExFreePool(DirectoryName.Buffer);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* First try to query the directory using a fixed-size buffer */
Context = 0;
Buffer = NULL;
Status = ZwQueryDirectoryObject(DirectoryHandle, InitialBuffer, sizeof(InitialBuffer),
FALSE, TRUE, &Context, &ReturnLength);
if (NT_SUCCESS(Status))
{
if (STATUS_NO_MORE_ENTRIES == ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
FALSE, &Context, NULL))
{
/* Our fixed-size buffer is large enough */
Buffer = InitialBuffer;
}
}
if (NULL == Buffer)
{
/* Need a larger buffer, check how large exactly */
Status = ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE, TRUE, &Context,
&ReturnLength);
if (STATUS_BUFFER_TOO_SMALL == Status)
{
BufferSize = ReturnLength;
Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
if (NULL == Buffer)
{
ObDereferenceObject(DirectoryHandle);
return STATUS_NO_MEMORY;
}
/* We should have a sufficiently large buffer now */
Context = 0;
Status = ZwQueryDirectoryObject(DirectoryHandle, Buffer, BufferSize,
FALSE, TRUE, &Context, &ReturnLength);
if (! NT_SUCCESS(Status) ||
STATUS_NO_MORE_ENTRIES != ZwQueryDirectoryObject(DirectoryHandle, NULL, 0, FALSE,
FALSE, &Context, NULL))
{
/* Something went wrong, maybe someone added a directory entry? Just give up. */
ExFreePool(Buffer);
ObDereferenceObject(DirectoryHandle);
return NT_SUCCESS(Status) ? STATUS_INTERNAL_ERROR : Status;
}
}
}
ZwClose(DirectoryHandle);
/*
* Count the required size of buffer.
*/
ReturnLength = sizeof(DWORD);
EntryCount = 0;
for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
DirEntry++)
{
ReturnLength += DirEntry->Name.Length + sizeof(WCHAR);
EntryCount++;
}
DPRINT("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
if (NULL != pRequiredSize)
{
Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
if (! NT_SUCCESS(Status))
{
if (Buffer != InitialBuffer)
{
ExFreePool(Buffer);
}
return STATUS_BUFFER_TOO_SMALL;
}
}
/*
* Check if the supplied buffer is large enough.
*/
if (dwSize < ReturnLength)
{
if (Buffer != InitialBuffer)
{
ExFreePool(Buffer);
}
return STATUS_BUFFER_TOO_SMALL;
}
/*
* Generate the resulting buffer contents.
*/
Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
if (! NT_SUCCESS(Status))
{
if (Buffer != InitialBuffer)
{
ExFreePool(Buffer);
}
return Status;
}
lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
NullWchar = L'\0';
for (DirEntry = (POBJECT_DIRECTORY_INFORMATION) Buffer; 0 != DirEntry->Name.Length;
DirEntry++)
{
Status = MmCopyToCaller(lpBuffer, DirEntry->Name.Buffer, DirEntry->Name.Length);
if (! NT_SUCCESS(Status))
{
if (Buffer != InitialBuffer)
{
ExFreePool(Buffer);
}
return Status;
}
lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
if (! NT_SUCCESS(Status))
{
if (Buffer != InitialBuffer)
{
ExFreePool(Buffer);
}
return Status;
}
lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
}
/*
* Clean up
*/
if (NULL != Buffer && Buffer != InitialBuffer)
{
ExFreePool(Buffer);
}
return STATUS_SUCCESS;
}
static NTSTATUS FASTCALL
BuildDesktopNameList(
HWINSTA hWindowStation,
ULONG dwSize,
PVOID lpBuffer,
PULONG pRequiredSize)
{
NTSTATUS Status;
PWINSTATION_OBJECT WindowStation;
KIRQL OldLevel;
PLIST_ENTRY DesktopEntry;
PDESKTOP_OBJECT DesktopObject;
DWORD EntryCount;
ULONG ReturnLength;
WCHAR NullWchar;
Status = IntValidateWindowStationHandle(hWindowStation,
KernelMode,
0,
&WindowStation);
if (! NT_SUCCESS(Status))
{
return Status;
}
KeAcquireSpinLock(&WindowStation->Lock, &OldLevel);
/*
* Count the required size of buffer.
*/
ReturnLength = sizeof(DWORD);
EntryCount = 0;
for (DesktopEntry = WindowStation->DesktopListHead.Flink;
DesktopEntry != &WindowStation->DesktopListHead;
DesktopEntry = DesktopEntry->Flink)
{
DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP_OBJECT, ListEntry);
ReturnLength += ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length + sizeof(WCHAR);
EntryCount++;
}
DPRINT("Required size: %d Entry count: %d\n", ReturnLength, EntryCount);
if (NULL != pRequiredSize)
{
Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
if (! NT_SUCCESS(Status))
{
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
ObDereferenceObject(WindowStation);
return STATUS_BUFFER_TOO_SMALL;
}
}
/*
* Check if the supplied buffer is large enough.
*/
if (dwSize < ReturnLength)
{
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
ObDereferenceObject(WindowStation);
return STATUS_BUFFER_TOO_SMALL;
}
/*
* Generate the resulting buffer contents.
*/
Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
if (! NT_SUCCESS(Status))
{
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
ObDereferenceObject(WindowStation);
return Status;
}
lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(DWORD));
NullWchar = L'\0';
for (DesktopEntry = WindowStation->DesktopListHead.Flink;
DesktopEntry != &WindowStation->DesktopListHead;
DesktopEntry = DesktopEntry->Flink)
{
DesktopObject = CONTAINING_RECORD(DesktopEntry, DESKTOP_OBJECT, ListEntry);
Status = MmCopyToCaller(lpBuffer, ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Buffer, ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length);
if (! NT_SUCCESS(Status))
{
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
ObDereferenceObject(WindowStation);
return Status;
}
lpBuffer = (PVOID) ((PCHAR) lpBuffer + ((PUNICODE_STRING)GET_DESKTOP_NAME(DesktopObject))->Length);
Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
if (! NT_SUCCESS(Status))
{
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
ObDereferenceObject(WindowStation);
return Status;
}
lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
}
/*
* Clean up
*/
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
ObDereferenceObject(WindowStation);
return STATUS_SUCCESS;
}
/*
* NtUserBuildNameList
*
* Function used for enumeration of desktops or window stations.
*
* Parameters
* hWinSta
* For enumeration of window stations this parameter must be set to
* zero. Otherwise it's handle for window station.
*
* dwSize
* Size of buffer passed by caller.
*
* lpBuffer
* Buffer passed by caller. If the function succedes, the buffer is
* filled with window station/desktop count (in first DWORD) and
* NULL-terminated window station/desktop names.
*
* pRequiredSize
* If the function suceedes, this is the number of bytes copied.
* Otherwise it's size of buffer needed for function to succeed.
*
* Status
* @implemented
*/
NTSTATUS STDCALL
NtUserBuildNameList(
HWINSTA hWindowStation,
ULONG dwSize,
PVOID lpBuffer,
PULONG pRequiredSize)
{
/* The WindowStation name list and desktop name list are build in completely
different ways. Call the appropriate function */
return NULL == hWindowStation ? BuildWindowStationNameList(dwSize, lpBuffer, pRequiredSize) :
BuildDesktopNameList(hWindowStation, dwSize, lpBuffer, pRequiredSize);
}
/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -