|
|
/*++
Copyright (c) 2001, Microsoft Corporation
Module Name:
com.c
Abstract:
This file implements the COM entry.
Author:
Revision History:
Notes:
--*/
#include "precomp.h"
#define COBJMACROS
#include "msctf.h"
#include "tlapi.h"
#include "apcompat.h"
#ifdef CUAS_ENABLE
#ifndef RtlIsThreadWithinLoaderCallout
BOOLEAN NTAPI RtlIsThreadWithinLoaderCallout (VOID); #endif
HRESULT CtfAImmCreateInputContext(HIMC himc); HRESULT ActivateOrDeactivateTIM( BOOL fActivate); DWORD GetCoInitCountSkip(); DWORD IncCoInitCountSkip(); DWORD DecCoInitCountSkip(); HRESULT Internal_CoInitializeEx(void* pv, DWORD dw);
//+---------------------------------------------------------------------------
//
// For InitializeSpy
//
//----------------------------------------------------------------------------
typedef struct _IMMISPY { IInitializeSpy; ULONG cref; } IMMISPY;
//+---------------------------------------------------------------------------
//
// CTFIMMTLS
//
//----------------------------------------------------------------------------
typedef struct _CTFIMMTLS { IMMISPY *pimmispy; ULARGE_INTEGER uliISpyCookie; DWORD dwInRefCountSkipMode; DWORD dwRefCountSkip; BOOL fInCtfImmCoUninitialize; } CTFIMMTLS;
CTFIMMTLS* GetTLS();
IMMISPY *AllocIMMISPY(); void DeleteIMMISPY(IMMISPY *pimmispy);
//+---------------------------------------------------------------------------
//
// _InsideLoaderLock()
//
//----------------------------------------------------------------------------
BOOL _InsideLoaderLock() { return (NtCurrentTeb()->ClientId.UniqueThread == ((PRTL_CRITICAL_SECTION)(NtCurrentPeb()->LoaderLock))->OwningThread); }
//+---------------------------------------------------------------------------
//
// PImmISpyFromPISpy
//
//----------------------------------------------------------------------------
IMMISPY *PImmISpyFromPISpy(IInitializeSpy *pispy) { return (IMMISPY *)pispy; }
//+---------------------------------------------------------------------------
//
// ISPY_AddRef
//
//----------------------------------------------------------------------------
ULONG ISPY_AddRef(IInitializeSpy *pispy) { IMMISPY *pimmispy = PImmISpyFromPISpy(pispy);
pimmispy->cref++; return pimmispy->cref; }
//+---------------------------------------------------------------------------
//
// ISPY_Release
//
//----------------------------------------------------------------------------
ULONG ISPY_Release(IInitializeSpy *pispy) { IMMISPY *pimmispy = PImmISpyFromPISpy(pispy);
pimmispy->cref--; if (!pimmispy->cref) { DeleteIMMISPY(pimmispy); return 0; }
return pimmispy->cref; }
//+---------------------------------------------------------------------------
//
// ISPY_QueryInterface
//
//----------------------------------------------------------------------------
HRESULT ISPY_QueryInterface(IInitializeSpy *pispy, REFIID riid, void **ppvObject) {
if (!ppvObject) return E_INVALIDARG;
*ppvObject = NULL;
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IInitializeSpy)) { ISPY_AddRef(pispy); *ppvObject = pispy; return S_OK; }
return E_NOINTERFACE; }
//+---------------------------------------------------------------------------
//
// ISPY_PreInitialize
//
//----------------------------------------------------------------------------
HRESULT ISPY_PreInitialize(IInitializeSpy * pispy, DWORD dwCoInit, DWORD dwCurThreadAptRefs) { DWORD dwRet = IncCoInitCountSkip();
UNREFERENCED_PARAMETER(pispy);
//
// If we already initialize com and a 2nd initialization is MT,
// we should disable CUAS. So the CoInit(MT) from caller will work.
//
if (GetClientInfo()->CI_flags & CI_CUAS_COINIT_CALLED) { if ((dwCurThreadAptRefs == (dwRet + 1)) && (dwCoInit == COINIT_MULTITHREADED)) { ActivateOrDeactivateTIM(FALSE); CtfImmCoUninitialize(); } }
return S_OK; }
//+---------------------------------------------------------------------------
//
// ISPY_PostInitialize
//
//----------------------------------------------------------------------------
HRESULT ISPY_PostInitialize(IInitializeSpy * pispy, HRESULT hrCoInit, DWORD dwCoInit, DWORD dwNewThreadAptRefs) { DWORD dwRet = GetCoInitCountSkip(); UNREFERENCED_PARAMETER(pispy); UNREFERENCED_PARAMETER(dwCoInit);
//
// If we already initialize com and got a 2nd initialization,
// change the return value to S_OK. So the caller think
// that it is the first initialization.
//
if (GetClientInfo()->CI_flags & CI_CUAS_COINIT_CALLED) { if ((hrCoInit == S_FALSE) && (dwNewThreadAptRefs == (dwRet + 2))) { return S_OK; } }
return hrCoInit; }
//+---------------------------------------------------------------------------
//
// ISPY_PreUninitialize
//
//----------------------------------------------------------------------------
HRESULT ISPY_PreUninitialize(IInitializeSpy * pispy, DWORD dwCurThreadAptRefs) { UNREFERENCED_PARAMETER(pispy); UNREFERENCED_PARAMETER(dwCurThreadAptRefs);
//
// #607467
//
// Norton Systemworks setup calls CoUninitialize() without calling
// CoInitialize(). So we got under ref problem.
// If the last ref count is ours, we recover it by calling
// CoInitializeEx().
//
if (dwCurThreadAptRefs == 1) { if (!RtlDllShutdownInProgress() && !_InsideLoaderLock() && (GetClientInfo()->CI_flags & CI_CUAS_COINIT_CALLED)) { CTFIMMTLS* ptls = GetTLS(); if (ptls && !ptls->fInCtfImmCoUninitialize) { Internal_CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); } } }
return S_OK; }
//+---------------------------------------------------------------------------
//
// ISPY_PostUninitialize
//
//----------------------------------------------------------------------------
HRESULT ISPY_PostUninitialize(IInitializeSpy * pispy, DWORD dwNewThreadAptRefs) { UNREFERENCED_PARAMETER(pispy); UNREFERENCED_PARAMETER(dwNewThreadAptRefs);
DecCoInitCountSkip(); return S_OK; }
//+---------------------------------------------------------------------------
//
// g_vtbnlISPY
//
//----------------------------------------------------------------------------
IInitializeSpyVtbl g_vtblISPY = { ISPY_QueryInterface, ISPY_AddRef, ISPY_Release, ISPY_PreInitialize, ISPY_PostInitialize, ISPY_PreUninitialize, ISPY_PostUninitialize, };
//+---------------------------------------------------------------------------
//
// AllocIMMISPY
//
//----------------------------------------------------------------------------
IMMISPY *AllocIMMISPY() { IMMISPY *pimmispy = ImmLocalAlloc(0, sizeof(IMMISPY)); if (!pimmispy) return NULL;
pimmispy->lpVtbl = &g_vtblISPY; pimmispy->cref = 1;
return pimmispy; }
//+---------------------------------------------------------------------------
//
// DeletIMMISPY
//
//----------------------------------------------------------------------------
void DeleteIMMISPY(IMMISPY *pimmispy) { ImmLocalFree(pimmispy); }
//////////////////////////////////////////////////////////////////////////////
//
// TLS
//
//////////////////////////////////////////////////////////////////////////////
DWORD g_dwTLSIndex = (DWORD)-1;
//+---------------------------------------------------------------------------
//
// InitTLS
//
//----------------------------------------------------------------------------
void InitTLS() { RtlEnterCriticalSection(&gcsImeDpi); if (g_dwTLSIndex == (DWORD)-1) g_dwTLSIndex = TlsAlloc(); RtlLeaveCriticalSection(&gcsImeDpi); }
//+---------------------------------------------------------------------------
//
// InternalAllocateTLS
//
//----------------------------------------------------------------------------
CTFIMMTLS* InternalAllocateTLS() { CTFIMMTLS* ptls;
if (g_dwTLSIndex == (DWORD)-1) return NULL;
ptls = (CTFIMMTLS*)TlsGetValue(g_dwTLSIndex); if (ptls == NULL) { if ((ptls = (CTFIMMTLS*)ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(CTFIMMTLS))) == NULL) return NULL;
if (!TlsSetValue(g_dwTLSIndex, ptls)) { ImmLocalFree(ptls); return NULL; } } return ptls; }
//+---------------------------------------------------------------------------
//
// GetTLS
//
//----------------------------------------------------------------------------
CTFIMMTLS* GetTLS() { if (g_dwTLSIndex == (DWORD)-1) return NULL;
return (CTFIMMTLS*)TlsGetValue(g_dwTLSIndex); }
//+---------------------------------------------------------------------------
//
// CtfImmEnterCoInitCountSkipMode
//
//----------------------------------------------------------------------------
BOOL WINAPI CtfImmEnterCoInitCountSkipMode() { CTFIMMTLS* ptls = GetTLS(); if (!ptls) return FALSE;
ptls->dwInRefCountSkipMode++; return TRUE; }
//+---------------------------------------------------------------------------
//
// CtfImmLeaveCoInitCountSkip
//
//----------------------------------------------------------------------------
BOOL WINAPI CtfImmLeaveCoInitCountSkipMode() { CTFIMMTLS* ptls = GetTLS(); if (!ptls) return FALSE;
if (ptls->dwInRefCountSkipMode < 1) { UserAssert(0); return FALSE; }
ptls->dwInRefCountSkipMode--; return TRUE; }
//+---------------------------------------------------------------------------
//
// GetCoInitCountSkip
//
//----------------------------------------------------------------------------
DWORD GetCoInitCountSkip() { CTFIMMTLS* ptls = GetTLS(); if (!ptls) return 0;
return ptls->dwRefCountSkip; }
//+---------------------------------------------------------------------------
//
// IncCoInitCountSkip
//
//----------------------------------------------------------------------------
DWORD IncCoInitCountSkip() { DWORD dwRet = 0; CTFIMMTLS* ptls = GetTLS(); if (!ptls) return dwRet;
dwRet = ptls->dwRefCountSkip; if (ptls->dwInRefCountSkipMode) ptls->dwRefCountSkip++;
return dwRet; }
//+---------------------------------------------------------------------------
//
// DecCoInitCountSkip
//
//----------------------------------------------------------------------------
DWORD DecCoInitCountSkip() { DWORD dwRet = 0; CTFIMMTLS* ptls = GetTLS(); if (!ptls) return dwRet;
dwRet = ptls->dwRefCountSkip; if (ptls->dwInRefCountSkipMode) { if (ptls->dwRefCountSkip < 1) { UserAssert(0); return dwRet; } ptls->dwRefCountSkip--; } return dwRet; }
//+---------------------------------------------------------------------------
//
// InternalDestroyTLS
//
//----------------------------------------------------------------------------
BOOL InternalDestroyTLS() { CTFIMMTLS* ptls;
ptls = (CTFIMMTLS*)TlsGetValue(g_dwTLSIndex); if (ptls != NULL) { ImmLocalFree(ptls); TlsSetValue(g_dwTLSIndex, NULL); return TRUE; } return FALSE; }
/*
* Text frame service processing is disabled for all the thread in the current process */ BOOL g_disable_CUAS_flag = FALSE;
//+---------------------------------------------------------------------------
//
// delay load
//
//----------------------------------------------------------------------------
FARPROC GetFn(HINSTANCE *phInst, TCHAR *pchLib, char *pchFunc) { if (*phInst == NULL) { *phInst = LoadLibrary(pchLib); if (*phInst == NULL) { UserAssert(0); return NULL; } }
return GetProcAddress(*phInst, pchFunc); }
HINSTANCE g_hOle32 = NULL;
HRESULT Internal_CoInitializeEx(void* pv, DWORD dw) { static FARPROC pfn = NULL; if (pfn == NULL || g_hOle32 == NULL) { pfn = GetFn(&g_hOle32, L"ole32.dll", "CoInitializeEx"); if (pfn == NULL) { UserAssert(0); return E_FAIL; } } return (HRESULT)(*pfn)(pv, dw); }
void Internal_CoUninitialize() { static FARPROC pfn = NULL; if (pfn == NULL || g_hOle32 == NULL) { pfn = GetFn(&g_hOle32, L"ole32.dll", "CoUninitialize"); if (pfn == NULL) { UserAssert(0); return; } } (*pfn)(); }
HRESULT Internal_CoRegisterInitializeSpy(LPINITIALIZESPY pSpy, ULARGE_INTEGER *puliCookie) { static FARPROC pfn = NULL; if (pfn == NULL || g_hOle32 == NULL) { pfn = GetFn(&g_hOle32, L"ole32.dll", "CoRegisterInitializeSpy"); if (pfn == NULL) { UserAssert(0); return E_FAIL; } } return (HRESULT)(*pfn)(pSpy, puliCookie); }
HRESULT Internal_CoRevokeInitializeSpy(ULARGE_INTEGER uliCookie) { static FARPROC pfn = NULL; if (pfn == NULL || g_hOle32 == NULL) { pfn = GetFn(&g_hOle32, L"ole32.dll", "CoRevokeInitializeSpy"); if (pfn == NULL) { UserAssert(0); return E_FAIL; } } return (HRESULT)(*pfn)(uliCookie); }
HINSTANCE g_hMsctf = NULL;
HRESULT Internal_TF_CreateLangBarMgr(ITfLangBarMgr** pv) { static FARPROC pfn = NULL; if (pfn == NULL || g_hMsctf == NULL) { pfn = GetFn(&g_hMsctf, L"msctf.dll", "TF_CreateLangBarMgr"); if (pfn == NULL) { UserAssert(0); return E_FAIL; } } return (HRESULT)(*pfn)(pv); }
DWORD Internal_TF_CicNotify(int nCode, WPARAM wParam, LPARAM lParam) { static FARPROC pfn = NULL; if (pfn == NULL || g_hMsctf == NULL) { pfn = GetFn(&g_hMsctf, L"msctf.dll", "TF_CicNotify"); if (pfn == NULL) { UserAssert(0); return E_FAIL; } } return (DWORD)(*pfn)(nCode, wParam, lParam); }
#if 0
HINSTANCE g_hNtdll = NULL;
BOOLEAN Internal_RtlIsThreadWithinLoaderCallout(VOID) { static FARPROC pfn = NULL; if (pfn == NULL || g_hNtdll == NULL) { pfn = GetFn(&g_hNtdll, L"ntdll.dll", "RtlIsThreadWithinLoaderCallout"); if (pfn == NULL) { UserAssert(0); return FALSE; } } return (BOOLEAN)(*pfn)(); } #endif
//+---------------------------------------------------------------------------
//
// CtfImmCoInitialize
//
//----------------------------------------------------------------------------
HRESULT CtfImmCoInitialize() { //
// CoInitializeEx
//
HRESULT hr = E_NOINTERFACE;
//
// Check CI flag
//
if (GetClientInfo()->CI_flags & CI_CUAS_COINIT_CALLED) return S_OK;
hr = Internal_CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (SUCCEEDED(hr)) { RIPMSG0(RIP_VERBOSE, "CtfImmCoInitialize succeeded.");
//
// Set CI flag
//
GetClientInfo()->CI_flags |= CI_CUAS_COINIT_CALLED;
{ CTFIMMTLS* ptls; //
// Initialize CoInitSpy.
//
InitTLS(); ptls = InternalAllocateTLS();
if (ptls && !ptls->pimmispy) { ptls->pimmispy = AllocIMMISPY(); if (ptls->pimmispy) { HRESULT hrTemp; hrTemp = Internal_CoRegisterInitializeSpy((LPINITIALIZESPY)ptls->pimmispy, &(ptls->uliISpyCookie));
if (FAILED(hrTemp)) { DeleteIMMISPY(ptls->pimmispy); ptls->pimmispy = NULL; memset(&ptls->uliISpyCookie, 0, sizeof(ULARGE_INTEGER));
} } } }
hr = S_OK; } else { RIPMSG1(RIP_WARNING, "CtfImmCoInitialize failed. err=%x", hr); } return hr; }
//+---------------------------------------------------------------------------
//
// CtfImmCoUninitialize
//
//----------------------------------------------------------------------------
void WINAPI CtfImmCoUninitialize() { if (GetClientInfo()->CI_flags & CI_CUAS_COINIT_CALLED) { CTFIMMTLS* ptls = GetTLS(); if (ptls) { ptls->fInCtfImmCoUninitialize = TRUE; Internal_CoUninitialize(); ptls->fInCtfImmCoUninitialize = FALSE; GetClientInfo()->CI_flags &= ~CI_CUAS_COINIT_CALLED; }
{ CTFIMMTLS* ptls; //
// revoke initialize spy
//
ptls = InternalAllocateTLS(); if (ptls && ptls->pimmispy) { Internal_CoRevokeInitializeSpy(ptls->uliISpyCookie); ISPY_Release((IInitializeSpy *)ptls->pimmispy); ptls->pimmispy = NULL; memset(&ptls->uliISpyCookie, 0, sizeof(ULARGE_INTEGER)); } } } }
//+---------------------------------------------------------------------------
//
// CtfImmTIMActivate
//
//----------------------------------------------------------------------------
HRESULT CtfImmTIMActivate( HKL hKL) { HRESULT hr = S_OK;
/*
* Text frame service processing is disabled for all the thread in the current process */ if (g_disable_CUAS_flag) { RIPMSG0(RIP_VERBOSE, "CtfImmTIMActivate: g_disable_CUAS_flag is ON."); /*
* set client info flag. */ GetClientInfo()->CI_flags |= CI_CUAS_DISABLE; return hr; }
/*
* Check client info flag. */ if (GetClientInfo()->CI_flags & CI_CUAS_DISABLE) { RIPMSG0(RIP_VERBOSE, "CtfImmTIMActivate: CI_CUAS_DISABLE is ON."); return hr; }
/*
* Check Disable Advanced Text Services switch. * If it is On, doesn't activate TIM. */ if (IsDisabledTextServices()) { /*
* set client info flag. */ GetClientInfo()->CI_flags |= CI_CUAS_DISABLE;
RIPMSG0(RIP_VERBOSE, "CtfImmTIMActivate: Disabled Text Services."); return hr; }
/*
* Check a interactive user logon. */ if (!IsInteractiveUserLogon() || IsRunningInMsoobe()) { RIPMSG0(RIP_VERBOSE, "CtfImmTIMActivate: Not a interactive user logon. or MSOOBE mode"); return hr; }
/*
* Check CUAS switch. If CUAS is OFF, doesn't activate TIM. */ if (! IsCUASEnabled()) { /*
* If AIMM enabled, then return S_OK; */ DWORD dwImeCompatFlags = ImmGetAppCompatFlags(NULL); if (dwImeCompatFlags & (IMECOMPAT_AIMM12 | IMECOMPAT_AIMM_LEGACY_CLSID | IMECOMPAT_AIMM12_TRIDENT)) { return S_OK; }
/*
* set client info flag. */ GetClientInfo()->CI_flags |= CI_CUAS_DISABLE;
RIPMSG0(RIP_VERBOSE, "CtfImmTIMActivate: CUAS switch is OFF."); return hr; }
/*
* * KACF_DISABLECICERO is already defined in private/Lab06_DEV * we will use this flag later. * * APPCOMPATFLAG(KACF_DISABLECICERO) * KACF_DISABLECICERO is 0x100 */ #ifndef KACF_DISABLECICERO
#define KACF_DISABLECICERO 0x00000100 // If set. Cicero support for the current process
// is disabled.
#endif
if (APPCOMPATFLAG(KACF_DISABLECICERO)) { /*
* set client info flag. */ GetClientInfo()->CI_flags |= CI_CUAS_DISABLE;
RIPMSG0(RIP_VERBOSE, "CtfImmTIMActivate: KACF_DISABLECICERO app compatiblity flag is ON."); return hr; }
if (RtlIsThreadWithinLoaderCallout()) { RIPMSG0(RIP_VERBOSE, "CtfImmTIMActivate: we're in DllMain()."); return hr; }
if (_InsideLoaderLock()) { RIPMSG0(RIP_VERBOSE, "CtfImmTIMActivate: we're in DllMain."); return hr; }
if (IS_CICERO_ENABLED_AND_NOT16BIT()) { HINSTANCE hCtf = NULL;
if (IS_IME_KBDLAYOUT(hKL)) { LANGID lg = LOWORD(HandleToUlong(hKL)); hKL = (HKL)LongToHandle( MAKELONG(lg, lg) ); }
if (!ImmLoadIME(hKL)) { //
RIPMSG1(RIP_VERBOSE, "CtfImmTIMActivate: ImmLoadIME=%lx fail.", hKL); //
// Cicero keyboard layout doesn't loaded yet.
// MSCTF ! TF_InvalidAssemblyListCacheIfExist load Cicero assembly.
//
hCtf = LoadLibrary(TEXT("msctf.dll")); if (hCtf) { typedef BOOL (WINAPI* PFNINVALIDASSEMBLY)(); PFNINVALIDASSEMBLY pfn; pfn = (PFNINVALIDASSEMBLY)GetProcAddress(hCtf, "TF_InvalidAssemblyListCacheIfExist"); if (pfn) { pfn(); } } }
/*
* Initialize COM for Cicero IME. */ CtfImmCoInitialize();
if ( (GetClientInfo()->CI_flags & CI_CUAS_COINIT_CALLED) && ! (GetClientInfo()->CI_flags & CI_CUAS_TIM_ACTIVATED)) { /*
* Create and Activate TIM */ hr = Internal_CtfImeCreateThreadMgr(); if (SUCCEEDED(hr)) { GetClientInfo()->CI_flags |= CI_CUAS_TIM_ACTIVATED; RIPMSG0(RIP_VERBOSE, "CtfImmTIMActivate: Succeeded CtfImeCreateThreadMgr."); } else { RIPMSG0(RIP_WARNING, "CtfImmTIMActivate: Fail CtfImeCreateThreadMgr."); } }
if (hCtf) { FreeLibrary(hCtf); } }
return hr; }
//+---------------------------------------------------------------------------
//
// CtfImmTIMCreateInputContext
//
//----------------------------------------------------------------------------
HRESULT CtfImmTIMCreateInputContext( HIMC hImc) { PCLIENTIMC pClientImc; HRESULT hr = S_FALSE; DWORD dwThreadId;
if (GetClientInfo()->CI_flags & CI_CUAS_AIMM12ACTIVATED) { if ((pClientImc = ImmLockClientImc(hImc)) == NULL) return E_FAIL;
/*
* check fCtfImeContext first */ if (pClientImc->fCtfImeContext) goto Exit;
pClientImc->fCtfImeContext = TRUE; hr = CtfAImmCreateInputContext(hImc); if (SUCCEEDED(hr)) { RIPMSG0(RIP_VERBOSE, "CtfImmTIMCreateInputContext: Succeeded CtfImeCreateInputContext."); } else { pClientImc->fCtfImeContext = FALSE;
RIPMSG0(RIP_WARNING, "CtfImmTIMCreateInputContext: Fail CtfImeCreateInputContext."); } goto Exit; }
if (!(GetClientInfo()->CI_flags & CI_CUAS_TIM_ACTIVATED)) { //
// Tim is not activated. We don't have to create the InputContext.
//
return S_OK; }
if ((pClientImc = ImmLockClientImc(hImc)) == NULL) return E_FAIL;
/*
* check fCtfImeContext first */ if (pClientImc->fCtfImeContext) goto Exit;
dwThreadId = GetInputContextThread(hImc); if (dwThreadId != GetCurrentThreadId()) goto Exit;
if (IS_CICERO_ENABLED_AND_NOT16BIT()) { /*
* Set fCtfImeContext before calling ctfime to avoid recursion * call. */ pClientImc->fCtfImeContext = TRUE;
/*
* Create Input Context */ hr = Internal_CtfImeCreateInputContext(hImc); if (SUCCEEDED(hr)) { RIPMSG0(RIP_VERBOSE, "CtfImmTIMCreateInputContext: Succeeded CtfImeCreateInputContext."); } else { pClientImc->fCtfImeContext = FALSE;
RIPMSG0(RIP_WARNING, "CtfImmTIMCreateInputContext: Fail CtfImeCreateInputContext."); } }
Exit: ImmUnlockClientImc(pClientImc);
return hr; }
//+---------------------------------------------------------------------------
//
// CtfImmTIMDestroyInputContext
//
//----------------------------------------------------------------------------
HRESULT CtfImmTIMDestroyInputContext( HIMC hImc) { HRESULT hr = E_NOINTERFACE;
if (IS_CICERO_ENABLED_AND_NOT16BIT()) { /*
* Destroy Input Context. */ hr = Internal_CtfImeDestroyInputContext(hImc); if (SUCCEEDED(hr)) { RIPMSG0(RIP_VERBOSE, "CtfImmTIMDestroyInputContext: Succeeded CtfImeDestroyInputContext."); } else { RIPMSG0(RIP_WARNING, "CtfImmTIMDestroyInputContext: Fail CtfImeDestroyInputContext."); } } return hr; }
//+---------------------------------------------------------------------------
//
// CtfImmRestoreToolbarWnd
//
//----------------------------------------------------------------------------
void CtfImmRestoreToolbarWnd( DWORD dwStatus) { ITfLangBarMgr* plbm;
if (SUCCEEDED(Internal_TF_CreateLangBarMgr(&plbm))) { if (dwStatus) { ITfLangBarMgr_ShowFloating(plbm, dwStatus); } ITfLangBarMgr_Release(plbm); } return; }
//+---------------------------------------------------------------------------
//
// CtfImmHideToolbarWnd
//
//----------------------------------------------------------------------------
DWORD CtfImmHideToolbarWnd() { ITfLangBarMgr* plbm; DWORD _dwPrev = 0;
if (SUCCEEDED(Internal_TF_CreateLangBarMgr(&plbm))) { if (SUCCEEDED(ITfLangBarMgr_GetShowFloatingStatus(plbm, &_dwPrev))) { BOOL fHide = TRUE; if (_dwPrev & TF_SFT_DESKBAND) fHide = FALSE;
//
// mask for show/hide
//
_dwPrev &= (TF_SFT_SHOWNORMAL | TF_SFT_DOCK | TF_SFT_MINIMIZED | TF_SFT_HIDDEN);
if (fHide) ITfLangBarMgr_ShowFloating(plbm, TF_SFT_HIDDEN); } ITfLangBarMgr_Release(plbm); }
return _dwPrev; }
//+---------------------------------------------------------------------------
//
// CtfImmGetGuidAtom
//
//----------------------------------------------------------------------------
HRESULT CtfImmGetGuidAtom(HIMC hImc, BYTE bAttr, DWORD* pGuidAtom) { HRESULT hr = E_FAIL;
*pGuidAtom = 0;
if (IS_CICERO_ENABLED_AND_NOT16BIT()) {
PIMEDPI pImeDpi; DWORD dwImcThreadId = (DWORD)NtUserQueryInputContext(hImc, InputContextThread); HKL hKL = GetKeyboardLayout(dwImcThreadId);
if (IS_IME_KBDLAYOUT(hKL)) { RIPMSG1(RIP_WARNING, "CtfImmGetGuidAtom: hKL=%lx.", hKL); return FALSE; }
pImeDpi = FindOrLoadImeDpi(hKL); if (pImeDpi == NULL) { RIPMSG0(RIP_WARNING, "CtfImmGetGuidAtom: no pImeDpi entry."); } else { /*
* Get GUID atom value */ hr = (*pImeDpi->pfn.CtfImeGetGuidAtom)(hImc, bAttr, pGuidAtom); if (SUCCEEDED(hr)) { RIPMSG0(RIP_VERBOSE, "CtfImmGetGuidAtom: Succeeded CtfImeGetGuidAtom."); } else { RIPMSG0(RIP_WARNING, "CtfImmGetGuidAtom: Fail CtfImeGetGuidAtom."); } ImmUnlockImeDpi(pImeDpi); } }
return hr; }
//+---------------------------------------------------------------------------
//
// CtfImmIsGuidMapEnable
//
//----------------------------------------------------------------------------
BOOL CtfImmIsGuidMapEnable(HIMC hImc) { BOOL ret = FALSE;
if (IS_CICERO_ENABLED_AND_NOT16BIT()) {
PIMEDPI pImeDpi; DWORD dwImcThreadId = (DWORD)NtUserQueryInputContext(hImc, InputContextThread); HKL hKL = GetKeyboardLayout(dwImcThreadId);
if (IS_IME_KBDLAYOUT(hKL)) { RIPMSG1(RIP_WARNING, "CtfImmIsGuidMapEnable: hKL=%lx.", hKL); return FALSE; }
pImeDpi = FindOrLoadImeDpi(hKL); if (pImeDpi == NULL) { RIPMSG0(RIP_WARNING, "CtfImmIsGuidMapEnable: no pImeDpi entry."); } else { /*
* Get GUID atom value */ ret = (*pImeDpi->pfn.CtfImeIsGuidMapEnable)(hImc); ImmUnlockImeDpi(pImeDpi); } }
return ret; }
//+---------------------------------------------------------------------------
//
// CtfImmSetAppCompatFlags
//
//----------------------------------------------------------------------------
DWORD g_aimm_compat_flags = 0;
VOID CtfImmSetAppCompatFlags( DWORD dwFlag) { if (dwFlag & ~(IMECOMPAT_AIMM_LEGACY_CLSID | IMECOMPAT_AIMM_TRIDENT55 | IMECOMPAT_AIMM12_TRIDENT | IMECOMPAT_AIMM12)) { return; }
g_aimm_compat_flags = dwFlag; }
//+---------------------------------------------------------------------------
//
// ActivateOrDeactivateTIM
//
//----------------------------------------------------------------------------
HRESULT ActivateOrDeactivateTIM( BOOL fActivate) { HRESULT hr = S_OK;
if (IS_CICERO_ENABLED_AND_NOT16BIT()) { if (GetClientInfo()->CI_flags & CI_CUAS_COINIT_CALLED) { if (! fActivate) { /*
* Deactivate TIM */ if (GetClientInfo()->CI_flags & CI_CUAS_TIM_ACTIVATED) { hr = Internal_CtfImeDestroyThreadMgr(); if (SUCCEEDED(hr)) { GetClientInfo()->CI_flags &= ~CI_CUAS_TIM_ACTIVATED; RIPMSG0(RIP_VERBOSE, "CtfImmLastEnabledWndDestroy: Succeeded CtfImeDestroyThreadMgr."); } else { RIPMSG0(RIP_WARNING, "CtfImmLastEnabledWndDestroy: Fail CtfImeDestroyThreadMgr."); }
} } else { /*
* Activate TIM */ if (! (GetClientInfo()->CI_flags & CI_CUAS_TIM_ACTIVATED)) { hr = Internal_CtfImeCreateThreadMgr(); if (SUCCEEDED(hr)) { GetClientInfo()->CI_flags |= CI_CUAS_TIM_ACTIVATED; RIPMSG0(RIP_VERBOSE, "CtfImmLastEnabledWndDestroy: Succeeded CtfImeDestroyThreadMgr."); } else { RIPMSG0(RIP_WARNING, "CtfImmLastEnabledWndDestroy: Fail CtfImeDestroyThreadMgr."); } } } }
} return hr; }
//+---------------------------------------------------------------------------
//
// CtfImmLastEnabledWndDestroy
// LPARAM 0 = Deactivate TIM.
// ! 0 = Activate TIM.
//
//----------------------------------------------------------------------------
HRESULT CtfImmLastEnabledWndDestroy( LPARAM lParam) { return ActivateOrDeactivateTIM(lParam ? TRUE : FALSE); }
//+---------------------------------------------------------------------------
//
// ImmSetLangBand
//
//----------------------------------------------------------------------------
// TM_LANGUAGEBAND is defined in "shell\inc\trayp.h"
#define TM_LANGUAGEBAND WM_USER+0x105
typedef struct _LANG_BAND { HWND hwndTray; BOOL fLangBand; } LANG_BAND;
DWORD DelaySetLangBand( LANG_BAND* langband) { HWND hwndIME;
//
// Delay 3000msec.
// If this delay value is not enough, Explorer takes CPU power 100%.
// printui!CTrayNotify::_ResetAll
//
Sleep(3000);
hwndIME = ImmGetDefaultIMEWnd(langband->hwndTray); if (hwndIME) { DWORD_PTR dwResult; LRESULT lResult = (LRESULT)0;
lResult = SendMessageTimeout(hwndIME, WM_IME_SYSTEM, langband->fLangBand ? IMS_SETLANGBAND : IMS_RESETLANGBAND, (LPARAM)langband->hwndTray, SMTO_ABORTIFHUNG | SMTO_BLOCK, 5000, &dwResult);
//
// Checking the language band setting fail case
//
if (!lResult || dwResult != langband->fLangBand) { // UserAssert(0);
} }
ImmLocalFree(langband);
return 0; }
LRESULT CtfImmSetLangBand( HWND hwndTray, BOOL fLangBand) { DWORD_PTR dwResult = 0; PWND pwnd;
// check if the window of the Explorer Tray is valid
if ((pwnd = ValidateHwnd(hwndTray)) == NULL) { RIPMSG1(RIP_WARNING, "CtfImmSetLangBand: Invalid hwndTray %lx.", hwndTray); } else { if (TestWF(pwnd, WFISINITIALIZED)) { // TRUE if the Explorer Tray is initialized
LRESULT lResult = (LRESULT)0;
lResult = SendMessageTimeout(hwndTray, TM_LANGUAGEBAND, 0, fLangBand, SMTO_ABORTIFHUNG | SMTO_BLOCK, 5000, &dwResult);
//
// Checking the language band setting fail case
//
if (!lResult || dwResult != fLangBand) { // UserAssert(0);
} } else { LANG_BAND* langband = (LANG_BAND*) ImmLocalAlloc(0, sizeof(LANG_BAND)); if (langband != NULL) { HANDLE hThread; DWORD ThreadId;
langband->hwndTray = hwndTray; langband->fLangBand = fLangBand;
hThread = CreateThread(NULL, 0, DelaySetLangBand, langband, 0, &ThreadId); if (hThread) { CloseHandle(hThread); } } } } return dwResult; }
BOOL CtfImmIsCiceroEnabled() { return IS_CICERO_ENABLED(); }
BOOL CtfImmIsCiceroStartedInThread() { return (GetClientInfo()->CI_flags & CI_CUAS_MSCTF_RUNNING) ? TRUE : FALSE; }
HRESULT CtfImmSetCiceroStartInThread(BOOL fSet) { if (fSet) GetClientInfo()->CI_flags |= CI_CUAS_MSCTF_RUNNING; else GetClientInfo()->CI_flags &= ~CI_CUAS_MSCTF_RUNNING; return S_OK; }
BOOL IsCUASEnabled() { LONG lRet; HKEY hKeyCtf; DWORD dwType; DWORD dwCUAS; DWORD dwTmp;
lRet = RegOpenKey(HKEY_LOCAL_MACHINE, gszRegCtfShared, &hKeyCtf); if ( lRet != ERROR_SUCCESS ) { return FALSE; }
dwType = 0; dwCUAS = 0; dwTmp = sizeof(DWORD); lRet = RegQueryValueEx(hKeyCtf, gszValCUASEnable, NULL, &dwType, (LPBYTE)&dwCUAS, &dwTmp); RegCloseKey(hKeyCtf);
if ( lRet != ERROR_SUCCESS || dwType != REG_DWORD) { return FALSE; }
return (BOOL)dwCUAS; }
//+---------------------------------------------------------------------------
//
// ImmDisableTextFrameService
//
//----------------------------------------------------------------------------
BOOL ImmDisableTextFrameService(DWORD idThread) { HRESULT hr = S_OK;
if (idThread == -1) { // Text frame service processing is disabled for all the thread in the current process
g_disable_CUAS_flag = TRUE; }
if ((idThread == 0 || g_disable_CUAS_flag) && (! (GetClientInfo()->CI_flags & CI_CUAS_DISABLE))) { /*
* set client info flag. */ GetClientInfo()->CI_flags |= CI_CUAS_DISABLE;
if (IS_CICERO_ENABLED_AND_NOT16BIT()) { if (GetClientInfo()->CI_flags & CI_CUAS_COINIT_CALLED) { /*
* Deactivate TIM */ if (GetClientInfo()->CI_flags & CI_CUAS_TIM_ACTIVATED) { hr = Internal_CtfImeDestroyThreadMgr(); if (SUCCEEDED(hr)) { GetClientInfo()->CI_flags &= ~CI_CUAS_TIM_ACTIVATED; RIPMSG0(RIP_VERBOSE, "ImmDisableTextFrameService: Succeeded CtfImeDestroyThreadMgr."); } else { RIPMSG0(RIP_WARNING, "ImmDisableTextFrameService: Fail CtfImeDestroyThreadMgr."); }
if (SUCCEEDED(hr)) { /*
* CoUninitialize */ CtfImmCoUninitialize(); } } } } }
return hr == S_OK ? TRUE : FALSE; }
BOOL CtfImmIsTextFrameServiceDisabled() { return (GetClientInfo()->CI_flags & CI_CUAS_DISABLE) ? TRUE : FALSE; }
BOOL IsDisabledTextServices() { static const TCHAR c_szCTFKey[] = TEXT("SOFTWARE\\Microsoft\\CTF"); static const TCHAR c_szDiableTim[] = TEXT("Disable Thread Input Manager");
HKEY hKey;
if (RegOpenKey(HKEY_CURRENT_USER, c_szCTFKey, &hKey) == ERROR_SUCCESS) { DWORD cb; DWORD dwDisableTim = 0;
cb = sizeof(DWORD);
RegQueryValueEx(hKey, c_szDiableTim, NULL, NULL, (LPBYTE)&dwDisableTim, &cb);
RegCloseKey(hKey);
//
// Ctfmon disabling flag is set.
//
if (dwDisableTim) return TRUE; }
return FALSE; }
BOOL IsInteractiveUserLogon() { PSID InteractiveSid; BOOL bCheckSucceeded; BOOL bAmInteractive = FALSE; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid(&NtAuthority, 1, SECURITY_INTERACTIVE_RID, 0, 0, 0, 0, 0, 0, 0, &InteractiveSid)) { return FALSE; }
//
// This checking is for logged on user or not. So we can blcok running
// ctfmon.exe process from non-authorized user.
//
bCheckSucceeded = CheckTokenMembership(NULL, InteractiveSid, &bAmInteractive);
if (InteractiveSid) FreeSid(InteractiveSid);
return (bCheckSucceeded && bAmInteractive); }
//+---------------------------------------------------------------------------
//
// IsRunningInMsoobe()
//
//----------------------------------------------------------------------------
BOOL IsRunningInMsoobe() { static const TCHAR c_szMsoobeModule[] = TEXT("msoobe.exe");
TCHAR szFileName[MAX_PATH]; TCHAR szModuleName[MAX_PATH]; LPTSTR pszFilePart = NULL;
if (GetModuleFileName(NULL, szFileName, sizeof(szFileName)/sizeof(szFileName[0])) == 0) return FALSE;
GetFullPathName(szFileName, sizeof(szFileName)/sizeof(szFileName[0]), szModuleName, &pszFilePart);
if (pszFilePart == NULL) return FALSE;
if (lstrcmpiW(pszFilePart, c_szMsoobeModule) == 0) return TRUE;
return FALSE; }
//+---------------------------------------------------------------------------
//
// LoadCtfIme
//
//----------------------------------------------------------------------------
BOOL CheckAndApplyAppCompat(LPWSTR wszImeFile);
typedef HRESULT (CALLBACK* PFNCREATETHREADMGR)(); typedef HRESULT (CALLBACK* PFNDESTROYTHREADMGR)(); typedef HRESULT (CALLBACK* PFNCREATEINPUTCONTEXT)(HIMC); typedef HRESULT (CALLBACK* PFNDESTROYINPUTCONTEXT)(HIMC); typedef HRESULT (CALLBACK* PFNSETACTIVECONTEXTALWAYS)(HIMC, BOOL, HWND, HKL); typedef BOOL (CALLBACK* PFNPROCESSCICHOTKEY)(HIMC, UINT, LPARAM); typedef LRESULT (CALLBACK* PFNDISPATCHDEFIMEMESSAGE)(HWND, UINT, WPARAM, LPARAM); typedef BOOL (CALLBACK* PFNIMEISIME)(HKL);
PFNCREATETHREADMGR g_pfnCtfImeCreateThreadMgr = NULL; PFNDESTROYTHREADMGR g_pfnCtfImeDestroyThreadMgr = NULL; PFNCREATEINPUTCONTEXT g_pfnCtfImeCreateInputContext = NULL; PFNDESTROYINPUTCONTEXT g_pfnCtfImeDestroyInputContext= NULL; PFNSETACTIVECONTEXTALWAYS g_pfnCtfImeSetActiveContextAlways= NULL; PFNPROCESSCICHOTKEY g_pfnCtfImeProcessCicHotkey = NULL; PFNDISPATCHDEFIMEMESSAGE g_pfnCtfImeDispatchDefImeMessage = NULL; PFNIMEISIME g_pfnCtfImeIsIME = NULL;
#define GET_CTFIMEPROC(x) \
if (!(g_pfn##x = (PVOID) GetProcAddress(g_hCtfIme, #x))) { \ RIPMSG0(RIP_WARNING, "LoadCtfIme: " #x " not supported"); \ goto LoadCtfIme_ErrOut; }
HMODULE g_hCtfIme = NULL;
HMODULE LoadCtfIme() { IMEINFOEX iiex;
RtlEnterCriticalSection(&gcsImeDpi);
if (g_hCtfIme) goto Exit;
if (ImmLoadLayout((HKL)0x04090409, &iiex)) { WCHAR wszImeFile[MAX_PATH];
GetSystemPathName(wszImeFile, iiex.wszImeFile, MAX_PATH);
if (!CheckAndApplyAppCompat(wszImeFile)) { RIPMSG1(RIP_WARNING, "LoadCtfIme: IME (%ws) blocked by appcompat", wszImeFile); } else { g_hCtfIme = LoadLibraryW(wszImeFile); if (g_hCtfIme) { GET_CTFIMEPROC(CtfImeCreateThreadMgr); GET_CTFIMEPROC(CtfImeDestroyThreadMgr); GET_CTFIMEPROC(CtfImeCreateInputContext); GET_CTFIMEPROC(CtfImeDestroyInputContext); GET_CTFIMEPROC(CtfImeSetActiveContextAlways); GET_CTFIMEPROC(CtfImeProcessCicHotkey); GET_CTFIMEPROC(CtfImeDispatchDefImeMessage); GET_CTFIMEPROC(CtfImeIsIME); } } } goto Exit;
LoadCtfIme_ErrOut: if (g_hCtfIme) { FreeLibrary(g_hCtfIme); g_hCtfIme = NULL; }
Exit:
RtlLeaveCriticalSection(&gcsImeDpi); return g_hCtfIme; }
//+---------------------------------------------------------------------------
//
// CtfAImmCreateInputContext
//
//----------------------------------------------------------------------------
HRESULT CtfAImmCreateInputContext(HIMC himc) { return Internal_CtfImeCreateInputContext(himc); }
//+---------------------------------------------------------------------------
//
// EnumIMC
//
//----------------------------------------------------------------------------
BOOL EnumIMC(HIMC hIMC, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); CtfAImmCreateInputContext(hIMC); return TRUE; }
//+---------------------------------------------------------------------------
//
// CtfAImmActivate
//
//----------------------------------------------------------------------------
HRESULT CtfAImmActivate(HMODULE* phMod) { HRESULT hr = E_FAIL; HMODULE hCtfIme = LoadCtfIme();
hr = Internal_CtfImeCreateThreadMgr(); if (hr == S_OK) {
GetClientInfo()->CI_flags |= CI_CUAS_AIMM12ACTIVATED;
/*
* reset client info flag. * Bug#525583 - Reset CU_CUAS_DISABLE flag before create * the input context. */ GetClientInfo()->CI_flags &= ~CI_CUAS_DISABLE;
ImmEnumInputContext(0, EnumIMC, 0); }
if (phMod) *phMod = hCtfIme;
return hr; }
//+---------------------------------------------------------------------------
//
// CtfAImmDectivate
//
//----------------------------------------------------------------------------
HRESULT CtfAImmDeactivate(HMODULE hMod) { HRESULT hr = E_FAIL;
//
// Load CTFIME and destroy TIM.
//
if (hMod) { hr = Internal_CtfImeDestroyThreadMgr(); if (hr == S_OK) { GetClientInfo()->CI_flags &= ~CI_CUAS_AIMM12ACTIVATED; /*
* set client info flag. */ GetClientInfo()->CI_flags |= CI_CUAS_DISABLE; } //
// Win BUG: 611569
//
// Don't call FreeLibrary because LoadCtfIme() hold CTFIME module handle in global.
//
// FreeLibrary(hMod);
}
return hr; }
//+---------------------------------------------------------------------------
//
// CtfAImmIsIME
//
//----------------------------------------------------------------------------
BOOL CtfAImmIsIME(HKL hkl) { if (LoadCtfIme()) return (g_pfnCtfImeIsIME)(hkl);
return ImmIsIME(hkl); }
//+---------------------------------------------------------------------------
//
// CtfImmDispatchDefImeMessage
//
//----------------------------------------------------------------------------
LRESULT CtfImmDispatchDefImeMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (RtlDllShutdownInProgress() || _InsideLoaderLock()) return 0;
if (LoadCtfIme()) { return (g_pfnCtfImeDispatchDefImeMessage)(hwnd, message, wParam, lParam); }
return 0; }
//+---------------------------------------------------------------------------
//
// Internal_CtfImeCreateThreadMgr
//
//----------------------------------------------------------------------------
HRESULT Internal_CtfImeCreateThreadMgr() { if (!LoadCtfIme()) return E_FAIL;
return (g_pfnCtfImeCreateThreadMgr)(); }
//+---------------------------------------------------------------------------
//
// Internal_CtfImeDestroyThreadMgr
//
//----------------------------------------------------------------------------
HRESULT Internal_CtfImeDestroyThreadMgr() { if (!LoadCtfIme()) return E_FAIL;
return (g_pfnCtfImeDestroyThreadMgr)(); } //+---------------------------------------------------------------------------
//
// Internal_CtfImeProcessCicHotkey
//
//----------------------------------------------------------------------------
BOOL Internal_CtfImeProcessCicHotkey(HIMC hIMC, UINT uVKey, LPARAM lParam) { if (!LoadCtfIme()) return FALSE;
return (g_pfnCtfImeProcessCicHotkey)(hIMC, uVKey, lParam); }
//+---------------------------------------------------------------------------
//
// Internal_CtfImeCreateInputContext
//
//----------------------------------------------------------------------------
HRESULT Internal_CtfImeCreateInputContext(HIMC himc) { if (!LoadCtfIme()) return E_FAIL;
return (g_pfnCtfImeCreateInputContext)(himc); }
//+---------------------------------------------------------------------------
//
// Internal_CtfImeDestroyInputContext
//
//----------------------------------------------------------------------------
HRESULT Internal_CtfImeDestroyInputContext(HIMC himc) { if (!LoadCtfIme()) return E_FAIL;
return (g_pfnCtfImeDestroyInputContext)(himc); }
//+---------------------------------------------------------------------------
//
// Internal_CtfImeSetActiveContextAlways
//
//----------------------------------------------------------------------------
HRESULT Internal_CtfImeSetActiveContextAlways(HIMC himc, BOOL fActive, HWND hwnd, HKL hkl) { if (!LoadCtfIme()) return E_FAIL;
return (g_pfnCtfImeSetActiveContextAlways)(himc, fActive, hwnd, hkl); }
#else
void CtfImmGetGuidAtom() { } void CtfImmHideToolbarWnd() { } void CtfImmIsGuidMapEnable() { } void CtfImmRestoreToolbarWnd() { } void CtfImmSetAppCompatFlags() { } void CtfImmTIMActivate() { } void CtfImmIsCiceroEnabled() { } void CtfImmDispatchDefImeMessage() { } #endif // CUAS_ENABLE
|