reactos/dll/ime/msctfime/msctfime.cpp

931 lines
21 KiB
C++
Raw Normal View History

/*
* PROJECT: ReactOS msctfime.ime
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
* PURPOSE: Supporting IME interface of Text Input Processors (TIPs)
* COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#include "msctfime.h"
#include <ndk/ldrfuncs.h> /* for RtlDllShutdownInProgress */
WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
typedef CicArray<GUID> CDispAttrPropCache;
HINSTANCE g_hInst = NULL; /* The instance of this module */
BOOL g_bWinLogon = FALSE;
UINT g_uACP = CP_ACP;
DWORD g_dwOSInfo = 0;
BOOL gfTFInitLib = FALSE;
CRITICAL_SECTION g_csLock;
CDispAttrPropCache *g_pPropCache = NULL;
EXTERN_C void __cxa_pure_virtual(void)
{
ERR("__cxa_pure_virtual\n");
}
typedef BOOLEAN (WINAPI *FN_DllShutdownInProgress)(VOID);
/// This function calls ntdll!RtlDllShutdownInProgress.
/// It can detect the system is shutting down or not.
/// @implemented
EXTERN_C BOOLEAN WINAPI DllShutdownInProgress(VOID)
{
HMODULE hNTDLL;
static FN_DllShutdownInProgress s_fnDllShutdownInProgress = NULL;
if (s_fnDllShutdownInProgress)
return s_fnDllShutdownInProgress();
hNTDLL = cicGetSystemModuleHandle(L"ntdll.dll", FALSE);
s_fnDllShutdownInProgress =
(FN_DllShutdownInProgress)GetProcAddress(hNTDLL, "RtlDllShutdownInProgress");
if (!s_fnDllShutdownInProgress)
return FALSE;
return s_fnDllShutdownInProgress();
}
/// This function checks if the current user logon session is interactive.
/// @implemented
static BOOL
IsInteractiveUserLogon(VOID)
{
BOOL bOK, IsMember = FALSE;
PSID pSid;
SID_IDENTIFIER_AUTHORITY IdentAuth = { SECURITY_NT_AUTHORITY };
if (!AllocateAndInitializeSid(&IdentAuth, 1, SECURITY_INTERACTIVE_RID,
0, 0, 0, 0, 0, 0, 0, &pSid))
{
ERR("Error: %ld\n", GetLastError());
return FALSE;
}
bOK = CheckTokenMembership(NULL, pSid, &IsMember);
if (pSid)
FreeSid(pSid);
return bOK && IsMember;
}
/// @implemented
ITfCategoryMgr *GetUIMCat(PCIC_LIBTHREAD pLibThread)
{
if (!pLibThread)
return NULL;
if (pLibThread->m_pCategoryMgr)
return pLibThread->m_pCategoryMgr;
if (FAILED(cicCoCreateInstance(CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER,
IID_ITfCategoryMgr, (void **)&pLibThread->m_pCategoryMgr)))
{
return NULL;
}
return pLibThread->m_pCategoryMgr;
}
/// @implemented
HRESULT LibEnumItemsInCategory(PCIC_LIBTHREAD pLibThread, REFGUID rguid, IEnumGUID **ppEnum)
{
ITfCategoryMgr *pCat = GetUIMCat(pLibThread);
if (!pCat)
return E_FAIL;
return pCat->EnumItemsInCategory(rguid, ppEnum);
}
/// @implemented
HRESULT InitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread)
{
if (!pLibThread)
return E_FAIL;
if (pLibThread->m_pDisplayAttrMgr)
{
pLibThread->m_pDisplayAttrMgr->Release();
pLibThread->m_pDisplayAttrMgr = NULL;
}
if (FAILED(cicCoCreateInstance(CLSID_TF_DisplayAttributeMgr, NULL, CLSCTX_INPROC_SERVER,
IID_ITfDisplayAttributeMgr,
(void **)&pLibThread->m_pDisplayAttrMgr)))
{
return E_FAIL;
}
IEnumGUID *pEnumGuid;
LibEnumItemsInCategory(pLibThread, GUID_TFCAT_DISPLAYATTRIBUTEPROPERTY, &pEnumGuid);
HRESULT hr = E_OUTOFMEMORY;
::EnterCriticalSection(&g_csLock);
if (pEnumGuid && !g_pPropCache)
{
g_pPropCache = new(cicNoThrow) CDispAttrPropCache();
if (g_pPropCache)
{
g_pPropCache->Add(GUID_PROP_ATTRIBUTE);
GUID guid;
while (pEnumGuid->Next(1, &guid, NULL) == S_OK)
{
if (!IsEqualGUID(guid, GUID_PROP_ATTRIBUTE))
g_pPropCache->Add(guid);
}
hr = S_OK;
}
}
::LeaveCriticalSection(&g_csLock);
return hr;
}
/// @implemented
HRESULT UninitDisplayAttrbuteLib(PCIC_LIBTHREAD pLibThread)
{
if (!pLibThread)
return E_FAIL;
if (pLibThread->m_pDisplayAttrMgr)
{
pLibThread->m_pDisplayAttrMgr->Release();
pLibThread->m_pDisplayAttrMgr = NULL;
}
return S_OK;
}
/// Gets the charset from a language ID.
/// @implemented
BYTE GetCharsetFromLangId(_In_ DWORD dwValue)
{
CHARSETINFO info;
if (!::TranslateCharsetInfo((DWORD*)(DWORD_PTR)dwValue, &info, TCI_SRCLOCALE))
return 0;
return info.ciCharset;
}
/// Selects or unselects the input context.
/// @implemented
HRESULT
InternalSelectEx(
_In_ HIMC hIMC,
_In_ BOOL fSelect,
_In_ LANGID LangID)
{
CicIMCLock imcLock(hIMC);
if (FAILED(imcLock.m_hr))
return imcLock.m_hr;
if (PRIMARYLANGID(LangID) == LANG_CHINESE)
{
imcLock.get().cfCandForm[0].dwStyle = 0;
imcLock.get().cfCandForm[0].dwIndex = (DWORD)-1;
}
if (!fSelect)
{
imcLock.get().fdwInit &= ~INIT_GUIDMAP;
return imcLock.m_hr;
}
if (!imcLock.ClearCand())
return imcLock.m_hr;
// Populate conversion mode
if (!(imcLock.get().fdwInit & INIT_CONVERSION))
{
DWORD dwConv = (imcLock.get().fdwConversion & IME_CMODE_SOFTKBD);
if (LangID)
{
if (PRIMARYLANGID(LangID) == LANG_JAPANESE)
{
dwConv |= IME_CMODE_ROMAN | IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE;
}
else if (PRIMARYLANGID(LangID) != LANG_KOREAN)
{
dwConv |= IME_CMODE_NATIVE;
}
}
imcLock.get().fdwConversion |= dwConv;
imcLock.get().fdwInit |= INIT_CONVERSION;
}
// Populate sentence mode
imcLock.get().fdwSentence |= IME_SMODE_PHRASEPREDICT;
// Populate LOGFONT
if (!(imcLock.get().fdwInit & INIT_LOGFONT))
{
// Get logical font
LOGFONTW lf;
HDC hDC = ::GetDC(imcLock.get().hWnd);
HGDIOBJ hFont = GetCurrentObject(hDC, OBJ_FONT);
::GetObjectW(hFont, sizeof(LOGFONTW), &lf);
::ReleaseDC(imcLock.get().hWnd, hDC);
imcLock.get().lfFont.W = lf;
imcLock.get().fdwInit |= INIT_LOGFONT;
}
imcLock.get().lfFont.W.lfCharSet = GetCharsetFromLangId(LangID);
imcLock.InitContext();
return imcLock.m_hr;
}
class TLS;
/***********************************************************************
* ImeInquire (MSCTFIME.@)
*
* MSCTFIME's ImeInquire does nothing.
*
* @implemented
* @see CtfImeInquireExW
*/
EXTERN_C
BOOL WINAPI
ImeInquire(
_Out_ LPIMEINFO lpIMEInfo,
_Out_ LPWSTR lpszWndClass,
_In_ DWORD dwSystemInfoFlags)
{
TRACE("(%p, %p, 0x%lX)\n", lpIMEInfo, lpszWndClass, dwSystemInfoFlags);
return FALSE;
}
/***********************************************************************
* ImeConversionList (MSCTFIME.@)
*
* MSCTFIME's ImeConversionList does nothing.
*
* @implemented
* @see ImmGetConversionListW
*/
EXTERN_C DWORD WINAPI
ImeConversionList(
_In_ HIMC hIMC,
_In_ LPCWSTR lpSrc,
_Out_ LPCANDIDATELIST lpDst,
_In_ DWORD dwBufLen,
_In_ UINT uFlag)
{
TRACE("(%p, %s, %p, 0x%lX, %u)\n", hIMC, debugstr_w(lpSrc), lpDst, dwBufLen, uFlag);
return 0;
}
/***********************************************************************
* ImeRegisterWord (MSCTFIME.@)
*
* MSCTFIME's ImeRegisterWord does nothing.
*
* @implemented
* @see ImeUnregisterWord
*/
EXTERN_C BOOL WINAPI
ImeRegisterWord(
_In_ LPCWSTR lpszReading,
_In_ DWORD dwStyle,
_In_ LPCWSTR lpszString)
{
TRACE("(%s, 0x%lX, %s)\n", debugstr_w(lpszReading), dwStyle, debugstr_w(lpszString));
return FALSE;
}
/***********************************************************************
* ImeUnregisterWord (MSCTFIME.@)
*
* MSCTFIME's ImeUnregisterWord does nothing.
*
* @implemented
* @see ImeRegisterWord
*/
EXTERN_C BOOL WINAPI
ImeUnregisterWord(
_In_ LPCWSTR lpszReading,
_In_ DWORD dwStyle,
_In_ LPCWSTR lpszString)
{
TRACE("(%s, 0x%lX, %s)\n", debugstr_w(lpszReading), dwStyle, debugstr_w(lpszString));
return FALSE;
}
/***********************************************************************
* ImeGetRegisterWordStyle (MSCTFIME.@)
*
* MSCTFIME's ImeGetRegisterWordStyle does nothing.
*
* @implemented
* @see ImeRegisterWord
*/
EXTERN_C UINT WINAPI
ImeGetRegisterWordStyle(
_In_ UINT nItem,
_Out_ LPSTYLEBUFW lpStyleBuf)
{
TRACE("(%u, %p)\n", nItem, lpStyleBuf);
return 0;
}
/***********************************************************************
* ImeEnumRegisterWord (MSCTFIME.@)
*
* MSCTFIME's ImeEnumRegisterWord does nothing.
*
* @implemented
* @see ImeRegisterWord
*/
EXTERN_C UINT WINAPI
ImeEnumRegisterWord(
_In_ REGISTERWORDENUMPROCW lpfnEnumProc,
_In_opt_ LPCWSTR lpszReading,
_In_ DWORD dwStyle,
_In_opt_ LPCWSTR lpszString,
_In_opt_ LPVOID lpData)
{
TRACE("(%p, %s, %lu, %s, %p)\n", lpfnEnumProc, debugstr_w(lpszReading),
dwStyle, debugstr_w(lpszString), lpData);
return 0;
}
EXTERN_C BOOL WINAPI
ImeConfigure(
_In_ HKL hKL,
_In_ HWND hWnd,
_In_ DWORD dwMode,
_Inout_opt_ LPVOID lpData)
{
TRACE("(%p, %p, %lu, %p)\n", hKL, hWnd, dwMode, lpData);
TLS *pTLS = TLS::GetTLS();
if (!pTLS || !pTLS->m_pBridge || !pTLS->m_pThreadMgr)
return FALSE;
CicBridge *pBridge = pTLS->m_pBridge;
ITfThreadMgr *pThreadMgr = pTLS->m_pThreadMgr;
if (dwMode & 1)
return (pBridge->ConfigureGeneral(pTLS, pThreadMgr, hKL, hWnd) == S_OK);
if (dwMode & 2)
return (pBridge->ConfigureRegisterWord(pTLS, pThreadMgr, hKL, hWnd, lpData) == S_OK);
return FALSE;
}
/***********************************************************************
* ImeDestroy (MSCTFIME.@)
*
* @implemented
*/
EXTERN_C BOOL WINAPI
ImeDestroy(
_In_ UINT uReserved)
{
TRACE("(%u)\n", uReserved);
TLS *pTLS = TLS::PeekTLS();
if (pTLS)
return FALSE;
if (!pTLS->m_pBridge || !pTLS->m_pThreadMgr)
return FALSE;
if (pTLS->m_dwSystemInfoFlags & IME_SYSINFO_WINLOGON)
return TRUE;
if (pTLS->m_pBridge->DeactivateIMMX(pTLS, pTLS->m_pThreadMgr) != S_OK)
return FALSE;
return pTLS->m_pBridge->UnInitIMMX(pTLS);
}
/***********************************************************************
* ImeEscape (MSCTFIME.@)
*
* MSCTFIME's ImeEscape does nothing.
*
* @implemented
* @see CtfImeEscapeEx
*/
EXTERN_C LRESULT WINAPI
ImeEscape(
_In_ HIMC hIMC,
_In_ UINT uEscape,
_Inout_opt_ LPVOID lpData)
{
TRACE("(%p, %u, %p)\n", hIMC, uEscape, lpData);
return 0;
}
EXTERN_C BOOL WINAPI
ImeProcessKey(
_In_ HIMC hIMC,
_In_ UINT uVirKey,
_In_ LPARAM lParam,
_In_ CONST LPBYTE lpbKeyState)
{
FIXME("stub:(%p, %u, %p, lpbKeyState)\n", hIMC, uVirKey, lParam, lpbKeyState);
return FALSE;
}
/***********************************************************************
* ImeSelect (MSCTFIME.@)
*
* MSCTFIME's ImeSelect does nothing.
*
* @implemented
* @see CtfImeSelectEx
*/
EXTERN_C BOOL WINAPI
ImeSelect(
_In_ HIMC hIMC,
_In_ BOOL fSelect)
{
TRACE("(%p, %u)\n", hIMC, fSelect);
return FALSE;
}
/***********************************************************************
* ImeSetActiveContext (MSCTFIME.@)
*
* MSCTFIME's ImeSetActiveContext does nothing.
*
* @implemented
* @see CtfImeSetActiveContextAlways
*/
EXTERN_C BOOL WINAPI
ImeSetActiveContext(
_In_ HIMC hIMC,
_In_ BOOL fFlag)
{
TRACE("(%p, %u)\n", hIMC, fFlag);
return FALSE;
}
EXTERN_C UINT WINAPI
ImeToAsciiEx(
_In_ UINT uVirKey,
_In_ UINT uScanCode,
_In_ CONST LPBYTE lpbKeyState,
_Out_ LPTRANSMSGLIST lpTransMsgList,
_In_ UINT fuState,
_In_ HIMC hIMC)
{
FIXME("stub:(%u, %u, %p, %p, %u, %p)\n", uVirKey, uScanCode, lpbKeyState, lpTransMsgList,
fuState, hIMC);
return 0;
}
EXTERN_C BOOL WINAPI
NotifyIME(
_In_ HIMC hIMC,
_In_ DWORD dwAction,
_In_ DWORD dwIndex,
_In_ DWORD_PTR dwValue)
{
FIXME("stub:(%p, 0x%lX, 0x%lX, %p)\n", hIMC, dwAction, dwIndex, dwValue);
return FALSE;
}
EXTERN_C BOOL WINAPI
ImeSetCompositionString(
_In_ HIMC hIMC,
_In_ DWORD dwIndex,
_In_opt_ LPCVOID lpComp,
_In_ DWORD dwCompLen,
_In_opt_ LPCVOID lpRead,
_In_ DWORD dwReadLen)
{
FIXME("stub:(%p, 0x%lX, %p, 0x%lX, %p, 0x%lX)\n", hIMC, dwIndex, lpComp, dwCompLen,
lpRead, dwReadLen);
return FALSE;
}
EXTERN_C DWORD WINAPI
ImeGetImeMenuItems(
_In_ HIMC hIMC,
_In_ DWORD dwFlags,
_In_ DWORD dwType,
_Inout_opt_ LPIMEMENUITEMINFOW lpImeParentMenu,
_Inout_opt_ LPIMEMENUITEMINFOW lpImeMenu,
_In_ DWORD dwSize)
{
FIXME("stub:(%p, 0x%lX, 0x%lX, %p, %p, 0x%lX)\n", hIMC, dwFlags, dwType, lpImeParentMenu,
lpImeMenu, dwSize);
return 0;
}
/***********************************************************************
* CtfImeInquireExW (MSCTFIME.@)
*
* @implemented
*/
EXTERN_C HRESULT WINAPI
CtfImeInquireExW(
_Out_ LPIMEINFO lpIMEInfo,
_Out_ LPWSTR lpszWndClass,
_In_ DWORD dwSystemInfoFlags,
_In_ HKL hKL)
{
TRACE("(%p, %p, 0x%lX, %p)\n", lpIMEInfo, lpszWndClass, dwSystemInfoFlags, hKL);
TLS *pTLS = TLS::GetTLS();
if (!pTLS)
return E_OUTOFMEMORY;
if (!IsInteractiveUserLogon())
{
dwSystemInfoFlags |= IME_SYSINFO_WINLOGON;
g_bWinLogon = TRUE;
}
pTLS->m_dwSystemInfoFlags = dwSystemInfoFlags;
return Inquire(lpIMEInfo, lpszWndClass, dwSystemInfoFlags, hKL);
}
/***********************************************************************
* CtfImeSelectEx (MSCTFIME.@)
*
* @implemented
*/
EXTERN_C BOOL WINAPI
CtfImeSelectEx(
_In_ HIMC hIMC,
_In_ BOOL fSelect,
_In_ HKL hKL)
{
TRACE("(%p, %d, %p)\n", hIMC, fSelect, hKL);
TLS *pTLS = TLS::PeekTLS();
if (!pTLS)
return E_OUTOFMEMORY;
InternalSelectEx(hIMC, fSelect, LOWORD(hKL));
if (!pTLS->m_pBridge || !pTLS->m_pThreadMgr)
return E_OUTOFMEMORY;
return pTLS->m_pBridge->SelectEx(pTLS, pTLS->m_pThreadMgr, hIMC, fSelect, hKL);
}
EXTERN_C LRESULT WINAPI
CtfImeEscapeEx(
_In_ HIMC hIMC,
_In_ UINT uSubFunc,
_Inout_opt_ LPVOID lpData,
_In_ HKL hKL)
{
FIXME("stub:(%p, %u, %p, %p)\n", hIMC, uSubFunc, lpData, hKL);
return 0;
}
/***********************************************************************
* CtfImeGetGuidAtom (MSCTFIME.@)
*
* @implemented
*/
EXTERN_C HRESULT WINAPI
CtfImeGetGuidAtom(
_In_ HIMC hIMC,
_In_ DWORD dwUnknown,
_Out_opt_ LPDWORD pdwGuidAtom)
{
TRACE("(%p, 0x%lX, %p)\n", hIMC, dwUnknown, pdwGuidAtom);
CicIMCLock imcLock(hIMC);
if (FAILED(imcLock.m_hr))
return imcLock.m_hr;
CicIMCCLock<CTFIMECONTEXT> imccLock(imcLock.get().hCtfImeContext);
if (FAILED(imccLock.m_hr))
return imccLock.m_hr;
if (!imccLock.get().m_pCicIC)
return E_OUTOFMEMORY;
return imccLock.get().m_pCicIC->GetGuidAtom(imcLock, dwUnknown, pdwGuidAtom);
}
/***********************************************************************
* CtfImeIsGuidMapEnable (MSCTFIME.@)
*
* @implemented
*/
EXTERN_C BOOL WINAPI
CtfImeIsGuidMapEnable(
_In_ HIMC hIMC)
{
TRACE("(%p)\n", hIMC);
BOOL ret = FALSE;
CicIMCLock imcLock(hIMC);
if (SUCCEEDED(imcLock.m_hr))
ret = !!(imcLock.get().fdwInit & INIT_GUIDMAP);
return ret;
}
/***********************************************************************
* CtfImeCreateThreadMgr (MSCTFIME.@)
*
* @implemented
*/
EXTERN_C HRESULT WINAPI
CtfImeCreateThreadMgr(VOID)
{
TRACE("()\n");
TLS *pTLS = TLS::GetTLS();
if (!pTLS)
return E_OUTOFMEMORY;
if (!pTLS->m_pBridge)
{
pTLS->m_pBridge = new(cicNoThrow) CicBridge();
if (!pTLS->m_pBridge)
return E_OUTOFMEMORY;
}
HRESULT hr = S_OK;
if (!g_bWinLogon && !(pTLS->m_dwSystemInfoFlags & IME_SYSINFO_WINLOGON))
{
hr = pTLS->m_pBridge->InitIMMX(pTLS);
if (SUCCEEDED(hr))
{
if (!pTLS->m_pThreadMgr)
return E_OUTOFMEMORY;
hr = pTLS->m_pBridge->ActivateIMMX(pTLS, pTLS->m_pThreadMgr);
if (FAILED(hr))
pTLS->m_pBridge->UnInitIMMX(pTLS);
}
}
return hr;
}
/***********************************************************************
* CtfImeDestroyThreadMgr (MSCTFIME.@)
*
* @implemented
*/
EXTERN_C HRESULT WINAPI
CtfImeDestroyThreadMgr(VOID)
{
TRACE("()\n");
TLS *pTLS = TLS::PeekTLS();
if (!pTLS)
return E_OUTOFMEMORY;
if (pTLS->m_pBridge)
{
pTLS->m_pBridge = new(cicNoThrow) CicBridge();
if (!pTLS->m_pBridge)
return E_OUTOFMEMORY;
}
if (!pTLS->m_pThreadMgr)
return E_OUTOFMEMORY;
if (pTLS->m_dwSystemInfoFlags & IME_SYSINFO_WINLOGON)
return S_OK;
HRESULT hr = pTLS->m_pBridge->DeactivateIMMX(pTLS, pTLS->m_pThreadMgr);
if (hr == S_OK)
pTLS->m_pBridge->UnInitIMMX(pTLS);
return hr;
}
EXTERN_C HRESULT WINAPI
CtfImeCreateInputContext(
_In_ HIMC hIMC)
{
return E_NOTIMPL;
}
/***********************************************************************
* CtfImeDestroyInputContext (MSCTFIME.@)
*
* @implemented
*/
EXTERN_C HRESULT WINAPI
CtfImeDestroyInputContext(
_In_ HIMC hIMC)
{
TRACE("(%p)\n", hIMC);
TLS *pTLS = TLS::PeekTLS();
if (!pTLS || !pTLS->m_pBridge)
return E_OUTOFMEMORY;
return pTLS->m_pBridge->DestroyInputContext(pTLS, hIMC);
}
EXTERN_C HRESULT WINAPI
CtfImeSetActiveContextAlways(
_In_ HIMC hIMC,
_In_ BOOL fActive,
_In_ HWND hWnd,
_In_ HKL hKL)
{
FIXME("stub:(%p, %d, %p, %p)\n", hIMC, fActive, hWnd, hKL);
return E_NOTIMPL;
}
/***********************************************************************
* CtfImeProcessCicHotkey (MSCTFIME.@)
*
* @implemented
*/
EXTERN_C HRESULT WINAPI
CtfImeProcessCicHotkey(
_In_ HIMC hIMC,
_In_ UINT vKey,
_In_ LPARAM lParam)
{
TRACE("(%p, %u, %p)\n", hIMC, vKey, lParam);
TLS *pTLS = TLS::GetTLS();
if (!pTLS)
return S_OK;
HRESULT hr = S_OK;
ITfThreadMgr *pThreadMgr = NULL;
ITfThreadMgr_P *pThreadMgr_P = NULL;
if ((TF_GetThreadMgr(&pThreadMgr) == S_OK) &&
(pThreadMgr->QueryInterface(IID_ITfThreadMgr_P, (void**)&pThreadMgr_P) == S_OK) &&
CtfImmIsCiceroStartedInThread())
{
HRESULT hr2;
if (SUCCEEDED(pThreadMgr_P->CallImm32HotkeyHandler(vKey, lParam, &hr2)))
hr = hr2;
}
if (pThreadMgr)
pThreadMgr->Release();
if (pThreadMgr_P)
pThreadMgr_P->Release();
return hr;
}
/***********************************************************************
* CtfImeDispatchDefImeMessage (MSCTFIME.@)
*
* @implemented
*/
EXTERN_C LRESULT WINAPI
CtfImeDispatchDefImeMessage(
_In_ HWND hWnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam)
{
TRACE("(%p, %u, %p, %p)\n", hWnd, uMsg, wParam, lParam);
TLS *pTLS = TLS::GetTLS();
if (pTLS)
{
if (uMsg == WM_CREATE)
++pTLS->m_cWnds;
else if (uMsg == WM_DESTROY)
--pTLS->m_cWnds;
}
if (!IsMsImeMessage(uMsg))
return 0;
HKL hKL = GetKeyboardLayout(0);
if (IS_IME_HKL(hKL))
return 0;
HWND hImeWnd = (HWND)SendMessageW(hWnd, WM_IME_NOTIFY, 0x17, 0);
if (!IsWindow(hImeWnd))
return 0;
return SendMessageW(hImeWnd, uMsg, wParam, lParam);
}
EXTERN_C BOOL WINAPI
CtfImeIsIME(
_In_ HKL hKL)
{
FIXME("stub:(%p)\n", hKL);
return FALSE;
}
/***********************************************************************
* CtfImeThreadDetach (MSCTFIME.@)
*
* @implemented
*/
EXTERN_C HRESULT WINAPI
CtfImeThreadDetach(VOID)
{
ImeDestroy(0);
return S_OK;
}
/// @implemented
BOOL AttachIME(VOID)
{
return RegisterImeClass() && RegisterMSIMEMessage();
}
/// @implemented
VOID DetachIME(VOID)
{
UnregisterImeClass();
}
EXTERN_C VOID TFUninitLib(VOID)
{
if (g_pPropCache)
{
delete g_pPropCache;
g_pPropCache = NULL;
}
}
/// @implemented
BOOL ProcessAttach(HINSTANCE hinstDLL)
{
g_hInst = hinstDLL;
InitializeCriticalSectionAndSpinCount(&g_csLock, 0);
if (!TLS::Initialize())
return FALSE;
cicGetOSInfo(&g_uACP, &g_dwOSInfo);
cicInitUIFLib();
if (!TFInitLib())
return FALSE;
gfTFInitLib = TRUE;
return AttachIME();
}
/// @implemented
VOID ProcessDetach(HINSTANCE hinstDLL)
{
TF_DllDetachInOther();
if (gfTFInitLib)
{
DetachIME();
TFUninitLib();
}
DeleteCriticalSection(&g_csLock);
TLS::InternalDestroyTLS();
TLS::Uninitialize();
cicDoneUIFLib();
}
/// @implemented
EXTERN_C BOOL WINAPI
DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD dwReason,
_Inout_opt_ LPVOID lpvReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
{
TRACE("(%p, %lu, %p)\n", hinstDLL, dwReason, lpvReserved);
if (!ProcessAttach(hinstDLL))
{
ProcessDetach(hinstDLL);
return FALSE;
}
break;
}
case DLL_PROCESS_DETACH:
{
ProcessDetach(hinstDLL);
break;
}
case DLL_THREAD_DETACH:
{
TF_DllDetachInOther();
CtfImeThreadDetach();
TLS::InternalDestroyTLS();
break;
}
}
return TRUE;
}