From 079b36542c87b5f64eb549d1d3836297b61ea6c2 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Wed, 13 Dec 2023 21:37:15 +0900 Subject: [PATCH] [CTFMON][SDK] Add ctfmon.exe (#6149) ctfmon.exe will be a replacement of our kbswitch.exe in the future. That is the front-end of Language Bar. It is needed to support TIPs. - Add ctfmon.exe at base/applications/ctfmon. - Add , , and headers and use them. CORE-19362 --- base/applications/CMakeLists.txt | 1 + base/applications/ctfmon/CLoaderWnd.cpp | 100 ++++++ base/applications/ctfmon/CLoaderWnd.h | 26 ++ base/applications/ctfmon/CMakeLists.txt | 14 + base/applications/ctfmon/CRegWatcher.cpp | 339 ++++++++++++++++++++ base/applications/ctfmon/CRegWatcher.h | 45 +++ base/applications/ctfmon/ctfmon.cpp | 378 +++++++++++++++++++++++ base/applications/ctfmon/ctfmon.rc | 19 ++ base/applications/ctfmon/precomp.h | 49 +++ base/applications/ctfmon/res/ctfmon.ico | Bin 0 -> 22486 bytes base/applications/ctfmon/resource.h | 4 + sdk/include/reactos/cicero/CModulePath.h | 90 ++++++ sdk/include/reactos/cicero/cicbase.h | 44 +++ sdk/include/reactos/cicero/osinfo.h | 47 +++ 14 files changed, 1156 insertions(+) create mode 100644 base/applications/ctfmon/CLoaderWnd.cpp create mode 100644 base/applications/ctfmon/CLoaderWnd.h create mode 100644 base/applications/ctfmon/CMakeLists.txt create mode 100644 base/applications/ctfmon/CRegWatcher.cpp create mode 100644 base/applications/ctfmon/CRegWatcher.h create mode 100644 base/applications/ctfmon/ctfmon.cpp create mode 100644 base/applications/ctfmon/ctfmon.rc create mode 100644 base/applications/ctfmon/precomp.h create mode 100644 base/applications/ctfmon/res/ctfmon.ico create mode 100644 base/applications/ctfmon/resource.h create mode 100644 sdk/include/reactos/cicero/CModulePath.h create mode 100644 sdk/include/reactos/cicero/cicbase.h create mode 100644 sdk/include/reactos/cicero/osinfo.h diff --git a/base/applications/CMakeLists.txt b/base/applications/CMakeLists.txt index 7679233e5f2..dccaaa80438 100644 --- a/base/applications/CMakeLists.txt +++ b/base/applications/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(charmap) add_subdirectory(clipbrd) add_subdirectory(cmdutils) add_subdirectory(control) +add_subdirectory(ctfmon) add_subdirectory(drwtsn32) add_subdirectory(dxdiag) add_subdirectory(extrac32) diff --git a/base/applications/ctfmon/CLoaderWnd.cpp b/base/applications/ctfmon/CLoaderWnd.cpp new file mode 100644 index 00000000000..400941be008 --- /dev/null +++ b/base/applications/ctfmon/CLoaderWnd.cpp @@ -0,0 +1,100 @@ +/* + * PROJECT: ReactOS CTF Monitor + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Cicero TIP Bar loader window + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +#include "precomp.h" +#include "CLoaderWnd.h" +#include "CRegWatcher.h" + +BOOL CLoaderWnd::s_bUninitedSystem = FALSE; +BOOL CLoaderWnd::s_bWndClassRegistered = FALSE; + +BOOL CLoaderWnd::Init() +{ + if (s_bWndClassRegistered) + return TRUE; // Already registered + + // Register a window class + WNDCLASSEXW wc; + ZeroMemory(&wc, sizeof(wc)); + wc.cbSize = sizeof(wc); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.hInstance = g_hInst; + wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); + wc.lpfnWndProc = WindowProc; + wc.lpszClassName = L"CiCTipBarClass"; + if (!::RegisterClassExW(&wc)) + return FALSE; + + s_bWndClassRegistered = TRUE; // Remember + return TRUE; +} + +HWND CLoaderWnd::CreateWnd() +{ + m_hWnd = ::CreateWindowExW(0, L"CiCTipBarClass", NULL, WS_DISABLED, + 0, 0, 0, 0, NULL, NULL, g_hInst, NULL); + return m_hWnd; +} + +LRESULT CALLBACK +CLoaderWnd::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + break; + + case WM_DESTROY: + ::PostQuitMessage(0); + break; + + case WM_QUERYENDSESSION: + // NOTE: We don't support Win95/98/Me +#ifdef SUPPORT_WIN9X + if (!(g_dwOsInfo & OSINFO_NT) && (!g_fWinLogon || (lParam & ENDSESSION_LOGOFF))) + { + ClosePopupTipbar(); + TF_UninitSystem(); + CLoaderWnd::s_bUninitedSystem = TRUE; + } +#endif + return TRUE; + + case WM_ENDSESSION: + if (wParam) // The session is being ended? + { + if (!s_bUninitedSystem) + { + // Un-initialize now + UninitApp(); + TF_UninitSystem(); + s_bUninitedSystem = TRUE; + } + } + else if (s_bUninitedSystem) // Once un-initialized? + { + // Re-initialize + TF_InitSystem(); + if (!g_bOnWow64) + GetPopupTipbar(hwnd, !!g_fWinLogon); + + s_bUninitedSystem = FALSE; + } + break; + + case WM_SYSCOLORCHANGE: + case WM_DISPLAYCHANGE: + if (!g_bOnWow64) // Is the system x86/x64 native? + CRegWatcher::StartSysColorChangeTimer(); + break; + + default: + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + + return 0; +} diff --git a/base/applications/ctfmon/CLoaderWnd.h b/base/applications/ctfmon/CLoaderWnd.h new file mode 100644 index 00000000000..9127a40155e --- /dev/null +++ b/base/applications/ctfmon/CLoaderWnd.h @@ -0,0 +1,26 @@ +/* + * PROJECT: ReactOS CTF Monitor + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Cicero TIP Bar loader window + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +#pragma once + +class CLoaderWnd +{ +public: + HWND m_hWnd; + static BOOL s_bUninitedSystem; + static BOOL s_bWndClassRegistered; + + CLoaderWnd() : m_hWnd(NULL) { } + ~CLoaderWnd() { } + + BOOL Init(); + HWND CreateWnd(); + +protected: + static LRESULT CALLBACK + WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +}; diff --git a/base/applications/ctfmon/CMakeLists.txt b/base/applications/ctfmon/CMakeLists.txt new file mode 100644 index 00000000000..f88d8f5ad1a --- /dev/null +++ b/base/applications/ctfmon/CMakeLists.txt @@ -0,0 +1,14 @@ + +list(APPEND SOURCE + ctfmon.cpp + CLoaderWnd.cpp + CRegWatcher.cpp) + +add_rc_deps(ctfmon.rc ${CMAKE_CURRENT_SOURCE_DIR}/res/ctfmon.ico) +add_executable(ctfmon ${SOURCE} ctfmon.rc) +set_module_type(ctfmon win32gui UNICODE) +add_dependencies(ctfmon msctf) +target_link_libraries(ctfmon uuid) +add_importlibs(ctfmon msctf advapi32 shell32 user32 msvcrt kernel32) +add_pch(ctfmon precomp.h SOURCE) +add_cd_file(TARGET ctfmon DESTINATION reactos/system32 FOR all) diff --git a/base/applications/ctfmon/CRegWatcher.cpp b/base/applications/ctfmon/CRegWatcher.cpp new file mode 100644 index 00000000000..7782b5c096d --- /dev/null +++ b/base/applications/ctfmon/CRegWatcher.cpp @@ -0,0 +1,339 @@ +/* + * PROJECT: ReactOS CTF Monitor + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Registry watcher + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +#include "precomp.h" +#include "CRegWatcher.h" + +// The event handles to use in watching +HANDLE CRegWatcher::s_ahWatchEvents[WATCHENTRY_MAX] = { NULL }; + +// The registry entries to watch +WATCHENTRY CRegWatcher::s_WatchEntries[WATCHENTRY_MAX] = +{ + { HKEY_CURRENT_USER, L"Keyboard Layout\\Toggle" }, // WI_TOGGLE + { HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\CTF\\TIP" }, // WI_MACHINE_TIF + { HKEY_CURRENT_USER, L"Keyboard Layout\\Preload" }, // WI_PRELOAD + { HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run" }, // WI_RUN + { HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\CTF\\TIP" }, // WI_USER_TIF + { HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Speech" }, // WI_USER_SPEECH + { HKEY_CURRENT_USER, L"Control Panel\\Appearance" }, // WI_APPEARANCE + { HKEY_CURRENT_USER, L"Control Panel\\Colors" }, // WI_COLORS + { HKEY_CURRENT_USER, L"Control Panel\\Desktop\\WindowMetrics" }, // WI_WINDOW_METRICS + { HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Speech" }, // WI_MACHINE_SPEECH + { HKEY_CURRENT_USER, L"Keyboard Layout" }, // WI_KEYBOARD_LAYOUT + { HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\CTF\\Assemblies" }, // WI_ASSEMBLIES +}; + +// The timer IDs: For delaying ignitions +UINT CRegWatcher::s_nSysColorTimerId = 0; +UINT CRegWatcher::s_nKbdToggleTimerId = 0; +UINT CRegWatcher::s_nRegImxTimerId = 0; + +// %WINDIR%/IME/sptip.dll!TF_CreateLangProfileUtil +typedef HRESULT (WINAPI* FN_TF_CreateLangProfileUtil)(ITfFnLangProfileUtil**); + +BOOL +CRegWatcher::Init() +{ + // NOTE: We don't support Win95/98/Me +#ifdef SUPPORT_WIN9X + if (!(g_dwOsInfo & OSINFO_NT)) + s_WatchEntries[WI_RUN].hRootKey = HKEY_LOCAL_MACHINE; +#endif + + // Create some nameless events and initialize them + for (SIZE_T iEvent = 0; iEvent < _countof(s_ahWatchEvents); ++iEvent) + { + s_ahWatchEvents[iEvent] = ::CreateEventW(NULL, TRUE, FALSE, NULL); + InitEvent(iEvent, FALSE); + } + + // Internat.exe is an enemy of ctfmon.exe + KillInternat(); + + UpdateSpTip(); + + return TRUE; +} + +VOID +CRegWatcher::Uninit() +{ + for (SIZE_T iEvent = 0; iEvent < _countof(s_ahWatchEvents); ++iEvent) + { + // Close the key + WATCHENTRY& entry = s_WatchEntries[iEvent]; + if (entry.hKey) + { + ::RegCloseKey(entry.hKey); + entry.hKey = NULL; + } + + // Close the event handle + HANDLE& hEvent = s_ahWatchEvents[iEvent]; + if (hEvent) + { + ::CloseHandle(hEvent); + hEvent = NULL; + } + } +} + +BOOL +CRegWatcher::InitEvent( + _In_ SIZE_T iEvent, + _In_ BOOL bResetEvent) +{ + // Reset the signal status + if (bResetEvent) + ::ResetEvent(s_ahWatchEvents[iEvent]); + + // Close once to re-open + WATCHENTRY& entry = s_WatchEntries[iEvent]; + if (entry.hKey) + { + ::RegCloseKey(entry.hKey); + entry.hKey = NULL; + } + + // Open or create a registry key to watch registry key + LSTATUS error; + error = ::RegOpenKeyExW(entry.hRootKey, entry.pszSubKey, 0, KEY_READ, &entry.hKey); + if (error != ERROR_SUCCESS) + { + error = ::RegCreateKeyExW(entry.hRootKey, entry.pszSubKey, 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &entry.hKey, NULL); + if (error != ERROR_SUCCESS) + return FALSE; + } + + // Start registry watching + error = RegNotifyChangeKeyValue(entry.hKey, + TRUE, + REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME, + s_ahWatchEvents[iEvent], + TRUE); + return error == ERROR_SUCCESS; +} + +VOID +CRegWatcher::UpdateSpTip() +{ + // Post message 0x8002 to "SapiTipWorkerClass" windows + ::EnumWindows(EnumWndProc, 0); + + // Clear "ProfileInitialized" value + HKEY hKey; + LSTATUS error = ::RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\CTF\\Sapilayr", + 0, KEY_WRITE, &hKey); + if (error == ERROR_SUCCESS) + { + DWORD dwValue = 0, cbValue = sizeof(dwValue); + ::RegSetValueExW(hKey, L"ProfileInitialized", NULL, REG_DWORD, (LPBYTE)&dwValue, cbValue); + ::RegCloseKey(hKey); + } + + // Get %WINDIR%/IME/sptip.dll!TF_CreateLangProfileUtil function + HINSTANCE hSPTIP = LoadSystemLibrary(L"IME\\sptip.dll", TRUE); + FN_TF_CreateLangProfileUtil fnTF_CreateLangProfileUtil = + (FN_TF_CreateLangProfileUtil)::GetProcAddress(hSPTIP, "TF_CreateLangProfileUtil"); + if (fnTF_CreateLangProfileUtil) + { + // Call it + ITfFnLangProfileUtil *pProfileUtil = NULL; + HRESULT hr = fnTF_CreateLangProfileUtil(&pProfileUtil); + if ((hr == S_OK) && pProfileUtil) // Success! + { + // Register profile + hr = pProfileUtil->RegisterActiveProfiles(); + if (hr == S_OK) + TF_InvalidAssemblyListCacheIfExist(); // Invalidate the assembly list cache + + pProfileUtil->Release(); + } + } + + if (hSPTIP) + ::FreeLibrary(hSPTIP); +} + +VOID +CRegWatcher::KillInternat() +{ + HKEY hKey; + WATCHENTRY& entry = s_WatchEntries[WI_RUN]; + + // Delete internat.exe from registry "Run" key + LSTATUS error = ::RegOpenKeyExW(entry.hRootKey, entry.pszSubKey, 0, KEY_ALL_ACCESS, &hKey); + if (error == ERROR_SUCCESS) + { + ::RegDeleteValueW(hKey, L"internat.exe"); + ::RegCloseKey(hKey); + } + + // Kill the "Indicator" window (that internat.exe creates) + HWND hwndInternat = ::FindWindowW(L"Indicator", NULL); + if (hwndInternat) + ::PostMessageW(hwndInternat, WM_CLOSE, 0, 0); +} + +// Post message 0x8002 to every "SapiTipWorkerClass" window. +// Called from CRegWatcher::UpdateSpTip +BOOL CALLBACK +CRegWatcher::EnumWndProc( + _In_ HWND hWnd, + _In_ LPARAM lParam) +{ + WCHAR ClassName[MAX_PATH]; + + UNREFERENCED_PARAMETER(lParam); + + if (::GetClassNameW(hWnd, ClassName, _countof(ClassName)) && + _wcsicmp(ClassName, L"SapiTipWorkerClass") == 0) + { + PostMessageW(hWnd, 0x8002, 0, 0); // FIXME: Magic number + } + + return TRUE; +} + +VOID CALLBACK +CRegWatcher::SysColorTimerProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ UINT_PTR idEvent, + _In_ DWORD dwTime) +{ + UNREFERENCED_PARAMETER(hwnd); + UNREFERENCED_PARAMETER(uMsg); + UNREFERENCED_PARAMETER(idEvent); + UNREFERENCED_PARAMETER(dwTime); + + // Cancel the timer + if (s_nSysColorTimerId) + { + ::KillTimer(NULL, s_nSysColorTimerId); + s_nSysColorTimerId = 0; + } + + TF_PostAllThreadMsg(15, 16); +} + +VOID +CRegWatcher::StartSysColorChangeTimer() +{ + // Call SysColorTimerProc 0.5 seconds later (Delayed) + if (s_nSysColorTimerId) + { + ::KillTimer(NULL, s_nSysColorTimerId); + s_nSysColorTimerId = 0; + } + s_nSysColorTimerId = ::SetTimer(NULL, 0, 500, SysColorTimerProc); +} + +VOID CALLBACK +CRegWatcher::RegImxTimerProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ UINT_PTR idEvent, + _In_ DWORD dwTime) +{ + UNREFERENCED_PARAMETER(hwnd); + UNREFERENCED_PARAMETER(uMsg); + UNREFERENCED_PARAMETER(idEvent); + UNREFERENCED_PARAMETER(dwTime); + + // Cancel the timer + if (s_nRegImxTimerId) + { + ::KillTimer(NULL, s_nRegImxTimerId); + s_nRegImxTimerId = 0; + } + + TF_InvalidAssemblyListCache(); + TF_PostAllThreadMsg(12, 16); +} + +VOID CALLBACK +CRegWatcher::KbdToggleTimerProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ UINT_PTR idEvent, + _In_ DWORD dwTime) +{ + UNREFERENCED_PARAMETER(hwnd); + UNREFERENCED_PARAMETER(uMsg); + UNREFERENCED_PARAMETER(idEvent); + UNREFERENCED_PARAMETER(dwTime); + + // Cancel the timer + if (s_nKbdToggleTimerId) + { + ::KillTimer(NULL, s_nKbdToggleTimerId); + s_nKbdToggleTimerId = 0; + } + + TF_PostAllThreadMsg(11, 16); +} + +VOID +CRegWatcher::OnEvent( + _In_ SIZE_T iEvent) +{ + InitEvent(iEvent, TRUE); + + switch (iEvent) + { + case WI_TOGGLE: + { + // Call KbdToggleTimerProc 0.5 seconds later (Delayed) + if (s_nKbdToggleTimerId) + { + ::KillTimer(NULL, s_nKbdToggleTimerId); + s_nKbdToggleTimerId = 0; + } + s_nKbdToggleTimerId = ::SetTimer(NULL, 0, 500, KbdToggleTimerProc); + break; + } + case WI_MACHINE_TIF: + case WI_PRELOAD: + case WI_USER_TIF: + case WI_MACHINE_SPEECH: + case WI_KEYBOARD_LAYOUT: + case WI_ASSEMBLIES: + { + if (iEvent == WI_MACHINE_SPEECH) + UpdateSpTip(); + + // Call RegImxTimerProc 0.2 seconds later (Delayed) + if (s_nRegImxTimerId) + { + ::KillTimer(NULL, s_nRegImxTimerId); + s_nRegImxTimerId = 0; + } + s_nRegImxTimerId = ::SetTimer(NULL, 0, 200, RegImxTimerProc); + break; + } + case WI_RUN: // The "Run" key is changed + { + KillInternat(); // Deny internat.exe the right to live + break; + } + case WI_USER_SPEECH: + case WI_APPEARANCE: + case WI_COLORS: + case WI_WINDOW_METRICS: + { + StartSysColorChangeTimer(); + break; + } + default: + { + break; + } + } +} diff --git a/base/applications/ctfmon/CRegWatcher.h b/base/applications/ctfmon/CRegWatcher.h new file mode 100644 index 00000000000..1f75cb7fb4b --- /dev/null +++ b/base/applications/ctfmon/CRegWatcher.h @@ -0,0 +1,45 @@ +/* + * PROJECT: ReactOS CTF Monitor + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Registry watcher + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +#pragma once + +struct WATCHENTRY +{ + HKEY hRootKey; + LPCWSTR pszSubKey; + HKEY hKey; +}; + +#define WATCHENTRY_MAX 12 + +struct CRegWatcher +{ + static HANDLE s_ahWatchEvents[WATCHENTRY_MAX]; + static WATCHENTRY s_WatchEntries[WATCHENTRY_MAX]; + static UINT s_nSysColorTimerId, s_nKbdToggleTimerId, s_nRegImxTimerId; + + static BOOL Init(); + static VOID Uninit(); + static BOOL InitEvent(_In_ SIZE_T iEvent, _In_ BOOL bResetEvent); + static VOID UpdateSpTip(); + static VOID KillInternat(); + static VOID StartSysColorChangeTimer(); + static VOID OnEvent(_In_ SIZE_T iEvent); + +protected: + static BOOL CALLBACK + EnumWndProc(_In_ HWND hWnd, _In_ LPARAM lParam); + + static VOID CALLBACK + SysColorTimerProc(_In_ HWND hWnd, _In_ UINT uMsg, _In_ UINT_PTR idEvent, _In_ DWORD dwTime); + + static VOID CALLBACK + KbdToggleTimerProc(_In_ HWND hWnd, _In_ UINT uMsg, _In_ UINT_PTR idEvent, _In_ DWORD dwTime); + + static VOID CALLBACK + RegImxTimerProc(_In_ HWND hWnd, _In_ UINT uMsg, _In_ UINT_PTR idEvent, _In_ DWORD dwTime); +}; diff --git a/base/applications/ctfmon/ctfmon.cpp b/base/applications/ctfmon/ctfmon.cpp new file mode 100644 index 00000000000..ebeae0fd933 --- /dev/null +++ b/base/applications/ctfmon/ctfmon.cpp @@ -0,0 +1,378 @@ +/* + * PROJECT: ReactOS CTF Monitor + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Providing Language Bar front-end + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +#include "precomp.h" +#include "CRegWatcher.h" +#include "CLoaderWnd.h" + +// ntdll!NtQueryInformationProcess +typedef NTSTATUS (WINAPI *FN_NtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); +FN_NtQueryInformationProcess g_fnNtQueryInformationProcess = NULL; + +// kernel32!SetProcessShutdownParameters +typedef BOOL (WINAPI *FN_SetProcessShutdownParameters)(DWORD, DWORD); +FN_SetProcessShutdownParameters g_fnSetProcessShutdownParameters = NULL; + +// kernel32!GetSystemWow64DirectoryW +typedef UINT (WINAPI *FN_GetSystemWow64DirectoryW)(LPWSTR, UINT); +FN_GetSystemWow64DirectoryW g_fnGetSystemWow64DirectoryW = NULL; + +HINSTANCE g_hInst = NULL; // The application instance +HINSTANCE g_hKernel32 = NULL; // The "kernel32.dll" instance +UINT g_uACP = CP_ACP; // The active codepage +BOOL g_fWinLogon = FALSE; // Is it a log-on process? +HANDLE g_hCicMutex = NULL; // The Cicero mutex +BOOL g_bOnWow64 = FALSE; // Is the app running on WoW64? +BOOL g_fNoRunKey = FALSE; // Don't write registry key "Run"? +BOOL g_fJustRunKey = FALSE; // Just write registry key "Run"? +DWORD g_dwOsInfo = 0; // The OS version info. See GetOSInfo +CLoaderWnd* g_pLoaderWnd = NULL; // TIP Bar loader window + +// Is the current process on WoW64? +static BOOL +IsWow64(VOID) +{ + HMODULE hNTDLL = GetSystemModuleHandle(L"ntdll.dll", FALSE); + if (!hNTDLL) + return FALSE; + + g_fnNtQueryInformationProcess = + (FN_NtQueryInformationProcess)::GetProcAddress(hNTDLL, "NtQueryInformationProcess"); + if (!g_fnNtQueryInformationProcess) + return FALSE; + + ULONG_PTR Value = 0; + NTSTATUS Status = g_fnNtQueryInformationProcess(::GetCurrentProcess(), ProcessWow64Information, + &Value, sizeof(Value), NULL); + if (!NT_SUCCESS(Status)) + return FALSE; + + return !!Value; +} + +static VOID +ParseCommandLine( + _In_ LPCWSTR pszCmdLine) +{ + g_fNoRunKey = g_fJustRunKey = FALSE; + + for (LPCWSTR pch = pszCmdLine; *pch; ++pch) + { + // Skip space + while (*pch == L' ') + ++pch; + + if (*pch == UNICODE_NULL) + return; + + if ((*pch == L'-') || (*pch == L'/')) + { + ++pch; + switch (*pch) + { + case L'N': case L'n': // Found "/N" option + g_fNoRunKey = TRUE; + break; + + case L'R': case L'r': // Found "/R" option + g_fJustRunKey = TRUE; + break; + + case UNICODE_NULL: + return; + + default: + break; + } + } + } +} + +static VOID +WriteRegRun(VOID) +{ + if (g_fNoRunKey) // If "/N" option is specified + return; // Don't write + + // Open "Run" key + HKEY hKey; + LSTATUS error = ::RegCreateKeyW(HKEY_CURRENT_USER, + L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", + &hKey); + if (error != ERROR_SUCCESS) + return; + + // Write the module path + CModulePath ModPath; + if (ModPath.Init(L"ctfmon.exe", FALSE)) + { + DWORD cbData = (ModPath.m_cchPath + 1) * sizeof(WCHAR); + ::RegSetValueExW(hKey, L"ctfmon.exe", 0, REG_SZ, (BYTE*)ModPath.m_szPath, cbData); + } + + ::RegCloseKey(hKey); +} + +static HRESULT +GetGlobalCompartment( + _In_ REFGUID guid, + _Inout_ ITfCompartment **ppComp) +{ + *ppComp = NULL; + + ITfCompartmentMgr *pCompMgr = NULL; + HRESULT hr = TF_GetGlobalCompartment(&pCompMgr); + if (FAILED(hr)) + return hr; + + if (!pCompMgr) + return E_FAIL; + + hr = pCompMgr->GetCompartment(guid, ppComp); + pCompMgr->Release(); + return hr; +} + +static HRESULT +SetGlobalCompartmentDWORD( + _In_ REFGUID guid, + _In_ DWORD dwValue) +{ + HRESULT hr; + VARIANT vari; + ITfCompartment *pComp; + + hr = GetGlobalCompartment(guid, &pComp); + if (FAILED(hr)) + return hr; + + V_VT(&vari) = VT_I4; + V_I4(&vari) = dwValue; + hr = pComp->SetValue(0, &vari); + + pComp->Release(); + return hr; +} + +static BOOL +CheckX64System( + _In_ LPWSTR lpCmdLine) +{ + // Is the system x64? + SYSTEM_INFO SystemInfo; + ::GetSystemInfo(&SystemInfo); + if (SystemInfo.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_IA64 || + SystemInfo.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64) + { + return FALSE; + } + + // Get GetSystemWow64DirectoryW function + g_hKernel32 = GetSystemModuleHandle(L"kernel32.dll", FALSE); + g_fnGetSystemWow64DirectoryW = + (FN_GetSystemWow64DirectoryW)::GetProcAddress(g_hKernel32, "GetSystemWow64DirectoryW"); + if (!g_fnGetSystemWow64DirectoryW) + return FALSE; + + // Build WoW64 ctfmon.exe pathname + WCHAR szPath[MAX_PATH]; + UINT cchPath = g_fnGetSystemWow64DirectoryW(szPath, _countof(szPath)); + if (!cchPath && FAILED(StringCchCatW(szPath, _countof(szPath), L"\\ctfmon.exe"))) + return FALSE; + + // Create a WoW64 ctfmon.exe process + PROCESS_INFORMATION pi; + STARTUPINFOW si = { sizeof(si) }; + si.wShowWindow = SW_SHOWMINNOACTIVE; + if (!::CreateProcessW(szPath, lpCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + return FALSE; + + ::CloseHandle(pi.hThread); + ::CloseHandle(pi.hProcess); + return TRUE; +} + +static BOOL +InitApp( + _In_ HINSTANCE hInstance, + _In_ LPWSTR lpCmdLine) +{ + g_hInst = hInstance; // Save the instance handle + + g_uACP = ::GetACP(); // Save the active codepage + g_bOnWow64 = IsWow64(); // Is the current process on WoW64? + g_dwOsInfo = GetOSInfo(); // Get OS info + + // Create a mutex for Cicero + g_hCicMutex = TF_CreateCicLoadMutex(&g_fWinLogon); + if (!g_hCicMutex) + return FALSE; + + // Write to "Run" registry key for starting up + WriteRegRun(); + + // Call SetProcessShutdownParameters if possible + if (g_dwOsInfo & OSINFO_NT) + { + g_hKernel32 = GetSystemModuleHandle(L"kernel32.dll", FALSE); + g_fnSetProcessShutdownParameters = + (FN_SetProcessShutdownParameters) + ::GetProcAddress(g_hKernel32, "SetProcessShutdownParameters"); + if (g_fnSetProcessShutdownParameters) + g_fnSetProcessShutdownParameters(0xF0, SHUTDOWN_NORETRY); + } + + // Start text framework + TF_InitSystem(); + + // Start watching registry if x86/x64 native + if (!g_bOnWow64) + CRegWatcher::Init(); + + // Create TIP Bar loader window + g_pLoaderWnd = new CLoaderWnd(); + if (!g_pLoaderWnd || !g_pLoaderWnd->Init()) + return FALSE; + + if (g_pLoaderWnd->CreateWnd()) + { + // Go to the bottom of the hell + ::SetWindowPos(g_pLoaderWnd->m_hWnd, HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + } + + // Display TIP Bar Popup if x86/x64 native + if (!g_bOnWow64) + GetPopupTipbar(g_pLoaderWnd->m_hWnd, g_fWinLogon); + + // Do x64 stuffs + CheckX64System(lpCmdLine); + + return TRUE; +} + +VOID +UninitApp(VOID) +{ + // Close TIP Bar Popup + ClosePopupTipbar(); + + // Close the mutex + ::CloseHandle(g_hCicMutex); + g_hCicMutex = NULL; + + // Quit watching registry if x86/x64 native + if (!g_bOnWow64) + CRegWatcher::Uninit(); +} + +static INT +DoMainLoop(VOID) +{ + MSG msg; + + if (g_bOnWow64) // Is the current process on WoW64? + { + // Just a simple message loop + while (::GetMessageW(&msg, NULL, 0, 0)) + { + ::TranslateMessage(&msg); + ::DispatchMessageW(&msg); + } + return (INT)msg.wParam; + } + + // Open the existing event by the name + HANDLE hSwitchEvent = ::OpenEventW(SYNCHRONIZE, FALSE, L"WinSta0_DesktopSwitch"); + + // The target events to watch + HANDLE ahEvents[WATCHENTRY_MAX + 1]; + + // Borrow some handles from CRegWatcher + CopyMemory(ahEvents, CRegWatcher::s_ahWatchEvents, WATCHENTRY_MAX * sizeof(HANDLE)); + + ahEvents[WI_DESKTOP_SWITCH] = hSwitchEvent; // Add it + + // Another message loop + for (;;) + { + // Wait for target signal + DWORD dwWait = ::MsgWaitForMultipleObjects(_countof(ahEvents), ahEvents, 0, INFINITE, + QS_ALLINPUT); + if (dwWait == (WAIT_OBJECT_0 + _countof(ahEvents))) // Is input available? + { + // Do the events + while (::PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + goto Quit; + + ::TranslateMessage(&msg); + ::DispatchMessageW(&msg); + } + } + else if (dwWait == (WAIT_OBJECT_0 + WI_DESKTOP_SWITCH)) // Desktop switch? + { + SetGlobalCompartmentDWORD(GUID_COMPARTMENT_SPEECH_OPENCLOSE, 0); + ::ResetEvent(hSwitchEvent); + } + else // Do the other events + { + CRegWatcher::OnEvent(dwWait - WAIT_OBJECT_0); + } + } + +Quit: + ::CloseHandle(hSwitchEvent); + + return (INT)msg.wParam; +} + +// The main function for Unicode Win32 +EXTERN_C INT WINAPI +wWinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInst, + LPWSTR lpCmdLine, + INT nCmdShow) +{ + UNREFERENCED_PARAMETER(hPrevInst); + UNREFERENCED_PARAMETER(nCmdShow); + + // Parse command line + ParseCommandLine(lpCmdLine); + + if (g_fJustRunKey) // If "/R" option is specified + { + // Just write registry and exit + WriteRegRun(); + return 1; + } + + // Initialize the application + if (!InitApp(hInstance, lpCmdLine)) + return 0; + + // The main loop + INT ret = DoMainLoop(); + + // Clean up the loader + if (g_pLoaderWnd) + { + delete g_pLoaderWnd; + g_pLoaderWnd = NULL; + } + + // Un-initialize app and text framework + if (!CLoaderWnd::s_bUninitedSystem) + { + UninitApp(); + TF_UninitSystem(); + } + + return ret; +} diff --git a/base/applications/ctfmon/ctfmon.rc b/base/applications/ctfmon/ctfmon.rc new file mode 100644 index 00000000000..fe628048326 --- /dev/null +++ b/base/applications/ctfmon/ctfmon.rc @@ -0,0 +1,19 @@ +/* + * PROJECT: ReactOS CTF Monitor + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Providing Language Bar front-end + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +#include + +#include "resource.h" + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS CTF Monitor" +#define REACTOS_STR_INTERNAL_NAME "ctfmon" +#define REACTOS_STR_ORIGINAL_FILENAME "ctfmon.exe" +#include + +IDI_MAIN ICON "res/ctfmon.ico" diff --git a/base/applications/ctfmon/precomp.h b/base/applications/ctfmon/precomp.h new file mode 100644 index 00000000000..636739eb9e1 --- /dev/null +++ b/base/applications/ctfmon/precomp.h @@ -0,0 +1,49 @@ +/* + * PROJECT: ReactOS CTF Monitor + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Providing Language Bar front-end + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +#pragma once + +#define WIN32_NO_STATUS +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "resource.h" + +extern HINSTANCE g_hInst; +extern BOOL g_bOnWow64; +extern BOOL g_fWinLogon; +extern DWORD g_dwOsInfo; + +VOID UninitApp(VOID); + +typedef enum WATCH_INDEX +{ + WI_TOGGLE = 0, + WI_MACHINE_TIF = 1, + WI_PRELOAD = 2, + WI_RUN = 3, + WI_USER_TIF = 4, + WI_USER_SPEECH = 5, + WI_APPEARANCE = 6, + WI_COLORS = 7, + WI_WINDOW_METRICS = 8, + WI_MACHINE_SPEECH = 9, + WI_KEYBOARD_LAYOUT = 10, + WI_ASSEMBLIES = 11, + WI_DESKTOP_SWITCH = 12, +} WATCH_INDEX; diff --git a/base/applications/ctfmon/res/ctfmon.ico b/base/applications/ctfmon/res/ctfmon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5d7c7626fbf9599c6b08b7eabdc74c193d5e6c98 GIT binary patch literal 22486 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 literal 0 HcmV?d00001 diff --git a/base/applications/ctfmon/resource.h b/base/applications/ctfmon/resource.h new file mode 100644 index 00000000000..79f0b3152af --- /dev/null +++ b/base/applications/ctfmon/resource.h @@ -0,0 +1,4 @@ +#pragma once + +/* Icons */ +#define IDI_MAIN 100 diff --git a/sdk/include/reactos/cicero/CModulePath.h b/sdk/include/reactos/cicero/CModulePath.h new file mode 100644 index 00000000000..2418b157cdd --- /dev/null +++ b/sdk/include/reactos/cicero/CModulePath.h @@ -0,0 +1,90 @@ +/* + * PROJECT: ReactOS Cicero + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Manipulate module path + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +#pragma once + +struct CModulePath +{ + WCHAR m_szPath[MAX_PATH]; + SIZE_T m_cchPath; + + CModulePath() + { + m_szPath[0] = UNICODE_NULL; + m_cchPath = 0; + } + + BOOL Init(_In_ LPCWSTR pszFileName, _In_ BOOL bSysWinDir); +}; + +// Get an instance handle that is already loaded +static inline HINSTANCE +GetSystemModuleHandle( + _In_ LPCWSTR pszFileName, + _In_ BOOL bSysWinDir) +{ + CModulePath ModPath; + if (!ModPath.Init(pszFileName, bSysWinDir)) + return NULL; + return GetModuleHandleW(ModPath.m_szPath); +} + +// Load a system library +static inline HINSTANCE +LoadSystemLibrary( + _In_ LPCWSTR pszFileName, + _In_ BOOL bSysWinDir) +{ + CModulePath ModPath; + if (!ModPath.Init(pszFileName, bSysWinDir)) + return NULL; + return ::LoadLibraryW(ModPath.m_szPath); +} + +/******************************************************************************/ + +inline BOOL +CModulePath::Init( + _In_ LPCWSTR pszFileName, + _In_ BOOL bSysWinDir) +{ + SIZE_T cchPath; + if (bSysWinDir) + { + // Usually C:\Windows or C:\ReactOS + cchPath = ::GetSystemWindowsDirectory(m_szPath, _countof(m_szPath)); + } + else + { + // Usually C:\Windows\system32 or C:\ReactOS\system32 + cchPath = ::GetSystemDirectoryW(m_szPath, _countof(m_szPath)); + } + + m_szPath[_countof(m_szPath) - 1] = UNICODE_NULL; // Avoid buffer overrun + + if ((cchPath == 0) || (cchPath > _countof(m_szPath) - 2)) + goto Failure; + + // Add backslash if necessary + if ((cchPath > 0) && (m_szPath[cchPath - 1] != L'\\')) + { + m_szPath[cchPath + 0] = L'\\'; + m_szPath[cchPath + 1] = UNICODE_NULL; + } + + // Append pszFileName + if (FAILED(StringCchCatW(m_szPath, _countof(m_szPath), pszFileName))) + goto Failure; + + m_cchPath = wcslen(m_szPath); + return TRUE; + +Failure: + m_szPath[0] = UNICODE_NULL; + m_cchPath = 0; + return FALSE; +} diff --git a/sdk/include/reactos/cicero/cicbase.h b/sdk/include/reactos/cicero/cicbase.h new file mode 100644 index 00000000000..9048dcb865a --- /dev/null +++ b/sdk/include/reactos/cicero/cicbase.h @@ -0,0 +1,44 @@ +/* + * PROJECT: ReactOS Cicero + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Cicero base + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +static inline LPVOID cicMemAllocClear(SIZE_T size) +{ + return LocalAlloc(LMEM_ZEROINIT, size); +} + +static inline void cicMemFree(LPVOID ptr) +{ + if (ptr) + LocalFree(ptr); +} + +#ifdef __cplusplus +inline void* __cdecl operator new(size_t size) noexcept +{ + return cicMemAllocClear(size); +} + +inline void __cdecl operator delete(void* ptr) noexcept +{ + cicMemFree(ptr); +} + +inline void __cdecl operator delete(void* ptr, size_t size) noexcept +{ + cicMemFree(ptr); +} +#endif // __cplusplus + +// FIXME: Use msutb.dll and header +static inline void ClosePopupTipbar(void) +{ +} + +// FIXME: Use msutb.dll and header +static inline void GetPopupTipbar(HWND hwnd, BOOL fWinLogon) +{ +} diff --git a/sdk/include/reactos/cicero/osinfo.h b/sdk/include/reactos/cicero/osinfo.h new file mode 100644 index 00000000000..b260000dfbc --- /dev/null +++ b/sdk/include/reactos/cicero/osinfo.h @@ -0,0 +1,47 @@ +/* + * PROJECT: ReactOS Cicero + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Getting OS information + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +#pragma once + +/* The flags of GetOSInfo() */ +#define OSINFO_NT 0x01 +#define OSINFO_CJK 0x10 +#define OSINFO_IMM 0x20 +#define OSINFO_DBCS 0x40 + +static inline DWORD +GetOSInfo(VOID) +{ + DWORD dwOsInfo = 0; + + /* Check OS version info */ + OSVERSIONINFOW VerInfo = { sizeof(VerInfo) }; + GetVersionExW(&VerInfo); + if (VerInfo.dwPlatformId == DLLVER_PLATFORM_NT) + dwOsInfo |= OSINFO_NT; + + /* Check codepage */ + switch (GetACP()) + { + case 932: /* Japanese (Japan) */ + case 936: /* Chinese (PRC, Singapore) */ + case 949: /* Korean (Korea) */ + case 950: /* Chinese (Taiwan, Hong Kong) */ + dwOsInfo |= OSINFO_CJK; + break; + } + + if (GetSystemMetrics(SM_IMMENABLED)) + dwOsInfo |= OSINFO_IMM; + + if (GetSystemMetrics(SM_DBCSENABLED)) + dwOsInfo |= OSINFO_DBCS; + + /* I'm not interested in other flags */ + + return dwOsInfo; +}