/*++ Copyright (c) 1985 - 1999, Microsoft Corporation Module Name: srvinit.c Abstract: This is the main initialization file for the console Server. Author: Therese Stowell (thereses) 11-Nov-1990 Revision History: --*/ #include "precomp.h" #pragma hdrstop CONST PCSR_API_ROUTINE ConsoleServerApiDispatchTable[ConsolepMaxApiNumber - ConsolepOpenConsole] = { SrvOpenConsole, SrvGetConsoleInput, SrvWriteConsoleInput, SrvReadConsoleOutput, SrvWriteConsoleOutput, SrvReadConsoleOutputString, SrvWriteConsoleOutputString, SrvFillConsoleOutput, SrvGetConsoleMode, SrvGetConsoleNumberOfFonts, SrvGetConsoleNumberOfInputEvents, SrvGetConsoleScreenBufferInfo, SrvGetConsoleCursorInfo, SrvGetConsoleMouseInfo, SrvGetConsoleFontInfo, SrvGetConsoleFontSize, SrvGetConsoleCurrentFont, SrvSetConsoleMode, SrvSetConsoleActiveScreenBuffer, SrvFlushConsoleInputBuffer, SrvGetLargestConsoleWindowSize, SrvSetConsoleScreenBufferSize, SrvSetConsoleCursorPosition, SrvSetConsoleCursorInfo, SrvSetConsoleWindowInfo, SrvScrollConsoleScreenBuffer, SrvSetConsoleTextAttribute, SrvSetConsoleFont, SrvSetConsoleIcon, SrvReadConsole, SrvWriteConsole, SrvDuplicateHandle, SrvGetHandleInformation, SrvSetHandleInformation, SrvCloseHandle, SrvVerifyConsoleIoHandle, SrvAllocConsole, SrvFreeConsole, SrvGetConsoleTitle, SrvSetConsoleTitle, SrvCreateConsoleScreenBuffer, SrvInvalidateBitMapRect, SrvVDMConsoleOperation, SrvSetConsoleCursor, SrvShowConsoleCursor, SrvConsoleMenuControl, SrvSetConsolePalette, SrvSetConsoleDisplayMode, SrvRegisterConsoleVDM, SrvGetConsoleHardwareState, SrvSetConsoleHardwareState, SrvGetConsoleDisplayMode, SrvAddConsoleAlias, SrvGetConsoleAlias, SrvGetConsoleAliasesLength, SrvGetConsoleAliasExesLength, SrvGetConsoleAliases, SrvGetConsoleAliasExes, SrvExpungeConsoleCommandHistory, SrvSetConsoleNumberOfCommands, SrvGetConsoleCommandHistoryLength, SrvGetConsoleCommandHistory, SrvSetConsoleCommandHistoryMode, SrvGetConsoleCP, SrvSetConsoleCP, SrvSetConsoleKeyShortcuts, SrvSetConsoleMenuClose, SrvConsoleNotifyLastClose, SrvGenerateConsoleCtrlEvent, SrvGetConsoleKeyboardLayoutName, SrvGetConsoleWindow, #if defined(FE_SB) SrvGetConsoleCharType, SrvSetConsoleLocalEUDC, SrvSetConsoleCursorMode, SrvGetConsoleCursorMode, SrvRegisterConsoleOS2, SrvSetConsoleOS2OemFormat, #if defined(FE_IME) SrvGetConsoleNlsMode, SrvSetConsoleNlsMode, SrvRegisterConsoleIME, SrvUnregisterConsoleIME, #endif // FE_IME #endif // FE_SB SrvGetConsoleLangId, SrvAttachConsole, SrvGetConsoleSelectionInfo, SrvGetConsoleProcessList, }; CONST BOOLEAN ConsoleServerApiServerValidTable[ConsolepMaxApiNumber - ConsolepOpenConsole] = { FALSE, // OpenConsole FALSE, // GetConsoleInput, FALSE, // WriteConsoleInput, FALSE, // ReadConsoleOutput, FALSE, // WriteConsoleOutput, FALSE, // ReadConsoleOutputString, FALSE, // WriteConsoleOutputString, FALSE, // FillConsoleOutput, FALSE, // GetConsoleMode, FALSE, // GetNumberOfConsoleFonts, FALSE, // GetNumberOfConsoleInputEvents, FALSE, // GetConsoleScreenBufferInfo, FALSE, // GetConsoleCursorInfo, FALSE, // GetConsoleMouseInfo, FALSE, // GetConsoleFontInfo, FALSE, // GetConsoleFontSize, FALSE, // GetCurrentConsoleFont, FALSE, // SetConsoleMode, FALSE, // SetConsoleActiveScreenBuffer, FALSE, // FlushConsoleInputBuffer, FALSE, // GetLargestConsoleWindowSize, FALSE, // SetConsoleScreenBufferSize, FALSE, // SetConsoleCursorPosition, FALSE, // SetConsoleCursorInfo, FALSE, // SetConsoleWindowInfo, FALSE, // ScrollConsoleScreenBuffer, FALSE, // SetConsoleTextAttribute, FALSE, // SetConsoleFont, FALSE, // SetConsoleIcon FALSE, // ReadConsole, FALSE, // WriteConsole, FALSE, // DuplicateHandle, FALSE, // GetHandleInformation, FALSE, // SetHandleInformation, FALSE, // CloseHandle FALSE, // VerifyConsoleIoHandle FALSE, // AllocConsole, FALSE, // FreeConsole FALSE, // GetConsoleTitle, FALSE, // SetConsoleTitle, FALSE, // CreateConsoleScreenBuffer FALSE, // InvalidateConsoleBitmapRect FALSE, // VDMConsoleOperation FALSE, // SetConsoleCursor, FALSE, // ShowConsoleCursor FALSE, // ConsoleMenuControl FALSE, // SetConsolePalette FALSE, // SetConsoleDisplayMode FALSE, // RegisterConsoleVDM, FALSE, // GetConsoleHardwareState FALSE, // SetConsoleHardwareState TRUE, // GetConsoleDisplayMode FALSE, // AddConsoleAlias, FALSE, // GetConsoleAlias, FALSE, // GetConsoleAliasesLength, FALSE, // GetConsoleAliasExesLength, FALSE, // GetConsoleAliases, FALSE, // GetConsoleAliasExes FALSE, // ExpungeConsoleCommandHistory, FALSE, // SetConsoleNumberOfCommands, FALSE, // GetConsoleCommandHistoryLength, FALSE, // GetConsoleCommandHistory, FALSE, // SetConsoleCommandHistoryMode FALSE, // SrvGetConsoleCP, FALSE, // SrvSetConsoleCP, FALSE, // SrvSetConsoleKeyShortcuts, FALSE, // SrvSetConsoleMenuClose FALSE, // SrvConsoleNotifyLastClose FALSE, // SrvGenerateConsoleCtrlEvent FALSE, // SrvGetConsoleKeyboardLayoutName FALSE, // SrvGetConsoleWindow, #if defined(FE_SB) FALSE, // GetConsoleCharType FALSE, // SrvSetConsoleLocalEUDC, FALSE, // SrvSetConsoleCursorMode, FALSE, // SrvGetConsoleCursorMode FALSE, // SrvRegisterConsoleOS2, FALSE, // SrvSetConsoleOS2OemFormat, #if defined(FE_IME) FALSE, // GetConsoleNlsMode FALSE, // SetConsoleNlsMode FALSE, // RegisterConsoleIME FALSE, // UnregisterConsoleIME #endif // FE_IME #endif // FE_SB FALSE, // GetConsoleLangId FALSE, // AttachConsole FALSE, // GetConsoleSelectionInfo, FALSE, // GetConsoleProcessList }; #if DBG CONST PSZ ConsoleServerApiNameTable[ConsolepMaxApiNumber - ConsolepOpenConsole] = { "SrvOpenConsole", "SrvGetConsoleInput", "SrvWriteConsoleInput", "SrvReadConsoleOutput", "SrvWriteConsoleOutput", "SrvReadConsoleOutputString", "SrvWriteConsoleOutputString", "SrvFillConsoleOutput", "SrvGetConsoleMode", "SrvGetConsoleNumberOfFonts", "SrvGetConsoleNumberOfInputEvents", "SrvGetConsoleScreenBufferInfo", "SrvGetConsoleCursorInfo", "SrvGetConsoleMouseInfo", "SrvGetConsoleFontInfo", "SrvGetConsoleFontSize", "SrvGetConsoleCurrentFont", "SrvSetConsoleMode", "SrvSetConsoleActiveScreenBuffer", "SrvFlushConsoleInputBuffer", "SrvGetLargestConsoleWindowSize", "SrvSetConsoleScreenBufferSize", "SrvSetConsoleCursorPosition", "SrvSetConsoleCursorInfo", "SrvSetConsoleWindowInfo", "SrvScrollConsoleScreenBuffer", "SrvSetConsoleTextAttribute", "SrvSetConsoleFont", "SrvSetConsoleIcon", "SrvReadConsole", "SrvWriteConsole", "SrvDuplicateHandle", "SrvGetHandleInformation", "SrvSetHandleInformation", "SrvCloseHandle", "SrvVerifyConsoleIoHandle", "SrvAllocConsole", "SrvFreeConsole", "SrvGetConsoleTitle", "SrvSetConsoleTitle", "SrvCreateConsoleScreenBuffer", "SrvInvalidateBitMapRect", "SrvVDMConsoleOperation", "SrvSetConsoleCursor", "SrvShowConsoleCursor", "SrvConsoleMenuControl", "SrvSetConsolePalette", "SrvSetConsoleDisplayMode", "SrvRegisterConsoleVDM", "SrvGetConsoleHardwareState", "SrvSetConsoleHardwareState", "SrvGetConsoleDisplayMode", "SrvAddConsoleAlias", "SrvGetConsoleAlias", "SrvGetConsoleAliasesLength", "SrvGetConsoleAliasExesLength", "SrvGetConsoleAliases", "SrvGetConsoleAliasExes", "SrvExpungeConsoleCommandHistory", "SrvSetConsoleNumberOfCommands", "SrvGetConsoleCommandHistoryLength", "SrvGetConsoleCommandHistory", "SrvSetConsoleCommandHistoryMode", "SrvGetConsoleCP", "SrvSetConsoleCP", "SrvSetConsoleKeyShortcuts", "SrvSetConsoleMenuClose", "SrvConsoleNotifyLastClose", "SrvGenerateConsoleCtrlEvent", "SrvGetConsoleKeyboardLayoutName", "SrvGetConsoleWindow", #if defined(FE_SB) "SrvGetConsoleCharType", "SrvSetConsoleLocalEUDC", "SrvSetConsoleCursorMode", "SrvGetConsoleCursorMode", "SrvRegisterConsoleOS2", "SrvSetConsoleOS2OemFormat", #if defined(FE_IME) "SrvGetConsoleNlsMode", "SrvSetConsoleNlsMode", "SrvRegisterConsoleIME", "SrvUnregisterConsoleIME", #endif // FE_IME #endif // FE_SB "SrvGetConsoleLangId", "SrvAttachConsole", "SrvGetConsoleSelectionInfo", "SrvGetConsoleProcessList", }; #endif // DBG BOOL FullScreenInitialized; CRITICAL_SECTION ConsoleVDMCriticalSection; PCONSOLE_INFORMATION ConsoleVDMOnSwitching; CRITICAL_SECTION ConsoleInitWindowsLock; BOOL fOneTimeInitialized; UINT OEMCP; UINT WINDOWSCP; UINT ConsoleOutputCP; CONSOLE_REGISTRY_INFO DefaultRegInfo; #if defined(FE_SB) BOOLEAN gfIsDBCSACP; #endif VOID UnregisterVDM( IN PCONSOLE_INFORMATION Console ); ULONG NonConsoleProcessShutdown( PCSR_PROCESS Process, DWORD dwFlags ); ULONG ConsoleClientShutdown( PCSR_PROCESS Process, ULONG Flags, BOOLEAN fFirstPass ); NTSTATUS ConsoleClientConnectRoutine( IN PCSR_PROCESS Process, IN OUT PVOID ConnectionInfo, IN OUT PULONG ConnectionInfoLength ); VOID ConsoleClientDisconnectRoutine( IN PCSR_PROCESS Process ); VOID ConsolePlaySound( VOID ); HANDLE ghInstance; HICON ghDefaultIcon; HICON ghDefaultSmIcon; HCURSOR ghNormalCursor; PWIN32HEAP pConHeap; DWORD dwConBaseTag; DWORD gExtendedEditKey; BOOL gfTrimLeadingZeros; BOOL gfEnableColorSelection; BOOL gfLoadConIme; VOID LoadLinkInfo( PCONSOLE_INFO ConsoleInfo, LPWSTR Title, LPDWORD TitleLength, LPWSTR CurDir, LPWSTR AppName ) { DWORD dwLinkLen; WCHAR LinkName[MAX_PATH + 1]; LNKPROPNTCONSOLE linkprops; LPWSTR pszIconLocation; int nIconIndex; ConsoleInfo->uCodePage = OEMCP; // Do some initialization ConsoleInfo->hIcon = ghDefaultIcon; ConsoleInfo->hSmIcon = ghDefaultSmIcon; pszIconLocation = NULL; nIconIndex = 0; // Try to impersonate the client-side thread if (!CsrImpersonateClient(NULL)) { ConsoleInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME; goto DefaultInit; } // Did we get started from a link? if (ConsoleInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) { DWORD Success; DWORD oldLen; // Get the filename of the link (TitleLength is BYTES, not CHARS) dwLinkLen = (DWORD)(min(*TitleLength,(MAX_PATH+1)*sizeof(WCHAR))); RtlCopyMemory(LinkName, Title, dwLinkLen); LinkName[ MAX_PATH ] = (WCHAR)0; // Get the title for the window, which is effectively the link file name oldLen = *TitleLength; *TitleLength = GetTitleFromLinkName( LinkName, Title ); if (*TitleLength < oldLen) Title[ *TitleLength / sizeof(WCHAR) ] = L'\0'; // try to get console properties from the link Success = GetLinkProperties( LinkName, &linkprops, sizeof(linkprops) ); if (Success == LINK_NOINFO) { ConsoleInfo->dwStartupFlags &= (~STARTF_TITLEISLINKNAME); goto NormalInit; } if (linkprops.pszIconLocation && *linkprops.pszIconLocation) { pszIconLocation = linkprops.pszIconLocation; nIconIndex = linkprops.uIcon; ConsoleInfo->iIconId = 0; } // Transfer link settings ConsoleInfo->dwHotKey = linkprops.uHotKey; ConsoleInfo->wShowWindow = (WORD)linkprops.uShowCmd; if (Success == LINK_SIMPLEINFO) { ConsoleInfo->dwStartupFlags &= (~STARTF_TITLEISLINKNAME); goto NormalInit; } // Transfer console link settings ConsoleInfo->wFillAttribute = linkprops.console_props.wFillAttribute; ConsoleInfo->wPopupFillAttribute = linkprops.console_props.wPopupFillAttribute; RtlCopyMemory( &ConsoleInfo->dwScreenBufferSize, &linkprops.console_props.dwScreenBufferSize, sizeof(NT_CONSOLE_PROPS) - FIELD_OFFSET(NT_CONSOLE_PROPS, dwScreenBufferSize) ); ConsoleInfo->uCodePage = linkprops.fe_console_props.uCodePage; ConsoleInfo->dwStartupFlags &= ~(STARTF_USESIZE | STARTF_USECOUNTCHARS); } NormalInit: // // Go get the icon // if (pszIconLocation == NULL) { dwLinkLen = RtlDosSearchPath_U(CurDir, AppName, NULL, sizeof(LinkName), LinkName, NULL); if (dwLinkLen > 0 && dwLinkLen < sizeof(LinkName)) { pszIconLocation = LinkName; } else { pszIconLocation = AppName; } } if (pszIconLocation != NULL) { HICON hIcon, hSmIcon; hIcon = hSmIcon = NULL; PrivateExtractIconExW(pszIconLocation, nIconIndex, &hIcon, &hSmIcon, 1); /* * If there is no large icon, use the default ones. * If there is only a large icon in the resource, do not use * the default small one but let it be NULL so we'll stretch * the large one. */ if (hIcon != NULL) { ConsoleInfo->hIcon = hIcon; ConsoleInfo->hSmIcon = hSmIcon; } } CsrRevertToSelf(); if (!IsValidCodePage(ConsoleInfo->uCodePage)) { // fail safe ConsoleInfo->uCodePage = OEMCP; } if (!(ConsoleInfo->dwStartupFlags & STARTF_TITLEISLINKNAME)) { CONSOLE_REGISTRY_INFO RegInfo; DefaultInit: // // read values from the registry // RegInfo = DefaultRegInfo; GetRegistryValues(Title, &RegInfo); // // If a value isn't specified in STARTUPINFO, then use the one // from the registry. // if (!(ConsoleInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE)) { ConsoleInfo->wFillAttribute = RegInfo.ScreenFill.Attributes; } ConsoleInfo->wPopupFillAttribute = RegInfo.PopupFill.Attributes; if (!(ConsoleInfo->dwStartupFlags & STARTF_USECOUNTCHARS)) { ConsoleInfo->dwScreenBufferSize = RegInfo.ScreenBufferSize; } if (!(ConsoleInfo->dwStartupFlags & STARTF_USESIZE)) { ConsoleInfo->dwWindowSize = RegInfo.WindowSize; } if (!(ConsoleInfo->dwStartupFlags & STARTF_USEPOSITION)) { ConsoleInfo->dwWindowOrigin = RegInfo.WindowOrigin; ConsoleInfo->bAutoPosition = RegInfo.AutoPosition; } else { ConsoleInfo->bAutoPosition = FALSE; } if (!(ConsoleInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)) { ConsoleInfo->bFullScreen = RegInfo.FullScreen; } else { ConsoleInfo->bFullScreen = TRUE; } ConsoleInfo->uFontFamily = RegInfo.FontFamily; ConsoleInfo->uFontWeight = RegInfo.FontWeight; ConsoleInfo->dwFontSize = RegInfo.FontSize; RtlCopyMemory(ConsoleInfo->FaceName, RegInfo.FaceName, sizeof(RegInfo.FaceName)); ConsoleInfo->bQuickEdit = RegInfo.QuickEdit; ConsoleInfo->bInsertMode = RegInfo.InsertMode; ConsoleInfo->uCursorSize = RegInfo.CursorSize; ConsoleInfo->uHistoryBufferSize = RegInfo.HistoryBufferSize; ConsoleInfo->uNumberOfHistoryBuffers = RegInfo.NumberOfHistoryBuffers; ConsoleInfo->bHistoryNoDup = RegInfo.HistoryNoDup; RtlCopyMemory(ConsoleInfo->ColorTable, RegInfo.ColorTable, sizeof(RegInfo.ColorTable)); #ifdef FE_SB ConsoleInfo->uCodePage = RegInfo.CodePage; #endif } } BOOL InitWindowClass( VOID ) { WNDCLASSEX wc; BOOL retval; ATOM atomConsoleClass; ghNormalCursor = LoadCursor(NULL, IDC_ARROW); ASSERT(ghModuleWin != NULL); ghDefaultIcon = LoadIcon(ghModuleWin, MAKEINTRESOURCE(IDI_CONSOLE)); ghDefaultSmIcon = LoadImage(ghModuleWin, MAKEINTRESOURCE(IDI_CONSOLE), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); wc.hIcon = ghDefaultIcon; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; wc.lpfnWndProc = ConsoleWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = GWL_CONSOLE_WNDALLOC; wc.hInstance = ghInstance; wc.hCursor = ghNormalCursor; wc.hbrBackground = CreateSolidBrush(DefaultRegInfo.ColorTable[LOBYTE(DefaultRegInfo.ScreenFill.Attributes >> 4) & 0xF]); wc.lpszMenuName = NULL; wc.lpszClassName = CONSOLE_WINDOW_CLASS; wc.hIconSm = ghDefaultSmIcon; atomConsoleClass = RegisterClassEx(&wc); retval = (atomConsoleClass != 0); if (retval) { NtUserConsoleControl(ConsoleClassAtom, &atomConsoleClass, sizeof(ATOM)); } return retval; } NTSTATUS InitWindowsStuff( HDESK hdesk, LPDWORD lpdwThreadId) { NTSTATUS Status = STATUS_SUCCESS; CLIENT_ID ClientId; CONSOLEDESKTOPCONSOLETHREAD ConsoleDesktopInfo; INPUT_THREAD_INIT_INFO InputThreadInitInfo; // // This routine must be done within a critical section to ensure that // only one thread can initialize at a time. We need a special critical // section here because Csr calls into ConsoleAddProcessRoutine with // it's own critical section locked and then tries to grab the // ConsoleHandleTableLock. If we call CsrAddStaticServerThread here // with the ConsoleHandleTableLock locked we could get into a deadlock // situation. This critical section should not be used anywhere else. // RtlEnterCriticalSection(&ConsoleInitWindowsLock); ConsoleDesktopInfo.hdesk = hdesk; ConsoleDesktopInfo.dwThreadId = (DWORD)-1; NtUserConsoleControl(ConsoleDesktopConsoleThread, &ConsoleDesktopInfo, sizeof(ConsoleDesktopInfo)); if (ConsoleDesktopInfo.dwThreadId == 0) { if (!fOneTimeInitialized) { #ifdef FE_SB InitializeDbcsMisc(); #endif // FE_SB FullScreenInitialized = InitializeFullScreen(); // // read the registry values // GetRegistryValues(L"", &DefaultRegInfo); // // allocate buffer for scrolling // Status = InitializeScrollBuffer(); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "InitWindowsStuff: InitScrollBuffer failed %x", Status); goto ErrorExit; } } // // create GetMessage thread // Status = NtCreateEvent(&InputThreadInitInfo.InitCompleteEventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE); if (!NT_SUCCESS(Status)) { goto ErrorExit; } Status = NtDuplicateObject(NtCurrentProcess(), hdesk, NtCurrentProcess(), &InputThreadInitInfo.DesktopHandle, 0, 0, DUPLICATE_SAME_ACCESS); if (!NT_SUCCESS(Status)) { NtClose(InputThreadInitInfo.InitCompleteEventHandle); goto ErrorExit; } // // Create GetMessage thread. // Status = RtlCreateUserThread(NtCurrentProcess(), (PSECURITY_DESCRIPTOR) NULL, TRUE, 0, 0, 0x5000, ConsoleInputThread, &InputThreadInitInfo, &InputThreadInitInfo.ThreadHandle, &ClientId); if (!NT_SUCCESS(Status)) { NtClose(InputThreadInitInfo.InitCompleteEventHandle); CloseDesktop(InputThreadInitInfo.DesktopHandle); goto ErrorExit; } CsrAddStaticServerThread(InputThreadInitInfo.ThreadHandle, &ClientId, 0); NtResumeThread(InputThreadInitInfo.ThreadHandle, NULL); NtWaitForSingleObject(InputThreadInitInfo.InitCompleteEventHandle, FALSE, NULL); NtClose(InputThreadInitInfo.InitCompleteEventHandle); if (!NT_SUCCESS(InputThreadInitInfo.InitStatus)) { Status = InputThreadInitInfo.InitStatus; goto ErrorExit; } *lpdwThreadId = HandleToUlong(ClientId.UniqueThread); fOneTimeInitialized=TRUE; } else { *lpdwThreadId = ConsoleDesktopInfo.dwThreadId; } ErrorExit: RtlLeaveCriticalSection(&ConsoleInitWindowsLock); return Status; } NTSTATUS ConServerDllInitialization( PCSR_SERVER_DLL LoadedServerDll) /*++ Routine Description: This routine is called to initialize the server dll. It initializes the console handle table. Arguments: LoadedServerDll - Pointer to console server dll data Return Value: --*/ { NTSTATUS Status; LoadedServerDll->ApiNumberBase = CONSRV_FIRST_API_NUMBER; LoadedServerDll->MaxApiNumber = ConsolepMaxApiNumber; LoadedServerDll->ApiDispatchTable = (PCSR_API_ROUTINE *)ConsoleServerApiDispatchTable; LoadedServerDll->ApiServerValidTable = (PBOOLEAN)ConsoleServerApiServerValidTable; #if DBG LoadedServerDll->ApiNameTable = ConsoleServerApiNameTable; #endif LoadedServerDll->PerProcessDataLength = sizeof(CONSOLE_PER_PROCESS_DATA); LoadedServerDll->ConnectRoutine = ConsoleClientConnectRoutine; LoadedServerDll->DisconnectRoutine = ConsoleClientDisconnectRoutine; LoadedServerDll->AddProcessRoutine = ConsoleAddProcessRoutine; LoadedServerDll->ShutdownProcessRoutine = ConsoleClientShutdown; ghInstance = LoadedServerDll->ModuleHandle; // initialize data structures InitWin32HeapStubs(); pConHeap = Win32HeapCreate( "CH_Head", "CH_Tail", HEAP_GROWABLE | HEAP_CLASS_5 | #ifdef PRERELEASE HEAP_TAIL_CHECKING_ENABLED, #else 0, #endif // PRERELEASE NULL, // HeapBase 64 * 1024, // ReserveSize 4096, // CommitSize NULL, // Lock to use for serialization NULL); // GrowthThreshold if (pConHeap == NULL) { return STATUS_NO_MEMORY; } dwConBaseTag = Win32HeapCreateTag( pConHeap, 0, L"CON!", L"TMP\0" L"BMP\0" L"ALIAS\0" L"HISTORY\0" L"TITLE\0" L"HANDLE\0" L"CONSOLE\0" L"ICON\0" L"BUFFER\0" L"WAIT\0" L"FONT\0" L"SCREEN\0" #if defined(FE_SB) L"TMP DBCS\0" L"SCREEN DBCS\0" L"EUDC\0" L"CONVAREA\0" L"IME\0" #endif ); Status = InitializeConsoleHandleTable(); if (!NT_SUCCESS(Status)) { return Status; } Status = RtlInitializeCriticalSectionAndSpinCount(&ConsoleInitWindowsLock, 0x80000000); if (!NT_SUCCESS(Status)) { return Status; } // // Initialize Input thread local message queue // Status = RtlInitializeCriticalSectionAndSpinCount(&gInputThreadMsgLock, 0x80000000); if (!NT_SUCCESS(Status)) { return Status; } InitializeThreadMessages(); #ifdef i386 Status = RtlInitializeCriticalSectionAndSpinCount(&ConsoleVDMCriticalSection, 0x80000000); if (!NT_SUCCESS(Status)) { return Status; } ConsoleVDMOnSwitching = NULL; #endif OEMCP = GetOEMCP(); WINDOWSCP = GetACP(); #if !defined(FE_SB) ConsoleOutputCP = OEMCP; #endif InitializeFonts(); InputThreadTlsIndex = TlsAlloc(); if (InputThreadTlsIndex == 0xFFFFFFFF) { return STATUS_UNSUCCESSFUL; } #if defined(FE_SB) gfIsDBCSACP = !!IsAvailableFarEastCodePage(WINDOWSCP); #endif return STATUS_SUCCESS; } BOOL MapHandle( IN HANDLE ClientProcessHandle, IN HANDLE ServerHandle, OUT PHANDLE ClientHandle ) { // // map event handle into dll's handle space. // return DuplicateHandle(NtCurrentProcess(), ServerHandle, ClientProcessHandle, ClientHandle, 0, FALSE, DUPLICATE_SAME_ACCESS ); } VOID AddProcessToList( IN OUT PCONSOLE_INFORMATION Console, IN OUT PCONSOLE_PROCESS_HANDLE ProcessHandleRecord, IN HANDLE ProcessHandle ) { ASSERT(!(Console->Flags & (CONSOLE_TERMINATING | CONSOLE_SHUTTING_DOWN))); ProcessHandleRecord->ProcessHandle = ProcessHandle; ProcessHandleRecord->TerminateCount = 0; InsertHeadList(&Console->ProcessHandleList, &ProcessHandleRecord->ListLink); SetProcessFocus(ProcessHandleRecord->Process, Console->Flags & CONSOLE_HAS_FOCUS); } PCONSOLE_PROCESS_HANDLE FindProcessInList( IN PCONSOLE_INFORMATION Console, IN HANDLE ProcessHandle ) { PCONSOLE_PROCESS_HANDLE ProcessHandleRecord; PLIST_ENTRY ListHead, ListNext; ListHead = &Console->ProcessHandleList; ListNext = ListHead->Flink; while (ListNext != ListHead) { ProcessHandleRecord = CONTAINING_RECORD( ListNext, CONSOLE_PROCESS_HANDLE, ListLink ); if (ProcessHandleRecord->ProcessHandle == ProcessHandle) { return ProcessHandleRecord; } ListNext = ListNext->Flink; } return NULL; } VOID RemoveProcessFromList( IN OUT PCONSOLE_INFORMATION Console, IN HANDLE ProcessHandle ) { PCONSOLE_PROCESS_HANDLE ProcessHandleRecord; PLIST_ENTRY ListHead, ListNext; ListHead = &Console->ProcessHandleList; ListNext = ListHead->Flink; while (ListNext != ListHead) { ProcessHandleRecord = CONTAINING_RECORD( ListNext, CONSOLE_PROCESS_HANDLE, ListLink ); ListNext = ListNext->Flink; if (ProcessHandleRecord->ProcessHandle == ProcessHandle) { RemoveEntryList(&ProcessHandleRecord->ListLink); ConsoleHeapFree(ProcessHandleRecord); return; } } RIPMSG1(RIP_ERROR, "RemoveProcessFromList: Process %#p not found", ProcessHandle); } NTSTATUS SetUpConsole( IN OUT PCONSOLE_INFO ConsoleInfo, IN DWORD TitleLength, IN LPWSTR Title, IN LPWSTR CurDir, IN LPWSTR AppName, IN PCONSOLE_PER_PROCESS_DATA ProcessData, IN BOOLEAN WindowVisible, IN PUNICODE_STRING pstrDesktopName) { NTSTATUS Status; PCONSOLE_INFORMATION Console; DWORD ConsoleThreadId; HWINSTA hwinsta; HDESK hdesk; USEROBJECTFLAGS UserObjectFlags; DWORD Length; // // Connect to the windowstation and desktop. // if (!CsrImpersonateClient(NULL)) { return STATUS_BAD_IMPERSONATION_LEVEL; } hdesk = NtUserResolveDesktop(CONSOLE_CLIENTPROCESSHANDLE(), pstrDesktopName, FALSE, &hwinsta); CsrRevertToSelf(); if (hdesk == NULL) { return STATUS_UNSUCCESSFUL; } // // Need to initialize windows stuff once real console app starts. // This is because for the time being windows expects the first // app to be a windows app. // Status = InitWindowsStuff(hdesk, &ConsoleThreadId); if (!NT_SUCCESS(Status)) { CloseDesktop(hdesk); CloseWindowStation(hwinsta); return Status; } // // If the windowstation isn't visible, then neither is the window. // if (WindowVisible) { if (GetUserObjectInformation(hwinsta, UOI_FLAGS, &UserObjectFlags, sizeof(UserObjectFlags), &Length)) { if (!(UserObjectFlags.dwFlags & WSF_VISIBLE)) { WindowVisible = FALSE; } } } // // We need to see if we were spawned from a link. If we were, we // need to call back into the shell to try to get all the console // information from the link. // LoadLinkInfo( ConsoleInfo, Title, &TitleLength, CurDir, AppName ); LockConsoleHandleTable(); Status = AllocateConsoleHandle(&ConsoleInfo->ConsoleHandle); if (!NT_SUCCESS(Status)) { UnlockConsoleHandleTable(); CloseDesktop(hdesk); CloseWindowStation(hwinsta); return Status; } Status = AllocateConsole(ConsoleInfo->ConsoleHandle, Title, (USHORT)TitleLength, CONSOLE_CLIENTPROCESSHANDLE(), &ConsoleInfo->StdIn, &ConsoleInfo->StdOut, &ConsoleInfo->StdErr, ProcessData, ConsoleInfo, WindowVisible, ConsoleThreadId ); if (!NT_SUCCESS(Status)) { FreeConsoleHandle(ConsoleInfo->ConsoleHandle); UnlockConsoleHandleTable(); CloseDesktop(hdesk); CloseWindowStation(hwinsta); return Status; } CONSOLE_SETCONSOLEHANDLE(ConsoleInfo->ConsoleHandle); Status = DereferenceConsoleHandle(ConsoleInfo->ConsoleHandle,&Console); ASSERT (NT_SUCCESS(Status)); // // increment console reference count // RefConsole(Console); // // Save the windowstation and desktop handles so they // can be used later // Console->hWinSta = hwinsta; Console->hDesk = hdesk; UnlockConsoleHandleTable(); #if defined(FE_IME) if (CONSOLE_IS_IME_ENABLED()) { if (WindowVisible) { InitConsoleIMEStuff(Console->hDesk, ConsoleThreadId, Console); } } #endif return Status; } NTSTATUS ConsoleClientConnectRoutine( IN PCSR_PROCESS Process, IN OUT PVOID ConnectionInfo, IN OUT PULONG ConnectionInfoLength) /*++ Routine Description: This routine is called when a new process is created. For processes without parents, it creates the console. For processes with parents, it duplicates the handle table. Arguments: Process - Pointer to process structure. ConnectionInfo - Pointer to connection info. ConnectionInfoLength - Connection info length. Return Value: --*/ { NTSTATUS Status; PCONSOLE_API_CONNECTINFO p = (PCONSOLE_API_CONNECTINFO)ConnectionInfo; PCONSOLE_INFORMATION Console; PCONSOLE_PER_PROCESS_DATA ProcessData; PCONSOLE_PROCESS_HANDLE ProcessHandleRecord; CONSOLEWINDOWSTATIONPROCESS ConsoleWindowStationInfo; UNICODE_STRING strDesktopName; CONSOLE_PROCESS_INFO cpi; if (p == NULL || *ConnectionInfoLength != sizeof( *p ) || p->AppNameLength > sizeof(p->AppName) || p->CurDirLength > sizeof(p->CurDir) || p->TitleLength > sizeof(p->Title)) { RIPMSG0(RIP_ERROR, "CONSRV: bad connection info"); return STATUS_UNSUCCESSFUL; } // // Make sure the strings are NULL terminated. // p->AppName[NELEM(p->AppName) - 1] = 0; p->CurDir[NELEM(p->CurDir) - 1] = 0; p->Title[NELEM(p->Title) - 1] = 0; if (CtrlRoutine == NULL) { CtrlRoutine = p->CtrlRoutine; } #if defined(FE_IME) if (ConsoleIMERoutine == NULL) { ConsoleIMERoutine = p->ConsoleIMERoutine; } #endif ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(Process); Console = NULL; // // If this process is not a console app, stop right here - no // initialization is needed. Just need to remember that this // is not a console app so that we do no work during // ConsoleClientDisconnectRoutine(). // Status = STATUS_SUCCESS; if ((CONSOLE_GETCONSOLEAPPFROMPROCESSDATA(ProcessData) = p->ConsoleApp)) { // // First call off to USER so it unblocks any app waiting on a call // to WaitForInputIdle. This way apps calling WinExec() to exec console // apps will return right away. // cpi.dwProcessID = HandleToUlong(CONSOLE_CLIENTPROCESSID()); cpi.dwFlags = (p->ConsoleInfo.ConsoleHandle != NULL) ? 0 : CPI_NEWPROCESSWINDOW; NtUserConsoleControl(ConsoleNotifyConsoleApplication, &cpi, sizeof(CONSOLE_PROCESS_INFO)); // // create console // if (p->ConsoleInfo.ConsoleHandle == NULL) { ProcessHandleRecord = ConsoleHeapAlloc(HANDLE_TAG, sizeof(CONSOLE_PROCESS_HANDLE)); if (ProcessHandleRecord == NULL) { Status = STATUS_NO_MEMORY; goto ErrorExit; } // // We are creating a new console, so derereference // the parent's console, if any. // if (ProcessData->ConsoleHandle != NULL) { RemoveConsole(ProcessData, Process->ProcessHandle, 0); } // // Get the desktop name. // if (p->DesktopLength) { strDesktopName.Buffer = ConsoleHeapAlloc(TMP_TAG, p->DesktopLength); if (strDesktopName.Buffer == NULL) { Status = STATUS_NO_MEMORY; goto ErrorExit; } Status = NtReadVirtualMemory(Process->ProcessHandle, (PVOID)p->Desktop, strDesktopName.Buffer, p->DesktopLength, NULL ); if (!NT_SUCCESS(Status)) { ConsoleHeapFree(strDesktopName.Buffer); goto ErrorExit; } strDesktopName.MaximumLength = (USHORT)p->DesktopLength; strDesktopName.Length = (USHORT)(p->DesktopLength - sizeof(WCHAR)); } else { RtlInitUnicodeString(&strDesktopName, L"Default"); } ProcessData->RootProcess = TRUE; Status = SetUpConsole(&p->ConsoleInfo, p->TitleLength, p->Title, p->CurDir, p->AppName, ProcessData, p->WindowVisible, &strDesktopName); if (p->DesktopLength) { ConsoleHeapFree(strDesktopName.Buffer); } if (!NT_SUCCESS(Status)) { goto ErrorExit; } // Play the Open sound for console apps ConsolePlaySound(); Status = RevalidateConsole(p->ConsoleInfo.ConsoleHandle, &Console); ASSERT (NT_SUCCESS(Status)); } else { ProcessHandleRecord = NULL; ProcessData->RootProcess = FALSE; Status = STATUS_SUCCESS; if (!(NT_SUCCESS(RevalidateConsole(p->ConsoleInfo.ConsoleHandle, &Console))) ) { Status = STATUS_PROCESS_IS_TERMINATING; goto ErrorExit; } if (Console->Flags & CONSOLE_SHUTTING_DOWN) { Status = STATUS_PROCESS_IS_TERMINATING; goto ErrorExit; } Status = MapEventHandles(CONSOLE_CLIENTPROCESSHANDLE(), Console, &p->ConsoleInfo ); if (!NT_SUCCESS(Status)) { goto ErrorExit; } ProcessHandleRecord = FindProcessInList(Console, CONSOLE_CLIENTPROCESSHANDLE()); if (ProcessHandleRecord) { ProcessHandleRecord->CtrlRoutine = p->CtrlRoutine; ProcessHandleRecord->PropRoutine = p->PropRoutine; ProcessHandleRecord = NULL; } } if (NT_SUCCESS(Status)) { // // Associate the correct window station with client process // so they can do Global atom calls. // if (DuplicateHandle( NtCurrentProcess(), Console->hWinSta, Process->ProcessHandle, &ConsoleWindowStationInfo.hwinsta, 0, FALSE, DUPLICATE_SAME_ACCESS ) ) { ConsoleWindowStationInfo.dwProcessId = HandleToUlong(CONSOLE_CLIENTPROCESSID()); NtUserConsoleControl(ConsoleWindowStationProcess, &ConsoleWindowStationInfo, sizeof(ConsoleWindowStationInfo)); } if (ProcessHandleRecord) { ProcessHandleRecord->Process = Process; ProcessHandleRecord->CtrlRoutine = p->CtrlRoutine; ProcessHandleRecord->PropRoutine = p->PropRoutine; AddProcessToList(Console, ProcessHandleRecord, CONSOLE_CLIENTPROCESSHANDLE()); } SetProcessForegroundRights(Process, Console->Flags & CONSOLE_HAS_FOCUS); AllocateCommandHistory(Console, p->AppNameLength, p->AppName, CONSOLE_CLIENTPROCESSHANDLE()); } else { ErrorExit: CONSOLE_SETCONSOLEAPPFROMPROCESSDATA(ProcessData, FALSE); if (ProcessHandleRecord) ConsoleHeapFree(ProcessHandleRecord); if (ProcessData->ConsoleHandle != NULL) { RemoveConsole(ProcessData, Process->ProcessHandle, 0); } } if (Console) { ConsoleNotifyWinEvent(Console, EVENT_CONSOLE_START_APPLICATION, HandleToULong(Process->ClientId.UniqueProcess), 0); UnlockConsole(Console); } } else if (ProcessData->ConsoleHandle != NULL) { // // This is a non-console app with a reference to a // reference to a parent console. Dereference the // console. // RemoveConsole(ProcessData, Process->ProcessHandle, 0); } return Status; } #if defined(FE_IME) VOID FreeConsoleIMEStuff( PCONSOLE_INFORMATION Console) { PCONVERSIONAREA_INFORMATION ConvAreaInfo; PCONVERSIONAREA_INFORMATION ConvAreaInfoNext; ConvAreaInfo = Console->ConsoleIme.ConvAreaRoot; while(ConvAreaInfo) { ConvAreaInfoNext = ConvAreaInfo->ConvAreaNext; FreeConvAreaScreenBuffer(ConvAreaInfo->ScreenBuffer); ConsoleHeapFree(ConvAreaInfo); ConvAreaInfo = ConvAreaInfoNext; } if (Console->ConsoleIme.NumberOfConvAreaCompStr) { ConsoleHeapFree(Console->ConsoleIme.ConvAreaCompStr); } if (Console->ConsoleIme.CompStrData) { ConsoleHeapFree(Console->ConsoleIme.CompStrData); } } #else #define FreeConsoleIMEStuff(Console) #endif NTSTATUS RemoveConsole( IN PCONSOLE_PER_PROCESS_DATA ProcessData, IN HANDLE ProcessHandle, IN HANDLE ProcessId) { ULONG i; PHANDLE_DATA HandleData; NTSTATUS Status; PCONSOLE_INFORMATION Console; Status = RevalidateConsole(ProcessData->ConsoleHandle, &Console); // // If this process isn't using the console, error. // if (!NT_SUCCESS(Status)) { ASSERT(FALSE); return Status; } if (Console->Flags & CONSOLE_NOTIFY_LAST_CLOSE) { if (Console->ProcessIdLastNotifyClose == ProcessId) { // // If this process is the one who wants last close notification, // remove it. // Console->Flags &= ~CONSOLE_NOTIFY_LAST_CLOSE; NtClose(Console->hProcessLastNotifyClose); } else if (ProcessData->RootProcess) { // // Notify the ntvdm process to terminate if the console root // process is going away. // HANDLE ConsoleHandle; CONSOLE_PROCESS_TERMINATION_RECORD ProcessHandleList; Console->Flags &= ~CONSOLE_NOTIFY_LAST_CLOSE; ConsoleHandle = Console->ConsoleHandle; ProcessHandleList.ProcessHandle = Console->hProcessLastNotifyClose; ProcessHandleList.TerminateCount = 0; ProcessHandleList.CtrlRoutine = CtrlRoutine; UnlockConsole(Console); CreateCtrlThread(&ProcessHandleList, 1, NULL, SYSTEM_ROOT_CONSOLE_EVENT, TRUE); NtClose(ProcessHandleList.ProcessHandle); Status = RevalidateConsole(ConsoleHandle, &Console); UserAssert(NT_SUCCESS(Status)); if (!NT_SUCCESS(Status)) { return STATUS_SUCCESS; } } } if (Console->VDMProcessId == ProcessId && (Console->Flags & CONSOLE_VDM_REGISTERED)) { Console->Flags &= ~CONSOLE_FULLSCREEN_NOPAINT; UnregisterVDM(Console); } if (ProcessHandle != NULL) { RemoveProcessFromList(Console, ProcessHandle); FreeCommandHistory(Console, ProcessHandle); } UserAssert(Console->RefCount); // // close the process's handles. // for (i = 0; i < ProcessData->HandleTableSize; i++) { if (ProcessData->HandleTablePtr[i].HandleType != CONSOLE_FREE_HANDLE) { Status = DereferenceIoHandleNoCheck(ProcessData, LongToHandle(i), &HandleData); UserAssert(NT_SUCCESS(Status)); if (HandleData->HandleType & CONSOLE_INPUT_HANDLE) { Status = CloseInputHandle(ProcessData, Console, HandleData, LongToHandle(i)); } else { Status = CloseOutputHandle(ProcessData, Console, HandleData, LongToHandle(i), FALSE); } } } FreeProcessData(ProcessData); ProcessData->ConsoleHandle = NULL; // // Decrement the console reference count. Free the console if it goes to // zero. // DerefConsole(Console); if (Console->RefCount == 0) { FreeConsoleIMEStuff(Console); FreeCon(Console); } else { // // The root process is going away, so we need to reparent it. // if (ProcessData->RootProcess) { PLIST_ENTRY ListHead = Console->ProcessHandleList.Flink; PCONSOLE_PROCESS_HANDLE ProcessHandleRecord; PCSR_THREAD Thread; HANDLE hThread; RIPMSG1(RIP_WARNING, "Reparenting console 0x%p", ProcessData); ProcessHandleRecord = CONTAINING_RECORD(ListHead, CONSOLE_PROCESS_HANDLE, ListLink); ListHead = ProcessHandleRecord->Process->ThreadList.Flink; Thread = CONTAINING_RECORD(ListHead, CSR_THREAD, Link); ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(ProcessHandleRecord->Process); UserAssert(ProcessData->RootProcess == FALSE); ProcessData->RootProcess = TRUE; Status = NtDuplicateObject(NtCurrentProcess(), Thread->ThreadHandle, NtCurrentProcess(), &hThread, 0, FALSE, DUPLICATE_SAME_ACCESS); if (NT_SUCCESS(Status)) { /* * We can only close this handle if the dup call above * succeeded. If it didn't, then we're going to zombie this * process, but at least we can keep going. */ NtClose(Console->ClientThreadHandle); Console->ClientThreadHandle = hThread; } else { RIPMSGF1(RIP_WARNING, "Failed to dup thread handle: Status = 0x%x", Status); } } UnlockConsole(Console); } return STATUS_SUCCESS; } VOID ConsoleClientDisconnectRoutine( IN PCSR_PROCESS Process) /*++ Routine Description: This routine is called when a process is destroyed. It closes the process's handles and frees the console if it's the last reference. Arguments: Process - Pointer to process structure. Return Value: --*/ { PCONSOLE_PER_PROCESS_DATA ProcessData; PCONSOLE_INFORMATION Console; NTSTATUS Status; ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(Process); // // If this process is not a console app, stop right here - no // disconnect processing is needed, because this app didn't create // or connect to an existing console. // if (ProcessData->ConsoleHandle == NULL) { #if defined(FE_IME) if (ProcessData->hDesk) { // // If this process is a Console IME, // should unregister console IME on this desktop. // RemoveConsoleIME(Process, HandleToUlong(Process->ClientId.UniqueThread)); } #endif return; } Status = RevalidateConsole(ProcessData->ConsoleHandle, &Console); if (NT_SUCCESS(Status)) { ConsoleNotifyWinEvent(Console, EVENT_CONSOLE_END_APPLICATION, HandleToULong(Process->ClientId.UniqueProcess), 0); UnlockConsole(Console); } else { RIPMSG2(RIP_WARNING, "RevalidateConsole returned status 0x%x on console 0x%x", Status, ProcessData->ConsoleHandle); } RemoveConsole(ProcessData, CONSOLE_FROMPROCESSPROCESSHANDLE(Process), Process->ClientId.UniqueProcess); CONSOLE_SETCONSOLEAPPFROMPROCESSDATA(ProcessData, FALSE); } ULONG SrvAllocConsole( IN OUT PCSR_API_MSG m, IN OUT PCSR_REPLY_STATUS ReplyStatus ) { PCONSOLE_ALLOC_MSG a = (PCONSOLE_ALLOC_MSG)&m->u.ApiMessageData; PCONSOLE_PER_PROCESS_DATA ProcessData; NTSTATUS Status; PCONSOLE_INFORMATION Console; PCONSOLE_PROCESS_HANDLE ProcessHandleRecord; PCSR_PROCESS Process; UNICODE_STRING strDesktopName; ProcessData = CONSOLE_PERPROCESSDATA(); ASSERT(!CONSOLE_GETCONSOLEAPPFROMPROCESSDATA(ProcessData)); if (!CsrValidateMessageBuffer(m, &a->Title, a->TitleLength, sizeof(BYTE)) || !CsrValidateMessageBuffer(m, &a->Desktop, a->DesktopLength, sizeof(BYTE)) || !CsrValidateMessageBuffer(m, &a->CurDir, a->CurDirLength, sizeof(BYTE)) || !CsrValidateMessageBuffer(m, &a->AppName, a->AppNameLength, sizeof(BYTE)) || !CsrValidateMessageBuffer(m, &a->ConsoleInfo, sizeof(*a->ConsoleInfo), sizeof(BYTE))) { return STATUS_INVALID_PARAMETER; } Process = (PCSR_PROCESS)(CSR_SERVER_QUERYCLIENTTHREAD()->Process); if (a->DesktopLength) { RtlInitUnicodeString(&strDesktopName, a->Desktop); } else { RtlInitUnicodeString(&strDesktopName, L"Default"); } ProcessHandleRecord = ConsoleHeapAlloc(HANDLE_TAG, sizeof(CONSOLE_PROCESS_HANDLE)); if (ProcessHandleRecord == NULL) { return (ULONG)STATUS_NO_MEMORY; } Status = SetUpConsole(a->ConsoleInfo, a->TitleLength, a->Title, a->CurDir, a->AppName, ProcessData, TRUE, &strDesktopName); if (!NT_SUCCESS(Status)) { ConsoleHeapFree(ProcessHandleRecord); return Status; } CONSOLE_SETCONSOLEAPP(TRUE); Process->Flags |= CSR_PROCESS_CONSOLEAPP; Status = RevalidateConsole(a->ConsoleInfo->ConsoleHandle,&Console); ASSERT (NT_SUCCESS(Status)); ProcessHandleRecord->Process = CSR_SERVER_QUERYCLIENTTHREAD()->Process; ProcessHandleRecord->CtrlRoutine = a->CtrlRoutine; ProcessHandleRecord->PropRoutine = a->PropRoutine; ASSERT (!(Console->Flags & CONSOLE_SHUTTING_DOWN)); AddProcessToList(Console, ProcessHandleRecord, CONSOLE_CLIENTPROCESSHANDLE()); SetProcessForegroundRights(Process, Console->Flags & CONSOLE_HAS_FOCUS); AllocateCommandHistory(Console, a->AppNameLength, a->AppName, CONSOLE_CLIENTPROCESSHANDLE()); UnlockConsole(Console); return STATUS_SUCCESS; UNREFERENCED_PARAMETER(ReplyStatus); } ULONG SrvFreeConsole( IN OUT PCSR_API_MSG m, IN OUT PCSR_REPLY_STATUS ReplyStatus ) { PCONSOLE_FREE_MSG a = (PCONSOLE_FREE_MSG)&m->u.ApiMessageData; PCONSOLE_PER_PROCESS_DATA ProcessData; NTSTATUS Status; ProcessData = CONSOLE_PERPROCESSDATA(); ASSERT (CONSOLE_GETCONSOLEAPPFROMPROCESSDATA(ProcessData)); if (CONSOLE_GETCONSOLEHANDLEFROMPROCESSDATA(ProcessData) != a->ConsoleHandle) { RIPMSG1(RIP_WARNING, "SrvFreeConsole: invalid console handle %x", a->ConsoleHandle); return STATUS_INVALID_HANDLE; } Status = RemoveConsole(ProcessData, CONSOLE_CLIENTPROCESSHANDLE(), CONSOLE_CLIENTPROCESSID()); if (NT_SUCCESS(Status)) { CONSOLE_SETCONSOLEAPP(FALSE); } return Status; UNREFERENCED_PARAMETER(ReplyStatus); } ULONG SrvAttachConsole( IN OUT PCSR_API_MSG m, IN OUT PCSR_REPLY_STATUS ReplyStatus ) { PCONSOLE_ATTACH_MSG a = (PCONSOLE_ATTACH_MSG)&m->u.ApiMessageData; DWORD ProcessId; NTSTATUS Status; PCSR_PROCESS ParentProcess; PCSR_PROCESS Process; CLIENT_ID ClientId; OBJECT_ATTRIBUTES Obja; HANDLE ProcessHandle; PCONSOLE_INFORMATION Console; PCONSOLE_PER_PROCESS_DATA ProcessData; PCONSOLE_PER_PROCESS_DATA ParentProcessData; PCONSOLE_PROCESS_HANDLE ProcessHandleRecord; Process = (PCSR_PROCESS)(CSR_SERVER_QUERYCLIENTTHREAD()->Process); // // Make sure we have a valid buffer // if (!CsrValidateMessageBuffer(m, &a->ConsoleInfo, sizeof(*a->ConsoleInfo), sizeof(BYTE))) { return STATUS_INVALID_PARAMETER; } // // Make sure we're not already attached to a console // ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(Process); if (CONSOLE_GETCONSOLEAPPFROMPROCESSDATA(ProcessData)) { return STATUS_ACCESS_DENIED; } // // Figure out what process we're attaching to. // if (a->ProcessId == (DWORD)-1) { ProcessId = ProcessData->ParentProcessId; } else { ProcessId = a->ProcessId; } // // Lock the process we're attaching to so it can't go away. // Status = CsrLockProcessByClientId(LongToHandle(ProcessId), &ParentProcess); if (!NT_SUCCESS(Status)) { return Status; } // // Make sure we have access to the process. // if (!CsrImpersonateClient(NULL)) { CsrUnlockProcess(ParentProcess); return STATUS_BAD_IMPERSONATION_LEVEL; } ClientId.UniqueThread = NULL; ClientId.UniqueProcess = UlongToHandle(ProcessId); InitializeObjectAttributes( &Obja, NULL, 0, NULL, NULL ); Status = NtOpenProcess( &ProcessHandle, PROCESS_ALL_ACCESS, &Obja, &ClientId ); CsrRevertToSelf(); if (!NT_SUCCESS(Status)) { CsrUnlockProcess(ParentProcess); return Status; } NtClose(ProcessHandle); // // Add current process to parent process's console. // Process->Flags |= CSR_PROCESS_CONSOLEAPP; ParentProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(ParentProcess); *ProcessData = *ParentProcessData; Status = ConsoleAddProcessRoutine(ParentProcess, Process); if (NT_SUCCESS(Status)) { CONSOLE_SETCONSOLEAPP(TRUE); Status = RevalidateConsole(ProcessData->ConsoleHandle, &Console); } CsrUnlockProcess(ParentProcess); if (!NT_SUCCESS(Status)) { return Status; } // // Initialize per process console settings. // Status = MapEventHandles(CONSOLE_CLIENTPROCESSHANDLE(), Console, a->ConsoleInfo ); if (!NT_SUCCESS(Status)) { CONSOLE_SETCONSOLEAPPFROMPROCESSDATA(ProcessData, FALSE); UnlockConsole(Console); RemoveConsole(ProcessData, Process->ProcessHandle, 0); return Status; } NtCurrentPeb()->ProcessParameters->ConsoleHandle = a->ConsoleInfo->ConsoleHandle = ProcessData->ConsoleHandle; a->ConsoleInfo->StdIn = INDEX_TO_HANDLE(0); a->ConsoleInfo->StdOut = INDEX_TO_HANDLE(1); a->ConsoleInfo->StdErr = INDEX_TO_HANDLE(2); ProcessHandleRecord = FindProcessInList(Console, CONSOLE_CLIENTPROCESSHANDLE()); if (ProcessHandleRecord) { ProcessHandleRecord->CtrlRoutine = a->CtrlRoutine; ProcessHandleRecord->PropRoutine = a->PropRoutine; } SetProcessForegroundRights(Process, Console->Flags & CONSOLE_HAS_FOCUS); UnlockConsole(Console); return Status; UNREFERENCED_PARAMETER(ReplyStatus); } NTSTATUS MyRegOpenKey( IN HANDLE hKey, IN LPWSTR lpSubKey, OUT PHANDLE phResult ) { OBJECT_ATTRIBUTES Obja; UNICODE_STRING SubKey; // // Convert the subkey to a counted Unicode string. // RtlInitUnicodeString( &SubKey, lpSubKey ); // // Initialize the OBJECT_ATTRIBUTES structure and open the key. // InitializeObjectAttributes( &Obja, &SubKey, OBJ_CASE_INSENSITIVE, hKey, NULL ); return NtOpenKey( phResult, KEY_READ, &Obja ); } NTSTATUS MyRegQueryValue( IN HANDLE hKey, IN LPWSTR lpValueName, IN DWORD dwValueLength, OUT LPBYTE lpData ) { UNICODE_STRING ValueName; ULONG BufferLength; ULONG ResultLength; PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation; NTSTATUS Status; // // Convert the subkey to a counted Unicode string. // RtlInitUnicodeString( &ValueName, lpValueName ); BufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + dwValueLength; KeyValueInformation = ConsoleHeapAlloc(TMP_TAG, BufferLength); if (KeyValueInformation == NULL) return STATUS_NO_MEMORY; Status = NtQueryValueKey( hKey, &ValueName, KeyValuePartialInformation, KeyValueInformation, BufferLength, &ResultLength ); if (NT_SUCCESS(Status)) { ASSERT(KeyValueInformation->DataLength <= dwValueLength); RtlCopyMemory(lpData, KeyValueInformation->Data, KeyValueInformation->DataLength); if (KeyValueInformation->Type == REG_SZ || KeyValueInformation->Type == REG_MULTI_SZ ) { if (KeyValueInformation->DataLength + sizeof(WCHAR) > dwValueLength) { KeyValueInformation->DataLength -= sizeof(WCHAR); } lpData[KeyValueInformation->DataLength++] = 0; lpData[KeyValueInformation->DataLength] = 0; } } ConsoleHeapFree(KeyValueInformation); return Status; } #if defined(FE_SB) NTSTATUS MyRegQueryValueEx( IN HANDLE hKey, IN LPWSTR lpValueName, IN DWORD dwValueLength, OUT LPBYTE lpData, OUT LPDWORD lpDataLength ) { UNICODE_STRING ValueName; ULONG BufferLength; ULONG ResultLength; PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation; NTSTATUS Status; // // Convert the subkey to a counted Unicode string. // RtlInitUnicodeString( &ValueName, lpValueName ); BufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + dwValueLength; KeyValueInformation = ConsoleHeapAlloc(TMP_TAG, BufferLength); if (KeyValueInformation == NULL) return STATUS_NO_MEMORY; Status = NtQueryValueKey( hKey, &ValueName, KeyValuePartialInformation, KeyValueInformation, BufferLength, &ResultLength ); if (NT_SUCCESS(Status)) { ASSERT(KeyValueInformation->DataLength <= dwValueLength); RtlCopyMemory(lpData, KeyValueInformation->Data, KeyValueInformation->DataLength); if (lpDataLength) { *lpDataLength = KeyValueInformation->DataLength; } } ConsoleHeapFree(KeyValueInformation); return Status; } NTSTATUS MyRegEnumValue( IN HANDLE hKey, IN DWORD dwIndex, OUT DWORD dwValueLength, OUT LPWSTR lpValueName, OUT DWORD dwDataLength, OUT LPBYTE lpData ) { ULONG BufferLength; ULONG ResultLength; PKEY_VALUE_FULL_INFORMATION KeyValueInformation; NTSTATUS Status; // // Convert the subkey to a counted Unicode string. // BufferLength = sizeof(KEY_VALUE_FULL_INFORMATION) + dwValueLength + dwDataLength; KeyValueInformation = ConsoleHeapAlloc(TMP_TAG, BufferLength); if (KeyValueInformation == NULL) return STATUS_NO_MEMORY; Status = NtEnumerateValueKey( hKey, dwIndex, KeyValueFullInformation, KeyValueInformation, BufferLength, &ResultLength ); if (NT_SUCCESS(Status)) { ASSERT(KeyValueInformation->NameLength <= dwValueLength); RtlMoveMemory(lpValueName, KeyValueInformation->Name, KeyValueInformation->NameLength); lpValueName[ KeyValueInformation->NameLength >> 1 ] = UNICODE_NULL; ASSERT(KeyValueInformation->DataLength <= dwDataLength); RtlMoveMemory(lpData, (PBYTE)KeyValueInformation + KeyValueInformation->DataOffset, KeyValueInformation->DataLength); if (KeyValueInformation->Type == REG_SZ) { if (KeyValueInformation->DataLength + sizeof(WCHAR) > dwDataLength) { KeyValueInformation->DataLength -= sizeof(WCHAR); } lpData[KeyValueInformation->DataLength++] = 0; lpData[KeyValueInformation->DataLength] = 0; } } ConsoleHeapFree(KeyValueInformation); return Status; } #endif #define SYSTEM_ROOT (L"%SystemRoot%") #define SYSTEM_ROOT_LENGTH (sizeof(SYSTEM_ROOT) - sizeof(WCHAR)) LPWSTR TranslateConsoleTitle( LPWSTR ConsoleTitle, PUSHORT pcbTranslatedTitle, BOOL Unexpand, BOOL Substitute ) /*++ Routine Description: This routine translates path characters into '_' characters because the NT registry apis do not allow the creation of keys with names that contain path characters. It also converts absolute paths into %SystemRoot% relative ones. As an example, if both behaviors were specified it would convert a title like C:\WINNT\System32\cmd.exe to %SystemRoot%_System32_cmd.exe. Arguments: ConsoleTitle - Pointer to string to translate. pcbTranslatedTitle - On return, contains size of translated title. Unexpand - Convert absolute path to %SystemRoot% relative one. Substitute - Replace '\' with '_' in path. Return Value: Pointer to translated title or NULL. Note: This routine allocates a buffer that must be freed. --*/ { USHORT cbConsoleTitle, i; USHORT cbSystemRoot; LPWSTR TranslatedConsoleTitle, Tmp; cbConsoleTitle = (USHORT)((lstrlenW(ConsoleTitle) + 1) * sizeof(WCHAR)); cbSystemRoot = (USHORT)(lstrlenW(USER_SHARED_DATA->NtSystemRoot) * sizeof(WCHAR)); if (Unexpand && !MyStringCompareW(ConsoleTitle, USER_SHARED_DATA->NtSystemRoot, cbSystemRoot, TRUE)) { cbConsoleTitle -= cbSystemRoot; (PBYTE)ConsoleTitle += cbSystemRoot; cbSystemRoot = SYSTEM_ROOT_LENGTH; } else { cbSystemRoot = 0; } Tmp = TranslatedConsoleTitle = ConsoleHeapAlloc(TITLE_TAG, cbSystemRoot + cbConsoleTitle); if (TranslatedConsoleTitle == NULL) { return NULL; } RtlCopyMemory(TranslatedConsoleTitle, SYSTEM_ROOT, cbSystemRoot); (PBYTE)TranslatedConsoleTitle += cbSystemRoot; for (i=0;iConsoleHandle == NULL) && (ProcessData->hDesk != NULL)) { // // If this process is a Console IME, // should unregister console IME on this desktop. // RemoveConsoleIME(Process, HandleToUlong(Process->ClientId.UniqueThread)); } #endif if (fFirstPass) { return SHUTDOWN_UNKNOWN_PROCESS; } return NonConsoleProcessShutdown(Process, Flags); } // // Find the console structure pointer. // ConsoleHandle = CONSOLE_GETCONSOLEHANDLEFROMPROCESSDATA(ProcessData); Status = RevalidateConsole( ConsoleHandle, &Console); if (!NT_SUCCESS(Status)) { return SHUTDOWN_UNKNOWN_PROCESS; } // // If this is the invisible WOW console, return UNKNOWN so USER // enumerates 16-bit gui apps. // if ((Console->Flags & CONSOLE_NO_WINDOW) && (Console->Flags & CONSOLE_WOW_REGISTERED)) { UnlockConsole(Console); return SHUTDOWN_UNKNOWN_PROCESS; } // // Sometimes the console structure is around even though the // hWnd has been NULLed out. In this case, go to non-console // process shutdown. // hWnd = Console->hWnd; if (hWnd == NULL || !IsWindow(hWnd)) { UnlockConsole(Console); return NonConsoleProcessShutdown(Process, Flags); } // // Make a copy of the console termination event // Status = NtDuplicateObject(NtCurrentProcess(), Console->TerminationEvent, NtCurrentProcess(), &TerminationEvent, 0, FALSE, DUPLICATE_SAME_ACCESS ); if (!NT_SUCCESS(Status)) { UnlockConsole(Console); return NonConsoleProcessShutdown(Process, Flags); } // // Attach to the desktop. // utudi.hThread = Console->InputThreadInfo->ThreadHandle; utudi.drdRestore.pdeskRestore = NULL; Status = NtUserSetInformationThread(NtCurrentThread(), UserThreadUseDesktop, &utudi, sizeof(utudi)); UnlockConsole(Console); if (!NT_SUCCESS(Status)) { NtClose(TerminationEvent); return NonConsoleProcessShutdown(Process, Flags); } // // We're done looking at this process structure, so dereference it. // CsrDereferenceProcess(Process); // // Synchronously talk to this console. // Status = ShutdownConsole(ConsoleHandle, Flags); // // Detach from the desktop. // utudi.hThread = NULL; NtUserSetInformationThread(NtCurrentThread(), UserThreadUseDesktop, &utudi, sizeof(utudi)); // // If Status == STATUS_PROCESS_IS_TERMINATING, then we should wait // for the console to exit. // if (Status == STATUS_PROCESS_IS_TERMINATING) { WaitStatus = InternalWaitCancel(TerminationEvent, 500000); if (WaitStatus == STATUS_WAIT_1) { Status = SHUTDOWN_CANCEL; } else if (WaitStatus != STATUS_TIMEOUT) { Status = SHUTDOWN_KNOWN_PROCESS; } else { #if DBG PLIST_ENTRY ListHead, ListNext; PCONSOLE_PROCESS_HANDLE ProcessHandleRecord; PCSR_PROCESS Process; RIPMSG0(RIP_ERROR | RIP_THERESMORE, "********************************************"); RIPMSG1(RIP_ERROR | RIP_THERESMORE, "Shutdown wait timed out on console %p", Console); RIPMSG1(RIP_ERROR | RIP_THERESMORE, "Reference count is %d", Console->RefCount); RIPMSG0(RIP_ERROR | RIP_THERESMORE, "Dump these processes and see if they're hung"); ListHead = &Console->ProcessHandleList; ListNext = ListHead->Flink; while (ListNext != ListHead) { ProcessHandleRecord = CONTAINING_RECORD(ListNext, CONSOLE_PROCESS_HANDLE, ListLink); Process = ProcessHandleRecord->Process; RIPMSG2(RIP_ERROR | RIP_THERESMORE, "CsrProcess = %p ProcessId = %x", Process, Process->ClientId.UniqueProcess); ListNext = ListNext->Flink; } RIPMSG0(RIP_ERROR, "********************************************"); #endif Status = SHUTDOWN_CANCEL; } } NtClose(TerminationEvent); return Status; } ULONG NonConsoleProcessShutdown( PCSR_PROCESS Process, DWORD dwFlags ) { CONSOLE_PROCESS_TERMINATION_RECORD TerminateRecord; DWORD EventType; BOOL Success; HANDLE ProcessHandle; Success = DuplicateHandle(NtCurrentProcess(), Process->ProcessHandle, NtCurrentProcess(), &ProcessHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); if (!Success) ProcessHandle = Process->ProcessHandle; TerminateRecord.ProcessHandle = ProcessHandle; TerminateRecord.TerminateCount = 0; TerminateRecord.CtrlRoutine = CtrlRoutine; CsrDereferenceProcess(Process); EventType = CTRL_LOGOFF_EVENT; if (dwFlags & EWX_SHUTDOWN) EventType = CTRL_SHUTDOWN_EVENT; CreateCtrlThread(&TerminateRecord, 1, NULL, EventType, TRUE); if (Success) CloseHandle(ProcessHandle); return SHUTDOWN_KNOWN_PROCESS; } VOID InitializeConsoleAttributes( VOID ) /*++ Routine Description: This routine initializes default attributes from the current user's registry values. It gets called during logon/logoff. Arguments: none Return Value: none --*/ { // // Store default values in structure and mark it // as invalid (by resetting LastWriteTime). // DefaultRegInfo.ScreenFill.Attributes = 0x07; // white on black DefaultRegInfo.ScreenFill.Char.UnicodeChar = (WCHAR)' '; DefaultRegInfo.PopupFill.Attributes = 0xf5; // purple on white DefaultRegInfo.PopupFill.Char.UnicodeChar = (WCHAR)' '; DefaultRegInfo.InsertMode = FALSE; DefaultRegInfo.QuickEdit = FALSE; DefaultRegInfo.AutoPosition = TRUE; DefaultRegInfo.FullScreen = FALSE; DefaultRegInfo.ScreenBufferSize.X = 80; DefaultRegInfo.ScreenBufferSize.Y = 25; DefaultRegInfo.WindowSize.X = 80; DefaultRegInfo.WindowSize.Y = 25; DefaultRegInfo.WindowOrigin.X = 0; DefaultRegInfo.WindowOrigin.Y = 0; DefaultRegInfo.FontSize.X = 0; DefaultRegInfo.FontSize.Y = 0; DefaultRegInfo.FontFamily = 0; DefaultRegInfo.FontWeight = 0; DefaultRegInfo.FaceName[0] = L'\0'; DefaultRegInfo.CursorSize = CURSOR_SMALL_SIZE; DefaultRegInfo.HistoryBufferSize = DEFAULT_NUMBER_OF_COMMANDS; DefaultRegInfo.NumberOfHistoryBuffers = DEFAULT_NUMBER_OF_BUFFERS; DefaultRegInfo.HistoryNoDup = FALSE; DefaultRegInfo.ColorTable[ 0] = RGB(0, 0, 0 ); DefaultRegInfo.ColorTable[ 1] = RGB(0, 0, 0x80); DefaultRegInfo.ColorTable[ 2] = RGB(0, 0x80,0 ); DefaultRegInfo.ColorTable[ 3] = RGB(0, 0x80,0x80); DefaultRegInfo.ColorTable[ 4] = RGB(0x80,0, 0 ); DefaultRegInfo.ColorTable[ 5] = RGB(0x80,0, 0x80); DefaultRegInfo.ColorTable[ 6] = RGB(0x80,0x80,0 ); DefaultRegInfo.ColorTable[ 7] = RGB(0xC0,0xC0,0xC0); DefaultRegInfo.ColorTable[ 8] = RGB(0x80,0x80,0x80); DefaultRegInfo.ColorTable[ 9] = RGB(0, 0, 0xFF); DefaultRegInfo.ColorTable[10] = RGB(0, 0xFF,0 ); DefaultRegInfo.ColorTable[11] = RGB(0, 0xFF,0xFF); DefaultRegInfo.ColorTable[12] = RGB(0xFF,0, 0 ); DefaultRegInfo.ColorTable[13] = RGB(0xFF,0, 0xFF); DefaultRegInfo.ColorTable[14] = RGB(0xFF,0xFF,0 ); DefaultRegInfo.ColorTable[15] = RGB(0xFF,0xFF,0xFF); #if defined(FE_SB) // scotthsu DefaultRegInfo.CodePage = OEMCP; #endif DefaultRegInfo.LastWriteTime = 0; // // Get system metrics for this user // InitializeSystemMetrics(); } VOID GetRegistryValues( IN LPWSTR ConsoleTitle, OUT PCONSOLE_REGISTRY_INFO RegInfo ) /*++ Routine Description: This routine reads in values from the registry and places them in the supplied structure. Arguments: ConsoleTitle - name of subkey to open RegInfo - pointer to structure to receive information Return Value: none --*/ { HANDLE hCurrentUserKey; HANDLE hConsoleKey; HANDLE hTitleKey; NTSTATUS Status; LPWSTR TranslatedConsoleTitle; DWORD dwValue; DWORD i; WCHAR awchFaceName[LF_FACESIZE]; WCHAR awchBuffer[64]; KEY_BASIC_INFORMATION KeyInfo; ULONG ResultLength; // // Impersonate the client process // if (!CsrImpersonateClient(NULL)) { RIPMSG0(RIP_WARNING, "GetRegistryValues Impersonate failed"); return; } // // Open the current user registry key // Status = RtlOpenCurrentUser(MAXIMUM_ALLOWED, &hCurrentUserKey); if (!NT_SUCCESS(Status)) { CsrRevertToSelf(); return; } // // Open the console registry key // Status = MyRegOpenKey(hCurrentUserKey, CONSOLE_REGISTRY_STRING, &hConsoleKey); if (!NT_SUCCESS(Status)) { NtClose(hCurrentUserKey); CsrRevertToSelf(); return; } // // If we're not reading the default key, check if the default values // need to be updated // Status = NtQueryKey(hConsoleKey, KeyBasicInformation, &KeyInfo, sizeof(KeyInfo), &ResultLength); if (!NT_ERROR(Status)) { if (DefaultRegInfo.LastWriteTime != KeyInfo.LastWriteTime.QuadPart) { DefaultRegInfo.LastWriteTime = KeyInfo.LastWriteTime.QuadPart; if (RegInfo != &DefaultRegInfo) { GetRegistryValues(L"", &DefaultRegInfo); *RegInfo = DefaultRegInfo; } } } // // Open the console title subkey // TranslatedConsoleTitle = TranslateConsoleTitle(ConsoleTitle, NULL, TRUE, TRUE); if (TranslatedConsoleTitle == NULL) { NtClose(hConsoleKey); NtClose(hCurrentUserKey); CsrRevertToSelf(); return; } Status = MyRegOpenKey(hConsoleKey, TranslatedConsoleTitle, &hTitleKey); ConsoleHeapFree(TranslatedConsoleTitle); if (!NT_SUCCESS(Status)) { TranslatedConsoleTitle = TranslateConsoleTitle(ConsoleTitle, NULL, FALSE, TRUE); if (TranslatedConsoleTitle) { Status = MyRegOpenKey(hConsoleKey, TranslatedConsoleTitle, &hTitleKey); ConsoleHeapFree(TranslatedConsoleTitle); } } if (!NT_SUCCESS(Status)) { NtClose(hConsoleKey); NtClose(hCurrentUserKey); CsrRevertToSelf(); return; } // // Initial screen fill // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_FILLATTR, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->ScreenFill.Attributes = (WORD)dwValue; } // // Initial popup fill // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_POPUPATTR, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->PopupFill.Attributes = (WORD)dwValue; } // // Initial insert mode // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_INSERTMODE, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->InsertMode = !!dwValue; } // // Initial quick edit mode // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_QUICKEDIT, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->QuickEdit = !!dwValue; } #ifdef i386 // // Initial full screen mode // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_FULLSCR, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->FullScreen = !!dwValue; } #endif #if defined(FE_SB) // scotthsu // // Code Page // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_CODEPAGE, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->CodePage = (UINT)dwValue; // If this routine specified default settings for console property, // then make sure code page value when Fae East environment. // If code page value does not the same to OEMCP and any FE's code page then // we are override code page value to OEMCP on default console property. // Because, Far East environment has limitation that doesn not switch to // another FE's code page by the SetConsoleCP/SetConsoleOutputCP. // // Compare of ConsoleTitle and L"" has limit to default property of console. // It means, this code doesn't care user defined property. // Content of user defined property has responsibility to themselves. if (wcscmp(ConsoleTitle, L"") == 0 && IsAvailableFarEastCodePage(RegInfo->CodePage) && OEMCP != RegInfo->CodePage) { RegInfo->CodePage = OEMCP; } } #endif // FE_SB // // Initial screen buffer size // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_BUFFERSIZE, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->ScreenBufferSize.X = LOWORD(dwValue); RegInfo->ScreenBufferSize.Y = HIWORD(dwValue); if (RegInfo->ScreenBufferSize.X <= 0) RegInfo->ScreenBufferSize.X = 1; if (RegInfo->ScreenBufferSize.Y <= 0) RegInfo->ScreenBufferSize.Y = 1; } // // Initial window size // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_WINDOWSIZE, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->WindowSize.X = LOWORD(dwValue); RegInfo->WindowSize.Y = HIWORD(dwValue); if (RegInfo->WindowSize.X <= 0) RegInfo->WindowSize.X = 1; else if (RegInfo->WindowSize.X > RegInfo->ScreenBufferSize.X) RegInfo->WindowSize.X = RegInfo->ScreenBufferSize.X; if (RegInfo->WindowSize.Y <= 0) RegInfo->WindowSize.Y = 1; else if (RegInfo->WindowSize.Y > RegInfo->ScreenBufferSize.Y) RegInfo->WindowSize.Y = RegInfo->ScreenBufferSize.Y; } // // Initial window position // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_WINDOWPOS, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->WindowOrigin.X = LOWORD(dwValue); RegInfo->WindowOrigin.Y = HIWORD(dwValue); RegInfo->AutoPosition = FALSE; } // // Initial font size // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_FONTSIZE, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->FontSize.X = LOWORD(dwValue); RegInfo->FontSize.Y = HIWORD(dwValue); } // // Initial font family // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_FONTFAMILY, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->FontFamily = dwValue; } // // Initial font weight // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_FONTWEIGHT, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->FontWeight = dwValue; } // // Initial font face name // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_FACENAME, sizeof(awchFaceName), (PBYTE)awchFaceName))) { RtlCopyMemory(RegInfo->FaceName, awchFaceName, sizeof(awchFaceName)); RegInfo->FaceName[NELEM(RegInfo->FaceName) - 1] = 0; } // // Initial cursor size // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_CURSORSIZE, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->CursorSize = dwValue; } // // Initial history buffer size // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_HISTORYSIZE, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->HistoryBufferSize = dwValue; } // // Initial number of history buffers // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_HISTORYBUFS, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->NumberOfHistoryBuffers = dwValue; } // // Initial history duplication mode // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_HISTORYNODUP, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->HistoryNoDup = dwValue; } for (i=0; i<16; i++) { wsprintf(awchBuffer, CONSOLE_REGISTRY_COLORTABLE, i); if (NT_SUCCESS(MyRegQueryValue(hTitleKey, awchBuffer, sizeof(dwValue), (PBYTE)&dwValue))) { RegInfo->ColorTable[ i ] = dwValue; } } if (RegInfo == &DefaultRegInfo) { // // If the common (default) setting has been changed, // // // Get registry for conime flag // if (NT_SUCCESS(MyRegQueryValue(hConsoleKey, CONSOLE_REGISTRY_LOAD_CONIME, sizeof dwValue, (PBYTE)&dwValue))) { gfLoadConIme = (dwValue != 0); } else { gfLoadConIme = TRUE; } // // get extended edit mode and keys from registry. // if (NT_SUCCESS(MyRegQueryValue(hConsoleKey, CONSOLE_REGISTRY_EXTENDEDEDITKEY, sizeof dwValue, (PBYTE)&dwValue)) && dwValue <= 1) { ExtKeyDefBuf buf; gExtendedEditKey = dwValue; // // Initialize Extended Edit keys // InitExtendedEditKeys(NULL); if (NT_SUCCESS(MyRegQueryValue(hConsoleKey, CONSOLE_REGISTRY_EXTENDEDEDITKEY_CUSTOM, sizeof(buf), (PBYTE)&buf))) { InitExtendedEditKeys(&buf); } else { RIPMSG0(RIP_VERBOSE, "Error reading ExtendedEditkeyCustom."); } } else { gExtendedEditKey = 0; RIPMSG0(RIP_VERBOSE, "Error reading ExtendedEditkey."); } // // Word delimiters // if (gExtendedEditKey) { // If extended edit key is given, provide extended word delimiters // by default. memcpy((LPBYTE)gaWordDelimChars, (LPBYTE)gaWordDelimCharsDefault, sizeof gaWordDelimChars[0] * WORD_DELIM_MAX); } else { // Otherwise, stick to the original word delimiter. gaWordDelimChars[0] = L'\0'; } // Read word delimiters from registry if (NT_SUCCESS(MyRegQueryValue(hConsoleKey, CONSOLE_REGISTRY_WORD_DELIM, sizeof awchBuffer, (PBYTE)awchBuffer))) { // OK, copy it to the word delimiter array. wcsncpy(gaWordDelimChars, awchBuffer, WORD_DELIM_MAX); gaWordDelimChars[WORD_DELIM_MAX - 1] = 0; } // // Read Trim Zero Heading flag // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_TRIMZEROHEADINGS, sizeof(dwValue), (PBYTE)&dwValue))) { gfTrimLeadingZeros = dwValue; } else { gfTrimLeadingZeros = FALSE; } // // Color selected area function enable flag // if (NT_SUCCESS(MyRegQueryValue(hTitleKey, CONSOLE_REGISTRY_ENABLE_COLOR_SELECTION, sizeof(dwValue), (PBYTE)&dwValue))) { gfEnableColorSelection = !!dwValue; } else { gfEnableColorSelection = FALSE; } } // // Close the registry keys // NtClose(hTitleKey); NtClose(hConsoleKey); NtClose(hCurrentUserKey); CsrRevertToSelf(); } NTSTATUS GetConsoleLangId( IN UINT OutputCP, OUT LANGID* pLangId ) { NTSTATUS Status; if (CONSOLE_IS_DBCS_ENABLED()){ if (pLangId != NULL) { switch (OutputCP) { case 932: *pLangId = MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT); break; case 949: *pLangId = MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN); break; case 936: *pLangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED); break; case 950: *pLangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL); break; default: *pLangId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); break; } } Status = STATUS_SUCCESS; } else { Status = STATUS_NOT_SUPPORTED; } return Status; } ULONG SrvGetConsoleLangId( IN OUT PCSR_API_MSG m, IN OUT PCSR_REPLY_STATUS ReplyStatus ) { PCONSOLE_LANGID_MSG a = (PCONSOLE_LANGID_MSG)&m->u.ApiMessageData; NTSTATUS Status; PCONSOLE_INFORMATION Console; Status = ApiPreamble(a->ConsoleHandle, &Console ); if (!NT_SUCCESS(Status)) { return Status; } Status = GetConsoleLangId(Console->OutputCP, &a->LangId); UnlockConsole(Console); return Status; UNREFERENCED_PARAMETER(ReplyStatus); }