From dd5a9c52316c8c36a9ebbb1cc81461be0a734edc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Wed, 2 Jan 2013 00:32:20 +0000 Subject: [PATCH] [CONSRV] - 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 | 9 +- win32ss/user/consrv/conoutput.c | 66 +++--- win32ss/user/consrv/console.c | 218 ++++++++++-------- win32ss/user/consrv/consrv.h | 26 ++- win32ss/user/consrv/handle.c | 378 ++++++++++++++++++++++++++++---- win32ss/user/consrv/init.c | 4 +- 6 files changed, 510 insertions(+), 191 deletions(-) diff --git a/win32ss/user/consrv/conio.h b/win32ss/user/consrv/conio.h index 5cd093ef815..9e342314b65 100644 --- a/win32ss/user/consrv/conio.h +++ b/win32ss/user/consrv/conio.h @@ -10,11 +10,6 @@ #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); diff --git a/win32ss/user/consrv/conoutput.c b/win32ss/user/consrv/conoutput.c index 50b311643c7..719a534037d 100644 --- a/win32ss/user/consrv/conoutput.c +++ b/win32ss/user/consrv/conoutput.c @@ -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; diff --git a/win32ss/user/consrv/console.c b/win32ss/user/consrv/console.c index cdceb987752..7c4a794606c 100644 --- a/win32ss/user/consrv/console.c +++ b/win32ss/user/consrv/console.c @@ -12,7 +12,7 @@ #include "guiconsole.h" #include "tuiconsole.h" -#define NDEBUG +//#define NDEBUG #include /* 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) { diff --git a/win32ss/user/consrv/consrv.h b/win32ss/user/consrv/consrv.h index fa40a28de63..ed5a18ea496 100644 --- a/win32ss/user/consrv/consrv.h +++ b/win32ss/user/consrv/consrv.h @@ -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); diff --git a/win32ss/user/consrv/handle.c b/win32ss/user/consrv/handle.c index 3ed772978c7..6a92235ed75 100644 --- a/win32ss/user/consrv/handle.c +++ b/win32ss/user/consrv/handle.c @@ -11,7 +11,7 @@ #include "consrv.h" #include "conio.h" -#define NDEBUG +//#define NDEBUG #include @@ -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 */ diff --git a/win32ss/user/consrv/init.c b/win32ss/user/consrv/init.c index 0c7cc1c9e25..82233cde4f2 100644 --- a/win32ss/user/consrv/init.c +++ b/win32ss/user/consrv/init.c @@ -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; -- 2.17.1