3525 lines
101 KiB
C++
3525 lines
101 KiB
C++
//
|
|
// default.cpp
|
|
//
|
|
|
|
#include "private.h"
|
|
#include "globals.h"
|
|
#include "imelist.h"
|
|
#include "tim.h"
|
|
#include "nuimgr.h"
|
|
#include "nuihkl.h"
|
|
#include "nuictrl.h"
|
|
#include "catmgr.h"
|
|
#include "imelist.h"
|
|
#include "ptrary.h"
|
|
#include "ic.h"
|
|
#include "assembly.h"
|
|
#include "profiles.h"
|
|
#include "imelist.h"
|
|
#include "ithdmshl.h"
|
|
#include "marshal.h"
|
|
#include "mstub.h"
|
|
#include "smblock.h"
|
|
#include "timlist.h"
|
|
#include "thdutil.h"
|
|
#include "utb.h"
|
|
#include "mui.h"
|
|
#include "hotkey.h"
|
|
#include "profiles.h"
|
|
#include "lbaddin.h"
|
|
#include "cregkey.h"
|
|
|
|
CPtrArray<SYSTHREAD> *g_rgSysThread = NULL;
|
|
|
|
BOOL IsConsoleWindow(HWND hWnd);
|
|
void InitThreadHook(DWORD dwThreadId);
|
|
void UninitThreadHooks(SYSTHREAD *psfn);
|
|
void DestroyMarshalWindow(SYSTHREAD* psfn, HWND hwnd);
|
|
UINT _CBTHook(int nCode, WPARAM wParam, LPARAM lParam);
|
|
UINT _ShellProc(int nCode, WPARAM wParam, LPARAM lParam);
|
|
UINT _GetMsgHook(WPARAM wParam, LPARAM lParam);
|
|
UINT _KeyboardHook(WPARAM wParam, LPARAM lParam);
|
|
|
|
// crazy workaround for a system bug
|
|
// sometimes our hook procs will be called after
|
|
// we are detached. By this time we've unmapped
|
|
// our shared memory, so keep around a local copy.
|
|
static HHOOK s_hSysShellHook = 0;
|
|
|
|
static HHOOK s_hSysGetMsgHook = 0;
|
|
static HHOOK s_hSysCBTHook = 0;
|
|
|
|
// handling old input CPL
|
|
static BOOL g_fLoadedCPLName = FALSE;
|
|
static BOOL g_fCHWin9x = FALSE;
|
|
static BOOL g_fCHNT4 = FALSE;
|
|
|
|
TCHAR g_szKbdCPLName[128];
|
|
TCHAR g_szKbdCPLTitle[128];
|
|
TCHAR g_szWinCHCPLName[128];
|
|
TCHAR g_szWinCHCPLTitle[128];
|
|
TCHAR g_szNTCPLName[128];
|
|
TCHAR g_szNTCPLTitle[128];
|
|
TCHAR g_szOldCPLMsg[256];
|
|
TCHAR g_szCPLButton[128];
|
|
TCHAR g_szCPLGroupBox[128];
|
|
TCHAR g_szCHNT4CPLName[128];
|
|
TCHAR g_szCHNT4CPLTitle1[128];
|
|
TCHAR g_szCHNT4CPLTitle2[128];
|
|
TCHAR g_szCH9xKbdCPLTitle[128];
|
|
|
|
const CHAR c_szIntlCPLFetchClass[] = "IntlNewInputLocaleWndlClass";
|
|
|
|
// CPL window name and input locale tab title name RC ids
|
|
#define NTCPLNAMEID 1
|
|
#define NTCPLTITLEID 107
|
|
#define WINCPLNAMEID 102
|
|
//#define WINCPLTITLEID 42
|
|
#define WINCPLTITLEID 104
|
|
#define WINCPLCHNAMEID 112
|
|
#define WINCPLCHTITLEID 107
|
|
#define CHNT4CPLNAMEID 64
|
|
#define CHNT4CPLTITLEID1 1
|
|
#define CHNT4CPLTITLEID2 2
|
|
|
|
// CPL file names
|
|
#define MAINCPL TEXT("main.cpl")
|
|
#define INTLCPL TEXT("intl.cpl")
|
|
#define CHIMECPL TEXT("cime.cpl")
|
|
|
|
inline int SafeGetWindowText(HWND hWnd, LPTSTR szString, int nMaxCount)
|
|
{
|
|
int iRet;
|
|
|
|
iRet = GetWindowText(hWnd, szString, nMaxCount);
|
|
if (nMaxCount > 0)
|
|
{
|
|
// make sure the string is NULL terminated
|
|
// we're not supposed to have to do this, but we're seeing a bug
|
|
// where GetWindowText won't NULL terminate the string if it
|
|
// occupies the whole buffer.
|
|
if (iRet < nMaxCount && iRet >= 0)
|
|
{
|
|
szString[iRet] = 0;
|
|
}
|
|
else
|
|
{
|
|
szString[nMaxCount-1] = 0;
|
|
}
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InitStaticHooks
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void InitStaticHooks()
|
|
{
|
|
Assert(GetSharedMemory() != NULL);
|
|
|
|
#if 1
|
|
if (GetSharedMemory() == NULL && ! IsSharedMemoryCreated())
|
|
{
|
|
// Shared memory already closed.
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
s_hSysShellHook = GetSharedMemory()->hSysShellHook.GetHandle(g_bOnWow64);
|
|
|
|
s_hSysGetMsgHook = GetSharedMemory()->hSysGetMsgHook.GetHandle(g_bOnWow64);
|
|
s_hSysCBTHook = GetSharedMemory()->hSysCBTHook.GetHandle(g_bOnWow64);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// FindSYSTHREAD
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
SYSTHREAD *FindSYSTHREAD()
|
|
{
|
|
SYSTHREAD *psfn;
|
|
|
|
if (g_dwTLSIndex == (DWORD)-1)
|
|
return NULL;
|
|
|
|
psfn = (SYSTHREAD *)TlsGetValue(g_dwTLSIndex);
|
|
|
|
return psfn;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetSYSTHREAD
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
SYSTHREAD *GetSYSTHREAD()
|
|
{
|
|
SYSTHREAD *psfn;
|
|
|
|
if (g_dwTLSIndex == (DWORD)-1)
|
|
return NULL;
|
|
|
|
psfn = (SYSTHREAD *)TlsGetValue(g_dwTLSIndex);
|
|
|
|
if (!psfn)
|
|
{
|
|
//
|
|
// we don't allocate psfn after detached.
|
|
//
|
|
if (g_fDllProcessDetached)
|
|
return NULL;
|
|
|
|
psfn = (SYSTHREAD *)cicMemAllocClear(sizeof(SYSTHREAD));
|
|
if (!TlsSetValue(g_dwTLSIndex, psfn))
|
|
{
|
|
cicMemFree(psfn);
|
|
psfn = NULL;
|
|
}
|
|
|
|
if (psfn)
|
|
{
|
|
psfn->dwThreadId = GetCurrentThreadId();
|
|
psfn->dwProcessId = GetCurrentProcessId();
|
|
|
|
CicEnterCriticalSection(g_csInDllMain);
|
|
|
|
if (!g_rgSysThread)
|
|
g_rgSysThread = new CPtrArray<SYSTHREAD>;
|
|
|
|
if (g_rgSysThread)
|
|
{
|
|
if (g_rgSysThread->Insert(0, 1))
|
|
g_rgSysThread->Set(0, psfn);
|
|
}
|
|
|
|
CicLeaveCriticalSection(g_csInDllMain);
|
|
|
|
//
|
|
// init nModalLangBarId
|
|
//
|
|
psfn->nModalLangBarId = -1;
|
|
EnsureTIMList(psfn);
|
|
}
|
|
}
|
|
|
|
return psfn;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// FreeSYSTHREAD2
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void FreeSYSTHREAD2(SYSTHREAD *psfn)
|
|
{
|
|
Assert(psfn); // it's caller's responsibility to pass in a valid psfn
|
|
Assert(psfn->ptim == NULL); // someone leaked us?
|
|
Assert(psfn->pipp == NULL); // someone leaked us?
|
|
Assert(psfn->pdam == NULL); // someone leaked us?
|
|
|
|
UninitThreadHooks(psfn);
|
|
|
|
UninitLangBarAddIns(psfn);
|
|
delete psfn->_pGlobalCompMgr;
|
|
psfn->_pGlobalCompMgr = NULL;
|
|
|
|
if (psfn->plbim)
|
|
{
|
|
psfn->plbim->_RemoveSystemItems(psfn);
|
|
}
|
|
|
|
FreeMarshaledStubs(psfn);
|
|
|
|
if (psfn->plbim)
|
|
{
|
|
TraceMsg(TF_GENERAL, "FreeSYSTHREAD2 clean up plbim");
|
|
//
|
|
// Clean up a pointer that is marshalled to UTB.
|
|
//
|
|
delete psfn->plbim;
|
|
psfn->plbim = NULL;
|
|
}
|
|
|
|
if (psfn->ptim)
|
|
psfn->ptim->ClearLangBarItemMgr();
|
|
|
|
CicEnterCriticalSection(g_csInDllMain);
|
|
|
|
if (g_rgSysThread)
|
|
{
|
|
int nCnt = g_rgSysThread->Count();
|
|
while (nCnt)
|
|
{
|
|
nCnt--;
|
|
if (g_rgSysThread->Get(nCnt) == psfn)
|
|
{
|
|
g_rgSysThread->Remove(nCnt, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CicLeaveCriticalSection(g_csInDllMain);
|
|
|
|
if (psfn->pAsmList)
|
|
{
|
|
delete psfn->pAsmList;
|
|
psfn->pAsmList = NULL;
|
|
}
|
|
|
|
//
|
|
// remove the timlist entry for the current thread.
|
|
//
|
|
psfn->pti = NULL;
|
|
g_timlist.RemoveThread(psfn->dwThreadId);
|
|
|
|
DestroySharedHeap(psfn);
|
|
DestroySharedBlocks(psfn);
|
|
|
|
cicMemFree(psfn);
|
|
}
|
|
|
|
void FreeSYSTHREAD()
|
|
{
|
|
SYSTHREAD *psfn = (SYSTHREAD *)TlsGetValue(g_dwTLSIndex);
|
|
if (psfn)
|
|
{
|
|
//
|
|
// don't call ClearLangBarAddIns in FreeSYSTHREAD2.
|
|
// it is not safe to call this in DllMain(PROCESS_DETACH).
|
|
//
|
|
ClearLangBarAddIns(psfn, CLSID_NULL);
|
|
|
|
FreeSYSTHREAD2(psfn);
|
|
TlsSetValue(g_dwTLSIndex, NULL);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// EnsureAssemblyList
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
CAssemblyList *EnsureAssemblyList(SYSTHREAD *psfn, BOOL fUpdate)
|
|
{
|
|
if (!fUpdate && psfn->pAsmList)
|
|
return psfn->pAsmList;
|
|
|
|
if (!psfn->pAsmList)
|
|
psfn->pAsmList = new CAssemblyList;
|
|
|
|
if (psfn->pAsmList)
|
|
{
|
|
psfn->pAsmList->Load();
|
|
|
|
UpdateSystemLangBarItems(psfn, NULL, TRUE);
|
|
|
|
if (psfn->plbim && psfn->plbim->_GetLBarItemCtrl())
|
|
psfn->plbim->_GetLBarItemCtrl()->_AsmListUpdated(TRUE);
|
|
|
|
}
|
|
|
|
return psfn->pAsmList;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UpdateRegIMXHandler()
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void UpdateRegIMXHandler()
|
|
{
|
|
SYSTHREAD *psfn = GetSYSTHREAD();
|
|
|
|
//
|
|
// clear Category cache
|
|
//
|
|
CCategoryMgr::FreeCatCache();
|
|
|
|
TF_InitMlngInfo();
|
|
|
|
//
|
|
// Update Assembly list
|
|
//
|
|
if (psfn && psfn->pAsmList)
|
|
{
|
|
EnsureAssemblyList(psfn, TRUE);
|
|
|
|
if (!psfn->pAsmList->FindAssemblyByLangId(GetCurrentAssemblyLangId(psfn)))
|
|
{
|
|
CAssembly *pAsm = psfn->pAsmList->GetAssembly(0);
|
|
if (pAsm)
|
|
ActivateAssembly(pAsm->GetLangId(), ACTASM_NONE);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetCurrentAssemblyLangid
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
LANGID GetCurrentAssemblyLangId(SYSTHREAD *psfn)
|
|
{
|
|
if (!psfn)
|
|
{
|
|
psfn = GetSYSTHREAD();
|
|
if (!psfn)
|
|
return 0;
|
|
}
|
|
|
|
if (!psfn->langidCurrent)
|
|
{
|
|
HKL hKL = GetKeyboardLayout(NULL);
|
|
psfn->langidPrev = psfn->langidCurrent;
|
|
psfn->langidCurrent = LANGIDFROMHKL(hKL);
|
|
}
|
|
|
|
return psfn->langidCurrent;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetCurrentAssemblyLangid
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void SetCurrentAssemblyLangId(SYSTHREAD *psfn, LANGID langid)
|
|
{
|
|
psfn->langidPrev = psfn->langidCurrent;
|
|
psfn->langidCurrent = langid;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CheckVisibleWindowEnumProc
|
|
//
|
|
// find any other visible window in the thread.
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
typedef struct tag_CHECKVISIBLEWND {
|
|
BOOL fVisibleFound;
|
|
HWND hwndBeingDestroyed;
|
|
HWND hwndMarshal;
|
|
} CHECKVISIBLEWND;
|
|
|
|
BOOL CheckVisibleWindowEnumProc(HWND hwnd, LPARAM lParam)
|
|
{
|
|
CHECKVISIBLEWND *pcmw = (CHECKVISIBLEWND *)lParam;
|
|
LONG_PTR style;
|
|
|
|
//
|
|
// skip itself.
|
|
//
|
|
if (pcmw->hwndMarshal == hwnd)
|
|
return TRUE;
|
|
|
|
//
|
|
// skip one being destroyed.
|
|
//
|
|
if (pcmw->hwndBeingDestroyed == hwnd)
|
|
return TRUE;
|
|
|
|
//
|
|
// skip IME windows.
|
|
//
|
|
style = GetClassLongPtr(hwnd, GCL_STYLE);
|
|
if (style & CS_IME)
|
|
return TRUE;
|
|
|
|
//
|
|
// skip disable windows if it is not NT4.
|
|
//
|
|
// we disabled code on NT4 because mashaling window is not in HWND_MSG.
|
|
//
|
|
if (IsOnNT5())
|
|
{
|
|
style = GetWindowLongPtr(hwnd, GWL_STYLE);
|
|
if (style & WS_DISABLED)
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// skip in visible windows.
|
|
//
|
|
if (!IsWindowVisible(hwnd))
|
|
return TRUE;
|
|
|
|
//
|
|
// skip in destroy windows.
|
|
//
|
|
|
|
// #624872
|
|
// This is private user32 function.
|
|
// Due to dead lock of LdrpLoaderLock, we don't use delay load.
|
|
if (IsWindowInDestroy(hwnd))
|
|
return TRUE;
|
|
|
|
//
|
|
// ok, we found visible window and stop enumerating.
|
|
//
|
|
pcmw->fVisibleFound = TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef CUAS_ENABLE
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CheckNoWindowEnumProc
|
|
//
|
|
// find any other window in the thread.
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
typedef struct tag_CHECKNOWND {
|
|
BOOL fWindowFound;
|
|
HWND hwndBeingDestroyed;
|
|
} CHECKNOWND;
|
|
|
|
BOOL CheckNoWindowEnumProc(HWND hwnd, LPARAM lParam)
|
|
{
|
|
CHECKNOWND *pcmw = (CHECKNOWND *)lParam;
|
|
|
|
//
|
|
// skip one being destroyed.
|
|
//
|
|
if (pcmw->hwndBeingDestroyed == hwnd)
|
|
return TRUE;
|
|
|
|
//
|
|
// ok, we found window and stop enumerating.
|
|
//
|
|
pcmw->fWindowFound = TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
#endif // CUAS_ENABLE
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsConsoleWindow
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
#define CONSOLE_WINDOW_CLASS TEXT("ConsoleWindowClass")
|
|
|
|
BOOL IsConsoleWindow(HWND hWnd)
|
|
{
|
|
if (IsOnNT())
|
|
{
|
|
int n;
|
|
char szClass[33];
|
|
|
|
n = GetClassName(hWnd, szClass, sizeof(szClass)-1);
|
|
|
|
szClass[n] = TEXT('\0');
|
|
|
|
if (lstrcmp(szClass, CONSOLE_WINDOW_CLASS) == 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Input_EnumChildWndProc
|
|
//
|
|
// disable all controls that is in legacy keyboard property page.
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL CALLBACK Input_EnumChildWndProc(HWND hwnd, LPARAM lParam)
|
|
{
|
|
|
|
EnableWindow(hwnd, FALSE);
|
|
ShowWindow(hwnd, SW_HIDE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IntlCPLFetchWndProc
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
LRESULT CALLBACK IntlCPLFetchWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case (WM_CREATE) :
|
|
{
|
|
HWND hwndStatic;
|
|
HWND hwndButton;
|
|
HWND hwndGroup;
|
|
RECT rc;
|
|
HFONT hFont;
|
|
|
|
GetWindowRect(hwnd, &rc);
|
|
|
|
hwndGroup = CreateWindow(TEXT("button"), g_szCPLGroupBox,
|
|
WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
|
|
0, 0, 0, 0,
|
|
hwnd, NULL, g_hInst, NULL
|
|
);
|
|
MoveWindow(hwndGroup, 0, 0, rc.right-rc.left-20, 110, TRUE);
|
|
|
|
hwndStatic = CreateWindow(TEXT("static"), g_szOldCPLMsg,
|
|
WS_CHILD | WS_VISIBLE | SS_LEFT,
|
|
0, 0, 0, 0,
|
|
hwnd, NULL, g_hInst, NULL
|
|
);
|
|
MoveWindow(hwndStatic, 50, 20, rc.right-rc.left-80, 50, TRUE);
|
|
|
|
hwndButton = CreateWindow(TEXT("button"), g_szCPLButton,
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON,
|
|
0, 0, 0, 0,
|
|
hwnd, NULL, g_hInst, NULL
|
|
);
|
|
MoveWindow(hwndButton, 50, 75, 100, 25, TRUE);
|
|
|
|
hFont = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
|
|
|
|
SendMessage(hwndGroup, WM_SETFONT, (WPARAM)hFont, TRUE);
|
|
SendMessage(hwndStatic, WM_SETFONT, (WPARAM)hFont, TRUE);
|
|
SendMessage(hwndButton, WM_SETFONT, (WPARAM)hFont, TRUE);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
case (WM_COMMAND) :
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case ( BN_CLICKED ):
|
|
TF_RunInputCPL();
|
|
|
|
return FALSE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
case (WM_PAINT) :
|
|
{
|
|
HDC hdc;
|
|
HICON hIcon;
|
|
PAINTSTRUCT ps;
|
|
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
|
|
if (hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(ID_ICON_TEXT_SERVICE)))
|
|
{
|
|
DrawIconEx(hdc, 10, 20, hIcon, 32, 32, 0, NULL, DI_NORMAL);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
EndPaint(hwnd, &ps);
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return DefWindowProc(hwnd, message, wParam, lParam);
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CreateCPLFetchWindow
|
|
//
|
|
// Creating the fetch window to bring up the new Text Service cpl.
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void CreateCPLFetchWindow(HWND hwnd)
|
|
{
|
|
RECT rc;
|
|
HWND hwndCPLFetch;
|
|
WNDCLASSEX wndclass;
|
|
|
|
if (!(hwndCPLFetch = FindWindowEx(hwnd, NULL, c_szIntlCPLFetchClass, NULL)))
|
|
{
|
|
EnumChildWindows(hwnd, (WNDENUMPROC)Input_EnumChildWndProc, 0);
|
|
|
|
GetWindowRect(hwnd, &rc);
|
|
|
|
memset(&wndclass, 0, sizeof(wndclass));
|
|
wndclass.cbSize = sizeof(wndclass);
|
|
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
|
|
wndclass.hInstance = g_hInst;
|
|
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wndclass.lpfnWndProc = IntlCPLFetchWndProc;
|
|
wndclass.lpszClassName = c_szIntlCPLFetchClass;
|
|
RegisterClassEx(&wndclass);
|
|
|
|
|
|
hwndCPLFetch = CreateWindowEx(0, c_szIntlCPLFetchClass, "",
|
|
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
|
|
rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
|
|
hwnd, NULL, g_hInst, NULL
|
|
);
|
|
|
|
MoveWindow(hwndCPLFetch, 10, 10, rc.right-rc.left-10, rc.bottom-rc.top-10, TRUE);
|
|
ShowWindow(hwndCPLFetch, SW_SHOW);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Intl_EnumChildWndProc
|
|
//
|
|
// filtering the legacy keyboard property page.
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL CALLBACK Intl_EnumChildWndProc(HWND hwnd, LPARAM lParam)
|
|
{
|
|
TCHAR szWndName[MAX_PATH];
|
|
TCHAR szKbdPage[MAX_PATH];
|
|
|
|
if (GetCurrentThreadId() != GetWindowThreadProcessId(hwnd, NULL))
|
|
return TRUE;
|
|
|
|
SafeGetWindowText(hwnd, szWndName, MAX_PATH);
|
|
|
|
if (*szWndName == TEXT('\0'))
|
|
return TRUE;
|
|
|
|
if (IsOnNT())
|
|
StringCopyArray(szKbdPage, g_szNTCPLTitle);
|
|
else
|
|
{
|
|
LONG_PTR lpWndHandle;
|
|
|
|
if (lstrcmp(szWndName, g_szKbdCPLTitle) == 0)
|
|
return FALSE;
|
|
|
|
//
|
|
// Thunk call isn't good way to load 16bit module from here.
|
|
// So look up the window instance handle to determine keyboard
|
|
// "Language" tab window.
|
|
// This is Win9x specification and we can detect 32bit handle instance
|
|
// from HIWORD value form GWLP_HINSTANCE.
|
|
//
|
|
lpWndHandle = GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
|
|
|
|
if (HIWORD((DWORD) (LONG_PTR) lpWndHandle) != 0)
|
|
return FALSE;
|
|
|
|
StringCopyArray(szKbdPage, g_szKbdCPLTitle);
|
|
}
|
|
|
|
if ((lstrcmp(szWndName, szKbdPage) == 0) ||
|
|
(!IsOnNT() && lstrcmp(szWndName, szKbdPage) != 0))
|
|
{
|
|
CreateCPLFetchWindow(hwnd);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Intl_CH9xIMEEnumChildWndProc
|
|
//
|
|
// filtering the chinese Win9x special IME layout setting cpl.
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL CALLBACK Intl_CH9xIMEEnumChildWndProc(HWND hwnd, LPARAM lParam)
|
|
{
|
|
TCHAR szWndName[MAX_PATH];
|
|
TCHAR szKbdPage[MAX_PATH];
|
|
LONG_PTR lpWndHandle;
|
|
|
|
if (GetCurrentThreadId() != GetWindowThreadProcessId(hwnd, NULL))
|
|
return TRUE;
|
|
|
|
SafeGetWindowText(hwnd, szWndName, MAX_PATH);
|
|
|
|
if (*szWndName == TEXT('\0'))
|
|
return TRUE;
|
|
|
|
if (lstrcmp(szWndName, g_szKbdCPLTitle) == 0)
|
|
return FALSE;
|
|
|
|
//
|
|
// Thunk call isn't good way to load 16bit module from here.
|
|
// So look up the window instance handle to determine keyboard
|
|
// "Language" tab window.
|
|
// This is Win9x specification and we can detect 32bit handle instance
|
|
// from HIWORD value form GWLP_HINSTANCE.
|
|
//
|
|
lpWndHandle = GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
|
|
|
|
//if (HIWORD((DWORD) (LONG_PTR) lpWndHandle) != 0 &&
|
|
// (lstrcmp(szWndName, g_szCH9xKbdCPLTitle) != 0))
|
|
// Need to show up Chinese IME hotkey setting pages
|
|
if (HIWORD((DWORD) (LONG_PTR) lpWndHandle) != 0)
|
|
return FALSE;
|
|
|
|
StringCopyArray(szKbdPage, g_szKbdCPLTitle);
|
|
|
|
if (!IsOnNT() && lstrcmp(szWndName, szKbdPage) != 0)
|
|
{
|
|
CreateCPLFetchWindow(hwnd);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Intl_CHEnumChildWndProc
|
|
//
|
|
// filtering the chinese NT4 special IME layout setting cpl.
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL CALLBACK Intl_CHEnumChildWndProc(HWND hwnd, LPARAM lParam)
|
|
{
|
|
TCHAR szWndName[MAX_PATH];
|
|
|
|
if (GetCurrentThreadId() != GetWindowThreadProcessId(hwnd, NULL))
|
|
return TRUE;
|
|
|
|
SafeGetWindowText(hwnd, szWndName, MAX_PATH);
|
|
|
|
if (*szWndName == TEXT('\0'))
|
|
return TRUE;
|
|
|
|
//if ((lstrcmp(szWndName, g_szCHNT4CPLTitle1) == 0) ||
|
|
// (lstrcmp(szWndName, g_szCHNT4CPLTitle2) == 0))
|
|
// Need to show up Chinese IME hotkey setting pages
|
|
if ((lstrcmp(szWndName, g_szCHNT4CPLTitle1) == 0))
|
|
{
|
|
CreateCPLFetchWindow(hwnd);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetDialogCaptionTitle
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL GetDialogCaptionTitle(HINSTANCE hInst, LPCTSTR lpName, LPTSTR lpTitle, int cchTitleMax)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
HRSRC hrsrc = NULL;
|
|
|
|
hrsrc = FindResourceA(hInst, lpName, RT_DIALOG);
|
|
|
|
if (hrsrc)
|
|
{
|
|
PVOID pTemp;
|
|
DWORD dwCodePage;
|
|
LANGID langRes = 0;
|
|
UINT dwTitleOffset;
|
|
TCHAR szCodePage[10];
|
|
|
|
pTemp = (PVOID)LoadResource(hInst, (HRSRC)hrsrc);
|
|
|
|
if (pTemp == NULL)
|
|
goto Exit;
|
|
|
|
if (*((char *)pTemp) == 1)
|
|
dwTitleOffset = sizeof(DLGTEMPLATEEX) + 4;
|
|
else
|
|
dwTitleOffset = sizeof(DLGTEMPLATE) + 4;
|
|
|
|
langRes = GetPlatformResourceLangID();
|
|
|
|
if (GetLocaleInfo(MAKELCID(langRes, SORT_DEFAULT),
|
|
LOCALE_IDEFAULTANSICODEPAGE,
|
|
szCodePage,
|
|
ARRAYSIZE(szCodePage)))
|
|
{
|
|
szCodePage[ARRAYSIZE(szCodePage)-1] = 0;
|
|
if (!AsciiToNumDec(szCodePage, &dwCodePage))
|
|
{
|
|
dwCodePage = GetACP();
|
|
}
|
|
}
|
|
else
|
|
dwCodePage = GetACP();
|
|
|
|
if (WideCharToMultiByte(dwCodePage, NULL,
|
|
(LPCWSTR)((char *)pTemp + dwTitleOffset), -1,
|
|
lpTitle, cchTitleMax,
|
|
NULL, NULL))
|
|
bRet = TRUE;
|
|
}
|
|
|
|
Exit:
|
|
return bRet;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CheckLegacyInputCPL
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void CheckLegacyInputCPL(HWND hwndFore)
|
|
{
|
|
if (hwndFore && !IsOnNT51())
|
|
{
|
|
TCHAR szWndName[MAX_PATH];
|
|
TCHAR szWndName2[MAX_PATH];
|
|
TCHAR szWndName3[MAX_PATH];
|
|
|
|
//
|
|
// Load legacy keyboard cpl name and tab titles.
|
|
//
|
|
if (!g_fLoadedCPLName)
|
|
{
|
|
HANDLE hrsrc = NULL;
|
|
HINSTANCE hIntlInst = NULL;
|
|
HINSTANCE hMainInst = NULL;
|
|
HINSTANCE hCHIMEInst = NULL;
|
|
|
|
//
|
|
// Get the default CPL input locale Tab title name string
|
|
//
|
|
if (!LoadString(g_hInst, IDS_CPL_WIN9X_KBDCPLTITLE, g_szKbdCPLTitle, sizeof(g_szKbdCPLTitle)))
|
|
StringCopyArray(g_szKbdCPLTitle, TEXT("Speed"));
|
|
|
|
if (!LoadString(g_hInst, IDS_CPL_WINNT_KBDCPLTITLE, g_szNTCPLTitle, sizeof(g_szNTCPLTitle)))
|
|
StringCopyArray(g_szNTCPLTitle, TEXT("Input Locales"));
|
|
|
|
//
|
|
// Load CPL files to read CPL name and titles
|
|
//
|
|
hMainInst = LoadSystemLibraryEx(MAINCPL, NULL, LOAD_LIBRARY_AS_DATAFILE);
|
|
|
|
hIntlInst = LoadSystemLibraryEx(INTLCPL, NULL, LOAD_LIBRARY_AS_DATAFILE);
|
|
|
|
if (!LoadString(hMainInst, WINCPLNAMEID, g_szKbdCPLName, sizeof(g_szKbdCPLName)))
|
|
StringCopyArray(g_szKbdCPLName, TEXT("Keyboard Properties"));
|
|
|
|
if (IsOnNT())
|
|
{
|
|
if (!LoadString(hIntlInst, NTCPLNAMEID, g_szNTCPLName, sizeof(g_szNTCPLName)))
|
|
StringCopyArray(g_szNTCPLName, TEXT("Regional Options"));
|
|
|
|
if (!GetDialogCaptionTitle(hIntlInst, (LPTSTR)(LONG_PTR)NTCPLTITLEID, g_szNTCPLTitle, ARRAYSIZE(g_szNTCPLTitle)))
|
|
StringCopyArray(g_szNTCPLTitle, TEXT("Input Locales"));
|
|
|
|
if (!IsOnNT5())
|
|
{
|
|
switch (GetACP())
|
|
{
|
|
case 936:
|
|
case 950:
|
|
|
|
hCHIMEInst = LoadSystemLibraryEx(CHIMECPL, NULL, LOAD_LIBRARY_AS_DATAFILE);
|
|
|
|
if (!LoadString(hCHIMEInst, CHNT4CPLNAMEID, g_szCHNT4CPLName, sizeof(g_szCHNT4CPLName)))
|
|
*g_szCHNT4CPLName = TEXT('\0');
|
|
|
|
if (!GetDialogCaptionTitle(hCHIMEInst, (LPTSTR)(LONG_PTR)CHNT4CPLTITLEID1, g_szCHNT4CPLTitle1, ARRAYSIZE(g_szCHNT4CPLTitle1)))
|
|
*g_szCHNT4CPLTitle1 = TEXT('\0');
|
|
|
|
if (!GetDialogCaptionTitle(hCHIMEInst, (LPTSTR)(LONG_PTR)CHNT4CPLTITLEID2, g_szCHNT4CPLTitle2, ARRAYSIZE(g_szCHNT4CPLTitle2)))
|
|
*g_szCHNT4CPLTitle2 = TEXT('\0');
|
|
|
|
g_fCHNT4 = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (GetACP())
|
|
{
|
|
case 936:
|
|
case 950:
|
|
if (!LoadString(hMainInst, WINCPLCHNAMEID, g_szWinCHCPLName, sizeof(g_szWinCHCPLName)))
|
|
*g_szWinCHCPLName = TEXT('\0');
|
|
|
|
if (!GetDialogCaptionTitle(hMainInst, (LPTSTR)(LONG_PTR)WINCPLCHTITLEID, g_szCH9xKbdCPLTitle, ARRAYSIZE(g_szCH9xKbdCPLTitle)))
|
|
*g_szCH9xKbdCPLTitle = TEXT('\0');
|
|
|
|
g_fCHWin9x = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (!GetDialogCaptionTitle(hMainInst, (LPTSTR)(LONG_PTR)WINCPLTITLEID, g_szKbdCPLTitle, ARRAYSIZE(g_szKbdCPLTitle)))
|
|
StringCopyArray(g_szKbdCPLTitle, TEXT("Speed"));
|
|
}
|
|
|
|
if (hMainInst)
|
|
FreeLibrary(hMainInst);
|
|
|
|
if (hIntlInst)
|
|
FreeLibrary(hIntlInst);
|
|
|
|
if (hCHIMEInst)
|
|
FreeLibrary(hCHIMEInst);
|
|
|
|
if (!LoadString(g_hInst, IDS_CPL_INPUT_DISABLED, g_szOldCPLMsg, sizeof(g_szOldCPLMsg)))
|
|
StringCopyArray(g_szOldCPLMsg, TEXT("This dialog has been updated. \r\n\r\nPlease use the Text Input Settings applet in the Control Panel."));
|
|
|
|
if (!LoadString(g_hInst, IDS_CPL_INPUT_CHAANGE_BTN, g_szCPLButton, sizeof(g_szCPLButton)))
|
|
StringCopyArray(g_szCPLButton, TEXT("&Change..."));
|
|
|
|
if (!LoadString(g_hInst, IDS_CPL_INPUT_GROUPBOX, g_szCPLGroupBox, sizeof(g_szCPLGroupBox)))
|
|
StringCopyArray(g_szCPLGroupBox, TEXT("Input Languages and Methods"));
|
|
|
|
g_fLoadedCPLName = TRUE;
|
|
}
|
|
|
|
if (GetCurrentThreadId() != GetWindowThreadProcessId(hwndFore, NULL))
|
|
return;
|
|
|
|
SafeGetWindowText(hwndFore, szWndName, MAX_PATH);
|
|
StringCopyArray(szWndName2, szWndName);
|
|
StringCopyArray(szWndName3, szWndName);
|
|
|
|
int nSize = lstrlen(g_szNTCPLName);
|
|
*(szWndName3 + min(ARRAYSIZE(szWndName3), nSize)) = TEXT('\0');
|
|
|
|
if (IsOnNT() && *szWndName3 && lstrcmp(szWndName3, g_szNTCPLName) == 0)
|
|
{
|
|
EnumChildWindows(hwndFore, (WNDENUMPROC)Intl_EnumChildWndProc, 0);
|
|
return;
|
|
}
|
|
|
|
nSize = lstrlen(g_szKbdCPLName);
|
|
*(szWndName + min(ARRAYSIZE(szWndName), nSize)) = TEXT('\0');
|
|
|
|
if (*szWndName && lstrcmp(szWndName, g_szKbdCPLName) == 0)
|
|
{
|
|
if (!IsOnNT() && !FindWindowEx(hwndFore, NULL, NULL, g_szKbdCPLTitle))
|
|
return;
|
|
|
|
EnumChildWindows(hwndFore, (WNDENUMPROC)Intl_EnumChildWndProc, 0);
|
|
return;
|
|
}
|
|
|
|
if (g_fCHWin9x)
|
|
{
|
|
nSize = lstrlen(g_szWinCHCPLName);
|
|
|
|
*(szWndName2 + min(ARRAYSIZE(szWndName2), nSize)) = TEXT('\0');
|
|
|
|
if (*g_szWinCHCPLName && lstrcmp(szWndName2, g_szWinCHCPLName) == 0)
|
|
{
|
|
if (FindWindowEx(hwndFore, NULL, NULL, g_szWinCHCPLName))
|
|
EnumChildWindows(hwndFore, (WNDENUMPROC)Intl_CH9xIMEEnumChildWndProc, 0);
|
|
}
|
|
}
|
|
|
|
if (g_fCHNT4)
|
|
{
|
|
nSize = lstrlen(g_szCHNT4CPLName);
|
|
|
|
*(szWndName2 + min(ARRAYSIZE(szWndName2), nSize)) = TEXT('\0');
|
|
|
|
if (*g_szCHNT4CPLName && lstrcmp(szWndName2, g_szCHNT4CPLName) == 0)
|
|
{
|
|
if (FindWindowEx(hwndFore, NULL, NULL, g_szCHNT4CPLName))
|
|
EnumChildWindows(hwndFore, (WNDENUMPROC)Intl_CHEnumChildWndProc, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnForegroundChanged
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL IsParentWindow(HWND hwnd, HWND hwndParent)
|
|
{
|
|
while (hwnd)
|
|
{
|
|
if (hwnd == hwndParent)
|
|
return TRUE;
|
|
|
|
hwnd = GetParent(hwnd);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnForegroundChanged
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL OnForegroundChanged(HWND hwndFocus)
|
|
{
|
|
HWND hwndFore;
|
|
|
|
if (!hwndFocus)
|
|
hwndFocus = GetFocus();
|
|
|
|
hwndFore = GetForegroundWindow();
|
|
|
|
TraceMsg(TF_GENERAL, "OnForegroundChanged %x %x %x", GetCurrentThreadId(), hwndFore, hwndFocus);
|
|
|
|
//
|
|
// if foreground window is NULL
|
|
// OR foregrond window is minimized
|
|
// OR focus window is notify tray window,
|
|
//
|
|
// we keep the previous status.
|
|
//
|
|
if (!hwndFore ||
|
|
IsIconic(hwndFore) ||
|
|
IsNotifyTrayWnd(hwndFocus ? hwndFocus : hwndFore))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// we want to update both SharedMem->hwndForegorundPrev and
|
|
// SharedMem->dwFocusThreadPrev, if the foregorund window was changed.
|
|
//
|
|
if (hwndFore != GetSharedMemory()->hwndForeground)
|
|
{
|
|
GetSharedMemory()->hwndForegroundPrev = GetSharedMemory()->hwndForeground;
|
|
GetSharedMemory()->dwFocusThreadPrev = GetSharedMemory()->dwFocusThread;
|
|
}
|
|
|
|
GetSharedMemory()->hwndForeground = hwndFore;
|
|
if (hwndFocus)
|
|
{
|
|
DWORD dwFocusThread;
|
|
DWORD dwFocusProcess;
|
|
|
|
dwFocusThread = GetWindowThreadProcessId(hwndFocus, &dwFocusProcess);
|
|
|
|
if (hwndFore &&
|
|
(dwFocusThread != GetWindowThreadProcessId(hwndFore, NULL)))
|
|
{
|
|
if (!IsParentWindow(hwndFocus, hwndFore))
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Even the foregorund window was not changed, we may need to check
|
|
// the thread of focus window. New focus window is in different
|
|
// thread. Then we need to make TFPRIV_ONSETTHREADFOCUS message.
|
|
//
|
|
|
|
DWORD dwFocusThreadPrev = GetSharedMemory()->dwFocusThread;
|
|
GetSharedMemory()->dwFocusThread = dwFocusThread;
|
|
GetSharedMemory()->dwFocusProcess = dwFocusProcess;
|
|
|
|
if (dwFocusThreadPrev != GetSharedMemory()->dwFocusThread)
|
|
GetSharedMemory()->dwFocusThreadPrev = dwFocusThreadPrev;
|
|
}
|
|
else if (hwndFore)
|
|
{
|
|
//
|
|
// The focus window is not in the current thread... So at first we
|
|
// try to get the thread id of the foreground window.
|
|
// The focus window may not be in the foreground window's thread. But
|
|
// it is ok, as long as we track the focus in the focus thread.
|
|
//
|
|
GetSharedMemory()->dwFocusThread = GetWindowThreadProcessId(GetSharedMemory()->hwndForeground, &GetSharedMemory()->dwFocusProcess);
|
|
}
|
|
else
|
|
{
|
|
GetSharedMemory()->dwFocusThread = 0;
|
|
GetSharedMemory()->dwFocusProcess = 0;
|
|
}
|
|
|
|
if (GetSharedMemory()->dwFocusThread != GetSharedMemory()->dwLastFocusSinkThread)
|
|
{
|
|
//
|
|
// Perf:
|
|
//
|
|
// See SysGetMsgProc()!
|
|
// Now, only thread that has TIM needs to receive
|
|
// TFPRIV_ONKILLTHREADFOCUS or TF_PRIV_ONSETTHREADFOCUS.
|
|
// We should check the target thread has TIM or not. So we can
|
|
// save the number of these post messages.
|
|
//
|
|
|
|
if (GetSharedMemory()->dwFocusThreadPrev != 0)
|
|
{
|
|
PostThreadMessage(GetSharedMemory()->dwFocusThreadPrev,
|
|
g_msgPrivate,
|
|
TFPRIV_ONKILLTHREADFOCUS,
|
|
0);
|
|
}
|
|
|
|
if (GetSharedMemory()->dwFocusThread != 0)
|
|
{
|
|
PostThreadMessage(GetSharedMemory()->dwFocusThread,
|
|
g_msgPrivate,
|
|
TFPRIV_ONSETTHREADFOCUS,
|
|
0);
|
|
|
|
}
|
|
|
|
GetSharedMemory()->dwLastFocusSinkThread = GetSharedMemory()->dwFocusThread;
|
|
}
|
|
|
|
//
|
|
// Checking legacy keyboard CPL.
|
|
//
|
|
CheckLegacyInputCPL(hwndFore);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnIMENotify
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void OnIMENotify()
|
|
{
|
|
SYSTHREAD *psfn;
|
|
|
|
if (psfn = GetSYSTHREAD())
|
|
{
|
|
if (psfn->plbim && psfn->plbim->_GetLBarItemWin32IME())
|
|
{
|
|
psfn->plbim->_GetLBarItemWin32IME()->UpdateIMEIcon();
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef CHECKFEIMESELECTED
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CheckFEIMESelected
|
|
//
|
|
// This function checks the current selected FEIME is active in Cicero
|
|
// Assembly. If it is not activated, we calls ActivateAssemblyItem().
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
|
|
void CheckFEIMESelected(SYSTHREAD *psfn, HKL hKL)
|
|
{
|
|
int i;
|
|
CAssembly *pAsm;
|
|
BOOL fFound;
|
|
|
|
Assert(psfn);
|
|
|
|
if (!psfn->pAsmList)
|
|
return;
|
|
|
|
if (!IsPureIMEHKL(hKL))
|
|
return;
|
|
|
|
pAsm = psfn->pAsmList->FindAssemblyByLangId(LANGIDFROMHKL(hKL));
|
|
if (!pAsm)
|
|
return;
|
|
|
|
//
|
|
// Windows #311672
|
|
//
|
|
// EUDCEDIT.EXE calls ActivateKeyboardLayout() to activate IME hKL.
|
|
// Cicero should not break the API on WinXP. Skip SmartVoice hardcode.
|
|
//
|
|
//
|
|
#if 0
|
|
//
|
|
// SmartVoice Hack
|
|
//
|
|
// we want to remove this smart voice hack section to solve
|
|
// general ActivateKayboardLayout() problem. However Office10 wants
|
|
// the safest fix for this problem. So we check SmartVoice IME here
|
|
// to minimize the rish of CheckFEIMESelected() call.
|
|
//
|
|
{
|
|
static const char c_szSmartVoiceIME[] = "smartv20.ime";
|
|
char szIMEFile[MAX_PATH];
|
|
if (!ImmGetIMEFileNameA(hKL, szIMEFile, sizeof(szIMEFile)))
|
|
return;
|
|
|
|
if (lstrcmpi(szIMEFile, c_szSmartVoiceIME))
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// check if the hKL is substituted by the activate Item.
|
|
//
|
|
// We try to find the active Item first.
|
|
//
|
|
for (i = 0; i < pAsm->Count(); i++)
|
|
{
|
|
ASSEMBLYITEM *pItem = pAsm->GetItem(i);
|
|
|
|
if (!pItem)
|
|
continue;
|
|
|
|
if (!IsEqualGUID(pItem->catid, GUID_TFCAT_TIP_KEYBOARD))
|
|
continue;
|
|
|
|
if (!pItem->fEnabled)
|
|
continue;
|
|
|
|
if (!pItem->fActive)
|
|
continue;
|
|
|
|
if (pItem->hklSubstitute == hKL)
|
|
{
|
|
//
|
|
// #383710 OfficeXP's RichEd20.dll calls ActivateKeyboardlayout()
|
|
// with Korean IME hKL even though it is running on AIMM mode.
|
|
// we need to adjust the assembly item.
|
|
//
|
|
CThreadInputMgr *ptim = psfn->ptim;
|
|
if (ptim)
|
|
{
|
|
if (ptim->_GetFocusDocInputMgr())
|
|
{
|
|
ActivateAssemblyItem(psfn, LANGIDFROMHKL(hKL), pItem, 0);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we could not have a chance to sync the current hKL
|
|
// init hklBeingActivated and try when DIM gets the focus.
|
|
//
|
|
psfn->hklBeingActivated = NULL;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ok we could not find active Item with hKL as its substitute hKL.
|
|
// Let's find it from non-active Item, too.
|
|
//
|
|
if (psfn->ptim && psfn->ptim->_GetFocusDocInputMgr())
|
|
{
|
|
for (i = 0; i < pAsm->Count(); i++)
|
|
{
|
|
ASSEMBLYITEM *pItem = pAsm->GetItem(i);
|
|
|
|
if (!pItem)
|
|
continue;
|
|
|
|
if (!IsEqualGUID(pItem->catid, GUID_TFCAT_TIP_KEYBOARD))
|
|
continue;
|
|
|
|
if (!pItem->fEnabled)
|
|
continue;
|
|
|
|
if (pItem->hklSubstitute == hKL)
|
|
{
|
|
ActivateAssemblyItem(psfn, LANGIDFROMHKL(hKL), pItem, 0);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
fFound = FALSE;
|
|
for (i = 0; i < pAsm->Count(); i++)
|
|
{
|
|
ASSEMBLYITEM *pItem;
|
|
pItem= pAsm->GetItem(i);
|
|
|
|
if (!pItem)
|
|
continue;
|
|
|
|
if (!IsEqualGUID(pItem->catid, GUID_TFCAT_TIP_KEYBOARD))
|
|
continue;
|
|
|
|
if (pItem->hkl != hKL)
|
|
continue;
|
|
|
|
fFound = TRUE;
|
|
if (!pItem->fActive)
|
|
{
|
|
//
|
|
// This item is not activated.
|
|
// Call ActivateAssemblyItem() now and return.
|
|
//
|
|
ActivateAssemblyItem(psfn, LANGIDFROMHKL(hKL), pItem, 0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// we could not find the activated hKL in our Asmlist.
|
|
//
|
|
if (!fFound)
|
|
{
|
|
UnknownFEIMESelected(LANGIDFROMHKL(hKL));
|
|
}
|
|
}
|
|
#endif CHECKFEIMESELECTED
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnShellLanguage
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
void OnShellLanguage(HKL hKL)
|
|
{
|
|
SYSTHREAD *psfn;
|
|
|
|
HWND hwndFore = GetForegroundWindow();
|
|
if (IsConsoleWindow(hwndFore))
|
|
{
|
|
DWORD dwThreadId = GetWindowThreadProcessId(hwndFore, NULL);
|
|
|
|
g_timlist.SetConsoleHKL(dwThreadId, hKL);
|
|
|
|
if (OnForegroundChanged(NULL))
|
|
MakeSetFocusNotify(g_msgSetFocus, 0, 0);
|
|
|
|
MakeSetFocusNotify(g_msgLBUpdate,
|
|
TF_LBU_NTCONSOLELANGCHANGE,
|
|
(LPARAM)hKL);
|
|
return;
|
|
}
|
|
|
|
psfn = GetSYSTHREAD();
|
|
if (!psfn)
|
|
return;
|
|
|
|
if (psfn->hklBeingActivated == hKL)
|
|
psfn->hklBeingActivated = NULL;
|
|
|
|
|
|
if (LANGIDFROMHKL(hKL) != GetCurrentAssemblyLangId(psfn))
|
|
{
|
|
//
|
|
// if it is in Cicero aware and the hKL does not match with
|
|
// current assembly, someone else might call ActivateKayboardLayout().
|
|
// we need to change the current assembly right away..
|
|
//
|
|
// ActivateAssembly(LANGIDFROMHKL(hKL), ACTASM_ONSHELLLANGCHANGE);
|
|
//
|
|
|
|
//
|
|
// WM_INPUTLANGCHNAGEREQUEST is being queued now.
|
|
// Post another message to confirm the hKL.
|
|
//
|
|
PostThreadMessage(GetCurrentThreadId(),
|
|
g_msgPrivate,
|
|
TFPRIV_POSTINPUTCHANGEREQUEST,
|
|
0);
|
|
}
|
|
else
|
|
{
|
|
if (psfn->plbim)
|
|
UpdateSystemLangBarItems(psfn,
|
|
hKL,
|
|
!psfn->plbim->InAssemblyChange());
|
|
|
|
}
|
|
|
|
if (IsPureIMEHKL(hKL))
|
|
{
|
|
OnIMENotify();
|
|
|
|
//
|
|
// Temp rolling back SmartVoice (Cic#4580) fix. Since we got some
|
|
// regression like Cic#4713 and so on.
|
|
//
|
|
#ifdef CHECKFEIMESELECTED
|
|
//
|
|
// check this hkl is activated in Cicero Assembly.
|
|
//
|
|
CheckFEIMESelected(psfn, hKL);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UninitThread
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
typedef HRESULT (*PFNCTFIMETHREADDETACH)(void);
|
|
|
|
void UninitThread()
|
|
{
|
|
DWORD dwThreadId = GetCurrentThreadId();
|
|
SYSTHREAD *psfn = FindSYSTHREAD();
|
|
|
|
if (psfn)
|
|
psfn->fCUASDllDetachInOtherOrMe = TRUE;
|
|
|
|
// g_SharedMemory.Close();
|
|
|
|
#if 1
|
|
if (GetSharedMemory() == NULL && ! IsSharedMemoryCreated())
|
|
{
|
|
// Shared memory already closed.
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (GetSharedMemory()->dwFocusThread == dwThreadId)
|
|
{
|
|
GetSharedMemory()->dwFocusThread = 0;
|
|
GetSharedMemory()->dwFocusProcess = 0;
|
|
GetSharedMemory()->hwndForeground = NULL;
|
|
}
|
|
|
|
if (GetSharedMemory()->dwFocusThreadPrev == dwThreadId)
|
|
{
|
|
GetSharedMemory()->hwndForegroundPrev = NULL;
|
|
GetSharedMemory()->dwFocusThreadPrev = 0;
|
|
}
|
|
|
|
if (GetSharedMemory()->dwLastFocusSinkThread == dwThreadId)
|
|
{
|
|
GetSharedMemory()->dwLastFocusSinkThread = 0;
|
|
}
|
|
|
|
//
|
|
// Issue:
|
|
//
|
|
// UninitThread() is called from DLL_THREAD_DETACH so
|
|
// we should not call MakeSetFocusNotify() because it uses
|
|
// ciritical section and could cause dead lock.
|
|
//
|
|
MakeSetFocusNotify(g_msgThreadTerminate, 0, (LPARAM)dwThreadId);
|
|
|
|
|
|
if (psfn && GetSystemMetrics(SM_SHUTTINGDOWN))
|
|
{
|
|
psfn->fUninitThreadOnShuttingDown = TRUE;
|
|
}
|
|
|
|
//
|
|
// Tell msctfime that msctf's thread_detach is being called.
|
|
// So it can deactivate TIM now. If we don't do this now,
|
|
// it may deactivate TIM afte msctf's thread detach is called.
|
|
//
|
|
if (g_fCUAS && g_szCUASImeFile[0])
|
|
{
|
|
HINSTANCE hInstMsctfime;
|
|
|
|
hInstMsctfime = GetSystemModuleHandle(g_szCUASImeFile);
|
|
if (hInstMsctfime)
|
|
{
|
|
PFNCTFIMETHREADDETACH pfn = NULL;
|
|
pfn = (PFNCTFIMETHREADDETACH)GetProcAddress(hInstMsctfime,
|
|
"CtfImeThreadDetach");
|
|
if (pfn)
|
|
pfn();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SysShellProc
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
LRESULT CALLBACK SysShellProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
TraceMsg(TF_GENERAL, "SysShellProc %x %x %x", nCode, wParam, lParam);
|
|
HHOOK hHook;
|
|
|
|
if (g_fDllProcessDetached)
|
|
{
|
|
hHook = s_hSysShellHook;
|
|
goto Exit;
|
|
}
|
|
|
|
_try
|
|
{
|
|
hHook = GetSharedMemory()->hSysShellHook.GetHandle(g_bOnWow64);
|
|
|
|
_ShellProc(nCode, wParam, lParam);
|
|
}
|
|
_except(CicExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
Assert(0);
|
|
}
|
|
|
|
Exit:
|
|
return CallNextHookEx(hHook, nCode, wParam, lParam);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _ShellProc
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
UINT _ShellProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HWND hwndActive;
|
|
|
|
//
|
|
// give AIMM the Shell events.
|
|
//
|
|
CThreadInputMgr *ptim;
|
|
SYSTHREAD *psfn;
|
|
if (psfn = GetSYSTHREAD())
|
|
{
|
|
if (ptim = psfn->ptim)
|
|
{
|
|
if (ptim->GetSysHookSink())
|
|
{
|
|
ptim->GetSysHookSink()->OnSysShellProc(nCode, wParam, lParam);
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (nCode)
|
|
{
|
|
case HSHELL_LANGUAGE:
|
|
OnShellLanguage((HKL)lParam);
|
|
break;
|
|
|
|
case HSHELL_WINDOWACTIVATED:
|
|
//TraceMsg(TF_GENERAL, "SysShellProc: HSHELL_WINDOWACTIVATED %x", GetCurrentThreadId());
|
|
GetSharedMemory()->fInFullScreen = lParam ? TRUE : FALSE;
|
|
|
|
hwndActive = GetActiveWindow();
|
|
if (hwndActive &&
|
|
(GetWindowThreadProcessId(hwndActive, NULL) == GetCurrentThreadId()))
|
|
{
|
|
if (OnForegroundChanged(NULL))
|
|
MakeSetFocusNotify(g_msgSetFocus, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
hwndActive = GetForegroundWindow();
|
|
goto CheckConsole;
|
|
}
|
|
break;
|
|
|
|
case HSHELL_WINDOWCREATED:
|
|
hwndActive = (HWND)wParam;
|
|
CheckConsole:
|
|
if (hwndActive && IsOnNT() && IsConsoleWindow(hwndActive))
|
|
{
|
|
DWORD dwProcessId;
|
|
DWORD dwThreadId = GetWindowThreadProcessId(hwndActive,
|
|
&dwProcessId);
|
|
|
|
if ((nCode == HSHELL_WINDOWCREATED) ||
|
|
!(g_timlist.GetFlags(dwThreadId) & TLF_NTCONSOLE))
|
|
g_timlist.AddThreadProcess(dwThreadId,
|
|
dwProcessId,
|
|
NULL,
|
|
TLF_NTCONSOLE);
|
|
|
|
if (OnForegroundChanged(NULL))
|
|
{
|
|
HKL hklConsole = g_timlist.GetConsoleHKL(dwThreadId);
|
|
if (!hklConsole)
|
|
{
|
|
hklConsole = GetKeyboardLayout(dwThreadId);
|
|
g_timlist.SetConsoleHKL(dwThreadId, hklConsole);
|
|
}
|
|
MakeSetFocusNotify(g_msgSetFocus, 0, 0);
|
|
MakeSetFocusNotify(g_msgLBUpdate,
|
|
TF_LBU_NTCONSOLELANGCHANGE,
|
|
(LPARAM) (HKL)hklConsole);
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnSetWindowFocus()
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void OnSetWindowFocus(SYSTHREAD *psfn, HWND hwnd)
|
|
{
|
|
CThreadInputMgr *ptim;
|
|
Assert(psfn)
|
|
|
|
if (psfn->hklDelayActive)
|
|
{
|
|
ActivateKeyboardLayout(psfn->hklDelayActive, 0);
|
|
psfn->hklDelayActive = NULL;
|
|
}
|
|
|
|
if (ptim = psfn->ptim)
|
|
{
|
|
if (hwnd)
|
|
{
|
|
if (ptim->GetSysHookSink())
|
|
ptim->GetSysHookSink()->OnPreFocusDIM(hwnd);
|
|
|
|
Assert(GetWindowThreadProcessId(hwnd, NULL) == GetCurrentThreadId());
|
|
CDocumentInputManager *pdim;
|
|
|
|
pdim = ptim->_GetAssoc(hwnd);
|
|
|
|
//
|
|
// we don't want to clear focus dim if there is no
|
|
// foreground window.
|
|
//
|
|
if (pdim || GetForegroundWindow())
|
|
{
|
|
// focus dim will be clear if pdim is NULL.
|
|
ptim->_SetFocus(pdim, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// update foregorund window handle and thread id.
|
|
// Because shell hook is posted event, we need to update
|
|
// before MakeSetFocusNotify. Otherwise we miss timing to
|
|
// update them.
|
|
//
|
|
// We can not call GetFocus() since it may return
|
|
// the previous focus during CBT hook.
|
|
// When the focus moves back from embedded OLE server,
|
|
// GetFocus() may get the the OLE server's window handle.
|
|
//
|
|
if (OnForegroundChanged(hwnd))
|
|
{
|
|
//
|
|
// If hwndFocus is NULL, focus is moved to other thread.
|
|
//
|
|
MakeSetFocusNotify(g_msgSetFocus, 0, 0);
|
|
}
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnSetWindowFocusHandler()
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void OnSetWindowFocusHandler(SYSTHREAD *psfn, MSG *pmsg)
|
|
{
|
|
if (!psfn)
|
|
return;
|
|
|
|
//
|
|
// We're destroying the marhacl window right now. We don't have
|
|
// any more visible windows.
|
|
//
|
|
if (psfn->uDestroyingMarshalWnd)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
HWND hwndFocus = GetFocus();
|
|
if (hwndFocus)
|
|
{
|
|
//
|
|
// review review
|
|
//
|
|
// Don't we need to call
|
|
// OnForegroundChanged() if psfn->hwndBegin
|
|
// gFocued() is NULL?
|
|
// Maybe no, OnForegroundChanged() is
|
|
// called in activatewindow.
|
|
//
|
|
if (psfn->hwndBeingFocused == hwndFocus)
|
|
{
|
|
OnSetWindowFocus(psfn, hwndFocus);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// #476100
|
|
//
|
|
// if we miss this, we need to post
|
|
// TFPRIV_ONSETWINDOWFOCUS again.
|
|
// Because the focus thread might processed
|
|
// this meesage already and it does not
|
|
// call OnSetWindowFocus().
|
|
//
|
|
DWORD dwFocusWndThread = GetWindowThreadProcessId(hwndFocus, NULL);
|
|
if (psfn->dwThreadId != dwFocusWndThread)
|
|
{
|
|
PostThreadMessage(dwFocusWndThread,
|
|
g_msgPrivate,
|
|
TFPRIV_ONSETWINDOWFOCUS,
|
|
(LPARAM)-1);
|
|
}
|
|
else if (pmsg->lParam == (LPARAM)-2)
|
|
{
|
|
if (psfn->ptim && psfn->ptim->_GetFocusDocInputMgr())
|
|
{
|
|
HWND hwndAssoc;
|
|
|
|
hwndAssoc = psfn->ptim->_GetAssoced(psfn->ptim->_GetFocusDocInputMgr());
|
|
//
|
|
// lParam is -2 because the SetFocus(dim) is already
|
|
// called.
|
|
// hwndAssoc is NULL. Now we're in Cicero aware.
|
|
//
|
|
// So we just do OnForegroundChanged(). Don't call
|
|
// OnSetWindowFocus().
|
|
//
|
|
// Bug#623920 - Don't need to check up hwndAssoc since the current focus
|
|
// window has the right dim value and also need to update language bar even
|
|
// with hwndAssoc
|
|
//
|
|
//if (!hwndAssoc)
|
|
//
|
|
{
|
|
if (OnForegroundChanged(hwndFocus))
|
|
{
|
|
MakeSetFocusNotify(g_msgSetFocus, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ((pmsg->lParam == (LPARAM)-1) ||
|
|
(psfn->dwThreadId == GetWindowThreadProcessId(GetForegroundWindow(), NULL)))
|
|
{
|
|
//
|
|
// #479926
|
|
//
|
|
// The first SetFocus() in the thread
|
|
// may break the order of CBT hook
|
|
// because xxxSetFocus() calls
|
|
// xxxActivateWindow() and this cause
|
|
// another xxxSetFocus(). After
|
|
// xxxActivateWindow() returns
|
|
// the first xxxSetFocus() updates
|
|
// the spwndFocus.
|
|
//
|
|
// see ntuser\kernel\focusact.c
|
|
//
|
|
// Now we need to hack. We're 100% sure
|
|
// if the focus window and the fore-
|
|
// ground window is in same thread,
|
|
// we can do _SetFocus(dim).
|
|
// but if focusdim does not have a associated window,
|
|
// Cicero App might call SetFocus() already. Then
|
|
// we don't do anything.
|
|
//
|
|
if (psfn->ptim && psfn->ptim->_GetFocusDocInputMgr())
|
|
{
|
|
HWND hwndAssoc;
|
|
|
|
hwndAssoc = psfn->ptim->_GetAssoced(psfn->ptim->_GetFocusDocInputMgr());
|
|
if (hwndAssoc && hwndFocus != hwndAssoc)
|
|
OnSetWindowFocus(psfn, hwndFocus);
|
|
}
|
|
else if (!psfn->ptim ||
|
|
psfn->ptim->_IsNoFirstSetFocusAfterActivated() ||
|
|
psfn->ptim->_IsInternalFocusedDim())
|
|
{
|
|
OnSetWindowFocus(psfn, hwndFocus);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// try to update Kana status every time
|
|
// focus changes.
|
|
//
|
|
//
|
|
// when the focus is changed, we need to make
|
|
// notification again.
|
|
//
|
|
psfn->fInitCapsKanaIndicator = FALSE;
|
|
StartKanaCapsUpdateTimer(psfn);
|
|
|
|
Exit:
|
|
psfn->hwndBeingFocused = NULL;
|
|
psfn->fSetWindowFocusPosted = FALSE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// IsPostedMessage
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
__inline BOOL IsPostedMessage()
|
|
{
|
|
DWORD dwQueueStatus = GetQueueStatus(QS_POSTMESSAGE);
|
|
return (HIWORD(dwQueueStatus) & QS_POSTMESSAGE) ? TRUE : FALSE;
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// RemovePrivateMessage
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void RemovePrivateMessage(SYSTHREAD *psfn, HWND hwnd, UINT uMsg)
|
|
{
|
|
MSG msg;
|
|
UINT nQuitCode;
|
|
BOOL fQuitReceived = FALSE;
|
|
DWORD dwPMFlags = PM_REMOVE | PM_NOYIELD;
|
|
|
|
if (!IsPostedMessage())
|
|
return;
|
|
|
|
|
|
//
|
|
// Cic#4666 PostPet v1.12 fault.
|
|
// PostPet.exe cause av when it receives its internal message in
|
|
// CBT_DESTROYWINDOW hook when it is terminated.
|
|
// At this time, the child thread is calling SendMessage() to the window
|
|
// in the main thread. So calling PeekMessage() may receive the message
|
|
// and pass it to PostPet window.
|
|
//
|
|
// I found Win98 has a bug in PM_QS_POSTMESSAGE. Win98's PeekMessage()
|
|
// handles the message that is sent from other thread without
|
|
// PM_QS_SENDMESSAGE.
|
|
//
|
|
// If we has to fix this problem on Win98, I think it is better to have
|
|
// another compatibility flag so we can skip this PeekMessage() in
|
|
// PostPet.exe. In PostPet.exe, it is ok not to clean queue since
|
|
// this happens only app termination.
|
|
//
|
|
if (IsOnNT5())
|
|
dwPMFlags |= PM_QS_POSTMESSAGE;
|
|
|
|
while (PeekMessage(&msg, hwnd, uMsg, uMsg, dwPMFlags ))
|
|
{
|
|
if (msg.message == WM_QUIT)
|
|
{
|
|
nQuitCode = (UINT)(msg.wParam);
|
|
fQuitReceived = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// should we dispatch the message to the marshal window?
|
|
//
|
|
#if 0
|
|
//
|
|
// Cic#4869
|
|
//
|
|
// we don't want to dispatch this message to marshal window.
|
|
// This HCBT_DESTROYWINDOW may be in OLEAUT32.DLL's DllMain() and
|
|
// dispatching this message could cause the reentry to OLEAUT32's
|
|
// DLLMain() because we do delay load.
|
|
//
|
|
|
|
//
|
|
// dispatch if this message is for marshal window.
|
|
//
|
|
if (psfn->hwndMarshal && (psfn->hwndMarshal == msg.hwnd))
|
|
{
|
|
DispatchMessage(&msg);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Cic#4699
|
|
//
|
|
// Exception MSUIM.Msg.MuiMgrDirtyUpdate private message.
|
|
// If we get this message, reset CLangBarItemMgr::_fDirtyUpdateHandling
|
|
//
|
|
if (psfn->hwndMarshal && (psfn->hwndMarshal == msg.hwnd) &&
|
|
msg.message == g_msgNuiMgrDirtyUpdate &&
|
|
psfn->plbim)
|
|
{
|
|
psfn->plbim->ResetDirtyUpdate();
|
|
}
|
|
|
|
}
|
|
|
|
if (fQuitReceived)
|
|
PostQuitMessage(nQuitCode);
|
|
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CheckQueueOnLastWindowDestroyed()
|
|
//
|
|
// Super EnumWindow hack.
|
|
//
|
|
// When the last visible window in the thread is destroyed.
|
|
//
|
|
// 1. we destroy the marshal worker window on NT4. (Cic #658)
|
|
// Because some application may found Cic marshal window
|
|
// by calling EnumWindow.
|
|
//
|
|
//
|
|
// 2. we need to clean up the thread queue. (Cic #3080)
|
|
// Because some application calls GetMessage() or PeekMessage()
|
|
// with specific window handle or message soour private messages
|
|
// remain in the queue. Then WM_QUIT message won't be handled..
|
|
//
|
|
// this is not complete solution but at least we can avoid
|
|
// the ghost windows or remained message in the queue.
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void CheckQueueOnLastWindowDestroyed(SYSTHREAD *psfn, HWND hwnd)
|
|
{
|
|
BOOL fOnNT4;
|
|
|
|
//
|
|
// we don't have to do this on ctfmon process.
|
|
//
|
|
if (psfn->fCTFMON)
|
|
return;
|
|
|
|
//
|
|
// check if it's nt4.
|
|
//
|
|
fOnNT4 = (IsOnNT() && !IsOnNT5()) ? TRUE : FALSE;
|
|
|
|
#if 0
|
|
if (!fOnNT4)
|
|
{
|
|
//
|
|
// If there is no posted message, we don't have to do this.
|
|
// EnumThreadWindow() is slow....
|
|
//
|
|
if (!IsPostedMessage())
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE);
|
|
if (style & WS_CHILD)
|
|
return;
|
|
|
|
if (hwnd == psfn->hwndMarshal)
|
|
return;
|
|
|
|
//
|
|
// skip IME windows.
|
|
//
|
|
style = GetClassLongPtr(hwnd, GCL_STYLE);
|
|
if (style & CS_IME)
|
|
return;
|
|
|
|
|
|
//
|
|
// check the focus window first.
|
|
//
|
|
// if there is a focus window and it is not a child
|
|
// of the window that is being destroyed, we don't
|
|
// have to destroy marshal window.
|
|
//
|
|
HWND hwndTmp = GetFocus();
|
|
if (hwndTmp &&
|
|
(GetCurrentThreadId() != GetWindowThreadProcessId(hwndTmp, NULL)))
|
|
hwndTmp = NULL;
|
|
|
|
if (hwndTmp)
|
|
{
|
|
BOOL fParentFound = FALSE;
|
|
do {
|
|
if (hwndTmp == hwnd)
|
|
fParentFound = TRUE;
|
|
|
|
hwndTmp = GetParent(hwndTmp);
|
|
} while(hwndTmp);
|
|
|
|
if (!fParentFound)
|
|
return;
|
|
}
|
|
|
|
CHECKVISIBLEWND cmw;
|
|
cmw.hwndMarshal = psfn->hwndMarshal;
|
|
cmw.hwndBeingDestroyed = hwnd;
|
|
cmw.fVisibleFound = FALSE;
|
|
EnumThreadWindows(psfn->dwThreadId,
|
|
CheckVisibleWindowEnumProc,
|
|
(LPARAM)&cmw);
|
|
|
|
if (!cmw.fVisibleFound)
|
|
{
|
|
BOOL fInDestroyingMarshalWnd = FALSE;
|
|
if (psfn->uDestroyingMarshalWnd)
|
|
fInDestroyingMarshalWnd = TRUE;
|
|
|
|
psfn->uDestroyingMarshalWnd++;
|
|
|
|
DestroyMarshalWindow(psfn, hwnd);
|
|
|
|
#ifdef CUAS_ENABLE
|
|
//
|
|
// Under CUAS, we need to deactivate TIM to destroy all TIP's window
|
|
// when there is no visible window in this thread.
|
|
// And we destroy the default IME window so we can restore TIM for
|
|
// CUAS when the default IME window is created again in this thread.
|
|
// There is no way to know if the default IME window finds another
|
|
// top level window if it is created during DestroyWindow().
|
|
//
|
|
if (CtfImmIsCiceroEnabled() &&
|
|
!CtfImmIsTextFrameServiceDisabled() &&
|
|
!psfn->fCUASInCreateDummyWnd &&
|
|
!psfn->fDeactivatingTIP)
|
|
{
|
|
if (!psfn->fCUASInCtfImmLastEnabledWndDestroy)
|
|
{
|
|
psfn->fCUASInCtfImmLastEnabledWndDestroy = TRUE;
|
|
|
|
CtfImmLastEnabledWndDestroy(0);
|
|
|
|
if (!(InSendMessageEx(NULL) & ISMEX_SEND))
|
|
CtfImmCoUninitialize();
|
|
|
|
psfn->fCUASInCtfImmLastEnabledWndDestroy = FALSE;
|
|
}
|
|
|
|
if (!fInDestroyingMarshalWnd)
|
|
{
|
|
HWND hwndImmDef = ImmGetDefaultIMEWnd(hwnd);
|
|
if (hwndImmDef)
|
|
{
|
|
DestroyWindow(hwndImmDef);
|
|
}
|
|
}
|
|
|
|
psfn->fCUASNoVisibleWindowChecked = TRUE;
|
|
}
|
|
#endif CUAS_ENABLE
|
|
|
|
psfn->uDestroyingMarshalWnd--;
|
|
}
|
|
}
|
|
|
|
void DestroyMarshalWindow(SYSTHREAD* psfn, HWND hwnd)
|
|
{
|
|
BOOL fOnNT4;
|
|
|
|
if (IsPostedMessage())
|
|
{
|
|
if (psfn->hwndMarshal)
|
|
RemovePrivateMessage(psfn, psfn->hwndMarshal, 0);
|
|
|
|
RemovePrivateMessage(psfn, NULL, g_msgPrivate);
|
|
RemovePrivateMessage(psfn, NULL, g_msgRpcSendReceive);
|
|
RemovePrivateMessage(psfn, NULL, g_msgThreadMarshal);
|
|
RemovePrivateMessage(psfn, NULL, g_msgStubCleanUp);
|
|
}
|
|
|
|
//
|
|
// #339621
|
|
//
|
|
// This is rare but. We need to clear ShareMem->dwFocusThread and
|
|
// dwFocusProcess. Otherwise we will get another PostThreadMessage()
|
|
// with TFPRIV_ONKILLTHREADFOCUS later. And SQL setup hungs.
|
|
//
|
|
if (GetSharedMemory()->dwFocusThread == psfn->dwThreadId)
|
|
GetSharedMemory()->dwFocusThread = 0;
|
|
|
|
if (GetSharedMemory()->dwFocusProcess == psfn->dwProcessId)
|
|
GetSharedMemory()->dwFocusProcess = 0;
|
|
|
|
//
|
|
// check if it's nt4.
|
|
//
|
|
fOnNT4 = (IsOnNT() && !IsOnNT5()) ? TRUE : FALSE;
|
|
|
|
if (fOnNT4 && IsWindow(psfn->hwndMarshal))
|
|
{
|
|
DestroyWindow(psfn->hwndMarshal);
|
|
psfn->hwndMarshal = NULL;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CreateDummyWndForDefIMEWnd
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
#ifdef CUAS_ENABLE
|
|
BOOL g_fCDWRegistered = FALSE;
|
|
const CHAR c_szDummyWndForDefIMEWnd[] = "CicDUmmyWndForDefIMEWnd";
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CicDummyForDefIMEWndProc
|
|
//
|
|
// This needs to be user mode wndproc. Otherwise system does not create
|
|
// a default IME window
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
LRESULT CALLBACK CicDummyForDefIMEWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
void CreateDummyWndForDefIMEWnd()
|
|
{
|
|
HWND hwnd;
|
|
|
|
if (!g_fCDWRegistered)
|
|
{
|
|
WNDCLASSEX wndclass;
|
|
|
|
memset(&wndclass, 0, sizeof(wndclass));
|
|
wndclass.cbSize = sizeof(wndclass);
|
|
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
|
|
wndclass.hInstance = g_hInst;
|
|
wndclass.hCursor = NULL;
|
|
wndclass.lpfnWndProc = CicDummyForDefIMEWndProc;
|
|
wndclass.lpszClassName = c_szDummyWndForDefIMEWnd;
|
|
|
|
if (RegisterClassEx(&wndclass))
|
|
g_fCDWRegistered = TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// call CraeteWindow() to create a default IME window.
|
|
//
|
|
hwnd = CreateWindowEx(0, c_szDummyWndForDefIMEWnd, NULL,
|
|
WS_POPUP,
|
|
0,0,0,0,
|
|
NULL, NULL, g_hInst, NULL);
|
|
if (hwnd)
|
|
DestroyWindow(hwnd);
|
|
|
|
}
|
|
#endif // CUAS_ENABLE
|
|
|
|
#ifdef CUAS_ENABLE
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UninitThreadHooksIfNoWindow()
|
|
//
|
|
// When the last window in the thread is destroyed.
|
|
// Unhook thread local hook for SetThreadDesktop().
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void UninitThreadHooksIfNoWindow(SYSTHREAD* psfn, HWND hwnd)
|
|
{
|
|
CHECKNOWND cmw;
|
|
cmw.hwndBeingDestroyed = hwnd;
|
|
cmw.fWindowFound = FALSE;
|
|
EnumThreadWindows(psfn->dwThreadId,
|
|
CheckNoWindowEnumProc,
|
|
(LPARAM)&cmw);
|
|
|
|
if (! cmw.fWindowFound)
|
|
{
|
|
DestroyMarshalWindow(psfn, hwnd);
|
|
if (IsWindow(psfn->hwndMarshal))
|
|
{
|
|
DestroyWindow(psfn->hwndMarshal);
|
|
psfn->hwndMarshal = NULL;
|
|
}
|
|
UninitThreadHooks(psfn);
|
|
}
|
|
}
|
|
#endif // CUAS_ENABLE
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SysCBTProc
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
LRESULT CALLBACK SysCBTProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
SYSTHREAD *psfn;
|
|
HHOOK hHook;
|
|
|
|
if (g_fDllProcessDetached)
|
|
{
|
|
hHook = s_hSysCBTHook;
|
|
goto Exit;
|
|
}
|
|
|
|
_try
|
|
{
|
|
hHook = GetSharedMemory()->hSysCBTHook.GetHandle(g_bOnWow64);
|
|
|
|
InitThreadHook(GetCurrentThreadId());
|
|
|
|
switch (nCode)
|
|
{
|
|
case HCBT_CREATEWND:
|
|
if ((psfn = GetSYSTHREAD()) &&
|
|
psfn->hklDelayActive)
|
|
{
|
|
if (ActivateKeyboardLayout(psfn->hklDelayActive, 0))
|
|
psfn->hklDelayActive = NULL;
|
|
}
|
|
break;
|
|
|
|
case HCBT_ACTIVATE:
|
|
_CBTHook(HCBT_ACTIVATE, wParam, lParam);
|
|
break;
|
|
|
|
case HCBT_SETFOCUS:
|
|
_CBTHook(HCBT_SETFOCUS, wParam, lParam);
|
|
break;
|
|
|
|
case HCBT_DESTROYWND:
|
|
if (psfn = GetSYSTHREAD())
|
|
{
|
|
CheckQueueOnLastWindowDestroyed(psfn, (HWND)wParam);
|
|
#ifdef CUAS_ENABLE
|
|
UninitThreadHooksIfNoWindow(psfn, (HWND)wParam);
|
|
#endif // CUAS_ENABLE
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
_except(CicExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
Assert(0);
|
|
}
|
|
|
|
Exit:
|
|
return CallNextHookEx(hHook, nCode, wParam, lParam);
|
|
}
|
|
|
|
UINT _CBTHook(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
SYSTHREAD *psfn;
|
|
|
|
switch (nCode)
|
|
{
|
|
case HCBT_ACTIVATE:
|
|
if (wParam)
|
|
{
|
|
if (((HWND)wParam == GetForegroundWindow()) &&
|
|
OnForegroundChanged(NULL))
|
|
MakeSetFocusNotify(g_msgSetFocus, 0, 0);
|
|
}
|
|
break;
|
|
|
|
case HCBT_SETFOCUS:
|
|
if (psfn = GetSYSTHREAD())
|
|
{
|
|
#ifdef CUAS_ENABLE
|
|
//
|
|
// Cic#5254
|
|
//
|
|
// After we detect no more visible window,
|
|
// some window could become visible.
|
|
// Since we destroyed the default IME window,
|
|
// we need to recreate it.
|
|
//
|
|
// Here is a hack to do. Call a dummy CreateWindow()
|
|
// to create a default IME window in this thread.
|
|
//
|
|
if (psfn->fCUASNoVisibleWindowChecked)
|
|
{
|
|
psfn->fCUASInCreateDummyWnd = TRUE;
|
|
CreateDummyWndForDefIMEWnd();
|
|
psfn->fCUASInCreateDummyWnd = FALSE;
|
|
psfn->fCUASNoVisibleWindowChecked = FALSE;
|
|
}
|
|
#endif
|
|
|
|
psfn->hwndBeingFocused = (HWND)wParam;
|
|
|
|
if (!psfn->fSetWindowFocusPosted)
|
|
{
|
|
PostThreadMessage(GetCurrentThreadId(),
|
|
g_msgPrivate,
|
|
TFPRIV_ONSETWINDOWFOCUS,
|
|
(LPARAM)wParam);
|
|
psfn->fSetWindowFocusPosted = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// RemoveThisMessage
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL RemoveThisMessage(MSG *pmsg)
|
|
{
|
|
MSG msg;
|
|
SYSTHREAD *psfn;
|
|
|
|
if (psfn = GetSYSTHREAD())
|
|
{
|
|
if (psfn->uMsgRemoved)
|
|
{
|
|
Assert(psfn->uMsgRemoved == pmsg->message);
|
|
// Assert(psfn->dwMsgTime == pmsg->time);
|
|
return TRUE;
|
|
}
|
|
|
|
Assert(!psfn->uMsgRemoved);
|
|
psfn->uMsgRemoved = pmsg->message;
|
|
psfn->dwMsgTime = pmsg->time;
|
|
}
|
|
|
|
PeekMessage(&msg, NULL, pmsg->message, pmsg->message, PM_REMOVE | PM_NOYIELD);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// HandledThisMessage
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void FinishThisMessage(MSG *pmsg)
|
|
{
|
|
SYSTHREAD *psfn;
|
|
|
|
if (psfn = GetSYSTHREAD())
|
|
{
|
|
psfn->uMsgRemoved = 0;
|
|
psfn->dwMsgTime = 0;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// PostInputChangeRequestHandler()
|
|
//
|
|
// this is the function that is called by TFPRIV_POSTINPUTCHANGEREQUEST.
|
|
// We need to confirm the current hKL mathes with Cicero assembly language.
|
|
// And we need to check the substitute hKL is selected on Cicero control.
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void PostInputChangeRequestHandler()
|
|
{
|
|
SYSTHREAD *psfn = GetSYSTHREAD();
|
|
|
|
if (!psfn)
|
|
return;
|
|
|
|
//
|
|
// If the current hKL does not match with
|
|
// Cicero assembly language, we call
|
|
// ActivateAssembly() to sync to the current
|
|
// hKL. Someone accepted this language change.
|
|
//
|
|
HKL hKL = GetKeyboardLayout(0);
|
|
|
|
if (LANGIDFROMHKL(hKL) != GetCurrentAssemblyLangId(psfn))
|
|
{
|
|
//
|
|
// #494602, Corel Draw 10 calls LoadKeyboardLayout and ActivateKeyboardLayout.
|
|
// If specified hKL doesn't exist in our assembly list, then should update.
|
|
//
|
|
if (! IsPureIMEHKL(hKL) && psfn->pAsmList)
|
|
{
|
|
CAssembly *pAsm = psfn->pAsmList->FindAssemblyByLangId(LANGIDFROMHKL(hKL));
|
|
if (! pAsm)
|
|
{
|
|
CAssemblyList::InvalidCache();
|
|
EnsureAssemblyList(psfn, TRUE);
|
|
}
|
|
}
|
|
|
|
ActivateAssembly(LANGIDFROMHKL(hKL), ACTASM_NONE);
|
|
}
|
|
else
|
|
{
|
|
CThreadInputMgr *ptim = psfn->ptim;
|
|
if (ptim && ptim->_GetFocusDocInputMgr())
|
|
{
|
|
ASSEMBLYITEM *pItem = NULL;
|
|
|
|
if (psfn->pAsmList)
|
|
{
|
|
CAssembly *pAsm = psfn->pAsmList->FindAssemblyByLangId(LANGIDFROMHKL(hKL));
|
|
if (pAsm)
|
|
pItem = pAsm->GetSubstituteItem(hKL);
|
|
}
|
|
|
|
if (pItem)
|
|
ActivateAssemblyItem(psfn, LANGIDFROMHKL(hKL), pItem, AAIF_CHANGEDEFAULT);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InputLangChangeHandler
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void InputLangChangeHandler(MSG *pmsg)
|
|
{
|
|
SYSTHREAD *psfn;
|
|
IMM32HOTKEY *pHotKey;
|
|
HKL hKL = GetKeyboardLayout(0);
|
|
psfn = GetSYSTHREAD();
|
|
|
|
if (psfn)
|
|
psfn->hklBeingActivated = NULL;
|
|
|
|
if (IsInLangChangeHotkeyStatus())
|
|
{
|
|
pmsg->message = WM_NULL;
|
|
return;
|
|
}
|
|
|
|
if (pHotKey = IsInImmHotkeyStatus(psfn, LANGIDFROMHKL(hKL)))
|
|
{
|
|
//
|
|
// if we're hooking in IMM32's HotKey, we need to skip
|
|
// this INPUTLANGUAGECHANGEREQUEST.
|
|
//
|
|
pmsg->message = WM_NULL;
|
|
#ifdef SIMULATE_EATENKEYS
|
|
CancelImmHotkey(psfn, pmsg->hwnd, pHotKey);
|
|
#endif
|
|
|
|
//
|
|
// Chinese IME-NONIME toggle Hack for NT.
|
|
//
|
|
// On Win9x, we're using real IME as a dummy hKL of CH-Tips.
|
|
// we can forward the hotkey request to Assembly here.
|
|
//
|
|
if ((pHotKey->dwId == IME_CHOTKEY_IME_NONIME_TOGGLE) ||
|
|
(pHotKey->dwId == IME_THOTKEY_IME_NONIME_TOGGLE))
|
|
{
|
|
if (!IsOnNT())
|
|
{
|
|
PostThreadMessage(GetCurrentThreadId(),
|
|
g_msgPrivate,
|
|
TFPRIV_ACTIVATELANG,
|
|
0x0409);
|
|
|
|
}
|
|
else
|
|
{
|
|
ToggleCHImeNoIme(psfn, LANGIDFROMHKL(hKL), LANGIDFROMHKL(hKL));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// WM_INPUTLANGCHNAGEREQUEST is being queued now.
|
|
// Post another message to confirm the hKL.
|
|
//
|
|
PostThreadMessage(GetCurrentThreadId(),
|
|
g_msgPrivate,
|
|
TFPRIV_POSTINPUTCHANGEREQUEST,
|
|
0);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _InsideLoaderLock
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL _InsideLoaderLock()
|
|
{
|
|
return (NtCurrentTeb()->ClientId.UniqueThread ==
|
|
((PRTL_CRITICAL_SECTION)(NtCurrentPeb()->LoaderLock))->OwningThread);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _OwnedLoaderLockBySomeone
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL _OwnedLoaderLockBySomeone()
|
|
{
|
|
return ((PRTL_CRITICAL_SECTION)(NtCurrentPeb()->LoaderLock))->OwningThread ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
LONG WINAPI CicExceptionFilter(struct _EXCEPTION_POINTERS *pExceptionInfo)
|
|
{
|
|
(LONG)RtlUnhandledExceptionFilter(pExceptionInfo);
|
|
return(EXCEPTION_EXECUTE_HANDLER);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SysGetMsgProc
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
LRESULT CALLBACK SysGetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HHOOK hHook;
|
|
|
|
if (g_fDllProcessDetached)
|
|
{
|
|
hHook = s_hSysGetMsgHook;
|
|
goto Exit;
|
|
}
|
|
|
|
_try
|
|
{
|
|
hHook = GetSharedMemory()->hSysGetMsgHook.GetHandle(g_bOnWow64);
|
|
|
|
if (nCode == HC_ACTION && (wParam & PM_REMOVE)) // bug 29656: sometimes w/ word wParam is set to PM_REMOVE | PM_NOYIELD
|
|
{ // PM_NOYIELD is meaningless in win32 and sould be ignored
|
|
_GetMsgHook(wParam, lParam);
|
|
}
|
|
}
|
|
_except(CicExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
Assert(0);
|
|
}
|
|
|
|
Exit:
|
|
return CallNextHookEx(hHook, nCode, wParam, lParam);
|
|
}
|
|
|
|
UINT _GetMsgHook(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
MSG *pmsg;
|
|
UINT uMsg;
|
|
CThreadInputMgr *ptim;
|
|
SYSTHREAD *psfn;
|
|
|
|
pmsg = (MSG *)lParam;
|
|
uMsg = pmsg->message;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_ACTIVATEAPP:
|
|
TraceMsg(TF_GENERAL, "SysGetMsgProc: WM_ACTIVATEAPP %x %x", GetCurrentThreadId(), pmsg->wParam);
|
|
if (pmsg->wParam)
|
|
{
|
|
OnForegroundChanged(NULL);
|
|
}
|
|
break;
|
|
|
|
case WM_INPUTLANGCHANGEREQUEST:
|
|
InputLangChangeHandler(pmsg);
|
|
break;
|
|
|
|
default:
|
|
if (uMsg == g_msgPrivate)
|
|
{
|
|
psfn = GetSYSTHREAD();
|
|
if (psfn && psfn->pti)
|
|
{
|
|
DWORD dwFlags = TLFlagFromTFPriv(pmsg->wParam);
|
|
psfn->pti->dwFlags &= ~dwFlags;
|
|
}
|
|
|
|
switch (LOWORD(pmsg->wParam))
|
|
{
|
|
case TFPRIV_ONSETWINDOWFOCUS:
|
|
OnSetWindowFocusHandler(psfn, pmsg);
|
|
break;
|
|
|
|
case TFPRIV_ONKILLTHREADFOCUS:
|
|
//
|
|
// #497764
|
|
//
|
|
// PENJPN.DLL calls LoadImage() in ThreadFocusSink.
|
|
// But it needs loader lock because it calls
|
|
// GetModuleFileName().
|
|
//
|
|
// So we can not call ThreadFocusSink while someone
|
|
// holds the loader lock.
|
|
//
|
|
if (_OwnedLoaderLockBySomeone() && !_InsideLoaderLock())
|
|
{
|
|
Assert(0);
|
|
DWORD dwCurrentThread = GetCurrentThreadId();
|
|
if (GetSharedMemory()->dwFocusThread != dwCurrentThread)
|
|
{
|
|
PostThreadMessage(dwCurrentThread,
|
|
g_msgPrivate,
|
|
TFPRIV_ONKILLTHREADFOCUS,
|
|
0);
|
|
}
|
|
break;
|
|
}
|
|
// fall through...
|
|
case TFPRIV_ONSETTHREADFOCUS:
|
|
if (psfn && (ptim = CThreadInputMgr::_GetThisFromSYSTHREAD(psfn)))
|
|
{
|
|
ptim->_OnThreadFocus(pmsg->wParam == TFPRIV_ONSETTHREADFOCUS);
|
|
}
|
|
break;
|
|
|
|
case TFPRIV_UPDATEDISPATTR:
|
|
if (psfn && (ptim = CThreadInputMgr::_GetThisFromSYSTHREAD(psfn)))
|
|
{
|
|
ptim->UpdateDispAttr();
|
|
}
|
|
break;
|
|
|
|
case TFPRIV_LANGCHANGE:
|
|
if (psfn && psfn->plbim && psfn->plbim->_GetLBarItemCtrl())
|
|
{
|
|
BOOL bRet = ActivateNextAssembly((BOOL)(pmsg->lParam));
|
|
}
|
|
break;
|
|
|
|
case TFPRIV_KEYTIPCHANGE:
|
|
if (psfn && psfn->plbim && psfn->plbim->_GetLBarItemCtrl())
|
|
{
|
|
ActivateNextKeyTip((BOOL)(pmsg->lParam));
|
|
}
|
|
break;
|
|
|
|
case TFPRIV_GLOBALCOMPARTMENTSYNC:
|
|
if (psfn)
|
|
{
|
|
if (psfn->_pGlobalCompMgr)
|
|
psfn->_pGlobalCompMgr->NotifyGlobalCompartmentChange((DWORD)(pmsg->lParam));
|
|
}
|
|
break;
|
|
|
|
case TFPRIV_SETMODALLBAR:
|
|
SetModalLBarId(HIWORD((DWORD)pmsg->lParam),
|
|
LOWORD((DWORD)pmsg->lParam));
|
|
break;
|
|
|
|
case TFPRIV_RELEASEMODALLBAR:
|
|
SetModalLBarId(-1, -1);
|
|
break;
|
|
|
|
case TFPRIV_UPDATE_REG_KBDTOGGLE:
|
|
InitLangChangeHotKey();
|
|
break;
|
|
|
|
case TFPRIV_UPDATE_REG_IMX:
|
|
UpdateRegIMXHandler();
|
|
break;
|
|
|
|
case TFPRIV_REGISTEREDNEWLANGBAR:
|
|
// TraceMsg(TF_GENERAL, "TFPRIV_REGISTEREDNEWLANGBAR current thread %x", GetCurrentThreadId());
|
|
MakeSetFocusNotify(g_msgSetFocus, 0, 0);
|
|
break;
|
|
|
|
case TFPRIV_SYSCOLORCHANGED:
|
|
if (psfn)
|
|
FlushIconIndex(psfn);
|
|
|
|
break;
|
|
|
|
case TFPRIV_LOCKREQ:
|
|
if (psfn)
|
|
{
|
|
psfn->_fLockRequestPosted = FALSE;
|
|
CInputContext::_PostponeLockRequestCallback(psfn, NULL);
|
|
}
|
|
break;
|
|
|
|
case TFPRIV_POSTINPUTCHANGEREQUEST:
|
|
PostInputChangeRequestHandler();
|
|
break;
|
|
|
|
case TFPRIV_LANGBARCLOSED:
|
|
LangBarClosed();
|
|
break;
|
|
|
|
case TFPRIV_ACTIVATELANG:
|
|
ActivateAssembly((LANGID)pmsg->lParam, ACTASM_NONE);
|
|
break;
|
|
|
|
case TFPRIV_ENABLE_MSAA:
|
|
if (psfn && (ptim = CThreadInputMgr::_GetThisFromSYSTHREAD(psfn)))
|
|
{
|
|
ptim->_InitMSAA();
|
|
}
|
|
break;
|
|
|
|
case TFPRIV_DISABLE_MSAA:
|
|
if (psfn && (ptim = CThreadInputMgr::_GetThisFromSYSTHREAD(psfn)))
|
|
{
|
|
ptim->_UninitMSAA();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if ((uMsg == g_msgSetFocus) ||
|
|
(uMsg == g_msgThreadTerminate) ||
|
|
(uMsg == g_msgThreadItemChange) ||
|
|
(uMsg == g_msgShowFloating) ||
|
|
(uMsg == g_msgLBUpdate))
|
|
{
|
|
SetFocusNotifyHandler(uMsg, pmsg->wParam, pmsg->lParam);
|
|
}
|
|
else if (uMsg == g_msgLBarModal)
|
|
{
|
|
DispatchModalLBar((DWORD)pmsg->wParam, pmsg->lParam);
|
|
}
|
|
#ifdef DEBUG
|
|
else if ((uMsg == g_msgRpcSendReceive) ||
|
|
#ifdef POINTER_MARSHAL
|
|
(uMsg == g_msgPointerMarshal) ||
|
|
#endif // POINTER_MARSHAL
|
|
(uMsg == g_msgThreadMarshal) ||
|
|
(uMsg == g_msgStubCleanUp))
|
|
{
|
|
if (!pmsg->hwnd)
|
|
{
|
|
Assert(0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// StartKanaCapsUpdateTimer
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void StartKanaCapsUpdateTimer(SYSTHREAD *psfn)
|
|
{
|
|
if (GetCurrentAssemblyLangId(psfn) != 0x0411)
|
|
return;
|
|
|
|
if (!IsWindow(psfn->hwndMarshal))
|
|
return;
|
|
|
|
SetTimer(psfn->hwndMarshal, MARSHALWND_TIMER_UPDATEKANACAPS, 300, NULL);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// KanaCapsUpdate
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void KanaCapsUpdate(SYSTHREAD *psfn)
|
|
{
|
|
static SHORT g_sCaps = 0;
|
|
static SHORT g_sKana = 0;
|
|
|
|
if (GetCurrentAssemblyLangId(psfn) != 0x0411)
|
|
return;
|
|
|
|
SHORT sCaps = g_sCaps;
|
|
SHORT sKana = g_sKana;
|
|
g_sCaps = GetKeyState(VK_CAPITAL) & 0x01;
|
|
g_sKana = GetKeyState(VK_KANA) & 0x01;
|
|
|
|
//
|
|
// if psfn->fInitCapsKanaIndicator is true, it is enough to make a
|
|
// notification only when status is changed.
|
|
//
|
|
if ((sCaps != g_sCaps) ||
|
|
(sKana != g_sKana) ||
|
|
!psfn->fInitCapsKanaIndicator)
|
|
{
|
|
MakeSetFocusNotify(g_msgLBUpdate, TF_LBU_CAPSKANAKEY,
|
|
(LPARAM)((g_sCaps ? TF_LBUF_CAPS : 0) |
|
|
(g_sKana ? TF_LBUF_KANA : 0)));
|
|
|
|
psfn->fInitCapsKanaIndicator = TRUE;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CheckKoreanMouseClick
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL CheckKoreanMouseClick(SYSTHREAD *psfn, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
//
|
|
// check KeyUp and VK_PROCESSKEY
|
|
//
|
|
if (!(HIWORD(lParam) & KF_UP) || ((wParam & 0xff) != VK_PROCESSKEY))
|
|
return FALSE;
|
|
|
|
//
|
|
// if the current language is not 0x412, return.
|
|
//
|
|
if (GetCurrentAssemblyLangId(psfn) != 0x412)
|
|
return FALSE;
|
|
|
|
//
|
|
// If toolbar is clicked, we eat this VK_PROCESSKEY.
|
|
//
|
|
POINT pt;
|
|
HWND hwnd;
|
|
if (!GetCursorPos(&pt))
|
|
return FALSE;
|
|
|
|
hwnd = WindowFromPoint(pt);
|
|
if (!hwnd)
|
|
return FALSE;
|
|
|
|
DWORD dwTimFlags = g_timlist.GetFlags(GetWindowThreadProcessId(hwnd, NULL));
|
|
|
|
return (dwTimFlags & TLF_CTFMONPROCESS) ? TRUE : FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsJapaneseNonIMEVKKANJI
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL IsJapaneseNonIMEVKKANJI(WPARAM wParam)
|
|
{
|
|
if ((wParam & 0xff) != VK_KANJI)
|
|
return FALSE;
|
|
|
|
HKL hkl = GetKeyboardLayout(0);
|
|
if (IsPureIMEHKL(hkl))
|
|
return FALSE;
|
|
|
|
if (PRIMARYLANGID(LANGIDFROMHKL(hkl)) != LANG_JAPANESE)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsKoreanNonIMEVKJUNJA
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL IsKoreanNonIMEVKJUNJA(WPARAM wParam)
|
|
{
|
|
if ((wParam & 0xff) != VK_JUNJA)
|
|
return FALSE;
|
|
|
|
HKL hkl = GetKeyboardLayout(0);
|
|
if (IsPureIMEHKL(hkl))
|
|
return FALSE;
|
|
|
|
if (PRIMARYLANGID(LANGIDFROMHKL(hkl)) != LANG_KOREAN)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ThreadKeyboardProc
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
//
|
|
// Workaround for global keyboard hook
|
|
//
|
|
// On IA64 platform, Cicero install two global keyboard hooks which is 64bit and 32bit code.
|
|
// When any keyboard event occur on one apps instance, there two global keyboard hook procedure
|
|
// (SysKeyboardProc) called from win32k xxxCallHook2.
|
|
// If xxxCallHook2 detect different instance between current and receiver which is 64bit and 32bit,
|
|
// this function notify by InterSendMsg.
|
|
//
|
|
LRESULT CALLBACK ThreadKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HHOOK hHook = NULL;
|
|
UINT ret = 0;
|
|
SYSTHREAD *psfn = GetSYSTHREAD();
|
|
|
|
if (psfn)
|
|
hHook = psfn->hThreadKeyboardHook;
|
|
|
|
if (g_fDllProcessDetached)
|
|
goto Exit;
|
|
|
|
if (nCode == HC_ACTION)
|
|
{
|
|
_try
|
|
{
|
|
ret = _KeyboardHook(wParam, lParam);
|
|
}
|
|
_except(CicExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
Assert(0);
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
if ((ret == 0) && hHook)
|
|
return CallNextHookEx(hHook, nCode, wParam, lParam);
|
|
else
|
|
return ret;
|
|
}
|
|
|
|
UINT _KeyboardHook(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
SYSTHREAD *psfn = GetSYSTHREAD();
|
|
CThreadInputMgr *ptim = NULL;
|
|
BOOL fEaten;
|
|
HRESULT hr;
|
|
|
|
if (psfn)
|
|
ptim = CThreadInputMgr::_GetThisFromSYSTHREAD(psfn);
|
|
|
|
//
|
|
// If we're in Modal Lang bar mode (menu is shown.),
|
|
// we want to eat keys.
|
|
//
|
|
if (HandleModalLBar((HIWORD(lParam) & KF_UP) ? WM_KEYUP : WM_KEYDOWN,
|
|
wParam, lParam))
|
|
return 1;
|
|
|
|
|
|
if (CheckKoreanMouseClick(psfn, wParam, lParam))
|
|
return 1;
|
|
|
|
UpdateModifiers(wParam, lParam);
|
|
|
|
if ((HIWORD(lParam) & KF_UP))
|
|
StartKanaCapsUpdateTimer(psfn);
|
|
|
|
if (psfn)
|
|
{
|
|
if (CheckLangChangeHotKey(psfn, wParam, lParam))
|
|
{
|
|
//
|
|
// Cic#4645 We need to forward this key envent ot the next hook.
|
|
// mstsc.exe (TS client) needs it.
|
|
//
|
|
return 0;
|
|
// goto Exit;
|
|
// return 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// On CUAS, Imm32's Hotkey is simulated in ImmProcessKey
|
|
//
|
|
if (!psfn || !CtfImmIsCiceroStartedInThread())
|
|
CheckImm32HotKey(wParam, lParam);
|
|
|
|
if (HandleDBEKeys(wParam, lParam))
|
|
{
|
|
//
|
|
// #519671
|
|
//
|
|
// If there is a focus DIM and the current asm item is not Japanese
|
|
// TIP, we switch the assembly to Japanese TIP and open it.
|
|
//
|
|
// we do this after calling HandleDBEKeys(). So TIP's keyboard
|
|
// event sink for VK_KANJI won't be called.
|
|
//
|
|
if (IsJapaneseNonIMEVKKANJI(wParam))
|
|
ToggleJImeNoIme(psfn);
|
|
|
|
//
|
|
// Cic#4645 We need to forward this key envent ot the next hook.
|
|
// mstsc.exe (TS client) needs it.
|
|
//
|
|
return 0;
|
|
// goto Exit;
|
|
// return 1;
|
|
}
|
|
|
|
if (ptim)
|
|
{
|
|
ptim->_NotifyKeyTraceEventSink(wParam, lParam);
|
|
|
|
if (ptim->_ProcessHotKey(wParam, lParam, TSH_SYSHOTKEY, FALSE, FALSE))
|
|
return 1;
|
|
|
|
//
|
|
// give AIMM the key events.
|
|
//
|
|
if (ptim->GetSysHookSink())
|
|
{
|
|
hr = ptim->GetSysHookSink()->OnSysKeyboardProc(wParam, lParam);
|
|
if (hr == S_OK)
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// At last we can call KeyStrokemMgr.
|
|
//
|
|
if (!ptim->_AppWantsKeystrokes() &&
|
|
ptim->_IsKeystrokeFeedEnabled() &&
|
|
wParam != VK_PROCESSKEY &&
|
|
(!(HIWORD(lParam) & (KF_MENUMODE | KF_ALTDOWN)) || IsKoreanNonIMEVKJUNJA(wParam)))
|
|
{
|
|
hr = (HIWORD(lParam) & KF_UP) ? ptim->KeyUp(wParam, lParam, &fEaten) :
|
|
ptim->KeyDown(wParam, lParam, &fEaten);
|
|
|
|
if (hr == S_OK && fEaten)
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// F10 SysKeyDown work arround.
|
|
//
|
|
// KSMGR won't be called on WM_SYSKEYDOWN/UP. So we foward F10
|
|
// through AsynKeyHandler to support SyncLock in KS callback.
|
|
//
|
|
// we don't have to do this if there is no foreground keyboard tip.
|
|
//
|
|
if (((wParam & 0xff) == VK_F10) &&
|
|
(ptim->GetForegroundKeyboardTip() != TF_INVALID_GUIDATOM))
|
|
{
|
|
fEaten = FALSE;
|
|
if (ptim->_AsyncKeyHandler(wParam,
|
|
lParam,
|
|
TIM_AKH_SIMULATEKEYMSGS,
|
|
&fEaten) && fEaten)
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ThreadMouseProc
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
LRESULT CALLBACK ThreadMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HHOOK hHook = NULL;
|
|
SYSTHREAD *psfn = GetSYSTHREAD();
|
|
|
|
if (psfn)
|
|
hHook = psfn->hThreadMouseHook;
|
|
|
|
if (g_fDllProcessDetached)
|
|
goto Exit;
|
|
|
|
if (nCode == HC_ACTION)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
if ((wParam == WM_MOUSEMOVE) || (wParam == WM_NCMOUSEMOVE))
|
|
goto Exit;
|
|
|
|
_try
|
|
{
|
|
bRet = HandleModalLBar((UINT)wParam, 0,
|
|
MAKELPARAM(((MOUSEHOOKSTRUCT *)lParam)->pt.x,
|
|
((MOUSEHOOKSTRUCT *)lParam)->pt.y));
|
|
}
|
|
_except(CicExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
Assert(0);
|
|
}
|
|
|
|
if (bRet)
|
|
return 1;
|
|
}
|
|
|
|
Exit:
|
|
if (hHook)
|
|
return CallNextHookEx(hHook, nCode, wParam, lParam);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UninitHooks
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void UninitHooks()
|
|
{
|
|
HHOOK _h;
|
|
|
|
if ( (_h = GetSharedMemory()->hSysShellHook.GetHandle(g_bOnWow64)) != NULL)
|
|
{
|
|
UnhookWindowsHookEx(_h);
|
|
GetSharedMemory()->hSysShellHook.SetHandle(g_bOnWow64, NULL);
|
|
}
|
|
|
|
if ( (_h = GetSharedMemory()->hSysCBTHook.GetHandle(g_bOnWow64)) != NULL)
|
|
{
|
|
UnhookWindowsHookEx(_h);
|
|
GetSharedMemory()->hSysCBTHook.SetHandle(g_bOnWow64, NULL);
|
|
}
|
|
|
|
if ( (_h = GetSharedMemory()->hSysGetMsgHook.GetHandle(g_bOnWow64)) != NULL)
|
|
{
|
|
UnhookWindowsHookEx(_h);
|
|
GetSharedMemory()->hSysGetMsgHook.SetHandle(g_bOnWow64, NULL);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InitHooks
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void InitHooks()
|
|
{
|
|
Assert(! GetSharedMemory()->hSysShellHook.GetHandle(g_bOnWow64));
|
|
GetSharedMemory()->hSysShellHook.SetHandle(g_bOnWow64, SetWindowsHookEx(WH_SHELL, SysShellProc, g_hInst, 0));
|
|
|
|
//
|
|
// nb: we could move GetMsgHook to per-thread hook if we get rid of
|
|
// TFPRIV_MARSHALINTERFACE for non-cicero apps.
|
|
// TFPRIV_MARSHALINTERFACE is necesary because Tipbar does not
|
|
// know if the target thread has TIM. If there is no TIP or
|
|
// the GetMsgHook, the tipbar waits until timeout.
|
|
// To solve this problem, we must have TIM's thread list
|
|
// in shared mem. Maybe we should do this.
|
|
//
|
|
Assert(! GetSharedMemory()->hSysGetMsgHook.GetHandle(g_bOnWow64));
|
|
if (IsOnNT())
|
|
{
|
|
// we need a W hook on NT to work-around an os dbcs/unicode translation bug (4243)
|
|
GetSharedMemory()->hSysGetMsgHook.SetHandle(g_bOnWow64, SetWindowsHookExW(WH_GETMESSAGE, SysGetMsgProc, g_hInst, 0));
|
|
}
|
|
else
|
|
{
|
|
GetSharedMemory()->hSysGetMsgHook.SetHandle(g_bOnWow64, SetWindowsHookExA(WH_GETMESSAGE, SysGetMsgProc, g_hInst, 0));
|
|
}
|
|
|
|
Assert(! GetSharedMemory()->hSysCBTHook.GetHandle(g_bOnWow64));
|
|
GetSharedMemory()->hSysCBTHook.SetHandle(g_bOnWow64, SetWindowsHookEx(WH_CBT, SysCBTProc, g_hInst, 0));
|
|
|
|
InitStaticHooks();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InitThreadHooks
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void InitThreadHook(DWORD dwThreadId)
|
|
{
|
|
SYSTHREAD *psfn = GetSYSTHREAD();
|
|
if (!psfn)
|
|
return;
|
|
|
|
if (psfn->hThreadKeyboardHook && psfn->hThreadMouseHook)
|
|
return;
|
|
|
|
PVOID pvLdrLockCookie = NULL;
|
|
ULONG ulLockState = 0;
|
|
|
|
// make sure that no one else owns the loader lock because we
|
|
// could otherwise deadlock
|
|
LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY, &ulLockState,
|
|
&pvLdrLockCookie);
|
|
if (ulLockState == LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED)
|
|
{
|
|
__try {
|
|
if (!psfn->hThreadKeyboardHook)
|
|
{
|
|
//
|
|
// Install Local keyboard hook with hMod value.
|
|
// win32k mantain hMod ref count even another global hook
|
|
// detached.
|
|
//
|
|
psfn->hThreadKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, ThreadKeyboardProc, g_hInst, dwThreadId);
|
|
|
|
}
|
|
if (!psfn->hThreadMouseHook)
|
|
{
|
|
//
|
|
// Install Local keyboard hook with hMod value.
|
|
// win32k mantain hMod ref count even another global hook
|
|
// detached.
|
|
//
|
|
psfn->hThreadMouseHook = SetWindowsHookEx(WH_MOUSE, ThreadMouseProc, g_hInst, dwThreadId);
|
|
}
|
|
|
|
}
|
|
_except(CicExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
}
|
|
LdrUnlockLoaderLock(0, pvLdrLockCookie);
|
|
}
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UninitThreadHooks
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void UninitThreadHooks(SYSTHREAD *psfn)
|
|
{
|
|
if (!psfn)
|
|
return;
|
|
|
|
if (psfn->hThreadKeyboardHook)
|
|
{
|
|
UnhookWindowsHookEx(psfn->hThreadKeyboardHook);
|
|
psfn->hThreadKeyboardHook = NULL;
|
|
}
|
|
if (psfn->hThreadMouseHook)
|
|
{
|
|
UnhookWindowsHookEx(psfn->hThreadMouseHook);
|
|
psfn->hThreadMouseHook = NULL;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// TF_InitSystem
|
|
//
|
|
// Called by ctfmon on a single thread.
|
|
//+---------------------------------------------------------------------------
|
|
|
|
extern "C" BOOL WINAPI TF_InitSystem(void)
|
|
{
|
|
SYSTHREAD *psfn;
|
|
|
|
g_fCTFMONProcess = TRUE;
|
|
g_timlist.Init(TRUE);
|
|
if (psfn = GetSYSTHREAD())
|
|
{
|
|
g_gcomplist.Init(psfn);
|
|
|
|
EnsureAsmCacheFileMap();
|
|
EnsureAssemblyList(psfn);
|
|
psfn->fCTFMON = TRUE;
|
|
}
|
|
|
|
InitHooks();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// TF_UninitSystem
|
|
//
|
|
// Called by ctfmon on a single thread.
|
|
//+---------------------------------------------------------------------------
|
|
|
|
extern "C" BOOL WINAPI TF_UninitSystem(void)
|
|
{
|
|
CThreadMarshalWnd::DestroyAll();
|
|
|
|
UninitAsmCacheFileMap();
|
|
|
|
g_timlist.Uninit();
|
|
|
|
SYSTHREAD *psfn = FindSYSTHREAD();
|
|
g_gcomplist.Uninit(psfn);
|
|
|
|
UninitHooks();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// TF_InitThreadSystem
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL TF_InitThreadSystem(void)
|
|
{
|
|
DWORD dwThreadId = GetCurrentThreadId();
|
|
|
|
//
|
|
// we should not see the timlist entry of this thread. This thread
|
|
// is starting now.
|
|
// the thread with same ID was terminated incorrectly so there was no
|
|
// chance to clean timlist up.
|
|
//
|
|
|
|
if (g_timlist.IsThreadId(dwThreadId))
|
|
{
|
|
g_timlist.RemoveThread(dwThreadId);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// TF_UninitThreadSystem
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL TF_UninitThreadSystem(void)
|
|
{
|
|
SYSTHREAD *psfn = FindSYSTHREAD();
|
|
|
|
g_gcomplist.Uninit(psfn);
|
|
|
|
FreeSYSTHREAD();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UninitProcess()
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void UninitProcess()
|
|
{
|
|
DWORD dwProcessId = GetCurrentProcessId();
|
|
|
|
//
|
|
// FreeSYSTHREAD2() removes psfn from PtrArray.
|
|
//
|
|
if (g_rgSysThread)
|
|
{
|
|
|
|
while(g_rgSysThread->Count())
|
|
{
|
|
SYSTHREAD *psfn = g_rgSysThread->Get(0);
|
|
if (psfn)
|
|
FreeSYSTHREAD2(psfn);
|
|
}
|
|
delete g_rgSysThread;
|
|
g_rgSysThread = NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// remove all timlist entries for the current process.
|
|
//
|
|
g_timlist.RemoveProcess(dwProcessId);
|
|
|
|
|
|
CCategoryMgr::UninitGlobal();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InitAppCompatFlags
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
BOOL InitAppCompatFlags()
|
|
{
|
|
TCHAR szAppCompatKey[MAX_PATH];
|
|
TCHAR szFileName[MAX_PATH];
|
|
if (::GetModuleFileName(NULL, // handle to module
|
|
szFileName, // file name of module
|
|
sizeof(szFileName)/sizeof(TCHAR)) == 0)
|
|
return FALSE;
|
|
|
|
TCHAR szModuleName[MAX_PATH];
|
|
LPTSTR pszFilePart = NULL;
|
|
::GetFullPathName(szFileName, // file name
|
|
sizeof(szModuleName)/sizeof(TCHAR),
|
|
szModuleName, // path buffer
|
|
&pszFilePart); // address of file name in path
|
|
|
|
if (pszFilePart == NULL)
|
|
return FALSE;
|
|
|
|
|
|
StringCopyArray(szAppCompatKey, c_szAppCompat);
|
|
StringCatArray(szAppCompatKey, pszFilePart);
|
|
CMyRegKey key;
|
|
if (key.Open(HKEY_LOCAL_MACHINE, szAppCompatKey, KEY_READ) == S_OK)
|
|
{
|
|
DWORD dw;
|
|
if (key.QueryValue(dw, c_szCompatibility) == S_OK)
|
|
g_dwAppCompatibility = dw;
|
|
}
|
|
|
|
//
|
|
// Ciero #4605
|
|
//
|
|
// hack for 16bit apps on Win9x platform.
|
|
// all 16bit apps shrare one PPI (process info) and this means that
|
|
// there is one main thread for WaitForInputIdle() for all 16 bit apps.
|
|
// so we stop using WaitForInputIdle().
|
|
//
|
|
if (!IsOnNT())
|
|
{
|
|
if (!lstrcmpi(pszFilePart, "kernel32.dll"))
|
|
g_dwAppCompatibility |= CIC_COMPAT_NOWAITFORINPUTIDLEONWIN9X;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InitCUASFlag
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
void InitCUASFlag()
|
|
{
|
|
CMyRegKey key;
|
|
CMyRegKey keyIMM;
|
|
if (key.Open(HKEY_LOCAL_MACHINE, c_szCtfShared, KEY_READ) == S_OK)
|
|
{
|
|
DWORD dw;
|
|
if (key.QueryValue(dw, c_szCUAS) == S_OK)
|
|
g_fCUAS = dw ? TRUE : FALSE;
|
|
}
|
|
|
|
g_szCUASImeFile[0] = '\0';
|
|
if (g_fCUAS)
|
|
{
|
|
if (keyIMM.Open(HKEY_LOCAL_MACHINE, c_szIMMKey, KEY_READ) == S_OK)
|
|
{
|
|
TCHAR szCUASImeFile[16];
|
|
if (keyIMM.QueryValueCch(szCUASImeFile, c_szCUASIMEFile, ARRAYSIZE(szCUASImeFile)) == S_OK)
|
|
lstrcpy(g_szCUASImeFile, szCUASImeFile);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// TF_DllDetachInOther
|
|
//
|
|
//+---------------------------------------------------------------------------
|
|
|
|
extern "C" BOOL WINAPI TF_DllDetachInOther()
|
|
{
|
|
SYSTHREAD *psfn = FindSYSTHREAD();
|
|
|
|
if (psfn)
|
|
psfn->fCUASDllDetachInOtherOrMe = TRUE;
|
|
|
|
return TRUE;
|
|
}
|