Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377/* * 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 <katayama.hirofumi.mz@gmail.com> */
#include "precomp.h"#include "CRegWatcher.h"#include <ime/indicml.h>
// The event handles to use in watchingHANDLE CRegWatcher::s_ahWatchEvents[WI_REGEVTS_MAX] = { NULL };
// The registry entries to watchWATCHENTRY CRegWatcher::s_WatchEntries[WI_REGEVTS_MAX] ={ { HKEY_CURRENT_USER, TEXT("Keyboard Layout\\Toggle") }, // WI_TOGGLE { HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\CTF\\TIP") }, // WI_MACHINE_TIF { HKEY_CURRENT_USER, TEXT("Keyboard Layout\\Preload") }, // WI_PRELOAD { HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run") }, // WI_RUN { HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\TIP") }, // WI_USER_TIF { HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Speech") }, // WI_USER_SPEECH { HKEY_CURRENT_USER, TEXT("Control Panel\\Appearance") }, // WI_APPEARANCE { HKEY_CURRENT_USER, TEXT("Control Panel\\Colors") }, // WI_COLORS { HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop\\WindowMetrics") }, // WI_WINDOW_METRICS { HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Speech") }, // WI_MACHINE_SPEECH { HKEY_CURRENT_USER, TEXT("Keyboard Layout") }, // WI_KEYBOARD_LAYOUT { HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\Assemblies") }, // WI_ASSEMBLIES};
// The timer IDs: For delaying ignitionsUINT CRegWatcher::s_nSysColorTimerId = 0;UINT CRegWatcher::s_nKbdToggleTimerId = 0;UINT CRegWatcher::s_nRegImxTimerId = 0;
// %WINDIR%/IME/sptip.dll!TF_CreateLangProfileUtiltypedef HRESULT (WINAPI* FN_TF_CreateLangProfileUtil)(ITfFnLangProfileUtil**);
BOOLCRegWatcher::Init(){ // NOTE: We don't support Win95/98/Me#ifdef SUPPORT_WIN9X if (!(g_dwOsInfo & CIC_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] = ::CreateEvent(NULL, TRUE, FALSE, NULL); InitEvent(iEvent, FALSE); }
// Internat.exe is an enemy of ctfmon.exe KillInternat();
UpdateSpTip();
return TRUE;}
VOIDCRegWatcher::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; } }}
// advapi32!RegNotifyChangeKeyValuetypedef LONG (WINAPI *FN_RegNotifyChangeKeyValue)(HKEY, BOOL, DWORD, HANDLE, BOOL);
LONG WINAPIDelayedRegNotifyChangeKeyValue( HKEY hKey, BOOL bWatchSubtree, DWORD dwNotifyFilter, HANDLE hEvent, BOOL fAsynchronous){ static FN_RegNotifyChangeKeyValue s_fnRegNotifyChangeKeyValue = NULL;
if (!s_fnRegNotifyChangeKeyValue) { HINSTANCE hAdvApi32 = cicGetSystemModuleHandle(TEXT("advapi32.dll"), FALSE); s_fnRegNotifyChangeKeyValue = (FN_RegNotifyChangeKeyValue)GetProcAddress(hAdvApi32, "RegNotifyChangeKeyValue"); if (!s_fnRegNotifyChangeKeyValue) return ERROR_CALL_NOT_IMPLEMENTED; }
return s_fnRegNotifyChangeKeyValue(hKey, bWatchSubtree, dwNotifyFilter, hEvent, fAsynchronous);}
BOOLCRegWatcher::InitEvent( _In_ SIZE_T iEvent, _In_ BOOL bResetEvent){ if (iEvent >= _countof(s_ahWatchEvents)) return FALSE;
// 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 = ::RegOpenKeyEx(entry.hRootKey, entry.pszSubKey, 0, KEY_READ, &entry.hKey); if (error != ERROR_SUCCESS) { error = ::RegCreateKeyEx(entry.hRootKey, entry.pszSubKey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &entry.hKey, NULL); if (error != ERROR_SUCCESS) return FALSE; }
// Start registry watching error = DelayedRegNotifyChangeKeyValue(entry.hKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME, s_ahWatchEvents[iEvent], TRUE);#ifndef NDEBUG if (error != ERROR_SUCCESS) OutputDebugStringA("RegNotifyChangeKeyValue failed\n");#endif return error == ERROR_SUCCESS;}
VOIDCRegWatcher::UpdateSpTip(){ // Post message 0x8002 to "SapiTipWorkerClass" windows ::EnumWindows(EnumWndProc, 0);
// Clear "ProfileInitialized" value HKEY hKey; LSTATUS error = ::RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\Sapilayr"), 0, KEY_WRITE, &hKey); if (error == ERROR_SUCCESS) { DWORD dwValue = 0, cbValue = sizeof(dwValue); ::RegSetValueEx(hKey, TEXT("ProfileInitialized"), NULL, REG_DWORD, (LPBYTE)&dwValue, cbValue); ::RegCloseKey(hKey); }
// Get %WINDIR%/IME/sptip.dll!TF_CreateLangProfileUtil function HINSTANCE hSPTIP = cicLoadSystemLibrary(TEXT("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);}
VOIDCRegWatcher::KillInternat(){ HKEY hKey; WATCHENTRY& entry = s_WatchEntries[WI_RUN];
// Delete internat.exe from registry "Run" key LSTATUS error = ::RegOpenKeyEx(entry.hRootKey, entry.pszSubKey, 0, KEY_ALL_ACCESS, &hKey); if (error == ERROR_SUCCESS) { ::RegDeleteValue(hKey, TEXT("internat.exe")); ::RegCloseKey(hKey); }
// Kill the "Indicator" window (that internat.exe creates) HWND hwndInternat = ::FindWindow(INDICATOR_CLASS, NULL); if (hwndInternat) ::PostMessage(hwndInternat, WM_CLOSE, 0, 0);}
// Post message 0x8002 to every "SapiTipWorkerClass" window.// Called from CRegWatcher::UpdateSpTipBOOL CALLBACKCRegWatcher::EnumWndProc( _In_ HWND hWnd, _In_ LPARAM lParam){ TCHAR ClassName[MAX_PATH];
UNREFERENCED_PARAMETER(lParam);
if (::GetClassName(hWnd, ClassName, _countof(ClassName)) && _tcsicmp(ClassName, TEXT("SapiTipWorkerClass")) == 0) { PostMessage(hWnd, 0x8002, 0, 0); // FIXME: Magic number }
return TRUE;}
VOID CALLBACKCRegWatcher::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);}
VOIDCRegWatcher::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 CALLBACKCRegWatcher::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 CALLBACKCRegWatcher::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);}
VOIDCRegWatcher::OnEvent( _In_ SIZE_T iEvent){ if (iEvent >= _countof(s_ahWatchEvents)) return;
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; } }}