From a9feb1918139157b318cbb2642ca96960a23991c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sun, 7 Sep 2014 22:53:49 +0000 Subject: [PATCH] [KERNEL32][CONSRV] - Make CONSRV_API_CONNECTINFO, CONSOLE_ALLOCCONSOLE and CONSOLE_ATTACHCONSOLE Windows 2k3-compatible, so that using either their kernel32 in ROS or our kernel32 in windows, works. For that, complete and fix also the CONSOLE_START_INFO and CONSOLE_PROPERTIES structures. - Rewrite Alloc/AttachConsole and the console initialization functions to match what Windows expects when connecting to the console server, and make them compatible with the fixed structures. - Fix SrvAllocConsole and SrvAttachConsole accordingly, and few other console initialization functions in consrv. - Fix input EXE name support and store also the current directory from which we were started. - Use a temporarily define USE_CONSOLE_INIT_HANDLES that is not enabled yet because we do not use console initialization events (used by Windows for Alloc/AttachConsole and console initialization functions). Until this gets implemented in ReactOS, putting windows' kernel32 in ReactOS will fail when it will try to wait on those events. - For SrvAlloc/SrvAttach/SrvFreeConsole, ConSrvConnect and ConSrvDisconnect: correctly mark the process as console app. - Fix process initialization in ConSrvNewProcess. - Get rid of CONSOLE_PROCESS_DATA::ParentConsoleHandle member. - Temporarily move the link settings retrieval in console.c and hack a bit icon setting. [CONSRV] - Move console title setting from condrv back to consrv where it should belong in fact. CORE-7931 #resolve #comment ConsolepAlloc and ConsolepAttach finally fixed in revision 64079. svn path=/branches/condrv_restructure/; revision=64079 --- dll/win32/kernel32/client/console/console.c | 776 ++++++++++++------ dll/win32/kernel32/client/console/init.c | 585 ++++++++----- dll/win32/kernel32/client/console/readwrite.c | 26 +- dll/win32/kernel32/client/dllmain.c | 2 +- dll/win32/kernel32/client/proc.c | 2 +- dll/win32/kernel32/include/console.h | 59 +- include/reactos/subsys/win/conmsg.h | 125 +-- win32ss/user/winsrv/consrv/condrv/console.c | 162 ---- win32ss/user/winsrv/consrv/condrv/dummyterm.c | 6 - win32ss/user/winsrv/consrv/console.c | 456 ++++++++-- win32ss/user/winsrv/consrv/console.h | 16 +- win32ss/user/winsrv/consrv/consrv.h | 8 +- .../winsrv/consrv/frontends/gui/guisettings.c | 7 +- .../winsrv/consrv/frontends/gui/guiterm.c | 171 +--- .../winsrv/consrv/frontends/gui/guiterm.h | 7 - .../user/winsrv/consrv/frontends/terminal.c | 10 +- win32ss/user/winsrv/consrv/handle.c | 7 +- win32ss/user/winsrv/consrv/include/conio.h | 4 - .../user/winsrv/consrv/include/conio_winsrv.h | 4 +- win32ss/user/winsrv/consrv/include/term.h | 4 +- win32ss/user/winsrv/consrv/init.c | 70 +- win32ss/user/winsrv/consrv/procinit.h | 2 +- 22 files changed, 1544 insertions(+), 965 deletions(-) diff --git a/dll/win32/kernel32/client/console/console.c b/dll/win32/kernel32/client/console/console.c index 0a4059ac84a..fc79d8872ab 100644 --- a/dll/win32/kernel32/client/console/console.c +++ b/dll/win32/kernel32/client/console/console.c @@ -18,29 +18,37 @@ /* GLOBALS ********************************************************************/ extern RTL_CRITICAL_SECTION ConsoleLock; -extern BOOL ConsoleInitialized; -extern BOOL WINAPI IsDebuggerPresent(VOID); +extern BOOLEAN ConsoleInitialized; /* Console reserved "file" names */ static LPCWSTR BaseConFileName = CONSOLE_FILE_NAME; static LPCWSTR BaseConInputFileName = CONSOLE_INPUT_FILE_NAME; static LPCWSTR BaseConOutputFileName = CONSOLE_OUTPUT_FILE_NAME; -PHANDLER_ROUTINE InitialHandler[1]; -PHANDLER_ROUTINE* CtrlHandlers; -ULONG NrCtrlHandlers; -ULONG NrAllocatedHandlers; -BOOL LastCloseNotify = FALSE; +/* Console Control handling */ +static PHANDLER_ROUTINE InitialHandler[1]; +static PHANDLER_ROUTINE* CtrlHandlers; +static ULONG NrCtrlHandlers; +static ULONG NrAllocatedHandlers; +static BOOLEAN LastCloseNotify = FALSE; +extern BOOL WINAPI IsDebuggerPresent(VOID); + +/* Console Input facilities */ HANDLE InputWaitHandle = INVALID_HANDLE_VALUE; -#define INPUTEXENAME_BUFLEN 256 -static WCHAR InputExeName[INPUTEXENAME_BUFLEN]; +#define EXENAME_LENGTH 255 + 1 +static RTL_CRITICAL_SECTION ExeNameLock; +static BOOLEAN ExeNameInitialized; +static WCHAR ExeNameBuffer[EXENAME_LENGTH]; // NULL-terminated +static USHORT ExeNameLength; // Count in number of characters without NULL +static WCHAR StartDirBuffer[MAX_PATH + 1]; // NULL-terminated +static USHORT StartDirLength; // Count in number of characters without NULL /* Default Console Control Handler ********************************************/ -BOOL +static BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event) { @@ -193,8 +201,7 @@ ConsoleControlDispatcher(IN LPVOID lpThreadParameter) } VOID -WINAPI -InitConsoleCtrlHandling(VOID) +InitializeCtrlHandling(VOID) { /* Initialize Console Ctrl Handler */ NrAllocatedHandlers = NrCtrlHandlers = 1; @@ -203,6 +210,135 @@ InitConsoleCtrlHandling(VOID) } +/* Input EXE Name Support *****************************************************/ + +VOID +InitExeName(VOID) +{ + NTSTATUS Status; + PPEB Peb = NtCurrentPeb(); + PCURDIR CurrentDirectory = &Peb->ProcessParameters->CurrentDirectory; + PLDR_DATA_TABLE_ENTRY ImageEntry; + + if (ExeNameInitialized) return; + + /* Initialize the EXE name lock */ + Status = RtlInitializeCriticalSection(&ExeNameLock); + if (!NT_SUCCESS(Status)) return; + ExeNameInitialized = TRUE; + + ImageEntry = CONTAINING_RECORD(Peb->Ldr->InLoadOrderModuleList.Flink, + LDR_DATA_TABLE_ENTRY, + InLoadOrderLinks); + + /* Retrieve the EXE name, NULL-terminate it... */ + ExeNameLength = min(sizeof(ExeNameBuffer)/sizeof(ExeNameBuffer[0]), + ImageEntry->BaseDllName.Length / sizeof(WCHAR)); + RtlCopyMemory(ExeNameBuffer, + ImageEntry->BaseDllName.Buffer, + ImageEntry->BaseDllName.Length); + ExeNameBuffer[ExeNameLength] = UNICODE_NULL; + + /* ... and retrieve the current directory path and NULL-terminate it. */ + StartDirLength = min(sizeof(StartDirBuffer)/sizeof(StartDirBuffer[0]), + CurrentDirectory->DosPath.Length / sizeof(WCHAR)); + RtlCopyMemory(StartDirBuffer, + CurrentDirectory->DosPath.Buffer, + CurrentDirectory->DosPath.Length); + StartDirBuffer[StartDirLength] = UNICODE_NULL; +} + +/* + * NOTE: + * The "LPDWORD Length" parameters point on input to the maximum size of + * the buffers that can hold data (if != 0), and on output they hold the + * real size of the data. If "Length" are == 0 on input, then on output + * they receive the full size of the data. + * The "LPWSTR* String" parameters have a double meaning: + * - when "CaptureStrings" is TRUE, data is copied to the buffers pointed + * by the pointers (*String). + * - when "CaptureStrings" is FALSE, "*String" are set to the addresses of + * the source data. + */ +VOID +SetUpAppName(IN BOOLEAN CaptureStrings, + IN OUT LPDWORD CurDirLength, + IN OUT LPWSTR* CurDir, + IN OUT LPDWORD AppNameLength, + IN OUT LPWSTR* AppName) +{ + DWORD Length; + + /* Retrieve the needed buffer size */ + Length = (StartDirLength + 1) * sizeof(WCHAR); + if (*CurDirLength > 0) Length = min(Length, *CurDirLength); + *CurDirLength = Length; + + /* Capture the data if needed, or, return a pointer to it */ + if (CaptureStrings) + { + /* + * Length is always >= sizeof(WCHAR). Copy everything but the + * possible trailing NULL character, and then NULL-terminate. + */ + Length -= sizeof(WCHAR); + RtlCopyMemory(*CurDir, StartDirBuffer, Length); + (*CurDir)[Length / sizeof(WCHAR)] = UNICODE_NULL; + } + else + { + *CurDir = StartDirBuffer; + } + + /* Retrieve the needed buffer size */ + Length = (ExeNameLength + 1) * sizeof(WCHAR); + if (*AppNameLength > 0) Length = min(Length, *AppNameLength); + *AppNameLength = Length; + + /* Capture the data if needed, or, return a pointer to it */ + if (CaptureStrings) + { + /* + * Length is always >= sizeof(WCHAR). Copy everything but the + * possible trailing NULL character, and then NULL-terminate. + */ + Length -= sizeof(WCHAR); + RtlCopyMemory(*AppName, ExeNameBuffer, Length); + (*AppName)[Length / sizeof(WCHAR)] = UNICODE_NULL; + } + else + { + *AppName = ExeNameBuffer; + } +} + +USHORT +GetCurrentExeName(OUT PWCHAR ExeName, + IN USHORT BufferSize) +{ + USHORT ExeLength; + + if (ExeNameInitialized) + { + RtlEnterCriticalSection(&ExeNameLock); + + if (BufferSize > ExeNameLength * sizeof(WCHAR)) + BufferSize = ExeNameLength * sizeof(WCHAR); + + RtlCopyMemory(ExeName, ExeNameBuffer, BufferSize); + + RtlLeaveCriticalSection(&ExeNameLock); + ExeLength = BufferSize; + } + else + { + *ExeName = UNICODE_NULL; + ExeLength = 0; + } + + return ExeLength; +} + /* FUNCTIONS ******************************************************************/ LPCWSTR @@ -999,77 +1135,197 @@ SetStdHandle(DWORD nStdHandle, } -/*-------------------------------------------------------------- - * AllocConsole - * +/* * @implemented */ -BOOL -WINAPI -AllocConsole(VOID) +static BOOL +IntAllocConsole(LPWSTR Title, + DWORD TitleLength, + LPWSTR Desktop, + DWORD DesktopLength, + LPWSTR CurDir, + DWORD CurDirLength, + LPWSTR AppName, + DWORD AppNameLength, + LPTHREAD_START_ROUTINE CtrlRoutine, + LPTHREAD_START_ROUTINE PropRoutine, + PCONSOLE_START_INFO ConsoleStartInfo) { + BOOL Success = TRUE; +#ifdef USE_CONSOLE_INIT_HANDLES NTSTATUS Status; - PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters; +#endif + CONSOLE_API_MESSAGE ApiMessage; PCONSOLE_ALLOCCONSOLE AllocConsoleRequest = &ApiMessage.Data.AllocConsoleRequest; PCSR_CAPTURE_BUFFER CaptureBuffer; - if (Parameters->ConsoleHandle) - { - DPRINT1("AllocConsole: Allocating a console to a process already having one\n"); - SetLastError(ERROR_ACCESS_DENIED); - return FALSE; - } + AllocConsoleRequest->CtrlRoutine = CtrlRoutine; + AllocConsoleRequest->PropRoutine = PropRoutine; - CaptureBuffer = CsrAllocateCaptureBuffer(1, sizeof(CONSOLE_START_INFO)); + CaptureBuffer = CsrAllocateCaptureBuffer(5, TitleLength + + DesktopLength + + CurDirLength + + AppNameLength + + sizeof(CONSOLE_START_INFO)); if (CaptureBuffer == NULL) { - DPRINT1("CsrAllocateCaptureBuffer failed!\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; + Success = FALSE; + goto Quit; } - CsrAllocateMessagePointer(CaptureBuffer, - sizeof(CONSOLE_START_INFO), - (PVOID*)&AllocConsoleRequest->ConsoleStartInfo); + CsrCaptureMessageBuffer(CaptureBuffer, + ConsoleStartInfo, + sizeof(CONSOLE_START_INFO), + (PVOID*)&AllocConsoleRequest->ConsoleStartInfo); - InitConsoleInfo(AllocConsoleRequest->ConsoleStartInfo, - &Parameters->ImagePathName); + AllocConsoleRequest->TitleLength = TitleLength; + CsrCaptureMessageBuffer(CaptureBuffer, + Title, + TitleLength, + (PVOID*)&AllocConsoleRequest->ConsoleTitle); - AllocConsoleRequest->ConsoleHandle = NULL; - AllocConsoleRequest->CtrlDispatcher = ConsoleControlDispatcher; - AllocConsoleRequest->PropDispatcher = PropDialogHandler; + AllocConsoleRequest->DesktopLength = DesktopLength; + CsrCaptureMessageBuffer(CaptureBuffer, + Desktop, + DesktopLength, + (PVOID*)&AllocConsoleRequest->Desktop); - Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, - CaptureBuffer, - CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepAlloc), - sizeof(CONSOLE_ALLOCCONSOLE)); + AllocConsoleRequest->CurDirLength = CurDirLength; + CsrCaptureMessageBuffer(CaptureBuffer, + CurDir, + CurDirLength, + (PVOID*)&AllocConsoleRequest->CurDir); - CsrFreeCaptureBuffer(CaptureBuffer); + AllocConsoleRequest->AppNameLength = AppNameLength; + CsrCaptureMessageBuffer(CaptureBuffer, + AppName, + AppNameLength, + (PVOID*)&AllocConsoleRequest->AppName); + CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, + CaptureBuffer, + CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepAlloc), + sizeof(*AllocConsoleRequest)); + if (!NT_SUCCESS(ApiMessage.Status)) + { + BaseSetLastNTError(ApiMessage.Status); + Success = FALSE; + goto Quit; + } + +#ifdef USE_CONSOLE_INIT_HANDLES + // Is AllocConsoleRequest->ConsoleStartInfo->Events aligned on handle boundary ???? + Status = NtWaitForMultipleObjects(2, AllocConsoleRequest->ConsoleStartInfo->Events, + WaitAny, FALSE, NULL); if (!NT_SUCCESS(Status)) { BaseSetLastNTError(Status); - return FALSE; + Success = FALSE; + goto Quit; } - Parameters->ConsoleHandle = AllocConsoleRequest->ConsoleHandle; - SetStdHandle(STD_INPUT_HANDLE , AllocConsoleRequest->InputHandle ); - SetStdHandle(STD_OUTPUT_HANDLE, AllocConsoleRequest->OutputHandle); - SetStdHandle(STD_ERROR_HANDLE , AllocConsoleRequest->ErrorHandle ); + NtClose(AllocConsoleRequest->ConsoleStartInfo->Events[0]); + NtClose(AllocConsoleRequest->ConsoleStartInfo->Events[1]); + if (Status != STATUS_SUCCESS) + { + NtCurrentPeb()->ProcessParameters->ConsoleHandle = NULL; + Success = FALSE; + } + else +#endif + { + RtlCopyMemory(ConsoleStartInfo, + AllocConsoleRequest->ConsoleStartInfo, + sizeof(CONSOLE_START_INFO)); + Success = TRUE; + } - /* Initialize Console Ctrl Handler */ - InitConsoleCtrlHandling(); +Quit: + if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer); + return Success; +} - InputWaitHandle = AllocConsoleRequest->InputWaitHandle; +BOOL +WINAPI +AllocConsole(VOID) +{ + BOOL Success; + CONSOLE_START_INFO ConsoleStartInfo; - return TRUE; + PWCHAR ConsoleTitle; + PWCHAR Desktop; + PWCHAR AppName; + PWCHAR CurDir; + + ULONG TitleLength = (MAX_PATH + 1) * sizeof(WCHAR); + ULONG DesktopLength = (MAX_PATH + 1) * sizeof(WCHAR); + ULONG AppNameLength = 128 * sizeof(WCHAR); + ULONG CurDirLength = (MAX_PATH + 1) * sizeof(WCHAR); + + LCID lcid; + + RtlEnterCriticalSection(&ConsoleLock); + + if (NtCurrentPeb()->ProcessParameters->ConsoleHandle) + { + DPRINT1("AllocConsole: Allocating a console to a process already having one\n"); + SetLastError(ERROR_ACCESS_DENIED); + Success = FALSE; + goto Quit; + } + + /* Set up the console properties */ + SetUpConsoleInfo(FALSE, + &TitleLength, + &ConsoleTitle, + &DesktopLength, + &Desktop, + &ConsoleStartInfo); + DPRINT("ConsoleTitle = '%S' - Desktop = '%S'\n", + ConsoleTitle, Desktop); + + /* Initialize the Input EXE name */ + InitExeName(); + SetUpAppName(FALSE, + &CurDirLength, + &CurDir, + &AppNameLength, + &AppName); + DPRINT("CurDir = '%S' - AppName = '%S'\n", + CurDir, AppName); + + Success = IntAllocConsole(ConsoleTitle, + TitleLength, + Desktop, + DesktopLength, + CurDir, + CurDirLength, + AppName, + AppNameLength, + ConsoleControlDispatcher, + PropDialogHandler, + &ConsoleStartInfo); + if (Success) + { + /* Set up the handles */ + SetUpHandles(&ConsoleStartInfo); + InputWaitHandle = ConsoleStartInfo.InputWaitHandle; + + /* Initialize Console Ctrl Handling */ + InitializeCtrlHandling(); + + SetTEBLangID(lcid); + } + +Quit: + RtlLeaveCriticalSection(&ConsoleLock); + return Success; } -/*-------------------------------------------------------------- - * FreeConsole - * +/* * @implemented */ BOOL @@ -1114,9 +1370,7 @@ FreeConsole(VOID) } -/*-------------------------------------------------------------- - * GetConsoleScreenBufferInfo - * +/* * @implemented */ BOOL @@ -1159,9 +1413,7 @@ GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, } -/*-------------------------------------------------------------- - * SetConsoleCursorPosition - * +/* * @implemented */ BOOL @@ -1190,9 +1442,7 @@ SetConsoleCursorPosition(HANDLE hConsoleOutput, } -/*-------------------------------------------------------------- - * GetConsoleMode - * +/* * @implemented */ BOOL @@ -1228,9 +1478,7 @@ GetConsoleMode(HANDLE hConsoleHandle, } -/*-------------------------------------------------------------- - * SetConsoleMode - * +/* * @implemented */ BOOL @@ -1259,9 +1507,7 @@ SetConsoleMode(HANDLE hConsoleHandle, } -/*-------------------------------------------------------------- - * GetNumberOfConsoleInputEvents - * +/* * @implemented */ BOOL @@ -1298,9 +1544,7 @@ GetNumberOfConsoleInputEvents(HANDLE hConsoleInput, } -/*-------------------------------------------------------------- - * GetLargestConsoleWindowSize - * +/* * @implemented */ COORD @@ -1329,9 +1573,7 @@ GetLargestConsoleWindowSize(HANDLE hConsoleOutput) } -/*-------------------------------------------------------------- - * GetConsoleCursorInfo - * +/* * @implemented */ BOOL @@ -1371,9 +1613,7 @@ GetConsoleCursorInfo(HANDLE hConsoleOutput, } -/*-------------------------------------------------------------- - * SetConsoleCursorInfo - * +/* * @implemented */ BOOL @@ -1402,9 +1642,7 @@ SetConsoleCursorInfo(HANDLE hConsoleOutput, } -/*-------------------------------------------------------------- - * GetNumberOfConsoleMouseButtons - * +/* * @implemented */ BOOL @@ -1431,9 +1669,7 @@ GetNumberOfConsoleMouseButtons(LPDWORD lpNumberOfMouseButtons) } -/*-------------------------------------------------------------- - * SetConsoleActiveScreenBuffer - * +/* * @implemented */ BOOL @@ -1460,9 +1696,7 @@ SetConsoleActiveScreenBuffer(HANDLE hConsoleOutput) } -/*-------------------------------------------------------------- - * FlushConsoleInputBuffer - * +/* * @implemented */ BOOL @@ -1489,9 +1723,7 @@ FlushConsoleInputBuffer(HANDLE hConsoleInput) } -/*-------------------------------------------------------------- - * SetConsoleScreenBufferSize - * +/* * @implemented */ BOOL @@ -1564,9 +1796,7 @@ IntScrollConsoleScreenBuffer(HANDLE hConsoleOutput, } -/*-------------------------------------------------------------- - * ScrollConsoleScreenBufferA - * +/* * @implemented */ BOOL @@ -1586,9 +1816,7 @@ ScrollConsoleScreenBufferA(HANDLE hConsoleOutput, } -/*-------------------------------------------------------------- - * ScrollConsoleScreenBufferW - * +/* * @implemented */ BOOL @@ -1608,9 +1836,7 @@ ScrollConsoleScreenBufferW(HANDLE hConsoleOutput, } -/*-------------------------------------------------------------- - * SetConsoleWindowInfo - * +/* * @implemented */ BOOL @@ -1647,9 +1873,7 @@ SetConsoleWindowInfo(HANDLE hConsoleOutput, } -/*-------------------------------------------------------------- - * SetConsoleTextAttribute - * +/* * @implemented */ BOOL @@ -1774,9 +1998,7 @@ SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, } -/*-------------------------------------------------------------- - * GenerateConsoleCtrlEvent - * +/* * @implemented */ BOOL @@ -1854,9 +2076,9 @@ IntGetConsoleTitle(LPVOID lpConsoleTitle, DWORD dwNumChars, BOOLEAN bUnicode) memcpy(lpConsoleTitle, TitleRequest->Title, TitleRequest->Length); if (bUnicode) - ((LPWSTR)lpConsoleTitle)[dwNumChars] = L'\0'; + ((LPWSTR)lpConsoleTitle)[dwNumChars] = UNICODE_NULL; else - ((LPSTR)lpConsoleTitle)[dwNumChars] = '\0'; + ((LPSTR)lpConsoleTitle)[dwNumChars] = ANSI_NULL; } CsrFreeCaptureBuffer(CaptureBuffer); @@ -1865,9 +2087,7 @@ IntGetConsoleTitle(LPVOID lpConsoleTitle, DWORD dwNumChars, BOOLEAN bUnicode) } -/*-------------------------------------------------------------- - * GetConsoleTitleW - * +/* * @implemented */ DWORD @@ -1879,9 +2099,7 @@ GetConsoleTitleW(LPWSTR lpConsoleTitle, } -/*-------------------------------------------------------------- - * GetConsoleTitleA - * +/* * @implemented */ DWORD @@ -1935,9 +2153,7 @@ IntSetConsoleTitle(CONST VOID *lpConsoleTitle, BOOLEAN bUnicode) return TRUE; } -/*-------------------------------------------------------------- - * SetConsoleTitleW - * +/* * @implemented */ BOOL @@ -1948,9 +2164,7 @@ SetConsoleTitleW(LPCWSTR lpConsoleTitle) } -/*-------------------------------------------------------------- - * SetConsoleTitleA - * +/* * @implemented */ BOOL @@ -1961,9 +2175,7 @@ SetConsoleTitleA(LPCSTR lpConsoleTitle) } -/*-------------------------------------------------------------- - * CreateConsoleScreenBuffer - * +/* * @implemented */ HANDLE @@ -2040,9 +2252,7 @@ CreateConsoleScreenBuffer(DWORD dwDesiredAccess, } -/*-------------------------------------------------------------- - * GetConsoleCP - * +/* * @implemented */ UINT @@ -2070,9 +2280,7 @@ GetConsoleCP(VOID) } -/*-------------------------------------------------------------- - * SetConsoleCP - * +/* * @implemented */ BOOL @@ -2102,9 +2310,7 @@ SetConsoleCP(UINT wCodePageID) } -/*-------------------------------------------------------------- - * GetConsoleOutputCP - * +/* * @implemented */ UINT @@ -2132,9 +2338,7 @@ GetConsoleOutputCP(VOID) } -/*-------------------------------------------------------------- - * SetConsoleOutputCP - * +/* * @implemented */ BOOL @@ -2164,9 +2368,7 @@ SetConsoleOutputCP(UINT wCodePageID) } -/*-------------------------------------------------------------- - * GetConsoleProcessList - * +/* * @implemented */ DWORD @@ -2222,9 +2424,7 @@ GetConsoleProcessList(LPDWORD lpdwProcessList, } -/*-------------------------------------------------------------- - * GetConsoleSelectionInfo - * +/* * @implemented */ BOOL @@ -2258,60 +2458,136 @@ GetConsoleSelectionInfo(PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo) } -/*-------------------------------------------------------------- - * AttachConsole - * +/* * @implemented - * * @note Strongly inspired by AllocConsole. */ +static BOOL +IntAttachConsole(DWORD ProcessId, + LPTHREAD_START_ROUTINE CtrlRoutine, + LPTHREAD_START_ROUTINE PropRoutine, + PCONSOLE_START_INFO ConsoleStartInfo) +{ + BOOL Success = TRUE; +#ifdef USE_CONSOLE_INIT_HANDLES + NTSTATUS Status; +#endif + + CONSOLE_API_MESSAGE ApiMessage; + PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &ApiMessage.Data.AttachConsoleRequest; + PCSR_CAPTURE_BUFFER CaptureBuffer; + + AttachConsoleRequest->ProcessId = ProcessId; + AttachConsoleRequest->CtrlRoutine = CtrlRoutine; + AttachConsoleRequest->PropRoutine = PropRoutine; + + CaptureBuffer = CsrAllocateCaptureBuffer(1, sizeof(CONSOLE_START_INFO)); + if (CaptureBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + Success = FALSE; + goto Quit; + } + + CsrCaptureMessageBuffer(CaptureBuffer, + ConsoleStartInfo, + sizeof(CONSOLE_START_INFO), + (PVOID*)&AttachConsoleRequest->ConsoleStartInfo); + + CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, + CaptureBuffer, + CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepAttach), + sizeof(*AttachConsoleRequest)); + if (!NT_SUCCESS(ApiMessage.Status)) + { + BaseSetLastNTError(ApiMessage.Status); + Success = FALSE; + goto Quit; + } + +#ifdef USE_CONSOLE_INIT_HANDLES + // Is AttachConsoleRequest->ConsoleStartInfo->Events aligned on handle boundary ???? + Status = NtWaitForMultipleObjects(2, AttachConsoleRequest->ConsoleStartInfo->Events, + WaitAny, FALSE, NULL); + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + Success = FALSE; + goto Quit; + } + + NtClose(AttachConsoleRequest->ConsoleStartInfo->Events[0]); + NtClose(AttachConsoleRequest->ConsoleStartInfo->Events[1]); + if (Status != STATUS_SUCCESS) + { + NtCurrentPeb()->ProcessParameters->ConsoleHandle = NULL; + Success = FALSE; + } + else +#endif + { + RtlCopyMemory(ConsoleStartInfo, + AttachConsoleRequest->ConsoleStartInfo, + sizeof(CONSOLE_START_INFO)); + Success = TRUE; + } + +Quit: + if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer); + return Success; +} + BOOL WINAPI AttachConsole(DWORD dwProcessId) { - NTSTATUS Status; - PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters; - CONSOLE_API_MESSAGE ApiMessage; - PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &ApiMessage.Data.AttachConsoleRequest; + BOOL Success; + CONSOLE_START_INFO ConsoleStartInfo; - if (Parameters->ConsoleHandle) + DWORD dummy; + LCID lcid; + + RtlEnterCriticalSection(&ConsoleLock); + + if (NtCurrentPeb()->ProcessParameters->ConsoleHandle) { DPRINT1("AttachConsole: Attaching a console to a process already having one\n"); SetLastError(ERROR_ACCESS_DENIED); - return FALSE; + Success = FALSE; + goto Quit; } - AttachConsoleRequest->ProcessId = dwProcessId; - AttachConsoleRequest->CtrlDispatcher = ConsoleControlDispatcher; - AttachConsoleRequest->PropDispatcher = PropDialogHandler; + /* Set up the console properties */ + SetUpConsoleInfo(FALSE, + &dummy, + NULL, + &dummy, + NULL, + &ConsoleStartInfo); - Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, - NULL, - CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepAttach), - sizeof(CONSOLE_ATTACHCONSOLE)); - if (!NT_SUCCESS(Status)) + Success = IntAttachConsole(dwProcessId, + ConsoleControlDispatcher, + PropDialogHandler, + &ConsoleStartInfo); + if (Success) { - BaseSetLastNTError(Status); - return FALSE; + /* Set up the handles */ + SetUpHandles(&ConsoleStartInfo); + InputWaitHandle = ConsoleStartInfo.InputWaitHandle; + + /* Initialize Console Ctrl Handling */ + InitializeCtrlHandling(); + + SetTEBLangID(lcid); } - Parameters->ConsoleHandle = AttachConsoleRequest->ConsoleHandle; - 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; +Quit: + RtlLeaveCriticalSection(&ConsoleLock); + return Success; } -/*-------------------------------------------------------------- - * GetConsoleWindow - * +/* * @implemented */ HWND @@ -2337,9 +2613,7 @@ GetConsoleWindow(VOID) } -/*-------------------------------------------------------------- - * SetConsoleIcon - * +/* * @implemented */ BOOL @@ -2369,35 +2643,35 @@ SetConsoleIcon(HICON hIcon) /****************************************************************************** * \name SetConsoleInputExeNameW * \brief Sets the console input file name from a unicode string. - * \param lpInputExeName Pointer to a unicode string with the name. + * \param lpExeName Pointer to a unicode string with the name. * \return TRUE if successful, FALSE if unsuccsedful. - * \remarks If lpInputExeName is 0 or the string length is 0 or greater than 255, + * \remarks If lpExeName is 0 or the string length is 0 or greater than 255, * the function fails and sets last error to ERROR_INVALID_PARAMETER. */ BOOL WINAPI -SetConsoleInputExeNameW(LPCWSTR lpInputExeName) +SetConsoleInputExeNameW(IN LPWSTR lpExeName) { - int lenName; + DWORD ExeLength; - if ( !lpInputExeName || - (lenName = lstrlenW(lpInputExeName)) == 0 || - lenName > INPUTEXENAME_BUFLEN - 1 ) + ExeLength = lstrlenW(lpExeName); + if ((ExeLength == 0) || (ExeLength >= EXENAME_LENGTH)) { /* Fail if string is empty or too long */ SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - RtlEnterCriticalSection(&ConsoleLock); + RtlEnterCriticalSection(&ExeNameLock); _SEH2_TRY { - RtlCopyMemory(InputExeName, lpInputExeName, lenName * sizeof(WCHAR)); - InputExeName[lenName] = L'\0'; + /* Set the input EXE name, not NULL terminated */ + RtlCopyMemory(ExeNameBuffer, lpExeName, ExeLength * sizeof(WCHAR)); + ExeNameLength = (USHORT)ExeLength; } _SEH2_FINALLY { - RtlLeaveCriticalSection(&ConsoleLock); + RtlLeaveCriticalSection(&ExeNameLock); } _SEH2_END; @@ -2408,42 +2682,72 @@ SetConsoleInputExeNameW(LPCWSTR lpInputExeName) /****************************************************************************** * \name SetConsoleInputExeNameA * \brief Sets the console input file name from an ansi string. - * \param lpInputExeName Pointer to an ansi string with the name. + * \param lpExeName Pointer to an ansi string with the name. * \return TRUE if successful, FALSE if unsuccsedful. - * \remarks If lpInputExeName is 0 or the string length is 0 or greater than 255, + * \remarks If lpExeName is 0 or the string length is 0 or greater than 255, * the function fails and sets last error to ERROR_INVALID_PARAMETER. */ BOOL WINAPI -SetConsoleInputExeNameA(LPCSTR lpInputExeName) +SetConsoleInputExeNameA(IN LPSTR lpExeName) { - WCHAR Buffer[INPUTEXENAME_BUFLEN]; - ANSI_STRING InputExeNameA; - UNICODE_STRING InputExeNameU; NTSTATUS Status; +#ifdef USE_TEB_STATIC_USTR + PUNICODE_STRING ExeNameU; +#else + UNICODE_STRING ExeNameU; +#endif + ANSI_STRING ExeNameA; +#ifndef USE_TEB_STATIC_USTR + WCHAR Buffer[EXENAME_LENGTH]; +#endif - RtlInitAnsiString(&InputExeNameA, lpInputExeName); +#ifdef USE_TEB_STATIC_USTR + /* + * Use the TEB static UNICODE string for storage. It is already + * initialized at process creation time by the Memory Manager. + */ + ExeNameU = &NtCurrentTeb()->StaticUnicodeString; +#endif - if ( InputExeNameA.Length == 0 || - InputExeNameA.Length > INPUTEXENAME_BUFLEN - 1 ) + /* Initialize string for conversion */ + RtlInitAnsiString(&ExeNameA, lpExeName); + +#if 1 + if ((ExeNameA.Length == 0) || (ExeNameA.Length >= EXENAME_LENGTH)) { /* Fail if string is empty or too long */ SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } +#endif +#ifndef USE_TEB_STATIC_USTR + ExeNameU.Length = 0; + ExeNameU.MaximumLength = (USHORT)sizeof(Buffer); + ExeNameU.Buffer = Buffer; +#endif - InputExeNameU.Buffer = Buffer; - InputExeNameU.MaximumLength = sizeof(Buffer); - InputExeNameU.Length = 0; - - Status = RtlAnsiStringToUnicodeString(&InputExeNameU, &InputExeNameA, FALSE); +#ifdef USE_TEB_STATIC_USTR + Status = RtlAnsiStringToUnicodeString(ExeNameU, &ExeNameA, FALSE); +#else + Status = RtlAnsiStringToUnicodeString(&ExeNameU, &ExeNameA, FALSE); +#endif if (!NT_SUCCESS(Status)) { - BaseSetLastNTError(Status); + /* Fail if string is empty or too long */ + if (Status == STATUS_BUFFER_OVERFLOW) + SetLastError(ERROR_FILENAME_EXCED_RANGE); + else + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; } - return SetConsoleInputExeNameW(InputExeNameU.Buffer); +#ifdef USE_TEB_STATIC_USTR + return SetConsoleInputExeNameW(ExeNameU->Buffer); +#else + return SetConsoleInputExeNameW(ExeNameU.Buffer); +#endif } @@ -2460,37 +2764,30 @@ SetConsoleInputExeNameA(LPCSTR lpInputExeName) */ DWORD WINAPI -GetConsoleInputExeNameW(DWORD nBufferLength, LPWSTR lpBuffer) +GetConsoleInputExeNameW(IN DWORD nBufferLength, + OUT LPWSTR lpExeName) { - ULONG lenName = lstrlenW(InputExeName); - - if (nBufferLength == 0) + if (nBufferLength <= ExeNameLength) { - /* Buffer size is requested, return it */ - return lenName + 1; - } - - if (lenName + 1 > nBufferLength) - { - /* Buffer is not large enough! */ + /* Buffer is not large enough! Return the correct size. */ SetLastError(ERROR_BUFFER_OVERFLOW); - return 2; + return ExeNameLength + 1; } - RtlEnterCriticalSection(&ConsoleLock); + RtlEnterCriticalSection(&ExeNameLock); _SEH2_TRY { - RtlCopyMemory(lpBuffer, InputExeName, lenName * sizeof(WCHAR)); - lpBuffer[lenName] = '\0'; + /* Copy the input EXE name and NULL-terminate it */ + RtlCopyMemory(lpExeName, ExeNameBuffer, ExeNameLength * sizeof(WCHAR)); + lpExeName[ExeNameLength] = UNICODE_NULL; } _SEH2_FINALLY { - RtlLeaveCriticalSection(&ConsoleLock); + RtlLeaveCriticalSection(&ExeNameLock); } _SEH2_END; - /* Success, return 1 */ - return 1; + return TRUE; } @@ -2505,33 +2802,40 @@ GetConsoleInputExeNameW(DWORD nBufferLength, LPWSTR lpBuffer) */ DWORD WINAPI -GetConsoleInputExeNameA(DWORD nBufferLength, LPSTR lpBuffer) +GetConsoleInputExeNameA(IN DWORD nBufferLength, + OUT LPSTR lpExeName) { - WCHAR Buffer[INPUTEXENAME_BUFLEN]; - DWORD Ret; + NTSTATUS Status; + DWORD ExeLength; UNICODE_STRING BufferU; ANSI_STRING BufferA; + WCHAR Buffer[EXENAME_LENGTH]; - /* Get the unicode name */ - Ret = GetConsoleInputExeNameW(sizeof(Buffer) / sizeof(Buffer[0]), Buffer); + /* Get the UNICODE name */ + ExeLength = GetConsoleInputExeNameW(EXENAME_LENGTH, Buffer); - /* Initialize strings for conversion */ + if ((ExeLength == 0) || (ExeLength >= EXENAME_LENGTH)) + return ExeLength; + + /* Initialize the strings for conversion */ RtlInitUnicodeString(&BufferU, Buffer); BufferA.Length = 0; BufferA.MaximumLength = (USHORT)nBufferLength; - BufferA.Buffer = lpBuffer; + BufferA.Buffer = lpExeName; - /* Convert unicode name to ansi, copying as much chars as fit */ - RtlUnicodeStringToAnsiString(&BufferA, &BufferU, FALSE); - - /* Error handling */ - if (nBufferLength <= BufferU.Length / sizeof(WCHAR)) + /* Convert UNICODE name to ANSI, copying as much chars as it can fit */ + Status = RtlUnicodeStringToAnsiString(&BufferA, &BufferU, FALSE); + if (!NT_SUCCESS(Status)) { - SetLastError(ERROR_BUFFER_OVERFLOW); - return 2; + if (Status == STATUS_BUFFER_OVERFLOW) + { + SetLastError(ERROR_BUFFER_OVERFLOW); + return ExeLength + 1; + } + SetLastError(ERROR_INVALID_PARAMETER); } - return Ret; + return ExeLength; } BOOL diff --git a/dll/win32/kernel32/client/console/init.c b/dll/win32/kernel32/client/console/init.c index 1313b77a232..1d550b9e798 100644 --- a/dll/win32/kernel32/client/console/init.c +++ b/dll/win32/kernel32/client/console/init.c @@ -22,15 +22,14 @@ /* GLOBALS ********************************************************************/ RTL_CRITICAL_SECTION ConsoleLock; -BOOL ConsoleInitialized = FALSE; +BOOLEAN ConsoleInitialized = FALSE; extern HANDLE InputWaitHandle; static HMODULE ConsoleLibrary = NULL; static BOOL AlreadyDisplayingProps = FALSE; -#define WIN_OBJ_DIR L"\\Windows" -#define SESSION_DIR L"\\Sessions" +static const PWSTR DefaultConsoleTitle = L"ReactOS Console"; /* FUNCTIONS ******************************************************************/ @@ -41,6 +40,7 @@ PropDialogHandler(IN LPVOID lpThreadParameter) { // NOTE: lpThreadParameter corresponds to the client shared section handle. + NTSTATUS Status = STATUS_SUCCESS; APPLET_PROC CPLFunc; /* @@ -67,12 +67,11 @@ PropDialogHandler(IN LPVOID lpThreadParameter) GetSystemDirectoryW(szBuffer, MAX_PATH); wcscat(szBuffer, L"\\console.dll"); ConsoleLibrary = LoadLibraryW(szBuffer); - if (ConsoleLibrary == NULL) { DPRINT1("Failed to load console.dll\n"); - AlreadyDisplayingProps = FALSE; - return STATUS_UNSUCCESSFUL; + Status = STATUS_UNSUCCESSFUL; + goto Quit; } } @@ -80,203 +79,223 @@ PropDialogHandler(IN LPVOID lpThreadParameter) CPLFunc = (APPLET_PROC)GetProcAddress(ConsoleLibrary, "CPlApplet"); if (CPLFunc == NULL) { - DPRINT("Error: Console.dll misses CPlApplet export\n"); - AlreadyDisplayingProps = FALSE; - return STATUS_UNSUCCESSFUL; + DPRINT1("Error: Console.dll misses CPlApplet export\n"); + Status = STATUS_UNSUCCESSFUL; + goto Quit; } if (CPLFunc(NULL, CPL_INIT, 0, 0) == FALSE) { - DPRINT("Error: failed to initialize console.dll\n"); - AlreadyDisplayingProps = FALSE; - return STATUS_UNSUCCESSFUL; + DPRINT1("Error: failed to initialize console.dll\n"); + Status = STATUS_UNSUCCESSFUL; + goto Quit; } if (CPLFunc(NULL, CPL_GETCOUNT, 0, 0) != 1) { - DPRINT("Error: console.dll returned unexpected CPL count\n"); - AlreadyDisplayingProps = FALSE; - return STATUS_UNSUCCESSFUL; + DPRINT1("Error: console.dll returned unexpected CPL count\n"); + Status = STATUS_UNSUCCESSFUL; + goto Quit; } CPLFunc(NULL, CPL_DBLCLK, (LPARAM)lpThreadParameter, 0); CPLFunc(NULL, CPL_EXIT , 0, 0); +Quit: AlreadyDisplayingProps = FALSE; - return STATUS_SUCCESS; + return Status; +} + + +static INT +ParseShellInfo(LPCWSTR lpszShellInfo, + LPCWSTR lpszKeyword) +{ + DPRINT1("ParseShellInfo is UNIMPLEMENTED\n"); + return 0; +} + + +/* + * NOTE: + * The "LPDWORD Length" parameters point on input to the maximum size of + * the buffers that can hold data (if != 0), and on output they hold the + * real size of the data. If "Length" are == 0 on input, then on output + * they receive the full size of the data. + * The "LPWSTR* lpTitle" parameter has a double meaning: + * - when "CaptureTitle" is TRUE, data is copied to the buffer pointed + * by the pointer (*lpTitle). + * - when "CaptureTitle" is FALSE, "*lpTitle" is set to the address of + * the source data. + */ +VOID +SetUpConsoleInfo(IN BOOLEAN CaptureTitle, + IN OUT LPDWORD pTitleLength, + IN OUT LPWSTR* lpTitle OPTIONAL, + IN OUT LPDWORD pDesktopLength, + IN OUT LPWSTR* lpDesktop OPTIONAL, + IN OUT PCONSOLE_START_INFO ConsoleStartInfo) +{ + PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters; + DWORD Length; + + /* Initialize the fields */ + + ConsoleStartInfo->IconIndex = 0; + ConsoleStartInfo->hIcon = NULL; + ConsoleStartInfo->hIconSm = NULL; + ConsoleStartInfo->dwStartupFlags = Parameters->WindowFlags; + ConsoleStartInfo->nFont = 0; + ConsoleStartInfo->nInputBufferSize = 0; + ConsoleStartInfo->uCodePage = GetOEMCP(); + + if (lpTitle) + { + LPWSTR Title; + + /* If we don't have any title, use the default one */ + if (Parameters->WindowTitle.Buffer == NULL) + { + Title = DefaultConsoleTitle; + Length = lstrlenW(DefaultConsoleTitle) * sizeof(WCHAR); // sizeof(DefaultConsoleTitle); + } + else + { + Title = Parameters->WindowTitle.Buffer; + Length = Parameters->WindowTitle.Length; + } + + /* Retrieve the needed buffer size */ + Length += sizeof(WCHAR); + if (*pTitleLength > 0) Length = min(Length, *pTitleLength); + *pTitleLength = Length; + + /* Capture the data if needed, or, return a pointer to it */ + if (CaptureTitle) + { + /* + * Length is always >= sizeof(WCHAR). Copy everything but the + * possible trailing NULL character, and then NULL-terminate. + */ + Length -= sizeof(WCHAR); + RtlCopyMemory(*lpTitle, Title, Length); + (*lpTitle)[Length / sizeof(WCHAR)] = UNICODE_NULL; + } + else + { + *lpTitle = Title; + } + } + else + { + *pTitleLength = 0; + } + + if (lpDesktop && Parameters->DesktopInfo.Buffer && *Parameters->DesktopInfo.Buffer) + { + /* Retrieve the needed buffer size */ + Length = Parameters->DesktopInfo.Length + sizeof(WCHAR); + if (*pDesktopLength > 0) Length = min(Length, *pDesktopLength); + *pDesktopLength = Length; + + /* Return a pointer to the data */ + *lpDesktop = Parameters->DesktopInfo.Buffer; + } + else + { + *pDesktopLength = 0; + if (lpDesktop) *lpDesktop = NULL; + } + + if (Parameters->WindowFlags & STARTF_USEFILLATTRIBUTE) + { + ConsoleStartInfo->wFillAttribute = (WORD)Parameters->FillAttribute; + } + if (Parameters->WindowFlags & STARTF_USECOUNTCHARS) + { + ConsoleStartInfo->dwScreenBufferSize.X = (SHORT)Parameters->CountCharsX; + ConsoleStartInfo->dwScreenBufferSize.Y = (SHORT)Parameters->CountCharsY; + } + if (Parameters->WindowFlags & STARTF_USESHOWWINDOW) + { + ConsoleStartInfo->wShowWindow = (WORD)Parameters->ShowWindowFlags; + } + if (Parameters->WindowFlags & STARTF_USEPOSITION) + { + ConsoleStartInfo->dwWindowOrigin.X = (SHORT)Parameters->StartingX; + ConsoleStartInfo->dwWindowOrigin.Y = (SHORT)Parameters->StartingY; + } + if (Parameters->WindowFlags & STARTF_USESIZE) + { + ConsoleStartInfo->dwWindowSize.X = (SHORT)Parameters->CountX; + ConsoleStartInfo->dwWindowSize.Y = (SHORT)Parameters->CountY; + } + + /* Get shell information (ShellInfo.Buffer is NULL-terminated) */ + if (Parameters->ShellInfo.Buffer != NULL) + { + ConsoleStartInfo->IconIndex = ParseShellInfo(Parameters->ShellInfo.Buffer, L"dde."); + + if ((Parameters->WindowFlags & STARTF_USEHOTKEY) == 0) + ConsoleStartInfo->dwHotKey = ParseShellInfo(Parameters->ShellInfo.Buffer, L"hotkey."); + else + ConsoleStartInfo->dwHotKey = HandleToUlong(Parameters->StandardInput); + } } VOID -InitConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo, - IN PUNICODE_STRING ImagePathName) +SetUpHandles(IN PCONSOLE_START_INFO ConsoleStartInfo) { - STARTUPINFOW si; - SIZE_T Length; + PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters; - /* Get the startup information */ - GetStartupInfoW(&si); - - /* Initialize the fields */ - ConsoleStartInfo->dwStartupFlags = si.dwFlags; - if (si.dwFlags & STARTF_USEFILLATTRIBUTE) + if (ConsoleStartInfo->dwStartupFlags & STARTF_USEHOTKEY) { - ConsoleStartInfo->wFillAttribute = (WORD)si.dwFillAttribute; + Parameters->WindowFlags &= ~STARTF_USEHOTKEY; } - if (si.dwFlags & STARTF_USECOUNTCHARS) + if (ConsoleStartInfo->dwStartupFlags & STARTF_SHELLPRIVATE) { - ConsoleStartInfo->dwScreenBufferSize.X = (SHORT)(si.dwXCountChars); - ConsoleStartInfo->dwScreenBufferSize.Y = (SHORT)(si.dwYCountChars); - } - if (si.dwFlags & STARTF_USESHOWWINDOW) - { - ConsoleStartInfo->wShowWindow = si.wShowWindow; - } - if (si.dwFlags & STARTF_USEPOSITION) - { - ConsoleStartInfo->dwWindowOrigin.X = (SHORT)(si.dwX); - ConsoleStartInfo->dwWindowOrigin.Y = (SHORT)(si.dwY); - } - if (si.dwFlags & STARTF_USESIZE) - { - ConsoleStartInfo->dwWindowSize.X = (SHORT)(si.dwXSize); - ConsoleStartInfo->dwWindowSize.Y = (SHORT)(si.dwYSize); + Parameters->WindowFlags &= ~STARTF_SHELLPRIVATE; } - /* Set up the title for the console */ - if (si.lpTitle) - { - wcsncpy(ConsoleStartInfo->ConsoleTitle, si.lpTitle, MAX_PATH + 1); - } - else - { - ConsoleStartInfo->ConsoleTitle[0] = L'\0'; - } + /* We got the handles, let's set them */ + Parameters->ConsoleHandle = ConsoleStartInfo->ConsoleHandle; - /* Retrieve the application path name */ - Length = min(sizeof(ConsoleStartInfo->AppPath) / sizeof(ConsoleStartInfo->AppPath[0]) - 1, - ImagePathName->Length / sizeof(WCHAR)); - wcsncpy(ConsoleStartInfo->AppPath, ImagePathName->Buffer, Length); - ConsoleStartInfo->AppPath[Length] = L'\0'; - - /* The Console Server will use these fields to set up the console icon */ - ConsoleStartInfo->IconPath[0] = L'\0'; - ConsoleStartInfo->IconIndex = 0; + if (!(ConsoleStartInfo->dwStartupFlags & STARTF_USESTDHANDLES)) + { + Parameters->StandardInput = ConsoleStartInfo->InputHandle; + Parameters->StandardOutput = ConsoleStartInfo->OutputHandle; + Parameters->StandardError = ConsoleStartInfo->ErrorHandle; + } } -BOOL -WINAPI -BasepInitConsole(VOID) +static BOOLEAN +IsConsoleApp(VOID) +{ + PIMAGE_NT_HEADERS ImageNtHeader = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); + return (ImageNtHeader && (ImageNtHeader->OptionalHeader.Subsystem == + IMAGE_SUBSYSTEM_WINDOWS_CUI)); +} + + +static BOOLEAN +ConnectConsole(IN PWSTR SessionDir, + IN PCONSRV_API_CONNECTINFO ConnectInfo, + OUT PBOOLEAN IsServerProcess) { NTSTATUS Status; - PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters; - WCHAR SessionDir[256]; - ULONG SessionId = NtCurrentPeb()->SessionId; - BOOLEAN InServer; + ULONG ConnectInfoSize = sizeof(*ConnectInfo); - CONSRV_API_CONNECTINFO ConnectInfo; - ULONG ConnectInfoSize = sizeof(ConnectInfo); - - DPRINT("BasepInitConsole for : %wZ\n", &Parameters->ImagePathName); - DPRINT("Our current console handles are: %p, %p, %p %p\n", - Parameters->ConsoleHandle, Parameters->StandardInput, - Parameters->StandardOutput, Parameters->StandardError); - - /* Initialize our global console DLL lock */ - Status = RtlInitializeCriticalSection(&ConsoleLock); - if (!NT_SUCCESS(Status)) return FALSE; - ConsoleInitialized = TRUE; - - /* Do nothing if this isn't a console app... */ - if (RtlImageNtHeader(GetModuleHandle(NULL))->OptionalHeader.Subsystem != - IMAGE_SUBSYSTEM_WINDOWS_CUI) - { - DPRINT("Image is not a console application\n"); - Parameters->ConsoleHandle = NULL; - ConnectInfo.ConsoleStartInfo.ConsoleNeeded = FALSE; // ConsoleNeeded is used for knowing whether or not this is a CUI app. - - ConnectInfo.ConsoleStartInfo.ConsoleTitle[0] = L'\0'; - ConnectInfo.ConsoleStartInfo.AppPath[0] = L'\0'; - } - else - { - LPCWSTR ExeName; - - InitConsoleInfo(&ConnectInfo.ConsoleStartInfo, - &Parameters->ImagePathName); - - /* Initialize Input EXE name */ - ExeName = wcsrchr(Parameters->ImagePathName.Buffer, L'\\'); - if (ExeName) SetConsoleInputExeNameW(ExeName + 1); - - /* Assume one is needed */ - ConnectInfo.ConsoleStartInfo.ConsoleNeeded = TRUE; - - /* Handle the special flags given to us by BasePushProcessParameters */ - if (Parameters->ConsoleHandle == HANDLE_DETACHED_PROCESS) - { - /* No console to create */ - DPRINT("No console to create\n"); - Parameters->ConsoleHandle = NULL; - ConnectInfo.ConsoleStartInfo.ConsoleNeeded = FALSE; - } - else if (Parameters->ConsoleHandle == HANDLE_CREATE_NEW_CONSOLE) - { - /* We'll get the real one soon */ - DPRINT("Creating new console\n"); - Parameters->ConsoleHandle = NULL; - } - else if (Parameters->ConsoleHandle == HANDLE_CREATE_NO_WINDOW) - { - /* We'll get the real one soon */ - DPRINT("Creating new invisible console\n"); - Parameters->ConsoleHandle = NULL; - ConnectInfo.ConsoleStartInfo.wShowWindow = SW_HIDE; - } - else - { - if (Parameters->ConsoleHandle == INVALID_HANDLE_VALUE) - { - Parameters->ConsoleHandle = NULL; - } - DPRINT("Using existing console: %p\n", Parameters->ConsoleHandle); - } - } - - /* Now use the proper console handle */ - ConnectInfo.ConsoleHandle = Parameters->ConsoleHandle; - - /* Initialize the Console Ctrl Handler */ - InitConsoleCtrlHandling(); - ConnectInfo.ConsoleStartInfo.CtrlDispatcher = ConsoleControlDispatcher; - - /* Initialize the Property Dialog Handler */ - ConnectInfo.ConsoleStartInfo.PropDispatcher = PropDialogHandler; - - /* Setup the right Object Directory path */ - if (!SessionId) - { - /* Use the raw path */ - wcscpy(SessionDir, WIN_OBJ_DIR); - } - else - { - /* Use the session path */ - swprintf(SessionDir, - L"%ws\\%ld%ws", - SESSION_DIR, - SessionId, - WIN_OBJ_DIR); - } + ASSERT(SessionDir); /* Connect to the Console Server */ - DPRINT("Connecting to the Console Server in BasepInitConsole...\n"); + DPRINT("Connecting to the Console Server...\n"); Status = CsrClientConnectToServer(SessionDir, CONSRV_SERVERDLL_INDEX, - &ConnectInfo, + ConnectInfo, &ConnectInfoSize, - &InServer); + IsServerProcess); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to connect to the Console Server (Status %lx)\n", Status); @@ -284,36 +303,222 @@ BasepInitConsole(VOID) } /* Nothing to do for server-to-server */ - if (InServer) return TRUE; + if (*IsServerProcess) return TRUE; - /* Nothing to do if not a console app */ - if (!ConnectInfo.ConsoleStartInfo.ConsoleNeeded) return TRUE; + /* Nothing to do if this is not a console app */ + if (!ConnectInfo->IsConsoleApp) return TRUE; - /* We got the handles, let's set them */ - if ((Parameters->ConsoleHandle = ConnectInfo.ConsoleHandle)) +#ifdef USE_CONSOLE_INIT_HANDLES + /* Wait for the connection to finish */ + Status = NtWaitForMultipleObjects(2, ConnectInfo->ConsoleStartInfo.Events, + WaitAny, FALSE, NULL); + if (!NT_SUCCESS(Status)) { - /* If we already had some, don't use the new ones */ - if (!Parameters->StandardInput) - { - Parameters->StandardInput = ConnectInfo.InputHandle; - } - if (!Parameters->StandardOutput) - { - Parameters->StandardOutput = ConnectInfo.OutputHandle; - } - if (!Parameters->StandardError) - { - Parameters->StandardError = ConnectInfo.ErrorHandle; - } + BaseSetLastNTError(Status); + return FALSE; } - InputWaitHandle = ConnectInfo.InputWaitHandle; + NtClose(ConnectInfo->ConsoleStartInfo.Events[0]); + NtClose(ConnectInfo->ConsoleStartInfo.Events[1]); + + if (Status != STATUS_SUCCESS) + { + NtCurrentPeb()->ProcessParameters->ConsoleHandle = NULL; + return FALSE; + } +#endif + + return TRUE; +} + + +BOOLEAN +WINAPI +ConDllInitialize(IN ULONG Reason, + IN PWSTR SessionDir) +{ + NTSTATUS Status; + PRTL_USER_PROCESS_PARAMETERS Parameters = NtCurrentPeb()->ProcessParameters; + BOOLEAN IsServerProcess; + CONSRV_API_CONNECTINFO ConnectInfo; + LCID lcid; + + if (Reason != DLL_PROCESS_ATTACH) + { + if (Reason != DLL_THREAD_ATTACH || !IsConsoleApp()) + return TRUE; + + // Reason == DLL_THREAD_ATTACH and IsConsoleApp; + goto Exit; + } + + DPRINT("ConDllInitialize for: %wZ\n" + "Our current console handles are: 0x%p, 0x%p, 0x%p 0x%p\n", + &Parameters->ImagePathName, + Parameters->ConsoleHandle, + Parameters->StandardInput, + Parameters->StandardOutput, + Parameters->StandardError); + + /* Initialize our global console DLL lock */ + Status = RtlInitializeCriticalSection(&ConsoleLock); + if (!NT_SUCCESS(Status)) return FALSE; + ConsoleInitialized = TRUE; + + /* Show by default the console window when applicable */ + ConnectInfo.IsWindowVisible = TRUE; + /* If this is a console app, a console will be created/opened */ + ConnectInfo.IsConsoleApp = IsConsoleApp(); + + /* Do nothing if this is not a console app... */ + if (!ConnectInfo.IsConsoleApp) + { + DPRINT("Image is not a console application\n"); + } + + /* + * Handle the special flags given to us by BasePushProcessParameters. + */ + if (Parameters->ConsoleHandle == HANDLE_DETACHED_PROCESS) + { + /* No console to create */ + DPRINT("No console to create\n"); + /* + * The new process does not inherit its parent's console and cannot + * attach to the console of its parent. The new process can call the + * AllocConsole function at a later time to create a console. + */ + Parameters->ConsoleHandle = NULL; // Do not inherit the parent's console. + ConnectInfo.IsConsoleApp = FALSE; // Do not create any console. + } + else if (Parameters->ConsoleHandle == HANDLE_CREATE_NEW_CONSOLE) + { + /* We'll get the real one soon */ + DPRINT("Creating a new separate console\n"); + /* + * The new process has a new console, instead of inheriting + * its parent's console. + */ + Parameters->ConsoleHandle = NULL; // Do not inherit the parent's console. + } + else if (Parameters->ConsoleHandle == HANDLE_CREATE_NO_WINDOW) + { + /* We'll get the real one soon */ + DPRINT("Creating a new invisible console\n"); + /* + * The process is a console application that is being run + * without a console window. Therefore, the console handle + * for the application is not set. + */ + Parameters->ConsoleHandle = NULL; // Do not inherit the parent's console. + ConnectInfo.IsWindowVisible = FALSE; // A console is created but is not shown to the user. + } + else + { + DPRINT("Using existing console: 0x%p\n", Parameters->ConsoleHandle); + } + + /* Do nothing if this is not a console app... */ + if (!ConnectInfo.IsConsoleApp) + { + /* Do not inherit the parent's console if we are not a console app */ + Parameters->ConsoleHandle = NULL; + } + + /* Now use the proper console handle */ + ConnectInfo.ConsoleStartInfo.ConsoleHandle = Parameters->ConsoleHandle; + + /* Initialize the console dispatchers */ + ConnectInfo.CtrlRoutine = ConsoleControlDispatcher; + ConnectInfo.PropRoutine = PropDialogHandler; + // ConnectInfo.ImeRoutine = ImeRoutine; + + /* Set up the console properties */ + if (ConnectInfo.IsConsoleApp && Parameters->ConsoleHandle == NULL) + { + /* + * We can set up the console properties only if we create a new one + * (we do not inherit it from our parent). + */ + + LPWSTR ConsoleTitle = ConnectInfo.ConsoleTitle; + + ConnectInfo.TitleLength = sizeof(ConnectInfo.ConsoleTitle); + ConnectInfo.DesktopLength = 0; // SetUpConsoleInfo will give us the real length. + + SetUpConsoleInfo(TRUE, + &ConnectInfo.TitleLength, + &ConsoleTitle, + &ConnectInfo.DesktopLength, + &ConnectInfo.Desktop, + &ConnectInfo.ConsoleStartInfo); + DPRINT("ConsoleTitle = '%S' - Desktop = '%S'\n", + ConsoleTitle, ConnectInfo.Desktop); + } + else + { + ConnectInfo.TitleLength = 0; + ConnectInfo.DesktopLength = 0; + } + + /* Initialize the Input EXE name */ + if (ConnectInfo.IsConsoleApp) + { + LPWSTR CurDir = ConnectInfo.CurDir; + LPWSTR AppName = ConnectInfo.AppName; + + InitExeName(); + + ConnectInfo.CurDirLength = sizeof(ConnectInfo.CurDir); + ConnectInfo.AppNameLength = sizeof(ConnectInfo.AppName); + + SetUpAppName(TRUE, + &ConnectInfo.CurDirLength, + &CurDir, + &ConnectInfo.AppNameLength, + &AppName); + DPRINT("CurDir = '%S' - AppName = '%S'\n", + CurDir, AppName); + } + else + { + ConnectInfo.CurDirLength = 0; + ConnectInfo.AppNameLength = 0; + } + + /* + * Initialize Console Ctrl Handling, that needs to be supported by + * all applications, especially because it is used at shutdown. + */ + InitializeCtrlHandling(); + + /* Connect to the Console Server */ + if (!ConnectConsole(SessionDir, + &ConnectInfo, + &IsServerProcess)) + { + // DPRINT1("Failed to connect to the Console Server (Status %lx)\n", Status); + return FALSE; + } + + /* If we are not doing server-to-server init and if this is a console app... */ + if (!IsServerProcess && ConnectInfo.IsConsoleApp) + { + /* ... set the handles that we got */ + if (Parameters->ConsoleHandle == NULL) + SetUpHandles(&ConnectInfo.ConsoleStartInfo); + + InputWaitHandle = ConnectInfo.ConsoleStartInfo.InputWaitHandle; +Exit: + SetTEBLangID(lcid); + } + + DPRINT("Console setup: 0x%p, 0x%p, 0x%p, 0x%p\n", + Parameters->ConsoleHandle, + Parameters->StandardInput, + Parameters->StandardOutput, + Parameters->StandardError); - DPRINT("Console setup: %p, %p, %p, %p\n", - Parameters->ConsoleHandle, - Parameters->StandardInput, - Parameters->StandardOutput, - Parameters->StandardError); return TRUE; } diff --git a/dll/win32/kernel32/client/console/readwrite.c b/dll/win32/kernel32/client/console/readwrite.c index f1818a0c8c8..39d0727f6b1 100644 --- a/dll/win32/kernel32/client/console/readwrite.c +++ b/dll/win32/kernel32/client/console/readwrite.c @@ -31,10 +31,6 @@ * Read functions * ******************/ -DWORD -WINAPI -GetConsoleInputExeNameW(DWORD nBufferLength, LPWSTR lpBuffer); - static BOOL IntReadConsole(IN HANDLE hConsoleInput, @@ -58,26 +54,12 @@ IntReadConsole(IN HANDLE hConsoleInput, ReadConsoleRequest->Unicode = bUnicode; /* - * Retrieve the current console executable name string and length (always - * in UNICODE format). - * FIXME: Do not use GetConsoleInputExeNameW but use something else... + * Retrieve the (current) Input EXE name string and length, + * not NULL-terminated (always in UNICODE format). */ - // 1- Get the exe name length in characters, including NULL character. ReadConsoleRequest->ExeLength = - (USHORT)GetConsoleInputExeNameW(0, (PWCHAR)ReadConsoleRequest->StaticBuffer); - // 2- Get the exe name (GetConsoleInputExeNameW returns 1 in case of success). - if (GetConsoleInputExeNameW(ReadConsoleRequest->ExeLength, - (PWCHAR)ReadConsoleRequest->StaticBuffer) != 1) - { - // Nothing - ReadConsoleRequest->ExeLength = 0; - } - else - { - // Remove the NULL character, and convert in number of bytes. - ReadConsoleRequest->ExeLength--; - ReadConsoleRequest->ExeLength *= sizeof(WCHAR); - } + GetCurrentExeName((PWCHAR)ReadConsoleRequest->StaticBuffer, + sizeof(ReadConsoleRequest->StaticBuffer)); /*** For DEBUGGING purposes ***/ { diff --git a/dll/win32/kernel32/client/dllmain.c b/dll/win32/kernel32/client/dllmain.c index 04421291ac4..09aa3c0120d 100644 --- a/dll/win32/kernel32/client/dllmain.c +++ b/dll/win32/kernel32/client/dllmain.c @@ -200,7 +200,7 @@ DllMain(HANDLE hDll, } /* Initialize Console Support */ - if (!BasepInitConsole()) + if (!ConDllInitialize(dwReason, SessionDir)) { DPRINT1("Failed to set up console\n"); return FALSE; diff --git a/dll/win32/kernel32/client/proc.c b/dll/win32/kernel32/client/proc.c index 47bb1404509..e590f20ab2a 100644 --- a/dll/win32/kernel32/client/proc.c +++ b/dll/win32/kernel32/client/proc.c @@ -726,7 +726,7 @@ BasePushProcessParameters(IN ULONG ParameterFlags, ProcessParameters->StandardError = StartupInfo->hStdError; } - /* Use Special Flags for BasepInitConsole in Kernel32 */ + /* Use Special Flags for ConDllInitialize in Kernel32 */ if (CreationFlags & DETACHED_PROCESS) { ProcessParameters->ConsoleHandle = HANDLE_DETACHED_PROCESS; diff --git a/dll/win32/kernel32/include/console.h b/dll/win32/kernel32/include/console.h index 1886608e88e..d21fec09971 100644 --- a/dll/win32/kernel32/include/console.h +++ b/dll/win32/kernel32/include/console.h @@ -10,26 +10,35 @@ /* CONSTANTS ******************************************************************/ -#define HANDLE_DETACHED_PROCESS (HANDLE)-2 -#define HANDLE_CREATE_NEW_CONSOLE (HANDLE)-3 -#define HANDLE_CREATE_NO_WINDOW (HANDLE)-4 +#define HANDLE_DETACHED_PROCESS (HANDLE)-1 +#define HANDLE_CREATE_NEW_CONSOLE (HANDLE)-2 +#define HANDLE_CREATE_NO_WINDOW (HANDLE)-3 + +// Enable (and then get rid of) this define when support for +// console initialization handles is implemented in CONSRV. +// #define USE_CONSOLE_INIT_HANDLES /* FUNCTION PROTOTYPES ********************************************************/ -BOOL WINAPI -BasepInitConsole(VOID); +BOOLEAN +WINAPI +ConDllInitialize(IN ULONG Reason, + IN PWSTR SessionDir); -VOID WINAPI +VOID +WINAPI BasepUninitConsole(VOID); -VOID WINAPI -InitConsoleCtrlHandling(VOID); +VOID +InitializeCtrlHandling(VOID); -DWORD WINAPI +DWORD +WINAPI ConsoleControlDispatcher(IN LPVOID lpThreadParameter); -DWORD WINAPI +DWORD +WINAPI PropDialogHandler(IN LPVOID lpThreadParameter); HANDLE WINAPI @@ -59,9 +68,32 @@ GetConsoleInputWaitHandle(VOID); HANDLE TranslateStdHandle(HANDLE hHandle); +#define SetTEBLangID(p) (p) + VOID -InitConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo, - IN PUNICODE_STRING ImagePathName); +SetUpConsoleInfo(IN BOOLEAN CaptureTitle, + IN OUT LPDWORD pTitleLength, + IN OUT LPWSTR* lpTitle OPTIONAL, + IN OUT LPDWORD pDesktopLength, + IN OUT LPWSTR* lpDesktop OPTIONAL, + IN OUT PCONSOLE_START_INFO ConsoleStartInfo); + +VOID +SetUpHandles(IN PCONSOLE_START_INFO ConsoleStartInfo); + +VOID +InitExeName(VOID); + +VOID +SetUpAppName(IN BOOLEAN CaptureStrings, + IN OUT LPDWORD CurDirLength, + IN OUT LPWSTR* CurDir, + IN OUT LPDWORD AppNameLength, + IN OUT LPWSTR* AppName); + +USHORT +GetCurrentExeName(OUT PWCHAR ExeName, + IN USHORT BufferSize); LPCWSTR IntCheckForConsoleFileName(IN LPCWSTR pszName, @@ -73,7 +105,4 @@ OpenConsoleW(LPCWSTR wsName, BOOL bInheritHandle, DWORD dwShareMode); -BOOL WINAPI -SetConsoleInputExeNameW(LPCWSTR lpInputExeName); - /* EOF */ diff --git a/include/reactos/subsys/win/conmsg.h b/include/reactos/subsys/win/conmsg.h index 9bb3d7c2724..42d83987d7f 100644 --- a/include/reactos/subsys/win/conmsg.h +++ b/include/reactos/subsys/win/conmsg.h @@ -119,6 +119,13 @@ typedef enum _CONSRV_API_NUMBER // typedef struct _CONSOLE_PROPERTIES { + INT IconIndex; + HICON hIcon; + HICON hIconSm; + DWORD dwHotKey; + DWORD dwStartupFlags; + + // NT_CONSOLE_PROPS WORD wFillAttribute; WORD wPopupFillAttribute; @@ -134,62 +141,60 @@ typedef struct _CONSOLE_PROPERTIES DWORD nFont; DWORD nInputBufferSize; COORD dwFontSize; - UINT uFontFamily; - UINT uFontWeight; + UINT uFontFamily; + UINT uFontWeight; WCHAR FaceName[LF_FACESIZE]; - UINT uCursorSize; - BOOL bFullScreen; - BOOL bQuickEdit; - BOOL bInsertMode; - BOOL bAutoPosition; - UINT uHistoryBufferSize; - UINT uNumberOfHistoryBuffers; - BOOL bHistoryNoDup; + UINT uCursorSize; + BOOL bFullScreen; + BOOL bQuickEdit; + BOOL bInsertMode; + BOOL bAutoPosition; + UINT uHistoryBufferSize; + UINT uNumberOfHistoryBuffers; + BOOL bHistoryNoDup; COLORREF ColorTable[16]; - //NT_FE_CONSOLE_PROPS + // NT_FE_CONSOLE_PROPS UINT uCodePage; } CONSOLE_PROPERTIES; -// -// To minimize code changes, some fields were put here even though they really only belong in -// CONSRV_API_CONNECTINFO. Do not change the ordering however, as it's required for Windows -// compatibility. -// typedef struct _CONSOLE_START_INFO -{ - INT IconIndex; - HICON IconHandle1; - HICON IconHandle2; - DWORD dwHotKey; - DWORD dwStartupFlags; - CONSOLE_PROPERTIES; - - BOOLEAN ConsoleNeeded; // Used for GUI apps only. - LPTHREAD_START_ROUTINE CtrlDispatcher; - LPTHREAD_START_ROUTINE ImeDispatcher; - LPTHREAD_START_ROUTINE PropDispatcher; - ULONG TitleLength; - WCHAR ConsoleTitle[MAX_PATH + 1]; // Console title or full path to the startup shortcut - ULONG DesktopLength; - PWCHAR DesktopPath; - ULONG AppNameLength; - WCHAR AppPath[128]; // Full path of the launched app - ULONG IconPathLength; - WCHAR IconPath[MAX_PATH + 1]; // Path to the file containing the icon -} CONSOLE_START_INFO, *PCONSOLE_START_INFO; - -typedef struct _CONSRV_API_CONNECTINFO { HANDLE ConsoleHandle; HANDLE InputWaitHandle; HANDLE InputHandle; HANDLE OutputHandle; HANDLE ErrorHandle; - HANDLE Event1; - HANDLE Event2; - /* Adapted from CONSOLE_ALLOCCONSOLE */ + HANDLE Events[2]; + + CONSOLE_PROPERTIES; +} CONSOLE_START_INFO, *PCONSOLE_START_INFO; + +#if defined(_M_IX86) +C_ASSERT(sizeof(CONSOLE_START_INFO) == 0xFC); +#endif + +typedef struct _CONSRV_API_CONNECTINFO +{ CONSOLE_START_INFO ConsoleStartInfo; + + BOOLEAN IsConsoleApp; + BOOLEAN IsWindowVisible; + + // USHORT Padding; + + LPTHREAD_START_ROUTINE CtrlRoutine; + LPTHREAD_START_ROUTINE PropRoutine; + LPTHREAD_START_ROUTINE ImeRoutine; + + ULONG TitleLength; + WCHAR ConsoleTitle[MAX_PATH + 1]; // Console title or full path to the startup shortcut + ULONG DesktopLength; + PWCHAR Desktop; + ULONG AppNameLength; + WCHAR AppName[128]; // Full path of the launched app + ULONG CurDirLength; + WCHAR CurDir[MAX_PATH + 1]; } CONSRV_API_CONNECTINFO, *PCONSRV_API_CONNECTINFO; #if defined(_M_IX86) @@ -259,25 +264,31 @@ typedef struct _CONSOLE_ALLOCCONSOLE { PCONSOLE_START_INFO ConsoleStartInfo; - HANDLE ConsoleHandle; - HANDLE InputHandle; - HANDLE OutputHandle; - HANDLE ErrorHandle; - HANDLE InputWaitHandle; - LPTHREAD_START_ROUTINE CtrlDispatcher; - LPTHREAD_START_ROUTINE PropDispatcher; + ULONG TitleLength; + PWCHAR ConsoleTitle; // Console title or full path to the startup shortcut + ULONG DesktopLength; + PWCHAR Desktop; + ULONG AppNameLength; + PWCHAR AppName; // Full path of the launched app + ULONG CurDirLength; + PWCHAR CurDir; + + LPTHREAD_START_ROUTINE CtrlRoutine; + LPTHREAD_START_ROUTINE PropRoutine; } CONSOLE_ALLOCCONSOLE, *PCONSOLE_ALLOCCONSOLE; typedef struct _CONSOLE_ATTACHCONSOLE { - DWORD ProcessId; // If ProcessId == ATTACH_PARENT_PROCESS == -1, then attach the current process to its parent process console. - HANDLE ConsoleHandle; - HANDLE InputHandle; - HANDLE OutputHandle; - HANDLE ErrorHandle; - HANDLE InputWaitHandle; - LPTHREAD_START_ROUTINE CtrlDispatcher; - LPTHREAD_START_ROUTINE PropDispatcher; + /* + * If ProcessId == ATTACH_PARENT_PROCESS == -1, then attach + * the current process to its parent process console. + */ + DWORD ProcessId; + + PCONSOLE_START_INFO ConsoleStartInfo; + + LPTHREAD_START_ROUTINE CtrlRoutine; + LPTHREAD_START_ROUTINE PropRoutine; } CONSOLE_ATTACHCONSOLE, *PCONSOLE_ATTACHCONSOLE; typedef struct _CONSOLE_FREECONSOLE diff --git a/win32ss/user/winsrv/consrv/condrv/console.c b/win32ss/user/winsrv/consrv/condrv/console.c index 6e289a28f2a..4075e76f3a2 100644 --- a/win32ss/user/winsrv/consrv/condrv/console.c +++ b/win32ss/user/winsrv/consrv/condrv/console.c @@ -76,35 +76,6 @@ RemoveConsole(IN PCONSOLE Console) /* PRIVATE FUNCTIONS **********************************************************/ -// Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180 -static BOOLEAN -ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest, - IN PCWSTR Source) -{ - SIZE_T Size = (wcslen(Source) + 1) * sizeof(WCHAR); - if (Size > MAXUSHORT) return FALSE; - - UniDest->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size); - if (UniDest->Buffer == NULL) return FALSE; - - RtlCopyMemory(UniDest->Buffer, Source, Size); - UniDest->MaximumLength = (USHORT)Size; - UniDest->Length = (USHORT)Size - sizeof(WCHAR); - - return TRUE; -} - -// Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431 -static VOID -ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString) -{ - if (UnicodeString->Buffer) - { - ConsoleFreeHeap(UnicodeString->Buffer); - RtlZeroMemory(UnicodeString, sizeof(UNICODE_STRING)); - } -} - VOID NTAPI ConDrvPause(PCONSOLE Console) { @@ -194,9 +165,6 @@ ConDrvInitConsole(OUT PCONSOLE* NewConsole, TEXTMODE_BUFFER_INFO ScreenBufferInfo; PCONSOLE Console; PCONSOLE_SCREEN_BUFFER NewBuffer; -#if 0 - WCHAR DefaultTitle[128]; -#endif if (NewConsole == NULL || ConsoleInfo == NULL) return STATUS_INVALID_PARAMETER; @@ -272,28 +240,6 @@ ConDrvInitConsole(OUT PCONSOLE* NewConsole, Console->ActiveBuffer = NewBuffer; Console->UnpauseEvent = NULL; - /* Initialize the console title */ - ConsoleCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo->ConsoleTitle); -#if 0 - if (ConsoleInfo.ConsoleTitle[0] == L'\0') - { - if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, DefaultTitle, sizeof(DefaultTitle) / sizeof(DefaultTitle[0]))) - { - ConsoleCreateUnicodeString(&Console->Title, DefaultTitle); - } - else - { - ConsoleCreateUnicodeString(&Console->Title, L"ReactOS Console"); - } - } - else - { -#endif - ConsoleCreateUnicodeString(&Console->Title, ConsoleInfo->ConsoleTitle); -#if 0 - } -#endif - DPRINT("Console initialized\n"); /* All went right, so add the console to the list */ @@ -460,9 +406,6 @@ ConDrvDeleteConsole(IN PCONSOLE Console) if (Console->UnpauseEvent) CloseHandle(Console->UnpauseEvent); - ConsoleFreeUnicodeString(&Console->OriginalTitle); - ConsoleFreeUnicodeString(&Console->Title); - DPRINT("ConDrvDeleteConsole - Unlocking\n"); LeaveCriticalSection(&Console->Lock); DPRINT("ConDrvDeleteConsole - Destroying lock\n"); @@ -566,111 +509,6 @@ ConDrvSetConsoleMode(IN PCONSOLE Console, return Status; } -NTSTATUS NTAPI -ConDrvGetConsoleTitle(IN PCONSOLE Console, - IN BOOLEAN Unicode, - IN OUT PVOID TitleBuffer, - IN OUT PULONG BufLength) -{ - ULONG Length; - - if (Console == NULL || TitleBuffer == NULL || BufLength == NULL) - return STATUS_INVALID_PARAMETER; - - /* Copy title of the console to the user title buffer */ - if (Unicode) - { - if (*BufLength >= sizeof(WCHAR)) - { - Length = min(*BufLength - sizeof(WCHAR), Console->Title.Length); - RtlCopyMemory(TitleBuffer, Console->Title.Buffer, Length); - ((PWCHAR)TitleBuffer)[Length / sizeof(WCHAR)] = L'\0'; - *BufLength = Length; - } - else - { - *BufLength = Console->Title.Length; - } - } - else - { - if (*BufLength >= sizeof(CHAR)) - { - Length = min(*BufLength - sizeof(CHAR), Console->Title.Length / sizeof(WCHAR)); - Length = WideCharToMultiByte(Console->InputCodePage, 0, - Console->Title.Buffer, Length, - TitleBuffer, Length, - NULL, NULL); - ((PCHAR)TitleBuffer)[Length] = '\0'; - *BufLength = Length; - } - else - { - *BufLength = Console->Title.Length / sizeof(WCHAR); - } - } - - return STATUS_SUCCESS; -} - -NTSTATUS NTAPI -ConDrvSetConsoleTitle(IN PCONSOLE Console, - IN BOOLEAN Unicode, - IN PVOID TitleBuffer, - IN ULONG BufLength) -{ - PWCHAR Buffer; - ULONG Length; - - if (Console == NULL || TitleBuffer == NULL) - return STATUS_INVALID_PARAMETER; - - if (Unicode) - { - /* Length is in bytes */ - Length = BufLength; - } - else - { - /* Use the console input CP for the conversion */ - Length = MultiByteToWideChar(Console->InputCodePage, 0, - TitleBuffer, BufLength, - NULL, 0); - /* The returned Length was in number of wchars, convert it in bytes */ - Length *= sizeof(WCHAR); - } - - /* Allocate a new buffer to hold the new title (NULL-terminated) */ - Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Length + sizeof(WCHAR)); - if (!Buffer) return STATUS_NO_MEMORY; - - /* Free the old title */ - ConsoleFreeUnicodeString(&Console->Title); - - /* Copy title to console */ - Console->Title.Buffer = Buffer; - Console->Title.Length = Length; - Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR); - - if (Unicode) - { - RtlCopyMemory(Console->Title.Buffer, TitleBuffer, Console->Title.Length); - } - else - { - MultiByteToWideChar(Console->InputCodePage, 0, - TitleBuffer, BufLength, - Console->Title.Buffer, - Console->Title.Length / sizeof(WCHAR)); - } - - /* NULL-terminate */ - Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0'; - - // TermChangeTitle(Console); - return STATUS_SUCCESS; -} - NTSTATUS NTAPI ConDrvGetConsoleCP(IN PCONSOLE Console, OUT PUINT CodePage, diff --git a/win32ss/user/winsrv/consrv/condrv/dummyterm.c b/win32ss/user/winsrv/consrv/condrv/dummyterm.c index 2b612324489..2066cb54ee4 100644 --- a/win32ss/user/winsrv/consrv/condrv/dummyterm.c +++ b/win32ss/user/winsrv/consrv/condrv/dummyterm.c @@ -108,11 +108,6 @@ DummyReleaseScreenBuffer(IN OUT PTERMINAL This, { } -static VOID NTAPI -DummyChangeTitle(IN OUT PTERMINAL This) -{ -} - static VOID NTAPI DummyGetLargestConsoleWindowSize(IN OUT PTERMINAL This, PCOORD pSize) @@ -148,7 +143,6 @@ static TERMINAL_VTBL DummyVtbl = DummyResizeTerminal, DummySetActiveScreenBuffer, DummyReleaseScreenBuffer, - DummyChangeTitle, DummyGetLargestConsoleWindowSize, DummySetPalette, DummyShowMouseCursor, diff --git a/win32ss/user/winsrv/consrv/console.c b/win32ss/user/winsrv/consrv/console.c index dcade22cc32..fc0c8cdedf3 100644 --- a/win32ss/user/winsrv/consrv/console.c +++ b/win32ss/user/winsrv/consrv/console.c @@ -14,6 +14,11 @@ #include +/* This is for COM usage */ +#define COBJMACROS +#include + + #include #include #include "procinit.h" @@ -209,6 +214,35 @@ ConSrvValidateConsole(OUT PCONSRV_CONSOLE* Console, /* PRIVATE FUNCTIONS **********************************************************/ +// Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180 +static BOOLEAN +ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest, + IN PCWSTR Source) +{ + SIZE_T Size = (wcslen(Source) + 1) * sizeof(WCHAR); + if (Size > MAXUSHORT) return FALSE; + + UniDest->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size); + if (UniDest->Buffer == NULL) return FALSE; + + RtlCopyMemory(UniDest->Buffer, Source, Size); + UniDest->MaximumLength = (USHORT)Size; + UniDest->Length = (USHORT)Size - sizeof(WCHAR); + + return TRUE; +} + +// Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431 +static VOID +ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString) +{ + if (UnicodeString->Buffer) + { + ConsoleFreeHeap(UnicodeString->Buffer); + RtlZeroMemory(UnicodeString, sizeof(UNICODE_STRING)); + } +} + VOID ConioPause(PCONSRV_CONSOLE Console, UINT Flags) { @@ -317,10 +351,157 @@ ConSrvInitTerminal(IN OUT PTERMINAL Terminal, NTSTATUS NTAPI ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal); + +static BOOL +LoadShellLinkConsoleInfo(IN OUT PCONSOLE_INFO ConsoleInfo, + IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo) +{ +#define PATH_SEPARATOR L'\\' + + BOOL RetVal = FALSE; + HRESULT hRes = S_OK; + SIZE_T Length = 0; + LPWSTR LinkName = NULL; + LPWSTR IconPath = NULL; + WCHAR Buffer[MAX_PATH + 1]; + + ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0; + + if ((ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) + { + // return FALSE; // FIXME!! (for icon loading) + RetVal = TRUE; + goto Finish; + } + + /* 1- Find the last path separator if any */ + LinkName = wcsrchr(ConsoleInfo->ConsoleTitle, PATH_SEPARATOR); + if (LinkName == NULL) + LinkName = ConsoleInfo->ConsoleTitle; + else + ++LinkName; // Skip the path separator + + /* 2- Check for the link extension. The name ".lnk" is considered invalid. */ + Length = wcslen(LinkName); + if ( (Length <= 4) || (wcsicmp(LinkName + (Length - 4), L".lnk") != 0) ) + return FALSE; + + /* 3- It may be a link. Try to retrieve some properties */ + hRes = CoInitialize(NULL); + if (SUCCEEDED(hRes)) + { + /* Get a pointer to the IShellLink interface */ + IShellLinkW* pshl = NULL; + hRes = CoCreateInstance(&CLSID_ShellLink, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IShellLinkW, + (LPVOID*)&pshl); + if (SUCCEEDED(hRes)) + { + /* Get a pointer to the IPersistFile interface */ + IPersistFile* ppf = NULL; + hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf); + if (SUCCEEDED(hRes)) + { + /* Load the shortcut */ + hRes = IPersistFile_Load(ppf, ConsoleInfo->ConsoleTitle, STGM_READ); + if (SUCCEEDED(hRes)) + { + /* + * Finally we can get the properties ! + * Update the old ones if needed. + */ + INT ShowCmd = 0; + // WORD HotKey = 0; + + /* Reset the name of the console with the name of the shortcut */ + Length = min(/*Length*/ Length - 4, // 4 == len(".lnk") + sizeof(ConsoleInfo->ConsoleTitle) / sizeof(ConsoleInfo->ConsoleTitle[0]) - 1); + wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length); + ConsoleInfo->ConsoleTitle[Length] = L'\0'; + + /* Get the window showing command */ + hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd); + if (SUCCEEDED(hRes)) ConsoleInitInfo->ConsoleStartInfo->wShowWindow = (WORD)ShowCmd; + + /* Get the hotkey */ + // hRes = pshl->GetHotkey(&ShowCmd); + // if (SUCCEEDED(hRes)) ConsoleInitInfo->ConsoleStartInfo->HotKey = HotKey; + + /* Get the icon location, if any */ + hRes = IShellLinkW_GetIconLocation(pshl, + Buffer, + sizeof(Buffer)/sizeof(Buffer[0]) - 1, // == MAX_PATH + &ConsoleInitInfo->ConsoleStartInfo->IconIndex); + if (!SUCCEEDED(hRes)) + { + ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0; + } + else + { + IconPath = Buffer; + } + + // FIXME: Since we still don't load console properties from the shortcut, + // return false. When this will be done, we will return true instead. + RetVal = TRUE; // FALSE; + } + IPersistFile_Release(ppf); + } + IShellLinkW_Release(pshl); + } + } + CoUninitialize(); + +Finish: + + if (RetVal) + { + /* Get the associated icon, if any */ + if (IconPath == NULL) + { + // Question: How to retrieve the full path name + // of the app we are going to run?? + Length = RtlDosSearchPath_U(ConsoleInitInfo->CurDir, + ConsoleInitInfo->AppName, + NULL, + sizeof(Buffer), + Buffer, + NULL); + if (Length > 0 && Length < sizeof(Buffer)) + IconPath = Buffer; + else + IconPath = ConsoleInitInfo->AppName; + + // ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0; + } + DPRINT1("IconPath = '%S' ; IconIndex = %lu\n", + IconPath, ConsoleInitInfo->ConsoleStartInfo->IconIndex); + if (IconPath && *IconPath) + { + HICON hIcon = NULL, hIconSm = NULL; + PrivateExtractIconExW(IconPath, + ConsoleInitInfo->ConsoleStartInfo->IconIndex, + &hIcon, + &hIconSm, + 1); + DPRINT1("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm); + if (hIcon != NULL) ConsoleInitInfo->ConsoleStartInfo->hIcon = hIcon; + if (hIconSm != NULL) ConsoleInitInfo->ConsoleStartInfo->hIconSm = hIconSm; + } + } + + // FIXME: See the previous FIXME above. + RetVal = FALSE; + + return RetVal; +} + NTSTATUS NTAPI ConSrvInitConsole(OUT PHANDLE NewConsoleHandle, OUT PCONSRV_CONSOLE* NewConsole, - IN OUT PCONSOLE_START_INFO ConsoleStartInfo, + IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, IN ULONG ConsoleLeaderProcessId) { NTSTATUS Status; @@ -331,7 +512,7 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle, TERMINAL Terminal; /* The ConSrv terminal for this console */ - if (NewConsole == NULL || ConsoleStartInfo == NULL) + if (NewConsole == NULL || ConsoleInitInfo == NULL) return STATUS_INVALID_PARAMETER; *NewConsole = NULL; @@ -344,15 +525,15 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle, ConSrvGetDefaultSettings(&ConsoleInfo, ConsoleLeaderProcessId); /* 2. Get the title of the console (initialize ConsoleInfo.ConsoleTitle) */ - Length = min(wcslen(ConsoleStartInfo->ConsoleTitle), + Length = min(ConsoleInitInfo->TitleLength, sizeof(ConsoleInfo.ConsoleTitle) / sizeof(ConsoleInfo.ConsoleTitle[0]) - 1); - wcsncpy(ConsoleInfo.ConsoleTitle, ConsoleStartInfo->ConsoleTitle, Length); - ConsoleInfo.ConsoleTitle[Length] = L'\0'; + wcsncpy(ConsoleInfo.ConsoleTitle, ConsoleInitInfo->ConsoleTitle, Length); + ConsoleInfo.ConsoleTitle[Length] = L'\0'; // NULL-terminate it. /* 3. Initialize the ConSrv terminal */ Status = ConSrvInitTerminal(&Terminal, &ConsoleInfo, - ConsoleStartInfo, + ConsoleInitInfo, ConsoleLeaderProcessId); if (!NT_SUCCESS(Status)) { @@ -361,10 +542,25 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle, } DPRINT("CONSRV: Terminal initialized\n"); + /* + * Load per-application terminal settings. + * + * Check whether the process creating the console was launched via + * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the + * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too. + */ + // if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) // FIXME!! (for icon loading) + { + if (!LoadShellLinkConsoleInfo(&ConsoleInfo, ConsoleInitInfo)) + { + ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME; + } + } + /* * 4. Load the remaining console settings via the registry. */ - if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) + if ((ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) { /* * Either we weren't created by an app launched via a shell-link, @@ -379,17 +575,17 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle, * (and which was transmitted via the ConsoleStartInfo structure). * We therefore overwrite the values read in the registry. */ - if (ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE) + if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE) { - ConsoleInfo.ScreenAttrib = (USHORT)ConsoleStartInfo->wFillAttribute; + ConsoleInfo.ScreenAttrib = (USHORT)ConsoleInitInfo->ConsoleStartInfo->wFillAttribute; } - if (ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS) + if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS) { - ConsoleInfo.ScreenBufferSize = ConsoleStartInfo->dwScreenBufferSize; + ConsoleInfo.ScreenBufferSize = ConsoleInitInfo->ConsoleStartInfo->dwScreenBufferSize; } - if (ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE) + if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE) { - ConsoleInfo.ConsoleSize = ConsoleStartInfo->dwWindowSize; + ConsoleInfo.ConsoleSize = ConsoleInitInfo->ConsoleStartInfo->dwWindowSize; } } @@ -410,6 +606,31 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle, /*** Register ConSrv features ***/ + /* Initialize the console title */ +#if 0 + WCHAR DefaultTitle[128]; +#endif + ConsoleCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo.ConsoleTitle); +#if 0 + if (ConsoleInfo.ConsoleTitle[0] == L'\0') + { + if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, DefaultTitle, sizeof(DefaultTitle) / sizeof(DefaultTitle[0]))) + { + ConsoleCreateUnicodeString(&Console->Title, DefaultTitle); + } + else + { + ConsoleCreateUnicodeString(&Console->Title, L"ReactOS Console"); + } + } + else + { +#endif + ConsoleCreateUnicodeString(&Console->Title, ConsoleInfo.ConsoleTitle); +#if 0 + } +#endif + /* Initialize process support */ InitializeListHead(&Console->ProcessList); Console->NotifiedLastCloseProcess = NULL; @@ -482,6 +703,10 @@ ConSrvDeleteConsole(PCONSRV_CONSOLE Console) IntDeleteAllAliases(Console); HistoryDeleteBuffers(Console); + /* Free the console title */ + ConsoleFreeUnicodeString(&Console->OriginalTitle); + ConsoleFreeUnicodeString(&Console->Title); + /* Now, call the driver. ConDrvDeregisterTerminal is called on-demand. */ ConDrvDeleteConsole((PCONSOLE)Console); @@ -504,7 +729,7 @@ ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent, DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess); - if (ProcessData->CtrlDispatcher) + if (ProcessData->CtrlRoutine) { _SEH2_TRY { @@ -513,7 +738,7 @@ ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent, _SEH2_TRY { Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0, - ProcessData->CtrlDispatcher, + ProcessData->CtrlRoutine, UlongToPtr(CtrlEvent), 0, NULL); if (NULL == Thread) { @@ -522,7 +747,8 @@ ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent, } else { - DPRINT("ProcessData->CtrlDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process); + DPRINT("ProcessData->CtrlRoutine remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", + ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process); WaitForSingleObject(Thread, Timeout); } } @@ -628,9 +854,6 @@ ConSrvConsoleProcessCtrlEvent(IN PCONSRV_CONSOLE Console, } - - - /* PUBLIC SERVER APIS *********************************************************/ CSR_API(SrvAllocConsole) @@ -639,6 +862,7 @@ CSR_API(SrvAllocConsole) PCONSOLE_ALLOCCONSOLE AllocConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AllocConsoleRequest; PCSR_PROCESS CsrProcess = CsrGetClientThread()->Process; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess); + CONSOLE_INIT_INFO ConsoleInitInfo; if (ProcessData->ConsoleHandle != NULL) { @@ -646,33 +870,64 @@ CSR_API(SrvAllocConsole) return STATUS_ACCESS_DENIED; } - if (!CsrValidateMessageBuffer(ApiMessage, - (PVOID*)&AllocConsoleRequest->ConsoleStartInfo, - 1, - sizeof(CONSOLE_START_INFO))) + if ( !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&AllocConsoleRequest->ConsoleStartInfo, + 1, + sizeof(CONSOLE_START_INFO)) || + !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&AllocConsoleRequest->ConsoleTitle, + AllocConsoleRequest->TitleLength, + sizeof(BYTE)) || + !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&AllocConsoleRequest->Desktop, + AllocConsoleRequest->DesktopLength, + sizeof(BYTE)) || + !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&AllocConsoleRequest->CurDir, + AllocConsoleRequest->CurDirLength, + sizeof(BYTE)) || + !CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&AllocConsoleRequest->AppName, + AllocConsoleRequest->AppNameLength, + sizeof(BYTE)) ) { return STATUS_INVALID_PARAMETER; } + /* Initialize the console initialization info structure */ + ConsoleInitInfo.ConsoleStartInfo = AllocConsoleRequest->ConsoleStartInfo; + ConsoleInitInfo.TitleLength = AllocConsoleRequest->TitleLength; + ConsoleInitInfo.ConsoleTitle = AllocConsoleRequest->ConsoleTitle; + ConsoleInitInfo.DesktopLength = AllocConsoleRequest->DesktopLength; + ConsoleInitInfo.Desktop = AllocConsoleRequest->Desktop; + ConsoleInitInfo.AppNameLength = AllocConsoleRequest->AppNameLength; + ConsoleInitInfo.AppName = AllocConsoleRequest->AppName; + ConsoleInitInfo.CurDirLength = AllocConsoleRequest->CurDirLength; + ConsoleInitInfo.CurDir = AllocConsoleRequest->CurDir; + /* Initialize a new Console owned by the Console Leader Process */ Status = ConSrvAllocateConsole(ProcessData, - &AllocConsoleRequest->InputHandle, - &AllocConsoleRequest->OutputHandle, - &AllocConsoleRequest->ErrorHandle, - AllocConsoleRequest->ConsoleStartInfo); + &AllocConsoleRequest->ConsoleStartInfo->InputHandle, + &AllocConsoleRequest->ConsoleStartInfo->OutputHandle, + &AllocConsoleRequest->ConsoleStartInfo->ErrorHandle, + &ConsoleInitInfo); if (!NT_SUCCESS(Status)) { DPRINT1("Console allocation failed\n"); return Status; } + /* Mark the process as having a console */ + ProcessData->ConsoleApp = TRUE; + CsrProcess->Flags |= CsrProcessIsConsoleApp; + /* Return the console handle and the input wait handle to the caller */ - AllocConsoleRequest->ConsoleHandle = ProcessData->ConsoleHandle; - AllocConsoleRequest->InputWaitHandle = ProcessData->InputWaitHandle; + AllocConsoleRequest->ConsoleStartInfo->ConsoleHandle = ProcessData->ConsoleHandle; + AllocConsoleRequest->ConsoleStartInfo->InputWaitHandle = ProcessData->InputWaitHandle; /* Set the Property-Dialog and Control-Dispatcher handlers */ - ProcessData->PropDispatcher = AllocConsoleRequest->PropDispatcher; - ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher; + ProcessData->PropRoutine = AllocConsoleRequest->PropRoutine; + ProcessData->CtrlRoutine = AllocConsoleRequest->CtrlRoutine; return STATUS_SUCCESS; } @@ -694,6 +949,14 @@ CSR_API(SrvAttachConsole) return STATUS_ACCESS_DENIED; } + if (!CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&AttachConsoleRequest->ConsoleStartInfo, + 1, + sizeof(CONSOLE_START_INFO))) + { + return STATUS_INVALID_PARAMETER; + } + /* Check whether we try to attach to the parent's console */ if (ProcessId == ULongToHandle(ATTACH_PARENT_PROCESS)) { @@ -734,22 +997,26 @@ CSR_API(SrvAttachConsole) Status = ConSrvInheritConsole(TargetProcessData, SourceProcessData->ConsoleHandle, TRUE, - &AttachConsoleRequest->InputHandle, - &AttachConsoleRequest->OutputHandle, - &AttachConsoleRequest->ErrorHandle); + &AttachConsoleRequest->ConsoleStartInfo->InputHandle, + &AttachConsoleRequest->ConsoleStartInfo->OutputHandle, + &AttachConsoleRequest->ConsoleStartInfo->ErrorHandle); if (!NT_SUCCESS(Status)) { DPRINT1("Console inheritance failed\n"); goto Quit; } + /* Mark the process as having a console */ + TargetProcessData->ConsoleApp = TRUE; + TargetProcess->Flags |= CsrProcessIsConsoleApp; + /* Return the console handle and the input wait handle to the caller */ - AttachConsoleRequest->ConsoleHandle = TargetProcessData->ConsoleHandle; - AttachConsoleRequest->InputWaitHandle = TargetProcessData->InputWaitHandle; + AttachConsoleRequest->ConsoleStartInfo->ConsoleHandle = TargetProcessData->ConsoleHandle; + AttachConsoleRequest->ConsoleStartInfo->InputWaitHandle = TargetProcessData->InputWaitHandle; /* Set the Property-Dialog and Control-Dispatcher handlers */ - TargetProcessData->PropDispatcher = AttachConsoleRequest->PropDispatcher; - TargetProcessData->CtrlDispatcher = AttachConsoleRequest->CtrlDispatcher; + TargetProcessData->PropRoutine = AttachConsoleRequest->PropRoutine; + TargetProcessData->CtrlRoutine = AttachConsoleRequest->CtrlRoutine; Status = STATUS_SUCCESS; @@ -761,7 +1028,15 @@ Quit: CSR_API(SrvFreeConsole) { + PCSR_PROCESS CsrProcess = CsrGetClientThread()->Process; + PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess); + ConSrvRemoveConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process)); + + /* Mark the process as not having a console anymore */ + ProcessData->ConsoleApp = FALSE; + CsrProcess->Flags &= ~CsrProcessIsConsoleApp; + return STATUS_SUCCESS; } @@ -865,16 +1140,12 @@ CSR_API(SrvSetConsoleMode) return Status; } -NTSTATUS NTAPI -ConDrvGetConsoleTitle(IN PCONSOLE Console, - IN BOOLEAN Unicode, - IN OUT PVOID TitleBuffer, - IN OUT PULONG BufLength); CSR_API(SrvGetConsoleTitle) { NTSTATUS Status; PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest; PCONSRV_CONSOLE Console; + ULONG Length; if (!CsrValidateMessageBuffer(ApiMessage, (PVOID)&TitleRequest->Title, @@ -891,26 +1162,52 @@ CSR_API(SrvGetConsoleTitle) return Status; } - Status = ConDrvGetConsoleTitle(Console, - TitleRequest->Unicode, - TitleRequest->Title, - &TitleRequest->Length); + /* Copy title of the console to the user title buffer */ + if (TitleRequest->Unicode) + { + if (TitleRequest->Length >= sizeof(WCHAR)) + { + Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length); + RtlCopyMemory(TitleRequest->Title, Console->Title.Buffer, Length); + ((PWCHAR)TitleRequest->Title)[Length / sizeof(WCHAR)] = L'\0'; + TitleRequest->Length = Length; + } + else + { + TitleRequest->Length = Console->Title.Length; + } + } + else + { + if (TitleRequest->Length >= sizeof(CHAR)) + { + Length = min(TitleRequest->Length - sizeof(CHAR), Console->Title.Length / sizeof(WCHAR)); + Length = WideCharToMultiByte(Console->InputCodePage, 0, + Console->Title.Buffer, Length, + TitleRequest->Title, Length, + NULL, NULL); + ((PCHAR)TitleRequest->Title)[Length] = '\0'; + TitleRequest->Length = Length; + } + else + { + TitleRequest->Length = Console->Title.Length / sizeof(WCHAR); + } + } ConSrvReleaseConsole(Console, TRUE); return Status; } -NTSTATUS NTAPI -ConDrvSetConsoleTitle(IN PCONSOLE Console, - IN BOOLEAN Unicode, - IN PVOID TitleBuffer, - IN ULONG BufLength); CSR_API(SrvSetConsoleTitle) { NTSTATUS Status; PCONSOLE_GETSETCONSOLETITLE TitleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.TitleRequest; PCONSRV_CONSOLE Console; + PWCHAR Buffer; + ULONG Length; + if (!CsrValidateMessageBuffer(ApiMessage, (PVOID)&TitleRequest->Title, TitleRequest->Length, @@ -926,13 +1223,56 @@ CSR_API(SrvSetConsoleTitle) return Status; } - Status = ConDrvSetConsoleTitle(Console, - TitleRequest->Unicode, - TitleRequest->Title, - TitleRequest->Length); - // FIXME: Keep this call here, or put it in ConDrvSetConsoleTitle ?? - if (NT_SUCCESS(Status)) TermChangeTitle(Console); + if (TitleRequest->Unicode) + { + /* Length is in bytes */ + Length = TitleRequest->Length; + } + else + { + /* Use the console input CP for the conversion */ + Length = MultiByteToWideChar(Console->InputCodePage, 0, + TitleRequest->Title, TitleRequest->Length, + NULL, 0); + /* The returned Length was in number of wchars, convert it in bytes */ + Length *= sizeof(WCHAR); + } + /* Allocate a new buffer to hold the new title (NULL-terminated) */ + Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Length + sizeof(WCHAR)); + if (!Buffer) + { + Status = STATUS_NO_MEMORY; + goto Quit; + } + + /* Free the old title */ + ConsoleFreeUnicodeString(&Console->Title); + + /* Copy title to console */ + Console->Title.Buffer = Buffer; + Console->Title.Length = Length; + Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR); + + if (TitleRequest->Unicode) + { + RtlCopyMemory(Console->Title.Buffer, TitleRequest->Title, Console->Title.Length); + } + else + { + MultiByteToWideChar(Console->InputCodePage, 0, + TitleRequest->Title, TitleRequest->Length, + Console->Title.Buffer, + Console->Title.Length / sizeof(WCHAR)); + } + + /* NULL-terminate */ + Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = L'\0'; + + TermChangeTitle(Console); + Status = STATUS_SUCCESS; + +Quit: ConSrvReleaseConsole(Console, TRUE); return Status; } diff --git a/win32ss/user/winsrv/consrv/console.h b/win32ss/user/winsrv/consrv/console.h index c70341ce74c..7118dffb327 100644 --- a/win32ss/user/winsrv/consrv/console.h +++ b/win32ss/user/winsrv/consrv/console.h @@ -8,13 +8,27 @@ #pragma once +typedef struct _CONSOLE_INIT_INFO +{ + PCONSOLE_START_INFO ConsoleStartInfo; + + ULONG TitleLength; + PWCHAR ConsoleTitle; + ULONG DesktopLength; + PWCHAR Desktop; + ULONG AppNameLength; + PWCHAR AppName; + ULONG CurDirLength; + PWCHAR CurDir; +} CONSOLE_INIT_INFO, *PCONSOLE_INIT_INFO; + VOID NTAPI ConSrvInitConsoleSupport(VOID); NTSTATUS NTAPI ConSrvInitConsole(OUT PHANDLE NewConsoleHandle, OUT struct _CONSRV_CONSOLE** /* PCONSRV_CONSOLE* */ NewConsole, - IN OUT PCONSOLE_START_INFO ConsoleStartInfo, + IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, IN ULONG ConsoleLeaderProcessId); VOID NTAPI ConSrvDeleteConsole(struct _CONSRV_CONSOLE* /* PCONSRV_CONSOLE */ Console); diff --git a/win32ss/user/winsrv/consrv/consrv.h b/win32ss/user/winsrv/consrv/consrv.h index 18aabfb405a..09b87fc81f5 100644 --- a/win32ss/user/winsrv/consrv/consrv.h +++ b/win32ss/user/winsrv/consrv/consrv.h @@ -51,10 +51,9 @@ typedef struct _CONSOLE_PROCESS_DATA { LIST_ENTRY ConsoleLink; PCSR_PROCESS Process; // Process owning this structure. - HANDLE InputWaitHandle; HANDLE ConsoleHandle; - HANDLE ParentConsoleHandle; + HANDLE InputWaitHandle; BOOLEAN ConsoleApp; // TRUE if it is a CUI app, FALSE otherwise. @@ -62,8 +61,9 @@ typedef struct _CONSOLE_PROCESS_DATA ULONG HandleTableSize; struct _CONSOLE_IO_HANDLE* /* PCONSOLE_IO_HANDLE */ HandleTable; // Length-varying table - LPTHREAD_START_ROUTINE CtrlDispatcher; - LPTHREAD_START_ROUTINE PropDispatcher; // We hold the property dialog handler there, till all the GUI thingie moves out from CSRSS. + LPTHREAD_START_ROUTINE CtrlRoutine; + LPTHREAD_START_ROUTINE PropRoutine; // We hold the property dialog handler there, till all the GUI thingie moves out from CSRSS. + // LPTHREAD_START_ROUTINE ImeRoutine; } CONSOLE_PROCESS_DATA, *PCONSOLE_PROCESS_DATA; diff --git a/win32ss/user/winsrv/consrv/frontends/gui/guisettings.c b/win32ss/user/winsrv/consrv/frontends/gui/guisettings.c index 0d83fafeffc..f7d67ef9cfc 100644 --- a/win32ss/user/winsrv/consrv/frontends/gui/guisettings.c +++ b/win32ss/user/winsrv/consrv/frontends/gui/guisettings.c @@ -372,7 +372,7 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData, } /* Start the properties dialog */ - if (ProcessData->PropDispatcher) + if (ProcessData->PropRoutine) { _SEH2_TRY { @@ -381,7 +381,7 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData, _SEH2_TRY { Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0, - ProcessData->PropDispatcher, + ProcessData->PropRoutine, (PVOID)hClientSection, 0, NULL); if (NULL == Thread) { @@ -389,7 +389,8 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData, } else { - DPRINT("ProcessData->PropDispatcher remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process); + DPRINT("ProcessData->PropRoutine remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n", + ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process); /// WaitForSingleObject(Thread, INFINITE); } } diff --git a/win32ss/user/winsrv/consrv/frontends/gui/guiterm.c b/win32ss/user/winsrv/consrv/frontends/gui/guiterm.c index 52f441a553e..261692eb289 100644 --- a/win32ss/user/winsrv/consrv/frontends/gui/guiterm.c +++ b/win32ss/user/winsrv/consrv/frontends/gui/guiterm.c @@ -13,9 +13,6 @@ #include -#define COBJMACROS -#include - #define NDEBUG #include @@ -405,9 +402,7 @@ GuiInitFrontEnd(IN OUT PFRONTEND This, PGUI_CONSOLE_DATA GuiData; GUI_CONSOLE_INFO TermInfo; - SIZE_T Length = 0; - LPWSTR IconPath = NULL; - INT IconIndex = 0; + SIZE_T Length = 0; if (This == NULL || Console == NULL || This->OldData == NULL) return STATUS_INVALID_PARAMETER; @@ -422,10 +417,6 @@ GuiInitFrontEnd(IN OUT PFRONTEND This, ConsoleInfo = GuiInitInfo->ConsoleInfo; ConsoleStartInfo = GuiInitInfo->ConsoleStartInfo; - IconPath = ConsoleStartInfo->IconPath; - IconIndex = ConsoleStartInfo->IconIndex; - - /* Terminal data allocation */ GuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(GUI_CONSOLE_DATA)); if (!GuiData) @@ -451,10 +442,10 @@ GuiInitFrontEnd(IN OUT PFRONTEND This, /* 1. Load the default settings */ GuiConsoleGetDefaultSettings(&TermInfo, GuiInitInfo->ProcessId); - /* 3. Load the remaining console settings via the registry. */ + /* 3. Load the remaining console settings via the registry */ if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) { - /* Load the terminal infos from the registry. */ + /* Load the terminal infos from the registry */ GuiConsoleReadUserSettings(&TermInfo, ConsoleInfo->ConsoleTitle, GuiInitInfo->ProcessId); @@ -500,29 +491,17 @@ GuiInitFrontEnd(IN OUT PFRONTEND This, GuiData->GuiInfo.AutoPosition = TermInfo.AutoPosition; GuiData->GuiInfo.WindowOrigin = TermInfo.WindowOrigin; - /* Initialize the icon handles to their default values */ - GuiData->hIcon = ghDefaultIcon; - GuiData->hIconSm = ghDefaultIconSm; + /* Initialize the icon handles */ + if (ConsoleStartInfo->hIcon != NULL) + GuiData->hIcon = ConsoleStartInfo->hIcon; + else + GuiData->hIcon = ghDefaultIcon; + + if (ConsoleStartInfo->hIconSm != NULL) + GuiData->hIconSm = ConsoleStartInfo->hIconSm; + else + GuiData->hIconSm = ghDefaultIconSm; - /* Get the associated icon, if any */ - if (IconPath == NULL || IconPath[0] == L'\0') - { - IconPath = ConsoleStartInfo->AppPath; - IconIndex = 0; - } - DPRINT("IconPath = %S ; IconIndex = %lu\n", (IconPath ? IconPath : L"n/a"), IconIndex); - if (IconPath && IconPath[0] != L'\0') - { - HICON hIcon = NULL, hIconSm = NULL; - PrivateExtractIconExW(IconPath, - IconIndex, - &hIcon, - &hIconSm, - 1); - DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm); - if (hIcon != NULL) GuiData->hIcon = hIcon; - if (hIconSm != NULL) GuiData->hIconSm = hIconSm; - } ASSERT(GuiData->hIcon && GuiData->hIconSm); /* Mouse is shown by default with its default cursor shape */ @@ -1114,138 +1093,21 @@ static FRONTEND_VTBL GuiVtbl = }; -static BOOL -LoadShellLinkConsoleInfo(IN OUT PCONSOLE_START_INFO ConsoleStartInfo, - IN OUT PCONSOLE_INFO ConsoleInfo) -{ -#define PATH_SEPARATOR L'\\' - - BOOL RetVal = FALSE; - HRESULT hRes = S_OK; - LPWSTR LinkName = NULL; - SIZE_T Length = 0; - - if ((ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0) - return FALSE; - - ConsoleStartInfo->IconPath[0] = L'\0'; - ConsoleStartInfo->IconIndex = 0; - - /* 1- Find the last path separator if any */ - LinkName = wcsrchr(ConsoleStartInfo->ConsoleTitle, PATH_SEPARATOR); - if (LinkName == NULL) - { - LinkName = ConsoleStartInfo->ConsoleTitle; - } - else - { - /* Skip the path separator */ - ++LinkName; - } - - /* 2- Check for the link extension. The name ".lnk" is considered invalid. */ - Length = wcslen(LinkName); - if ( (Length <= 4) || (wcsicmp(LinkName + (Length - 4), L".lnk") != 0) ) - return FALSE; - - /* 3- It may be a link. Try to retrieve some properties */ - hRes = CoInitialize(NULL); - if (SUCCEEDED(hRes)) - { - /* Get a pointer to the IShellLink interface */ - IShellLinkW* pshl = NULL; - hRes = CoCreateInstance(&CLSID_ShellLink, - NULL, - CLSCTX_INPROC_SERVER, - &IID_IShellLinkW, - (LPVOID*)&pshl); - if (SUCCEEDED(hRes)) - { - /* Get a pointer to the IPersistFile interface */ - IPersistFile* ppf = NULL; - hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf); - if (SUCCEEDED(hRes)) - { - /* Load the shortcut */ - hRes = IPersistFile_Load(ppf, ConsoleStartInfo->ConsoleTitle, STGM_READ); - if (SUCCEEDED(hRes)) - { - /* - * Finally we can get the properties ! - * Update the old ones if needed. - */ - INT ShowCmd = 0; - // WORD HotKey = 0; - - /* Reset the name of the console with the name of the shortcut */ - Length = min(/*Length*/ Length - 4, // 4 == len(".lnk") - sizeof(ConsoleInfo->ConsoleTitle) / sizeof(ConsoleInfo->ConsoleTitle[0]) - 1); - wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length); - ConsoleInfo->ConsoleTitle[Length] = L'\0'; - - /* Get the window showing command */ - hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd); - if (SUCCEEDED(hRes)) ConsoleStartInfo->wShowWindow = (WORD)ShowCmd; - - /* Get the hotkey */ - // hRes = pshl->GetHotkey(&ShowCmd); - // if (SUCCEEDED(hRes)) ConsoleStartInfo->HotKey = HotKey; - - /* Get the icon location, if any */ - hRes = IShellLinkW_GetIconLocation(pshl, - ConsoleStartInfo->IconPath, - sizeof(ConsoleStartInfo->IconPath)/sizeof(ConsoleStartInfo->IconPath[0]) - 1, // == MAX_PATH - &ConsoleStartInfo->IconIndex); - if (!SUCCEEDED(hRes)) - { - ConsoleStartInfo->IconPath[0] = L'\0'; - ConsoleStartInfo->IconIndex = 0; - } - - // FIXME: Since we still don't load console properties from the shortcut, - // return false. When this will be done, we will return true instead. - RetVal = FALSE; - } - IPersistFile_Release(ppf); - } - IShellLinkW_Release(pshl); - } - } - CoUninitialize(); - - return RetVal; -} - NTSTATUS NTAPI GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, IN OUT PCONSOLE_INFO ConsoleInfo, IN OUT PVOID ExtraConsoleInfo, IN ULONG ProcessId) { - PCONSOLE_START_INFO ConsoleStartInfo = ExtraConsoleInfo; + PCONSOLE_INIT_INFO ConsoleInitInfo = ExtraConsoleInfo; PGUI_INIT_INFO GuiInitInfo; - if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleStartInfo == NULL) + if (FrontEnd == NULL || ConsoleInfo == NULL || ConsoleInitInfo == NULL) return STATUS_INVALID_PARAMETER; /* Initialize GUI terminal emulator common functionalities */ if (!GuiInit()) return STATUS_UNSUCCESSFUL; - /* - * Load per-application terminal settings. - * - * Check whether the process creating the console was launched via - * a shell-link. ConsoleInfo->ConsoleTitle may be updated with the - * name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too. - */ - if (ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) - { - if (!LoadShellLinkConsoleInfo(ConsoleStartInfo, ConsoleInfo)) - { - ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME; - } - } - /* * Initialize a private initialization info structure for later use. * It must be freed by a call to GuiUnloadFrontEnd or GuiInitFrontEnd. @@ -1255,9 +1117,10 @@ GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, // HACK: We suppose that the pointers will be valid in GuiInitFrontEnd... GuiInitInfo->ConsoleInfo = ConsoleInfo; - GuiInitInfo->ConsoleStartInfo = ConsoleStartInfo; + GuiInitInfo->ConsoleStartInfo = ConsoleInitInfo->ConsoleStartInfo; GuiInitInfo->ProcessId = ProcessId; + /* Finally, initialize the frontend structure */ FrontEnd->Vtbl = &GuiVtbl; FrontEnd->Data = NULL; diff --git a/win32ss/user/winsrv/consrv/frontends/gui/guiterm.h b/win32ss/user/winsrv/consrv/frontends/gui/guiterm.h index 8755cdd9f24..3b252afdb37 100644 --- a/win32ss/user/winsrv/consrv/frontends/gui/guiterm.h +++ b/win32ss/user/winsrv/consrv/frontends/gui/guiterm.h @@ -14,13 +14,6 @@ #include "guisettings.h" #include "conwnd.h" -NTSTATUS GuiInitConsole(PCONSOLE Console, - /*IN*/ PCONSOLE_START_INFO ConsoleStartInfo, - PCONSOLE_INFO ConsoleInfo, - DWORD ProcessId, - LPCWSTR IconPath, - INT IconIndex); - VOID GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData); diff --git a/win32ss/user/winsrv/consrv/frontends/terminal.c b/win32ss/user/winsrv/consrv/frontends/terminal.c index 30ad25c6e08..668b4d6b3e6 100644 --- a/win32ss/user/winsrv/consrv/frontends/terminal.c +++ b/win32ss/user/winsrv/consrv/frontends/terminal.c @@ -273,6 +273,8 @@ ConSrvTermInitTerminal(IN OUT PTERMINAL This, Console->FrontEndIFace = *FrontEnd; Status = FrontEnd->Vtbl->InitFrontEnd(FrontEnd, FrontEnd->Console); + if (!NT_SUCCESS(Status)) + DPRINT1("InitFrontEnd failed, Status = 0x%08lx\n", Status); /** HACK HACK!! Be sure FrontEndIFace is correctly updated in the console!! **/ DPRINT1("Using FrontEndIFace HACK(2), should be removed after proper implementation!\n"); @@ -697,13 +699,6 @@ ConSrvTermReleaseScreenBuffer(IN OUT PTERMINAL This, FrontEnd->Vtbl->ReleaseScreenBuffer(FrontEnd, ScreenBuffer); } -static VOID NTAPI -ConSrvTermChangeTitle(IN OUT PTERMINAL This) -{ - PFRONTEND FrontEnd = This->Data; - FrontEnd->Vtbl->ChangeTitle(FrontEnd); -} - static VOID NTAPI ConSrvTermGetLargestConsoleWindowSize(IN OUT PTERMINAL This, PCOORD pSize) @@ -743,7 +738,6 @@ static TERMINAL_VTBL ConSrvTermVtbl = ConSrvTermResizeTerminal, ConSrvTermSetActiveScreenBuffer, ConSrvTermReleaseScreenBuffer, - ConSrvTermChangeTitle, ConSrvTermGetLargestConsoleWindowSize, ConSrvTermSetPalette, ConSrvTermShowMouseCursor, diff --git a/win32ss/user/winsrv/consrv/handle.c b/win32ss/user/winsrv/consrv/handle.c index f45bfffdef8..f54a459f24e 100644 --- a/win32ss/user/winsrv/consrv/handle.c +++ b/win32ss/user/winsrv/consrv/handle.c @@ -470,15 +470,12 @@ ConSrvReleaseObject(IN PCONSOLE_IO_OBJECT Object, - - - NTSTATUS ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData, PHANDLE pInputHandle, PHANDLE pOutputHandle, PHANDLE pErrorHandle, - PCONSOLE_START_INFO ConsoleStartInfo) + PCONSOLE_INIT_INFO ConsoleInitInfo) { NTSTATUS Status = STATUS_SUCCESS; HANDLE ConsoleHandle; @@ -499,7 +496,7 @@ ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData, /* Initialize a new Console owned by this process */ Status = ConSrvInitConsole(&ConsoleHandle, &Console, - ConsoleStartInfo, + ConsoleInitInfo, HandleToUlong(ProcessData->Process->ClientId.UniqueProcess)); if (!NT_SUCCESS(Status)) { diff --git a/win32ss/user/winsrv/consrv/include/conio.h b/win32ss/user/winsrv/consrv/include/conio.h index e326e785fe9..a3728641c4d 100644 --- a/win32ss/user/winsrv/consrv/include/conio.h +++ b/win32ss/user/winsrv/consrv/include/conio.h @@ -251,7 +251,6 @@ typedef struct _TERMINAL_VTBL /* * External interface (functions corresponding to the Console API) */ - VOID (NTAPI *ChangeTitle)(IN OUT PTERMINAL This); VOID (NTAPI *GetLargestConsoleWindowSize)(IN OUT PTERMINAL This, PCOORD pSize); BOOL (NTAPI *SetPalette)(IN OUT PTERMINAL This, @@ -326,9 +325,6 @@ typedef struct _CONSOLE UINT OutputCodePage; /****************************** Other properties ******************************/ - UNICODE_STRING OriginalTitle; /* Original title of console, the one defined when the console leader is launched; it never changes. Always NULL-terminated */ - UNICODE_STRING Title; /* Title of console. Always NULL-terminated */ - COORD ConsoleSize; /* The current size of the console, for text-mode only */ BOOLEAN FixedSize; /* TRUE if the console is of fixed size */ diff --git a/win32ss/user/winsrv/consrv/include/conio_winsrv.h b/win32ss/user/winsrv/consrv/include/conio_winsrv.h index 36f94462f24..135ccb54352 100644 --- a/win32ss/user/winsrv/consrv/include/conio_winsrv.h +++ b/win32ss/user/winsrv/consrv/include/conio_winsrv.h @@ -183,7 +183,9 @@ typedef struct _WINSRV_CONSOLE HANDLE ErrorHardwareEvent; /****************************** Other properties ******************************/ - LIST_ENTRY PopupWindows; /*List of popup windows */ + LIST_ENTRY PopupWindows; /* List of popup windows */ + UNICODE_STRING OriginalTitle; /* Original title of console, the one defined when the console leader is launched; it never changes. Always NULL-terminated */ + UNICODE_STRING Title; /* Title of console. Always NULL-terminated */ COLORREF Colors[16]; /* Colour palette */ } WINSRV_CONSOLE; // , *PWINSRV_CONSOLE; diff --git a/win32ss/user/winsrv/consrv/include/term.h b/win32ss/user/winsrv/consrv/include/term.h index beb3cb84128..ecea140aff1 100644 --- a/win32ss/user/winsrv/consrv/include/term.h +++ b/win32ss/user/winsrv/consrv/include/term.h @@ -31,8 +31,6 @@ (Console)->TermIFace.Vtbl->SetActiveScreenBuffer(&(Console)->TermIFace) #define TermReleaseScreenBuffer(Console, ScreenBuffer) \ (Console)->TermIFace.Vtbl->ReleaseScreenBuffer(&(Console)->TermIFace, (ScreenBuffer)) -#define TermChangeTitle(Console) \ - (Console)->TermIFace.Vtbl->ChangeTitle(&(Console)->TermIFace) #define TermGetLargestConsoleWindowSize(Console, pSize) \ (Console)->TermIFace.Vtbl->GetLargestConsoleWindowSize(&(Console)->TermIFace, (pSize)) #define TermSetPalette(Console, PaletteHandle, PaletteUsage) \ @@ -45,6 +43,8 @@ #define TermRefreshInternalInfo(Console) \ (Console)->FrontEndIFace.Vtbl->RefreshInternalInfo(&(Console)->FrontEndIFace) +#define TermChangeTitle(Console) \ + (Console)->FrontEndIFace.Vtbl->ChangeTitle(&(Console)->FrontEndIFace) #define TermChangeIcon(Console, IconHandle) \ (Console)->FrontEndIFace.Vtbl->ChangeIcon(&(Console)->FrontEndIFace, (IconHandle)) #define TermGetConsoleWindowHandle(Console) \ diff --git a/win32ss/user/winsrv/consrv/init.c b/win32ss/user/winsrv/consrv/init.c index db82eb9a069..743166dbcea 100644 --- a/win32ss/user/winsrv/consrv/init.c +++ b/win32ss/user/winsrv/consrv/init.c @@ -354,8 +354,8 @@ ConSrvNewProcess(PCSR_PROCESS SourceProcess, RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData)); TargetProcessData->Process = TargetProcess; TargetProcessData->InputWaitHandle = NULL; - TargetProcessData->ConsoleHandle = TargetProcessData->ParentConsoleHandle = NULL; - TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE); + TargetProcessData->ConsoleHandle = NULL; + TargetProcessData->ConsoleApp = FALSE; /* * The handles table gets initialized either when inheriting from @@ -377,7 +377,7 @@ ConSrvNewProcess(PCSR_PROCESS SourceProcess, * handles table: this can happen if it is a GUI application having called * AllocConsole), then try to inherit handles from the parent process. */ - if (TargetProcessData->ConsoleApp /* && SourceProcessData->ConsoleApp */) + if (TargetProcess->Flags & CsrProcessIsConsoleApp /* && SourceProcessData->ConsoleHandle != NULL */) { PCONSOLE_PROCESS_DATA SourceProcessData = ConsoleGetPerProcessData(SourceProcess); PCONSRV_CONSOLE SourceConsole; @@ -389,10 +389,9 @@ ConSrvNewProcess(PCSR_PROCESS SourceProcess, { /* Inherit the parent's handles table */ Status = ConSrvInheritHandlesTable(SourceProcessData, TargetProcessData); - if (NT_SUCCESS(Status)) + if (!NT_SUCCESS(Status)) { - /* Temporary save the parent's console too */ - TargetProcessData->ParentConsoleHandle = SourceProcessData->ConsoleHandle; + DPRINT1("Inheriting handles table failed\n"); } /* Unlock the parent's console */ @@ -416,28 +415,37 @@ ConSrvConnect(IN PCSR_PROCESS CsrProcess, NTSTATUS Status = STATUS_SUCCESS; PCONSRV_API_CONNECTINFO ConnectInfo = (PCONSRV_API_CONNECTINFO)ConnectionInfo; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess); + CONSOLE_INIT_INFO ConsoleInitInfo; if ( ConnectionInfo == NULL || ConnectionInfoLength == NULL || - *ConnectionInfoLength != sizeof(CONSRV_API_CONNECTINFO) ) + *ConnectionInfoLength != sizeof(*ConnectInfo) ) { DPRINT1("CONSRV: Connection failed - ConnectionInfo = 0x%p ; ConnectionInfoLength = 0x%p (%lu), wanted %lu\n", ConnectionInfo, ConnectionInfoLength, ConnectionInfoLength ? *ConnectionInfoLength : (ULONG)-1, - sizeof(CONSRV_API_CONNECTINFO)); + sizeof(*ConnectInfo)); return STATUS_UNSUCCESSFUL; } /* If we don't need a console, then get out of here */ - if (!ConnectInfo->ConsoleStartInfo.ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps. - { - return STATUS_SUCCESS; - } + DPRINT("ConnectInfo->IsConsoleApp = %s\n", ConnectInfo->IsConsoleApp ? "True" : "False"); + if (!ConnectInfo->IsConsoleApp) return STATUS_SUCCESS; - /* If we don't have a console, then create a new one... */ - if (!ConnectInfo->ConsoleHandle || - ConnectInfo->ConsoleHandle != ProcessData->ParentConsoleHandle) + /* Initialize the console initialization info structure */ + ConsoleInitInfo.ConsoleStartInfo = &ConnectInfo->ConsoleStartInfo; + ConsoleInitInfo.TitleLength = ConnectInfo->TitleLength; + ConsoleInitInfo.ConsoleTitle = ConnectInfo->ConsoleTitle; + ConsoleInitInfo.DesktopLength = ConnectInfo->DesktopLength; + ConsoleInitInfo.Desktop = ConnectInfo->Desktop; + ConsoleInitInfo.AppNameLength = ConnectInfo->AppNameLength; + ConsoleInitInfo.AppName = ConnectInfo->AppName; + ConsoleInitInfo.CurDirLength = ConnectInfo->CurDirLength; + ConsoleInitInfo.CurDir = ConnectInfo->CurDir; + + /* If we don't inherit from an existing console, then create a new one... */ + if (ConnectInfo->ConsoleStartInfo.ConsoleHandle == NULL) { DPRINT("ConSrvConnect - Allocate a new console\n"); @@ -454,10 +462,10 @@ ConSrvConnect(IN PCSR_PROCESS CsrProcess, /* Initialize a new Console owned by the Console Leader Process */ Status = ConSrvAllocateConsole(ProcessData, - &ConnectInfo->InputHandle, - &ConnectInfo->OutputHandle, - &ConnectInfo->ErrorHandle, - &ConnectInfo->ConsoleStartInfo); + &ConnectInfo->ConsoleStartInfo.InputHandle, + &ConnectInfo->ConsoleStartInfo.OutputHandle, + &ConnectInfo->ConsoleStartInfo.ErrorHandle, + &ConsoleInitInfo); if (!NT_SUCCESS(Status)) { DPRINT1("Console allocation failed\n"); @@ -470,11 +478,11 @@ ConSrvConnect(IN PCSR_PROCESS CsrProcess, /* Reuse our current console */ Status = ConSrvInheritConsole(ProcessData, - ConnectInfo->ConsoleHandle, + ConnectInfo->ConsoleStartInfo.ConsoleHandle, FALSE, - NULL, // &ConnectInfo->InputHandle, - NULL, // &ConnectInfo->OutputHandle, - NULL); // &ConnectInfo->ErrorHandle); + NULL, // &ConnectInfo->ConsoleStartInfo.InputHandle, + NULL, // &ConnectInfo->ConsoleStartInfo.OutputHandle, + NULL); // &ConnectInfo->ConsoleStartInfo.ErrorHandle); if (!NT_SUCCESS(Status)) { DPRINT1("Console inheritance failed\n"); @@ -482,13 +490,17 @@ ConSrvConnect(IN PCSR_PROCESS CsrProcess, } } + /* Mark the process as having a console */ + ProcessData->ConsoleApp = TRUE; + // ProcessData->Flags |= CsrProcessIsConsoleApp; + /* Return the console handle and the input wait handle to the caller */ - ConnectInfo->ConsoleHandle = ProcessData->ConsoleHandle; - ConnectInfo->InputWaitHandle = ProcessData->InputWaitHandle; + ConnectInfo->ConsoleStartInfo.ConsoleHandle = ProcessData->ConsoleHandle; + ConnectInfo->ConsoleStartInfo.InputWaitHandle = ProcessData->InputWaitHandle; /* Set the Property-Dialog and Control-Dispatcher handlers */ - ProcessData->PropDispatcher = ConnectInfo->ConsoleStartInfo.PropDispatcher; - ProcessData->CtrlDispatcher = ConnectInfo->ConsoleStartInfo.CtrlDispatcher; + ProcessData->PropRoutine = ConnectInfo->PropRoutine; + ProcessData->CtrlRoutine = ConnectInfo->CtrlRoutine; return STATUS_SUCCESS; } @@ -508,6 +520,10 @@ ConSrvDisconnect(PCSR_PROCESS Process) { DPRINT("ConSrvDisconnect - calling ConSrvRemoveConsole\n"); ConSrvRemoveConsole(ProcessData); + + /* Mark the process as not having a console anymore */ + ProcessData->ConsoleApp = FALSE; + Process->Flags &= ~CsrProcessIsConsoleApp; } RtlDeleteCriticalSection(&ProcessData->HandleTableLock); diff --git a/win32ss/user/winsrv/consrv/procinit.h b/win32ss/user/winsrv/consrv/procinit.h index 5ceca6a25b1..cbc0d6b002b 100644 --- a/win32ss/user/winsrv/consrv/procinit.h +++ b/win32ss/user/winsrv/consrv/procinit.h @@ -12,7 +12,7 @@ NTSTATUS ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData, PHANDLE pInputHandle, PHANDLE pOutputHandle, PHANDLE pErrorHandle, - PCONSOLE_START_INFO ConsoleStartInfo); + PCONSOLE_INIT_INFO ConsoleInitInfo); NTSTATUS ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData, HANDLE ConsoleHandle, BOOLEAN CreateNewHandlesTable,