[CONSRV]: Use NtDuplicateObject with DUPLICATE_CLOSE_SOURCE to close a duplicated...
[reactos.git] / reactos / win32ss / user / winsrv / consrv / handle.c
index a114411..125dfab 100644 (file)
@@ -96,7 +96,7 @@ ConSrvCloseHandle(IN PCONSOLE_IO_HANDLE Handle)
                  * even of the last buffer, but having to deal with a lack of
                  * any active buffer might be error-prone. */
                 if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink)
-                    ConioDeleteScreenBuffer(Buffer);
+                    ConDrvDeleteScreenBuffer(Buffer);
             }
             else if (Object->Type == INPUT_BUFFER)
             {
@@ -470,19 +470,16 @@ ConSrvReleaseObject(IN PCONSOLE_IO_OBJECT Object,
 
 
 
-
-
-
 NTSTATUS
 ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData,
                       PHANDLE pInputHandle,
                       PHANDLE pOutputHandle,
                       PHANDLE pErrorHandle,
-                      PCONSOLE_START_INFO ConsoleStartInfo)
+                      PCONSOLE_INIT_INFO ConsoleInitInfo)
 {
     NTSTATUS Status = STATUS_SUCCESS;
     HANDLE ConsoleHandle;
-    PCONSOLE Console;
+    PCONSRV_CONSOLE Console;
 
     /*
      * We are about to create a new console. However when ConSrvNewProcess
@@ -497,10 +494,14 @@ ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData,
     ConSrvFreeHandlesTable(ProcessData);
 
     /* Initialize a new Console owned by this process */
+    DPRINT("Initialization of console '%S' for process '%S' on desktop '%S'\n",
+           ConsoleInitInfo->ConsoleTitle ? ConsoleInitInfo->ConsoleTitle : L"n/a",
+           ConsoleInitInfo->AppName ? ConsoleInitInfo->AppName : L"n/a",
+           ConsoleInitInfo->Desktop ? ConsoleInitInfo->Desktop : L"n/a");
     Status = ConSrvInitConsole(&ConsoleHandle,
                                &Console,
-                               ConsoleStartInfo,
-                               HandleToUlong(ProcessData->Process->ClientId.UniqueProcess));
+                               ConsoleInitInfo,
+                               ProcessData->Process);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Console initialization failed\n");
@@ -524,23 +525,72 @@ ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData,
         return Status;
     }
 
+    /* Duplicate the Initialization Events */
+    Status = NtDuplicateObject(NtCurrentProcess(),
+                               Console->InitEvents[INIT_SUCCESS],
+                               ProcessData->Process->ProcessHandle,
+                               &ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS],
+                               EVENT_ALL_ACCESS, 0, 0);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status);
+        ConSrvFreeHandlesTable(ProcessData);
+        ConSrvDeleteConsole(Console);
+        ProcessData->ConsoleHandle = NULL;
+        return Status;
+    }
+
+    Status = NtDuplicateObject(NtCurrentProcess(),
+                               Console->InitEvents[INIT_FAILURE],
+                               ProcessData->Process->ProcessHandle,
+                               &ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_FAILURE],
+                               EVENT_ALL_ACCESS, 0, 0);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status);
+        NtDuplicateObject(ProcessData->Process->ProcessHandle,
+                          ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS],
+                          NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
+        ConSrvFreeHandlesTable(ProcessData);
+        ConSrvDeleteConsole(Console);
+        ProcessData->ConsoleHandle = NULL;
+        return Status;
+    }
+
     /* Duplicate the Input Event */
     Status = NtDuplicateObject(NtCurrentProcess(),
                                Console->InputBuffer.ActiveEvent,
                                ProcessData->Process->ProcessHandle,
-                               &ProcessData->InputWaitHandle,
+                               &ConsoleInitInfo->ConsoleStartInfo->InputWaitHandle,
                                EVENT_ALL_ACCESS, 0, 0);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
+        DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status);
+        NtDuplicateObject(ProcessData->Process->ProcessHandle,
+                          ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_FAILURE],
+                          NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
+        NtDuplicateObject(ProcessData->Process->ProcessHandle,
+                          ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS],
+                          NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
         ConSrvFreeHandlesTable(ProcessData);
         ConSrvDeleteConsole(Console);
         ProcessData->ConsoleHandle = NULL;
         return Status;
     }
 
-    /* Insert the process into the processes list of the console */
+    /* Mark the process as having a console */
+    ProcessData->ConsoleApp = TRUE;
+    ProcessData->Process->Flags |= CsrProcessIsConsoleApp;
+
+    /* Return the console handle to the caller */
+    ConsoleInitInfo->ConsoleStartInfo->ConsoleHandle = ProcessData->ConsoleHandle;
+
+    /*
+     * Insert the process into the processes list of the console,
+     * and set its foreground priority.
+     */
     InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
+    ConSrvSetProcessFocus(ProcessData->Process, Console->HasFocus);
 
     /* Add a reference count because the process is tied to the console */
     _InterlockedIncrement(&Console->ReferenceCount);
@@ -557,7 +607,8 @@ ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
                      BOOLEAN CreateNewHandlesTable,
                      PHANDLE pInputHandle,
                      PHANDLE pOutputHandle,
-                     PHANDLE pErrorHandle)
+                     PHANDLE pErrorHandle,
+                     PCONSOLE_START_INFO ConsoleStartInfo)
 {
     NTSTATUS Status = STATUS_SUCCESS;
     PCONSOLE Console;
@@ -602,22 +653,69 @@ ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
         }
     }
 
+    /* Duplicate the Initialization Events */
+    Status = NtDuplicateObject(NtCurrentProcess(),
+                               Console->InitEvents[INIT_SUCCESS],
+                               ProcessData->Process->ProcessHandle,
+                               &ConsoleStartInfo->InitEvents[INIT_SUCCESS],
+                               EVENT_ALL_ACCESS, 0, 0);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status);
+        ConSrvFreeHandlesTable(ProcessData);
+        ProcessData->ConsoleHandle = NULL;
+        goto Quit;
+    }
+
+    Status = NtDuplicateObject(NtCurrentProcess(),
+                               Console->InitEvents[INIT_FAILURE],
+                               ProcessData->Process->ProcessHandle,
+                               &ConsoleStartInfo->InitEvents[INIT_FAILURE],
+                               EVENT_ALL_ACCESS, 0, 0);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status);
+        NtDuplicateObject(ProcessData->Process->ProcessHandle,
+                          ConsoleStartInfo->InitEvents[INIT_SUCCESS],
+                          NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
+        ConSrvFreeHandlesTable(ProcessData);
+        ProcessData->ConsoleHandle = NULL;
+        goto Quit;
+    }
+
     /* Duplicate the Input Event */
     Status = NtDuplicateObject(NtCurrentProcess(),
                                Console->InputBuffer.ActiveEvent,
                                ProcessData->Process->ProcessHandle,
-                               &ProcessData->InputWaitHandle,
+                               &ConsoleStartInfo->InputWaitHandle,
                                EVENT_ALL_ACCESS, 0, 0);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
+        DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status);
+        NtDuplicateObject(ProcessData->Process->ProcessHandle,
+                          ConsoleStartInfo->InitEvents[INIT_FAILURE],
+                          NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
+        NtDuplicateObject(ProcessData->Process->ProcessHandle,
+                          ConsoleStartInfo->InitEvents[INIT_SUCCESS],
+                          NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
         ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table.
         ProcessData->ConsoleHandle = NULL;
         goto Quit;
     }
 
-    /* Insert the process into the processes list of the console */
+    /* Mark the process as having a console */
+    ProcessData->ConsoleApp = TRUE;
+    ProcessData->Process->Flags |= CsrProcessIsConsoleApp;
+
+    /* Return the console handle to the caller */
+    ConsoleStartInfo->ConsoleHandle = ProcessData->ConsoleHandle;
+
+    /*
+     * Insert the process into the processes list of the console,
+     * and set its foreground priority.
+     */
     InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
+    ConSrvSetProcessFocus(ProcessData->Process, Console->HasFocus);
 
     /* Add a reference count because the process is tied to the console */
     _InterlockedIncrement(&Console->ReferenceCount);
@@ -633,74 +731,78 @@ Quit:
     return Status;
 }
 
-VOID
+NTSTATUS
 ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
 {
     PCONSOLE Console;
+    PCONSOLE_PROCESS_DATA ConsoleLeaderProcess;
 
     DPRINT("ConSrvRemoveConsole\n");
 
-    // RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+    /* Mark the process as not having a console anymore */
+    ProcessData->ConsoleApp = FALSE;
+    ProcessData->Process->Flags &= ~CsrProcessIsConsoleApp;
 
     /* Validate and lock the console */
-    if (ConSrvValidateConsole(&Console,
-                              ProcessData->ConsoleHandle,
-                              CONSOLE_RUNNING, TRUE))
+    if (!ConSrvValidateConsole(&Console,
+                               ProcessData->ConsoleHandle,
+                               CONSOLE_RUNNING, TRUE))
     {
-        /* Retrieve the console leader process */
-        PCONSOLE_PROCESS_DATA ConsoleLeaderProcess = ConSrvGetConsoleLeaderProcess(Console);
+        // FIXME: Find another status code
+        return STATUS_UNSUCCESSFUL;
+    }
 
-        DPRINT("ConSrvRemoveConsole - Locking OK\n");
+    DPRINT("ConSrvRemoveConsole - Locking OK\n");
 
-        /* Close all console handles and free the handles table */
-        ConSrvFreeHandlesTable(ProcessData);
+    /* Retrieve the console leader process */
+    ConsoleLeaderProcess = ConSrvGetConsoleLeaderProcess(Console);
 
-        /* Detach the process from the console */
-        ProcessData->ConsoleHandle = NULL;
+    /* Close all console handles and free the handles table */
+    ConSrvFreeHandlesTable(ProcessData);
+
+    /* Detach the process from the console */
+    ProcessData->ConsoleHandle = NULL;
 
-        /* Remove the process from the console's list of processes */
-        RemoveEntryList(&ProcessData->ConsoleLink);
+    /* 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)
+    /* 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)
         {
-            /* 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)...
+             * ... reset the flag first (so that we avoid multiple notifications)
+             * and then send the last close notification.
              */
-            else if (ProcessData == ConsoleLeaderProcess)
-            {
-                /*
-                 * ... reset the flag first (so that we avoid multiple notifications)
-                 * and then send the last close notification.
-                 */
-                Console->NotifyLastClose = FALSE;
-                ConSrvConsoleCtrlEvent(CTRL_LAST_CLOSE_EVENT, Console->NotifiedLastCloseProcess);
-
-                /* Only now, reset the pointer */
-                Console->NotifiedLastCloseProcess = NULL;
-            }
+            Console->NotifyLastClose = FALSE;
+            ConSrvConsoleCtrlEvent(CTRL_LAST_CLOSE_EVENT, Console->NotifiedLastCloseProcess);
+
+            /* Only now, reset the pointer */
+            Console->NotifiedLastCloseProcess = NULL;
         }
+    }
 
-        /* Update the internal info of the terminal */
-        TermRefreshInternalInfo(Console);
+    /* Update the internal info of the terminal */
+    TermRefreshInternalInfo(Console);
 
-        /* Release the console */
-        DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount);
-        ConSrvReleaseConsole(Console, TRUE);
-        //CloseHandle(ProcessData->InputWaitHandle);
-        //ProcessData->InputWaitHandle = NULL;
-    }
+    /* Release the console */
+    DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount);
+    ConSrvReleaseConsole(Console, TRUE);
 
-    // RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+    return STATUS_SUCCESS;
 }
 
 
@@ -727,7 +829,7 @@ CSR_API(SrvOpenConsole)
     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Can't get console\n");
+        DPRINT1("Can't get console, status %lx\n", Status);
         return Status;
     }
 
@@ -786,7 +888,7 @@ CSR_API(SrvDuplicateHandle)
     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Can't get console\n");
+        DPRINT1("Can't get console, status %lx\n", Status);
         return Status;
     }
 
@@ -856,7 +958,7 @@ CSR_API(SrvGetHandleInformation)
     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Can't get console\n");
+        DPRINT1("Can't get console, status %lx\n", Status);
         return Status;
     }
 
@@ -904,7 +1006,7 @@ CSR_API(SrvSetHandleInformation)
     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Can't get console\n");
+        DPRINT1("Can't get console, status %lx\n", Status);
         return Status;
     }
 
@@ -950,7 +1052,7 @@ CSR_API(SrvCloseHandle)
     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Can't get console\n");
+        DPRINT1("Can't get console, status %lx\n", Status);
         return Status;
     }
 
@@ -975,7 +1077,7 @@ CSR_API(SrvVerifyConsoleIoHandle)
     Status = ConSrvGetConsole(ProcessData, &Console, TRUE);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Can't get console\n");
+        DPRINT1("Can't get console, status %lx\n", Status);
         return Status;
     }