- Introduce a helper function to query the console leader process (instead of using duplicated code).
- Fix the algorithm of the last close notification, as demonstrated by the tests I did on windows 2003 (test app is provided in CORE-7250):
  a console app that registered for the last close notification, closes only if the process that was the console leader process at the time the app registered for the notification, is killed.
  In this case, we notify the app, and we clear some flags. On the contrary, if we close the app that registered for the notification, we just clear the flags without doing extra operations.

svn path=/trunk/; revision=62861
This commit is contained in:
Hermès Bélusca-Maïto 2014-04-22 00:46:49 +00:00
parent 94466379c8
commit 561cbbb117
5 changed files with 51 additions and 38 deletions

View file

@ -1091,6 +1091,16 @@ ConDrvSetConsoleCP(IN PCONSOLE Console,
return STATUS_SUCCESS;
}
PCONSOLE_PROCESS_DATA NTAPI
ConDrvGetConsoleLeaderProcess(IN PCONSOLE Console)
{
if (Console == NULL) return NULL;
return CONTAINING_RECORD(Console->ProcessList.Blink,
CONSOLE_PROCESS_DATA,
ConsoleLink);
}
NTSTATUS NTAPI
ConDrvGetConsoleProcessList(IN PCONSOLE Console,
IN OUT PULONG ProcessIdsList,

View file

@ -48,9 +48,7 @@ SetConWndConsoleLeaderCID(IN PGUI_CONSOLE_DATA GuiData)
PCONSOLE_PROCESS_DATA ProcessData;
CLIENT_ID ConsoleLeaderCID;
ProcessData = CONTAINING_RECORD(GuiData->Console->ProcessList.Blink,
CONSOLE_PROCESS_DATA,
ConsoleLink);
ProcessData = ConDrvGetConsoleLeaderProcess(GuiData->Console);
ConsoleLeaderCID = ProcessData->Process->ClientId;
SetWindowLongPtrW(GuiData->hWindow, GWLP_CONSOLE_LEADER_PID,
(LONG_PTR)(ConsoleLeaderCID.UniqueProcess));

View file

@ -356,9 +356,7 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
NtUnmapViewOfSection(NtCurrentProcess(), pSharedInfo);
/* Get the console leader process, our client */
ProcessData = CONTAINING_RECORD(Console->ProcessList.Blink,
CONSOLE_PROCESS_DATA,
ConsoleLink);
ProcessData = ConDrvGetConsoleLeaderProcess(Console);
/* Duplicate the section handle for the client */
Status = NtDuplicateObject(NtCurrentProcess(),
@ -430,9 +428,7 @@ GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
PGUI_CONSOLE_INFO GuiInfo = NULL;
/* Get the console leader process, our client */
ProcessData = CONTAINING_RECORD(Console->ProcessList.Blink,
CONSOLE_PROCESS_DATA,
ConsoleLink);
ProcessData = ConDrvGetConsoleLeaderProcess(Console);
/* Duplicate the section handle for ourselves */
Status = NtDuplicateObject(ProcessData->Process->ProcessHandle,

View file

@ -633,10 +633,6 @@ Quit:
return Status;
}
NTSTATUS
ConDrvConsoleCtrlEvent(IN ULONG CtrlEvent,
IN PCONSOLE_PROCESS_DATA ProcessData);
VOID
FASTCALL
ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
@ -652,6 +648,9 @@ ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
ProcessData->ConsoleHandle,
CONSOLE_RUNNING, TRUE))
{
/* Retrieve the console leader process */
PCONSOLE_PROCESS_DATA ConsoleLeaderProcess = ConDrvGetConsoleLeaderProcess(Console);
DPRINT("ConSrvRemoveConsole - Locking OK\n");
/* Close all console handles and free the handles table */
@ -660,36 +659,41 @@ ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
/* Detach the process from the console */
ProcessData->ConsoleHandle = NULL;
/* Remove ourselves from the console's list of processes */
/* Remove the process from the console's list of processes */
RemoveEntryList(&ProcessData->ConsoleLink);
/* Check whether the console should send a last close notification */
if (Console->NotifyLastClose)
{
/* If we are removing the process which wants the last close notification... */
if (ProcessData == Console->NotifiedLastCloseProcess)
{
/* ... just reset the flag and the pointer... */
Console->NotifyLastClose = FALSE;
Console->NotifiedLastCloseProcess = NULL;
}
/*
* ... otherwise, if we are removing the console leader process
* (that cannot be the process wanting the notification, because
* the previous case already dealt with it)...
*/
else if (ProcessData == ConsoleLeaderProcess)
{
/*
* ... reset the flag first (so that we avoid multiple notifications)
* and then send the last close notification.
*/
Console->NotifyLastClose = FALSE;
ConDrvConsoleCtrlEvent(CTRL_LAST_CLOSE_EVENT, Console->NotifiedLastCloseProcess);
/* Only now, reset the pointer */
Console->NotifiedLastCloseProcess = NULL;
}
}
/* 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);

View file

@ -343,6 +343,11 @@ typedef struct _CONSOLE
VOID FASTCALL ConioPause(PCONSOLE Console, UINT Flags);
VOID FASTCALL ConioUnpause(PCONSOLE Console, UINT Flags);
PCONSOLE_PROCESS_DATA NTAPI
ConDrvGetConsoleLeaderProcess(IN PCONSOLE Console);
NTSTATUS
ConDrvConsoleCtrlEvent(IN ULONG CtrlEvent,
IN PCONSOLE_PROCESS_DATA ProcessData);
NTSTATUS NTAPI
ConDrvConsoleProcessCtrlEvent(IN PCONSOLE Console,
IN ULONG ProcessGroupId,