Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386/* * 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!SetProcessShutdownParameterstypedef BOOL (WINAPI *FN_SetProcessShutdownParameters)(DWORD, DWORD);FN_SetProcessShutdownParameters g_fnSetProcessShutdownParameters = NULL;
// kernel32!GetSystemWow64DirectoryAtypedef UINT (WINAPI *FN_GetSystemWow64DirectoryA)(LPSTR, UINT);FN_GetSystemWow64DirectoryA g_fnGetSystemWow64DirectoryA = NULL;// kernel32!GetSystemWow64DirectoryWtypedef UINT (WINAPI *FN_GetSystemWow64DirectoryW)(LPWSTR, UINT);FN_GetSystemWow64DirectoryW g_fnGetSystemWow64DirectoryW = NULL;
HINSTANCE g_hInst = NULL; // The application instanceHINSTANCE g_hKernel32 = NULL; // The "kernel32.dll" instanceUINT g_uACP = CP_ACP; // The active codepageBOOL g_fWinLogon = FALSE; // Is it a log-on process?HANDLE g_hCicMutex = NULL; // The Cicero mutexBOOL 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 cicGetOSInfoCLoaderWnd* g_pLoaderWnd = NULL; // Tipbar loader window
static VOIDParseCommandLine( _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 VOIDWriteRegRun(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 HRESULTGetGlobalCompartment( _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 HRESULTSetGlobalCompartmentDWORD( _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 BOOLCheckX64System( _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 BOOLInitApp( _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 (s)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);
// Initialize x64-specific support CheckX64System(lpCmdLine);
return TRUE;}
VOIDUninitApp(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 INTDoMainLoop(VOID){ MSG msg;
if (g_bOnWow64) // Is the current process on WoW64? { // Simply run a message loop while (::GetMessage(&msg, NULL, 0, 0)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } return (INT)msg.wParam; }
// We wait on the CRegWatcher and the WinSta0 desktop-switch events. HANDLE ahEvents[WI_REGEVTS_MAX + 1]; DWORD dwEventCount;
// Get the CRegWatcher handles CopyMemory(ahEvents, CRegWatcher::s_ahWatchEvents, WI_REGEVTS_MAX * sizeof(HANDLE)); dwEventCount = WI_REGEVTS_MAX;
// Open the WinSta0 desktop-switch event and add it HANDLE hSwitchEvent = ::OpenEvent(SYNCHRONIZE, FALSE, TEXT("WinSta0_DesktopSwitch")); if (hSwitchEvent) { ahEvents[WI_DESKTOP_SWITCH] = hSwitchEvent; ++dwEventCount; }
// Run the event loop for (;;) { DWORD dwWait = ::MsgWaitForMultipleObjects(dwEventCount, ahEvents, FALSE, INFINITE, QS_ALLINPUT); if (dwWait == (WAIT_OBJECT_0 + dwEventCount)) // Is input available? { // Pump available messages 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 if (dwWait < (WAIT_OBJECT_0 + WI_REGEVTS_MAX)) // Do the other events { CRegWatcher::OnEvent(dwWait - WAIT_OBJECT_0); } else if (dwWait == WAIT_TIMEOUT) { // Ignore#ifndef NDEBUG OutputDebugStringA("DoMainLoop: WAIT_TIMEOUT\n");#endif } else if (dwWait == WAIT_FAILED) { // Something failed, bail out#ifndef NDEBUG OutputDebugStringA("DoMainLoop: WAIT_FAILED, exiting\n");#endif break; } }
Quit: if (hSwitchEvent) ::CloseHandle(hSwitchEvent);
return (INT)msg.wParam;}
// The main function for Unicode Win32EXTERN_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;}