reactos/reactos/win32ss/user/winsrv/consrv/console.c
Hermès Bélusca-Maïto 286ee4b8b1 [KERNEL32][CONSRV]
Implement (undocumented) SetLastConsoleEventActive API.
Patch by Alexander Andrejevic, with a minor modification by me concerning the addition of a NotifiedLastCloseProcess member to the CONSOLE structure and a check that makes sure that only the app that asked for the notification, receives it (and so that we don't call the console control dispatcher for nothing).
This API is used by ntvdm to be sure that it gets killed when all other console apps attached to the ntvdm's console are away.
CORE-7250

svn path=/trunk/; revision=62847
2014-04-21 01:22:17 +00:00

730 lines
23 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/console.c
* PURPOSE: Console Management Functions
* PROGRAMMERS: Gé van Geldorp
* Jeffrey Morlan
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include <ndk/psfuncs.h>
#include "procinit.h"
#ifdef TUITERM_COMPILE
#include "frontends/tui/tuiterm.h"
#endif
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
/***************/
#ifdef TUITERM_COMPILE
NTSTATUS NTAPI
TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
IN OUT PCONSOLE_INFO ConsoleInfo,
IN OUT PVOID ExtraConsoleInfo,
IN ULONG ProcessId);
NTSTATUS NTAPI
TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
#endif
NTSTATUS NTAPI
GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
IN OUT PCONSOLE_INFO ConsoleInfo,
IN OUT PVOID ExtraConsoleInfo,
IN ULONG ProcessId);
NTSTATUS NTAPI
GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
/***************/
typedef
NTSTATUS (NTAPI *FRONTEND_LOAD)(IN OUT PFRONTEND FrontEnd,
IN OUT PCONSOLE_INFO ConsoleInfo,
IN OUT PVOID ExtraConsoleInfo,
IN ULONG ProcessId);
typedef
NTSTATUS (NTAPI *FRONTEND_UNLOAD)(IN OUT PFRONTEND FrontEnd);
/*
* If we are not in GUI-mode, start the text-mode terminal emulator.
* If we fail, try to start the GUI-mode terminal emulator.
*
* Try to open the GUI-mode terminal emulator. Two cases are possible:
* - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
* failed and we start GUI-mode terminal emulator.
* - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
* succeeded BUT we failed at starting text-mode terminal emulator.
* Then GuiMode was switched to TRUE in order to try to open the GUI-mode
* terminal emulator (Win32k will automatically switch to graphical mode,
* therefore no additional code is needed).
*/
/*
* NOTE: Each entry of the table should be retrieved when loading a front-end
* (examples of the CSR servers which register some data for CSRSS).
*/
struct
{
CHAR FrontEndName[80];
FRONTEND_LOAD FrontEndLoad;
FRONTEND_UNLOAD FrontEndUnload;
} FrontEndLoadingMethods[] =
{
#ifdef TUITERM_COMPILE
{"TUI", TuiLoadFrontEnd, TuiUnloadFrontEnd},
#endif
{"GUI", GuiLoadFrontEnd, GuiUnloadFrontEnd},
// {"Not found", 0, NULL}
};
/* PRIVATE FUNCTIONS **********************************************************/
#if 0000
VOID FASTCALL
ConioPause(PCONSOLE Console, UINT Flags)
{
Console->PauseFlags |= Flags;
if (!Console->UnpauseEvent)
Console->UnpauseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
VOID FASTCALL
ConioUnpause(PCONSOLE Console, UINT Flags)
{
Console->PauseFlags &= ~Flags;
// if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
if (Console->PauseFlags == 0 && Console->UnpauseEvent)
{
SetEvent(Console->UnpauseEvent);
CloseHandle(Console->UnpauseEvent);
Console->UnpauseEvent = NULL;
CsrNotifyWait(&Console->WriteWaitQueue,
TRUE,
NULL,
NULL);
if (!IsListEmpty(&Console->WriteWaitQueue))
{
CsrDereferenceWait(&Console->WriteWaitQueue);
}
}
}
#endif
NTSTATUS FASTCALL
ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
PCONSOLE* Console,
BOOL LockConsole)
{
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE ProcessConsole;
ASSERT(Console);
*Console = NULL;
// RtlEnterCriticalSection(&ProcessData->HandleTableLock);
Status = ConDrvGetConsole(&ProcessConsole, ProcessData->ConsoleHandle, LockConsole);
if (NT_SUCCESS(Status)) *Console = ProcessConsole;
// RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return Status;
}
VOID FASTCALL
ConSrvReleaseConsole(PCONSOLE Console,
BOOL WasConsoleLocked)
{
/* Just call the driver */
ConDrvReleaseConsole(Console, WasConsoleLocked);
}
NTSTATUS NTAPI
ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
OUT PCONSOLE* NewConsole,
IN OUT PCONSOLE_START_INFO ConsoleStartInfo,
IN ULONG ConsoleLeaderProcessId)
{
NTSTATUS Status;
HANDLE ConsoleHandle;
PCONSOLE Console;
CONSOLE_INFO ConsoleInfo;
SIZE_T Length = 0;
ULONG i = 0;
FRONTEND FrontEnd;
if (NewConsole == NULL || ConsoleStartInfo == NULL)
return STATUS_INVALID_PARAMETER;
*NewConsole = NULL;
/*
* Load the console settings
*/
/* 1. Load the default settings */
ConSrvGetDefaultSettings(&ConsoleInfo, ConsoleLeaderProcessId);
/* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */
Length = min(wcslen(ConsoleStartInfo->ConsoleTitle),
sizeof(ConsoleInfo.ConsoleTitle) / sizeof(ConsoleInfo.ConsoleTitle[0]) - 1);
wcsncpy(ConsoleInfo.ConsoleTitle, ConsoleStartInfo->ConsoleTitle, Length);
ConsoleInfo.ConsoleTitle[Length] = L'\0';
/*
* Choose an adequate terminal front-end to load, and load it
*/
Status = STATUS_SUCCESS;
for (i = 0; i < sizeof(FrontEndLoadingMethods) / sizeof(FrontEndLoadingMethods[0]); ++i)
{
DPRINT("CONSRV: Trying to load %s terminal emulator...\n", FrontEndLoadingMethods[i].FrontEndName);
Status = FrontEndLoadingMethods[i].FrontEndLoad(&FrontEnd,
&ConsoleInfo,
ConsoleStartInfo,
ConsoleLeaderProcessId);
if (NT_SUCCESS(Status))
{
DPRINT("CONSRV: %s terminal emulator loaded successfully\n", FrontEndLoadingMethods[i].FrontEndName);
break;
}
else
{
DPRINT1("CONSRV: Loading %s terminal emulator failed, Status = 0x%08lx , continuing...\n", FrontEndLoadingMethods[i].FrontEndName, Status);
}
}
if (!NT_SUCCESS(Status))
{
DPRINT1("CONSRV: Failed to initialize a frontend, Status = 0x%08lx\n", Status);
return Status;
}
DPRINT("CONSRV: Frontend initialized\n");
/******************************************************************************/
/*
* 4. Load the remaining console settings via the registry.
*/
if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
{
/*
* Either we weren't created by an app launched via a shell-link,
* or we failed to load shell-link console properties.
* Therefore, load the console infos for the application from the registry.
*/
ConSrvReadUserSettings(&ConsoleInfo, ConsoleLeaderProcessId);
/*
* Now, update them with the properties the user might gave to us
* via the STARTUPINFO structure before calling CreateProcess
* (and which was transmitted via the ConsoleStartInfo structure).
* We therefore overwrite the values read in the registry.
*/
if (ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE)
{
ConsoleInfo.ScreenAttrib = (USHORT)ConsoleStartInfo->wFillAttribute;
}
if (ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS)
{
ConsoleInfo.ScreenBufferSize = ConsoleStartInfo->dwScreenBufferSize;
}
if (ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE)
{
ConsoleInfo.ConsoleSize = ConsoleStartInfo->dwWindowSize;
}
}
/* Set-up the code page */
ConsoleInfo.CodePage = GetOEMCP();
/******************************************************************************/
Status = ConDrvInitConsole(&ConsoleHandle,
&Console,
&ConsoleInfo,
ConsoleLeaderProcessId);
if (!NT_SUCCESS(Status))
{
DPRINT1("Creating a new console failed, Status = 0x%08lx\n", Status);
FrontEndLoadingMethods[i].FrontEndUnload(&FrontEnd);
return Status;
}
ASSERT(Console);
DPRINT("Console initialized\n");
Status = ConDrvRegisterFrontEnd(Console, &FrontEnd);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to register frontend to the given console, Status = 0x%08lx\n", Status);
ConDrvDeleteConsole(Console);
FrontEndLoadingMethods[i].FrontEndUnload(&FrontEnd);
return Status;
}
DPRINT("FrontEnd registered\n");
/* Return the newly created console to the caller and a success code too */
*NewConsoleHandle = ConsoleHandle;
*NewConsole = Console;
return STATUS_SUCCESS;
}
VOID NTAPI
ConSrvDeleteConsole(PCONSOLE Console)
{
DPRINT("ConSrvDeleteConsole\n");
/* Just call the driver. ConSrvDeregisterFrontEnd is called on-demand. */
ConDrvDeleteConsole(Console);
}
/* PUBLIC SERVER APIS *********************************************************/
CSR_API(SrvAllocConsole)
{
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE_ALLOCCONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest;
PCSR_PROCESS CsrProcess = CsrGetClientThread()->Process;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
if (ProcessData->ConsoleHandle != NULL)
{
DPRINT1("Process already has a console\n");
return STATUS_ACCESS_DENIED;
}
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
1,
sizeof(CONSOLE_START_INFO)))
{
return STATUS_INVALID_PARAMETER;
}
/* Initialize a new Console owned by the Console Leader Process */
Status = ConSrvAllocateConsole(ProcessData,
&AllocConsoleRequest->InputHandle,
&AllocConsoleRequest->OutputHandle,
&AllocConsoleRequest->ErrorHandle,
AllocConsoleRequest->ConsoleStartInfo);
if (!NT_SUCCESS(Status))
{
DPRINT1("Console allocation failed\n");
return Status;
}
/* Return the console handle and the input wait handle to the caller */
AllocConsoleRequest->ConsoleHandle = ProcessData->ConsoleHandle;
AllocConsoleRequest->InputWaitHandle = ProcessData->ConsoleEvent;
/* Set the Property-Dialog and Control-Dispatcher handlers */
ProcessData->PropDispatcher = AllocConsoleRequest->PropDispatcher;
ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
return STATUS_SUCCESS;
}
CSR_API(SrvAttachConsole)
{
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AttachConsoleRequest;
PCSR_PROCESS SourceProcess = NULL; // The parent process.
PCSR_PROCESS TargetProcess = CsrGetClientThread()->Process; // Ourselves.
HANDLE ProcessId = ULongToHandle(AttachConsoleRequest->ProcessId);
PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
if (TargetProcessData->ConsoleHandle != NULL)
{
DPRINT1("Process already has a console\n");
return STATUS_ACCESS_DENIED;
}
/* Check whether we try to attach to the parent's console */
if (ProcessId == ULongToHandle(ATTACH_PARENT_PROCESS))
{
PROCESS_BASIC_INFORMATION ProcessInfo;
ULONG Length = sizeof(ProcessInfo);
/* Get the real parent's ID */
Status = NtQueryInformationProcess(TargetProcess->ProcessHandle,
ProcessBasicInformation,
&ProcessInfo,
Length, &Length);
if (!NT_SUCCESS(Status))
{
DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status);
return Status;
}
ProcessId = ULongToHandle(ProcessInfo.InheritedFromUniqueProcessId);
}
/* Lock the source process via its PID */
Status = CsrLockProcessByClientId(ProcessId, &SourceProcess);
if (!NT_SUCCESS(Status)) return Status;
SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
if (SourceProcessData->ConsoleHandle == NULL)
{
Status = STATUS_INVALID_HANDLE;
goto Quit;
}
/*
* Inherit the console from the parent,
* if any, otherwise return an error.
*/
Status = ConSrvInheritConsole(TargetProcessData,
SourceProcessData->ConsoleHandle,
TRUE,
&AttachConsoleRequest->InputHandle,
&AttachConsoleRequest->OutputHandle,
&AttachConsoleRequest->ErrorHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("Console inheritance failed\n");
goto Quit;
}
/* Return the console handle and the input wait handle to the caller */
AttachConsoleRequest->ConsoleHandle = TargetProcessData->ConsoleHandle;
AttachConsoleRequest->InputWaitHandle = TargetProcessData->ConsoleEvent;
/* Set the Property-Dialog and Control-Dispatcher handlers */
TargetProcessData->PropDispatcher = AttachConsoleRequest->PropDispatcher;
TargetProcessData->CtrlDispatcher = AttachConsoleRequest->CtrlDispatcher;
Status = STATUS_SUCCESS;
Quit:
/* Unlock the "source" process and exit */
CsrUnlockProcess(SourceProcess);
return Status;
}
CSR_API(SrvFreeConsole)
{
ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
return STATUS_SUCCESS;
}
NTSTATUS NTAPI
ConDrvGetConsoleMode(IN PCONSOLE Console,
IN PCONSOLE_IO_OBJECT Object,
OUT PULONG ConsoleMode);
CSR_API(SrvGetConsoleMode)
{
NTSTATUS Status;
PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
PCONSOLE_IO_OBJECT Object;
Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ConsoleModeRequest->Handle,
&Object, NULL, GENERIC_READ, TRUE, 0);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvGetConsoleMode(Object->Console, Object,
&ConsoleModeRequest->Mode);
ConSrvReleaseObject(Object, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleMode(IN PCONSOLE Console,
IN PCONSOLE_IO_OBJECT Object,
IN ULONG ConsoleMode);
CSR_API(SrvSetConsoleMode)
{
NTSTATUS Status;
PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
PCONSOLE_IO_OBJECT Object;
Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
ConsoleModeRequest->Handle,
&Object, NULL, GENERIC_WRITE, TRUE, 0);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleMode(Object->Console, Object,
ConsoleModeRequest->Mode);
ConSrvReleaseObject(Object, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvGetConsoleTitle(IN PCONSOLE Console,
IN BOOLEAN Unicode,
IN OUT PVOID TitleBuffer,
IN OUT PULONG BufLength);
CSR_API(SrvGetConsoleTitle)
{
NTSTATUS Status;
PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
PCONSOLE Console;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&TitleRequest->Title,
TitleRequest->Length,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Can't get console\n");
return Status;
}
Status = ConDrvGetConsoleTitle(Console,
TitleRequest->Unicode,
TitleRequest->Title,
&TitleRequest->Length);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleTitle(IN PCONSOLE Console,
IN BOOLEAN Unicode,
IN PVOID TitleBuffer,
IN ULONG BufLength);
CSR_API(SrvSetConsoleTitle)
{
NTSTATUS Status;
PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest;
PCONSOLE Console;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&TitleRequest->Title,
TitleRequest->Length,
sizeof(BYTE)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Can't get console\n");
return Status;
}
Status = ConDrvSetConsoleTitle(Console,
TitleRequest->Unicode,
TitleRequest->Title,
TitleRequest->Length);
if (NT_SUCCESS(Status)) TermChangeTitle(Console);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvGetConsoleCP(IN PCONSOLE Console,
OUT PUINT CodePage,
IN BOOLEAN OutputCP);
CSR_API(SrvGetConsoleCP)
{
NTSTATUS Status;
PCONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleCPRequest;
PCONSOLE Console;
DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
GetConsoleCPRequest->OutputCP ? "Output" : "Input");
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvGetConsoleCP(Console,
&GetConsoleCPRequest->CodePage,
GetConsoleCPRequest->OutputCP);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvSetConsoleCP(IN PCONSOLE Console,
IN UINT CodePage,
IN BOOLEAN OutputCP);
CSR_API(SrvSetConsoleCP)
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PCONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetConsoleCPRequest;
PCONSOLE Console;
DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
SetConsoleCPRequest->OutputCP ? "Output" : "Input");
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvSetConsoleCP(Console,
SetConsoleCPRequest->CodePage,
SetConsoleCPRequest->OutputCP);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
NTSTATUS NTAPI
ConDrvGetConsoleProcessList(IN PCONSOLE Console,
IN OUT PULONG ProcessIdsList,
IN ULONG MaxIdListItems,
OUT PULONG ProcessIdsTotal);
CSR_API(SrvGetConsoleProcessList)
{
NTSTATUS Status;
PCONSOLE_GETPROCESSLIST GetProcessListRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetProcessListRequest;
PCONSOLE Console;
if (!CsrValidateMessageBuffer(ApiMessage,
(PVOID)&GetProcessListRequest->ProcessIdsList,
GetProcessListRequest->ProcessCount,
sizeof(DWORD)))
{
return STATUS_INVALID_PARAMETER;
}
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvGetConsoleProcessList(Console,
GetProcessListRequest->ProcessIdsList,
GetProcessListRequest->ProcessCount,
&GetProcessListRequest->ProcessCount);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
CSR_API(SrvGenerateConsoleCtrlEvent)
{
NTSTATUS Status;
PCONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GenerateCtrlEventRequest;
PCONSOLE Console;
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
Status = ConDrvConsoleProcessCtrlEvent(Console,
GenerateCtrlEventRequest->ProcessGroupId,
GenerateCtrlEventRequest->CtrlEvent);
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
CSR_API(SrvConsoleNotifyLastClose)
{
NTSTATUS Status;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
PCONSOLE Console;
Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
/* Only one process is allowed to be registered for last close notification */
if (!Console->NotifyLastClose)
{
Console->NotifiedLastCloseProcess = ProcessData;
Console->NotifyLastClose = TRUE;
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_ACCESS_DENIED;
}
ConSrvReleaseConsole(Console, TRUE);
return Status;
}
CSR_API(SrvGetConsoleMouseInfo)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
CSR_API(SrvSetConsoleKeyShortcuts)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
CSR_API(SrvGetConsoleKeyboardLayoutName)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
CSR_API(SrvGetConsoleCharType)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
CSR_API(SrvSetConsoleLocalEUDC)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
CSR_API(SrvSetConsoleCursorMode)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
CSR_API(SrvGetConsoleCursorMode)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
CSR_API(SrvGetConsoleNlsMode)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
CSR_API(SrvSetConsoleNlsMode)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
CSR_API(SrvGetConsoleLangId)
{
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */