[CONSRV]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Wed, 2 Jan 2013 00:32:20 +0000 (00:32 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Wed, 2 Jan 2013 00:32:20 +0000 (00:32 +0000)
- Fix console apps initialization.
- Add some debug output (NOTE TO MYSELF: remove them when all things work).
- Rewrite ConsoleNewProcess.
- Reorganize SrvAllocConsole and create ConsoleConnect based on SrvAllocConsole.
- Create ConsoleDisconnect which undoes what ConsoleConnect and ConsoleNewProcess did.
- Rework a little bit CsrInitConsole.

Now the console app. initialization algorithm is the following:

1- A process is created, its type (GUI or CUI) is determined (kernel32 and basesrv).
2- ConsoleNewProcess is called (consrv) and makes this new process inherit the console handles table from its parent
   (NOTE: this is done for all CUI processes, because at this point, we still don't know whether we must inherit
   the handles from the parent or not).
3- (back in kernel32) In BasepInitConsole, we determine whether or not we must create a new console window or use
   the parent's one or not using one at all. We (as a client) connect to the console server (consrv) (via CsrClientConnectToServer)
   which in turn (via CSRSS mechanism) calls ConsoleConnect. For GUI processes we do nothing. For CUI processes, we initialize
   a new console based on properties set in BasepInitConsole.
4- When a process dies, ConsoleDisconnect is called and whether it is a GUI or CUI process, we revert the actions done previously.

Part 2/2

TODO: - Debug the CSR waits.
      - Work on the console properties property-sheet.
      - See what can be done on http://jira.reactos.org/browse/CORE-122

svn path=/branches/ros-csrss/; revision=58098

win32ss/user/consrv/conio.h
win32ss/user/consrv/conoutput.c
win32ss/user/consrv/console.c
win32ss/user/consrv/consrv.h
win32ss/user/consrv/handle.c
win32ss/user/consrv/init.c

index 5cd093e..9e34231 100644 (file)
 
 #define CSR_DEFAULT_CURSOR_SIZE 25
 
-/* Object type magic numbers */
-
-#define CONIO_CONSOLE_MAGIC         0x00000001
-#define CONIO_SCREEN_BUFFER_MAGIC   0x00000002
-
 /************************************************************************
  * Screen buffer structure represents the win32 screen buffer object.   *
  * Internally, the portion of the buffer being shown CAN loop past the  *
@@ -29,7 +24,7 @@
  * being printed causes another line to scroll down, that the buffer IS *
  * memcpy()'s up, and the bottom of the buffer is still displayed, but  *
  * internally, I just wrap back to the top of the buffer.               *
- ***********************************************************************/
+ ************************************************************************/
 
 typedef struct tagCSRSS_SCREEN_BUFFER
 {
@@ -149,7 +144,7 @@ typedef struct ConsoleInput_t
 /* console.c */
 NTSTATUS FASTCALL ConioConsoleFromProcessData(PCONSOLE_PROCESS_DATA ProcessData,
                                               PCSRSS_CONSOLE *Console);
-VOID WINAPI ConioDeleteConsole(Object_t *Object);
+VOID WINAPI ConioDeleteConsole(PCSRSS_CONSOLE Console);
 VOID WINAPI CsrInitConsoleSupport(VOID);
 VOID FASTCALL ConioPause(PCSRSS_CONSOLE Console, UINT Flags);
 VOID FASTCALL ConioUnpause(PCSRSS_CONSOLE Console, UINT Flags);
index 50b3116..719a534 100644 (file)
@@ -489,58 +489,60 @@ DoWriteConsole(IN PCSR_API_MESSAGE ApiMessage,
                                NULL,
                                NULL))
             {
+                /* Fail */
                 ConioUnlockScreenBuffer(Buff);
                 return STATUS_NO_MEMORY;
             }
         }
 
         /* Wait until we un-pause the console */
-        ConioUnlockScreenBuffer(Buff);
-        return STATUS_PENDING;
+        Status = STATUS_PENDING;
     }
-
-    if(WriteConsoleRequest->Unicode)
+    else
     {
-        Length = WideCharToMultiByte(Console->OutputCodePage, 0,
-                                     (PWCHAR)WriteConsoleRequest->Buffer,
-                                     WriteConsoleRequest->NrCharactersToWrite,
-                                     NULL, 0, NULL, NULL);
-        Buffer = RtlAllocateHeap(GetProcessHeap(), 0, Length);
-        if (Buffer)
+        if(WriteConsoleRequest->Unicode)
         {
-            WideCharToMultiByte(Console->OutputCodePage, 0,
-                                (PWCHAR)WriteConsoleRequest->Buffer,
-                                WriteConsoleRequest->NrCharactersToWrite,
-                                Buffer, Length, NULL, NULL);
+            Length = WideCharToMultiByte(Console->OutputCodePage, 0,
+                                         (PWCHAR)WriteConsoleRequest->Buffer,
+                                         WriteConsoleRequest->NrCharactersToWrite,
+                                         NULL, 0, NULL, NULL);
+            Buffer = RtlAllocateHeap(GetProcessHeap(), 0, Length);
+            if (Buffer)
+            {
+                WideCharToMultiByte(Console->OutputCodePage, 0,
+                                    (PWCHAR)WriteConsoleRequest->Buffer,
+                                    WriteConsoleRequest->NrCharactersToWrite,
+                                    Buffer, Length, NULL, NULL);
+            }
+            else
+            {
+                Status = STATUS_NO_MEMORY;
+            }
         }
         else
         {
-            Status = STATUS_NO_MEMORY;
+            Buffer = (PCHAR)WriteConsoleRequest->Buffer;
         }
-    }
-    else
-    {
-        Buffer = (PCHAR)WriteConsoleRequest->Buffer;
-    }
 
-    if (Buffer)
-    {
-        if (NT_SUCCESS(Status))
+        if (Buffer)
         {
-            Status = ConioWriteConsole(Console, Buff, Buffer,
-                                       WriteConsoleRequest->NrCharactersToWrite, TRUE);
             if (NT_SUCCESS(Status))
             {
-                Written = WriteConsoleRequest->NrCharactersToWrite;
+                Status = ConioWriteConsole(Console, Buff, Buffer,
+                                           WriteConsoleRequest->NrCharactersToWrite, TRUE);
+                if (NT_SUCCESS(Status))
+                {
+                    Written = WriteConsoleRequest->NrCharactersToWrite;
+                }
+            }
+            if (WriteConsoleRequest->Unicode)
+            {
+                RtlFreeHeap(GetProcessHeap(), 0, Buffer);
             }
         }
-        if (WriteConsoleRequest->Unicode)
-        {
-            RtlFreeHeap(GetProcessHeap(), 0, Buffer);
-        }
-    }
 
-    WriteConsoleRequest->NrCharactersWritten = Written;
+        WriteConsoleRequest->NrCharactersWritten = Written;
+    }
 
     ConioUnlockScreenBuffer(Buff);
     return Status;
index cdceb98..7c4a794 100644 (file)
@@ -12,7 +12,7 @@
 #include "guiconsole.h"
 #include "tuiconsole.h"
 
-#define NDEBUG
+//#define NDEBUG
 #include <debug.h>
 
 /* FUNCTIONS *****************************************************************/
@@ -75,6 +75,7 @@ ConioConsoleCtrlEventTimeout(DWORD Event,
             return;
         }
 
+        DPRINT1("We succeeded at creating ProcessData->CtrlDispatcher remote thread, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
         WaitForSingleObject(Thread, Timeout);
         CloseHandle(Thread);
     }
@@ -86,15 +87,29 @@ ConioConsoleCtrlEvent(DWORD Event, PCONSOLE_PROCESS_DATA ProcessData)
     ConioConsoleCtrlEventTimeout(Event, ProcessData, 0);
 }
 
-static NTSTATUS WINAPI
-CsrInitConsole(PCSRSS_CONSOLE Console, int ShowCmd)
+/* static */ NTSTATUS WINAPI
+CsrInitConsole(PCSRSS_CONSOLE* NewConsole, int ShowCmd)
 {
     NTSTATUS Status;
     SECURITY_ATTRIBUTES SecurityAttributes;
+    PCSRSS_CONSOLE Console;
     PCSRSS_SCREEN_BUFFER NewBuffer;
     BOOL GuiMode;
     WCHAR Title[255];
 
+    if (NewConsole == NULL) return STATUS_INVALID_PARAMETER;
+
+    *NewConsole = NULL;
+
+    /* Allocate a console structure */
+    Console = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_CONSOLE));
+    if (NULL == Console)
+    {
+        DPRINT1("Not enough memory for console creation.\n");
+        return STATUS_NO_MEMORY;
+    }
+
+    /* Initialize the console */
     Console->Title.MaximumLength = Console->Title.Length = 0;
     Console->Title.Buffer = NULL;
 
@@ -112,6 +127,7 @@ CsrInitConsole(PCSRSS_CONSOLE Console, int ShowCmd)
     Console->Header.Type = CONIO_CONSOLE_MAGIC;
     Console->Header.Console = Console;
     Console->Mode = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT;
+    InitializeListHead(&Console->ProcessList);
     InitializeListHead(&Console->BufferList);
     Console->ActiveBuffer = NULL;
     InitializeListHead(&Console->ReadWaitQueue);
@@ -129,6 +145,7 @@ CsrInitConsole(PCSRSS_CONSOLE Console, int ShowCmd)
     if (NULL == Console->ActiveEvent)
     {
         RtlFreeUnicodeString(&Console->Title);
+        HeapFree(ConSrvHeap, 0, Console);
         return STATUS_UNSUCCESSFUL;
     }
     Console->PrivateData = NULL;
@@ -143,6 +160,7 @@ CsrInitConsole(PCSRSS_CONSOLE Console, int ShowCmd)
         RtlFreeUnicodeString(&Console->Title);
         DeleteCriticalSection(&Console->Lock);
         CloseHandle(Console->ActiveEvent);
+        HeapFree(ConSrvHeap, 0, Console);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
     /* init screen buffer with defaults */
@@ -186,6 +204,7 @@ CsrInitConsole(PCSRSS_CONSOLE Console, int ShowCmd)
             DeleteCriticalSection(&Console->Lock);
             CloseHandle(Console->ActiveEvent);
             DPRINT1("GuiInitConsole: failed, Status = 0x%08lx\n", Status);
+            HeapFree(ConSrvHeap, 0, Console);
             return Status;
         }
     }
@@ -199,12 +218,15 @@ CsrInitConsole(PCSRSS_CONSOLE Console, int ShowCmd)
         CloseHandle(Console->ActiveEvent);
         HeapFree(ConSrvHeap, 0, NewBuffer);
         DPRINT1("CsrInitConsoleScreenBuffer: failed\n");
+        HeapFree(ConSrvHeap, 0, Console);
         return Status;
     }
 
-    /* copy buffer contents to screen */
+    /* Copy buffer contents to screen */
     ConioDrawConsole(Console);
 
+    *NewConsole = Console;
+
     return STATUS_SUCCESS;
 }
 
@@ -271,109 +293,116 @@ CSR_API(SrvAllocConsole)
     NTSTATUS Status = STATUS_SUCCESS;
     PCSRSS_ALLOC_CONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest;
     PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
-    PCSRSS_CONSOLE Console;
-    BOOLEAN NewConsole = FALSE;
 
     DPRINT("SrvAllocConsole\n");
 
-    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
-
-    if (ProcessData->Console)
+    if (ProcessData->Console != NULL)
     {
         DPRINT1("Process already has a console\n");
-        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
         return STATUS_INVALID_PARAMETER;
     }
 
+    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+
     DPRINT1("SrvAllocConsole - Checkpoint 1\n");
 
-    /* If we don't need a console, then get out of here */
-    if (!AllocConsoleRequest->ConsoleNeeded)
+    /* Initialize a new Console */
+    Status = CsrInitConsole(&ProcessData->Console, AllocConsoleRequest->ShowCmd);
+    if (!NT_SUCCESS(Status))
     {
-        DPRINT("No console needed\n");
+        DPRINT1("Console initialization failed\n");
         RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-        return STATUS_SUCCESS;
+        return Status;
     }
 
-    /* If we already have one, then don't create a new one... */
-    if (!AllocConsoleRequest->Console ||
-         AllocConsoleRequest->Console != ProcessData->ParentConsole)
-    {
-        /* Allocate a console structure */
-        NewConsole = TRUE;
-        Console = HeapAlloc(ConSrvHeap, HEAP_ZERO_MEMORY, sizeof(CSRSS_CONSOLE));
-        if (NULL == Console)
-        {
-            DPRINT1("Not enough memory for console\n");
-            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-            return STATUS_NO_MEMORY;
-        }
+    /* Insert the process into the processes list of the console */
+    InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
 
-        /* Initialize list head */
-        InitializeListHead(&Console->ProcessList);
+    /* Return it to the caller */
+    AllocConsoleRequest->Console = ProcessData->Console;
 
-        /* Insert process data required for GUI initialization */
-        InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
+    /* Add a reference count because the process is tied to the console */
+    _InterlockedIncrement(&ProcessData->Console->ReferenceCount);
 
-        /* Initialize the Console */
-        Status = CsrInitConsole(Console, AllocConsoleRequest->ShowCmd);
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT1("Console init failed\n");
-            HeapFree(ConSrvHeap, 0, Console);
-            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-            return Status;
-        }
-    }
-    else
+#if 0000
+    /*
+     * We've just created a new console. However when ConsoleNewProcess was
+     * called, we didn't know that we wanted to create a new console and
+     * therefore, we by default inherited the handles table from our parent
+     * process. It's only now that we notice that in fact we do not need
+     * them, because we've created a new console and thus we must use it.
+     *
+     * Therefore, free our handles table and recreate a new one.
+     */
+
+    ULONG i;
+
+    /* Close all console handles and free the handle table memory */
+    for (i = 0; i < ProcessData->HandleTableSize; i++)
     {
-        /* Reuse our current console */
-        Console = AllocConsoleRequest->Console;
+        Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
     }
+    ProcessData->HandleTableSize = 0;
+    RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
+    ProcessData->HandleTable = NULL;
+#endif
 
-    /* Set the Process Console */
-    ProcessData->Console = Console;
+    /*
+     * Create a new handle table - Insert the IO handles
+     */
 
-    /* Return it to the caller */
-    AllocConsoleRequest->Console = Console;
+    /* Insert the Input handle */
+    Status = Win32CsrInsertObject(ProcessData,
+                                  &AllocConsoleRequest->InputHandle,
+                                  &ProcessData->Console->Header,
+                                  GENERIC_READ | GENERIC_WRITE,
+                                  TRUE,
+                                  FILE_SHARE_READ | FILE_SHARE_WRITE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to insert the input handle\n");
+        ConioDeleteConsole(ProcessData->Console);
+        ProcessData->Console = NULL;
+        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+        return Status;
+    }
 
-    /* Add a reference count because the process is tied to the console */
-    _InterlockedIncrement(&Console->ReferenceCount);
-
-    if (NewConsole || !ProcessData->bInheritHandles)
-    {
-        /* Insert the Objects */
-        Status = Win32CsrInsertObject(ProcessData,
-                                      &AllocConsoleRequest->InputHandle,
-                                      &Console->Header,
-                                      GENERIC_READ | GENERIC_WRITE,
-                                      TRUE,
-                                      FILE_SHARE_READ | FILE_SHARE_WRITE);
-        if (! NT_SUCCESS(Status))
-        {
-            DPRINT1("Failed to insert object\n");
-            ConioDeleteConsole((Object_t *) Console);
-            ProcessData->Console = NULL;
-            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-            return Status;
-        }
+    /* Insert the Output handle */
+    Status = Win32CsrInsertObject(ProcessData,
+                                  &AllocConsoleRequest->OutputHandle,
+                                  &ProcessData->Console->ActiveBuffer->Header,
+                                  GENERIC_READ | GENERIC_WRITE,
+                                  TRUE,
+                                  FILE_SHARE_READ | FILE_SHARE_WRITE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to insert the output handle\n");
+        ConioDeleteConsole(ProcessData->Console);
+        Win32CsrReleaseObject(ProcessData,
+                              AllocConsoleRequest->InputHandle);
+        ProcessData->Console = NULL;
+        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+        return Status;
+    }
 
-        Status = Win32CsrInsertObject(ProcessData,
-                                      &AllocConsoleRequest->OutputHandle,
-                                      &Console->ActiveBuffer->Header,
-                                      GENERIC_READ | GENERIC_WRITE,
-                                      TRUE,
-                                      FILE_SHARE_READ | FILE_SHARE_WRITE);
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT1("Failed to insert object\n");
-            ConioDeleteConsole((Object_t *) Console);
-            Win32CsrReleaseObject(ProcessData,
-                                  AllocConsoleRequest->InputHandle);
-            ProcessData->Console = NULL;
-            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-            return Status;
-        }
+    /* Insert the Error handle */
+    Status = Win32CsrInsertObject(ProcessData,
+                                  &AllocConsoleRequest->ErrorHandle,
+                                  &ProcessData->Console->ActiveBuffer->Header,
+                                  GENERIC_READ | GENERIC_WRITE,
+                                  TRUE,
+                                  FILE_SHARE_READ | FILE_SHARE_WRITE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to insert the error handle\n");
+        ConioDeleteConsole(ProcessData->Console);
+        Win32CsrReleaseObject(ProcessData,
+                              AllocConsoleRequest->OutputHandle);
+        Win32CsrReleaseObject(ProcessData,
+                              AllocConsoleRequest->InputHandle);
+        ProcessData->Console = NULL;
+        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+        return Status;
     }
 
     /* Duplicate the Event */
@@ -385,9 +414,11 @@ CSR_API(SrvAllocConsole)
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
-        ConioDeleteConsole((Object_t *) Console);
-        if (NewConsole || !ProcessData->bInheritHandles)
+        ConioDeleteConsole(ProcessData->Console);
+        // if (NewConsole /* || !ProcessData->bInheritHandles */)
         {
+            Win32CsrReleaseObject(ProcessData,
+                                  AllocConsoleRequest->ErrorHandle);
             Win32CsrReleaseObject(ProcessData,
                                   AllocConsoleRequest->OutputHandle);
             Win32CsrReleaseObject(ProcessData,
@@ -397,38 +428,31 @@ CSR_API(SrvAllocConsole)
         RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
         return Status;
     }
+    /* Input Wait Handle */
+    AllocConsoleRequest->InputWaitHandle = ProcessData->ConsoleEvent;
 
     /* Set the Ctrl Dispatcher */
     ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
     DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
 
-    if (!NewConsole)
-    {
-        /* Insert into the list if it has not been added */
-        InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
-    }
-
     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
     return STATUS_SUCCESS;
 }
 
 CSR_API(SrvFreeConsole)
 {
+    DPRINT1("SrvFreeConsole\n");
     Win32CsrReleaseConsole(CsrGetClientThread()->Process);
     return STATUS_SUCCESS;
 }
 
 VOID WINAPI
-ConioDeleteConsole(Object_t *Object)
+ConioDeleteConsole(PCSRSS_CONSOLE Console)
 {
-    PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Object;
     ConsoleInput *Event;
 
     DPRINT("ConioDeleteConsole\n");
 
-    /* TODO: Dereference all the waits in Console->ReadWaitQueue */
-    /* TODO: Dereference all the waits in Console->WriteWaitQueue */
-
     /* Drain input event queue */
     while (Console->InputEvents.Flink != &Console->InputEvents)
     {
index fa40a28..ed5a18e 100644 (file)
@@ -35,6 +35,9 @@ extern HANDLE ConSrvHeap;
 // extern HANDLE BaseSrvSharedHeap;
 // extern PBASE_STATIC_SERVER_DATA BaseStaticServerData;
 
+/* Object type magic numbers */
+#define CONIO_CONSOLE_MAGIC         0x00000001  // -->  Input-type handles
+#define CONIO_SCREEN_BUFFER_MAGIC   0x00000002  // --> Output-type handles
 
 /* Common things to input/output/console objects */
 typedef struct Object_tt
@@ -62,14 +65,17 @@ typedef struct _CSRSS_HANDLE
 typedef struct _CONSOLE_PROCESS_DATA
 {
     LIST_ENTRY ConsoleLink;
-    PCSR_PROCESS Process;   // Parent process.
+    PCSR_PROCESS Process;   // Process owning this structure.
     HANDLE ConsoleEvent;
     /* PCSRSS_CONSOLE */ struct tagCSRSS_CONSOLE* Console;
     /* PCSRSS_CONSOLE */ struct tagCSRSS_CONSOLE* ParentConsole;
-    BOOL bInheritHandles;
+
+    // BOOL bInheritHandles;
+    BOOL ConsoleApp;    // TRUE if it is a CUI app, FALSE otherwise.
+
     RTL_CRITICAL_SECTION HandleTableLock;
     ULONG HandleTableSize;
-    /* PCSRSS_HANDLE */ struct _CSRSS_HANDLE* HandleTable; // Is it a length-varying table or length-fixed ??
+    PCSRSS_HANDLE HandleTable; // Length-varying table
     LPTHREAD_START_ROUTINE CtrlDispatcher;
 } CONSOLE_PROCESS_DATA, *PCONSOLE_PROCESS_DATA;
 
@@ -128,11 +134,7 @@ CSR_API(SrvGetConsoleSelectionInfo);
 CSR_API(SrvCloseHandle);
 CSR_API(SrvVerifyConsoleIoHandle);
 CSR_API(SrvDuplicateHandle);
-CSR_API(CsrGetInputWaitHandle);
-
-NTSTATUS NTAPI ConsoleNewProcess(PCSR_PROCESS SourceProcess,
-                                 PCSR_PROCESS TargetProcess);
-VOID NTAPI Win32CsrReleaseConsole(PCSR_PROCESS Process);
+/// CSR_API(CsrGetInputWaitHandle);
 
 NTSTATUS FASTCALL Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
                                        PHANDLE Handle,
@@ -149,6 +151,14 @@ VOID FASTCALL Win32CsrUnlockObject(Object_t *Object);
 NTSTATUS FASTCALL Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData,
                                         HANDLE Handle);
 
+NTSTATUS NTAPI ConsoleNewProcess(PCSR_PROCESS SourceProcess,
+                                 PCSR_PROCESS TargetProcess);
+NTSTATUS NTAPI ConsoleConnect(IN PCSR_PROCESS CsrProcess,
+                              IN OUT PVOID ConnectionInfo,
+                              IN OUT PULONG ConnectionInfoLength);
+VOID NTAPI ConsoleDisconnect(PCSR_PROCESS Process);
+VOID NTAPI Win32CsrReleaseConsole(PCSR_PROCESS Process);
+
 /* lineinput.c */
 CSR_API(SrvGetConsoleCommandHistoryLength);
 CSR_API(SrvGetConsoleCommandHistory);
index 3ed7729..6a92235 100644 (file)
@@ -11,7 +11,7 @@
 #include "consrv.h"
 #include "conio.h"
 
-#define NDEBUG
+//#define NDEBUG
 #include <debug.h>
 
 
@@ -21,11 +21,16 @@ static INT
 AdjustHandleCounts(PCSRSS_HANDLE Entry, INT Change)
 {
     Object_t *Object = Entry->Object;
+
+    DPRINT1("AdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->HandleCount = %d, Object->Type = %lu\n", Entry, Change, Object, Object->HandleCount, Object->Type);
+
     if (Entry->Access & GENERIC_READ)           Object->AccessRead += Change;
     if (Entry->Access & GENERIC_WRITE)          Object->AccessWrite += Change;
     if (!(Entry->ShareMode & FILE_SHARE_READ))  Object->ExclusiveRead += Change;
     if (!(Entry->ShareMode & FILE_SHARE_WRITE)) Object->ExclusiveWrite += Change;
+
     Object->HandleCount += Change;
+
     return Object->HandleCount;
 }
 
@@ -46,17 +51,26 @@ Win32CsrCloseHandleEntry(PCSRSS_HANDLE Entry)
     {
         PCSRSS_CONSOLE Console = Object->Console;
         EnterCriticalSection(&Console->Lock);
-        /* If the last handle to a screen buffer is closed, delete it */
-        if (AdjustHandleCounts(Entry, -1) == 0
-            && Object->Type == CONIO_SCREEN_BUFFER_MAGIC)
+
+        /* If the last handle to a screen buffer is closed, delete it... */
+        if (AdjustHandleCounts(Entry, -1) == 0)
         {
-            PCSRSS_SCREEN_BUFFER Buffer = (PCSRSS_SCREEN_BUFFER)Object;
-            /* ...unless it's the only buffer left. Windows allows deletion
-             * 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);
+            if (Object->Type == CONIO_SCREEN_BUFFER_MAGIC)
+            {
+                PCSRSS_SCREEN_BUFFER Buffer = (PCSRSS_SCREEN_BUFFER)Object;
+                /* ...unless it's the only buffer left. Windows allows deletion
+                 * 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);
+            }
+            else if (Object->Type == CONIO_CONSOLE_MAGIC)
+            {
+                /* TODO: FIXME: Destroy here the console ?? */
+                // ConioDeleteConsole(Console);
+            }
         }
+
         LeaveCriticalSection(&Console->Lock);
         Entry->Object = NULL;
     }
@@ -94,7 +108,7 @@ Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
         if (Block == NULL)
         {
             RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-            return(STATUS_UNSUCCESSFUL);
+            return STATUS_UNSUCCESSFUL;
         }
         RtlCopyMemory(Block,
                       ProcessData->HandleTable,
@@ -129,6 +143,8 @@ Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData,
         RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
         return STATUS_INVALID_HANDLE;
     }
+
+    DPRINT1("Win32CsrReleaseObject - Process 0x%p, Release 0x%p\n", ProcessData->Process, &ProcessData->HandleTable[h]);
     Win32CsrCloseHandleEntry(&ProcessData->HandleTable[h]);
 
     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
@@ -169,24 +185,43 @@ Win32CsrLockObject(PCONSOLE_PROCESS_DATA ProcessData,
     return STATUS_SUCCESS;
 }
 
+VOID FASTCALL
+Win32CsrUnlockConsole(PCSRSS_CONSOLE Console)
+{
+    LeaveCriticalSection(&Console->Lock);
+
+    /* Decrement reference count */
+    if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
+        ConioDeleteConsole(Console);
+}
+
 VOID
 FASTCALL
 Win32CsrUnlockObject(Object_t *Object)
 {
-    PCSRSS_CONSOLE Console = Object->Console;
-    LeaveCriticalSection(&Console->Lock);
-    /* dec ref count */
-    if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
-        ConioDeleteConsole(&Console->Header);
+    Win32CsrUnlockConsole(Object->Console);
 }
 
 
 
+/** Remark: this function can be called by SrvAttachConsole (not yet implemented) **/
 NTSTATUS
 NTAPI
 ConsoleNewProcess(PCSR_PROCESS SourceProcess,
                   PCSR_PROCESS TargetProcess)
 {
+    /**************************************************************************
+     * This function is called whenever a new process (GUI or CUI) is created.
+     *
+     * Copy the parent's handles table here if both the parent and the child
+     * processes are CUI. If we must actually create our proper console (and
+     * thus do not inherit from the console handles of the parent's), then we
+     * will clean this table in the next ConsoleConnect call. Why we are doing
+     * this? It's because here, we still don't know whether or not we must create
+     * a new console instead of inherit it from the parent, and, because in
+     * ConsoleConnect we don't have any reference to the parent process anymore.
+     **************************************************************************/
+
     PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
     ULONG i;
 
@@ -200,9 +235,22 @@ ConsoleNewProcess(PCSR_PROCESS SourceProcess,
     DPRINT1("ConsoleNewProcess - OK\n");
 
     TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
+    DPRINT1("TargetProcessData = 0x%p\n", TargetProcessData);
+
+    /**** HACK !!!! ****/ RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData));
 
     /* Initialize the new (target) process */
     TargetProcessData->Process = TargetProcess;
+    TargetProcessData->ConsoleEvent = NULL;
+    TargetProcessData->Console = TargetProcessData->ParentConsole = NULL;
+    // TargetProcessData->bInheritHandles = FALSE;
+    TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE);
+
+    // Testing
+    TargetProcessData->HandleTableSize = 0;
+    TargetProcessData->HandleTable = NULL;
+
+    /* HACK */ RtlZeroMemory(&TargetProcessData->HandleTableLock, sizeof(RTL_CRITICAL_SECTION));
     RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
 
     /* Do nothing if the source process is NULL */
@@ -210,51 +258,256 @@ ConsoleNewProcess(PCSR_PROCESS SourceProcess,
         return STATUS_SUCCESS;
 
     SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
+    DPRINT1("SourceProcessData = 0x%p\n", SourceProcessData);
 
-    // TODO: Check if one of the processes is really a CONSOLE.
     /*
-    if (!(CreateProcessRequest->CreationFlags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)))
+     * If both of the processes (parent and new child) are console applications,
+     * then try to inherit handles from the parent process.
+     */
+    if ( SourceProcessData->Console != NULL && /* SourceProcessData->ConsoleApp */
+         TargetProcessData->ConsoleApp )
     {
-        // NewProcess == TargetProcess.
-        NewProcess->ParentConsole = Process->Console;
-        NewProcess->bInheritHandles = CreateProcessRequest->bInheritHandles;
-    }
-    */
+/*
+        if (TargetProcessData->HandleTableSize)
+        {
+            return STATUS_INVALID_PARAMETER;
+        }
+*/
+
+        DPRINT1("ConsoleNewProcess - Copy the handle table (1)\n");
+        /* Temporary "inherit" the console from the parent */
+        TargetProcessData->ParentConsole = SourceProcessData->Console;
+        RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
+        DPRINT1("ConsoleNewProcess - Copy the handle table (2)\n");
+
+        /* Allocate a new handle table for the child process */
+        TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap,
+                                                         HEAP_ZERO_MEMORY,
+                                                         SourceProcessData->HandleTableSize
+                                                                 * sizeof(CSRSS_HANDLE));
+        if (TargetProcessData->HandleTable == NULL)
+        {
+            RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
+            return STATUS_UNSUCCESSFUL;
+        }
+
+        TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
 
-    /* Only inherit if the if the flag was set */
-    if (!TargetProcessData->bInheritHandles) return STATUS_SUCCESS;
+        /*
+         * Parse the parent process' handles table and, for each handle,
+         * do a copy of it and reference it, if the handle is inheritable.
+         */
+        for (i = 0; i < SourceProcessData->HandleTableSize; i++)
+        {
+            if (SourceProcessData->HandleTable[i].Object != NULL &&
+                SourceProcessData->HandleTable[i].Inheritable)
+            {
+                /*
+                 * Copy the handle data and increment the reference count of the
+                 * pointed object (via the call to Win32CsrCreateHandleEntry).
+                 */
+                TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
+                Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]);
+            }
+        }
 
-    if (TargetProcessData->HandleTableSize)
+        RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
+    }
+    else
     {
-        return STATUS_INVALID_PARAMETER;
+        DPRINT1("ConsoleNewProcess - We don't launch a Console process : SourceProcessData->Console = 0x%p ; TargetProcess->Flags = %lu\n", SourceProcessData->Console, TargetProcess->Flags);
     }
 
-    RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
+    return STATUS_SUCCESS;
+}
+
+// Temporary ; move it to a header.
+NTSTATUS WINAPI CsrInitConsole(PCSRSS_CONSOLE* NewConsole, int ShowCmd);
 
-    TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap,
-                                                     HEAP_ZERO_MEMORY,
-                                                     SourceProcessData->HandleTableSize
-                                                             * sizeof(CSRSS_HANDLE));
-    if (TargetProcessData->HandleTable == NULL)
+NTSTATUS
+NTAPI
+ConsoleConnect(IN PCSR_PROCESS CsrProcess,
+               IN OUT PVOID ConnectionInfo,
+               IN OUT PULONG ConnectionInfoLength)
+{
+    /**************************************************************************
+     * This function is called whenever a CUI new process is created.
+     **************************************************************************/
+
+    NTSTATUS Status = STATUS_SUCCESS;
+    PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo;
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
+    BOOLEAN NewConsole = FALSE;
+    // PCSRSS_CONSOLE Console = NULL;
+
+    DPRINT1("ConsoleConnect\n");
+
+    if ( ConnectionInfo       == NULL ||
+         ConnectionInfoLength == NULL ||
+        *ConnectionInfoLength != sizeof(CONSOLE_CONNECTION_INFO) )
     {
-        RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
+        DPRINT1("CONSRV: Connection failed\n");
         return STATUS_UNSUCCESSFUL;
     }
 
-    TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
+    /* If we don't need a console, then get out of here */
+    if (!ConnectInfo->ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps.
+    {
+        DPRINT("ConsoleConnect - No console needed\n");
+        return STATUS_SUCCESS;
+    }
+
+    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+
+    /* If we don't have a console, then create a new one... */
+    if (!ConnectInfo->Console ||
+         ConnectInfo->Console != ProcessData->ParentConsole)
+    {
+        // PCSRSS_CONSOLE Console;
+
+        DPRINT1("ConsoleConnect - Allocate a new console\n");
+
+        /* Initialize a new Console */
+        NewConsole = TRUE;
+        Status = CsrInitConsole(&ProcessData->Console, ConnectInfo->ShowCmd);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Console initialization failed\n");
+            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+            return Status;
+        }
+    }
+    else /* We inherit it from the parent */
+    {
+        DPRINT1("ConsoleConnect - Reuse current (parent's) console\n");
+
+        /* Reuse our current console */
+        NewConsole = FALSE;
+        ProcessData->Console = ConnectInfo->Console;
+    }
+
+    /* Insert the process into the processes list of the console */
+    InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
+
+    /* Return it to the caller */
+    ConnectInfo->Console = ProcessData->Console;
+
+    /* Add a reference count because the process is tied to the console */
+    _InterlockedIncrement(&ProcessData->Console->ReferenceCount);
+
+    if (NewConsole /* || !ProcessData->bInheritHandles */)
+    {
+        /*
+         * We've just created a new console. However when ConsoleNewProcess was
+         * called, we didn't know that we wanted to create a new console and
+         * therefore, we by default inherited the handles table from our parent
+         * process. It's only now that we notice that in fact we do not need
+         * them, because we've created a new console and thus we must use it.
+         *
+         * Therefore, free our handles table and recreate a new one.
+         */
+
+        ULONG i;
+
+        /* Close all console handles and free the handle table memory */
+        for (i = 0; i < ProcessData->HandleTableSize; i++)
+        {
+            Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
+        }
+        ProcessData->HandleTableSize = 0;
+        RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
+        ProcessData->HandleTable = NULL;
+
+        /*
+         * Create a new handle table - Insert the IO handles
+         */
+
+        /* Insert the Input handle */
+        Status = Win32CsrInsertObject(ProcessData,
+                                      &ConnectInfo->InputHandle,
+                                      &ProcessData->Console->Header,
+                                      GENERIC_READ | GENERIC_WRITE,
+                                      TRUE,
+                                      FILE_SHARE_READ | FILE_SHARE_WRITE);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to insert the input handle\n");
+            ConioDeleteConsole(ProcessData->Console);
+            ProcessData->Console = NULL;
+            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+            return Status;
+        }
+
+        /* Insert the Output handle */
+        Status = Win32CsrInsertObject(ProcessData,
+                                      &ConnectInfo->OutputHandle,
+                                      &ProcessData->Console->ActiveBuffer->Header,
+                                      GENERIC_READ | GENERIC_WRITE,
+                                      TRUE,
+                                      FILE_SHARE_READ | FILE_SHARE_WRITE);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to insert the output handle\n");
+            ConioDeleteConsole(ProcessData->Console);
+            Win32CsrReleaseObject(ProcessData,
+                                  ConnectInfo->InputHandle);
+            ProcessData->Console = NULL;
+            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+            return Status;
+        }
+
+        /* Insert the Error handle */
+        Status = Win32CsrInsertObject(ProcessData,
+                                      &ConnectInfo->ErrorHandle,
+                                      &ProcessData->Console->ActiveBuffer->Header,
+                                      GENERIC_READ | GENERIC_WRITE,
+                                      TRUE,
+                                      FILE_SHARE_READ | FILE_SHARE_WRITE);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to insert the error handle\n");
+            ConioDeleteConsole(ProcessData->Console);
+            Win32CsrReleaseObject(ProcessData,
+                                  ConnectInfo->OutputHandle);
+            Win32CsrReleaseObject(ProcessData,
+                                  ConnectInfo->InputHandle);
+            ProcessData->Console = NULL;
+            RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+            return Status;
+        }
+    }
 
-    for (i = 0; i < SourceProcessData->HandleTableSize; i++)
+    /* Duplicate the Event */
+    Status = NtDuplicateObject(NtCurrentProcess(),
+                               ProcessData->Console->ActiveEvent,
+                               ProcessData->Process->ProcessHandle,
+                               &ProcessData->ConsoleEvent,
+                               EVENT_ALL_ACCESS, 0, 0);
+    if (!NT_SUCCESS(Status))
     {
-        if (SourceProcessData->HandleTable[i].Object != NULL &&
-            SourceProcessData->HandleTable[i].Inheritable)
+        DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
+        ConioDeleteConsole(ProcessData->Console);
+        if (NewConsole /* || !ProcessData->bInheritHandles */)
         {
-            TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
-            Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]);
+            Win32CsrReleaseObject(ProcessData,
+                                  ConnectInfo->ErrorHandle);
+            Win32CsrReleaseObject(ProcessData,
+                                  ConnectInfo->OutputHandle);
+            Win32CsrReleaseObject(ProcessData,
+                                  ConnectInfo->InputHandle);
         }
+        ProcessData->Console = NULL;
+        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+        return Status;
     }
+    /* Input Wait Handle */
+    ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent;
 
-    RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
+    /* Set the Ctrl Dispatcher */
+    ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher;
+    DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
 
+    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
     return STATUS_SUCCESS;
 }
 
@@ -266,30 +519,63 @@ Win32CsrReleaseConsole(PCSR_PROCESS Process)
     PCSRSS_CONSOLE Console;
     ULONG i;
 
-    /* Close all console handles and detach process from console */
+    DPRINT1("Win32CsrReleaseConsole\n");
+
     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
 
+    /* Close all console handles and free the handle table memory */
     for (i = 0; i < ProcessData->HandleTableSize; i++)
+    {
         Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
+    }
     ProcessData->HandleTableSize = 0;
     RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
     ProcessData->HandleTable = NULL;
 
+    /* Detach process from console */
     Console = ProcessData->Console;
     if (Console != NULL)
     {
+        DPRINT1("Win32CsrReleaseConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount);
         ProcessData->Console = NULL;
         EnterCriticalSection(&Console->Lock);
         RemoveEntryList(&ProcessData->ConsoleLink);
-        LeaveCriticalSection(&Console->Lock);
-        if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
-            ConioDeleteConsole(&Console->Header);
+        Win32CsrUnlockConsole(Console);
         //CloseHandle(ProcessData->ConsoleEvent);
         //ProcessData->ConsoleEvent = NULL;
     }
+
     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
 }
 
+VOID
+WINAPI
+ConsoleDisconnect(PCSR_PROCESS Process)
+{
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
+
+    /**************************************************************************
+     * This function is called whenever a new process (GUI or CUI) is destroyed.
+     *
+     * Only do something if the process is a CUI. <-- modify this behaviour if
+     *                                                we deal with a GUI which
+     *                                                quits and acquired a
+     *                                                console...
+     **************************************************************************/
+
+    DPRINT1("ConsoleDisconnect called\n");
+    // if (ProcessData->Console != NULL)
+    if (ProcessData->ConsoleApp)
+    {
+        DPRINT1("ConsoleDisconnect - calling Win32CsrReleaseConsole\n");
+        Win32CsrReleaseConsole(Process);
+    }
+
+    RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
+}
+
+
+
 CSR_API(SrvCloseHandle)
 {
     PCSRSS_CLOSE_HANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
@@ -374,6 +660,7 @@ CSR_API(SrvDuplicateHandle)
     return ApiMessage->Status;
 }
 
+/**
 CSR_API(CsrGetInputWaitHandle)
 {
     PCSRSS_GET_INPUT_WAIT_HANDLE GetConsoleInputWaitHandle = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetConsoleInputWaitHandle;
@@ -383,5 +670,6 @@ CSR_API(CsrGetInputWaitHandle)
 
     return STATUS_SUCCESS;
 }
+**/
 
 /* EOF */
index 0c7cc1c..82233cd 100644 (file)
@@ -460,8 +460,8 @@ CSR_SERVER_DLL_INIT(ConServerDllInitialization)
     LoadedServerDll->ValidTable = ConsoleServerApiServerValidTable;
     LoadedServerDll->NameTable = ConsoleServerApiNameTable;
     LoadedServerDll->SizeOfProcessData = sizeof(CONSOLE_PROCESS_DATA);
-    LoadedServerDll->ConnectCallback = NULL;
-    LoadedServerDll->DisconnectCallback = Win32CsrReleaseConsole;
+    LoadedServerDll->ConnectCallback = ConsoleConnect;
+    LoadedServerDll->DisconnectCallback = ConsoleDisconnect;
     LoadedServerDll->NewProcessCallback = ConsoleNewProcess;
     // LoadedServerDll->HardErrorCallback = Win32CsrHardError;