- 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; 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 NTSTATUS NTAPI
ConDrvGetConsoleProcessList(IN PCONSOLE Console, ConDrvGetConsoleProcessList(IN PCONSOLE Console,
IN OUT PULONG ProcessIdsList, IN OUT PULONG ProcessIdsList,

View file

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

View file

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

View file

@ -633,10 +633,6 @@ Quit:
return Status; return Status;
} }
NTSTATUS
ConDrvConsoleCtrlEvent(IN ULONG CtrlEvent,
IN PCONSOLE_PROCESS_DATA ProcessData);
VOID VOID
FASTCALL FASTCALL
ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData) ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
@ -652,6 +648,9 @@ ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
ProcessData->ConsoleHandle, ProcessData->ConsoleHandle,
CONSOLE_RUNNING, TRUE)) CONSOLE_RUNNING, TRUE))
{ {
/* Retrieve the console leader process */
PCONSOLE_PROCESS_DATA ConsoleLeaderProcess = ConDrvGetConsoleLeaderProcess(Console);
DPRINT("ConSrvRemoveConsole - Locking OK\n"); DPRINT("ConSrvRemoveConsole - Locking OK\n");
/* Close all console handles and free the handles table */ /* Close all console handles and free the handles table */
@ -660,36 +659,41 @@ ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
/* Detach the process from the console */ /* Detach the process from the console */
ProcessData->ConsoleHandle = NULL; 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); 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 */ /* Update the internal info of the terminal */
TermRefreshInternalInfo(Console); 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 */ /* Release the console */
DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount); DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount);
ConDrvReleaseConsole(Console, TRUE); ConDrvReleaseConsole(Console, TRUE);

View file

@ -343,6 +343,11 @@ typedef struct _CONSOLE
VOID FASTCALL ConioPause(PCONSOLE Console, UINT Flags); VOID FASTCALL ConioPause(PCONSOLE Console, UINT Flags);
VOID FASTCALL ConioUnpause(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 NTSTATUS NTAPI
ConDrvConsoleProcessCtrlEvent(IN PCONSOLE Console, ConDrvConsoleProcessCtrlEvent(IN PCONSOLE Console,
IN ULONG ProcessGroupId, IN ULONG ProcessGroupId,