mirror of
https://github.com/reactos/reactos.git
synced 2025-01-07 14:51:00 +00:00
[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
This commit is contained in:
parent
38be5bceff
commit
286ee4b8b1
7 changed files with 114 additions and 32 deletions
|
@ -30,6 +30,7 @@ PHANDLER_ROUTINE InitialHandler[1];
|
|||
PHANDLER_ROUTINE* CtrlHandlers;
|
||||
ULONG NrCtrlHandlers;
|
||||
ULONG NrAllocatedHandlers;
|
||||
BOOL LastCloseNotify = FALSE;
|
||||
|
||||
HANDLE InputWaitHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
|
@ -129,8 +130,14 @@ ConsoleControlDispatcher(IN LPVOID lpThreadParameter)
|
|||
case CTRL_SHUTDOWN_EVENT:
|
||||
break;
|
||||
|
||||
case 3:
|
||||
ExitThread(0);
|
||||
case CTRL_LAST_CLOSE_EVENT:
|
||||
/*
|
||||
* In case the console app hasn't register for last close notification,
|
||||
* just kill this console handler thread. We don't want that such apps
|
||||
* get killed for unexpected reasons. On the contrary apps that registered
|
||||
* can be killed because they expect to be.
|
||||
*/
|
||||
if (!LastCloseNotify) ExitThread(0);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
|
@ -2595,14 +2602,26 @@ BOOL WINAPI GetConsoleKeyboardLayoutNameW(LPWSTR name)
|
|||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
* @implemented
|
||||
*/
|
||||
BOOL
|
||||
DWORD
|
||||
WINAPI
|
||||
SetLastConsoleEventActive(VOID)
|
||||
{
|
||||
STUB;
|
||||
return FALSE;
|
||||
CONSOLE_API_MESSAGE ApiMessage;
|
||||
PCONSOLE_NOTIFYLASTCLOSE NotifyLastCloseRequest = &ApiMessage.Data.NotifyLastCloseRequest;
|
||||
|
||||
/* Set the flag used by the console control dispatcher */
|
||||
LastCloseNotify = TRUE;
|
||||
|
||||
/* Set up the input arguments */
|
||||
NotifyLastCloseRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
|
||||
|
||||
/* Call CSRSS; just return the NTSTATUS cast to DWORD */
|
||||
return CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
|
||||
NULL,
|
||||
CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepNotifyLastClose),
|
||||
sizeof(*NotifyLastCloseRequest));
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -65,11 +65,12 @@ extern "C" {
|
|||
/*
|
||||
* Control handler codes
|
||||
*/
|
||||
#define CTRL_C_EVENT 0
|
||||
#define CTRL_BREAK_EVENT 1
|
||||
#define CTRL_CLOSE_EVENT 2
|
||||
#define CTRL_LOGOFF_EVENT 5
|
||||
#define CTRL_SHUTDOWN_EVENT 6
|
||||
#define CTRL_C_EVENT 0
|
||||
#define CTRL_BREAK_EVENT 1
|
||||
#define CTRL_CLOSE_EVENT 2
|
||||
#define CTRL_LAST_CLOSE_EVENT 3 /* Undocumented */
|
||||
#define CTRL_LOGOFF_EVENT 5
|
||||
#define CTRL_SHUTDOWN_EVENT 6
|
||||
|
||||
/*
|
||||
* Input mode flags
|
||||
|
|
|
@ -202,6 +202,20 @@ typedef struct
|
|||
PDWORD ProcessIdsList;
|
||||
} CONSOLE_GETPROCESSLIST, *PCONSOLE_GETPROCESSLIST;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE ConsoleHandle;
|
||||
DWORD CtrlEvent;
|
||||
DWORD ProcessGroupId;
|
||||
} CONSOLE_GENERATECTRLEVENT, *PCONSOLE_GENERATECTRLEVENT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE ConsoleHandle;
|
||||
} CONSOLE_NOTIFYLASTCLOSE, *PCONSOLE_NOTIFYLASTCLOSE;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE OutputHandle;
|
||||
|
@ -349,6 +363,7 @@ typedef struct
|
|||
} CONSOLE_GETSETHWSTATE, *PCONSOLE_GETSETHWSTATE;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE ConsoleHandle;
|
||||
|
@ -526,6 +541,15 @@ typedef struct
|
|||
BOOL AppendToEnd;
|
||||
} CONSOLE_WRITEINPUT, *PCONSOLE_WRITEINPUT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE ConsoleHandle;
|
||||
HANDLE InputHandle;
|
||||
DWORD NumberOfEvents;
|
||||
} CONSOLE_GETNUMINPUTEVENTS, *PCONSOLE_GETNUMINPUTEVENTS;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE ConsoleHandle;
|
||||
|
@ -584,6 +608,7 @@ typedef struct
|
|||
} CONSOLE_OPENCONSOLE, *PCONSOLE_OPENCONSOLE;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE ConsoleHandle;
|
||||
|
@ -700,20 +725,6 @@ typedef struct
|
|||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE ConsoleHandle;
|
||||
DWORD CtrlEvent;
|
||||
DWORD ProcessGroupId;
|
||||
} CONSOLE_GENERATECTRLEVENT, *PCONSOLE_GENERATECTRLEVENT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE ConsoleHandle;
|
||||
HANDLE InputHandle;
|
||||
DWORD NumberOfEvents;
|
||||
} CONSOLE_GETNUMINPUTEVENTS, *PCONSOLE_GETNUMINPUTEVENTS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE ConsoleHandle;
|
||||
|
@ -757,8 +768,10 @@ typedef struct _CONSOLE_API_MESSAGE
|
|||
CONSOLE_ATTACHCONSOLE AttachConsoleRequest;
|
||||
CONSOLE_FREECONSOLE FreeConsoleRequest;
|
||||
|
||||
/* Process list */
|
||||
/* Processes */
|
||||
CONSOLE_GETPROCESSLIST GetProcessListRequest;
|
||||
CONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest;
|
||||
CONSOLE_NOTIFYLASTCLOSE NotifyLastCloseRequest;
|
||||
|
||||
/* Handles */
|
||||
CONSOLE_OPENCONSOLE OpenConsoleRequest;
|
||||
|
@ -806,6 +819,7 @@ typedef struct _CONSOLE_API_MESSAGE
|
|||
CONSOLE_GETINPUT GetInputRequest; // SrvGetConsoleInput / PeekConsoleInput & ReadConsoleInput
|
||||
CONSOLE_READOUTPUT ReadOutputRequest; // SrvReadConsoleOutput / ReadConsoleOutput
|
||||
CONSOLE_READOUTPUTCODE ReadOutputCodeRequest; // SrvReadConsoleOutputString / ReadConsoleOutputAttribute & ReadConsoleOutputCharacter
|
||||
CONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest;
|
||||
|
||||
/* Write */
|
||||
CONSOLE_WRITECONSOLE WriteConsoleRequest; // SrvWriteConsole / WriteConsole
|
||||
|
@ -830,9 +844,6 @@ typedef struct _CONSOLE_API_MESSAGE
|
|||
CONSOLE_SETHISTORYNUMBERCOMMANDS SetHistoryNumberCommandsRequest;
|
||||
CONSOLE_GETSETHISTORYINFO HistoryInfoRequest;
|
||||
|
||||
CONSOLE_GENERATECTRLEVENT GenerateCtrlEventRequest;
|
||||
CONSOLE_GETNUMINPUTEVENTS GetNumInputEventsRequest;
|
||||
|
||||
/* Input and Output Code Pages */
|
||||
CONSOLE_GETINPUTOUTPUTCP GetConsoleCPRequest;
|
||||
CONSOLE_SETINPUTOUTPUTCP SetConsoleCPRequest;
|
||||
|
|
|
@ -244,7 +244,7 @@ ConDrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent,
|
|||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
NTSTATUS
|
||||
ConDrvConsoleCtrlEvent(IN ULONG CtrlEvent,
|
||||
IN PCONSOLE_PROCESS_DATA ProcessData)
|
||||
{
|
||||
|
@ -535,6 +535,8 @@ ConDrvInitConsole(OUT PHANDLE NewConsoleHandle,
|
|||
Console->ReferenceCount = 0;
|
||||
InitializeCriticalSection(&Console->Lock);
|
||||
InitializeListHead(&Console->ProcessList);
|
||||
Console->NotifiedLastCloseProcess = NULL;
|
||||
Console->NotifyLastClose = FALSE;
|
||||
|
||||
/* Initialize the frontend interface */
|
||||
ResetFrontEnd(Console);
|
||||
|
|
|
@ -641,8 +641,27 @@ CSR_API(SrvGenerateConsoleCtrlEvent)
|
|||
|
||||
CSR_API(SrvConsoleNotifyLastClose)
|
||||
{
|
||||
DPRINT1("%s not yet implemented\n", __FUNCTION__);
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -633,6 +633,10 @@ Quit:
|
|||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
ConDrvConsoleCtrlEvent(IN ULONG CtrlEvent,
|
||||
IN PCONSOLE_PROCESS_DATA ProcessData);
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
|
||||
|
@ -662,6 +666,30 @@ ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
|
|||
/* Update the internal info of the terminal */
|
||||
TermRefreshInternalInfo(Console);
|
||||
|
||||
/*
|
||||
* Check if there is only one process still attached to the console,
|
||||
* and that the console should send a control event in this case.
|
||||
*/
|
||||
if ((Console->ProcessList.Flink != &Console->ProcessList) &&
|
||||
(Console->ProcessList.Flink->Flink == &Console->ProcessList) &&
|
||||
// (Console->ProcessList.Flink == Console->ProcessList.Blink) &&
|
||||
Console->NotifyLastClose)
|
||||
{
|
||||
PCONSOLE_PROCESS_DATA LastProcess = CONTAINING_RECORD(Console->ProcessList.Flink,
|
||||
CONSOLE_PROCESS_DATA,
|
||||
ConsoleLink);
|
||||
/* If the remaining process is the one that wanted the notification... */
|
||||
if (LastProcess == Console->NotifiedLastCloseProcess)
|
||||
{
|
||||
/* ... notify it that it's the only one remaining on the console */
|
||||
ConDrvConsoleCtrlEvent(CTRL_LAST_CLOSE_EVENT, LastProcess);
|
||||
}
|
||||
|
||||
/* In any case reset the pointer and the flag */
|
||||
Console->NotifiedLastCloseProcess = NULL;
|
||||
Console->NotifyLastClose = FALSE;
|
||||
}
|
||||
|
||||
/* Release the console */
|
||||
DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount);
|
||||
ConDrvReleaseConsole(Console, TRUE);
|
||||
|
|
|
@ -282,6 +282,8 @@ typedef struct _CONSOLE
|
|||
CONSOLE_STATE State; /* State of the console */
|
||||
|
||||
LIST_ENTRY ProcessList; /* List of processes owning the console. The first one is the so-called "Console Leader Process" */
|
||||
PCONSOLE_PROCESS_DATA NotifiedLastCloseProcess; /* Pointer to the unique process that needs to be notified when all the other processes have been detached from the console */
|
||||
BOOLEAN NotifyLastClose; /* TRUE if the console should send a control event to the last attached process after all the others detached, if it wanted to be notified */
|
||||
|
||||
FRONTEND TermIFace; /* Frontend-specific interface */
|
||||
|
||||
|
|
Loading…
Reference in a new issue