diff --git a/dll/win32/kernel32/client/console/console.c b/dll/win32/kernel32/client/console/console.c index d71f3226b49..a0c9ca652b1 100644 --- a/dll/win32/kernel32/client/console/console.c +++ b/dll/win32/kernel32/client/console/console.c @@ -802,8 +802,8 @@ AllocConsole(VOID) if (NtCurrentPeb()->ProcessParameters->ConsoleHandle) { - DPRINT("AllocConsole: Allocate duplicate console to the same Process\n"); - BaseSetLastNTError (STATUS_OBJECT_NAME_EXISTS); + DPRINT1("AllocConsole: Allocate duplicate console to the same Process\n"); + SetLastError(ERROR_ACCESS_DENIED); return FALSE; } @@ -824,7 +824,6 @@ AllocConsole(VOID) } NtCurrentPeb()->ProcessParameters->ConsoleHandle = AllocConsoleRequest->Console; - SetStdHandle(STD_INPUT_HANDLE , AllocConsoleRequest->InputHandle ); SetStdHandle(STD_OUTPUT_HANDLE, AllocConsoleRequest->OutputHandle); SetStdHandle(STD_ERROR_HANDLE , AllocConsoleRequest->ErrorHandle ); @@ -1910,13 +1909,50 @@ GetConsoleSelectionInfo(PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo) /*-------------------------------------------------------------- * AttachConsole * - * @unimplemented + * @implemented + * + * @note Strongly inspired by AllocConsole. */ BOOL WINAPI AttachConsole(DWORD dwProcessId) { - DPRINT1("AttachConsole(0x%x) UNIMPLEMENTED!\n", dwProcessId); + NTSTATUS Status; + CONSOLE_API_MESSAGE ApiMessage; + PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &ApiMessage.Data.AttachConsoleRequest; + + DPRINT1("AttachConsole(%lu)\n", dwProcessId); + + if (NtCurrentPeb()->ProcessParameters->ConsoleHandle) + { + DPRINT1("AttachConsole: Attaching a console to a process already having one\n"); + SetLastError(ERROR_ACCESS_DENIED); + return FALSE; + } + + AttachConsoleRequest->ProcessId = dwProcessId; + AttachConsoleRequest->CtrlDispatcher = ConsoleControlDispatcher; + + Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, + NULL, + CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepAttach), + sizeof(CONSOLE_ATTACHCONSOLE)); + if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = ApiMessage.Status)) + { + BaseSetLastNTError(Status); + return FALSE; + } + + NtCurrentPeb()->ProcessParameters->ConsoleHandle = AttachConsoleRequest->Console; + SetStdHandle(STD_INPUT_HANDLE , AttachConsoleRequest->InputHandle ); + SetStdHandle(STD_OUTPUT_HANDLE, AttachConsoleRequest->OutputHandle); + SetStdHandle(STD_ERROR_HANDLE , AttachConsoleRequest->ErrorHandle ); + + /* Initialize Console Ctrl Handler */ + InitConsoleCtrlHandling(); + + InputWaitHandle = AttachConsoleRequest->InputWaitHandle; + return TRUE; } diff --git a/include/reactos/subsys/win/conmsg.h b/include/reactos/subsys/win/conmsg.h index e6061b62837..d652975b227 100644 --- a/include/reactos/subsys/win/conmsg.h +++ b/include/reactos/subsys/win/conmsg.h @@ -102,7 +102,7 @@ typedef enum _CONSRV_API_NUMBER // ConsolepRegisterConsoleIME, // ConsolepUnregisterConsoleIME, // ConsolepGetLangId, - // ConsolepAttach, + ConsolepAttach, ConsolepGetSelectionInfo, ConsolepGetProcessList, ConsolepGetHistory, @@ -177,6 +177,17 @@ typedef struct LPTHREAD_START_ROUTINE CtrlDispatcher; } CONSOLE_ALLOCCONSOLE, *PCONSOLE_ALLOCCONSOLE; +typedef struct +{ + DWORD ProcessId; // If ProcessId == ATTACH_PARENT_PROCESS == -1, then attach the current process to its parent process console. + HANDLE Console; // ConsoleHandle // In fact, it is a PCSRSS_CONSOLE <-- correct that !! + HANDLE InputHandle; + HANDLE OutputHandle; + HANDLE ErrorHandle; + HANDLE InputWaitHandle; + LPTHREAD_START_ROUTINE CtrlDispatcher; +} CONSOLE_ATTACHCONSOLE, *PCONSOLE_ATTACHCONSOLE; + typedef struct { ULONG Dummy; @@ -543,6 +554,7 @@ typedef struct _CONSOLE_API_MESSAGE union { CONSOLE_ALLOCCONSOLE AllocConsoleRequest; + CONSOLE_ATTACHCONSOLE AttachConsoleRequest; CONSOLE_FREECONSOLE FreeConsoleRequest; /* Handles */ diff --git a/win32ss/user/consrv/console.c b/win32ss/user/consrv/console.c index 4eabc9db67c..6c90bc65da0 100644 --- a/win32ss/user/consrv/console.c +++ b/win32ss/user/consrv/console.c @@ -301,58 +301,52 @@ CSR_API(SrvAllocConsole) if (ProcessData->Console != NULL) { DPRINT1("Process already has a console\n"); - return STATUS_INVALID_PARAMETER; + return STATUS_ACCESS_DENIED; } - RtlEnterCriticalSection(&ProcessData->HandleTableLock); - +/******************************************************************************/ +/** This comes from ConsoleConnect!! **/ DPRINT1("SrvAllocConsole - Checkpoint 1\n"); +#if 0000 + /* + * We are about to create 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 the console we can have and our handles table, + * and recreate a new one later on. + */ + Win32CsrReleaseConsole(ProcessData); + // Win32CsrFreeHandlesTable(ProcessData); +#endif + /* Initialize a new Console owned by the Console Leader Process */ Status = CsrInitConsole(&ProcessData->Console, AllocConsoleRequest->ShowCmd, ConsoleLeader); if (!NT_SUCCESS(Status)) { DPRINT1("Console initialization failed\n"); - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return Status; } + /* Add a reference count because the process is tied to the console */ + _InterlockedIncrement(&ProcessData->Console->ReferenceCount); + /* Insert the process into the processes list of the console */ InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink); /* Return it to the caller */ AllocConsoleRequest->Console = ProcessData->Console; - /* Add a reference count because the process is tied to the console */ - _InterlockedIncrement(&ProcessData->Console->ReferenceCount); - -#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++) - { - Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]); - } - ProcessData->HandleTableSize = 0; - RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable); - ProcessData->HandleTable = NULL; -#endif /* * Create a new handle table - Insert the IO handles */ + RtlEnterCriticalSection(&ProcessData->HandleTableLock); + /* Insert the Input handle */ Status = Win32CsrInsertObject(ProcessData, &AllocConsoleRequest->InputHandle, @@ -363,9 +357,10 @@ CSR_API(SrvAllocConsole) if (!NT_SUCCESS(Status)) { DPRINT1("Failed to insert the input handle\n"); - ConioDeleteConsole(ProcessData->Console); - ProcessData->Console = NULL; RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + Win32CsrReleaseConsole(ProcessData); + // ConioDeleteConsole(ProcessData->Console); + // ProcessData->Console = NULL; return Status; } @@ -379,11 +374,12 @@ CSR_API(SrvAllocConsole) 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); + Win32CsrReleaseConsole(ProcessData); + // Win32CsrReleaseObject(ProcessData, + // AllocConsoleRequest->InputHandle); + // ConioDeleteConsole(ProcessData->Console); + // ProcessData->Console = NULL; return Status; } @@ -397,16 +393,19 @@ CSR_API(SrvAllocConsole) 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); + Win32CsrReleaseConsole(ProcessData); + // Win32CsrReleaseObject(ProcessData, + // AllocConsoleRequest->OutputHandle); + // Win32CsrReleaseObject(ProcessData, + // AllocConsoleRequest->InputHandle); + // ConioDeleteConsole(ProcessData->Console); + // ProcessData->Console = NULL; return Status; } + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + /* Duplicate the Event */ Status = NtDuplicateObject(NtCurrentProcess(), ProcessData->Console->ActiveEvent, @@ -416,18 +415,18 @@ CSR_API(SrvAllocConsole) if (!NT_SUCCESS(Status)) { DPRINT1("NtDuplicateObject() failed: %lu\n", Status); - ConioDeleteConsole(ProcessData->Console); - // if (NewConsole /* || !ProcessData->bInheritHandles */) - { - Win32CsrReleaseObject(ProcessData, - AllocConsoleRequest->ErrorHandle); - Win32CsrReleaseObject(ProcessData, - AllocConsoleRequest->OutputHandle); - Win32CsrReleaseObject(ProcessData, - AllocConsoleRequest->InputHandle); - } - ProcessData->Console = NULL; - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + Win32CsrReleaseConsole(ProcessData); + // if (NewConsole) + // { + // Win32CsrReleaseObject(ProcessData, + // AllocConsoleRequest->ErrorHandle); + // Win32CsrReleaseObject(ProcessData, + // AllocConsoleRequest->OutputHandle); + // Win32CsrReleaseObject(ProcessData, + // AllocConsoleRequest->InputHandle); + // } + // ConioDeleteConsole(ProcessData->Console); // FIXME: Just release the console ? + // ProcessData->Console = NULL; return Status; } /* Input Wait Handle */ @@ -436,15 +435,149 @@ CSR_API(SrvAllocConsole) /* Set the Ctrl Dispatcher */ ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher; DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher); +/******************************************************************************/ - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_SUCCESS; } +CSR_API(SrvAttachConsole) +{ + NTSTATUS Status = STATUS_SUCCESS; + PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AttachConsoleRequest; + PCSR_PROCESS SourceProcess = NULL; // The parent process. + PCSR_PROCESS TargetProcess = CsrGetClientThread()->Process; // Ourselves. + HANDLE ProcessId = ULongToHandle(AttachConsoleRequest->ProcessId); + PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData; + + DPRINT("SrvAttachConsole\n"); + + TargetProcessData = ConsoleGetPerProcessData(TargetProcess); + + if (TargetProcessData->Console != NULL) + { + DPRINT1("Process already has a console\n"); + return STATUS_ACCESS_DENIED; + } + + if (ProcessId == ULongToHandle(ATTACH_PARENT_PROCESS)) + { + PROCESS_BASIC_INFORMATION ProcessInfo; + ULONG Length = sizeof(ProcessInfo); + + /* Get the real parent's ID */ + + Status = NtQueryInformationProcess(TargetProcess->ProcessHandle, + ProcessBasicInformation, + &ProcessInfo, + Length, &Length); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status); + return Status; + } + + DPRINT("We, process (ID) %lu;%lu\n", TargetProcess->ClientId.UniqueProcess, TargetProcess->ClientId.UniqueThread); + ProcessId = ULongToHandle(ProcessInfo.InheritedFromUniqueProcessId); + DPRINT("Parent process ID = %lu\n", ProcessId); + } + + /* Lock the target process via its PID */ + DPRINT1("Lock process Id %lu\n", ProcessId); + Status = CsrLockProcessByClientId(ProcessId, &SourceProcess); + DPRINT1("Lock process Status %lu\n", Status); + if (!NT_SUCCESS(Status)) return Status; + DPRINT1("AttachConsole OK\n"); + +/******************************************************************************/ +/** This comes from ConsoleNewProcess!! **/ + SourceProcessData = ConsoleGetPerProcessData(SourceProcess); + + /* + * Inherit the console from the parent, + * if any, otherwise return an error. + */ + DPRINT1("SourceProcessData->Console = 0x%p\n", SourceProcessData->Console); + if (SourceProcessData->Console == NULL) + { + Status = STATUS_INVALID_HANDLE; + goto Quit; + } + TargetProcessData->Console = SourceProcessData->Console; + + DPRINT1("SrvAttachConsole - Copy the handle table (1)\n"); + Status = Win32CsrInheritHandlesTable(SourceProcessData, TargetProcessData); + DPRINT1("SrvAttachConsole - Copy the handle table (2)\n"); + if (!NT_SUCCESS(Status)) + { + goto Quit; + } + +/******************************************************************************/ + +/******************************************************************************/ +/** This comes from ConsoleConnect / SrvAllocConsole!! **/ + /* Add a reference count because the process is tied to the console */ + _InterlockedIncrement(&TargetProcessData->Console->ReferenceCount); + + /* Insert the process into the processes list of the console */ + InsertHeadList(&TargetProcessData->Console->ProcessList, &TargetProcessData->ConsoleLink); + + /* Return it to the caller */ + AttachConsoleRequest->Console = TargetProcessData->Console; + + /** Here, we inherited the console handles from the "source" process, + ** so no need to reinitialize the handles table. **/ + + DPRINT1("SrvAttachConsole - Checkpoint\n"); + + /* Duplicate the Event */ + Status = NtDuplicateObject(NtCurrentProcess(), + TargetProcessData->Console->ActiveEvent, + TargetProcessData->Process->ProcessHandle, + &TargetProcessData->ConsoleEvent, + EVENT_ALL_ACCESS, 0, 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtDuplicateObject() failed: %lu\n", Status); + Win32CsrReleaseConsole(TargetProcessData); +// #if 0 + // if (NewConsole) + // { + // Win32CsrReleaseObject(TargetProcessData, + // AttachConsoleRequest->ErrorHandle); + // Win32CsrReleaseObject(TargetProcessData, + // AttachConsoleRequest->OutputHandle); + // Win32CsrReleaseObject(TargetProcessData, + // AttachConsoleRequest->InputHandle); + // } +// #endif + // ConioDeleteConsole(TargetProcessData->Console); // FIXME: Just release the console ? + // TargetProcessData->Console = NULL; + goto Quit; + } + /* Input Wait Handle */ + AttachConsoleRequest->InputWaitHandle = TargetProcessData->ConsoleEvent; + + /* Set the Ctrl Dispatcher */ + TargetProcessData->CtrlDispatcher = AttachConsoleRequest->CtrlDispatcher; + DPRINT("CONSRV: CtrlDispatcher address: %x\n", TargetProcessData->CtrlDispatcher); + + Status = STATUS_SUCCESS; +/******************************************************************************/ + +Quit: + DPRINT1("SrvAttachConsole - exiting 1\n"); + /* Unlock the "source" process */ + CsrUnlockProcess(SourceProcess); + DPRINT1("SrvAttachConsole - exiting 2\n"); + + return Status; +} + CSR_API(SrvFreeConsole) { DPRINT1("SrvFreeConsole\n"); - Win32CsrReleaseConsole(CsrGetClientThread()->Process); + Win32CsrReleaseConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process)); return STATUS_SUCCESS; } diff --git a/win32ss/user/consrv/consrv.h b/win32ss/user/consrv/consrv.h index b4dbbdf441c..b60f4839cf6 100644 --- a/win32ss/user/consrv/consrv.h +++ b/win32ss/user/consrv/consrv.h @@ -73,7 +73,6 @@ typedef struct _CONSOLE_PROCESS_DATA /* PCONSOLE */ struct _CONSOLE* Console; /* PCONSOLE */ struct _CONSOLE* ParentConsole; - // BOOL bInheritHandles; BOOL ConsoleApp; // TRUE if it is a CUI app, FALSE otherwise. RTL_CRITICAL_SECTION HandleTableLock; @@ -118,6 +117,7 @@ CSR_API(SrvSetConsoleScreenBufferSize); /* console.c */ CSR_API(SrvOpenConsole); CSR_API(SrvAllocConsole); +CSR_API(SrvAttachConsole); CSR_API(SrvFreeConsole); CSR_API(SrvSetConsoleMode); CSR_API(SrvGetConsoleMode); @@ -139,6 +139,9 @@ CSR_API(SrvVerifyConsoleIoHandle); CSR_API(SrvDuplicateHandle); /// CSR_API(CsrGetInputWaitHandle); +NTSTATUS FASTCALL Win32CsrInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData, + IN PCONSOLE_PROCESS_DATA TargetProcessData); +VOID FASTCALL Win32CsrFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData); NTSTATUS FASTCALL Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData, PHANDLE Handle, Object_t *Object, @@ -153,6 +156,7 @@ NTSTATUS FASTCALL Win32CsrLockObject(PCONSOLE_PROCESS_DATA ProcessData, VOID FASTCALL Win32CsrUnlockObject(Object_t *Object); NTSTATUS FASTCALL Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData, HANDLE Handle); +VOID FASTCALL Win32CsrReleaseConsole(PCONSOLE_PROCESS_DATA ProcessData); NTSTATUS NTAPI ConsoleNewProcess(PCSR_PROCESS SourceProcess, PCSR_PROCESS TargetProcess); @@ -160,7 +164,6 @@ 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); diff --git a/win32ss/user/consrv/handle.c b/win32ss/user/consrv/handle.c index 7381713d443..eddb4b83eca 100644 --- a/win32ss/user/consrv/handle.c +++ b/win32ss/user/consrv/handle.c @@ -79,6 +79,85 @@ Win32CsrCloseHandleEntry(PCONSOLE_IO_HANDLE Entry) /* FUNCTIONS *****************************************************************/ +NTSTATUS +FASTCALL +Win32CsrInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData, + IN PCONSOLE_PROCESS_DATA TargetProcessData) +{ + NTSTATUS Status = STATUS_SUCCESS; + ULONG i; + + RtlEnterCriticalSection(&SourceProcessData->HandleTableLock); + + /* Inherit a handles table only if there is no already */ + if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */) + { + Status = STATUS_UNSUCCESSFUL; /* STATUS_INVALID_PARAMETER */ + goto Quit; + } + + /* Allocate a new handle table for the child process */ + TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap, + HEAP_ZERO_MEMORY, + SourceProcessData->HandleTableSize + * sizeof(CONSOLE_IO_HANDLE)); + if (TargetProcessData->HandleTable == NULL) + { + Status = STATUS_NO_MEMORY; + goto Quit; + } + + TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize; + + /* + * 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]); + } + } + +Quit: + RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock); + return Status; +} + +VOID +FASTCALL +Win32CsrFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData) +{ + DPRINT1("Win32CsrFreeHandlesTable\n"); + + RtlEnterCriticalSection(&ProcessData->HandleTableLock); + + if (ProcessData->HandleTable != NULL) + { + ULONG i; + + /* Close all console handles and free the handle table memory */ + for (i = 0; i < ProcessData->HandleTableSize; i++) + { + Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]); + } + RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable); + ProcessData->HandleTable = NULL; + } + + ProcessData->HandleTableSize = 0; + + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); +} + NTSTATUS FASTCALL Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData, @@ -122,7 +201,8 @@ Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData, ProcessData->HandleTable[i].Inheritable = Inheritable; ProcessData->HandleTable[i].ShareMode = ShareMode; Win32CsrCreateHandleEntry(&ProcessData->HandleTable[i]); - *Handle = UlongToHandle((i << 2) | 0x3); + *Handle = ULongToHandle((i << 2) | 0x3); + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_SUCCESS; } @@ -202,9 +282,33 @@ Win32CsrUnlockObject(Object_t *Object) Win32CsrUnlockConsole(Object->Console); } +VOID +FASTCALL +Win32CsrReleaseConsole(PCONSOLE_PROCESS_DATA ProcessData) +{ + PCONSOLE Console; + + DPRINT1("Win32CsrReleaseConsole\n"); + + /* Close all console handles and free the handle table memory */ + Win32CsrFreeHandlesTable(ProcessData); + + /* 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); + Win32CsrUnlockConsole(Console); + //CloseHandle(ProcessData->ConsoleEvent); + //ProcessData->ConsoleEvent = NULL; + } +} + -/** Remark: this function can be called by SrvAttachConsole (not yet implemented) **/ NTSTATUS NTAPI ConsoleNewProcess(PCSR_PROCESS SourceProcess, @@ -223,7 +327,6 @@ ConsoleNewProcess(PCSR_PROCESS SourceProcess, **************************************************************************/ PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData; - ULONG i; DPRINT1("ConsoleNewProcess inside\n"); DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess, TargetProcess); @@ -243,14 +346,13 @@ ConsoleNewProcess(PCSR_PROCESS SourceProcess, 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)); + /**** HACK !!!! ****/ RtlZeroMemory(&TargetProcessData->HandleTableLock, sizeof(RTL_CRITICAL_SECTION)); RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock); /* Do nothing if the source process is NULL */ @@ -267,51 +369,17 @@ ConsoleNewProcess(PCSR_PROCESS SourceProcess, if ( SourceProcessData->Console != NULL && /* SourceProcessData->ConsoleApp */ TargetProcessData->ConsoleApp ) { -/* - if (TargetProcessData->HandleTableSize) - { - return STATUS_INVALID_PARAMETER; - } -*/ + NTSTATUS Status; - DPRINT1("ConsoleNewProcess - Copy the handle table (1)\n"); + Status = Win32CsrInheritHandlesTable(SourceProcessData, TargetProcessData); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + // FIXME: Do it before, or after the handles table inheritance ?? /* 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(CONSOLE_IO_HANDLE)); - if (TargetProcessData->HandleTable == NULL) - { - RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock); - return STATUS_UNSUCCESSFUL; - } - - TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize; - - /* - * 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]); - } - } - - RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock); } else { @@ -335,7 +403,6 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess, PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess); BOOLEAN NewConsole = FALSE; - // PCONSOLE Console = NULL; DPRINT1("ConsoleConnect\n"); @@ -354,21 +421,30 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess, 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) { DPRINT1("ConsoleConnect - Allocate a new console\n"); + /* + * We are about to create 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 the console we can have and our handles table, + * and recreate a new one later on. + */ + Win32CsrReleaseConsole(ProcessData); + /* Initialize a new Console owned by the Console Leader Process */ NewConsole = TRUE; Status = CsrInitConsole(&ProcessData->Console, ConnectInfo->ShowCmd, CsrProcess); if (!NT_SUCCESS(Status)) { DPRINT1("Console initialization failed\n"); - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return Status; } } @@ -381,42 +457,23 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess, ProcessData->Console = ConnectInfo->Console; } + /* Add a reference count because the process is tied to the console */ + _InterlockedIncrement(&ProcessData->Console->ReferenceCount); + /* 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 */) + if (NewConsole) { - /* - * 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 */ + RtlEnterCriticalSection(&ProcessData->HandleTableLock); + /* Insert the Input handle */ Status = Win32CsrInsertObject(ProcessData, &ConnectInfo->InputHandle, @@ -427,9 +484,10 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess, if (!NT_SUCCESS(Status)) { DPRINT1("Failed to insert the input handle\n"); - ConioDeleteConsole(ProcessData->Console); - ProcessData->Console = NULL; RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + Win32CsrReleaseConsole(ProcessData); + // ConioDeleteConsole(ProcessData->Console); + // ProcessData->Console = NULL; return Status; } @@ -443,11 +501,12 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess, 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); + Win32CsrReleaseConsole(ProcessData); + // Win32CsrReleaseObject(ProcessData, + // ConnectInfo->InputHandle); + // ConioDeleteConsole(ProcessData->Console); + // ProcessData->Console = NULL; return Status; } @@ -461,15 +520,18 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess, 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); + Win32CsrReleaseConsole(ProcessData); + // Win32CsrReleaseObject(ProcessData, + // ConnectInfo->OutputHandle); + // Win32CsrReleaseObject(ProcessData, + // ConnectInfo->InputHandle); + // ConioDeleteConsole(ProcessData->Console); + // ProcessData->Console = NULL; return Status; } + + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); } /* Duplicate the Event */ @@ -481,18 +543,18 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess, if (!NT_SUCCESS(Status)) { DPRINT1("NtDuplicateObject() failed: %lu\n", Status); - ConioDeleteConsole(ProcessData->Console); - if (NewConsole /* || !ProcessData->bInheritHandles */) - { - Win32CsrReleaseObject(ProcessData, - ConnectInfo->ErrorHandle); - Win32CsrReleaseObject(ProcessData, - ConnectInfo->OutputHandle); - Win32CsrReleaseObject(ProcessData, - ConnectInfo->InputHandle); - } - ProcessData->Console = NULL; - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + Win32CsrReleaseConsole(ProcessData); + // if (NewConsole) + // { + // Win32CsrReleaseObject(ProcessData, + // ConnectInfo->ErrorHandle); + // Win32CsrReleaseObject(ProcessData, + // ConnectInfo->OutputHandle); + // Win32CsrReleaseObject(ProcessData, + // ConnectInfo->InputHandle); + // } + // ConioDeleteConsole(ProcessData->Console); // FIXME: Just release the console ? + // ProcessData->Console = NULL; return Status; } /* Input Wait Handle */ @@ -500,49 +562,11 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess, /* Set the Ctrl Dispatcher */ ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher; - DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher); + DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher); - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_SUCCESS; } -VOID -WINAPI -Win32CsrReleaseConsole(PCSR_PROCESS Process) -{ - PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process); - PCONSOLE Console; - ULONG i; - - 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); - Win32CsrUnlockConsole(Console); - //CloseHandle(ProcessData->ConsoleEvent); - //ProcessData->ConsoleEvent = NULL; - } - - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); -} - VOID WINAPI ConsoleDisconnect(PCSR_PROCESS Process) @@ -551,19 +575,14 @@ ConsoleDisconnect(PCSR_PROCESS 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) + if ( ProcessData->Console != NULL || + ProcessData->HandleTable != NULL ) { DPRINT1("ConsoleDisconnect - calling Win32CsrReleaseConsole\n"); - Win32CsrReleaseConsole(Process); + Win32CsrReleaseConsole(ProcessData); } RtlDeleteCriticalSection(&ProcessData->HandleTableLock); diff --git a/win32ss/user/consrv/init.c b/win32ss/user/consrv/init.c index 82233cde4f2..25b9b19ad85 100644 --- a/win32ss/user/consrv/init.c +++ b/win32ss/user/consrv/init.c @@ -107,7 +107,7 @@ PCSR_API_ROUTINE ConsoleServerApiDispatchTable[ConsolepMaxApiNumber] = // SrvRegisterConsoleIME, // SrvUnregisterConsoleIME, // SrvGetConsoleLangId, - // SrvAttachConsole, + SrvAttachConsole, SrvGetConsoleSelectionInfo, SrvGetConsoleProcessList, SrvGetConsoleHistory, @@ -198,7 +198,7 @@ BOOLEAN ConsoleServerApiServerValidTable[ConsolepMaxApiNumber] = // FALSE, // SrvRegisterConsoleIME, // FALSE, // SrvUnregisterConsoleIME, // FALSE, // SrvGetConsoleLangId, - // FALSE, // SrvAttachConsole, + FALSE, // SrvAttachConsole, FALSE, // SrvGetConsoleSelectionInfo, FALSE, // SrvGetConsoleProcessList, FALSE, // SrvGetConsoleHistory, @@ -291,7 +291,7 @@ PCHAR ConsoleServerApiNameTable[ConsolepMaxApiNumber] = // "RegisterConsoleIME", // "UnregisterConsoleIME", // "GetConsoleLangId", - // "AttachConsole", + "AttachConsole", "GetConsoleSelectionInfo", "GetConsoleProcessList", "GetConsoleHistory",