You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
433 lines
11 KiB
433 lines
11 KiB
//
|
|
// cicload.cpp
|
|
//
|
|
|
|
#include "private.h"
|
|
#include "cicload.h"
|
|
#include "loader.h"
|
|
#include "immxutil.h"
|
|
#include "osver.h"
|
|
#include "regwatch.h"
|
|
#include "mem.h"
|
|
#include "msutbapi.h"
|
|
#include "ciccs.h"
|
|
|
|
DECLARE_OSVER();
|
|
|
|
typedef BOOL (WINAPI *PFNSETPROCESSSHUTDOWNPARAMETERS)( DWORD dwLevel, DWORD dwFlags);
|
|
|
|
LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);
|
|
|
|
CLoaderWnd *g_pLoaderWnd;
|
|
|
|
HINSTANCE g_hInst;
|
|
|
|
HANDLE g_hInstanceMutex;
|
|
|
|
BOOL g_fWinLogon = FALSE;
|
|
BOOL g_fRunOnceMode = FALSE;
|
|
BOOL g_bOnWow64 = FALSE;
|
|
BOOL g_fNoRunKey = FALSE;
|
|
|
|
#ifdef DEBUG
|
|
DWORD g_dwThreadDllMain = 0;
|
|
#endif
|
|
|
|
CCicCriticalSectionStatic g_cs;
|
|
|
|
extern "C" HANDLE WINAPI TF_CreateCicLoadMutex(BOOL *pfWinLogon);
|
|
|
|
extern "C" HRESULT WINAPI TF_GetGlobalCompartment(ITfCompartmentMgr **pCompMgr);
|
|
|
|
HRESULT GetGlobalCompartment(REFGUID rguidComp, ITfCompartment **ppComp)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ITfCompartmentMgr *pCompMgr = NULL;
|
|
|
|
*ppComp = NULL;
|
|
|
|
if (FAILED(hr = TF_GetGlobalCompartment(&pCompMgr)))
|
|
{
|
|
Assert(0);
|
|
goto Exit;
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && pCompMgr)
|
|
{
|
|
hr = pCompMgr->GetCompartment(rguidComp, ppComp);
|
|
pCompMgr->Release();
|
|
}
|
|
else
|
|
hr = E_FAIL;
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT SetGlobalCompartmentDWORD(REFGUID rguidComp, DWORD dw)
|
|
{
|
|
HRESULT hr;
|
|
ITfCompartment *pComp;
|
|
VARIANT var;
|
|
|
|
if (SUCCEEDED(hr = GetGlobalCompartment(rguidComp, &pComp)))
|
|
{
|
|
var.vt = VT_I4;
|
|
var.lVal = dw;
|
|
hr = pComp->SetValue(0, &var);
|
|
pComp->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT STDAPICALLTYPE StubCoCreateInstance(REFCLSID rclsid, LPUNKNOWN punkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv)
|
|
{
|
|
// we should never get here! This function is a stub to keep the library happy, so it won't actually
|
|
// load ole32.dll. ctfmon.exe should never be loading ole32.dll!
|
|
Assert(0);
|
|
if (ppv != NULL)
|
|
{
|
|
*ppv = NULL;
|
|
}
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
void AddRunRegkey()
|
|
{
|
|
HKEY hkeyRun;
|
|
const static TCHAR c_szCTFMon[] = TEXT("ctfmon.exe");
|
|
|
|
if (g_fNoRunKey)
|
|
return;
|
|
|
|
if (RegCreateKey( HKEY_CURRENT_USER,
|
|
REGSTR_PATH_RUN,
|
|
&hkeyRun ) == ERROR_SUCCESS)
|
|
{
|
|
CicSystemModulePath pathCTFMon;
|
|
|
|
if (pathCTFMon.Init(c_szCTFMon))
|
|
{
|
|
RegSetValueEx(hkeyRun,
|
|
c_szCTFMon,
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE)pathCTFMon.GetPath(),
|
|
pathCTFMon.GetLength() * sizeof(TCHAR));
|
|
|
|
RegCloseKey(hkeyRun);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL InitApp(HINSTANCE hInstance)
|
|
{
|
|
|
|
g_hInstanceMutex = TF_CreateCicLoadMutex(&g_fWinLogon);
|
|
|
|
if (!g_hInstanceMutex)
|
|
return FALSE;
|
|
|
|
AddRunRegkey();
|
|
|
|
g_hInst = hInstance;
|
|
if (!g_cs.Init())
|
|
return FALSE;
|
|
|
|
TFInitLib_PrivateForCiceroOnly(StubCoCreateInstance);
|
|
InitOSVer();
|
|
|
|
//
|
|
// Specify the shutdown order of the progman process.
|
|
//
|
|
// Progman (level = 2)
|
|
// taskman (level = 1)
|
|
// ntsd or windbg (level = 0)
|
|
//
|
|
// Ctfmon is enough to have 0xf0 after any programs..
|
|
//
|
|
if (IsOnNT())
|
|
{
|
|
static PFNSETPROCESSSHUTDOWNPARAMETERS pfnSetShutdownParam;
|
|
static HINSTANCE hLibKernel32 = NULL;
|
|
hLibKernel32 = GetSystemModuleHandle( TEXT("kernel32.dll") );
|
|
if (hLibKernel32)
|
|
{
|
|
pfnSetShutdownParam = (PFNSETPROCESSSHUTDOWNPARAMETERS)GetProcAddress(hLibKernel32, TEXT("SetProcessShutdownParameters"));
|
|
if (pfnSetShutdownParam)
|
|
pfnSetShutdownParam(0xf0, SHUTDOWN_NORETRY);
|
|
}
|
|
|
|
}
|
|
|
|
// rev up default Cicero support for the system
|
|
TF_InitSystem();
|
|
|
|
if (! g_bOnWow64)
|
|
{
|
|
CRegWatcher::Init();
|
|
}
|
|
|
|
g_pLoaderWnd = new CLoaderWnd();
|
|
if (!g_pLoaderWnd)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!g_pLoaderWnd->Init())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
g_pLoaderWnd->CreateWnd();
|
|
|
|
//
|
|
// locate this window at the bottom of z-order list.
|
|
// so we can delay WM_QUERYENDSESSION under Win9x platform.
|
|
//
|
|
if (g_pLoaderWnd->GetWnd())
|
|
SetWindowPos(g_pLoaderWnd->GetWnd(), HWND_BOTTOM, 0, 0, 0, 0,
|
|
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void UninitApp(void)
|
|
{
|
|
ClosePopupTipbar();
|
|
TFUninitLib();
|
|
CloseHandle(g_hInstanceMutex);
|
|
if (! g_bOnWow64)
|
|
{
|
|
CRegWatcher::Uninit();
|
|
}
|
|
}
|
|
|
|
void CheckCmdLine(PSTR pszCmdLine)
|
|
{
|
|
PSTR psz = pszCmdLine;
|
|
|
|
while (*psz)
|
|
{
|
|
if (*psz == ' ')
|
|
{
|
|
psz++;
|
|
if (!*psz)
|
|
return;
|
|
|
|
if ((*psz == '-') || (*psz == '/'))
|
|
{
|
|
psz++;
|
|
if (!*psz)
|
|
return;
|
|
|
|
|
|
switch (*psz)
|
|
{
|
|
case 'r':
|
|
case 'R':
|
|
g_fRunOnceMode = TRUE;
|
|
break;
|
|
|
|
case 'n':
|
|
case 'N':
|
|
g_fNoRunKey = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
psz++;
|
|
}
|
|
|
|
}
|
|
|
|
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pszCmdLine, int iCmdShow)
|
|
{
|
|
MSG msg;
|
|
DWORD dwWaitObj;
|
|
|
|
CcshellGetDebugFlags();
|
|
Dbg_MemInit(TEXT("CTFMON"), NULL);
|
|
|
|
//
|
|
// Retrive WOW64
|
|
//
|
|
g_bOnWow64 = RunningOnWow64();
|
|
|
|
|
|
CheckCmdLine(pszCmdLine);
|
|
|
|
|
|
if (g_fRunOnceMode)
|
|
{
|
|
AddRunRegkey();
|
|
Dbg_MemUninit();
|
|
return 1;
|
|
}
|
|
|
|
if (!InitApp(hInstance))
|
|
{
|
|
Dbg_MemUninit();
|
|
return 0;
|
|
}
|
|
|
|
if (! g_bOnWow64)
|
|
{
|
|
//
|
|
// Load MSUTB.DLL
|
|
//
|
|
GetPopupTipbar(g_pLoaderWnd->GetWnd(), g_fWinLogon ? UTB_GTI_WINLOGON : 0);
|
|
}
|
|
|
|
//
|
|
// For 64bit only.
|
|
// Launch ctfmon(32).
|
|
//
|
|
{
|
|
SYSTEM_INFO sys;
|
|
GetSystemInfo(&sys);
|
|
if ((sys.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) ||
|
|
(sys.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64))
|
|
{
|
|
HMODULE h = GetSystemModuleHandle("kernel32.dll");
|
|
if (h)
|
|
{
|
|
const char c_szCtfMonExe[] = "\\ctfmon.exe";
|
|
PGET_SYSTEM_WOW64_DIRECTORY_A lpfn;
|
|
lpfn = (PGET_SYSTEM_WOW64_DIRECTORY_A)GetProcAddress(h, GET_SYSTEM_WOW64_DIRECTORY_NAME_T_A);
|
|
if (lpfn)
|
|
{
|
|
char buf[MAX_PATH];
|
|
UINT len;
|
|
len = (lpfn)(buf, sizeof(buf)/sizeof(char));
|
|
if (len &&
|
|
(ARRAYSIZE(buf) > len + ARRAYSIZE(c_szCtfMonExe)))
|
|
{
|
|
PROCESS_INFORMATION process;
|
|
STARTUPINFO si;
|
|
memset(&si, 0, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
si.wShowWindow = SW_SHOWMINNOACTIVE;
|
|
|
|
lstrcat(buf, c_szCtfMonExe);
|
|
|
|
if (CreateProcess(buf, // application name
|
|
pszCmdLine, // command line
|
|
NULL, // process SD
|
|
NULL, // thread SD
|
|
FALSE, // inherit handle
|
|
0, // creation flags
|
|
NULL, // environment
|
|
NULL, // current directory
|
|
&si, // startup info
|
|
&process)) // process information
|
|
{
|
|
CloseHandle(process.hProcess);
|
|
CloseHandle(process.hThread);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HANDLE hEventWS0 = 0;
|
|
if (! g_bOnWow64)
|
|
hEventWS0 = OpenEvent(SYNCHRONIZE, FALSE, _T("WinSta0_DesktopSwitch"));
|
|
|
|
while (TRUE)
|
|
{
|
|
if (! g_bOnWow64)
|
|
{
|
|
HANDLE rgAllEvents[NUM_REG_WATCH+1];
|
|
const HANDLE *prgRegEvents = CRegWatcher::GetEvents();
|
|
memcpy(rgAllEvents, prgRegEvents, NUM_REG_WATCH*sizeof(HANDLE));
|
|
|
|
#define IDX_EVENT_WS NUM_REG_WATCH
|
|
|
|
#define NUM_ALL_EVENTS (NUM_REG_WATCH+1)
|
|
|
|
rgAllEvents[IDX_EVENT_WS] = hEventWS0;
|
|
|
|
dwWaitObj = MsgWaitForMultipleObjects(NUM_ALL_EVENTS, rgAllEvents, FALSE, INFINITE, QS_ALLINPUT);
|
|
|
|
if (dwWaitObj == WAIT_OBJECT_0 + NUM_ALL_EVENTS)
|
|
{
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (msg.message == WM_QUIT)
|
|
goto Exit;
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
else if (dwWaitObj == WAIT_OBJECT_0 + IDX_EVENT_WS)
|
|
{
|
|
// win station switching event
|
|
|
|
// set mic off
|
|
SetGlobalCompartmentDWORD(GUID_COMPARTMENT_SPEECH_OPENCLOSE, 0);
|
|
|
|
// reset the event (needed? not sure if this is auto-reset)
|
|
::ResetEvent(rgAllEvents[IDX_EVENT_WS]);
|
|
}
|
|
else if (dwWaitObj < WAIT_OBJECT_0 + NUM_REG_WATCH)
|
|
{
|
|
CRegWatcher::OnEvent(dwWaitObj - WAIT_OBJECT_0);
|
|
}
|
|
else
|
|
{
|
|
Assert(0); // error
|
|
msg.wParam = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
delete g_pLoaderWnd;
|
|
|
|
|
|
if (!CLoaderWnd::_bUninitedSystem)
|
|
{
|
|
UninitApp();
|
|
|
|
// it is over!
|
|
TF_UninitSystem();
|
|
}
|
|
|
|
g_cs.Delete();
|
|
|
|
Dbg_MemUninit();
|
|
|
|
return (int)(msg.wParam);
|
|
}
|
|
|
|
|
|
int _stdcall ModuleEntry(void)
|
|
{
|
|
int i;
|
|
STARTUPINFO si;
|
|
|
|
si.dwFlags = 0;
|
|
GetStartupInfoA(&si);
|
|
|
|
i = WinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
|
|
|
|
ExitProcess(i);
|
|
return i;
|
|
}
|