Implement NtUserBuildNamesList()

svn path=/trunk/; revision=10622
This commit is contained in:
Gé van Geldorp 2004-08-20 22:38:49 +00:00
parent 847119b3cd
commit 261286187f
2 changed files with 297 additions and 90 deletions

View file

@ -22,6 +22,7 @@
#define TAG_TIMERTD TAG('T', 'I', 'M', 'T') /* timer thread dereference list */
#define TAG_TIMERBMP TAG('T', 'I', 'M', 'B') /* timers bitmap */
#define TAG_CALLBACK TAG('C', 'B', 'C', 'K') /* callback memory */
#define TAG_WINSTA TAG('W', 'S', 'T', 'A') /* window station */
/* objects */
#define TAG_BEZIER TAG('B', 'E', 'Z', 'R') /* bezier */

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: winsta.c,v 1.64 2004/06/20 00:45:37 navaraf Exp $
* $Id: winsta.c,v 1.65 2004/08/20 22:38:49 gvg Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@ -954,6 +954,295 @@ NtUserSetWindowStationUser(
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;
PDIRECTORY_BASIC_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 = (PDIRECTORY_BASIC_INFORMATION) Buffer; 0 != DirEntry->ObjectName.Length;
DirEntry++)
{
ReturnLength += DirEntry->ObjectName.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 = (PDIRECTORY_BASIC_INFORMATION) Buffer; 0 != DirEntry->ObjectName.Length;
DirEntry++)
{
Status = MmCopyToCaller(lpBuffer, DirEntry->ObjectName.Buffer, DirEntry->ObjectName.Length);
if (! NT_SUCCESS(Status))
{
if (Buffer != InitialBuffer)
{
ExFreePool(Buffer);
}
return Status;
}
lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->ObjectName.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 += DesktopObject->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))
{
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, DesktopObject->Name.Buffer, DesktopObject->Name.Length);
if (! NT_SUCCESS(Status))
{
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
ObDereferenceObject(WindowStation);
return Status;
}
lpBuffer = (PVOID) ((PCHAR) lpBuffer + DesktopObject->Name.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
*
@ -977,103 +1266,20 @@ NtUserSetWindowStationUser(
* Otherwise it's size of buffer needed for function to succeed.
*
* Status
* @unimplemented
* @implemented
*/
NTSTATUS STDCALL
NtUserBuildNameList(
HWINSTA hWinSta,
HWINSTA hWindowStation,
ULONG dwSize,
PVOID lpBuffer,
PULONG pRequiredSize)
{
#if 0
NTSTATUS Status;
HANDLE DirectoryHandle;
ULONG EntryCount = 0;
UNICODE_STRING DirectoryNameW;
PWCHAR BufferChar;
PDIRECTORY_OBJECT DirObj = NULL;
PLIST_ENTRY CurrentEntry = NULL;
POBJECT_HEADER CurrentObject = NULL;
/*
* Generate full window station name
*/
/* FIXME: Correct this for desktop */
if (!IntGetFullWindowStationName(&DirectoryNameW, NULL, NULL))
{
SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
return 0;
}
/*
* Try to open the directory.
*/
Status = ObReferenceObjectByName(&DirectoryNameW, 0, NULL, DIRECTORY_QUERY,
ObDirectoryType, UserMode, (PVOID*)&DirObj, NULL);
if (!NT_SUCCESS(Status))
{
ExFreePool(DirectoryNameW.Buffer);
return Status;
}
/*
* Count the required size of buffer.
*/
*pRequiredSize = sizeof(DWORD);
for (CurrentEntry = DirObj->head.Flink; CurrentEntry != &DirObj->head;
CurrentEntry = CurrentEntry->Flink)
{
CurrentObject = CONTAINING_RECORD(CurrentEntry, OBJECT_HEADER, Entry);
*pRequiredSize += CurrentObject->Name.Length + sizeof(UNICODE_NULL);
++EntryCount;
}
DPRINT1("Required size: %d Entry count: %d\n", *pRequiredSize, EntryCount);
/*
* Check if the supplied buffer is large enought.
*/
if (*pRequiredSize > dwSize)
{
ExFreePool(DirectoryNameW.Buffer);
ObDereferenceObject(DirectoryHandle);
return STATUS_BUFFER_TOO_SMALL;
}
/*
* Generate the resulting buffer contents.
*/
*((DWORD *)lpBuffer) = EntryCount;
BufferChar = (PWCHAR)((INT_PTR)lpBuffer + 4);
for (CurrentEntry = DirObj->head.Flink; CurrentEntry != &DirObj->head;
CurrentEntry = CurrentEntry->Flink)
{
CurrentObject = CONTAINING_RECORD(CurrentEntry, OBJECT_HEADER, Entry);
wcscpy(BufferChar, CurrentObject->Name.Buffer);
DPRINT1("Name: %s\n", BufferChar);
BufferChar += (CurrentObject->Name.Length / sizeof(WCHAR)) + 1;
}
/*
* Free any resource.
*/
ExFreePool(DirectoryNameW.Buffer);
ObDereferenceObject(DirectoryHandle);
return STATUS_SUCCESS;
#else
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
#endif
/* 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 */