// // dam.cpp // #include "private.h" #include "tlhelp32.h" #include "globals.h" #include "dam.h" #include "tim.h" #include "thdutil.h" #include "timlist.h" // get CLSID_STRLEN #include "regsvr.h" /* ff4619e8-ea5e-43e5-b308-11cd26ab6b3a */ const IID IID_CDisplayAttributeMgr = { 0xff4619e8, 0xea5e, 0x43e5, {0xb3, 0x08, 0x11, 0xcd, 0x26, 0xab, 0x6b, 0x3a} }; const TCHAR c_szDAMCacheKey[] = TEXT("SOFTWARE\\Microsoft\\CTF\\DisplayAttributeCache\\"); const TCHAR c_szDAMNumValue[] = TEXT("CheckNum"); CDispAttrGuidCache *g_pDispAttrGuidCache = NULL; // // from aimm1.2\win32\aimmdap.cpp // /* 503286E2-5D2A-4D3D-B0D1-EE50D843B79D */ const CLSID CLSID_CAImmDAP = { 0x503286E2, 0x5D2A, 0x4D3D, {0xB0, 0xD1, 0xEE, 0x50, 0xD8, 0x43, 0xB7, 0x9D} }; DBG_ID_INSTANCE(CDisplayAttributeMgr); DBG_ID_INSTANCE(CEnumDisplayAttributeInfo); ////////////////////////////////////////////////////////////////////////////// // // CDispAttrGuidCache // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // StaticUnInit // // Caller must hold mutex. //---------------------------------------------------------------------------- void CDispAttrGuidCache::StaticUnInit() { Assert(ISINDLLMAIN()); // for mutex if (g_pDispAttrGuidCache) delete g_pDispAttrGuidCache; g_pDispAttrGuidCache = NULL; } //+--------------------------------------------------------------------------- // // StaticInit // //---------------------------------------------------------------------------- void CDispAttrGuidCache::StaticInit() { CicEnterCriticalSection(g_cs); if (!g_pDispAttrGuidCache) { g_pDispAttrGuidCache = new CDispAttrGuidCache(); if (g_pDispAttrGuidCache) g_pDispAttrGuidCache->Load(); } CicLeaveCriticalSection(g_cs); } //+--------------------------------------------------------------------------- // // Add // //---------------------------------------------------------------------------- BOOL CDispAttrGuidCache::Add(REFCLSID clsid, REFGUID guid) { BOOL bRet = FALSE; TfGuidAtom gaGuid; TfGuidAtom gaClsid; if (FAILED(MyRegisterGUID(clsid, &gaClsid))) return bRet; if (FAILED(MyRegisterGUID(guid, &gaGuid))) return bRet; CicEnterCriticalSection(g_cs); if (!Get(gaGuid, NULL)) { DISPATTRGUID *pGuid; if (!_rgDispAttrGuid.Insert(0, 1)) { goto Exit; } pGuid = _rgDispAttrGuid.GetPtr(0); pGuid->clsid = clsid; pGuid->gaClsid = gaClsid; pGuid->guid = guid; pGuid->gaGuid = gaGuid; } bRet = TRUE; Exit: CicLeaveCriticalSection(g_cs); return bRet; } //+--------------------------------------------------------------------------- // // Remove // //---------------------------------------------------------------------------- void CDispAttrGuidCache::Remove(TfGuidAtom guidatom) { int nCnt = _rgDispAttrGuid.Count(); int i; for (i = 0; i < nCnt; i++) { DISPATTRGUID *pGuid = _rgDispAttrGuid.GetPtr(i); if (pGuid->gaGuid == guidatom) { _rgDispAttrGuid.Remove(i, 1); return; } } } //+--------------------------------------------------------------------------- // // RemoveClsid // //---------------------------------------------------------------------------- void CDispAttrGuidCache::RemoveClsid(TfGuidAtom guidatom) { int nCnt = _rgDispAttrGuid.Count(); int i; i = 0; while (i < nCnt) { DISPATTRGUID *pGuid = _rgDispAttrGuid.GetPtr(i); if (pGuid->gaClsid == guidatom) { _rgDispAttrGuid.Remove(i, 1); nCnt--; continue; } i++; } } //+--------------------------------------------------------------------------- // // Get // //---------------------------------------------------------------------------- BOOL CDispAttrGuidCache::Get(TfGuidAtom guidatom, DISPATTRGUID *pDisp) { BOOL bRet; CicEnterCriticalSection(g_cs); bRet = InternalGet(guidatom, pDisp); CicLeaveCriticalSection(g_cs); return bRet; } //+--------------------------------------------------------------------------- // // InternalGet // //---------------------------------------------------------------------------- BOOL CDispAttrGuidCache::InternalGet(TfGuidAtom guidatom, DISPATTRGUID *pDisp) { int nCnt; int i; BOOL bRet = FALSE; nCnt = _rgDispAttrGuid.Count(); DISPATTRGUID *pGuid = _rgDispAttrGuid.GetPtr(0); for (i = 0; i < nCnt; i++) { if (pGuid->gaGuid == guidatom) { if (pDisp) *pDisp = *pGuid; bRet = TRUE; goto Exit; } pGuid++; } Exit: return bRet; } //+--------------------------------------------------------------------------- // // IsClsid // //---------------------------------------------------------------------------- BOOL CDispAttrGuidCache::IsClsid(TfGuidAtom gaClsid) { BOOL bRet = FALSE; int nCnt; int i; DISPATTRGUID *pGuid; CicEnterCriticalSection(g_cs); pGuid = _rgDispAttrGuid.GetPtr(0); nCnt = _rgDispAttrGuid.Count(); for (i = 0; i < nCnt; i++) { if (pGuid->gaClsid == gaClsid) { bRet = TRUE; break; } pGuid++; } CicLeaveCriticalSection(g_cs); return bRet; } //+--------------------------------------------------------------------------- // // Save // //---------------------------------------------------------------------------- HRESULT CDispAttrGuidCache::Save() { DWORD dw; HKEY hKeyDAM; DISPATTRGUID *pDAG; int nCnt; if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szDAMCacheKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyDAM, &dw) != ERROR_SUCCESS) { return E_FAIL; } nCnt = _rgDispAttrGuid.Count(); if (nCnt) { pDAG = _rgDispAttrGuid.GetPtr(0); RegSetValueEx(hKeyDAM, NULL, 0, REG_BINARY, (CONST BYTE *)pDAG, sizeof(DISPATTRGUID) * nCnt); RegSetValueEx(hKeyDAM, c_szDAMNumValue, 0, REG_DWORD, (LPBYTE)&nCnt, sizeof(DWORD)); } else { RegDeleteValue(hKeyDAM, NULL); RegDeleteValue(hKeyDAM, c_szDAMNumValue); } RegCloseKey(hKeyDAM); return S_OK; } //+--------------------------------------------------------------------------- // // Load // //---------------------------------------------------------------------------- HRESULT CDispAttrGuidCache::Load() { HKEY hKeyDAM; HRESULT hr = E_FAIL; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szDAMCacheKey, 0, KEY_READ, &hKeyDAM) != ERROR_SUCCESS) { return hr; } Assert(_rgDispAttrGuid.Count() == 0); DWORD dwType = REG_DWORD; DWORD dwSize = sizeof(DWORD); DWORD dwCntReg = 0; // // Issue: should be removed before release. // we changed the size of structre so old chace does not match with // new one. Check the size of structure. // if (RegQueryValueEx(hKeyDAM, c_szDAMNumValue, 0, &dwType, (LPBYTE)&dwCntReg, &dwSize) != ERROR_SUCCESS) dwCntReg = 0; dwType = REG_BINARY; if (RegQueryValueEx(hKeyDAM, NULL, 0, &dwType, NULL, &dwSize) == ERROR_SUCCESS) { DWORD i; DWORD dwCnt = dwSize / sizeof(DISPATTRGUID); if (dwCnt != dwCntReg) goto Exit; _rgDispAttrGuid.Insert(0, dwCnt); DISPATTRGUID *pDAG = _rgDispAttrGuid.GetPtr(0); RegQueryValueEx(hKeyDAM, NULL, 0, &dwType, (BYTE *)pDAG, &dwSize); for (i = 0; i < dwCnt; i++) { if (FAILED(MyRegisterGUID(pDAG[i].clsid, &pDAG[i].gaClsid))) goto Exit; if (FAILED(MyRegisterGUID(pDAG[i].guid, &pDAG[i].gaGuid))) goto Exit; } } hr = S_OK; Exit: RegCloseKey(hKeyDAM); return hr; } ////////////////////////////////////////////////////////////////////////////// // // CDisplayAttributeMgr // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CDisplayAttributeMgr::CDisplayAttributeMgr() { Dbg_MemSetThisNameID(TEXT("CDisplayAttributeMgr")); _SetThis(this); } //+--------------------------------------------------------------------------- // // dtor // //---------------------------------------------------------------------------- CDisplayAttributeMgr::~CDisplayAttributeMgr() { int nCnt = _rgDaPrv.Count(); if (nCnt) { DAPROVIDERMAP *pDaPrv; pDaPrv = _rgDaPrv.GetPtr(0); while(nCnt--) { pDaPrv->pPrv->Release(); pDaPrv++; } } _SetThis(NULL); // clear out singleton tls } //---------------------------------------------------------------------------- // // OnUndateinfo // // Use kernel32 or ntdll directly to enumerate all threads, because // we don't have global TIM list. // //---------------------------------------------------------------------------- HRESULT CDisplayAttributeMgr::OnUpdateInfo() { PostTimListMessage(TLF_TIMACTIVE, 0, g_msgPrivate, TFPRIV_UPDATEDISPATTR, 0); return S_OK; } //---------------------------------------------------------------------------- // // EnumThreadProc // //---------------------------------------------------------------------------- BOOL CDisplayAttributeMgr::EnumThreadProc(DWORD dwThread, DWORD dwProcessId, void *pv) { PostThreadMessage(dwThread, g_msgPrivate, TFPRIV_UPDATEDISPATTR, 0); return FALSE; } //---------------------------------------------------------------------------- // // EnumDisplayAttributeInfo // //---------------------------------------------------------------------------- HRESULT CDisplayAttributeMgr::EnumDisplayAttributeInfo(IEnumTfDisplayAttributeInfo **ppEnum) { CEnumDisplayAttributeInfo *pEnum; if (!ppEnum) return E_INVALIDARG; pEnum = new CEnumDisplayAttributeInfo(); if (!pEnum) return E_OUTOFMEMORY; if (pEnum->Init()) *ppEnum = pEnum; else SafeReleaseClear(pEnum); return pEnum ? S_OK : E_FAIL; } //---------------------------------------------------------------------------- // // GetDisplayAttributeInfo // //---------------------------------------------------------------------------- HRESULT CDisplayAttributeMgr::GetDisplayAttributeInfo(REFGUID guid, ITfDisplayAttributeInfo **ppInfo, CLSID *pclsid) { CLSID clsid; ITfDisplayAttributeProvider *pProvider; HRESULT hr = E_FAIL; StaticCacheInit(); if (ppInfo) *ppInfo = NULL; if (g_pDispAttrGuidCache) { DISPATTRGUID dag; TfGuidAtom gaGuid; if (FAILED(MyRegisterGUID(guid, &gaGuid))) return hr; if (g_pDispAttrGuidCache->Get(gaGuid, &dag)) { if (ppInfo) { DAPROVIDERMAP *pDaPrv; int i; int nCnt = _rgDaPrv.Count(); BOOL bFound = FALSE; for (i = 0; i < nCnt; i++) { pDaPrv = _rgDaPrv.GetPtr(i); if (pDaPrv->gaClsid == dag.gaClsid) { Assert(pDaPrv->pPrv); hr = pDaPrv->pPrv->GetDisplayAttributeInfo(guid, ppInfo); bFound = TRUE; break; } } if (!bFound && SUCCEEDED(CoCreateInstance(dag.clsid, NULL, CLSCTX_INPROC_SERVER, IID_ITfDisplayAttributeProvider, (void**)&pProvider))) { hr = pProvider->GetDisplayAttributeInfo(guid, ppInfo); if (_rgDaPrv.Insert(nCnt, 1)) { pDaPrv = _rgDaPrv.GetPtr(nCnt); pDaPrv->gaClsid = dag.gaClsid; pDaPrv->pPrv = pProvider; } else pProvider->Release(); } } else { hr = S_OK; } if (SUCCEEDED(hr)) { if (pclsid) *pclsid = dag.clsid; return hr; } // // someone removed DisplayAttribute Info. So we clear the cache. // g_pDispAttrGuidCache->Clear(); } } IEnumGUID *pEnumGUID; if (FAILED(MyEnumItemsInCategory(GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &pEnumGUID))) return E_FAIL; DWORD dwIndex = 0; BOOL fFound = FALSE; CThreadInputMgr *ptim = CThreadInputMgr::_GetThis(); if (ptim == NULL) goto Exit; while (!fFound && (pEnumGUID->Next(1, &clsid, NULL) == S_OK)) { if (!IsEqualCLSID(clsid, CLSID_CAImmDAP) && (ptim->_IsActiveInputProcessor(clsid) != S_OK)) continue; // // Issue: // // we may want to load only providers that are enabled in this // thread. Use CIMEList to check if tips is enabled. // if (SUCCEEDED(CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_ITfDisplayAttributeProvider, (void**)&pProvider))) { IEnumTfDisplayAttributeInfo *pEnumDAI; if (SUCCEEDED(pProvider->EnumDisplayAttributeInfo(&pEnumDAI))) { ITfDisplayAttributeInfo *pInfo; while (pEnumDAI->Next(1, &pInfo, NULL) == S_OK) { GUID guidTemp; if (SUCCEEDED(pInfo->GetGUID(&guidTemp))) { if (g_pDispAttrGuidCache) g_pDispAttrGuidCache->Add(clsid, guidTemp); if (IsEqualGUID(guidTemp, guid)) { if (ppInfo) *ppInfo = pInfo; if (pclsid) *pclsid = clsid; fFound = TRUE; hr = S_OK; break; } } pInfo->Release(); } pEnumDAI->Release(); } pProvider->Release(); } } Exit: pEnumGUID->Release(); if (g_pDispAttrGuidCache) g_pDispAttrGuidCache->Save(); return hr; } //---------------------------------------------------------------------------- // // RegisterGUID // //---------------------------------------------------------------------------- HRESULT CDisplayAttributeMgr::_RegisterGUID(const TCHAR *pszKey, REFGUID rguid, WCHAR *pszDesc, ULONG cchDesc) { DWORD dw; HKEY hKeyDAM; HKEY hKeyItem; TCHAR achGuid[CLSID_STRLEN+1]; if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyDAM, &dw) != ERROR_SUCCESS) { return E_FAIL; } CLSIDToStringA(rguid, achGuid); if (RegCreateKeyEx(hKeyDAM, achGuid, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyItem, &dw) == ERROR_SUCCESS) { int cchDescA = cchDesc * sizeof(WCHAR) + 1; char *pszDescA = new char[cchDescA]; if (pszDescA) { cchDescA = WideCharToMultiByte(CP_ACP, 0, pszDesc, wcslen(pszDesc), pszDescA, cchDescA, NULL, NULL); *(pszDescA + cchDescA) = L'\0'; RegSetValueEx(hKeyItem, TEXT("Description"), 0, REG_SZ, (CONST BYTE *)pszDescA, cchDescA); delete pszDescA; } RegCloseKey(hKeyItem); } RegCloseKey(hKeyDAM); return S_OK; } //---------------------------------------------------------------------------- // // UnregisterGUID // //---------------------------------------------------------------------------- HRESULT CDisplayAttributeMgr::_UnregisterGUID(const TCHAR *pszKey, REFGUID rguid) { DWORD dw; HKEY hKeyDAM; TCHAR achGuid[CLSID_STRLEN+1]; if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyDAM, &dw) != ERROR_SUCCESS) { return E_FAIL; } CLSIDToStringA(rguid, achGuid); RegDeleteKey(hKeyDAM, achGuid); RegCloseKey(hKeyDAM); return S_OK; } ////////////////////////////////////////////////////////////////////////////// // // CEnumDisplayAttributeInfo // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CEnumDisplayAttributeInfo::CEnumDisplayAttributeInfo() { Dbg_MemSetThisNameID(TEXT("CEnumDisplayAttributeInfo")); } //+--------------------------------------------------------------------------- // // Init // //---------------------------------------------------------------------------- BOOL CEnumDisplayAttributeInfo::Init() { IEnumGUID *pEnumGUID; CLSID clsid; ULONG uDAMax; BOOL fRet; StaticCacheInit(); if (FAILED(MyEnumItemsInCategory(GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &pEnumGUID))) return FALSE; fRet = FALSE; if ((_prgUnk = SUA_Alloc(1)) == NULL) goto Exit; _prgUnk->cRef = 1; _prgUnk->cUnk = 0; uDAMax = 1; while (pEnumGUID->Next(1, &clsid, NULL) == S_OK) { ITfDisplayAttributeProvider *pProvider; // // Issue: // // we may want to load only providers that are enabled in this // thread. Use CIMEList to check if tips is enabled. // if (SUCCEEDED(CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_ITfDisplayAttributeProvider, (void**)&pProvider))) { IEnumTfDisplayAttributeInfo *pEnum; if (SUCCEEDED(pProvider->EnumDisplayAttributeInfo(&pEnum))) { ITfDisplayAttributeInfo *pInfo; while (pEnum->Next(1, &pInfo, NULL) == S_OK) { GUID guidTemp; if (SUCCEEDED(pInfo->GetGUID(&guidTemp))) { if (g_pDispAttrGuidCache) g_pDispAttrGuidCache->Add(clsid, guidTemp); } if (_prgUnk->cUnk >= uDAMax) { // need a bigger array uDAMax *= 2; if (!SUA_ReAlloc(&_prgUnk, uDAMax)) { pInfo->Release(); SUA_Release(_prgUnk); _prgUnk = NULL; goto Exit; } } _prgUnk->rgUnk[_prgUnk->cUnk++] = pInfo; } pEnum->Release(); } pProvider->Release(); } } if (uDAMax > _prgUnk->cUnk) { // free up unused mem SUA_ReAlloc(&_prgUnk, _prgUnk->cUnk); } fRet = TRUE; Exit: pEnumGUID->Release(); if (g_pDispAttrGuidCache) g_pDispAttrGuidCache->Save(); return fRet; }