Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / reactos / win32ss / user / ntuser / winsta.c
diff --git a/reactos/win32ss/user/ntuser/winsta.c b/reactos/win32ss/user/ntuser/winsta.c
deleted file mode 100644 (file)
index 4970205..0000000
+++ /dev/null
@@ -1,1533 +0,0 @@
-/*
- *  COPYRIGHT:        See COPYING in the top level directory
- *  PROJECT:          ReactOS Win32k subsystem
- *  PURPOSE:          Window stations
- *  FILE:             win32ss/user/ntuser/winsta.c
- *  PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
- *  TODO:             The process window station is created on
- *                    the first USER32/GDI32 call not related
- *                    to window station/desktop handling
- */
-
-#include <win32k.h>
-DBG_DEFAULT_CHANNEL(UserWinsta);
-
-/* GLOBALS *******************************************************************/
-
-/* Currently active window station */
-PWINSTATION_OBJECT InputWindowStation = NULL;
-
-/* Winlogon SAS window */
-HWND hwndSAS = NULL;
-
-/* Full path to WindowStations directory */
-UNICODE_STRING gustrWindowStationsDir;
-
-/* INITIALIZATION FUNCTIONS ****************************************************/
-
-INIT_FUNCTION
-NTSTATUS
-NTAPI
-InitWindowStationImpl(VOID)
-{
-    GENERIC_MAPPING IntWindowStationMapping = { WINSTA_READ,
-                                                WINSTA_WRITE,
-                                                WINSTA_EXECUTE,
-                                                WINSTA_ACCESS_ALL};
-
-    /* Set Winsta Object Attributes */
-    ExWindowStationObjectType->TypeInfo.DefaultNonPagedPoolCharge = sizeof(WINSTATION_OBJECT);
-    ExWindowStationObjectType->TypeInfo.GenericMapping = IntWindowStationMapping;
-    ExWindowStationObjectType->TypeInfo.ValidAccessMask = WINSTA_ACCESS_ALL;
-
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-UserCreateWinstaDirectory(VOID)
-{
-    PPEB Peb;
-    NTSTATUS Status;
-    WCHAR wstrWindowStationsDir[MAX_PATH];
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    HANDLE hWinstaDir;
-
-    /* Create the WindowStations directory and cache its path for later use */
-    Peb = NtCurrentPeb();
-    if(Peb->SessionId == 0)
-    {
-        if (!RtlCreateUnicodeString(&gustrWindowStationsDir, WINSTA_OBJ_DIR))
-        {
-            return STATUS_INSUFFICIENT_RESOURCES;
-        }
-    }
-    else
-    {
-        swprintf(wstrWindowStationsDir,
-                 L"%ws\\%lu%ws",
-                 SESSION_DIR,
-                 Peb->SessionId,
-                 WINSTA_OBJ_DIR);
-
-        if (!RtlCreateUnicodeString(&gustrWindowStationsDir, wstrWindowStationsDir))
-        {
-            return STATUS_INSUFFICIENT_RESOURCES;
-        }
-    }
-
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &gustrWindowStationsDir,
-                               0,
-                               NULL,
-                               NULL);
-    Status = ZwCreateDirectoryObject(&hWinstaDir, 0, &ObjectAttributes);
-    if (!NT_SUCCESS(Status))
-    {
-        ERR("Could not create %wZ directory (Status 0x%X)\n", &gustrWindowStationsDir,  Status);
-        return Status;
-    }
-
-    TRACE("Created directory %wZ for session %lu\n", &gustrWindowStationsDir, Peb->SessionId);
-
-    return Status;
-}
-
-/* OBJECT CALLBACKS  **********************************************************/
-
-NTSTATUS
-APIENTRY
-IntWinStaObjectDelete(
-    _In_ PVOID Parameters)
-{
-    PWIN32_DELETEMETHOD_PARAMETERS DeleteParameters = Parameters;
-    PWINSTATION_OBJECT WinSta = (PWINSTATION_OBJECT)DeleteParameters->Object;
-
-    TRACE("Deleting window station (0x%p)\n", WinSta);
-
-    WinSta->Flags |= WSS_DYING;
-
-    UserEmptyClipboardData(WinSta);
-
-    RtlDestroyAtomTable(WinSta->AtomTable);
-
-    RtlFreeUnicodeString(&WinSta->Name);
-
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS
-APIENTRY
-IntWinStaObjectParse(
-    _In_ PVOID Parameters)
-{
-    PWIN32_PARSEMETHOD_PARAMETERS ParseParameters = Parameters;
-    PUNICODE_STRING RemainingName = ParseParameters->RemainingName;
-
-    /* Assume we don't find anything */
-    *ParseParameters->Object = NULL;
-
-    /* Check for an empty name */
-    if (!RemainingName->Length)
-    {
-        /* Make sure this is a window station, can't parse a desktop now */
-        if (ParseParameters->ObjectType != ExWindowStationObjectType)
-        {
-            /* Fail */
-            return STATUS_OBJECT_TYPE_MISMATCH;
-        }
-
-        /* Reference the window station and return */
-        ObReferenceObject(ParseParameters->ParseObject);
-        *ParseParameters->Object = ParseParameters->ParseObject;
-        return STATUS_SUCCESS;
-    }
-
-    /* Check for leading slash */
-    if (RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)
-    {
-        /* Skip it */
-        RemainingName->Buffer++;
-        RemainingName->Length -= sizeof(WCHAR);
-        RemainingName->MaximumLength -= sizeof(WCHAR);
-    }
-
-    /* Check if there is still a slash */
-    if (wcschr(RemainingName->Buffer, OBJ_NAME_PATH_SEPARATOR))
-    {
-        /* In this case, fail */
-        return STATUS_OBJECT_PATH_INVALID;
-    }
-
-    /*
-     * Check if we are parsing a desktop.
-     */
-    if (ParseParameters->ObjectType == ExDesktopObjectType)
-    {
-        /* Then call the desktop parse routine */
-        return IntDesktopObjectParse(ParseParameters->ParseObject,
-                                     ParseParameters->ObjectType,
-                                     ParseParameters->AccessState,
-                                     ParseParameters->AccessMode,
-                                     ParseParameters->Attributes,
-                                     ParseParameters->CompleteName,
-                                     RemainingName,
-                                     ParseParameters->Context,
-                                     ParseParameters->SecurityQos,
-                                     ParseParameters->Object);
-    }
-
-    /* Should hopefully never get here */
-    return STATUS_OBJECT_TYPE_MISMATCH;
-}
-
-NTSTATUS
-NTAPI
-IntWinstaOkToClose(
-    _In_ PVOID Parameters)
-{
-    PWIN32_OKAYTOCLOSEMETHOD_PARAMETERS OkToCloseParameters = Parameters;
-    PPROCESSINFO ppi;
-
-    ppi = PsGetCurrentProcessWin32Process();
-
-    if(ppi && (OkToCloseParameters->Handle == ppi->hwinsta))
-    {
-        return STATUS_ACCESS_DENIED;
-    }
-
-    return STATUS_SUCCESS;
-}
-
-/* PRIVATE FUNCTIONS **********************************************************/
-
-/*
- * 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,
-    POBJECT_HANDLE_INFORMATION pObjectHandleInfo)
-{
-    NTSTATUS Status;
-
-    if (WindowStation == NULL)
-    {
-        ERR("Invalid window station handle\n");
-        EngSetLastError(ERROR_INVALID_HANDLE);
-        return STATUS_INVALID_HANDLE;
-    }
-
-    Status = ObReferenceObjectByHandle(WindowStation,
-                                       DesiredAccess,
-                                       ExWindowStationObjectType,
-                                       AccessMode,
-                                       (PVOID*)Object,
-                                       pObjectHandleInfo);
-
-    if (!NT_SUCCESS(Status))
-        SetLastNtError(Status);
-
-    return Status;
-}
-
-BOOL FASTCALL
-co_IntInitializeDesktopGraphics(VOID)
-{
-    TEXTMETRICW tmw;
-    UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
-    PDESKTOP pdesk;
-
-    ScreenDeviceContext = IntGdiCreateDC(&DriverName, NULL, NULL, NULL, FALSE);
-    if (NULL == ScreenDeviceContext)
-    {
-        IntDestroyPrimarySurface();
-        return FALSE;
-    }
-    GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_PUBLIC);
-
-    if (! IntCreatePrimarySurface())
-    {
-        return FALSE;
-    }
-
-    hSystemBM = NtGdiCreateCompatibleDC(ScreenDeviceContext);
-
-    NtGdiSelectFont(hSystemBM, NtGdiGetStockObject(SYSTEM_FONT));
-    GreSetDCOwner(hSystemBM, GDI_OBJ_HMGR_PUBLIC);
-
-    /* Update the SERVERINFO */
-    gpsi->aiSysMet[SM_CXSCREEN] = gppdevPrimary->gdiinfo.ulHorzRes;
-    gpsi->aiSysMet[SM_CYSCREEN] = gppdevPrimary->gdiinfo.ulVertRes;
-    gpsi->Planes        = NtGdiGetDeviceCaps(ScreenDeviceContext, PLANES);
-    gpsi->BitsPixel     = NtGdiGetDeviceCaps(ScreenDeviceContext, BITSPIXEL);
-    gpsi->BitCount      = gpsi->Planes * gpsi->BitsPixel;
-    gpsi->dmLogPixels   = NtGdiGetDeviceCaps(ScreenDeviceContext, LOGPIXELSY);
-    if (NtGdiGetDeviceCaps(ScreenDeviceContext, RASTERCAPS) & RC_PALETTE)
-    {
-        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;
-
-    /* Put the pointer in the center of the screen */
-    gpsi->ptCursor.x = gpsi->aiSysMet[SM_CXSCREEN] / 2;
-    gpsi->ptCursor.y = gpsi->aiSysMet[SM_CYSCREEN] / 2;
-
-    /* Attach monitor */
-    UserAttachMonitor((HDEV)gppdevPrimary);
-
-    /* Setup the cursor */
-    co_IntLoadDefaultCursors();
-
-    /* Setup the icons */
-    co_IntSetWndIcons();
-
-    /* Setup Menu */
-    MenuInit();
-
-    /* Show the desktop */
-    pdesk = IntGetActiveDesktop();
-    ASSERT(pdesk);
-    co_IntShowDesktop(pdesk, gpsi->aiSysMet[SM_CXSCREEN], gpsi->aiSysMet[SM_CYSCREEN], TRUE);
-
-    return TRUE;
-}
-
-VOID FASTCALL
-IntEndDesktopGraphics(VOID)
-{
-    if (NULL != ScreenDeviceContext)
-    {  // No need to allocate a new dcattr.
-        GreSetDCOwner(ScreenDeviceContext, GDI_OBJ_HMGR_POWNED);
-        GreDeleteObject(ScreenDeviceContext);
-        ScreenDeviceContext = NULL;
-    }
-    IntHideDesktop(IntGetActiveDesktop());
-    IntDestroyPrimarySurface();
-}
-
-HDC FASTCALL
-IntGetScreenDC(VOID)
-{
-    return ScreenDeviceContext;
-}
-
-BOOL FASTCALL
-CheckWinstaAttributeAccess(ACCESS_MASK DesiredAccess)
-{
-    PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
-    if ( gpidLogon != PsGetCurrentProcessId() )
-    {
-        if (!(ppi->W32PF_flags & W32PF_IOWINSTA))
-        {
-            ERR("Requires Interactive Window Station\n");
-            EngSetLastError(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION);
-            return FALSE;
-        }
-        if (!RtlAreAllAccessesGranted(ppi->amwinsta, DesiredAccess))
-        {
-            ERR("Access Denied\n");
-            EngSetLastError(ERROR_ACCESS_DENIED);
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-
-
-/* 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 APIENTRY
-NtUserCreateWindowStation(
-    POBJECT_ATTRIBUTES ObjectAttributes,
-    ACCESS_MASK dwDesiredAccess,
-    DWORD Unknown2,
-    DWORD Unknown3,
-    DWORD Unknown4,
-    DWORD Unknown5,
-    DWORD Unknown6)
-{
-    UNICODE_STRING WindowStationName;
-    PWINSTATION_OBJECT WindowStationObject;
-    HWINSTA WindowStation;
-    NTSTATUS Status;
-
-    TRACE("NtUserCreateWindowStation called\n");
-
-    Status = ObOpenObjectByName(ObjectAttributes,
-                                ExWindowStationObjectType,
-                                UserMode,
-                                NULL,
-                                dwDesiredAccess,
-                                NULL,
-                                (PVOID*)&WindowStation);
-
-    if (NT_SUCCESS(Status))
-    {
-        TRACE("NtUserCreateWindowStation opened window station %wZ\n", ObjectAttributes->ObjectName);
-        return (HWINSTA)WindowStation;
-    }
-
-    /*
-     * No existing window station found, try to create 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,
-                            ExWindowStationObjectType,
-                            ObjectAttributes,
-                            UserMode,
-                            NULL,
-                            sizeof(WINSTATION_OBJECT),
-                            0,
-                            0,
-                            (PVOID*)&WindowStationObject);
-
-    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;
-    }
-
-    /* Initialize the window station */
-    RtlZeroMemory(WindowStationObject, sizeof(WINSTATION_OBJECT));
-
-    InitializeListHead(&WindowStationObject->DesktopListHead);
-    WindowStationObject->Name = WindowStationName;
-    WindowStationObject->dwSessionId = NtCurrentPeb()->SessionId;
-    Status = RtlCreateAtomTable(37, &WindowStationObject->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;
-    }
-
-    Status = ObInsertObject((PVOID)WindowStationObject,
-                            NULL,
-                            dwDesiredAccess,
-                            0,
-                            NULL,
-                            (PVOID*)&WindowStation);
-
-    if (!NT_SUCCESS(Status))
-    {
-        ERR("ObInsertObject failed with %lx for window station\n", Status);
-        SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
-        return 0;
-    }
-
-    if (InputWindowStation == NULL)
-    {
-        ERR("Initializing input window station\n");
-        InputWindowStation = WindowStationObject;
-
-        WindowStationObject->Flags &= ~WSS_NOIO;
-
-        InitCursorImpl();
-    }
-    else
-    {
-        WindowStationObject->Flags |= WSS_NOIO;
-    }
-
-    TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n",
-          WindowStation, &WindowStationObject->Name, WindowStation);
-    return WindowStation;
-}
-
-/*
- * NtUserOpenWindowStation
- *
- * Opens an existing window station.
- *
- * Parameters
- *    lpszWindowStationName
- *       Name of the existing window station.
- *
- *    dwDesiredAccess
- *       Requested type of access.
- *
- * Return Value
- *    If the function succeeds, the return value is the handle to the
- *    specified window station. If the function fails, the return value
- *    is NULL.
- *
- * Remarks
- *    The returned handle can be closed with NtUserCloseWindowStation.
- *
- * Status
- *    @implemented
- */
-
-HWINSTA APIENTRY
-NtUserOpenWindowStation(
-    POBJECT_ATTRIBUTES ObjectAttributes,
-    ACCESS_MASK dwDesiredAccess)
-{
-    HWINSTA hwinsta;
-    NTSTATUS Status;
-
-    Status = ObOpenObjectByName(ObjectAttributes,
-                                ExWindowStationObjectType,
-                                UserMode,
-                                NULL,
-                                dwDesiredAccess,
-                                NULL,
-                                (PVOID*)&hwinsta);
-
-    if (!NT_SUCCESS(Status))
-    {
-        ERR("NtUserOpenWindowStation failed\n");
-        SetLastNtError(Status);
-        return 0;
-    }
-
-    TRACE("Opened window station %wZ with handle %p\n", ObjectAttributes->ObjectName, hwinsta);
-
-    return hwinsta;
-}
-
-/*
- * NtUserCloseWindowStation
- *
- * Closes a window station handle.
- *
- * Parameters
- *    hWinSta
- *       Handle to the window station.
- *
- * Return Value
- *    Status
- *
- * Remarks
- *    The window station handle can be created with NtUserCreateWindowStation
- *    or NtUserOpenWindowStation. Attemps to close a handle to the window
- *    station assigned to the calling process will fail.
- *
- * Status
- *    @implemented
- */
-
-BOOL
-APIENTRY
-NtUserCloseWindowStation(
-    HWINSTA hWinSta)
-{
-    PWINSTATION_OBJECT Object;
-    NTSTATUS Status;
-
-    TRACE("NtUserCloseWindowStation called (%p)\n", hWinSta);
-
-    if (hWinSta == UserGetProcessWindowStation())
-    {
-        ERR("Attempted to close process window station\n");
-        return FALSE;
-    }
-
-    Status = IntValidateWindowStationHandle(hWinSta,
-                                            UserMode,
-                                            0,
-                                            &Object,
-                                            0);
-
-    if (!NT_SUCCESS(Status))
-    {
-        ERR("Validation of window station handle (%p) failed\n", hWinSta);
-        return FALSE;
-    }
-
-    ObDereferenceObject(Object);
-
-    TRACE("Closing window station handle (%p)\n", hWinSta);
-
-    Status = ObCloseHandle(hWinSta, UserMode);
-    if (!NT_SUCCESS(Status))
-    {
-        SetLastNtError(Status);
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-/*
- * NtUserGetObjectInformation
- *
- * The NtUserGetObjectInformation function retrieves information about a
- * window station or desktop object.
- *
- * Parameters
- *    hObj
- *       Handle to the window station or desktop object for which to
- *       return information. This can be a handle of type HDESK or HWINSTA
- *       (for example, a handle returned by NtUserCreateWindowStation,
- *       NtUserOpenWindowStation, NtUserCreateDesktop, or NtUserOpenDesktop).
- *
- *    nIndex
- *       Specifies the object information to be retrieved.
- *
- *    pvInfo
- *       Pointer to a buffer to receive the object information.
- *
- *    nLength
- *       Specifies the size, in bytes, of the buffer pointed to by the
- *       pvInfo parameter.
- *
- *    lpnLengthNeeded
- *       Pointer to a variable receiving the number of bytes required to
- *       store the requested information. If this variable's value is
- *       greater than the value of the nLength parameter when the function
- *       returns, the function returns FALSE, and none of the information
- *       is copied to the pvInfo buffer. If the value of the variable pointed
- *       to by lpnLengthNeeded is less than or equal to the value of nLength,
- *       the entire information block is copied.
- *
- * Return Value
- *    If the function succeeds, the return value is nonzero. If the function
- *    fails, the return value is zero.
- *
- * Status
- *    @unimplemented
- */
-
-BOOL APIENTRY
-NtUserGetObjectInformation(
-    HANDLE hObject,
-    DWORD nIndex,
-    PVOID pvInformation,
-    DWORD nLength,
-    PDWORD nLengthNeeded)
-{
-    NTSTATUS Status;
-    PWINSTATION_OBJECT WinStaObject = NULL;
-    PDESKTOP DesktopObject = NULL;
-    USEROBJECTFLAGS ObjectFlags;
-    PVOID pvData = NULL;
-    DWORD nDataSize = 0;
-
-    _SEH2_TRY
-    {
-        if (nLengthNeeded)
-            ProbeForWrite(nLengthNeeded, sizeof(*nLengthNeeded), 1);
-        ProbeForWrite(pvInformation, nLength, 1);
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-    {
-        SetLastNtError(_SEH2_GetExceptionCode());
-        return FALSE;
-    }
-    _SEH2_END;
-
-    /* Try window station */
-    TRACE("Trying to open window station %p\n", hObject);
-    Status = ObReferenceObjectByHandle(hObject,
-                                       0,
-                                       ExWindowStationObjectType,
-                                       UserMode,
-                                       (PVOID*)&WinStaObject,
-                                       NULL);
-
-    if (Status == STATUS_OBJECT_TYPE_MISMATCH)
-    {
-        /* Try desktop */
-        TRACE("Trying to open desktop %p\n", hObject);
-        WinStaObject = NULL;
-        Status = IntValidateDesktopHandle(hObject,
-                                          UserMode,
-                                          0,
-                                          &DesktopObject);
-    }
-
-    if (!NT_SUCCESS(Status))
-    {
-        ERR("Failed: 0x%x\n", Status);
-        goto Exit;
-    }
-
-    TRACE("WinSta or Desktop opened!!\n");
-
-    /* Get data */
-    switch (nIndex)
-    {
-        case UOI_FLAGS:
-        {
-            /* This is a default implementation that does almost nothing */
-            ObjectFlags.fInherit = FALSE;
-            ObjectFlags.fReserved = FALSE;
-            ObjectFlags.dwFlags = 0;
-
-            pvData = &ObjectFlags;
-            nDataSize = sizeof(ObjectFlags);
-            Status = STATUS_SUCCESS;
-            ERR("UOI_FLAGS unimplemented!\n");
-            break;
-        }
-
-        case UOI_NAME:
-        {
-            if (WinStaObject != NULL)
-            {
-                pvData = WinStaObject->Name.Buffer;
-                nDataSize = WinStaObject->Name.Length + sizeof(WCHAR);
-                Status = STATUS_SUCCESS;
-            }
-            else if (DesktopObject != NULL)
-            {
-                pvData = DesktopObject->pDeskInfo->szDesktopName;
-                nDataSize = (wcslen(DesktopObject->pDeskInfo->szDesktopName) + 1) * sizeof(WCHAR);
-                Status = STATUS_SUCCESS;
-            }
-            else
-            {
-                Status = STATUS_INVALID_PARAMETER;
-            }
-            break;
-        }
-
-        case UOI_TYPE:
-        {
-            if (WinStaObject != NULL)
-            {
-                pvData = L"WindowStation";
-                nDataSize = sizeof(L"WindowStation");
-                Status = STATUS_SUCCESS;
-            }
-            else if (DesktopObject != NULL)
-            {
-                pvData = L"Desktop";
-                nDataSize = sizeof(L"Desktop");
-                Status = STATUS_SUCCESS;
-            }
-            else
-            {
-                Status = STATUS_INVALID_PARAMETER;
-            }
-            break;
-        }
-
-        case UOI_USER_SID:
-            Status = STATUS_NOT_IMPLEMENTED;
-            ERR("UOI_USER_SID unimplemented!\n");
-            break;
-
-        default:
-            Status = STATUS_INVALID_PARAMETER;
-            break;
-    }
-
-Exit:
-    if ((Status == STATUS_SUCCESS) && (nLength < nDataSize))
-        Status = STATUS_BUFFER_TOO_SMALL;
-
-    _SEH2_TRY
-    {
-        if (nLengthNeeded)
-            *nLengthNeeded = nDataSize;
-
-        /* Try to copy data to caller */
-        if (Status == STATUS_SUCCESS)
-        {
-            TRACE("Trying to copy data to caller (len = %lu, len needed = %lu)\n", nLength, nDataSize);
-            RtlCopyMemory(pvInformation, pvData, nDataSize);
-        }
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-    {
-        Status = _SEH2_GetExceptionCode();
-    }
-    _SEH2_END;
-
-    /* Release objects */
-    if (DesktopObject != NULL)
-        ObDereferenceObject(DesktopObject);
-    if (WinStaObject != NULL)
-        ObDereferenceObject(WinStaObject);
-
-    if (!NT_SUCCESS(Status))
-    {
-        SetLastNtError(Status);
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-/*
- * NtUserSetObjectInformation
- *
- * The NtUserSetObjectInformation function sets information about a
- * window station or desktop object.
- *
- * Parameters
- *    hObj
- *       Handle to the window station or desktop object for which to set
- *       object information. This value can be a handle of type HDESK or
- *       HWINSTA.
- *
- *    nIndex
- *       Specifies the object information to be set.
- *
- *    pvInfo
- *       Pointer to a buffer containing the object information.
- *
- *    nLength
- *       Specifies the size, in bytes, of the information contained in the
- *       buffer pointed to by pvInfo.
- *
- * Return Value
- *    If the function succeeds, the return value is nonzero. If the function
- *    fails the return value is zero.
- *
- * Status
- *    @unimplemented
- */
-
-BOOL
-APIENTRY
-NtUserSetObjectInformation(
-    HANDLE hObject,
-    DWORD nIndex,
-    PVOID pvInformation,
-    DWORD nLength)
-{
-    /* FIXME: ZwQueryObject */
-    /* FIXME: ZwSetInformationObject */
-    SetLastNtError(STATUS_UNSUCCESSFUL);
-    return FALSE;
-}
-
-
-
-
-HWINSTA FASTCALL
-UserGetProcessWindowStation(VOID)
-{
-    PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
-
-    return ppi->hwinsta;
-}
-
-
-/*
- * NtUserGetProcessWindowStation
- *
- * Returns a handle to the current process window station.
- *
- * Return Value
- *    If the function succeeds, the return value is handle to the window
- *    station assigned to the current process. If the function fails, the
- *    return value is NULL.
- *
- * Status
- *    @implemented
- */
-
-HWINSTA APIENTRY
-NtUserGetProcessWindowStation(VOID)
-{
-    return UserGetProcessWindowStation();
-}
-
-BOOL FASTCALL
-UserSetProcessWindowStation(HWINSTA hWindowStation)
-{
-    PPROCESSINFO ppi;
-    NTSTATUS Status;
-    HWINSTA hwinstaOld;
-    OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
-    PWINSTATION_OBJECT NewWinSta = NULL, OldWinSta;
-
-    ppi = PsGetCurrentProcessWin32Process();
-
-    /* Reference the new window station */
-    if(hWindowStation !=NULL)
-    {
-        Status = IntValidateWindowStationHandle(hWindowStation,
-                                                UserMode,
-                                                0,
-                                                &NewWinSta,
-                                                &ObjectHandleInfo);
-        if (!NT_SUCCESS(Status))
-        {
-            TRACE("Validation of window station handle (%p) failed\n",
-                  hWindowStation);
-            SetLastNtError(Status);
-            return FALSE;
-        }
-    }
-
-    OldWinSta = ppi->prpwinsta;
-    hwinstaOld = 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.
-     */
-
-    PsSetProcessWindowStation(ppi->peProcess, hWindowStation);
-
-    ppi->prpwinsta = NewWinSta;
-    ppi->hwinsta = hWindowStation;
-    ppi->amwinsta = hWindowStation != NULL ? ObjectHandleInfo.GrantedAccess : 0;
-    TRACE("WS : Granted Access 0x%08lx\n",ppi->amwinsta);
-
-    if (RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_READSCREEN))
-    {
-        ppi->W32PF_flags |= W32PF_READSCREENACCESSGRANTED;
-    }
-    else
-    {
-        ppi->W32PF_flags &= ~W32PF_READSCREENACCESSGRANTED;
-    }
-
-    if (NewWinSta && !(NewWinSta->Flags & WSS_NOIO) )
-    {
-        ppi->W32PF_flags |= W32PF_IOWINSTA;
-    }
-    else // Might be closed if the handle is null.
-    {
-        ppi->W32PF_flags &= ~W32PF_IOWINSTA;
-    }
-    return TRUE;
-}
-
-/*
- * NtUserSetProcessWindowStation
- *
- * Assigns a window station to the current process.
- *
- * Parameters
- *    hWinSta
- *       Handle to the window station.
- *
- * Return Value
- *    Status
- *
- * Status
- *    @implemented
- */
-
-BOOL APIENTRY
-NtUserSetProcessWindowStation(HWINSTA hWindowStation)
-{
-    BOOL ret;
-
-    UserEnterExclusive();
-
-    ret = UserSetProcessWindowStation(hWindowStation);
-
-    UserLeave();
-
-    return ret;
-}
-
-/*
- * NtUserLockWindowStation
- *
- * Locks switching desktops. Only the logon application is allowed to call this function.
- *
- * Status
- *    @implemented
- */
-
-BOOL APIENTRY
-NtUserLockWindowStation(HWINSTA hWindowStation)
-{
-    PWINSTATION_OBJECT Object;
-    NTSTATUS Status;
-
-    TRACE("About to set process window station with handle (%p)\n",
-          hWindowStation);
-
-    if (gpidLogon != PsGetCurrentProcessId())
-    {
-        ERR("Unauthorized process attempted to lock the window station!\n");
-        EngSetLastError(ERROR_ACCESS_DENIED);
-        return FALSE;
-    }
-
-    Status = IntValidateWindowStationHandle(hWindowStation,
-                                            UserMode,
-                                            0,
-                                            &Object,
-                                            0);
-    if (!NT_SUCCESS(Status))
-    {
-        TRACE("Validation of window station handle (%p) 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 APIENTRY
-NtUserUnlockWindowStation(HWINSTA hWindowStation)
-{
-    PWINSTATION_OBJECT Object;
-    NTSTATUS Status;
-    BOOL Ret;
-
-    TRACE("About to set process window station with handle (%p)\n",
-          hWindowStation);
-
-    if (gpidLogon != PsGetCurrentProcessId())
-    {
-        ERR("Unauthorized process attempted to unlock the window station!\n");
-        EngSetLastError(ERROR_ACCESS_DENIED);
-        return FALSE;
-    }
-
-    Status = IntValidateWindowStationHandle(hWindowStation,
-                                            UserMode,
-                                            0,
-                                            &Object,
-                                            0);
-    if (!NT_SUCCESS(Status))
-    {
-        TRACE("Validation of window station handle (%p) failed\n",
-              hWindowStation);
-        SetLastNtError(Status);
-        return FALSE;
-    }
-
-    Ret = (Object->Flags & WSS_LOCKED) == WSS_LOCKED;
-    Object->Flags &= ~WSS_LOCKED;
-
-    ObDereferenceObject(Object);
-    return Ret;
-}
-
-static NTSTATUS FASTCALL
-BuildWindowStationNameList(
-    ULONG dwSize,
-    PVOID lpBuffer,
-    PULONG pRequiredSize)
-{
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    NTSTATUS Status;
-    HANDLE DirectoryHandle;
-    char InitialBuffer[256], *Buffer;
-    ULONG Context, ReturnLength, BufferSize;
-    DWORD EntryCount;
-    POBJECT_DIRECTORY_INFORMATION DirEntry;
-    WCHAR NullWchar;
-
-    /*
-     * Try to open the directory.
-     */
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &gustrWindowStationsDir,
-                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
-                               NULL,
-                               NULL);
-
-    Status = ZwOpenDirectoryObject(&DirectoryHandle,
-                                   DIRECTORY_QUERY,
-                                   &ObjectAttributes);
-
-    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 (!NT_SUCCESS(Status))
-        {
-            ERR("ZwQueryDirectoryObject failed\n");
-            ZwClose(DirectoryHandle);
-            return Status;
-        }
-
-        BufferSize = ReturnLength;
-        Buffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_WINSTA);
-        if (NULL == Buffer)
-        {
-            ZwClose(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. */
-            ExFreePoolWithTag(Buffer, TAG_WINSTA);
-            ZwClose(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++;
-    }
-    TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
-    if (NULL != pRequiredSize)
-    {
-        Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
-        if (! NT_SUCCESS(Status))
-        {
-            if (Buffer != InitialBuffer)
-            {
-                ExFreePoolWithTag(Buffer, TAG_WINSTA);
-            }
-            return STATUS_BUFFER_TOO_SMALL;
-        }
-    }
-
-    /*
-     * Check if the supplied buffer is large enough.
-     */
-    if (dwSize < ReturnLength)
-    {
-        if (Buffer != InitialBuffer)
-        {
-            ExFreePoolWithTag(Buffer, TAG_WINSTA);
-        }
-        return STATUS_BUFFER_TOO_SMALL;
-    }
-
-    /*
-     * Generate the resulting buffer contents.
-     */
-    Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
-    if (! NT_SUCCESS(Status))
-    {
-        if (Buffer != InitialBuffer)
-        {
-            ExFreePoolWithTag(Buffer, TAG_WINSTA);
-        }
-        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)
-            {
-                ExFreePoolWithTag(Buffer, TAG_WINSTA);
-            }
-            return Status;
-        }
-        lpBuffer = (PVOID) ((PCHAR) lpBuffer + DirEntry->Name.Length);
-        Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
-        if (! NT_SUCCESS(Status))
-        {
-            if (Buffer != InitialBuffer)
-            {
-                ExFreePoolWithTag(Buffer, TAG_WINSTA);
-            }
-            return Status;
-        }
-        lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
-    }
-
-    /*
-     * Clean up
-     */
-    if (Buffer != InitialBuffer)
-    {
-        ExFreePoolWithTag(Buffer, TAG_WINSTA);
-    }
-
-    return STATUS_SUCCESS;
-}
-
-static NTSTATUS FASTCALL
-BuildDesktopNameList(
-    HWINSTA hWindowStation,
-    ULONG dwSize,
-    PVOID lpBuffer,
-    PULONG pRequiredSize)
-{
-    NTSTATUS Status;
-    PWINSTATION_OBJECT WindowStation;
-    PLIST_ENTRY DesktopEntry;
-    PDESKTOP DesktopObject;
-    DWORD EntryCount;
-    ULONG ReturnLength;
-    WCHAR NullWchar;
-    UNICODE_STRING DesktopName;
-
-    Status = IntValidateWindowStationHandle(hWindowStation,
-                                            UserMode,
-                                            0,
-                                            &WindowStation,
-                                            0);
-    if (! NT_SUCCESS(Status))
-    {
-        return Status;
-    }
-
-    /*
-     * 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, ListEntry);
-        RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
-        ReturnLength += DesktopName.Length + sizeof(WCHAR);
-        EntryCount++;
-    }
-    TRACE("Required size: %lu Entry count: %lu\n", ReturnLength, EntryCount);
-    if (NULL != pRequiredSize)
-    {
-        Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
-        if (! NT_SUCCESS(Status))
-        {
-            ObDereferenceObject(WindowStation);
-            return STATUS_BUFFER_TOO_SMALL;
-        }
-    }
-
-    /*
-     * Check if the supplied buffer is large enough.
-     */
-    if (dwSize < ReturnLength)
-    {
-        ObDereferenceObject(WindowStation);
-        return STATUS_BUFFER_TOO_SMALL;
-    }
-
-    /*
-     * Generate the resulting buffer contents.
-     */
-    Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
-    if (! NT_SUCCESS(Status))
-    {
-        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, ListEntry);
-        RtlInitUnicodeString(&DesktopName, DesktopObject->pDeskInfo->szDesktopName);
-        Status = MmCopyToCaller(lpBuffer, DesktopName.Buffer, DesktopName.Length);
-        if (! NT_SUCCESS(Status))
-        {
-            ObDereferenceObject(WindowStation);
-            return Status;
-        }
-        lpBuffer = (PVOID) ((PCHAR)lpBuffer + DesktopName.Length);
-        Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
-        if (! NT_SUCCESS(Status))
-        {
-            ObDereferenceObject(WindowStation);
-            return Status;
-        }
-        lpBuffer = (PVOID) ((PCHAR) lpBuffer + sizeof(WCHAR));
-    }
-
-    /*
-     * Clean up and return
-     */
-    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 succeeds, the buffer is
- *       filled with window station/desktop count (in first DWORD) and
- *       NULL-terminated window station/desktop names.
- *
- *    pRequiredSize
- *       If the function succeeds, this is the number of bytes copied.
- *       Otherwise it's size of buffer needed for function to succeed.
- *
- * Status
- *    @implemented
- */
-
-NTSTATUS APIENTRY
-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);
-}
-
-/*
- * @implemented
- */
-BOOL APIENTRY
-NtUserSetLogonNotifyWindow(HWND hWnd)
-{
-    if (gpidLogon != PsGetCurrentProcessId())
-    {
-        return FALSE;
-    }
-
-    if (!IntIsWindow(hWnd))
-    {
-        return FALSE;
-    }
-
-    hwndSAS = hWnd;
-
-    return TRUE;
-}
-
-BOOL
-APIENTRY
-NtUserLockWorkStation(VOID)
-{
-    BOOL ret;
-    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
-
-    UserEnterExclusive();
-
-    if (pti->rpdesk == IntGetActiveDesktop())
-    {
-        ret = UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_LOCK_WORKSTATION, 0);
-    }
-    else
-    {
-        ret = FALSE;
-    }
-
-    UserLeave();
-
-    return ret;
-}
-
-BOOL APIENTRY
-NtUserSetWindowStationUser(
-    HWINSTA hWindowStation,
-    PLUID pluid,
-    PSID psid,
-    DWORD size)
-{
-    NTSTATUS Status;
-    PWINSTATION_OBJECT WindowStation = NULL;
-    BOOL Ret = FALSE;
-
-    UserEnterExclusive();
-
-    if (gpidLogon != PsGetCurrentProcessId())
-    {
-        EngSetLastError(ERROR_ACCESS_DENIED);
-        goto Leave;
-    }
-
-    Status = IntValidateWindowStationHandle(hWindowStation,
-                                            UserMode,
-                                            0,
-                                            &WindowStation,
-                                            0);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Leave;
-    }
-
-    if (WindowStation->psidUser)
-    {
-        ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
-    }
-
-    WindowStation->psidUser = ExAllocatePoolWithTag(PagedPool, size, USERTAG_SECURITY);
-    if (WindowStation->psidUser == NULL)
-    {
-        EngSetLastError(ERROR_OUTOFMEMORY);
-        goto Leave;
-    }
-
-    _SEH2_TRY
-    {
-        ProbeForRead( psid, size, 1);
-        ProbeForRead( pluid, sizeof(LUID), 1);
-
-        RtlCopyMemory(WindowStation->psidUser, psid, size);
-        WindowStation->luidUser = *pluid;
-    }
-    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
-    {
-        Status = _SEH2_GetExceptionCode();
-    }
-    _SEH2_END;
-
-    if (!NT_SUCCESS(Status))
-    {
-        ExFreePoolWithTag(WindowStation->psidUser, USERTAG_SECURITY);
-        WindowStation->psidUser = 0;
-        goto Leave;
-    }
-
-    Ret = TRUE;
-
-Leave:
-    if (WindowStation) ObDereferenceObject(WindowStation);
-    UserLeave();
-    return Ret;
-}
-
-
-/* EOF */