mirror of
https://github.com/reactos/reactos.git
synced 2025-05-25 20:18:22 +00:00
[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 <cicero/cicbase.h>, <cicero/CModulePath.h>, and <cicero/osinfo.h> headers and use them. CORE-19362
This commit is contained in:
parent
a19ba4760e
commit
079b36542c
14 changed files with 1156 additions and 0 deletions
|
@ -6,6 +6,7 @@ add_subdirectory(charmap)
|
||||||
add_subdirectory(clipbrd)
|
add_subdirectory(clipbrd)
|
||||||
add_subdirectory(cmdutils)
|
add_subdirectory(cmdutils)
|
||||||
add_subdirectory(control)
|
add_subdirectory(control)
|
||||||
|
add_subdirectory(ctfmon)
|
||||||
add_subdirectory(drwtsn32)
|
add_subdirectory(drwtsn32)
|
||||||
add_subdirectory(dxdiag)
|
add_subdirectory(dxdiag)
|
||||||
add_subdirectory(extrac32)
|
add_subdirectory(extrac32)
|
||||||
|
|
100
base/applications/ctfmon/CLoaderWnd.cpp
Normal file
100
base/applications/ctfmon/CLoaderWnd.cpp
Normal 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 TIP 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
|
||||||
|
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;
|
||||||
|
}
|
26
base/applications/ctfmon/CLoaderWnd.h
Normal file
26
base/applications/ctfmon/CLoaderWnd.h
Normal 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 TIP 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);
|
||||||
|
};
|
14
base/applications/ctfmon/CMakeLists.txt
Normal file
14
base/applications/ctfmon/CMakeLists.txt
Normal 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)
|
||||||
|
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)
|
339
base/applications/ctfmon/CRegWatcher.cpp
Normal file
339
base/applications/ctfmon/CRegWatcher.cpp
Normal file
|
@ -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 <katayama.hirofumi.mz@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
base/applications/ctfmon/CRegWatcher.h
Normal file
45
base/applications/ctfmon/CRegWatcher.h
Normal 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;
|
||||||
|
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);
|
||||||
|
};
|
378
base/applications/ctfmon/ctfmon.cpp
Normal file
378
base/applications/ctfmon/ctfmon.cpp
Normal file
|
@ -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 <katayama.hirofumi.mz@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
19
base/applications/ctfmon/ctfmon.rc
Normal file
19
base/applications/ctfmon/ctfmon.rc
Normal 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"
|
49
base/applications/ctfmon/precomp.h
Normal file
49
base/applications/ctfmon/precomp.h
Normal file
|
@ -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 <katayama.hirofumi.mz@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WIN32_NO_STATUS
|
||||||
|
#include <windows.h>
|
||||||
|
#include <ndk/pstypes.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <strsafe.h>
|
||||||
|
#include <msctf.h>
|
||||||
|
#include <ctfutb.h>
|
||||||
|
#include <ctffunc.h>
|
||||||
|
|
||||||
|
#include <cicero/cicbase.h>
|
||||||
|
#include <cicero/osinfo.h>
|
||||||
|
#include <cicero/CModulePath.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;
|
BIN
base/applications/ctfmon/res/ctfmon.ico
Normal file
BIN
base/applications/ctfmon/res/ctfmon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
4
base/applications/ctfmon/resource.h
Normal file
4
base/applications/ctfmon/resource.h
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* Icons */
|
||||||
|
#define IDI_MAIN 100
|
90
sdk/include/reactos/cicero/CModulePath.h
Normal file
90
sdk/include/reactos/cicero/CModulePath.h
Normal file
|
@ -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 <katayama.hirofumi.mz@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
44
sdk/include/reactos/cicero/cicbase.h
Normal file
44
sdk/include/reactos/cicero/cicbase.h
Normal file
|
@ -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 <katayama.hirofumi.mz@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
47
sdk/include/reactos/cicero/osinfo.h
Normal file
47
sdk/include/reactos/cicero/osinfo.h
Normal file
|
@ -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 <katayama.hirofumi.mz@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in a new issue