// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. #include "pch.h" #include "SampleAppHost.h" #include "resource.h" #include "../types/inc/User32Utils.hpp" #include using namespace winrt; using namespace winrt::Windows::UI; using namespace winrt::Windows::UI::Composition; using namespace winrt::Windows::UI::Xaml::Hosting; using namespace winrt::Windows::Foundation::Numerics; // Routine Description: // - Takes an image architecture and locates a string resource that maps to that architecture. // Arguments: // - imageArchitecture - An IMAGE_FILE_MACHINE architecture enum value // - See https://docs.microsoft.com/en-us/windows/win32/sysinfo/image-file-machine-constants // Return Value: // - A string value representing the human-readable name of this architecture. static std::wstring ImageArchitectureToString(USHORT imageArchitecture) { // clang-format off const auto id = imageArchitecture == IMAGE_FILE_MACHINE_I386 ? IDS_X86_ARCHITECTURE : imageArchitecture == IMAGE_FILE_MACHINE_AMD64 ? IDS_AMD64_ARCHITECTURE : imageArchitecture == IMAGE_FILE_MACHINE_ARM64 ? IDS_ARM64_ARCHITECTURE : imageArchitecture == IMAGE_FILE_MACHINE_ARM ? IDS_ARM_ARCHITECTURE : IDS_UNKNOWN_ARCHITECTURE; // clang-format on return GetStringResource(id); } // Routine Description: // - Blocks the user from launching the application with a message box dialog and early exit // if the process architecture doesn't match the system platform native architecture. // - This is because the conhost.exe must match the condrv.sys on the system and the PTY // infrastructure that powers everything won't work if we have a mismatch. // Arguments: // - // Return Value: // - static void EnsureNativeArchitecture() { USHORT processMachine{}; USHORT nativeMachine{}; THROW_IF_WIN32_BOOL_FALSE(IsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine)); if (processMachine != IMAGE_FILE_MACHINE_UNKNOWN && processMachine != nativeMachine) { const auto formatPattern = GetStringResource(IDS_ERROR_ARCHITECTURE_FORMAT); const auto nativeArchitecture = ImageArchitectureToString(nativeMachine); const auto processArchitecture = ImageArchitectureToString(processMachine); auto buffer{ wil::str_printf(formatPattern.data(), nativeArchitecture.data(), processArchitecture.data()) }; MessageBoxW(nullptr, buffer.data(), GetStringResource(IDS_ERROR_DIALOG_TITLE).data(), MB_OK | MB_ICONERROR); ExitProcess(0); } } static bool _messageIsF7Keypress(const MSG& message) { return (message.message == WM_KEYDOWN || message.message == WM_SYSKEYDOWN) && message.wParam == VK_F7; } static bool _messageIsAltKeyup(const MSG& message) { return (message.message == WM_KEYUP || message.message == WM_SYSKEYUP) && message.wParam == VK_MENU; } int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) { // If Terminal is spawned by a shortcut that requests that it run in a new process group // while attached to a console session, that request is nonsense. That request will, however, // cause WT to start with Ctrl-C disabled. This wouldn't matter, because it's a Windows-subsystem // application. Unfortunately, that state is heritable. In short, if you start WT using cmd in // a weird way, ^C stops working _inside_ the terminal. Mad. SetConsoleCtrlHandler(NULL, FALSE); // Block the user from starting if they launched the incorrect architecture version of the project. // This should only be applicable to developer versions. The package installation process // should choose and install the correct one from the bundle. EnsureNativeArchitecture(); // Make sure to call this so we get WM_POINTER messages. EnableMouseInPointer(true); // !!! LOAD BEARING !!! // We must initialize the main thread as a single-threaded apartment before // constructing any Xaml objects. Failing to do so will cause some issues // in accessibility somewhere down the line when a UIAutomation object will // be queried on the wrong thread at the wrong time. // We used to initialize as STA only _after_ initializing the application // host, which loaded the settings. The settings needed to be loaded in MTA // because we were using the Windows.Storage APIs. Since we're no longer // doing that, we can safely init as STA before any WinRT dispatches. winrt::init_apartment(winrt::apartment_type::single_threaded); // Create the SampleAppHost object, which will create both the window and the // Terminal App. This MUST BE constructed before the Xaml manager as TermApp // provides an implementation of Windows.UI.Xaml.Application. SampleAppHost host; // Initialize the xaml content. This must be called AFTER the // WindowsXamlManager is initialized. host.Initialize(); MSG message; while (GetMessage(&message, nullptr, 0, 0)) { TranslateMessage(&message); DispatchMessage(&message); } return 0; }