// // imecls.cpp // #include "private.h" #include "imecls.h" DBG_ID_INSTANCE(CSysImeClassWnd); DBG_ID_INSTANCE(CSysImeClassWndArray); #define IMECLASSNAME TEXT("ime") ////////////////////////////////////////////////////////////////////////////// // // misc func // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // CheckExistingImeClassWnd // //---------------------------------------------------------------------------- BOOL CheckExistingImeClassWnd(SYSTHREAD *psfn) { #ifdef USE_IMECLASS_SUBCLASS if (!psfn->prgImeClassWnd) { HWND hwnd = NULL; DWORD dwCurThreadId = GetCurrentThreadId(); while (hwnd = FindWindowEx(NULL, hwnd, IMECLASSNAME, NULL)) { DWORD dwThreadId = GetWindowThreadProcessId(hwnd, NULL); if (dwThreadId != dwCurThreadId) continue; CSysImeClassWnd *picw = new CSysImeClassWnd(); picw->Init(hwnd); } } if (!psfn->prgImeClassWnd) return TRUE; if (GetFocus()) psfn->prgImeClassWnd->StartSubclass(); #endif return TRUE; } //+--------------------------------------------------------------------------- // // UninitImeClassWndOnProcess // //---------------------------------------------------------------------------- BOOL UninitImeClassWndOnProcess() { HWND hwnd = NULL; DWORD dwCurProcessId = GetCurrentProcessId(); while (hwnd = FindWindowEx(NULL, hwnd, IMECLASSNAME, NULL)) { DWORD dwProcessId; DWORD dwThreadId = GetWindowThreadProcessId(hwnd, &dwProcessId); if (dwProcessId != dwCurProcessId) continue; // // Set the wndproc pointer back to original WndProc. // // some other subclass window may keep my WndProc pointer. // but msctf.dll may be unloaded from memory so we don't want to // call him to set the wndproc pointer back to our Wndproc pointer. // The pointer will be bogus. // WNDPROC pfn = (WNDPROC)GetClassLongPtr(hwnd, GCLP_WNDPROC); if (pfn != (WNDPROC)GetWindowLongPtr(hwnd, GWLP_WNDPROC)) SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)pfn); } return TRUE; } ////////////////////////////////////////////////////////////////////////////// // // CSysImeClassWnd // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CSysImeClassWnd::CSysImeClassWnd() { Dbg_MemSetThisNameID(TEXT("CSysImeClassWnd")); } //+--------------------------------------------------------------------------- // // dtor // //---------------------------------------------------------------------------- CSysImeClassWnd::~CSysImeClassWnd() { if (IsWindow(_hwnd)) { Stop(); if (_pfn) { // // Set the wndproc pointer back to original WndProc. // // some other subclass window may keep my WndProc pointer. // but msctf.dll may be unloaded from memory so we don't want to // call him to set the wndproc pointer back to our Wndproc pointer. // The pointer will be bogus. // WNDPROC pfnOrgImeWndProc; pfnOrgImeWndProc = (WNDPROC)GetClassLongPtr(_hwnd, GCLP_WNDPROC); SetWindowLongPtr(_hwnd, GWLP_WNDPROC, (LONG_PTR)pfnOrgImeWndProc); _pfn = NULL; } } } //+--------------------------------------------------------------------------- // // IsImeClassWnd // //---------------------------------------------------------------------------- BOOL CSysImeClassWnd::IsImeClassWnd(HWND hwnd) { char szCls[6]; if (!GetClassName(hwnd, szCls, sizeof(szCls))) return FALSE; return lstrcmpi(szCls, IMECLASSNAME) ? FALSE : TRUE; } //+--------------------------------------------------------------------------- // // Init // //---------------------------------------------------------------------------- BOOL CSysImeClassWnd::Init(HWND hwnd) { SYSTHREAD *psfn = GetSYSTHREAD(); if (psfn == NULL) return FALSE; if (!psfn->prgImeClassWnd) { psfn->prgImeClassWnd = new CSysImeClassWndArray(); if (!psfn->prgImeClassWnd) return FALSE; } CSysImeClassWnd **ppicw = psfn->prgImeClassWnd->Append(1); if (!ppicw) return FALSE; *ppicw = this; _hwnd = hwnd; _pfn = NULL; return TRUE; } //+--------------------------------------------------------------------------- // // Start // //---------------------------------------------------------------------------- void CSysImeClassWnd::Start() { Assert(IsWindow(_hwnd)); if (_pfn) return; _pfn = (WNDPROC)SetWindowLongPtr(_hwnd, GWLP_WNDPROC, (LONG_PTR)WndProc); } //+--------------------------------------------------------------------------- // // Stop // //---------------------------------------------------------------------------- void CSysImeClassWnd::Stop() { Assert(IsWindow(_hwnd)); WNDPROC pfnCur; if (!_pfn) return; // // unfortunately, we can not restore the wndproc pointer always. // someone else subclassed it after we did. // pfnCur = (WNDPROC)GetWindowLongPtr(_hwnd, GWLP_WNDPROC); if (pfnCur == WndProc) { SetWindowLongPtr(_hwnd, GWLP_WNDPROC, (LONG_PTR)_pfn); _pfn = NULL; } } //+--------------------------------------------------------------------------- // // WndProc // //---------------------------------------------------------------------------- LRESULT CSysImeClassWnd::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lRet; SYSTHREAD *psfn = GetSYSTHREAD(); if (!psfn || !psfn->prgImeClassWnd) { Assert(0); return 0; } CSysImeClassWnd *_this = psfn->prgImeClassWnd->Find(hwnd); if (!_this) { #ifdef DEBUG if ((uMsg != WM_DESTROY) && (uMsg != WM_NCDESTROY)) { Assert(0); } #endif return 0; } WNDPROC pfn = _this->_pfn; if (!pfn) { Assert(0); return 0; } switch (uMsg) { #if 0 // // we have a fall back logic to set the original window proc back // if we can not restore the window proc correctly. // so we don't have to do paranoid subclassing here. // case WM_IME_SELECT: case WM_IME_SETCONTEXT: _this->Stop(); lRet = CallWindowProc(pfn, hwnd, uMsg, wParam, lParam); _this->Start(); return lRet; #endif case WM_IME_NOTIFY: if ((wParam == IMN_SETOPENSTATUS) || (wParam == IMN_SETCONVERSIONMODE)) OnIMENotify(); break; case WM_DESTROY: lRet = CallWindowProc(pfn, hwnd, uMsg, wParam, lParam); psfn->prgImeClassWnd->Remove(_this); return lRet; } return CallWindowProc(pfn, hwnd, uMsg, wParam, lParam); } ////////////////////////////////////////////////////////////////////////////// // // CSysImeClassWndArray // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CSysImeClassWndArray::CSysImeClassWndArray() { Dbg_MemSetThisNameID(TEXT("CSysImeClassWndArray")); } //+--------------------------------------------------------------------------- // // StartSubClass // //---------------------------------------------------------------------------- BOOL CSysImeClassWndArray::StartSubclass() { for (int i = 0; i < Count(); i++) { CSysImeClassWnd *picw = Get(i); picw->Start(); } return TRUE; } //+--------------------------------------------------------------------------- // // StopSubClass // //---------------------------------------------------------------------------- BOOL CSysImeClassWndArray::StopSubclass() { for (int i = 0; i < Count(); i++) { CSysImeClassWnd *picw = Get(i); picw->Stop(); } return TRUE; } //+--------------------------------------------------------------------------- // // Find // //---------------------------------------------------------------------------- CSysImeClassWnd *CSysImeClassWndArray::Find(HWND hwnd) { for (int i = 0; i < Count(); i++) { CSysImeClassWnd *picw = Get(i); if (picw->GetWnd() == hwnd) return picw; } return NULL; } //+--------------------------------------------------------------------------- // // Remove // //---------------------------------------------------------------------------- void CSysImeClassWndArray::Remove(CSysImeClassWnd *picw) { for (int i = 0; i < Count(); i++) { if (picw == Get(i)) { CPtrArray::Remove(i, 1); delete picw; break; } } } //+--------------------------------------------------------------------------- // // RemoveAll // //---------------------------------------------------------------------------- void CSysImeClassWndArray::RemoveAll() { for (int i = 0; i < Count(); i++) { CSysImeClassWnd *picw = Get(i); delete picw; } Clear(); }