From 561cbbb117d2136b6e8989a3e0282060a16400bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Tue, 22 Apr 2014 00:46:49 +0000 Subject: [PATCH] [CONSRV] - 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 --- .../user/winsrv/consrv/condrv/console.c | 10 +++ .../user/winsrv/consrv/frontends/gui/conwnd.c | 4 +- .../winsrv/consrv/frontends/gui/guisettings.c | 8 +-- reactos/win32ss/user/winsrv/consrv/handle.c | 62 ++++++++++--------- .../user/winsrv/consrv/include/conio.h | 5 ++ 5 files changed, 51 insertions(+), 38 deletions(-) diff --git a/reactos/win32ss/user/winsrv/consrv/condrv/console.c b/reactos/win32ss/user/winsrv/consrv/condrv/console.c index 3ec35f220af..c19754da56e 100644 --- a/reactos/win32ss/user/winsrv/consrv/condrv/console.c +++ b/reactos/win32ss/user/winsrv/consrv/condrv/console.c @@ -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, diff --git a/reactos/win32ss/user/winsrv/consrv/frontends/gui/conwnd.c b/reactos/win32ss/user/winsrv/consrv/frontends/gui/conwnd.c index 6e8adfb6231..da3a0f11614 100644 --- a/reactos/win32ss/user/winsrv/consrv/frontends/gui/conwnd.c +++ b/reactos/win32ss/user/winsrv/consrv/frontends/gui/conwnd.c @@ -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)); diff --git a/reactos/win32ss/user/winsrv/consrv/frontends/gui/guisettings.c b/reactos/win32ss/user/winsrv/consrv/frontends/gui/guisettings.c index 0d64f83e604..fadfc79aeba 100644 --- a/reactos/win32ss/user/winsrv/consrv/frontends/gui/guisettings.c +++ b/reactos/win32ss/user/winsrv/consrv/frontends/gui/guisettings.c @@ -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, diff --git a/reactos/win32ss/user/winsrv/consrv/handle.c b/reactos/win32ss/user/winsrv/consrv/handle.c index 81fa41d2dce..98b7ff0c0db 100644 --- a/reactos/win32ss/user/winsrv/consrv/handle.c +++ b/reactos/win32ss/user/winsrv/consrv/handle.c @@ -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); diff --git a/reactos/win32ss/user/winsrv/consrv/include/conio.h b/reactos/win32ss/user/winsrv/consrv/include/conio.h index 6dda15759fe..631eebd3f01 100644 --- a/reactos/win32ss/user/winsrv/consrv/include/conio.h +++ b/reactos/win32ss/user/winsrv/consrv/include/conio.h @@ -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,