[CTFMON][MSCTF][MSCTFIME][MSUTB] Move CTF modules to base/ctf (#8040)

This PR reorganizes the location of
the CTF-related modules to improve
grep-ability, understanding, and
readability. New folder base/ctf will
become incomplete Cicero, CTF or
TSF (Text Services Framework).
JIRA issue: CORE-19360
JIRA issue: CORE-19361
JIRA issue: CORE-19363
- Move ctfmon, msctf, msctfime,
  and msutb modules to new
  directory base/ctf.
- Adapt CMakeLists.txt to this move.
- Modify .github/labeler.yml and
  media/doc/WINESYNC.txt.
- No code content changes except
  CMakeLists.txt, .github/labeler.yml,
  and media/doc/WINESYNC.txt.
This commit is contained in:
Katayama Hirofumi MZ 2025-05-28 05:04:03 +09:00 committed by GitHub
parent 2a0d98c2bc
commit d4c64771cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
77 changed files with 9 additions and 11 deletions

View file

@ -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 Tipbar (Language Bar) loader window
* COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#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
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hInstance = g_hInst;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpfnWndProc = WindowProc;
wc.lpszClassName = TEXT("CiCTipBarClass");
if (!::RegisterClassEx(&wc))
return FALSE;
s_bWndClassRegistered = TRUE; // Remember
return TRUE;
}
HWND CLoaderWnd::CreateWnd()
{
m_hWnd = ::CreateWindowEx(0, TEXT("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 & CIC_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 DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}

View file

@ -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 Tipbar (Language Bar) loader window
* COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#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);
};

View file

@ -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 msutb)
target_link_libraries(ctfmon uuid cicero)
add_importlibs(ctfmon msctf msutb advapi32 shell32 user32 msvcrt kernel32)
add_pch(ctfmon precomp.h SOURCE)
add_cd_file(TARGET ctfmon DESTINATION reactos/system32 FOR all)

View file

@ -0,0 +1,370 @@
/*
* 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 watching
HANDLE CRegWatcher::s_ahWatchEvents[WATCHENTRY_MAX] = { NULL };
// The registry entries to watch
WATCHENTRY CRegWatcher::s_WatchEntries[WATCHENTRY_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 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 & 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;
}
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;
}
}
}
// advapi32!RegNotifyChangeKeyValue
typedef LONG (WINAPI *FN_RegNotifyChangeKeyValue)(HKEY, BOOL, DWORD, HANDLE, BOOL);
LONG WINAPI
DelayedRegNotifyChangeKeyValue(
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);
}
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 = ::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;
}
VOID
CRegWatcher::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);
}
VOID
CRegWatcher::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::UpdateSpTip
BOOL CALLBACK
CRegWatcher::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 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;
}
}
}

View file

@ -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 <katayama.hirofumi.mz@gmail.com>
*/
#pragma once
struct WATCHENTRY
{
HKEY hRootKey;
LPCTSTR 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);
};

365
base/ctf/ctfmon/ctfmon.cpp Normal file
View file

@ -0,0 +1,365 @@
/*
* 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 <katayama.hirofumi.mz@gmail.com>
*/
#include "precomp.h"
#include "CRegWatcher.h"
#include "CLoaderWnd.h"
// kernel32!SetProcessShutdownParameters
typedef BOOL (WINAPI *FN_SetProcessShutdownParameters)(DWORD, DWORD);
FN_SetProcessShutdownParameters g_fnSetProcessShutdownParameters = NULL;
// kernel32!GetSystemWow64DirectoryA
typedef UINT (WINAPI *FN_GetSystemWow64DirectoryA)(LPSTR, UINT);
FN_GetSystemWow64DirectoryA g_fnGetSystemWow64DirectoryA = 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 cicGetOSInfo
CLoaderWnd* g_pLoaderWnd = NULL; // Tipbar loader window
static VOID
ParseCommandLine(
_In_ LPCTSTR pszCmdLine)
{
g_fNoRunKey = g_fJustRunKey = FALSE;
for (LPCTSTR pch = pszCmdLine; *pch; ++pch)
{
// Skip space
while (*pch == TEXT(' '))
++pch;
if (*pch == TEXT('\0'))
return;
if ((*pch == TEXT('-')) || (*pch == TEXT('/')))
{
++pch;
switch (*pch)
{
case TEXT('N'): case TEXT('n'): // Found "/N" option
g_fNoRunKey = TRUE;
break;
case TEXT('R'): case TEXT('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 = ::RegCreateKey(HKEY_CURRENT_USER,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run"),
&hKey);
if (error != ERROR_SUCCESS)
return;
// Write the module path
CicSystemModulePath ModPath;
if (ModPath.Init(TEXT("ctfmon.exe"), FALSE))
{
DWORD cbData = (ModPath.m_cchPath + 1) * sizeof(TCHAR);
::RegSetValueEx(hKey, TEXT("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_ LPTSTR 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 = cicGetSystemModuleHandle(TEXT("kernel32.dll"), FALSE);
#ifdef UNICODE
g_fnGetSystemWow64DirectoryW =
(FN_GetSystemWow64DirectoryW)::GetProcAddress(g_hKernel32, "GetSystemWow64DirectoryW");
if (!g_fnGetSystemWow64DirectoryW)
return FALSE;
#else
g_fnGetSystemWow64DirectoryA =
(FN_GetSystemWow64DirectoryA)::GetProcAddress(g_hKernel32, "GetSystemWow64DirectoryA");
if (!g_fnGetSystemWow64DirectoryA)
return FALSE;
#endif
// Build WoW64 ctfmon.exe pathname
TCHAR szPath[MAX_PATH];
#ifdef UNICODE
UINT cchPath = g_fnGetSystemWow64DirectoryW(szPath, _countof(szPath));
#else
UINT cchPath = g_fnGetSystemWow64DirectoryA(szPath, _countof(szPath));
#endif
if (!cchPath && FAILED(StringCchCat(szPath, _countof(szPath), TEXT("\\ctfmon.exe"))))
return FALSE;
// Create a WoW64 ctfmon.exe process
PROCESS_INFORMATION pi;
STARTUPINFO si = { sizeof(si) };
si.wShowWindow = SW_SHOWMINNOACTIVE;
if (!::CreateProcess(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_ LPTSTR lpCmdLine)
{
g_hInst = hInstance; // Save the instance handle
g_bOnWow64 = cicIsWow64(); // Is the current process on WoW64?
cicGetOSInfo(&g_uACP, &g_dwOsInfo); // 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 & CIC_OSINFO_NT)
{
g_hKernel32 = cicGetSystemModuleHandle(TEXT("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 Tipbar loader window
g_pLoaderWnd = new(cicNoThrow) 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 Tipbar Popup if x86/x64 native and necessary
if (!g_bOnWow64)
GetPopupTipbar(g_pLoaderWnd->m_hWnd, g_fWinLogon);
// Do x64 stuffs
CheckX64System(lpCmdLine);
return TRUE;
}
VOID
UninitApp(VOID)
{
// Close Tipbar 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 (::GetMessage(&msg, NULL, 0, 0))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return (INT)msg.wParam;
}
// Open the existing event by the name
HANDLE hSwitchEvent = ::OpenEvent(SYNCHRONIZE, FALSE, TEXT("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 (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
goto Quit;
::TranslateMessage(&msg);
::DispatchMessage(&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
_tWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInst,
LPTSTR 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;
}

19
base/ctf/ctfmon/ctfmon.rc Normal file
View file

@ -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 <katayama.hirofumi.mz@gmail.com>
*/
#include <windef.h>
#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 <reactos/version.rc>
IDI_MAIN ICON "res/ctfmon.ico"

48
base/ctf/ctfmon/precomp.h Normal file
View file

@ -0,0 +1,48 @@
/*
* 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 <katayama.hirofumi.mz@gmail.com>
*/
#pragma once
#define WIN32_NO_STATUS
#include <windows.h>
#include <shellapi.h>
#include <shlwapi.h>
#include <stdlib.h>
#include <tchar.h>
#include <strsafe.h>
#include <msctf.h>
#include <msctf_undoc.h>
#include <ctfutb.h>
#include <ctffunc.h>
#include <cicbase.h>
#include <cicutb.h>
#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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -0,0 +1,4 @@
#pragma once
/* Icons */
#define IDI_MAIN 100