[CALC] Fix input bug when display is in error. (#5988)
[reactos.git] / dll / win32 / imm32 / imm.c
index a64f382..175432c 100644 (file)
 /*
- * IMM32 library
- *
- * Copyright 1998 Patrik Stridvall
- * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * PROJECT:     ReactOS IMM32
+ * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE:     Implementing Far-Eastern languages input
+ * COPYRIGHT:   Copyright 1998 Patrik Stridvall
+ *              Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
+ *              Copyright 2017 James Tabor <james.tabor@reactos.org>
+ *              Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org>
+ *              Copyright 2020-2022 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
  */
 
-#include <stdarg.h>
-#include <stdio.h>
-
-#define WIN32_NO_STATUS
-#include <windef.h>
-#include <winbase.h>
-#include <wingdi.h>
-#include <winuser.h>
-#include <winerror.h>
-#include <wine/debug.h>
-#include <imm.h>
-#include <ddk/imm.h>
-#include <winnls.h>
-#include <winreg.h>
-#include <wine/list.h>
-#include <stdlib.h>
-#include <ndk/umtypes.h>
-#include <ndk/pstypes.h>
-#include <ndk/rtlfuncs.h>
-#include "../../../win32ss/include/ntuser.h"
-#include "../../../win32ss/include/ntwin32.h"
-#include <imm32_undoc.h>
-#include <strsafe.h>
+#include "precomp.h"
+#include <ndk/exfuncs.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(imm);
 
-#define IMM_INIT_MAGIC 0x19650412
-#define IMM_INVALID_CANDFORM ULONG_MAX
-
-#define LANGID_CHINESE_SIMPLIFIED MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
-#define LANGID_CHINESE_TRADITIONAL MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
-#define LANGID_JAPANESE MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)
-
-#define REGKEY_KEYBOARD_LAYOUTS \
-    L"System\\CurrentControlSet\\Control\\Keyboard Layouts"
-#define REGKEY_IMM \
-    L"Software\\Microsoft\\Windows NT\\CurrentVersion\\IMM"
-
-#define ROUNDUP4(n) (((n) + 3) & ~3)  /* DWORD alignment */
-
-HMODULE g_hImm32Inst = NULL;
-RTL_CRITICAL_SECTION g_csImeDpi;
-PIMEDPI g_pImeDpiList = NULL;
-PSERVERINFO g_psi = NULL;
-SHAREDINFO g_SharedInfo = { NULL };
-BYTE g_bClientRegd = FALSE;
-HANDLE g_hImm32Heap = NULL;
+HMODULE ghImm32Inst = NULL; /* The IMM32 instance */
+PSERVERINFO gpsi = NULL;
+SHAREDINFO gSharedInfo = { NULL };
+BYTE gfImmInitialized = FALSE; /* Is IMM32 initialized? */
+ULONG_PTR gHighestUserAddress = 0;
 
-static BOOL APIENTRY Imm32InitInstance(HMODULE hMod)
+static BOOL APIENTRY ImmInitializeGlobals(HMODULE hMod)
 {
     NTSTATUS status;
+    SYSTEM_BASIC_INFORMATION SysInfo;
 
     if (hMod)
-        g_hImm32Inst = hMod;
+        ghImm32Inst = hMod;
 
-    if (g_bClientRegd)
+    if (gfImmInitialized)
         return TRUE;
 
-    status = RtlInitializeCriticalSection(&g_csImeDpi);
+    status = RtlInitializeCriticalSection(&gcsImeDpi);
     if (NT_ERROR(status))
+    {
+        ERR("\n");
         return FALSE;
+    }
 
-    g_bClientRegd = TRUE;
-    return TRUE;
-}
-
-LPVOID APIENTRY Imm32HeapAlloc(DWORD dwFlags, DWORD dwBytes)
-{
-    if (!g_hImm32Heap)
+    status = NtQuerySystemInformation(SystemBasicInformation, &SysInfo, sizeof(SysInfo), NULL);
+    if (NT_ERROR(status))
     {
-        g_hImm32Heap = RtlGetProcessHeap();
-        if (g_hImm32Heap == NULL)
-            return NULL;
+        ERR("\n");
+        return FALSE;
     }
-    return HeapAlloc(g_hImm32Heap, dwFlags, dwBytes);
-}
-
-static DWORD_PTR APIENTRY Imm32QueryWindow(HWND hWnd, DWORD Index)
-{
-    return NtUserQueryWindow(hWnd, Index);
-}
-
-static DWORD APIENTRY
-Imm32UpdateInputContext(HIMC hIMC, DWORD Unknown1, PCLIENTIMC pClientImc)
-{
-    return NtUserUpdateInputContext(hIMC, Unknown1, pClientImc);
-}
+    gHighestUserAddress = SysInfo.MaximumUserModeAddress;
 
-static DWORD APIENTRY Imm32QueryInputContext(HIMC hIMC, DWORD dwUnknown2)
-{
-    return NtUserQueryInputContext(hIMC, dwUnknown2);
+    gfImmInitialized = TRUE;
+    return TRUE;
 }
 
-static DWORD APIENTRY Imm32NotifyIMEStatus(HWND hwnd, HIMC hIMC, DWORD dwConversion)
+/***********************************************************************
+ *             ImmRegisterClient(IMM32.@)
+ *       ( Undocumented, called from user32.dll )
+ */
+BOOL WINAPI ImmRegisterClient(PSHAREDINFO ptr, HINSTANCE hMod)
 {
-    return NtUserNotifyIMEStatus(hwnd, hIMC, dwConversion);
+    gSharedInfo = *ptr;
+    gpsi = gSharedInfo.psi;
+    return ImmInitializeGlobals(hMod);
 }
 
-static HIMC APIENTRY Imm32CreateInputContext(PCLIENTIMC pClientImc)
+/***********************************************************************
+ *             ImmLoadLayout (IMM32.@)
+ */
+BOOL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx)
 {
-    return NtUserCreateInputContext(pClientImc);
-}
+    DWORD cbData, dwType;
+    HKEY hKey;
+    LSTATUS error;
+    WCHAR szLayout[MAX_PATH];
+    LPCWSTR pszSubKey;
 
-static BOOL APIENTRY Imm32DestroyInputContext(HIMC hIMC)
-{
-    return NtUserDestroyInputContext(hIMC);
-}
+    TRACE("(%p, %p)\n", hKL, pImeInfoEx);
 
-DWORD_PTR APIENTRY Imm32GetThreadState(DWORD Routine)
-{
-    return NtUserGetThreadState(Routine);
-}
+    /* Choose a key */
+    if (IS_IME_HKL(hKL) || !IS_CICERO_MODE() || IS_16BIT_MODE()) /* Non-Cicero? */
+    {
+        StringCchPrintfW(szLayout, _countof(szLayout), L"%s\\%08lX",
+                         REGKEY_KEYBOARD_LAYOUTS, HandleToUlong(hKL));
+        pszSubKey = szLayout;
+    }
+    else /* Cicero */
+    {
+        pszSubKey = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\IMM";
+    }
 
-static VOID APIENTRY Imm32FreeImeDpi(PIMEDPI pImeDpi, BOOL bDestroy)
-{
-    if (pImeDpi->hInst == NULL)
-        return;
-    if (bDestroy)
-        pImeDpi->ImeDestroy(0);
-    FreeLibrary(pImeDpi->hInst);
-    pImeDpi->hInst = NULL;
-}
+    /* Open the key */
+    error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, pszSubKey, 0, KEY_READ, &hKey);
+    if (IS_ERROR_UNEXPECTEDLY(error))
+        return FALSE;
 
-static BOOL APIENTRY
-Imm32NotifyAction(HIMC hIMC, HWND hwnd, DWORD dwAction, DWORD_PTR dwIndex, DWORD_PTR dwValue,
-                  DWORD_PTR dwCommand, DWORD_PTR dwData)
-{
-    DWORD dwLayout;
-    HKL hKL;
-    PIMEDPI pImeDpi;
+    /* Load "IME File" value */
+    cbData = sizeof(pImeInfoEx->wszImeFile);
+    error = RegQueryValueExW(hKey, L"IME File", NULL, &dwType,
+                             (LPBYTE)pImeInfoEx->wszImeFile, &cbData);
 
-    if (dwAction)
-    {
-        dwLayout = Imm32QueryInputContext(hIMC, 1);
-        if (dwLayout)
-        {
-            /* find keyboard layout and lock it */
-            hKL = GetKeyboardLayout(dwLayout);
-            pImeDpi = ImmLockImeDpi(hKL);
-            if (pImeDpi)
-            {
-                /* do notify */
-                pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue);
+    /* Avoid buffer overrun */
+    pImeInfoEx->wszImeFile[_countof(pImeInfoEx->wszImeFile) - 1] = UNICODE_NULL;
 
-                ImmUnlockImeDpi(pImeDpi); /* unlock */
-            }
-        }
-    }
+    RegCloseKey(hKey);
 
-    if (hwnd && dwCommand)
-        SendMessageW(hwnd, WM_IME_NOTIFY, dwCommand, dwData);
+    if (error != ERROR_SUCCESS || dwType != REG_SZ)
+        return FALSE; /* Failed */
 
-    return TRUE;
+    pImeInfoEx->hkl = hKL;
+    pImeInfoEx->fLoadFlag = 0;
+    return Imm32LoadImeVerInfo(pImeInfoEx);
 }
 
-static PIMEDPI APIENTRY Imm32FindImeDpi(HKL hKL)
+/***********************************************************************
+ *             ImmFreeLayout (IMM32.@)
+ */
+BOOL WINAPI ImmFreeLayout(DWORD dwUnknown)
 {
+    WCHAR szKBD[KL_NAMELENGTH];
+    UINT iKL, cKLs;
+    HKL hOldKL, hNewKL, *pList;
     PIMEDPI pImeDpi;
+    LANGID LangID;
 
-    RtlEnterCriticalSection(&g_csImeDpi);
-    for (pImeDpi = g_pImeDpiList; pImeDpi != NULL; pImeDpi = pImeDpi->pNext)
-    {
-        if (pImeDpi->hKL == hKL)
-            break;
-    }
-    RtlLeaveCriticalSection(&g_csImeDpi);
+    TRACE("(0x%lX)\n", dwUnknown);
 
-    return pImeDpi;
-}
+    hOldKL = GetKeyboardLayout(0);
 
-static BOOL Imm32GetSystemLibraryPath(LPWSTR pszPath, DWORD cchPath, LPCWSTR pszFileName)
-{
-    if (!pszFileName[0] || !GetSystemDirectoryW(pszPath, cchPath))
-        return FALSE;
-    StringCchCatW(pszPath, cchPath, L"\\");
-    StringCchCatW(pszPath, cchPath, pszFileName);
-    return TRUE;
-}
+    if (dwUnknown == 1)
+    {
+        if (!IS_IME_HKL(hOldKL))
+            return TRUE;
 
-DWORD APIENTRY Imm32SetImeOwnerWindow(PIMEINFOEX pImeInfoEx, BOOL fFlag)
-{
-    return NtUserSetImeOwnerWindow(pImeInfoEx, fFlag);
-}
+        LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
 
-static BOOL APIENTRY Imm32InquireIme(PIMEDPI pImeDpi)
-{
-    WCHAR szUIClass[64];
-    WNDCLASSW wcW;
-    DWORD dwSysInfoFlags = 0; // TODO: ???
-    LPIMEINFO pImeInfo = &pImeDpi->ImeInfo;
+        cKLs = GetKeyboardLayoutList(0, NULL);
+        if (cKLs)
+        {
+            pList = ImmLocalAlloc(0, cKLs * sizeof(HKL));
+            if (IS_NULL_UNEXPECTEDLY(pList))
+                return FALSE;
 
-    // TODO: Imm32GetThreadState(THREADSTATE_UNKNOWN16);
+            cKLs = GetKeyboardLayoutList(cKLs, pList);
+            for (iKL = 0; iKL < cKLs; ++iKL)
+            {
+                if (!IS_IME_HKL(pList[iKL]))
+                {
+                    LangID = LOWORD(pList[iKL]);
+                    break;
+                }
+            }
 
-    if (!IS_IME_HKL(pImeDpi->hKL))
-    {
-        if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED) &&
-            pImeDpi->CtfImeInquireExW)
+            ImmLocalFree(pList);
+        }
+
+        StringCchPrintfW(szKBD, _countof(szKBD), L"%08X", LangID);
+        if (!LoadKeyboardLayoutW(szKBD, KLF_ACTIVATE))
         {
-            // TODO:
-            return FALSE;
+            WARN("Default to English US\n");
+            LoadKeyboardLayoutW(L"00000409", KLF_ACTIVATE | 0x200);
         }
     }
-
-    if (!pImeDpi->ImeInquire(pImeInfo, szUIClass, dwSysInfoFlags))
-        return FALSE;
-
-    szUIClass[_countof(szUIClass) - 1] = 0;
-
-    if (pImeInfo->dwPrivateDataSize == 0)
-        pImeInfo->dwPrivateDataSize = 4;
-
-#define VALID_IME_PROP (IME_PROP_AT_CARET              | \
-                        IME_PROP_SPECIAL_UI            | \
-                        IME_PROP_CANDLIST_START_FROM_1 | \
-                        IME_PROP_UNICODE               | \
-                        IME_PROP_COMPLETE_ON_UNSELECT  | \
-                        IME_PROP_END_UNLOAD            | \
-                        IME_PROP_KBD_CHAR_FIRST        | \
-                        IME_PROP_IGNORE_UPKEYS         | \
-                        IME_PROP_NEED_ALTKEY           | \
-                        IME_PROP_NO_KEYS_ON_CLOSE      | \
-                        IME_PROP_ACCEPT_WIDE_VKEY)
-#define VALID_CMODE_CAPS (IME_CMODE_ALPHANUMERIC | \
-                          IME_CMODE_NATIVE       | \
-                          IME_CMODE_KATAKANA     | \
-                          IME_CMODE_LANGUAGE     | \
-                          IME_CMODE_FULLSHAPE    | \
-                          IME_CMODE_ROMAN        | \
-                          IME_CMODE_CHARCODE     | \
-                          IME_CMODE_HANJACONVERT | \
-                          IME_CMODE_SOFTKBD      | \
-                          IME_CMODE_NOCONVERSION | \
-                          IME_CMODE_EUDC         | \
-                          IME_CMODE_SYMBOL       | \
-                          IME_CMODE_FIXED)
-#define VALID_SMODE_CAPS (IME_SMODE_NONE          | \
-                          IME_SMODE_PLAURALCLAUSE | \
-                          IME_SMODE_SINGLECONVERT | \
-                          IME_SMODE_AUTOMATIC     | \
-                          IME_SMODE_PHRASEPREDICT | \
-                          IME_SMODE_CONVERSATION)
-#define VALID_UI_CAPS (UI_CAP_2700    | \
-                       UI_CAP_ROT90   | \
-                       UI_CAP_ROTANY  | \
-                       UI_CAP_SOFTKBD)
-#define VALID_SCS_CAPS (SCS_CAP_COMPSTR            | \
-                        SCS_CAP_MAKEREAD           | \
-                        SCS_CAP_SETRECONVERTSTRING)
-#define VALID_SELECT_CAPS (SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE)
-
-    if (pImeInfo->fdwProperty & ~VALID_IME_PROP)
-        return FALSE;
-    if (pImeInfo->fdwConversionCaps & ~VALID_CMODE_CAPS)
-        return FALSE;
-    if (pImeInfo->fdwSentenceCaps & ~VALID_SMODE_CAPS)
-        return FALSE;
-    if (pImeInfo->fdwUICaps & ~VALID_UI_CAPS)
-        return FALSE;
-    if (pImeInfo->fdwSCSCaps & ~VALID_SCS_CAPS)
-        return FALSE;
-    if (pImeInfo->fdwSelectCaps & ~VALID_SELECT_CAPS)
-        return FALSE;
-
-#undef VALID_IME_PROP
-#undef VALID_CMODE_CAPS
-#undef VALID_SMODE_CAPS
-#undef VALID_UI_CAPS
-#undef VALID_SCS_CAPS
-#undef VALID_SELECT_CAPS
-
-    if (pImeInfo->fdwProperty & IME_PROP_UNICODE)
+    else if (dwUnknown == 2)
     {
-        StringCchCopyW(pImeDpi->szUIClass, _countof(pImeDpi->szUIClass), szUIClass);
+        RtlEnterCriticalSection(&gcsImeDpi);
+Retry:
+        for (pImeDpi = gpImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext)
+        {
+            if (Imm32ReleaseIME(pImeDpi->hKL))
+                goto Retry;
+        }
+        RtlLeaveCriticalSection(&gcsImeDpi);
     }
     else
     {
-        if (pImeDpi->uCodePage != GetACP() && pImeDpi->uCodePage)
-            return FALSE;
-
-        MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPSTR)szUIClass, -1,
-                            pImeDpi->szUIClass, _countof(pImeDpi->szUIClass));
+        hNewKL = (HKL)(DWORD_PTR)dwUnknown;
+        if (IS_IME_HKL(hNewKL) && hNewKL != hOldKL)
+            Imm32ReleaseIME(hNewKL);
     }
 
-    return GetClassInfoW(pImeDpi->hInst, pImeDpi->szUIClass, &wcW);
+    return TRUE;
 }
 
-static BOOL APIENTRY Imm32LoadImeInfo(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi)
+VOID APIENTRY Imm32SelectInputContext(HKL hNewKL, HKL hOldKL, HIMC hIMC)
 {
-    WCHAR szPath[MAX_PATH];
-    HINSTANCE hIME;
-    FARPROC fn;
+    PCLIENTIMC pClientImc;
+    LPINPUTCONTEXTDX pIC;
+    LPGUIDELINE pGL;
+    LPCANDIDATEINFO pCI;
+    LPCOMPOSITIONSTRING pCS;
+    LOGFONTA LogFontA;
+    LOGFONTW LogFontW;
+    BOOL fOldOpen, bIsNewHKLIme = TRUE, bIsOldHKLIme = TRUE, bClientWide, bNewDpiWide;
+    DWORD cbNewPrivate = 0, cbOldPrivate = 0, dwOldConversion, dwOldSentence, dwSize, dwNewSize;
+    PIMEDPI pNewImeDpi = NULL, pOldImeDpi = NULL;
+    HANDLE hPrivate;
+    PIME_STATE pNewState = NULL, pOldState = NULL;
 
-    if (!Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile))
-        return FALSE;
+    pClientImc = ImmLockClientImc(hIMC);
+    if (IS_NULL_UNEXPECTEDLY(pClientImc))
+        return;
+
+    pNewImeDpi = ImmLockImeDpi(hNewKL);
 
-    hIME = GetModuleHandleW(szPath);
-    if (hIME == NULL)
+    if (hNewKL != hOldKL)
+        pOldImeDpi = ImmLockImeDpi(hOldKL);
+
+    if (pNewImeDpi)
     {
-        hIME = LoadLibraryW(szPath);
-        if (hIME == NULL)
-        {
-            ERR("Imm32LoadImeInfo: LoadLibraryW(%S) failed\n", szPath);
-            return FALSE;
-        }
+        cbNewPrivate = pNewImeDpi->ImeInfo.dwPrivateDataSize;
+        pClientImc->uCodePage = pNewImeDpi->uCodePage;
     }
-    pImeDpi->hInst = hIME;
-
-#define DEFINE_IME_ENTRY(type, name, params, extended) \
-    do { \
-        fn = GetProcAddress(hIME, #name); \
-        if (fn) pImeDpi->name = (FN_##name)fn; \
-        else if (!extended) goto Failed; \
-    } while (0);
-#include "../../../win32ss/include/imetable.h"
-#undef DEFINE_IME_ENTRY
-
-    if (!Imm32InquireIme(pImeDpi))
+    else
     {
-        ERR("Imm32LoadImeInfo: Imm32InquireIme failed\n");
-        goto Failed;
+        pClientImc->uCodePage = CP_ACP;
     }
 
-    if (pImeInfoEx->fLoadFlag)
-        return TRUE;
-
-    Imm32SetImeOwnerWindow(pImeInfoEx, TRUE);
-    return TRUE;
+    if (pOldImeDpi)
+        cbOldPrivate = pOldImeDpi->ImeInfo.dwPrivateDataSize;
 
-Failed:
-    FreeLibrary(pImeDpi->hInst);
-    pImeDpi->hInst = NULL;
-    return FALSE;
-}
+    cbNewPrivate = max(cbNewPrivate, sizeof(DWORD));
+    cbOldPrivate = max(cbOldPrivate, sizeof(DWORD));
 
-static PIMEDPI APIENTRY Ime32LoadImeDpi(HKL hKL, BOOL bLock)
-{
-    IMEINFOEX ImeInfoEx;
-    CHARSETINFO ci;
-    PIMEDPI pImeDpiNew, pImeDpiFound;
-    UINT uCodePage;
-    LCID lcid;
-
-    if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL) ||
-        ImeInfoEx.fLoadFlag == 1)
+    if (pClientImc->hKL == hOldKL)
     {
-        return NULL;
+        if (pOldImeDpi)
+        {
+            if (IS_IME_HKL(hOldKL))
+                pOldImeDpi->ImeSelect(hIMC, FALSE);
+            else if (IS_CICERO_MODE() && !IS_16BIT_MODE())
+                pOldImeDpi->CtfImeSelectEx(hIMC, FALSE, hOldKL);
+        }
+        pClientImc->hKL = NULL;
     }
 
-    pImeDpiNew = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(IMEDPI));
-    if (pImeDpiNew == NULL)
-        return NULL;
-
-    pImeDpiNew->hKL = hKL;
-
-    lcid = LOWORD(hKL);
-    if (TranslateCharsetInfo((LPDWORD)(DWORD_PTR)lcid, &ci, TCI_SRCLOCALE))
-        uCodePage = ci.ciACP;
-    else
-        uCodePage = CP_ACP;
-    pImeDpiNew->uCodePage = uCodePage;
-
-    if (!Imm32LoadImeInfo(&ImeInfoEx, pImeDpiNew))
+    if (CtfImmIsTextFrameServiceDisabled() && IS_CICERO_MODE() && !IS_16BIT_MODE())
     {
-        HeapFree(g_hImm32Heap, 0, pImeDpiNew);
-        return FALSE;
+        bIsNewHKLIme = IS_IME_HKL(hNewKL);
+        bIsOldHKLIme = IS_IME_HKL(hOldKL);
     }
 
-    RtlEnterCriticalSection(&g_csImeDpi);
-
-    pImeDpiFound = Imm32FindImeDpi(hKL);
-    if (pImeDpiFound)
+    pIC = (LPINPUTCONTEXTDX)Imm32InternalLockIMC(hIMC, FALSE);
+    if (!pIC)
     {
-        if (!bLock)
-            pImeDpiFound->dwFlags &= ~IMEDPI_FLAG_LOCKED;
-
-        RtlLeaveCriticalSection(&g_csImeDpi);
+        if (pNewImeDpi)
+        {
+            if (IS_IME_HKL(hNewKL))
+                pNewImeDpi->ImeSelect(hIMC, TRUE);
+            else if (IS_CICERO_MODE() && !IS_16BIT_MODE())
+                pNewImeDpi->CtfImeSelectEx(hIMC, TRUE, hNewKL);
 
-        Imm32FreeImeDpi(pImeDpiNew, FALSE);
-        HeapFree(g_hImm32Heap, 0, pImeDpiNew);
-        return pImeDpiFound;
+            pClientImc->hKL = hNewKL;
+        }
     }
     else
     {
-        if (bLock)
+        dwOldConversion = pIC->fdwConversion;
+        dwOldSentence = pIC->fdwSentence;
+        fOldOpen = pIC->fOpen;
+
+        if (pNewImeDpi)
         {
-            pImeDpiNew->dwFlags |= IMEDPI_FLAG_LOCKED;
-            pImeDpiNew->cLockObj = 1;
+            bClientWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
+            bNewDpiWide = ImeDpi_IsUnicode(pNewImeDpi);
+            if (bClientWide && !bNewDpiWide)
+            {
+                if (pIC->fdwInit & INIT_LOGFONT)
+                {
+                    LogFontWideToAnsi(&pIC->lfFont.W, &LogFontA);
+                    pIC->lfFont.A = LogFontA;
+                }
+                pClientImc->dwFlags &= ~CLIENTIMC_WIDE;
+            }
+            else if (!bClientWide && bNewDpiWide)
+            {
+                if (pIC->fdwInit & INIT_LOGFONT)
+                {
+                    LogFontAnsiToWide(&pIC->lfFont.A, &LogFontW);
+                    pIC->lfFont.W = LogFontW;
+                }
+                pClientImc->dwFlags |= CLIENTIMC_WIDE;
+            }
         }
 
-        pImeDpiNew->pNext = g_pImeDpiList;
-        g_pImeDpiList = pImeDpiNew;
-
-        RtlLeaveCriticalSection(&g_csImeDpi);
-        return pImeDpiNew;
-    }
-}
+        if (cbOldPrivate != cbNewPrivate)
+        {
+            hPrivate = ImmReSizeIMCC(pIC->hPrivate, cbNewPrivate);
+            if (!hPrivate)
+            {
+                ImmDestroyIMCC(pIC->hPrivate);
+                hPrivate = ImmCreateIMCC(cbNewPrivate);
+            }
+            pIC->hPrivate = hPrivate;
+        }
 
-BOOL WINAPI ImmLoadIME(HKL hKL)
-{
-    PW32CLIENTINFO pInfo;
-    PIMEDPI pImeDpi;
+#define MAX_IMCC_SIZE 0x1000
+        dwSize = ImmGetIMCCSize(pIC->hMsgBuf);
+        if (ImmGetIMCCLockCount(pIC->hMsgBuf) || dwSize > MAX_IMCC_SIZE)
+        {
+            ImmDestroyIMCC(pIC->hMsgBuf);
+            pIC->hMsgBuf = ImmCreateIMCC(sizeof(UINT));
+            pIC->dwNumMsgBuf = 0;
+        }
 
-    if (!IS_IME_HKL(hKL))
-    {
-        if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
-            return FALSE;
+        dwSize = ImmGetIMCCSize(pIC->hGuideLine);
+        dwNewSize = sizeof(GUIDELINE);
+        if (ImmGetIMCCLockCount(pIC->hGuideLine) ||
+            dwSize < dwNewSize || dwSize > MAX_IMCC_SIZE)
+        {
+            ImmDestroyIMCC(pIC->hGuideLine);
+            pIC->hGuideLine = ImmCreateIMCC(dwNewSize);
+            pGL = ImmLockIMCC(pIC->hGuideLine);
+            if (pGL)
+            {
+                pGL->dwSize = dwNewSize;
+                ImmUnlockIMCC(pIC->hGuideLine);
+            }
+        }
 
-        pInfo = (PW32CLIENTINFO)(NtCurrentTeb()->Win32ClientInfo);
-        if ((pInfo->W32ClientInfo[0] & 2))
-            return FALSE;
-    }
+        dwSize = ImmGetIMCCSize(pIC->hCandInfo);
+        dwNewSize = sizeof(CANDIDATEINFO);
+        if (ImmGetIMCCLockCount(pIC->hCandInfo) ||
+            dwSize < dwNewSize || dwSize > MAX_IMCC_SIZE)
+        {
+            ImmDestroyIMCC(pIC->hCandInfo);
+            pIC->hCandInfo = ImmCreateIMCC(dwNewSize);
+            pCI = ImmLockIMCC(pIC->hCandInfo);
+            if (pCI)
+            {
+                pCI->dwSize = dwNewSize;
+                ImmUnlockIMCC(pIC->hCandInfo);
+            }
+        }
 
-    pImeDpi = Imm32FindImeDpi(hKL);
-    if (pImeDpi == NULL)
-        pImeDpi = Ime32LoadImeDpi(hKL, FALSE);
-    return (pImeDpi != NULL);
-}
+        dwSize = ImmGetIMCCSize(pIC->hCompStr);
+        dwNewSize = sizeof(COMPOSITIONSTRING);
+        if (ImmGetIMCCLockCount(pIC->hCompStr) ||
+            dwSize < dwNewSize || dwSize > MAX_IMCC_SIZE)
+        {
+            ImmDestroyIMCC(pIC->hCompStr);
+            pIC->hCompStr = ImmCreateIMCC(dwNewSize);
+            pCS = ImmLockIMCC(pIC->hCompStr);
+            if (pCS)
+            {
+                pCS->dwSize = dwNewSize;
+                ImmUnlockIMCC(pIC->hCompStr);
+            }
+        }
+#undef MAX_IMCC_SIZE
 
-PIMEDPI APIENTRY ImmLockOrLoadImeDpi(HKL hKL)
-{
-    PW32CLIENTINFO pInfo;
-    PIMEDPI pImeDpi;
+        if (pOldImeDpi && bIsOldHKLIme)
+        {
+            pOldState = Imm32FetchImeState(pIC, hOldKL);
+            if (pOldState)
+                Imm32SaveImeStateSentence(pIC, pOldState, hOldKL);
+        }
 
-    if (!IS_IME_HKL(hKL))
-    {
-        if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
-            return NULL;
+        if (pNewImeDpi && bIsNewHKLIme)
+            pNewState = Imm32FetchImeState(pIC, hNewKL);
 
-        pInfo = (PW32CLIENTINFO)(NtCurrentTeb()->Win32ClientInfo);
-        if ((pInfo->W32ClientInfo[0] & 2))
-            return NULL;
-    }
+        if (pOldState != pNewState)
+        {
+            if (pOldState)
+            {
+                pOldState->fOpen = !!pIC->fOpen;
+                pOldState->dwConversion = pIC->fdwConversion;
+                pOldState->dwConversion &= ~IME_CMODE_EUDC;
+                pOldState->dwSentence = pIC->fdwSentence;
+                pOldState->dwInit = pIC->fdwInit;
+            }
 
-    pImeDpi = ImmLockImeDpi(hKL);
-    if (pImeDpi == NULL)
-        pImeDpi = Ime32LoadImeDpi(hKL, TRUE);
-    return pImeDpi;
-}
+            if (pNewState)
+            {
+                if (pIC->dwChange & INPUTCONTEXTDX_CHANGE_FORCE_OPEN)
+                {
+                    pIC->dwChange &= ~INPUTCONTEXTDX_CHANGE_FORCE_OPEN;
+                    pIC->fOpen = TRUE;
+                }
+                else
+                {
+                    pIC->fOpen = pNewState->fOpen;
+                }
 
-HKL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx)
-{
-    DWORD cbData;
-    UNICODE_STRING UnicodeString;
-    HKEY hLayoutKey = NULL, hLayoutsKey = NULL;
-    LONG error;
-    NTSTATUS Status;
-    WCHAR szLayout[MAX_PATH];
+                pIC->fdwConversion = pNewState->dwConversion;
+                pIC->fdwConversion &= ~IME_CMODE_EUDC;
+                pIC->fdwSentence = pNewState->dwSentence;
+                pIC->fdwInit = pNewState->dwInit;
+            }
+        }
 
-    TRACE("(%p, %p)\n", hKL, pImeInfoEx);
+        if (pNewState)
+            Imm32LoadImeStateSentence(pIC, pNewState, hNewKL);
 
-    if (IS_IME_HKL(hKL) ||
-        !g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED) ||
-        ((PW32CLIENTINFO)NtCurrentTeb()->Win32ClientInfo)->W32ClientInfo[0] & 2)
-    {
-        UnicodeString.Buffer = szLayout;
-        UnicodeString.MaximumLength = sizeof(szLayout);
-        Status = RtlIntegerToUnicodeString((DWORD_PTR)hKL, 16, &UnicodeString);
-        if (!NT_SUCCESS(Status))
-            return NULL;
+        if (pNewImeDpi)
+        {
+            if (IS_IME_HKL(hNewKL))
+                pNewImeDpi->ImeSelect(hIMC, TRUE);
+            else if (IS_CICERO_MODE() && !IS_16BIT_MODE())
+                pNewImeDpi->CtfImeSelectEx(hIMC, TRUE, hNewKL);
 
-        error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hLayoutsKey);
-        if (error)
-            return NULL;
+            pClientImc->hKL = hNewKL;
+        }
 
-        error = RegOpenKeyW(hLayoutsKey, szLayout, &hLayoutKey);
-    }
-    else
-    {
-        error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_IMM, &hLayoutKey);
-    }
+        pIC->dwChange = 0;
+        if (pIC->fOpen != fOldOpen)
+            pIC->dwChange |= INPUTCONTEXTDX_CHANGE_OPEN;
+        if (pIC->fdwConversion != dwOldConversion)
+            pIC->dwChange |= INPUTCONTEXTDX_CHANGE_CONVERSION;
+        if (pIC->fdwSentence != dwOldSentence)
+            pIC->dwChange |= INPUTCONTEXTDX_CHANGE_SENTENCE;
 
-    if (error)
-    {
-        ERR("RegOpenKeyW error: 0x%08lX\n", error);
-        hKL = NULL;
-    }
-    else
-    {
-        cbData = sizeof(pImeInfoEx->wszImeFile);
-        error = RegQueryValueExW(hLayoutKey, L"Ime File", 0, 0,
-                                 (LPBYTE)pImeInfoEx->wszImeFile, &cbData);
-        if (error)
-            hKL = NULL;
+        ImmUnlockIMC(hIMC);
     }
 
-    RegCloseKey(hLayoutKey);
-    if (hLayoutsKey)
-        RegCloseKey(hLayoutsKey);
-    return hKL;
+    ImmUnlockImeDpi(pOldImeDpi);
+    ImmUnlockImeDpi(pNewImeDpi);
+    ImmUnlockClientImc(pClientImc);
 }
 
-typedef struct _tagImmHkl{
-    struct list entry;
-    HKL         hkl;
-    HMODULE     hIME;
-    IMEINFO     imeInfo;
-    WCHAR       imeClassName[17]; /* 16 character max */
-    ULONG       uSelected;
-    HWND        UIWnd;
-
-    /* Function Pointers */
-    BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, const WCHAR *);
-    BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *);
-    BOOL (WINAPI *pImeDestroy)(UINT);
-    LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *);
-    BOOL (WINAPI *pImeSelect)(HIMC, BOOL);
-    BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL);
-    UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, DWORD *, UINT, HIMC);
-    BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD);
-    BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *);
-    BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *);
-    UINT (WINAPI *pImeEnumRegisterWord)(REGISTERWORDENUMPROCW, const WCHAR *, DWORD, const WCHAR *, void *);
-    BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void *, DWORD, const void *, DWORD);
-    DWORD (WINAPI *pImeConversionList)(HIMC, const WCHAR *, CANDIDATELIST *, DWORD, UINT);
-    BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *);
-    UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *);
-    DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD);
-} ImmHkl;
-
-typedef struct tagInputContextData
+typedef struct SELECT_LAYOUT
 {
-        DWORD           dwLock;
-        INPUTCONTEXT    IMC;
-        DWORD           threadID;
-
-        ImmHkl          *immKbd;
-        UINT            lastVK;
-        BOOL            threadDefault;
-        DWORD           magic;
-} InputContextData;
-
-#define WINE_IMC_VALID_MAGIC 0x56434D49
-
-typedef struct _tagTRANSMSG {
-    UINT message;
-    WPARAM wParam;
-    LPARAM lParam;
-} TRANSMSG, *LPTRANSMSG;
-
-typedef struct _tagIMMThreadData {
-    struct list entry;
-    DWORD threadID;
-    HIMC defaultContext;
-    HWND hwndDefault;
-    BOOL disableIME;
-    DWORD windowRefs;
-} IMMThreadData;
-
-static struct list ImmHklList = LIST_INIT(ImmHklList);
-static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
-
-static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0};
+    HKL hNewKL;
+    HKL hOldKL;
+} SELECT_LAYOUT, *LPSELECT_LAYOUT;
 
-static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
-static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0};
-static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0};
-
-static const WCHAR szwIME[] = {'I','M','E',0};
-static const WCHAR szwDefaultIME[] = {'D','e','f','a','u','l','t',' ','I','M','E',0};
-
-static CRITICAL_SECTION threaddata_cs;
-static CRITICAL_SECTION_DEBUG critsect_debug =
+// Win: SelectContextProc
+static BOOL CALLBACK Imm32SelectContextProc(HIMC hIMC, LPARAM lParam)
 {
-    0, 0, &threaddata_cs,
-    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
-      0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") }
-};
-static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
-static BOOL disable_ime;
-
-static inline BOOL is_himc_ime_unicode(const InputContextData *data)
-{
-    return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE);
+    LPSELECT_LAYOUT pSelect = (LPSELECT_LAYOUT)lParam;
+    Imm32SelectInputContext(pSelect->hNewKL, pSelect->hOldKL, hIMC);
+    return TRUE;
 }
 
-static inline BOOL is_kbd_ime_unicode(const ImmHkl *hkl)
+// Win: NotifyIMEProc
+static BOOL CALLBACK Imm32NotifyIMEProc(HIMC hIMC, LPARAM lParam)
 {
-    return !!(hkl->imeInfo.fdwProperty & IME_PROP_UNICODE);
+    ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, (DWORD)lParam, 0);
+    return TRUE;
 }
 
-static InputContextData* get_imc_data(HIMC hIMC);
-
-static inline WCHAR *strdupAtoW( const char *str )
+/***********************************************************************
+ *             ImmActivateLayout (IMM32.@)
+ */
+BOOL WINAPI ImmActivateLayout(HKL hKL)
 {
-    WCHAR *ret = NULL;
-    if (str)
-    {
-        DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
-        if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
-            MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
-    }
-    return ret;
-}
+    PIMEDPI pImeDpi;
+    HKL hOldKL;
+    LPARAM lParam;
+    HWND hwndDefIME = NULL;
+    SELECT_LAYOUT SelectLayout;
 
-static inline CHAR *strdupWtoA( const WCHAR *str )
-{
-    CHAR *ret = NULL;
-    if (str)
-    {
-        DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
-        if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
-            WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
-    }
-    return ret;
-}
+    hOldKL = GetKeyboardLayout(0);
 
-static DWORD convert_candidatelist_WtoA(
-        LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
-{
-    DWORD ret, i, len;
+    if (hOldKL == hKL && !(GetWin32ClientInfo()->CI_flags & CI_IMMACTIVATE))
+        return TRUE;
 
-    ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
-    if ( lpDst && dwBufLen > 0 )
-    {
-        *lpDst = *lpSrc;
-        lpDst->dwOffset[0] = ret;
-    }
+    ImmLoadIME(hKL);
 
-    for ( i = 0; i < lpSrc->dwCount; i++)
+    if (hOldKL != hKL)
     {
-        LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
-
-        if ( lpDst && dwBufLen > 0 )
+        pImeDpi = ImmLockImeDpi(hOldKL);
+        if (pImeDpi)
         {
-            LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
-
-            len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1,
-                                      (LPSTR)dest, dwBufLen, NULL, NULL);
+            if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_COMPLETE_ON_UNSELECT)
+                lParam = CPS_COMPLETE;
+            else
+                lParam = CPS_CANCEL;
+            ImmUnlockImeDpi(pImeDpi);
 
-            if ( i + 1 < lpSrc->dwCount )
-                lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(char);
-            dwBufLen -= len * sizeof(char);
+            ImmEnumInputContext(0, Imm32NotifyIMEProc, lParam);
         }
-        else
-            len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, NULL, 0, NULL, NULL);
 
-        ret += len * sizeof(char);
+        hwndDefIME = ImmGetDefaultIMEWnd(NULL);
+        if (IsWindow(hwndDefIME))
+            SendMessageW(hwndDefIME, WM_IME_SELECT, FALSE, (LPARAM)hOldKL);
+
+        NtUserSetThreadLayoutHandles(hKL, hOldKL);
     }
 
-    if ( lpDst )
-        lpDst->dwSize = ret;
+    SelectLayout.hNewKL = hKL;
+    SelectLayout.hOldKL = hOldKL;
+    ImmEnumInputContext(0, Imm32SelectContextProc, (LPARAM)&SelectLayout);
 
-    return ret;
+    if (IsWindow(hwndDefIME))
+        SendMessageW(hwndDefIME, WM_IME_SELECT, TRUE, (LPARAM)hKL);
+
+    return TRUE;
 }
 
-static DWORD convert_candidatelist_AtoW(
-        LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
+/***********************************************************************
+ *             ImmAssociateContext (IMM32.@)
+ */
+HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
 {
-    DWORD ret, i, len;
+    PWND pWnd;
+    HWND hwndFocus;
+    DWORD dwValue;
+    HIMC hOldIMC;
+
+    TRACE("(%p, %p)\n", hWnd, hIMC);
 
-    ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
-    if ( lpDst && dwBufLen > 0 )
+    if (!IS_IMM_MODE())
     {
-        *lpDst = *lpSrc;
-        lpDst->dwOffset[0] = ret;
+        TRACE("\n");
+        return NULL;
     }
 
-    for ( i = 0; i < lpSrc->dwCount; i++)
-    {
-        LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
+    pWnd = ValidateHwnd(hWnd);
+    if (IS_NULL_UNEXPECTEDLY(pWnd))
+        return NULL;
 
-        if ( lpDst && dwBufLen > 0 )
-        {
-            LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
-
-            len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1,
-                                      (LPWSTR)dest, dwBufLen);
-
-            if ( i + 1 < lpSrc->dwCount )
-                lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(WCHAR);
-            dwBufLen -= len * sizeof(WCHAR);
-        }
-        else
-            len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, NULL, 0);
-
-        ret += len * sizeof(WCHAR);
-    }
-
-    if ( lpDst )
-        lpDst->dwSize = ret;
-
-    return ret;
-}
+    if (hIMC && IS_CROSS_THREAD_HIMC(hIMC))
+        return NULL;
 
-static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread)
-{
-    IMMThreadData *data;
-    DWORD process;
+    hOldIMC = pWnd->hImc;
+    if (hOldIMC == hIMC)
+        return hIMC;
 
-    if (hwnd)
+    dwValue = NtUserAssociateInputContext(hWnd, hIMC, 0);
+    switch (dwValue)
     {
-        if (!(thread = GetWindowThreadProcessId(hwnd, &process))) return NULL;
-        if (process != GetCurrentProcessId()) return NULL;
-    }
-    else if (thread)
-    {
-        HANDLE h = OpenThread(THREAD_QUERY_INFORMATION, FALSE, thread);
-        if (!h) return NULL;
-        process = GetProcessIdOfThread(h);
-        CloseHandle(h);
-        if (process != GetCurrentProcessId()) return NULL;
-    }
-    else
-        thread = GetCurrentThreadId();
+        case 0:
+            return hOldIMC;
 
-    EnterCriticalSection(&threaddata_cs);
-    LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
-        if (data->threadID == thread) return data;
-
-    data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
-    data->threadID = thread;
-    list_add_head(&ImmThreadDataList,&data->entry);
-    TRACE("Thread Data Created (%x)\n",thread);
-    return data;
-}
+        case 1:
+            hwndFocus = (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_FOCUS);
+            if (hwndFocus == hWnd)
+            {
+                ImmSetActiveContext(hWnd, hOldIMC, FALSE);
+                ImmSetActiveContext(hWnd, hIMC, TRUE);
+            }
+            return hOldIMC;
 
-static HMODULE load_graphics_driver(void)
-{
-    static const WCHAR display_device_guid_propW[] = {
-        '_','_','w','i','n','e','_','d','i','s','p','l','a','y','_',
-        'd','e','v','i','c','e','_','g','u','i','d',0 };
-    static const WCHAR key_pathW[] = {
-        'S','y','s','t','e','m','\\',
-        'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
-        'C','o','n','t','r','o','l','\\',
-        'V','i','d','e','o','\\','{',0};
-    static const WCHAR displayW[] = {'}','\\','0','0','0','0',0};
-    static const WCHAR driverW[] = {'G','r','a','p','h','i','c','s','D','r','i','v','e','r',0};
-
-    HMODULE ret = 0;
-    HKEY hkey;
-    DWORD size;
-    WCHAR path[MAX_PATH];
-    WCHAR key[ARRAY_SIZE( key_pathW ) + ARRAY_SIZE( displayW ) + 40];
-    UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), display_device_guid_propW ));
-
-    if (!guid_atom) return 0;
-    memcpy( key, key_pathW, sizeof(key_pathW) );
-    if (!GlobalGetAtomNameW( guid_atom, key + lstrlenW(key), 40 )) return 0;
-    lstrcatW( key, displayW );
-    if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0;
-    size = sizeof(path);
-    if (!RegQueryValueExW( hkey, driverW, NULL, NULL, (BYTE *)path, &size )) ret = LoadLibraryW( path );
-    RegCloseKey( hkey );
-    TRACE( "%s %p\n", debugstr_w(path), ret );
-    return ret;
+        default:
+            return NULL;
+    }
 }
 
-/* ImmHkl loading and freeing */
-#define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);}
-static ImmHkl *IMM_GetImmHkl(HKL hkl)
+/***********************************************************************
+ *              ImmAssociateContextEx (IMM32.@)
+ */
+BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
 {
-    ImmHkl *ptr;
-    WCHAR filename[MAX_PATH];
+    HWND hwndFocus;
+    PWND pFocusWnd;
+    HIMC hOldIMC = NULL;
+    DWORD dwValue;
 
-    TRACE("Seeking ime for keyboard %p\n",hkl);
+    TRACE("(%p, %p, 0x%lX)\n", hWnd, hIMC, dwFlags);
 
-    LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry)
+    if (!IS_IMM_MODE())
     {
-        if (ptr->hkl == hkl)
-            return ptr;
+        TRACE("\n");
+        return FALSE;
     }
-    /* not found... create it */
 
-    ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl));
+    if (hIMC && !(dwFlags & IACE_DEFAULT) && IS_CROSS_THREAD_HIMC(hIMC))
+        return FALSE;
+
+    hwndFocus = (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_FOCUS);
+    pFocusWnd = ValidateHwnd(hwndFocus);
+    if (pFocusWnd)
+        hOldIMC = pFocusWnd->hImc;
 
-    ptr->hkl = hkl;
-    if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename);
-    if (!ptr->hIME) ptr->hIME = load_graphics_driver();
-    if (ptr->hIME)
+    dwValue = NtUserAssociateInputContext(hWnd, hIMC, dwFlags);
+    switch (dwValue)
     {
-        LOAD_FUNCPTR(ImeInquire);
-        if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL))
-        {
-            FreeLibrary(ptr->hIME);
-            ptr->hIME = NULL;
-        }
-        else
-        {
-            LOAD_FUNCPTR(ImeDestroy);
-            LOAD_FUNCPTR(ImeSelect);
-            if (!ptr->pImeSelect || !ptr->pImeDestroy)
-            {
-                FreeLibrary(ptr->hIME);
-                ptr->hIME = NULL;
-            }
-            else
+        case 0:
+            return TRUE;
+
+        case 1:
+            pFocusWnd = ValidateHwnd(hwndFocus);
+            if (pFocusWnd)
             {
-                LOAD_FUNCPTR(ImeConfigure);
-                LOAD_FUNCPTR(ImeEscape);
-                LOAD_FUNCPTR(ImeSetActiveContext);
-                LOAD_FUNCPTR(ImeToAsciiEx);
-                LOAD_FUNCPTR(NotifyIME);
-                LOAD_FUNCPTR(ImeRegisterWord);
-                LOAD_FUNCPTR(ImeUnregisterWord);
-                LOAD_FUNCPTR(ImeEnumRegisterWord);
-                LOAD_FUNCPTR(ImeSetCompositionString);
-                LOAD_FUNCPTR(ImeConversionList);
-                LOAD_FUNCPTR(ImeProcessKey);
-                LOAD_FUNCPTR(ImeGetRegisterWordStyle);
-                LOAD_FUNCPTR(ImeGetImeMenuItems);
-                /* make sure our classname is WCHAR */
-                if (!is_kbd_ime_unicode(ptr))
+                hIMC = pFocusWnd->hImc;
+                if (hIMC != hOldIMC)
                 {
-                    WCHAR bufW[17];
-                    MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName,
-                                        -1, bufW, 17);
-                    lstrcpyW(ptr->imeClassName, bufW);
+                    ImmSetActiveContext(hwndFocus, hOldIMC, FALSE);
+                    ImmSetActiveContext(hwndFocus, hIMC, TRUE);
                 }
             }
-        }
-    }
-    list_add_head(&ImmHklList,&ptr->entry);
-
-    return ptr;
-}
-#undef LOAD_FUNCPTR
+            return TRUE;
 
-HWND WINAPI __wine_get_ui_window(HKL hkl)
-{
-    ImmHkl *immHkl = IMM_GetImmHkl(hkl);
-    return immHkl->UIWnd;
+        default:
+            return FALSE;
+    }
 }
 
-/* for posting messages as the IME */
-static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
+/***********************************************************************
+ *             ImmCreateContext (IMM32.@)
+ */
+HIMC WINAPI ImmCreateContext(void)
 {
-    HWND target = GetFocus();
-    if (!target)
-       PostMessageW(data->IMC.hWnd,msg,wParam,lParam);
-    else
-       PostMessageW(target, msg, wParam, lParam);
-}
+    PCLIENTIMC pClientImc;
+    HIMC hIMC;
 
-/* for sending messages as the IME */
-static void ImmInternalSendIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
-{
-    HWND target = GetFocus();
-    if (!target)
-       SendMessageW(data->IMC.hWnd,msg,wParam,lParam);
-    else
-       SendMessageW(target, msg, wParam, lParam);
-}
+    TRACE("()\n");
 
-static InputContextData* get_imc_data(HIMC hIMC)
-{
-    InputContextData *data = hIMC;
+    if (!IS_IMM_MODE())
+    {
+        TRACE("\n");
+        return NULL;
+    }
 
-    if (hIMC == NULL)
+    pClientImc = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
+    if (IS_NULL_UNEXPECTEDLY(pClientImc))
         return NULL;
 
-    if(IsBadReadPtr(data, sizeof(InputContextData)) || data->magic != WINE_IMC_VALID_MAGIC)
+    hIMC = NtUserCreateInputContext((ULONG_PTR)pClientImc);
+    if (IS_NULL_UNEXPECTEDLY(hIMC))
     {
-        SetLastError(ERROR_INVALID_HANDLE);
+        ImmLocalFree(pClientImc);
         return NULL;
     }
-    return data;
-}
-
-static HIMC get_default_context( HWND hwnd )
-{
-    FIXME("Don't use this function\n");
-    return FALSE;
-}
 
-static BOOL IMM_IsCrossThreadAccess(HWND hWnd,  HIMC hIMC)
-{
-    InputContextData *data;
+    RtlInitializeCriticalSection(&pClientImc->cs);
 
-    if (hWnd)
-    {
-        DWORD thread = GetWindowThreadProcessId(hWnd, NULL);
-        if (thread != GetCurrentThreadId()) return TRUE;
-    }
-    data = get_imc_data(hIMC);
-    if (data && data->threadID != GetCurrentThreadId())
-        return TRUE;
+    pClientImc->dwCompatFlags = (DWORD)NtUserGetThreadState(THREADSTATE_IMECOMPATFLAGS);
 
-    return FALSE;
+    return hIMC;
 }
 
-/***********************************************************************
- *             ImmAssociateContext (IMM32.@)
- */
-HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
+// Win: DestroyImeModeSaver
+static VOID APIENTRY Imm32DestroyImeModeSaver(LPINPUTCONTEXTDX pIC)
 {
-    HIMC old = NULL;
-    InputContextData *data = get_imc_data(hIMC);
+    PIME_STATE pState, pNext;
+    PIME_SUBSTATE pSubState, pSubNext;
 
-    TRACE("(%p, %p):\n", hWnd, hIMC);
-
-    if(hIMC && !data)
-        return NULL;
-
-    /*
-     * If already associated just return
-     */
-    if (hIMC && data->IMC.hWnd == hWnd)
-        return hIMC;
-
-    if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC))
-        return NULL;
-
-    if (hWnd)
+    for (pState = pIC->pState; pState; pState = pNext)
     {
-        HIMC defaultContext = get_default_context( hWnd );
-        old = RemovePropW(hWnd,szwWineIMCProperty);
-
-        if (old == NULL)
-            old = defaultContext;
-        else if (old == (HIMC)-1)
-            old = NULL;
+        pNext = pState->pNext;
 
-        if (hIMC != defaultContext)
+        for (pSubState = pState->pSubState; pSubState; pSubState = pSubNext)
         {
-            if (hIMC == NULL) /* Meaning disable imm for that window*/
-                SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1);
-            else
-                SetPropW(hWnd,szwWineIMCProperty,hIMC);
-        }
-
-        if (old)
-        {
-            InputContextData *old_data = old;
-            if (old_data->IMC.hWnd == hWnd)
-                old_data->IMC.hWnd = NULL;
+            pSubNext = pSubState->pNext;
+            ImmLocalFree(pSubState);
         }
-    }
-
-    if (!hIMC)
-        return old;
 
-    if(GetActiveWindow() == data->IMC.hWnd)
-    {
-        SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL);
-        data->IMC.hWnd = hWnd;
-        SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL);
+        ImmLocalFree(pState);
     }
 
-    return old;
-}
-
-
-/*
- * Helper function for ImmAssociateContextEx
- */
-static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam)
-{
-    HIMC hImc = (HIMC)lParam;
-    ImmAssociateContext(hwnd,hImc);
-    return TRUE;
+    pIC->pState = NULL;
 }
 
-/***********************************************************************
- *              ImmAssociateContextEx (IMM32.@)
- */
-BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
+// Win: DestroyInputContext
+BOOL APIENTRY Imm32DestroyInputContext(HIMC hIMC, HKL hKL, BOOL bKeep)
 {
-    TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags);
+    PIMEDPI pImeDpi;
+    LPINPUTCONTEXTDX pIC;
+    PCLIENTIMC pClientImc;
+    PIMC pIMC;
 
-    if (!hWnd)
+    if (hIMC == NULL)
         return FALSE;
 
-    switch (dwFlags)
-    {
-    case 0:
-        ImmAssociateContext(hWnd,hIMC);
-        return TRUE;
-    case IACE_DEFAULT:
+    if (!IS_IMM_MODE())
     {
-        HIMC defaultContext = get_default_context( hWnd );
-        if (!defaultContext) return FALSE;
-        ImmAssociateContext(hWnd,defaultContext);
-        return TRUE;
-    }
-    case IACE_IGNORENOCONTEXT:
-        if (GetPropW(hWnd,szwWineIMCProperty))
-            ImmAssociateContext(hWnd,hIMC);
-        return TRUE;
-    case IACE_CHILDREN:
-        EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC);
-        return TRUE;
-    default:
-        FIXME("Unknown dwFlags 0x%x\n",dwFlags);
+        TRACE("\n");
         return FALSE;
     }
-}
-
-/***********************************************************************
- *             ImmConfigureIMEA (IMM32.@)
- */
-BOOL WINAPI ImmConfigureIMEA(
-  HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
-{
-    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
 
-    TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
-
-    if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
+    pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT);
+    if (IS_NULL_UNEXPECTEDLY(pIMC))
         return FALSE;
 
-    if (immHkl->hIME && immHkl->pImeConfigure)
+    if (pIMC->head.pti != Imm32CurrentPti())
     {
-        if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl))
-            return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
-        else
-        {
-            REGISTERWORDW rww;
-            REGISTERWORDA *rwa = lpData;
-            BOOL rc;
-
-            rww.lpReading = strdupAtoW(rwa->lpReading);
-            rww.lpWord = strdupAtoW(rwa->lpWord);
-            rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww);
-            HeapFree(GetProcessHeap(),0,rww.lpReading);
-            HeapFree(GetProcessHeap(),0,rww.lpWord);
-            return rc;
-        }
-    }
-    else
-        return FALSE;
-}
-
-/***********************************************************************
- *             ImmConfigureIMEW (IMM32.@)
- */
-BOOL WINAPI ImmConfigureIMEW(
-  HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
-{
-    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
-
-    TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
-
-    if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
+        ERR("Thread mismatch\n");
         return FALSE;
-
-    if (immHkl->hIME && immHkl->pImeConfigure)
-    {
-        if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl))
-            return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
-        else
-        {
-            REGISTERWORDW *rww = lpData;
-            REGISTERWORDA rwa;
-            BOOL rc;
-
-            rwa.lpReading = strdupWtoA(rww->lpReading);
-            rwa.lpWord = strdupWtoA(rww->lpWord);
-            rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa);
-            HeapFree(GetProcessHeap(),0,rwa.lpReading);
-            HeapFree(GetProcessHeap(),0,rwa.lpWord);
-            return rc;
-        }
     }
-    else
-        return FALSE;
-}
-
-/***********************************************************************
- *             ImmCreateContext (IMM32.@)
- */
-HIMC WINAPI ImmCreateContext(void)
-{
-    PCLIENTIMC pClientImc;
-    HIMC hIMC;
-
-    TRACE("()\n");
 
-    if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
-        return NULL;
-
-    pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
+    pClientImc = (PCLIENTIMC)pIMC->dwClientImcData;
     if (pClientImc == NULL)
-        return NULL;
-
-    hIMC = Imm32CreateInputContext(pClientImc);
-    if (hIMC == NULL)
     {
-        HeapFree(g_hImm32Heap, 0, pClientImc);
-        return NULL;
+        TRACE("pClientImc == NULL\n");
+        goto Finish;
     }
 
-    RtlInitializeCriticalSection(&pClientImc->cs);
-    pClientImc->unknown = Imm32GetThreadState(THREADSTATE_UNKNOWN13);
-    return hIMC;
-}
-
-static VOID APIENTRY Imm32CleanupContextExtra(LPINPUTCONTEXT pIC)
-{
-    FIXME("We have to do something do here");
-}
-
-static PCLIENTIMC APIENTRY Imm32FindClientImc(HIMC hIMC)
-{
-    // FIXME
-    return NULL;
-}
-
-BOOL APIENTRY Imm32CleanupContext(HIMC hIMC, HKL hKL, BOOL bKeep)
-{
-    PIMEDPI pImeDpi;
-    LPINPUTCONTEXT pIC;
-    PCLIENTIMC pClientImc;
-
-    if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32) || hIMC == NULL)
-        return FALSE;
-
-    FIXME("We have do something to do here\n");
-    pClientImc = Imm32FindClientImc(hIMC);
-    if (!pClientImc)
+    if ((pClientImc->dwFlags & CLIENTIMC_UNKNOWN2) && !bKeep)
+    {
+        ERR("Can't destroy for CLIENTIMC_UNKNOWN2\n");
         return FALSE;
+    }
 
-    if (pClientImc->hImc == NULL)
-    {
-        pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1;
-        ImmUnlockClientImc(pClientImc);
-        if (!bKeep)
-            return Imm32DestroyInputContext(hIMC);
+    if (pClientImc->dwFlags & CLIENTIMC_DESTROY)
         return TRUE;
-    }
 
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
+    InterlockedIncrement(&pClientImc->cLockObj);
+
+    if (IS_NULL_UNEXPECTEDLY(pClientImc->hInputContext))
+        goto Quit;
+
+    pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
+    if (IS_NULL_UNEXPECTEDLY(pIC))
     {
         ImmUnlockClientImc(pClientImc);
         return FALSE;
     }
 
-    FIXME("We have do something to do here\n");
+    CtfImmTIMDestroyInputContext(hIMC);
 
     if (pClientImc->hKL == hKL)
     {
         pImeDpi = ImmLockImeDpi(hKL);
-        if (pImeDpi != NULL)
+        if (pImeDpi)
         {
             if (IS_IME_HKL(hKL))
-            {
                 pImeDpi->ImeSelect(hIMC, FALSE);
-            }
-            else if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
-            {
-                FIXME("We have do something to do here\n");
-            }
+            else if (IS_CICERO_MODE() && !IS_16BIT_MODE())
+                pImeDpi->CtfImeSelectEx(hIMC, FALSE, hKL);
+
             ImmUnlockImeDpi(pImeDpi);
         }
+
         pClientImc->hKL = NULL;
     }
 
@@ -1172,3442 +718,376 @@ BOOL APIENTRY Imm32CleanupContext(HIMC hIMC, HKL hKL, BOOL bKeep)
     ImmDestroyIMCC(pIC->hGuideLine);
     ImmDestroyIMCC(pIC->hCandInfo);
     ImmDestroyIMCC(pIC->hCompStr);
-
-    Imm32CleanupContextExtra(pIC);
-
+    Imm32DestroyImeModeSaver(pIC);
     ImmUnlockIMC(hIMC);
 
-    pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1;
+Quit:
+    pClientImc->dwFlags |= CLIENTIMC_DESTROY;
     ImmUnlockClientImc(pClientImc);
 
-    if (!bKeep)
-        return Imm32DestroyInputContext(hIMC);
-
-    return TRUE;
+Finish:
+    if (bKeep)
+        return TRUE;
+    return NtUserDestroyInputContext(hIMC);
 }
 
-/***********************************************************************
- *             ImmDestroyContext (IMM32.@)
- */
-BOOL WINAPI ImmDestroyContext(HIMC hIMC)
+// NOTE: Windows does recursive call ImmLockIMC here but we don't do so.
+// Win: BOOL CreateInputContext(HIMC hIMC, HKL hKL, BOOL fSelect)
+BOOL APIENTRY
+Imm32CreateInputContext(HIMC hIMC, LPINPUTCONTEXT pIC, PCLIENTIMC pClientImc, HKL hKL, BOOL fSelect)
 {
-    DWORD dwImeThreadId, dwThreadId;
-    HKL hKL;
-
-    TRACE("(%p)\n", hIMC);
+    DWORD dwIndex, cbPrivate;
+    PIMEDPI pImeDpi = NULL;
+    LPCOMPOSITIONSTRING pCS;
+    LPCANDIDATEINFO pCI;
+    LPGUIDELINE pGL;
 
-    if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
-        return FALSE;
+    /* Create IC components */
+    pIC->hCompStr = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
+    pIC->hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
+    pIC->hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
+    pIC->hMsgBuf = ImmCreateIMCC(sizeof(UINT));
+    if (IS_NULL_UNEXPECTEDLY(pIC->hCompStr) ||
+        IS_NULL_UNEXPECTEDLY(pIC->hCandInfo) ||
+        IS_NULL_UNEXPECTEDLY(pIC->hGuideLine) ||
+        IS_NULL_UNEXPECTEDLY(pIC->hMsgBuf))
+    {
+        goto Fail;
+    }
 
-    dwImeThreadId = Imm32QueryInputContext(hIMC, 1);
-    dwThreadId = GetCurrentThreadId();
-    if (dwImeThreadId != dwThreadId)
-        return FALSE;
+    /* Initialize IC components */
+    pCS = ImmLockIMCC(pIC->hCompStr);
+    if (IS_NULL_UNEXPECTEDLY(pCS))
+        goto Fail;
+    pCS->dwSize = sizeof(COMPOSITIONSTRING);
+    ImmUnlockIMCC(pIC->hCompStr);
 
-    hKL = GetKeyboardLayout(0);
-    return Imm32CleanupContext(hIMC, hKL, FALSE);
-}
+    pCI = ImmLockIMCC(pIC->hCandInfo);
+    if (IS_NULL_UNEXPECTEDLY(pCI))
+        goto Fail;
+    pCI->dwSize = sizeof(CANDIDATEINFO);
+    ImmUnlockIMCC(pIC->hCandInfo);
 
-/***********************************************************************
- *             ImmDisableIME (IMM32.@)
- */
-BOOL WINAPI ImmDisableIME(DWORD dwThreadId)
-{
-    return NtUserDisableThreadIme(dwThreadId);
-}
+    pGL = ImmLockIMCC(pIC->hGuideLine);
+    if (IS_NULL_UNEXPECTEDLY(pGL))
+        goto Fail;
+    pGL->dwSize = sizeof(GUIDELINE);
+    ImmUnlockIMCC(pIC->hGuideLine);
 
-/***********************************************************************
- *             ImmEnumRegisterWordA (IMM32.@)
- */
-UINT WINAPI ImmEnumRegisterWordA(
-  HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc,
-  LPCSTR lpszReading, DWORD dwStyle,
-  LPCSTR lpszRegister, LPVOID lpData)
-{
-    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
-    TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc,
-        debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister), lpData);
-    if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
-    {
-        if (!is_kbd_ime_unicode(immHkl))
-            return immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
-                (LPCWSTR)lpszReading, dwStyle, (LPCWSTR)lpszRegister, lpData);
-        else
-        {
-            LPWSTR lpszwReading = strdupAtoW(lpszReading);
-            LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
-            BOOL rc;
+    pIC->dwNumMsgBuf = 0;
+    pIC->fOpen = FALSE;
+    pIC->fdwConversion = pIC->fdwSentence = 0;
 
-            rc = immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
-                                              lpszwReading, dwStyle, lpszwRegister,
-                                              lpData);
+    for (dwIndex = 0; dwIndex < MAX_CANDIDATEFORM; ++dwIndex)
+        pIC->cfCandForm[dwIndex].dwIndex = IMM_INVALID_CANDFORM;
 
-            HeapFree(GetProcessHeap(),0,lpszwReading);
-            HeapFree(GetProcessHeap(),0,lpszwRegister);
-            return rc;
-        }
+    /* Get private data size */
+    pImeDpi = ImmLockImeDpi(hKL);
+    if (!pImeDpi)
+    {
+        cbPrivate = sizeof(DWORD);
     }
     else
-        return 0;
-}
+    {
+        /* Update CLIENTIMC */
+        pClientImc->uCodePage = pImeDpi->uCodePage;
+        if (ImeDpi_IsUnicode(pImeDpi))
+            pClientImc->dwFlags |= CLIENTIMC_WIDE;
 
-/***********************************************************************
- *             ImmEnumRegisterWordW (IMM32.@)
- */
-UINT WINAPI ImmEnumRegisterWordW(
-  HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc,
-  LPCWSTR lpszReading, DWORD dwStyle,
-  LPCWSTR lpszRegister, LPVOID lpData)
-{
-    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
-    TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc,
-        debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), lpData);
-    if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
+        cbPrivate = pImeDpi->ImeInfo.dwPrivateDataSize;
+    }
+
+    /* Create private data */
+    pIC->hPrivate = ImmCreateIMCC(cbPrivate);
+    if (IS_NULL_UNEXPECTEDLY(pIC->hPrivate))
+        goto Fail;
+
+    CtfImmTIMCreateInputContext(hIMC);
+
+    if (pImeDpi)
     {
-        if (is_kbd_ime_unicode(immHkl))
-            return immHkl->pImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle,
-                                            lpszRegister, lpData);
-        else
+        /* Select the IME */
+        if (fSelect)
         {
-            LPSTR lpszaReading = strdupWtoA(lpszReading);
-            LPSTR lpszaRegister = strdupWtoA(lpszRegister);
-            BOOL rc;
+            if (IS_IME_HKL(hKL))
+                pImeDpi->ImeSelect(hIMC, TRUE);
+            else if (IS_CICERO_MODE() && !IS_16BIT_MODE())
+                pImeDpi->CtfImeSelectEx(hIMC, TRUE, hKL);
+        }
 
-            rc = immHkl->pImeEnumRegisterWord(lpfnEnumProc, (LPCWSTR)lpszaReading,
-                                              dwStyle, (LPCWSTR)lpszaRegister, lpData);
+        /* Set HKL */
+        pClientImc->hKL = hKL;
 
-            HeapFree(GetProcessHeap(),0,lpszaReading);
-            HeapFree(GetProcessHeap(),0,lpszaRegister);
-            return rc;
-        }
+        ImmUnlockImeDpi(pImeDpi);
     }
-    else
-        return 0;
-}
 
-static inline BOOL EscapeRequiresWA(UINT uEscape)
-{
-        if (uEscape == IME_ESC_GET_EUDC_DICTIONARY ||
-            uEscape == IME_ESC_SET_EUDC_DICTIONARY ||
-            uEscape == IME_ESC_IME_NAME ||
-            uEscape == IME_ESC_GETHELPFILENAME)
-        return TRUE;
+    return TRUE;
+
+Fail:
+    if (pImeDpi)
+        ImmUnlockImeDpi(pImeDpi);
+
+    pIC->hMsgBuf = ImmDestroyIMCC(pIC->hMsgBuf);
+    pIC->hGuideLine = ImmDestroyIMCC(pIC->hGuideLine);
+    pIC->hCandInfo = ImmDestroyIMCC(pIC->hCandInfo);
+    pIC->hCompStr = ImmDestroyIMCC(pIC->hCompStr);
     return FALSE;
 }
 
-/***********************************************************************
- *             ImmEscapeA (IMM32.@)
- */
-LRESULT WINAPI ImmEscapeA(
-  HKL hKL, HIMC hIMC,
-  UINT uEscape, LPVOID lpData)
-{
-    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
-    TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
-
-    if (immHkl->hIME && immHkl->pImeEscape)
-    {
-        if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl))
-            return immHkl->pImeEscape(hIMC,uEscape,lpData);
-        else
-        {
-            WCHAR buffer[81]; /* largest required buffer should be 80 */
-            LRESULT rc;
-            if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
-            {
-                MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81);
-                rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
-            }
-            else
-            {
-                rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
-                WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL);
-            }
-            return rc;
-        }
-    }
-    else
-        return 0;
-}
-
-/***********************************************************************
- *             ImmEscapeW (IMM32.@)
- */
-LRESULT WINAPI ImmEscapeW(
-  HKL hKL, HIMC hIMC,
-  UINT uEscape, LPVOID lpData)
-{
-    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
-    TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
-
-    if (immHkl->hIME && immHkl->pImeEscape)
-    {
-        if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl))
-            return immHkl->pImeEscape(hIMC,uEscape,lpData);
-        else
-        {
-            CHAR buffer[81]; /* largest required buffer should be 80 */
-            LRESULT rc;
-            if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
-            {
-                WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL);
-                rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
-            }
-            else
-            {
-                rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
-                MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80);
-            }
-            return rc;
-        }
-    }
-    else
-        return 0;
-}
-
-static PCLIENTIMC APIENTRY Imm32GetClientImcCache(void)
-{
-    // FIXME: Do something properly here
-    return NULL;
-}
-
-static NTSTATUS APIENTRY
-Imm32BuildHimcList(DWORD dwThreadId, DWORD dwCount, HIMC *phList, LPDWORD pdwCount)
-{
-    return NtUserBuildHimcList(dwThreadId, dwCount, phList, pdwCount);
-}
-
-static DWORD APIENTRY Imm32AllocAndBuildHimcList(DWORD dwThreadId, HIMC **pphList)
-{
-#define INITIAL_COUNT 0x40
-#define MAX_RETRY 10
-    NTSTATUS Status;
-    DWORD dwCount = INITIAL_COUNT, cRetry = 0;
-    HIMC *phNewList;
-
-    phNewList = Imm32HeapAlloc(0, dwCount * sizeof(HIMC));
-    if (phNewList == NULL)
-        return 0;
-
-    Status = Imm32BuildHimcList(dwThreadId, dwCount, phNewList, &dwCount);
-    while (Status == STATUS_BUFFER_TOO_SMALL)
-    {
-        HeapFree(g_hImm32Heap, 0, phNewList);
-        if (cRetry++ >= MAX_RETRY)
-            return 0;
-
-        phNewList = Imm32HeapAlloc(0, dwCount * sizeof(HIMC));
-        if (phNewList == NULL)
-            return 0;
-
-        Status = Imm32BuildHimcList(dwThreadId, dwCount, phNewList, &dwCount);
-    }
-
-    if (NT_ERROR(Status) || !dwCount)
-    {
-        HeapFree(g_hImm32Heap, 0, phNewList);
-        return 0;
-    }
-
-    *pphList = phNewList;
-    return dwCount;
-#undef INITIAL_COUNT
-#undef MAX_RETRY
-}
-
-static BOOL APIENTRY Imm32ImeNonImeToggle(HIMC hIMC, HKL hKL, HWND hWnd, LANGID LangID)
-{
-    LPINPUTCONTEXT pIC;
-    BOOL fOpen;
-
-    if (hWnd != NULL)
-        return FALSE;
-
-    if (!IS_IME_HKL(hKL) || LOWORD(hKL) != LangID)
-    {
-        FIXME("We have to do something here\n");
-        return TRUE;
-    }
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return TRUE;
-
-    fOpen = pIC->fOpen;
-    ImmUnlockIMC(hIMC);
-
-    if (!fOpen)
-    {
-        ImmSetOpenStatus(hIMC, TRUE);
-        return TRUE;
-    }
-
-    FIXME("We have to do something here\n");
-    return TRUE;
-}
-
-static BOOL APIENTRY Imm32CShapeToggle(HIMC hIMC, HKL hKL, HWND hWnd)
-{
-    LPINPUTCONTEXT pIC;
-    BOOL fOpen;
-    DWORD dwConversion, dwSentence;
-
-    if (hWnd == NULL || !IS_IME_HKL(hKL))
-        return FALSE;
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return TRUE;
-
-    fOpen = pIC->fOpen;
-    if (fOpen)
-    {
-        dwConversion = (pIC->fdwConversion ^ IME_CMODE_FULLSHAPE);
-        dwSentence = pIC->fdwSentence;
-    }
-
-    ImmUnlockIMC(hIMC);
-
-    if (fOpen)
-        ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
-    else
-        ImmSetOpenStatus(hIMC, TRUE);
-
-    return TRUE;
-}
-
-static BOOL APIENTRY Imm32CSymbolToggle(HIMC hIMC, HKL hKL, HWND hWnd)
-{
-    LPINPUTCONTEXT pIC;
-    BOOL fOpen;
-    DWORD dwConversion, dwSentence;
-
-    if (hWnd == NULL || !IS_IME_HKL(hKL))
-        return FALSE;
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return TRUE;
-
-    fOpen = pIC->fOpen;
-    if (fOpen)
-    {
-        dwConversion = (pIC->fdwConversion ^ IME_CMODE_SYMBOL);
-        dwSentence = pIC->fdwSentence;
-    }
-
-    ImmUnlockIMC(hIMC);
-
-    if (fOpen)
-        ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
-    else
-        ImmSetOpenStatus(hIMC, TRUE);
-
-    return TRUE;
-}
-
-static BOOL APIENTRY Imm32JCloseOpen(HIMC hIMC, HKL hKL, HWND hWnd)
-{
-    BOOL fOpen;
-
-    if (ImmIsIME(hKL) && LOWORD(hKL) == LANGID_JAPANESE)
-    {
-        fOpen = ImmGetOpenStatus(hIMC);
-        ImmSetOpenStatus(hIMC, !fOpen);
-        return TRUE;
-    }
-
-    FIXME("We have to do something here\n");
-    return TRUE;
-}
-
-static BOOL APIENTRY Imm32KShapeToggle(HIMC hIMC)
-{
-    LPINPUTCONTEXT pIC;
-    DWORD dwConversion, dwSentence;
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return FALSE;
-
-    dwConversion = (pIC->fdwConversion ^ IME_CMODE_FULLSHAPE);
-    dwSentence = pIC->fdwSentence;
-    ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
-
-    if (pIC->fdwConversion & (IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE))
-        ImmSetOpenStatus(hIMC, TRUE);
-    else
-        ImmSetOpenStatus(hIMC, FALSE);
-
-    ImmUnlockIMC(hIMC);
-    return TRUE;
-}
-
-static BOOL APIENTRY Imm32KHanjaConvert(HIMC hIMC)
-{
-    LPINPUTCONTEXT pIC;
-    DWORD dwConversion, dwSentence;
-
-    pIC = ImmLockIMC(hIMC);
-    if (!pIC)
-        return FALSE;
-
-    dwConversion = (pIC->fdwConversion ^ IME_CMODE_HANJACONVERT);
-    dwSentence = pIC->fdwSentence;
-    ImmUnlockIMC(hIMC);
-
-    ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
-    return TRUE;
-}
-
-static BOOL APIENTRY Imm32KEnglish(HIMC hIMC)
-{
-    LPINPUTCONTEXT pIC;
-    DWORD dwConversion, dwSentence;
-    BOOL fOpen;
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return FALSE;
-
-    dwConversion = (pIC->fdwConversion ^ IME_CMODE_NATIVE);
-    dwSentence = pIC->fdwSentence;
-    ImmSetConversionStatus(hIMC, dwConversion, dwSentence);
-
-    fOpen = ((pIC->fdwConversion & (IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE)) != 0);
-    ImmSetOpenStatus(hIMC, fOpen);
-
-    ImmUnlockIMC(hIMC);
-    return TRUE;
-}
-
-static BOOL APIENTRY Imm32ProcessHotKey(HWND hWnd, HIMC hIMC, HKL hKL, DWORD dwHotKeyID)
-{
-    DWORD dwImeThreadId, dwThreadId;
-    PIMEDPI pImeDpi;
-    BOOL ret;
-
-    if (hIMC)
-    {
-        dwImeThreadId = Imm32QueryInputContext(hIMC, 1);
-        dwThreadId = GetCurrentThreadId();
-        if (dwImeThreadId != dwThreadId)
-            return FALSE;
-    }
-
-    switch (dwHotKeyID)
-    {
-        case IME_CHOTKEY_IME_NONIME_TOGGLE:
-            return Imm32ImeNonImeToggle(hIMC, hKL, hWnd, LANGID_CHINESE_SIMPLIFIED);
-
-        case IME_CHOTKEY_SHAPE_TOGGLE:
-            return Imm32CShapeToggle(hIMC, hKL, hWnd);
-
-        case IME_CHOTKEY_SYMBOL_TOGGLE:
-            return Imm32CSymbolToggle(hIMC, hKL, hWnd);
-
-        case IME_JHOTKEY_CLOSE_OPEN:
-            return Imm32JCloseOpen(hIMC, hKL, hWnd);
-
-        case IME_KHOTKEY_SHAPE_TOGGLE:
-            return Imm32KShapeToggle(hIMC);
-
-        case IME_KHOTKEY_HANJACONVERT:
-            return Imm32KHanjaConvert(hIMC);
-
-        case IME_KHOTKEY_ENGLISH:
-            return Imm32KEnglish(hIMC);
-
-        case IME_THOTKEY_IME_NONIME_TOGGLE:
-            return Imm32ImeNonImeToggle(hIMC, hKL, hWnd, LANGID_CHINESE_TRADITIONAL);
-
-        case IME_THOTKEY_SHAPE_TOGGLE:
-            return Imm32CShapeToggle(hIMC, hKL, hWnd);
-
-        case IME_THOTKEY_SYMBOL_TOGGLE:
-            return Imm32CSymbolToggle(hIMC, hKL, hWnd);
-
-        default:
-            break;
-    }
-
-    if (dwHotKeyID < IME_HOTKEY_PRIVATE_FIRST || IME_HOTKEY_PRIVATE_LAST < dwHotKeyID)
-        return FALSE;
-
-    pImeDpi = ImmLockImeDpi(hKL);
-    if (pImeDpi == NULL)
-        return FALSE;
-
-    ret = (BOOL)pImeDpi->ImeEscape(hIMC, IME_ESC_PRIVATE_HOTKEY, &dwHotKeyID);
-    ImmUnlockImeDpi(pImeDpi);
-    return ret;
-}
-
-PCLIENTIMC WINAPI ImmLockClientImc(HIMC hImc)
+LPINPUTCONTEXT APIENTRY Imm32InternalLockIMC(HIMC hIMC, BOOL fSelect)
 {
+    HANDLE hIC;
+    LPINPUTCONTEXT pIC = NULL;
     PCLIENTIMC pClientImc;
+    WORD LangID;
+    DWORD dwThreadId;
+    HKL hOldKL, hNewKL;
+    PIMEDPI pImeDpi = NULL;
 
-    TRACE("(%p)\n", hImc);
-
-    if (hImc == NULL)
-        return NULL;
-
-    pClientImc = Imm32GetClientImcCache();
+    pClientImc = ImmLockClientImc(hIMC);
     if (!pClientImc)
-    {
-        pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
-        if (!pClientImc)
-            return NULL;
-
-        RtlInitializeCriticalSection(&pClientImc->cs);
-        pClientImc->unknown = Imm32GetThreadState(THREADSTATE_UNKNOWN13);
-
-        if (!Imm32UpdateInputContext(hImc, 0, pClientImc))
-        {
-            HeapFree(g_hImm32Heap, 0, pClientImc);
-            return NULL;
-        }
-
-        pClientImc->dwFlags |= CLIENTIMC_UNKNOWN2;
-    }
-    else
-    {
-        if (pClientImc->dwFlags & CLIENTIMC_UNKNOWN1)
-            return NULL;
-    }
-
-    InterlockedIncrement(&pClientImc->cLockObj);
-    return pClientImc;
-}
-
-VOID WINAPI ImmUnlockClientImc(PCLIENTIMC pClientImc)
-{
-    LONG cLocks;
-    HIMC hImc;
-
-    TRACE("(%p)\n", pClientImc);
-
-    cLocks = InterlockedDecrement(&pClientImc->cLockObj);
-    if (cLocks != 0 || !(pClientImc->dwFlags & CLIENTIMC_UNKNOWN1))
-        return;
-
-    hImc = pClientImc->hImc;
-    if (hImc)
-        LocalFree(hImc);
-
-    RtlDeleteCriticalSection(&pClientImc->cs);
-    HeapFree(g_hImm32Heap, 0, pClientImc);
-}
-
-static DWORD APIENTRY
-CandidateListWideToAnsi(const CANDIDATELIST *pWideCL, LPCANDIDATELIST pAnsiCL, DWORD dwBufLen,
-                        UINT uCodePage)
-{
-    BOOL bUsedDefault;
-    DWORD dwSize, dwIndex, cbGot, cbLeft;
-    const BYTE *pbWide;
-    LPBYTE pbAnsi;
-    LPDWORD pibOffsets;
-
-    /* calculate total ansi size */
-    if (pWideCL->dwCount > 0)
-    {
-        dwSize = sizeof(CANDIDATELIST) + ((pWideCL->dwCount - 1) * sizeof(DWORD));
-        for (dwIndex = 0; dwIndex < pWideCL->dwCount; ++dwIndex)
-        {
-            pbWide = (const BYTE *)pWideCL + pWideCL->dwOffset[dwIndex];
-            cbGot = WideCharToMultiByte(uCodePage, 0, (LPCWSTR)pbWide, -1, NULL, 0,
-                                        NULL, &bUsedDefault);
-            dwSize += cbGot;
-        }
-    }
-    else
-    {
-        dwSize = sizeof(CANDIDATELIST);
-    }
-
-    dwSize = ROUNDUP4(dwSize);
-    if (dwBufLen == 0)
-        return dwSize;
-    if (dwBufLen < dwSize)
-        return 0;
-
-    /* store to ansi */
-    pAnsiCL->dwSize = dwBufLen;
-    pAnsiCL->dwStyle = pWideCL->dwStyle;
-    pAnsiCL->dwCount = pWideCL->dwCount;
-    pAnsiCL->dwSelection = pWideCL->dwSelection;
-    pAnsiCL->dwPageStart = pWideCL->dwPageStart;
-    pAnsiCL->dwPageSize = pWideCL->dwPageSize;
-
-    pibOffsets = pAnsiCL->dwOffset;
-    if (pWideCL->dwCount > 0)
-    {
-        pibOffsets[0] = sizeof(CANDIDATELIST) + ((pWideCL->dwCount - 1) * sizeof(DWORD));
-        cbLeft = dwBufLen - pibOffsets[0];
-
-        for (dwIndex = 0; dwIndex < pWideCL->dwCount; ++dwIndex)
-        {
-            pbWide = (const BYTE *)pWideCL + pWideCL->dwOffset[dwIndex];
-            pbAnsi = (LPBYTE)pAnsiCL + pibOffsets[dwIndex];
-
-            /* convert to ansi */
-            cbGot = WideCharToMultiByte(uCodePage, 0, (LPCWSTR)pbWide, -1,
-                                        (LPSTR)pbAnsi, cbLeft, NULL, &bUsedDefault);
-            cbLeft -= cbGot;
-
-            if (dwIndex < pWideCL->dwCount - 1)
-                pibOffsets[dwIndex + 1] = pibOffsets[dwIndex] + cbGot;
-        }
-    }
-    else
-    {
-        pibOffsets[0] = sizeof(CANDIDATELIST);
-    }
-
-    return dwBufLen;
-}
-
-static DWORD APIENTRY
-CandidateListAnsiToWide(const CANDIDATELIST *pAnsiCL, LPCANDIDATELIST pWideCL, DWORD dwBufLen,
-                        UINT uCodePage)
-{
-    DWORD dwSize, dwIndex, cchGot, cbGot, cbLeft;
-    const BYTE *pbAnsi;
-    LPBYTE pbWide;
-    LPDWORD pibOffsets;
-
-    /* calculate total wide size */
-    if (pAnsiCL->dwCount > 0)
-    {
-        dwSize = sizeof(CANDIDATELIST) + ((pAnsiCL->dwCount - 1) * sizeof(DWORD));
-        for (dwIndex = 0; dwIndex < pAnsiCL->dwCount; ++dwIndex)
-        {
-            pbAnsi = (const BYTE *)pAnsiCL + pAnsiCL->dwOffset[dwIndex];
-            cchGot = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, (LPCSTR)pbAnsi, -1, NULL, 0);
-            dwSize += cchGot * sizeof(WCHAR);
-        }
-    }
-    else
-    {
-        dwSize = sizeof(CANDIDATELIST);
-    }
-
-    dwSize = ROUNDUP4(dwSize);
-    if (dwBufLen == 0)
-        return dwSize;
-    if (dwBufLen < dwSize)
-        return 0;
+        return NULL;
 
-    /* store to wide */
-    pWideCL->dwSize = dwBufLen;
-    pWideCL->dwStyle = pAnsiCL->dwStyle;
-    pWideCL->dwCount = pAnsiCL->dwCount;
-    pWideCL->dwSelection = pAnsiCL->dwSelection;
-    pWideCL->dwPageStart = pAnsiCL->dwPageStart;
-    pWideCL->dwPageSize = pAnsiCL->dwPageSize;
+    RtlEnterCriticalSection(&pClientImc->cs);
 
-    pibOffsets = pWideCL->dwOffset;
-    if (pAnsiCL->dwCount > 0)
+    if (pClientImc->hInputContext)
     {
-        pibOffsets[0] = sizeof(CANDIDATELIST) + ((pWideCL->dwCount - 1) * sizeof(DWORD));
-        cbLeft = dwBufLen - pibOffsets[0];
-
-        for (dwIndex = 0; dwIndex < pAnsiCL->dwCount; ++dwIndex)
-        {
-            pbAnsi = (const BYTE *)pAnsiCL + pAnsiCL->dwOffset[dwIndex];
-            pbWide = (LPBYTE)pWideCL + pibOffsets[dwIndex];
-
-            /* convert to wide */
-            cchGot = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, (LPCSTR)pbAnsi, -1,
-                                         (LPWSTR)pbWide, cbLeft / sizeof(WCHAR));
-            cbGot = cchGot * sizeof(WCHAR);
-            cbLeft -= cbGot;
+        pIC = LocalLock(pClientImc->hInputContext);
+        if (IS_NULL_UNEXPECTEDLY(pIC))
+            goto Failure;
 
-            if (dwIndex + 1 < pAnsiCL->dwCount)
-                pibOffsets[dwIndex + 1] = pibOffsets[dwIndex] + cbGot;
-        }
-    }
-    else
-    {
-        pibOffsets[0] = sizeof(CANDIDATELIST);
-    }
-
-    return dwBufLen;
-}
-
-static DWORD APIENTRY
-ImmGetCandidateListAW(HIMC hIMC, DWORD dwIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen,
-                      BOOL bAnsi)
-{
-    DWORD ret = 0;
-    LPINPUTCONTEXT pIC;
-    PCLIENTIMC pClientImc;
-    LPCANDIDATEINFO pCI;
-    LPCANDIDATELIST pCL;
-    DWORD dwSize;
-
-    pClientImc = ImmLockClientImc(hIMC);
-    if (!pClientImc)
-        return 0;
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-    {
-        ImmUnlockClientImc(pClientImc);
-        return 0;
-    }
-
-    pCI = ImmLockIMCC(pIC->hCandInfo);
-    if (pCI == NULL)
-    {
-        ImmUnlockIMC(hIMC);
-        ImmUnlockClientImc(pClientImc);
-        return 0;
-    }
-
-    if (pCI->dwSize < sizeof(CANDIDATEINFO) || pCI->dwCount <= dwIndex)
-        goto Quit;
-
-    /* get required size */
-    pCL = (LPCANDIDATELIST)((LPBYTE)pCI + pCI->dwOffset[dwIndex]);
-    if (bAnsi)
-    {
-        if (pClientImc->dwFlags & CLIENTIMC_WIDE)
-            dwSize = CandidateListAnsiToWide(pCL, NULL, 0, CP_ACP);
-        else
-            dwSize = pCL->dwSize;
-    }
-    else
-    {
-        if (pClientImc->dwFlags & CLIENTIMC_WIDE)
-            dwSize = pCL->dwSize;
-        else
-            dwSize = CandidateListWideToAnsi(pCL, NULL, 0, CP_ACP);
-    }
-
-    if (dwBufLen != 0 && dwSize != 0)
-    {
-        if (lpCandList == NULL || dwBufLen < dwSize)
-            goto Quit;
-
-        /* store */
-        if (bAnsi)
-        {
-            if (pClientImc->dwFlags & CLIENTIMC_WIDE)
-                CandidateListAnsiToWide(pCL, lpCandList, dwSize, CP_ACP);
-            else
-                RtlCopyMemory(lpCandList, pCL, dwSize);
-        }
-        else
-        {
-            if (pClientImc->dwFlags & CLIENTIMC_WIDE)
-                RtlCopyMemory(lpCandList, pCL, dwSize);
-            else
-                CandidateListWideToAnsi(pCL, lpCandList, dwSize, CP_ACP);
-        }
-    }
-
-    ret = dwSize;
-
-Quit:
-    ImmUnlockIMCC(pIC->hCandInfo);
-    ImmUnlockIMC(hIMC);
-    ImmUnlockClientImc(pClientImc);
-    return ret;
-}
-
-DWORD APIENTRY ImmGetCandidateListCountAW(HIMC hIMC, LPDWORD lpdwListCount, BOOL bAnsi)
-{
-    DWORD ret = 0, cbGot, dwIndex;
-    PCLIENTIMC pClientImc;
-    LPINPUTCONTEXT pIC;
-    const CANDIDATEINFO *pCI;
-    const BYTE *pb;
-    const CANDIDATELIST *pCL;
-    const DWORD *pdwOffsets;
-
-    if (lpdwListCount == NULL)
-        return 0;
-
-    *lpdwListCount = 0;
-
-    pClientImc = ImmLockClientImc(hIMC);
-    if (pClientImc == NULL)
-        return 0;
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-    {
-        ImmUnlockClientImc(pClientImc);
-        return 0;
-    }
-
-    pCI = ImmLockIMCC(pIC->hCandInfo);
-    if (pCI == NULL)
-    {
-        ImmUnlockIMC(hIMC);
-        ImmUnlockClientImc(pClientImc);
-        return 0;
-    }
-
-    if (pCI->dwSize < sizeof(CANDIDATEINFO))
-        goto Quit;
-
-    *lpdwListCount = pCI->dwCount; /* the number of candidate lists */
-
-    /* calculate total size of candidate lists */
-    if (bAnsi)
-    {
-        if (pClientImc->dwFlags & CLIENTIMC_WIDE)
-        {
-            ret = ROUNDUP4(pCI->dwPrivateSize);
-            pdwOffsets = pCI->dwOffset;
-            for (dwIndex = 0; dwIndex < pCI->dwCount; ++dwIndex)
-            {
-                pb = (const BYTE *)pCI + pdwOffsets[dwIndex];
-                pCL = (const CANDIDATELIST *)pb;
-                cbGot = CandidateListWideToAnsi(pCL, NULL, 0, CP_ACP);
-                ret += cbGot;
-            }
-        }
-        else
-        {
-            ret = pCI->dwSize;
-        }
-    }
-    else
-    {
-        if (pClientImc->dwFlags & CLIENTIMC_WIDE)
-        {
-            ret = pCI->dwSize;
-        }
-        else
-        {
-            ret = ROUNDUP4(pCI->dwPrivateSize);
-            pdwOffsets = pCI->dwOffset;
-            for (dwIndex = 0; dwIndex < pCI->dwCount; ++dwIndex)
-            {
-                pb = (const BYTE *)pCI + pdwOffsets[dwIndex];
-                pCL = (const CANDIDATELIST *)pb;
-                cbGot = CandidateListAnsiToWide(pCL, NULL, 0, CP_ACP);
-                ret += cbGot;
-            }
-        }
-    }
-
-Quit:
-    ImmUnlockIMCC(pIC->hCandInfo);
-    ImmUnlockIMC(hIMC);
-    ImmUnlockClientImc(pClientImc);
-    return ret;
-}
-
-/***********************************************************************
- *             ImmGetCandidateListA (IMM32.@)
- */
-DWORD WINAPI ImmGetCandidateListA(
-  HIMC hIMC, DWORD dwIndex,
-  LPCANDIDATELIST lpCandList, DWORD dwBufLen)
-{
-    return ImmGetCandidateListAW(hIMC, dwIndex, lpCandList, dwBufLen, TRUE);
-}
-
-/***********************************************************************
- *             ImmGetCandidateListCountA (IMM32.@)
- */
-DWORD WINAPI ImmGetCandidateListCountA(
-  HIMC hIMC, LPDWORD lpdwListCount)
-{
-    return ImmGetCandidateListCountAW(hIMC, lpdwListCount, TRUE);
-}
-
-/***********************************************************************
- *             ImmGetCandidateListCountW (IMM32.@)
- */
-DWORD WINAPI ImmGetCandidateListCountW(
-  HIMC hIMC, LPDWORD lpdwListCount)
-{
-    return ImmGetCandidateListCountAW(hIMC, lpdwListCount, FALSE);
-}
-
-/***********************************************************************
- *             ImmGetCandidateListW (IMM32.@)
- */
-DWORD WINAPI ImmGetCandidateListW(
-  HIMC hIMC, DWORD dwIndex,
-  LPCANDIDATELIST lpCandList, DWORD dwBufLen)
-{
-    return ImmGetCandidateListAW(hIMC, dwIndex, lpCandList, dwBufLen, FALSE);
-}
-
-/***********************************************************************
- *             ImmGetCandidateWindow (IMM32.@)
- */
-BOOL WINAPI ImmGetCandidateWindow(
-  HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate)
-{
-    BOOL ret = FALSE;
-    LPINPUTCONTEXT pIC;
-    LPCANDIDATEFORM pCF;
-
-    TRACE("(%p, %lu, %p)\n", hIMC, dwIndex, lpCandidate);
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC  == NULL)
-        return FALSE;
-
-    pCF = &pIC->cfCandForm[dwIndex];
-    if (pCF->dwIndex != IMM_INVALID_CANDFORM)
-    {
-        *lpCandidate = *pCF;
-        ret = TRUE;
-    }
-
-    ImmUnlockIMC(hIMC);
-    return ret;
-}
-
-static VOID APIENTRY LogFontAnsiToWide(const LOGFONTA *plfA, LPLOGFONTW plfW)
-{
-    size_t cch;
-    RtlCopyMemory(plfW, plfA, offsetof(LOGFONTA, lfFaceName));
-    StringCchLengthA(plfA->lfFaceName, _countof(plfA->lfFaceName), &cch);
-    cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plfA->lfFaceName, (INT)cch,
-                              plfW->lfFaceName, _countof(plfW->lfFaceName));
-    if (cch > _countof(plfW->lfFaceName) - 1)
-        cch = _countof(plfW->lfFaceName) - 1;
-    plfW->lfFaceName[cch] = 0;
-}
-
-static VOID APIENTRY LogFontWideToAnsi(const LOGFONTW *plfW, LPLOGFONTA plfA)
-{
-    size_t cch;
-    RtlCopyMemory(plfA, plfW, offsetof(LOGFONTW, lfFaceName));
-    StringCchLengthW(plfW->lfFaceName, _countof(plfW->lfFaceName), &cch);
-    cch = WideCharToMultiByte(CP_ACP, 0, plfW->lfFaceName, (INT)cch,
-                              plfA->lfFaceName, _countof(plfA->lfFaceName), NULL, NULL);
-    if (cch > _countof(plfA->lfFaceName) - 1)
-        cch = _countof(plfA->lfFaceName) - 1;
-    plfA->lfFaceName[cch] = 0;
-}
-
-/***********************************************************************
- *             ImmGetCompositionFontA (IMM32.@)
- */
-BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
-{
-    PCLIENTIMC pClientImc;
-    BOOL ret = FALSE, bWide;
-    LPINPUTCONTEXT pIC;
-
-    TRACE("(%p, %p)\n", hIMC, lplf);
-
-    pClientImc = ImmLockClientImc(hIMC);
-    if (pClientImc == NULL)
-        return FALSE;
-
-    bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
-    ImmUnlockClientImc(pClientImc);
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return FALSE;
-
-    if (pIC->fdwInit & INIT_LOGFONT)
-    {
-        if (bWide)
-            LogFontWideToAnsi(&pIC->lfFont.W, lplf);
-        else
-            *lplf = pIC->lfFont.A;
-
-        ret = TRUE;
-    }
-
-    ImmUnlockIMC(hIMC);
-    return ret;
-}
-
-/***********************************************************************
- *             ImmGetCompositionFontW (IMM32.@)
- */
-BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
-{
-    PCLIENTIMC pClientImc;
-    BOOL bWide;
-    LPINPUTCONTEXT pIC;
-    BOOL ret = FALSE;
-
-    TRACE("(%p, %p)\n", hIMC, lplf);
-
-    pClientImc = ImmLockClientImc(hIMC);
-    if (pClientImc == NULL)
-        return FALSE;
-
-    bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
-    ImmUnlockClientImc(pClientImc);
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return FALSE;
-
-    if (pIC->fdwInit & INIT_LOGFONT)
-    {
-        if (bWide)
-            *lplf = pIC->lfFont.W;
-        else
-            LogFontAnsiToWide(&pIC->lfFont.A, lplf);
-
-        ret = TRUE;
-    }
-
-    ImmUnlockIMC(hIMC);
-    return ret;
-}
-
-
-/* Helpers for the GetCompositionString functions */
-
-/* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
-   length is always in bytes. */
-static INT CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst,
-        INT dst_len, BOOL unicode)
-{
-    int char_size = unicode ? sizeof(WCHAR) : sizeof(char);
-    INT ret;
-
-    if (is_himc_ime_unicode(data) ^ unicode)
-    {
-        if (unicode)
-            ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR));
-        else
-            ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL);
-        ret *= char_size;
-    }
-    else
-    {
-        if (dst_len)
-        {
-            ret = min(src_len * char_size, dst_len);
-            memcpy(dst, src, ret);
-        }
-        else
-            ret = src_len * char_size;
-    }
-
-    return ret;
-}
-
-/* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
-   passed mode. String length is in characters, attributes are in byte arrays. */
-static INT CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string,
-        INT str_len, BYTE *dst, INT dst_len, BOOL unicode)
-{
-    union
-    {
-        const void *str;
-        const WCHAR *strW;
-        const char *strA;
-    } string;
-    INT rc;
-
-    string.str = comp_string;
-
-    if (is_himc_ime_unicode(data) && !unicode)
-    {
-        rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL);
-        if (dst_len)
-        {
-            int i, j = 0, k = 0;
-
-            if (rc < dst_len)
-                dst_len = rc;
-            for (i = 0; i < str_len; ++i)
-            {
-                int len;
-
-                len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL);
-                for (; len > 0; --len)
-                {
-                    dst[j++] = src[k];
-
-                    if (j >= dst_len)
-                        goto end;
-                }
-                ++k;
-            }
-        end:
-            rc = j;
-        }
-    }
-    else if (!is_himc_ime_unicode(data) && unicode)
-    {
-        rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0);
-        if (dst_len)
-        {
-            int i, j = 0;
-
-            if (rc < dst_len)
-                dst_len = rc;
-            for (i = 0; i < str_len; ++i)
-            {
-                if (IsDBCSLeadByte(string.strA[i]))
-                    continue;
-
-                dst[j++] = src[i];
-
-                if (j >= dst_len)
-                    break;
-            }
-            rc = j;
-        }
-    }
-    else
-    {
-        memcpy(dst, src, min(src_len, dst_len));
-        rc = src_len;
-    }
-
-    return rc;
-}
-
-static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource,
-                                     LPBYTE target, INT tlen, BOOL unicode )
-{
-    INT rc;
-
-    if (is_himc_ime_unicode(data) && !unicode)
-    {
-        if (tlen)
-        {
-            int i;
-
-            if (slen < tlen)
-                tlen = slen;
-            tlen /= sizeof (DWORD);
-            for (i = 0; i < tlen; ++i)
-            {
-                ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
-                                                          ((DWORD *)source)[i],
-                                                          NULL, 0,
-                                                          NULL, NULL);
-            }
-            rc = sizeof (DWORD) * i;
-        }
-        else
-            rc = slen;
-    }
-    else if (!is_himc_ime_unicode(data) && unicode)
-    {
-        if (tlen)
-        {
-            int i;
-
-            if (slen < tlen)
-                tlen = slen;
-            tlen /= sizeof (DWORD);
-            for (i = 0; i < tlen; ++i)
-            {
-                ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
-                                                          ((DWORD *)source)[i],
-                                                          NULL, 0);
-            }
-            rc = sizeof (DWORD) * i;
-        }
-        else
-            rc = slen;
-    }
-    else
-    {
-        memcpy( target, source, min(slen,tlen));
-        rc = slen;
-    }
-
-    return rc;
-}
-
-static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode)
-{
-    int rc;
-
-    if (is_himc_ime_unicode(data) && !unicode)
-    {
-        rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
-    }
-    else if (!is_himc_ime_unicode(data) && unicode)
-    {
-        rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
-    }
-    else
-        rc = offset;
-
-    return rc;
-}
-
-static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
-                                      DWORD dwBufLen, BOOL unicode)
-{
-    LONG rc = 0;
-    InputContextData *data = get_imc_data(hIMC);
-    LPCOMPOSITIONSTRING compstr;
-    LPBYTE compdata;
-
-    TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
-
-    if (!data)
-       return FALSE;
-
-    if (!data->IMC.hCompStr)
-       return FALSE;
-
-    compdata = ImmLockIMCC(data->IMC.hCompStr);
-    compstr = (LPCOMPOSITIONSTRING)compdata;
-
-    switch (dwIndex)
-    {
-    case GCS_RESULTSTR:
-        TRACE("GCS_RESULTSTR\n");
-        rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
-        break;
-    case GCS_COMPSTR:
-        TRACE("GCS_COMPSTR\n");
-        rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
-        break;
-    case GCS_COMPATTR:
-        TRACE("GCS_COMPATTR\n");
-        rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
-                                     compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
-                                     lpBuf, dwBufLen, unicode);
-        break;
-    case GCS_COMPCLAUSE:
-        TRACE("GCS_COMPCLAUSE\n");
-        rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
-                                       compdata + compstr->dwCompStrOffset,
-                                       lpBuf, dwBufLen, unicode);
-        break;
-    case GCS_RESULTCLAUSE:
-        TRACE("GCS_RESULTCLAUSE\n");
-        rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
-                                       compdata + compstr->dwResultStrOffset,
-                                       lpBuf, dwBufLen, unicode);
-        break;
-    case GCS_RESULTREADSTR:
-        TRACE("GCS_RESULTREADSTR\n");
-        rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
-        break;
-    case GCS_RESULTREADCLAUSE:
-        TRACE("GCS_RESULTREADCLAUSE\n");
-        rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
-                                       compdata + compstr->dwResultStrOffset,
-                                       lpBuf, dwBufLen, unicode);
-        break;
-    case GCS_COMPREADSTR:
-        TRACE("GCS_COMPREADSTR\n");
-        rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
-        break;
-    case GCS_COMPREADATTR:
-        TRACE("GCS_COMPREADATTR\n");
-        rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
-                                     compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
-                                     lpBuf, dwBufLen, unicode);
-        break;
-    case GCS_COMPREADCLAUSE:
-        TRACE("GCS_COMPREADCLAUSE\n");
-        rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
-                                       compdata + compstr->dwCompStrOffset,
-                                       lpBuf, dwBufLen, unicode);
-        break;
-    case GCS_CURSORPOS:
-        TRACE("GCS_CURSORPOS\n");
-        rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
-        break;
-    case GCS_DELTASTART:
-        TRACE("GCS_DELTASTART\n");
-        rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
-        break;
-    default:
-        FIXME("Unhandled index 0x%x\n",dwIndex);
-        break;
-    }
-
-    ImmUnlockIMCC(data->IMC.hCompStr);
-
-    return rc;
-}
-
-/***********************************************************************
- *             ImmGetCompositionStringA (IMM32.@)
- */
-LONG WINAPI ImmGetCompositionStringA(
-  HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
-{
-    return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
-}
-
-
-/***********************************************************************
- *             ImmGetCompositionStringW (IMM32.@)
- */
-LONG WINAPI ImmGetCompositionStringW(
-  HIMC hIMC, DWORD dwIndex,
-  LPVOID lpBuf, DWORD dwBufLen)
-{
-    return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
-}
-
-/***********************************************************************
- *             ImmGetCompositionWindow (IMM32.@)
- */
-BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
-{
-    LPINPUTCONTEXT pIC;
-    BOOL ret = FALSE;
-
-    TRACE("(%p, %p)\n", hIMC, lpCompForm);
-
-    pIC = ImmLockIMC(hIMC);
-    if (!pIC)
-        return FALSE;
-
-    if (pIC->fdwInit & INIT_COMPFORM)
-    {
-        *lpCompForm = pIC->cfCompForm;
-        ret = TRUE;
-    }
-
-    ImmUnlockIMC(hIMC);
-    return ret;
-}
-
-/***********************************************************************
- *             ImmGetContext (IMM32.@)
- *
- */
-HIMC WINAPI ImmGetContext(HWND hWnd)
-{
-    HIMC rc;
-
-    TRACE("%p\n", hWnd);
-
-    if (!IsWindow(hWnd))
-    {
-        SetLastError(ERROR_INVALID_WINDOW_HANDLE);
-        return NULL;
-    }
-
-    rc = GetPropW(hWnd,szwWineIMCProperty);
-    if (rc == (HIMC)-1)
-        rc = NULL;
-    else if (rc == NULL)
-        rc = get_default_context( hWnd );
-
-    if (rc)
-    {
-        InputContextData *data = rc;
-        data->IMC.hWnd = hWnd;
-    }
-
-    TRACE("returning %p\n", rc);
-
-    return rc;
-}
-
-/***********************************************************************
- *             ImmGetConversionListA (IMM32.@)
- */
-DWORD WINAPI ImmGetConversionListA(
-  HKL hKL, HIMC hIMC,
-  LPCSTR pSrc, LPCANDIDATELIST lpDst,
-  DWORD dwBufLen, UINT uFlag)
-{
-    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
-    TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_a(pSrc), lpDst,
-                dwBufLen, uFlag);
-    if (immHkl->hIME && immHkl->pImeConversionList)
-    {
-        if (!is_kbd_ime_unicode(immHkl))
-            return immHkl->pImeConversionList(hIMC,(LPCWSTR)pSrc,lpDst,dwBufLen,uFlag);
-        else
-        {
-            LPCANDIDATELIST lpwDst;
-            DWORD ret = 0, len;
-            LPWSTR pwSrc = strdupAtoW(pSrc);
-
-            len = immHkl->pImeConversionList(hIMC, pwSrc, NULL, 0, uFlag);
-            lpwDst = HeapAlloc(GetProcessHeap(), 0, len);
-            if ( lpwDst )
-            {
-                immHkl->pImeConversionList(hIMC, pwSrc, lpwDst, len, uFlag);
-                ret = convert_candidatelist_WtoA( lpwDst, lpDst, dwBufLen);
-                HeapFree(GetProcessHeap(), 0, lpwDst);
-            }
-            HeapFree(GetProcessHeap(), 0, pwSrc);
-
-            return ret;
-        }
-    }
-    else
-        return 0;
-}
-
-/***********************************************************************
- *             ImmGetConversionListW (IMM32.@)
- */
-DWORD WINAPI ImmGetConversionListW(
-  HKL hKL, HIMC hIMC,
-  LPCWSTR pSrc, LPCANDIDATELIST lpDst,
-  DWORD dwBufLen, UINT uFlag)
-{
-    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
-    TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_w(pSrc), lpDst,
-                dwBufLen, uFlag);
-    if (immHkl->hIME && immHkl->pImeConversionList)
-    {
-        if (is_kbd_ime_unicode(immHkl))
-            return immHkl->pImeConversionList(hIMC,pSrc,lpDst,dwBufLen,uFlag);
-        else
-        {
-            LPCANDIDATELIST lpaDst;
-            DWORD ret = 0, len;
-            LPSTR paSrc = strdupWtoA(pSrc);
-
-            len = immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, NULL, 0, uFlag);
-            lpaDst = HeapAlloc(GetProcessHeap(), 0, len);
-            if ( lpaDst )
-            {
-                immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, lpaDst, len, uFlag);
-                ret = convert_candidatelist_AtoW( lpaDst, lpDst, dwBufLen);
-                HeapFree(GetProcessHeap(), 0, lpaDst);
-            }
-            HeapFree(GetProcessHeap(), 0, paSrc);
-
-            return ret;
-        }
-    }
-    else
-        return 0;
-}
-
-/***********************************************************************
- *             ImmGetConversionStatus (IMM32.@)
- */
-BOOL WINAPI ImmGetConversionStatus(
-  HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
-{
-    LPINPUTCONTEXT pIC;
-
-    TRACE("(%p %p %p)\n", hIMC, lpfdwConversion, lpfdwSentence);
-
-    pIC = ImmLockIMC(hIMC);
-    if (!pIC)
-        return FALSE;
-
-    if (lpfdwConversion)
-        *lpfdwConversion = pIC->fdwConversion;
-    if (lpfdwSentence)
-        *lpfdwSentence = pIC->fdwSentence;
-
-    ImmUnlockIMC(hIMC);
-    return TRUE;
-}
-
-static BOOL needs_ime_window(HWND hwnd)
-{
-    WCHAR classW[8];
-
-    if (GetClassNameW(hwnd, classW, ARRAY_SIZE(classW)) && !lstrcmpW(classW, szwIME))
-        return FALSE;
-    if (GetClassLongPtrW(hwnd, GCL_STYLE) & CS_IME) return FALSE;
-
-    return TRUE;
-}
-
-/***********************************************************************
- *             __wine_register_window (IMM32.@)
- */
-BOOL WINAPI __wine_register_window(HWND hwnd)
-{
-    HWND new = NULL;
-    IMMThreadData *thread_data;
-    TRACE("(%p)\n", hwnd);
-
-    if (!needs_ime_window(hwnd))
-        return FALSE;
-
-    thread_data = IMM_GetThreadData(hwnd, 0);
-    if (!thread_data)
-        return FALSE;
-
-    if (thread_data->disableIME || disable_ime)
-    {
-        TRACE("IME for this thread is disabled\n");
-        LeaveCriticalSection(&threaddata_cs);
-        return FALSE;
-    }
-    thread_data->windowRefs++;
-    TRACE("windowRefs=%u, hwndDefault=%p\n",
-          thread_data->windowRefs, thread_data->hwndDefault);
-
-    /* Create default IME window */
-    if (thread_data->windowRefs == 1)
-    {
-        /* Do not create the window inside of a critical section */
-        LeaveCriticalSection(&threaddata_cs);
-        new = CreateWindowExW( 0, szwIME, szwDefaultIME,
-                               WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS,
-                               0, 0, 1, 1, 0, 0, 0, 0);
-        /* thread_data is in the current thread so we can assume it's still valid */
-        EnterCriticalSection(&threaddata_cs);
-        /* See if anyone beat us */
-        if (thread_data->hwndDefault == NULL)
-        {
-            thread_data->hwndDefault = new;
-            new = NULL;
-            TRACE("Default is %p\n", thread_data->hwndDefault);
-        }
-    }
-
-    LeaveCriticalSection(&threaddata_cs);
-
-    /* Clean up an unused new window outside of the critical section */
-    if (new != NULL)
-        DestroyWindow(new);
-    return TRUE;
-}
-
-/***********************************************************************
- *             __wine_unregister_window (IMM32.@)
- */
-void WINAPI __wine_unregister_window(HWND hwnd)
-{
-    HWND to_destroy = 0;
-    IMMThreadData *thread_data;
-    TRACE("(%p)\n", hwnd);
-
-    thread_data = IMM_GetThreadData(hwnd, 0);
-    if (!thread_data) return;
-
-    thread_data->windowRefs--;
-    TRACE("windowRefs=%u, hwndDefault=%p\n",
-          thread_data->windowRefs, thread_data->hwndDefault);
-
-    /* Destroy default IME window */
-    if (thread_data->windowRefs == 0 && thread_data->hwndDefault)
-    {
-        to_destroy = thread_data->hwndDefault;
-        thread_data->hwndDefault = NULL;
-    }
-    LeaveCriticalSection(&threaddata_cs);
-
-    if (to_destroy) DestroyWindow( to_destroy );
-}
-
-/***********************************************************************
- *             ImmGetDefaultIMEWnd (IMM32.@)
- */
-HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
-{
-    if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
-        return NULL;
-
-    if (hWnd == NULL)
-        return (HWND)Imm32GetThreadState(THREADSTATE_ACTIVEWINDOW);
-
-    return (HWND)Imm32QueryWindow(hWnd, QUERY_WINDOW_DEFAULT_IME);
-}
-
-/***********************************************************************
- *             CtfImmIsCiceroEnabled (IMM32.@)
- */
-BOOL WINAPI CtfImmIsCiceroEnabled(VOID)
-{
-    return (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED));
-}
-
-/***********************************************************************
- *             ImmGetDescriptionA (IMM32.@)
- */
-UINT WINAPI ImmGetDescriptionA(
-  HKL hKL, LPSTR lpszDescription, UINT uBufLen)
-{
-    IMEINFOEX info;
-    size_t cch;
-
-    TRACE("(%p,%p,%d)\n", hKL, lpszDescription, uBufLen);
-
-    if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
-        return 0;
-
-    StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
-    cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeDescription, (INT)cch,
-                              lpszDescription, uBufLen, NULL, NULL);
-    if (uBufLen)
-        lpszDescription[cch] = 0;
-    return cch;
-}
-
-/***********************************************************************
- *             ImmGetDescriptionW (IMM32.@)
- */
-UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
-{
-    IMEINFOEX info;
-    size_t cch;
-
-    TRACE("(%p, %p, %d)\n", hKL, lpszDescription, uBufLen);
-
-    if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
-        return 0;
-
-    if (uBufLen != 0)
-        StringCchCopyW(lpszDescription, uBufLen, info.wszImeDescription);
-
-    StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
-    return (UINT)cch;
-}
-
-static DWORD APIENTRY
-ImmGetGuideLineAW(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen, BOOL bAnsi)
-{
-    PCLIENTIMC pClientImc;
-    LPINPUTCONTEXT pIC;
-    LPGUIDELINE pGuideLine;
-    DWORD cb, ret = 0;
-    LPVOID pvStr, pvPrivate;
-    BOOL bUsedDefault;
-
-    pClientImc = ImmLockClientImc(hIMC);
-    if (!pClientImc)
-        return 0;
-
-    pIC = ImmLockIMC(hIMC);
-    if (!pIC)
-    {
-        ImmUnlockClientImc(pClientImc);
-        return 0;
-    }
-
-    pGuideLine = ImmLockIMCC(pIC->hGuideLine);
-    if (!pGuideLine)
-    {
-        ImmUnlockIMC(hIMC);
-        ImmUnlockClientImc(pClientImc);
-        return 0;
-    }
-
-    if (dwIndex == GGL_LEVEL)
-    {
-        ret = pGuideLine->dwLevel;
-        goto Quit;
-    }
-
-    if (dwIndex == GGL_INDEX)
-    {
-        ret = pGuideLine->dwIndex;
-        goto Quit;
-    }
-
-    if (dwIndex == GGL_STRING)
-    {
-        pvStr = (LPBYTE)pGuideLine + pGuideLine->dwStrOffset;
-
-        /* get size */
-        if (bAnsi)
-        {
-            if (pClientImc->dwFlags & CLIENTIMC_WIDE)
-            {
-                cb = WideCharToMultiByte(CP_ACP, 0, pvStr, pGuideLine->dwStrLen,
-                                         NULL, 0, NULL, &bUsedDefault);
-            }
-            else
-            {
-                cb = pGuideLine->dwStrLen * sizeof(CHAR);
-            }
-        }
-        else
-        {
-            if (pClientImc->dwFlags & CLIENTIMC_WIDE)
-            {
-                cb = pGuideLine->dwStrLen * sizeof(WCHAR);
-            }
-            else
-            {
-                cb = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pvStr, pGuideLine->dwStrLen,
-                                         NULL, 0) * sizeof(WCHAR);
-            }
-        }
-
-        if (dwBufLen == 0 || cb == 0 || lpBuf == NULL || dwBufLen < cb)
-        {
-            ret = cb;
-            goto Quit;
-        }
-
-        /* store to buffer */
-        if (bAnsi)
-        {
-            if (pClientImc->dwFlags & CLIENTIMC_WIDE)
-            {
-                ret = WideCharToMultiByte(CP_ACP, 0, pvStr, pGuideLine->dwStrLen,
-                                          lpBuf, dwBufLen, NULL, &bUsedDefault);
-                goto Quit;
-            }
-        }
-        else
-        {
-            if (!(pClientImc->dwFlags & CLIENTIMC_WIDE))
-            {
-                ret = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pvStr, pGuideLine->dwStrLen,
-                                          lpBuf, dwBufLen) * sizeof(WCHAR);
-                goto Quit;
-            }
-        }
-
-        RtlCopyMemory(lpBuf, pvStr, cb);
-        ret = cb;
-        goto Quit;
-    }
-
-    if (dwIndex == GGL_PRIVATE)
-    {
-        pvPrivate = (LPBYTE)pGuideLine + pGuideLine->dwPrivateOffset;
-
-        /* get size */
-        if (bAnsi)
-        {
-            if ((pClientImc->dwFlags & CLIENTIMC_WIDE) &&
-                pGuideLine->dwIndex == GL_ID_REVERSECONVERSION)
-            {
-                cb = CandidateListWideToAnsi(pvPrivate, NULL, 0, CP_ACP);
-            }
-            else
-            {
-                cb = pGuideLine->dwPrivateSize;
-            }
-        }
-        else
-        {
-            if (!(pClientImc->dwFlags & CLIENTIMC_WIDE) &&
-                pGuideLine->dwIndex == GL_ID_REVERSECONVERSION)
-            {
-                cb = CandidateListAnsiToWide(pvPrivate, NULL, 0, CP_ACP);
-            }
-            else
-            {
-                cb = pGuideLine->dwPrivateSize;
-            }
-        }
-
-        if (dwBufLen == 0 || cb == 0 || lpBuf == NULL || dwBufLen < cb)
-        {
-            ret = cb;
-            goto Quit;
-        }
-
-        /* store to buffer */
-        if (bAnsi)
-        {
-            if ((pClientImc->dwFlags & CLIENTIMC_WIDE) &&
-                pGuideLine->dwIndex == GL_ID_REVERSECONVERSION)
-            {
-                ret = CandidateListWideToAnsi(pvPrivate, lpBuf, cb, CP_ACP);
-                goto Quit;
-            }
-        }
-        else
-        {
-            if (!(pClientImc->dwFlags & CLIENTIMC_WIDE) &&
-                pGuideLine->dwIndex == GL_ID_REVERSECONVERSION)
-            {
-                ret = CandidateListAnsiToWide(pvPrivate, lpBuf, cb, CP_ACP);
-                goto Quit;
-            }
-        }
-
-        RtlCopyMemory(lpBuf, pvPrivate, cb);
-        ret = cb;
-        goto Quit;
-    }
-
-Quit:
-    ImmUnlockIMCC(pIC->hGuideLine);
-    ImmUnlockIMC(hIMC);
-    ImmUnlockClientImc(pClientImc);
-    return ret;
-}
-
-/***********************************************************************
- *             ImmGetGuideLineA (IMM32.@)
- */
-DWORD WINAPI ImmGetGuideLineA(
-  HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
-{
-    TRACE("(%p, %lu, %p, %lu)\n", hIMC, dwIndex, lpBuf, dwBufLen);
-    return ImmGetGuideLineAW(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
-}
-
-/***********************************************************************
- *             ImmGetGuideLineW (IMM32.@)
- */
-DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
-{
-    TRACE("(%p, %lu, %p, %lu)\n", hIMC, dwIndex, lpBuf, dwBufLen);
-    return ImmGetGuideLineAW(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
-}
-
-/***********************************************************************
- *             ImmGetIMEFileNameA (IMM32.@)
- */
-UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
-{
-    BOOL bDefUsed;
-    IMEINFOEX info;
-    size_t cch;
-
-    TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen);
-
-    if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
-    {
-        if (uBufLen > 0)
-            lpszFileName[0] = 0;
-        return 0;
-    }
-
-    StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch);
-
-    cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeFile, (INT)cch,
-                              lpszFileName, uBufLen, NULL, &bDefUsed);
-    if (uBufLen == 0)
-        return (UINT)cch;
-
-    if (cch > uBufLen - 1)
-        cch = uBufLen - 1;
-
-    lpszFileName[cch] = 0;
-    return (UINT)cch;
-}
-
-/***********************************************************************
- *             ImmGetIMEFileNameW (IMM32.@)
- */
-UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
-{
-    IMEINFOEX info;
-    size_t cch;
-
-    TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen);
-
-    if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
-    {
-        if (uBufLen > 0)
-            lpszFileName[0] = 0;
-        return 0;
-    }
-
-    StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch);
-    if (uBufLen == 0)
-        return (UINT)cch;
-
-    StringCchCopyNW(lpszFileName, uBufLen, info.wszImeFile, cch);
-
-    if (cch > uBufLen - 1)
-        cch = uBufLen - 1;
-
-    lpszFileName[cch] = 0;
-    return (UINT)cch;
-}
-
-/***********************************************************************
- *             ImmGetOpenStatus (IMM32.@)
- */
-BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
-{
-    BOOL ret;
-    LPINPUTCONTEXT pIC;
-
-    TRACE("(%p)\n", hIMC);
-
-    if (!hIMC)
-        return FALSE;
-
-    pIC = ImmLockIMC(hIMC);
-    if (!pIC)
-        return FALSE;
-
-    ret = pIC->fOpen;
-
-    ImmUnlockIMC(hIMC);
-    return ret;
-}
-
-/***********************************************************************
- *             ImmGetProperty (IMM32.@)
- */
-DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
-{
-    DWORD rc = 0;
-    ImmHkl *kbd;
-
-    TRACE("(%p, %d)\n", hKL, fdwIndex);
-    kbd = IMM_GetImmHkl(hKL);
-
-    if (kbd && kbd->hIME)
-    {
-        switch (fdwIndex)
-        {
-            case IGP_PROPERTY: rc = kbd->imeInfo.fdwProperty; break;
-            case IGP_CONVERSION: rc = kbd->imeInfo.fdwConversionCaps; break;
-            case IGP_SENTENCE: rc = kbd->imeInfo.fdwSentenceCaps; break;
-            case IGP_SETCOMPSTR: rc = kbd->imeInfo.fdwSCSCaps; break;
-            case IGP_SELECT: rc = kbd->imeInfo.fdwSelectCaps; break;
-            case IGP_GETIMEVERSION: rc = IMEVER_0400; break;
-            case IGP_UI: rc = 0; break;
-            default: rc = 0;
-        }
-    }
-    return rc;
-}
-
-/***********************************************************************
- *             ImmGetRegisterWordStyleA (IMM32.@)
- */
-UINT WINAPI ImmGetRegisterWordStyleA(
-  HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
-{
-    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
-    TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
-    if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
-    {
-        if (!is_kbd_ime_unicode(immHkl))
-            return immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)lpStyleBuf);
-        else
-        {
-            STYLEBUFW sbw;
-            UINT rc;
-
-            rc = immHkl->pImeGetRegisterWordStyle(nItem,&sbw);
-            WideCharToMultiByte(CP_ACP, 0, sbw.szDescription, -1,
-                lpStyleBuf->szDescription, 32, NULL, NULL);
-            lpStyleBuf->dwStyle = sbw.dwStyle;
-            return rc;
-        }
-    }
-    else
-        return 0;
-}
-
-/***********************************************************************
- *             ImmGetRegisterWordStyleW (IMM32.@)
- */
-UINT WINAPI ImmGetRegisterWordStyleW(
-  HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
-{
-    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
-    TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
-    if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
-    {
-        if (is_kbd_ime_unicode(immHkl))
-            return immHkl->pImeGetRegisterWordStyle(nItem,lpStyleBuf);
-        else
-        {
-            STYLEBUFA sba;
-            UINT rc;
-
-            rc = immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)&sba);
-            MultiByteToWideChar(CP_ACP, 0, sba.szDescription, -1,
-                lpStyleBuf->szDescription, 32);
-            lpStyleBuf->dwStyle = sba.dwStyle;
-            return rc;
-        }
-    }
-    else
-        return 0;
-}
-
-/***********************************************************************
- *             ImmGetStatusWindowPos (IMM32.@)
- */
-BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
-{
-    LPINPUTCONTEXT pIC;
-    BOOL ret;
-
-    TRACE("(%p, %p)\n", hIMC, lpptPos);
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return FALSE;
-
-    ret = !!(pIC->fdwInit & INIT_STATUSWNDPOS);
-    if (ret)
-        *lpptPos = pIC->ptStatusWndPos;
-
-    ImmUnlockIMC(hIMC);
-    return ret;
-}
-
-/***********************************************************************
- *             ImmGetVirtualKey (IMM32.@)
- */
-UINT WINAPI ImmGetVirtualKey(HWND hWnd)
-{
-    HIMC hIMC;
-    LPINPUTCONTEXTDX pIC;
-    UINT ret = VK_PROCESSKEY;
-
-    TRACE("(%p)\n", hWnd);
-
-    hIMC = ImmGetContext(hWnd);
-    pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
-    if (!pIC)
-        return ret;
-
-    if (pIC->bHasVKey)
-        ret = pIC->nVKey;
-
-    ImmUnlockIMC(hIMC);
-    return ret;
-}
-
-/***********************************************************************
- *             ImmInstallIMEA (IMM32.@)
- */
-HKL WINAPI ImmInstallIMEA(
-  LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
-{
-    INT cchFileName, cchLayoutText;
-    LPWSTR pszFileNameW, pszLayoutTextW;
-    HKL hKL;
-
-    TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText));
-
-    cchFileName = lstrlenA(lpszIMEFileName) + 1;
-    cchLayoutText = lstrlenA(lpszLayoutText) + 1;
-
-    pszFileNameW = Imm32HeapAlloc(0, cchFileName * sizeof(WCHAR));
-    if (pszFileNameW == NULL)
-        return NULL;
-
-    pszLayoutTextW = Imm32HeapAlloc(0, cchLayoutText * sizeof(WCHAR));
-    if (pszLayoutTextW == NULL)
-    {
-        HeapFree(g_hImm32Heap, 0, pszFileNameW);
-        return NULL;
-    }
-
-    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpszIMEFileName, -1, pszFileNameW, cchFileName);
-    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpszLayoutText, -1, pszLayoutTextW, cchLayoutText);
-
-    hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW);
-    HeapFree(g_hImm32Heap, 0, pszFileNameW);
-    HeapFree(g_hImm32Heap, 0, pszLayoutTextW);
-    return hKL;
-}
-
-/***********************************************************************
- *             ImmInstallIMEW (IMM32.@)
- */
-HKL WINAPI ImmInstallIMEW(
-  LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
-{
-    INT lcid = GetUserDefaultLCID();
-    INT count;
-    HKL hkl;
-    DWORD rc;
-    HKEY hkey;
-    WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
-
-    TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
-                          debugstr_w(lpszLayoutText));
-
-    /* Start with 2.  e001 will be blank and so default to the wine internal IME */
-    count = 2;
-
-    while (count < 0xfff)
-    {
-        DWORD disposition = 0;
-
-        hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
-        wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
-
-        rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
-        if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
-            break;
-        else if (rc == ERROR_SUCCESS)
-            RegCloseKey(hkey);
-
-        count++;
-    }
-
-    if (count == 0xfff)
-    {
-        WARN("Unable to find slot to install IME\n");
-        return 0;
-    }
-
-    if (rc == ERROR_SUCCESS)
-    {
-        rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName,
-                            (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
-        if (rc == ERROR_SUCCESS)
-            rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText,
-                                (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
-        RegCloseKey(hkey);
-        return hkl;
-    }
-    else
-    {
-        WARN("Unable to set IME registry values\n");
-        return 0;
-    }
-}
-
-/***********************************************************************
- *             ImmIsIME (IMM32.@)
- */
-BOOL WINAPI ImmIsIME(HKL hKL)
-{
-    IMEINFOEX info;
-    TRACE("(%p)\n", hKL);
-    return !!ImmGetImeInfoEx(&info, ImeInfoExImeWindow, &hKL);
-}
-
-/***********************************************************************
- *             ImmIsUIMessageA (IMM32.@)
- */
-BOOL WINAPI ImmIsUIMessageA(
-  HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
-{
-    TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
-    if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
-            (msg == WM_IME_SETCONTEXT) ||
-            (msg == WM_IME_NOTIFY) ||
-            (msg == WM_IME_COMPOSITIONFULL) ||
-            (msg == WM_IME_SELECT) ||
-            (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
-    {
-        if (hWndIME)
-            SendMessageA(hWndIME, msg, wParam, lParam);
-
-        return TRUE;
-    }
-    return FALSE;
-}
-
-/***********************************************************************
- *             ImmIsUIMessageW (IMM32.@)
- */
-BOOL WINAPI ImmIsUIMessageW(
-  HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
-{
-    TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
-    if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
-            (msg == WM_IME_SETCONTEXT) ||
-            (msg == WM_IME_NOTIFY) ||
-            (msg == WM_IME_COMPOSITIONFULL) ||
-            (msg == WM_IME_SELECT) ||
-            (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
-    {
-        if (hWndIME)
-            SendMessageW(hWndIME, msg, wParam, lParam);
-
-        return TRUE;
-    }
-    return FALSE;
-}
-
-/***********************************************************************
- *             ImmNotifyIME (IMM32.@)
- */
-BOOL WINAPI ImmNotifyIME(
-  HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
-{
-    DWORD dwImeThreadId, dwThreadId;
-    HKL hKL;
-    PIMEDPI pImeDpi;
-    BOOL ret;
-
-    TRACE("(%p, %lu, %lu, %lu)\n", hIMC, dwAction, dwIndex, dwValue);
-
-    if (hIMC)
-    {
-        dwImeThreadId = Imm32QueryWindow(hIMC, QUERY_WINDOW_UNIQUE_THREAD_ID);
-        dwThreadId = GetCurrentThreadId();
-        if (dwImeThreadId != dwThreadId)
-            return FALSE;
-    }
-
-    hKL = GetKeyboardLayout(0);
-    pImeDpi = ImmLockImeDpi(hKL);
-    if (pImeDpi == NULL)
-        return FALSE;
-
-    ret = pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue);
-    ImmUnlockImeDpi(pImeDpi);
-    return ret;
-}
-
-/***********************************************************************
- *             ImmRegisterWordA (IMM32.@)
- */
-BOOL WINAPI ImmRegisterWordA(
-  HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
-{
-    BOOL ret = FALSE;
-    PIMEDPI pImeDpi;
-    LPWSTR pszReadingW = NULL, pszRegisterW = NULL;
-    INT cch;
-
-    TRACE("(%p, %s, 0x%lX, %s)\n", hKL, debugstr_a(lpszReading), dwStyle,
-          debugstr_a(lpszRegister));
-
-    pImeDpi = ImmLockOrLoadImeDpi(hKL);
-    if (!pImeDpi)
-        return FALSE;
-
-    if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE))
-    {
-        ret = pImeDpi->ImeRegisterWord(lpszReading, dwStyle, lpszRegister);
-        ImmUnlockImeDpi(pImeDpi);
-        return ret;
-    }
-
-    if (lpszReading)
-    {
-        cch = lstrlenA(lpszReading);
-        pszReadingW = Imm32HeapAlloc(0, (cch + 1) * sizeof(WCHAR));
-        if (pszReadingW == NULL)
-            goto Quit;
-        cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpszReading, cch,
-                                  pszReadingW, cch + 1);
-        pszReadingW[cch] = 0;
-    }
-
-    if (lpszRegister)
-    {
-        cch = lstrlenA(lpszRegister);
-        pszRegisterW = Imm32HeapAlloc(0, (cch + 1) * sizeof(WCHAR));
-        if (pszRegisterW == NULL)
-            goto Quit;
-        cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpszRegister, cch,
-                                  pszRegisterW, cch + 1);
-        pszRegisterW[cch] = 0;
-    }
-
-    ret = pImeDpi->ImeRegisterWord(pszReadingW, dwStyle, pszRegisterW);
-
-Quit:
-    if (pszReadingW)
-        HeapFree(g_hImm32Heap, 0, pszReadingW);
-    if (pszRegisterW)
-        HeapFree(g_hImm32Heap, 0, pszRegisterW);
-    ImmUnlockImeDpi(pImeDpi);
-    return ret;
-}
-
-/***********************************************************************
- *             ImmRegisterWordW (IMM32.@)
- */
-BOOL WINAPI ImmRegisterWordW(
-  HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
-{
-    BOOL ret = FALSE;
-    PIMEDPI pImeDpi;
-    LPSTR pszReadingA = NULL, pszRegisterA = NULL;
-    INT cchW, cchA;
-
-    TRACE("(%p, %s, 0x%lX, %s)\n", hKL, debugstr_w(lpszReading), dwStyle,
-          debugstr_w(lpszRegister));
-
-    pImeDpi = ImmLockOrLoadImeDpi(hKL);
-    if (!pImeDpi)
-        return FALSE;
-
-    if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)
-    {
-        ret = pImeDpi->ImeRegisterWord(lpszReading, dwStyle, lpszRegister);
-        ImmUnlockImeDpi(pImeDpi);
-        return ret;
-    }
-
-    if (lpszReading)
-    {
-        cchW = lstrlenW(lpszReading);
-        cchA = (cchW + 1) * sizeof(WCHAR);
-        pszReadingA = Imm32HeapAlloc(0, cchA);
-        if (!pszReadingA)
-            goto Quit;
-        cchA = WideCharToMultiByte(CP_ACP, 0, lpszReading, cchW, pszReadingA, cchA, NULL, NULL);
-        pszReadingA[cchA] = 0;
-    }
-
-    if (lpszRegister)
-    {
-        cchW = lstrlenW(lpszRegister);
-        cchA = (cchW + 1) * sizeof(WCHAR);
-        pszRegisterA = Imm32HeapAlloc(0, cchA);
-        if (!pszRegisterA)
-            goto Quit;
-        cchA = WideCharToMultiByte(CP_ACP, 0, lpszRegister, cchW, pszRegisterA, cchA, NULL, NULL);
-        pszRegisterA[cchA] = 0;
-    }
-
-    ret = pImeDpi->ImeRegisterWord(pszReadingA, dwStyle, pszRegisterA);
-
-Quit:
-    if (pszReadingA)
-        HeapFree(g_hImm32Heap, 0, pszReadingA);
-    if (pszRegisterA)
-        HeapFree(g_hImm32Heap, 0, pszRegisterA);
-    ImmUnlockImeDpi(pImeDpi);
-    return ret;
-}
-
-/***********************************************************************
- *             ImmReleaseContext (IMM32.@)
- */
-BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
-{
-  static BOOL shown = FALSE;
-
-  if (!shown) {
-     FIXME("(%p, %p): stub\n", hWnd, hIMC);
-     shown = TRUE;
-  }
-  return TRUE;
-}
-
-/***********************************************************************
-*              ImmRequestMessageA(IMM32.@)
-*/
-LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
-{
-    InputContextData *data = get_imc_data(hIMC);
-
-    TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
-
-    if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
-
-    SetLastError(ERROR_INVALID_HANDLE);
-    return 0;
-}
-
-/***********************************************************************
-*              ImmRequestMessageW(IMM32.@)
-*/
-LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
-{
-    InputContextData *data = get_imc_data(hIMC);
-
-    TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
-
-    if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
-
-    SetLastError(ERROR_INVALID_HANDLE);
-    return 0;
-}
-
-/***********************************************************************
- *             ImmSetCandidateWindow (IMM32.@)
- */
-BOOL WINAPI ImmSetCandidateWindow(
-  HIMC hIMC, LPCANDIDATEFORM lpCandidate)
-{
-#define MAX_CANDIDATEFORM 4
-    DWORD dwImeThreadId, dwThreadId;
-    HWND hWnd;
-    LPINPUTCONTEXT pIC;
-
-    TRACE("(%p, %p)\n", hIMC, lpCandidate);
-
-    if (lpCandidate->dwIndex >= MAX_CANDIDATEFORM)
-        return FALSE;
-
-    dwImeThreadId = Imm32QueryInputContext(hIMC, 1);
-    dwThreadId = GetCurrentThreadId();
-    if (dwImeThreadId != dwThreadId)
-        return FALSE;
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return FALSE;
-
-    hWnd = pIC->hWnd;
-    pIC->cfCandForm[lpCandidate->dwIndex] = *lpCandidate;
-
-    ImmUnlockIMC(hIMC);
-
-    Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS,
-                      IMN_SETCANDIDATEPOS, (1 << lpCandidate->dwIndex));
-    return TRUE;
-#undef MAX_CANDIDATEFORM
-}
-
-static VOID APIENTRY WideToAnsiLogFont(const LOGFONTW *plfW, LPLOGFONTA plfA)
-{
-    BOOL bUsedDef;
-    size_t cchW, cchA = _countof(plfA->lfFaceName);
-    RtlCopyMemory(plfA, plfW, offsetof(LOGFONTA, lfFaceName));
-    StringCchLengthW(plfW->lfFaceName, _countof(plfW->lfFaceName), &cchW);
-    cchA = WideCharToMultiByte(CP_ACP, 0, plfW->lfFaceName, (INT)cchW,
-                               plfA->lfFaceName, (INT)cchA, NULL, &bUsedDef);
-    if (cchA > _countof(plfA->lfFaceName) - 1)
-        cchA = _countof(plfA->lfFaceName) - 1;
-    plfA->lfFaceName[cchA] = 0;
-}
-
-static VOID APIENTRY AnsiToWideLogFont(const LOGFONTA *plfA, LPLOGFONTW plfW)
-{
-    size_t cchA, cchW = _countof(plfW->lfFaceName);
-    RtlCopyMemory(plfW, plfA, offsetof(LOGFONTW, lfFaceName));
-    StringCchLengthA(plfA->lfFaceName, _countof(plfA->lfFaceName), &cchA);
-    cchW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plfA->lfFaceName, (INT)cchA,
-                               plfW->lfFaceName, cchW);
-    if (cchW > _countof(plfW->lfFaceName) - 1)
-        cchW = _countof(plfW->lfFaceName) - 1;
-    plfW->lfFaceName[cchW] = 0;
-}
-
-/***********************************************************************
- *             ImmSetCompositionFontA (IMM32.@)
- */
-BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
-{
-    LOGFONTW lfW;
-    DWORD dwImeThreadId, dwThreadId;
-    PCLIENTIMC pClientImc;
-    BOOL bWide;
-    LPINPUTCONTEXTDX pIC;
-    LCID lcid;
-    HWND hWnd;
-    PTEB pTeb;
-
-    TRACE("(%p, %p)\n", hIMC, lplf);
-
-    dwImeThreadId = Imm32QueryInputContext(hIMC, 1);
-    dwThreadId = GetCurrentThreadId();
-    if (dwImeThreadId != dwThreadId)
-        return FALSE;
-
-    pClientImc = ImmLockClientImc(hIMC);
-    if (pClientImc == NULL)
-        return FALSE;
-
-    bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
-    ImmUnlockClientImc(pClientImc);
-
-    if (bWide)
-    {
-        AnsiToWideLogFont(lplf, &lfW);
-        return ImmSetCompositionFontW(hIMC, &lfW);
-    }
-
-    pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return FALSE;
-
-    pTeb = NtCurrentTeb();
-    if (pTeb->Win32ClientInfo[2] < 0x400)
-    {
-        lcid = GetSystemDefaultLCID();
-        if (PRIMARYLANGID(lcid) == LANG_JAPANESE && !(pIC->dwUIFlags & 2) &&
-            pIC->cfCompForm.dwStyle != CFS_DEFAULT)
-        {
-            PostMessageA(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
-        }
-    }
-
-    pIC->lfFont.A = *lplf;
-    pIC->fdwInit |= INIT_LOGFONT;
-    hWnd = pIC->hWnd;
-
-    ImmUnlockIMC(hIMC);
-
-    Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT,
-                      IMN_SETCOMPOSITIONFONT, 0);
-    return TRUE;
-}
-
-/***********************************************************************
- *             ImmSetCompositionFontW (IMM32.@)
- */
-BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
-{
-    LOGFONTA lfA;
-    DWORD dwImeThreadId, dwThreadId;
-    PCLIENTIMC pClientImc;
-    BOOL bWide;
-    HWND hWnd;
-    LPINPUTCONTEXTDX pIC;
-    PTEB pTeb;
-    LCID lcid;
-
-    TRACE("(%p, %p)\n", hIMC, lplf);
-
-    dwImeThreadId = Imm32QueryInputContext(hIMC, 1);
-    dwThreadId = GetCurrentThreadId();
-    if (dwImeThreadId != dwThreadId)
-        return FALSE;
-
-    pClientImc = ImmLockClientImc(hIMC);
-    if (pClientImc == NULL)
-        return FALSE;
-
-    bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
-    ImmUnlockClientImc(pClientImc);
-
-    if (!bWide)
-    {
-        WideToAnsiLogFont(lplf, &lfA);
-        return ImmSetCompositionFontA(hIMC, &lfA);
-    }
-
-    pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return FALSE;
-
-    pTeb = NtCurrentTeb();
-    if (pTeb->Win32ClientInfo[2] < 0x400)
-    {
-        lcid = GetSystemDefaultLCID();
-        if (PRIMARYLANGID(lcid) == LANG_JAPANESE &&
-            !(pIC->dwUIFlags & 2) &&
-            pIC->cfCompForm.dwStyle != CFS_DEFAULT)
-        {
-            PostMessageW(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
-        }
-    }
-
-    pIC->lfFont.W = *lplf;
-    pIC->fdwInit |= INIT_LOGFONT;
-    hWnd = pIC->hWnd;
-
-    ImmUnlockIMC(hIMC);
-
-    Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT,
-                      IMN_SETCOMPOSITIONFONT, 0);
-    return TRUE;
-}
-
-/***********************************************************************
- *             ImmSetCompositionStringA (IMM32.@)
- */
-BOOL WINAPI ImmSetCompositionStringA(
-  HIMC hIMC, DWORD dwIndex,
-  LPCVOID lpComp, DWORD dwCompLen,
-  LPCVOID lpRead, DWORD dwReadLen)
-{
-    DWORD comp_len;
-    DWORD read_len;
-    WCHAR *CompBuffer = NULL;
-    WCHAR *ReadBuffer = NULL;
-    BOOL rc;
-    InputContextData *data = get_imc_data(hIMC);
-
-    TRACE("(%p, %d, %p, %d, %p, %d):\n",
-            hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
-
-    if (!data)
-        return FALSE;
-
-    if (!(dwIndex == SCS_SETSTR ||
-          dwIndex == SCS_CHANGEATTR ||
-          dwIndex == SCS_CHANGECLAUSE ||
-          dwIndex == SCS_SETRECONVERTSTRING ||
-          dwIndex == SCS_QUERYRECONVERTSTRING))
-        return FALSE;
-
-    if (!is_himc_ime_unicode(data))
-        return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
-                        dwCompLen, lpRead, dwReadLen);
-
-    comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
-    if (comp_len)
-    {
-        CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
-        MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
-    }
-
-    read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
-    if (read_len)
-    {
-        ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
-        MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
-    }
-
-    rc =  ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
-                                   ReadBuffer, read_len);
-
-    HeapFree(GetProcessHeap(), 0, CompBuffer);
-    HeapFree(GetProcessHeap(), 0, ReadBuffer);
-
-    return rc;
-}
-
-/***********************************************************************
- *             ImmSetCompositionStringW (IMM32.@)
- */
-BOOL WINAPI ImmSetCompositionStringW(
-       HIMC hIMC, DWORD dwIndex,
-       LPCVOID lpComp, DWORD dwCompLen,
-       LPCVOID lpRead, DWORD dwReadLen)
-{
-    DWORD comp_len;
-    DWORD read_len;
-    CHAR *CompBuffer = NULL;
-    CHAR *ReadBuffer = NULL;
-    BOOL rc;
-    InputContextData *data = get_imc_data(hIMC);
-
-    TRACE("(%p, %d, %p, %d, %p, %d):\n",
-            hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
-
-    if (!data)
-        return FALSE;
-
-    if (!(dwIndex == SCS_SETSTR ||
-          dwIndex == SCS_CHANGEATTR ||
-          dwIndex == SCS_CHANGECLAUSE ||
-          dwIndex == SCS_SETRECONVERTSTRING ||
-          dwIndex == SCS_QUERYRECONVERTSTRING))
-        return FALSE;
-
-    if (is_himc_ime_unicode(data))
-        return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
-                        dwCompLen, lpRead, dwReadLen);
-
-    comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
-                                   NULL);
-    if (comp_len)
-    {
-        CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
-        WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
-                            NULL, NULL);
-    }
-
-    read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
-                                   NULL);
-    if (read_len)
-    {
-        ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
-        WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
-                            NULL, NULL);
-    }
-
-    rc =  ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
-                                   ReadBuffer, read_len);
-
-    HeapFree(GetProcessHeap(), 0, CompBuffer);
-    HeapFree(GetProcessHeap(), 0, ReadBuffer);
-
-    return rc;
-}
-
-/***********************************************************************
- *             ImmSetCompositionWindow (IMM32.@)
- */
-BOOL WINAPI ImmSetCompositionWindow(
-  HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
-{
-    DWORD dwImeThreadId, dwThreadId;
-    LPINPUTCONTEXT pIC;
-    HWND hWnd;
-
-    dwImeThreadId = NtUserQueryInputContext(hIMC, 1);
-    dwThreadId = GetCurrentThreadId();
-    if (dwImeThreadId != dwThreadId)
-        return FALSE;
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return FALSE;
-
-    pIC->cfCompForm = *lpCompForm;
-    pIC->fdwInit |= INIT_COMPFORM;
-
-    hWnd = pIC->hWnd;
-
-    ImmUnlockIMC(hIMC);
-
-    Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
-                      IMC_SETCOMPOSITIONWINDOW, IMN_SETCOMPOSITIONWINDOW, 0);
-    return TRUE;
-}
-
-/***********************************************************************
- *             ImmSetConversionStatus (IMM32.@)
- */
-BOOL WINAPI ImmSetConversionStatus(
-  HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
-{
-    HKL hKL;
-    LPINPUTCONTEXT pIC;
-    DWORD dwImeThreadId, dwThreadId, dwOldConversion, dwOldSentence;
-    BOOL fConversionChange = FALSE, fSentenceChange = FALSE;
-    HWND hWnd;
-
-    TRACE("(%p, 0x%lX, 0x%lX)\n", hIMC, fdwConversion, fdwSentence);
-
-    hKL = GetKeyboardLayout(0);
-    if (!IS_IME_HKL(hKL))
-    {
-        if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
-        {
-            FIXME("Cicero\n");
-            return FALSE;
-        }
-    }
-
-    dwImeThreadId = Imm32QueryInputContext(hIMC, 1);
-    dwThreadId = GetCurrentThreadId();
-    if (dwImeThreadId != dwThreadId)
-        return FALSE;
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return FALSE;
-
-    if (pIC->fdwConversion != fdwConversion)
-    {
-        dwOldConversion = pIC->fdwConversion;
-        pIC->fdwConversion = fdwConversion;
-        fConversionChange = TRUE;
-    }
-
-    if (pIC->fdwSentence != fdwSentence)
-    {
-        dwOldSentence = pIC->fdwSentence;
-        pIC->fdwSentence = fdwSentence;
-        fSentenceChange = TRUE;
-    }
-
-    hWnd = pIC->hWnd;
-    ImmUnlockIMC(hIMC);
-
-    if (fConversionChange)
-    {
-        Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldConversion,
-                          IMC_SETCONVERSIONMODE, IMN_SETCONVERSIONMODE, 0);
-        Imm32NotifyIMEStatus(hWnd, hIMC, fdwConversion);
-    }
-
-    if (fSentenceChange)
-    {
-        Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldSentence,
-                          IMC_SETSENTENCEMODE, IMN_SETSENTENCEMODE, 0);
-    }
-
-    return TRUE;
-}
-
-/***********************************************************************
- *             ImmLockImeDpi (IMM32.@)
- */
-PIMEDPI WINAPI ImmLockImeDpi(HKL hKL)
-{
-    PIMEDPI pImeDpi = NULL;
-
-    TRACE("(%p)\n", hKL);
-
-    RtlEnterCriticalSection(&g_csImeDpi);
-
-    /* Find by hKL */
-    for (pImeDpi = g_pImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext)
-    {
-        if (pImeDpi->hKL == hKL) /* found */
-        {
-            /* lock if possible */
-            if (pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN)
-                pImeDpi = NULL;
-            else
-                ++(pImeDpi->cLockObj);
-            break;
-        }
-    }
-
-    RtlLeaveCriticalSection(&g_csImeDpi);
-    return pImeDpi;
-}
-
-/***********************************************************************
- *             ImmUnlockImeDpi (IMM32.@)
- */
-VOID WINAPI ImmUnlockImeDpi(PIMEDPI pImeDpi)
-{
-    PIMEDPI *ppEntry;
-
-    TRACE("(%p)\n", pImeDpi);
-
-    if (pImeDpi == NULL)
-        return;
-
-    RtlEnterCriticalSection(&g_csImeDpi);
-
-    /* unlock */
-    --(pImeDpi->cLockObj);
-    if (pImeDpi->cLockObj != 0)
-    {
-        RtlLeaveCriticalSection(&g_csImeDpi);
-        return;
-    }
-
-    if ((pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN) == 0)
-    {
-        if ((pImeDpi->dwFlags & IMEDPI_FLAG_LOCKED) == 0 ||
-            (pImeDpi->ImeInfo.fdwProperty & IME_PROP_END_UNLOAD) == 0)
-        {
-            RtlLeaveCriticalSection(&g_csImeDpi);
-            return;
-        }
-    }
-
-    /* Remove from list */
-    for (ppEntry = &g_pImeDpiList; *ppEntry; ppEntry = &((*ppEntry)->pNext))
-    {
-        if (*ppEntry == pImeDpi) /* found */
-        {
-            *ppEntry = pImeDpi->pNext;
-            break;
-        }
-    }
-
-    Imm32FreeImeDpi(pImeDpi, TRUE);
-    HeapFree(g_hImm32Heap, 0, pImeDpi);
-
-    RtlLeaveCriticalSection(&g_csImeDpi);
-}
-
-/***********************************************************************
- *             ImmSetOpenStatus (IMM32.@)
- */
-BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
-{
-    DWORD dwImeThreadId, dwThreadId, dwConversion;
-    LPINPUTCONTEXT pIC;
-    HWND hWnd;
-    BOOL bHasChange = FALSE;
-
-    TRACE("(%p, %d)\n", hIMC, fOpen);
-
-    dwImeThreadId = Imm32QueryInputContext(hIMC, 1);
-    dwThreadId = GetCurrentThreadId();
-    if (dwImeThreadId != dwThreadId)
-        return FALSE;
-
-    pIC = ImmLockIMC(hIMC);
-    if (pIC == NULL)
-        return FALSE;
-
-    if (pIC->fOpen != fOpen)
-    {
-        pIC->fOpen = fOpen;
-        hWnd = pIC->hWnd;
-        dwConversion = pIC->fdwConversion;
-        bHasChange = TRUE;
-    }
-
-    ImmUnlockIMC(hIMC);
-
-    if (bHasChange)
-    {
-        Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
-                          IMC_SETOPENSTATUS, IMN_SETOPENSTATUS, 0);
-        Imm32NotifyIMEStatus(hWnd, hIMC, dwConversion);
-    }
-
-    return TRUE;
-}
-
-/***********************************************************************
- *             ImmSetStatusWindowPos (IMM32.@)
- */
-BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
-{
-    LPINPUTCONTEXT pIC;
-    HWND hWnd;
-    DWORD dwImeThreadId, dwThreadId;
-
-    TRACE("(%p, {%ld, %ld})\n", hIMC, lpptPos->x, lpptPos->y);
-
-    dwImeThreadId = Imm32QueryInputContext(hIMC, 1);
-    dwThreadId = GetCurrentThreadId();
-    if (dwImeThreadId != dwThreadId)
-        return FALSE;
-
-    pIC = ImmLockIMC(hIMC);
-    if (!pIC)
-        return FALSE;
-
-    hWnd = pIC->hWnd;
-    pIC->ptStatusWndPos = *lpptPos;
-    pIC->fdwInit |= INIT_STATUSWNDPOS;
-
-    ImmUnlockIMC(hIMC);
-
-    Imm32NotifyAction(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
-                      IMC_SETSTATUSWINDOWPOS, IMN_SETSTATUSWINDOWPOS, 0);
-    return TRUE;
-}
-
-/***********************************************************************
- *              ImmCreateSoftKeyboard(IMM32.@)
- */
-HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
-{
-    FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return 0;
-}
-
-/***********************************************************************
- *              ImmDestroySoftKeyboard(IMM32.@)
- */
-BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
-{
-    TRACE("(%p)\n", hSoftWnd);
-    return DestroyWindow(hSoftWnd);
-}
-
-/***********************************************************************
- *              ImmShowSoftKeyboard(IMM32.@)
- */
-BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
-{
-    TRACE("(%p, %d)\n", hSoftWnd, nCmdShow);
-    if (hSoftWnd)
-        return ShowWindow(hSoftWnd, nCmdShow);
-    return FALSE;
-}
-
-/***********************************************************************
- *             ImmSimulateHotKey (IMM32.@)
- */
-BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
-{
-    HIMC hIMC;
-    DWORD dwThreadId;
-    HKL hKL;
-    BOOL ret;
-
-    TRACE("(%p, 0x%lX)\n", hWnd, dwHotKeyID);
-
-    hIMC = ImmGetContext(hWnd);
-    dwThreadId = GetWindowThreadProcessId(hWnd, NULL);
-    hKL = GetKeyboardLayout(dwThreadId);
-    ret = Imm32ProcessHotKey(hWnd, hIMC, hKL, dwHotKeyID);
-    ImmReleaseContext(hWnd, hIMC);
-    return ret;
-}
-
-/***********************************************************************
- *             ImmUnregisterWordA (IMM32.@)
- */
-BOOL WINAPI ImmUnregisterWordA(
-  HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
-{
-    BOOL ret = FALSE;
-    PIMEDPI pImeDpi;
-    LPWSTR pszReadingW = NULL, pszUnregisterW = NULL;
-    INT cch;
-
-    TRACE("(%p, %s, 0x%lX, %s)\n", hKL, debugstr_a(lpszReading), dwStyle,
-          debugstr_a(lpszUnregister));
-
-    pImeDpi = ImmLockOrLoadImeDpi(hKL);
-    if (pImeDpi == NULL)
-        return FALSE;
-
-    if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE))
-    {
-        ret = pImeDpi->ImeUnregisterWord(lpszReading, dwStyle, lpszUnregister);
-        ImmUnlockImeDpi(pImeDpi);
-        return ret;
-    }
-
-    if (lpszReading)
-    {
-        cch = lstrlenA(lpszReading);
-        pszReadingW = Imm32HeapAlloc(0, (cch + 1) * sizeof(WCHAR));
-        if (pszReadingW == NULL)
-            goto Quit;
-        cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpszReading, cch,
-                                  pszReadingW, cch + 1);
-        pszReadingW[cch] = 0;
-    }
-
-    if (lpszUnregister)
-    {
-        cch = lstrlenA(lpszUnregister);
-        pszUnregisterW = Imm32HeapAlloc(0, (cch + 1) * sizeof(WCHAR));
-        if (pszUnregisterW == NULL)
-            goto Quit;
-        cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpszUnregister, cch,
-                                  pszUnregisterW, cch + 1);
-        pszUnregisterW[cch] = 0;
-    }
-
-    ret = pImeDpi->ImeUnregisterWord(pszReadingW, dwStyle, pszUnregisterW);
-
-Quit:
-    if (pszReadingW)
-        HeapFree(g_hImm32Heap, 0, pszReadingW);
-    if (pszUnregisterW)
-        HeapFree(g_hImm32Heap, 0, pszUnregisterW);
-    ImmUnlockImeDpi(pImeDpi);
-    return ret;
-}
-
-/***********************************************************************
- *             ImmUnregisterWordW (IMM32.@)
- */
-BOOL WINAPI ImmUnregisterWordW(
-  HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
-{
-    ImmHkl *immHkl = IMM_GetImmHkl(hKL);
-    TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
-            debugstr_w(lpszUnregister));
-    if (immHkl->hIME && immHkl->pImeUnregisterWord)
-    {
-        if (is_kbd_ime_unicode(immHkl))
-            return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister);
-        else
-        {
-            LPSTR lpszaReading = strdupWtoA(lpszReading);
-            LPSTR lpszaUnregister = strdupWtoA(lpszUnregister);
-            BOOL rc;
-
-            rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle,
-                                            (LPCWSTR)lpszaUnregister);
-            HeapFree(GetProcessHeap(),0,lpszaReading);
-            HeapFree(GetProcessHeap(),0,lpszaUnregister);
-            return rc;
-        }
-    }
-    else
-        return FALSE;
-}
-
-/***********************************************************************
- *             ImmGetImeMenuItemsA (IMM32.@)
- */
-DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
-   LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
-    DWORD dwSize)
-{
-    InputContextData *data = get_imc_data(hIMC);
-    TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
-        lpImeParentMenu, lpImeMenu, dwSize);
-
-    if (!data)
-    {
-        SetLastError(ERROR_INVALID_HANDLE);
-        return 0;
-    }
-
-    if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
-    {
-        if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
-            return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
-                                (IMEMENUITEMINFOW*)lpImeParentMenu,
-                                (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
-        else
-        {
-            IMEMENUITEMINFOW lpImeParentMenuW;
-            IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
-            DWORD rc;
-
-            if (lpImeParentMenu)
-                parent = &lpImeParentMenuW;
-            if (lpImeMenu)
-            {
-                int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
-                dwSize = count * sizeof(IMEMENUITEMINFOW);
-                lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
-            }
-            else
-                lpImeMenuW = NULL;
-
-            rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
-                                parent, lpImeMenuW, dwSize);
-
-            if (lpImeParentMenu)
-            {
-                memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
-                lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
-                WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
-                    -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
-                    NULL, NULL);
-            }
-            if (lpImeMenu && rc)
-            {
-                unsigned int i;
-                for (i = 0; i < rc; i++)
-                {
-                    memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
-                    lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
-                    WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
-                        -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
-                        NULL, NULL);
-                }
-            }
-            HeapFree(GetProcessHeap(),0,lpImeMenuW);
-            return rc;
-        }
-    }
-    else
-        return 0;
-}
-
-/***********************************************************************
-*              ImmGetImeMenuItemsW (IMM32.@)
-*/
-DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
-   LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
-   DWORD dwSize)
-{
-    InputContextData *data = get_imc_data(hIMC);
-    TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
-        lpImeParentMenu, lpImeMenu, dwSize);
-
-    if (!data)
-    {
-        SetLastError(ERROR_INVALID_HANDLE);
-        return 0;
-    }
-
-    if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
-    {
-        if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
-            return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
-                                lpImeParentMenu, lpImeMenu, dwSize);
-        else
-        {
-            IMEMENUITEMINFOA lpImeParentMenuA;
-            IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
-            DWORD rc;
-
-            if (lpImeParentMenu)
-                parent = &lpImeParentMenuA;
-            if (lpImeMenu)
-            {
-                int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
-                dwSize = count * sizeof(IMEMENUITEMINFOA);
-                lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
-            }
-            else
-                lpImeMenuA = NULL;
-
-            rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
-                                (IMEMENUITEMINFOW*)parent,
-                                (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
-
-            if (lpImeParentMenu)
-            {
-                memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
-                lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
-                MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
-                    -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
-            }
-            if (lpImeMenu && rc)
-            {
-                unsigned int i;
-                for (i = 0; i < rc; i++)
-                {
-                    memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
-                    lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
-                    MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
-                        -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
-                }
-            }
-            HeapFree(GetProcessHeap(),0,lpImeMenuA);
-            return rc;
-        }
-    }
-    else
-        return 0;
-}
-
-/***********************************************************************
-*              ImmLockIMC(IMM32.@)
-*/
-LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
-{
-    InputContextData *data = get_imc_data(hIMC);
-
-    if (!data)
-        return NULL;
-    data->dwLock++;
-    return &data->IMC;
-}
-
-/***********************************************************************
-*              ImmUnlockIMC(IMM32.@)
-*/
-BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
-{
-    PCLIENTIMC pClientImc;
-    HIMC hClientImc;
-
-    pClientImc = ImmLockClientImc(hIMC);
-    if (pClientImc == NULL)
-        return FALSE;
+        CtfImmTIMCreateInputContext(hIMC);
+        goto Success;
+    }
 
-    hClientImc = pClientImc->hImc;
-    if (hClientImc)
-        LocalUnlock(hClientImc);
+    dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
+    if (dwThreadId == GetCurrentThreadId() && IS_CICERO_MODE() && !IS_16BIT_MODE())
+    {
+        hOldKL = GetKeyboardLayout(0);
+        LangID = LOWORD(hOldKL);
+        hNewKL = (HKL)(DWORD_PTR)MAKELONG(LangID, LangID);
 
-    InterlockedDecrement(&pClientImc->cLockObj);
-    ImmUnlockClientImc(pClientImc);
-    return TRUE;
-}
+        pImeDpi = Imm32FindOrLoadImeDpi(hNewKL);
+        if (pImeDpi)
+        {
+            CtfImmTIMActivate(hNewKL);
+        }
+    }
 
-/***********************************************************************
-*              ImmGetIMCLockCount(IMM32.@)
-*/
-DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
-{
-    DWORD ret;
-    HIMC hClientImc;
-    PCLIENTIMC pClientImc;
+    if (!NtUserQueryInputContext(hIMC, QIC_DEFAULTWINDOWIME))
+    {
+        ERR("No default IME window\n");
+        goto Failure;
+    }
 
-    pClientImc = ImmLockClientImc(hIMC);
-    if (pClientImc == NULL)
-        return 0;
+    hIC = LocalAlloc(LHND, sizeof(INPUTCONTEXTDX));
+    pIC = LocalLock(hIC);
+    if (IS_NULL_UNEXPECTEDLY(pIC))
+    {
+        LocalFree(hIC);
+        goto Failure;
+    }
+    pClientImc->hInputContext = hIC;
 
-    ret = 0;
-    hClientImc = pClientImc->hImc;
-    if (hClientImc)
-        ret = (LocalFlags(hClientImc) & LMEM_LOCKCOUNT);
+    hNewKL = GetKeyboardLayout(dwThreadId);
+    if (!Imm32CreateInputContext(hIMC, pIC, pClientImc, hNewKL, fSelect))
+    {
+        LocalUnlock(hIC);
+        pClientImc->hInputContext = LocalFree(hIC);
+        goto Failure;
+    }
 
+Success:
+    RtlLeaveCriticalSection(&pClientImc->cs);
+    InterlockedIncrement(&pClientImc->cLockObj);
     ImmUnlockClientImc(pClientImc);
-    return ret;
-}
-
-/***********************************************************************
-*              ImmCreateIMCC(IMM32.@)
-*/
-HIMCC  WINAPI ImmCreateIMCC(DWORD size)
-{
-    if (size < 4)
-        size = 4;
-    return LocalAlloc(LHND, size);
-}
+    return pIC;
 
-/***********************************************************************
-*       ImmDestroyIMCC(IMM32.@)
-*/
-HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
-{
-    if (block)
-        return LocalFree(block);
+Failure:
+    RtlLeaveCriticalSection(&pClientImc->cs);
+    ImmUnlockClientImc(pClientImc);
     return NULL;
 }
 
 /***********************************************************************
-*              ImmLockIMCC(IMM32.@)
-*/
-LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
+ *             ImmDestroyContext (IMM32.@)
+ */
+BOOL WINAPI ImmDestroyContext(HIMC hIMC)
 {
-    if (imcc)
-        return LocalLock(imcc);
-    return NULL;
-}
+    HKL hKL;
 
-/***********************************************************************
-*              ImmUnlockIMCC(IMM32.@)
-*/
-BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
-{
-    if (imcc)
-        return LocalUnlock(imcc);
-    return FALSE;
-}
+    TRACE("(%p)\n", hIMC);
 
-/***********************************************************************
-*              ImmGetIMCCLockCount(IMM32.@)
-*/
-DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
-{
-    return LocalFlags(imcc) & LMEM_LOCKCOUNT;
-}
+    if (!IS_IMM_MODE())
+    {
+        TRACE("\n");
+        return FALSE;
+    }
 
-/***********************************************************************
-*              ImmReSizeIMCC(IMM32.@)
-*/
-HIMCC  WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
-{
-    if (!imcc)
-        return NULL;
-    return LocalReAlloc(imcc, size, LHND);
-}
+    if (IS_CROSS_THREAD_HIMC(hIMC))
+        return FALSE;
 
-/***********************************************************************
-*              ImmGetIMCCSize(IMM32.@)
-*/
-DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
-{
-    if (imcc)
-        return LocalSize(imcc);
-    return 0;
+    hKL = GetKeyboardLayout(0);
+    return Imm32DestroyInputContext(hIMC, hKL, FALSE);
 }
 
 /***********************************************************************
-*              ImmGenerateMessage(IMM32.@)
-*/
-BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
+ *             ImmLockClientImc (IMM32.@)
+ */
+PCLIENTIMC WINAPI ImmLockClientImc(HIMC hImc)
 {
-    InputContextData *data = get_imc_data(hIMC);
+    PIMC pIMC;
+    PCLIENTIMC pClientImc;
 
-    if (!data)
-    {
-        SetLastError(ERROR_INVALID_HANDLE);
-        return FALSE;
-    }
+    TRACE("(%p)\n", hImc);
 
-    TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf);
-    if (data->IMC.dwNumMsgBuf > 0)
-    {
-        LPTRANSMSG lpTransMsg;
-        HIMCC hMsgBuf;
-        DWORD i, dwNumMsgBuf;
+    if (IS_NULL_UNEXPECTEDLY(hImc))
+        return NULL;
+
+    pIMC = ValidateHandle(hImc, TYPE_INPUTCONTEXT);
+    if (!pIMC || !Imm32CheckImcProcess(pIMC))
+        return NULL;
 
-        /* We are going to detach our hMsgBuff so that if processing messages
-           generates new messages they go into a new buffer */
-        hMsgBuf = data->IMC.hMsgBuf;
-        dwNumMsgBuf = data->IMC.dwNumMsgBuf;
+    pClientImc = (PCLIENTIMC)pIMC->dwClientImcData;
+    if (pClientImc)
+    {
+        if (pClientImc->dwFlags & CLIENTIMC_DESTROY)
+            return NULL;
+        goto Finish;
+    }
 
-        data->IMC.hMsgBuf = ImmCreateIMCC(0);
-        data->IMC.dwNumMsgBuf = 0;
+    pClientImc = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
+    if (IS_NULL_UNEXPECTEDLY(pClientImc))
+        return NULL;
 
-        lpTransMsg = ImmLockIMCC(hMsgBuf);
-        for (i = 0; i < dwNumMsgBuf; i++)
-            ImmInternalSendIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
+    RtlInitializeCriticalSection(&pClientImc->cs);
+    pClientImc->dwCompatFlags = (DWORD)NtUserGetThreadState(THREADSTATE_IMECOMPATFLAGS);
 
-        ImmUnlockIMCC(hMsgBuf);
-        ImmDestroyIMCC(hMsgBuf);
+    if (!NtUserUpdateInputContext(hImc, UIC_CLIENTIMCDATA, (DWORD_PTR)pClientImc))
+    {
+        ERR("\n");
+        ImmLocalFree(pClientImc);
+        return NULL;
     }
 
-    return TRUE;
+    pClientImc->dwFlags |= CLIENTIMC_UNKNOWN2;
+
+Finish:
+    InterlockedIncrement(&pClientImc->cLockObj);
+    return pClientImc;
 }
 
 /***********************************************************************
-*       ImmTranslateMessage(IMM32.@)
-*       ( Undocumented, call internally and from user32.dll )
-*/
-BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData)
+ *             ImmUnlockClientImc (IMM32.@)
+ */
+VOID WINAPI ImmUnlockClientImc(PCLIENTIMC pClientImc)
 {
-    InputContextData *data;
-    HIMC imc = ImmGetContext(hwnd);
-    BYTE state[256];
-    UINT scancode;
-    LPVOID list = 0;
-    UINT msg_count;
-    UINT uVirtKey;
-    static const DWORD list_count = 10;
-
-    TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData);
-
-    if (imc)
-        data = imc;
-    else
-        return FALSE;
+    LONG cLocks;
+    HANDLE hInputContext;
 
-    if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx)
-        return FALSE;
+    TRACE("(%p)\n", pClientImc);
+
+    cLocks = InterlockedDecrement(&pClientImc->cLockObj);
+    if (cLocks != 0 || !(pClientImc->dwFlags & CLIENTIMC_DESTROY))
+        return;
 
-    GetKeyboardState(state);
-    scancode = lKeyData >> 0x10 & 0xff;
+    hInputContext = pClientImc->hInputContext;
+    if (hInputContext)
+        LocalFree(hInputContext);
 
-    list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD));
-    ((DWORD*)list)[0] = list_count;
+    RtlDeleteCriticalSection(&pClientImc->cs);
+    ImmLocalFree(pClientImc);
+}
 
-    if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
-    {
-        WCHAR chr;
+// Win: ImmGetSaveContext
+static HIMC APIENTRY ImmGetSaveContext(HWND hWnd, DWORD dwContextFlags)
+{
+    HIMC hIMC;
+    PCLIENTIMC pClientImc;
+    PWND pWnd;
 
-        if (!is_himc_ime_unicode(data))
-            ToAscii(data->lastVK, scancode, state, &chr, 0);
-        else
-            ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0));
-        uVirtKey = MAKELONG(data->lastVK,chr);
+    if (!IS_IMM_MODE())
+    {
+        TRACE("Not IMM mode.\n");
+        return NULL;
     }
-    else
-        uVirtKey = data->lastVK;
 
-    msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc);
-    TRACE("%i messages generated\n",msg_count);
-    if (msg_count && msg_count <= list_count)
+    if (!hWnd)
     {
-        UINT i;
-        LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD));
-
-        for (i = 0; i < msg_count; i++)
-            ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam);
+        hIMC = (HIMC)NtUserGetThreadState(THREADSTATE_DEFAULTINPUTCONTEXT);
+        goto Quit;
     }
-    else if (msg_count > list_count)
-        ImmGenerateMessage(imc);
 
-    HeapFree(GetProcessHeap(),0,list);
+    pWnd = ValidateHwnd(hWnd);
+    if (IS_NULL_UNEXPECTEDLY(pWnd) || IS_CROSS_PROCESS_HWND(hWnd))
+        return NULL;
+
+    hIMC = pWnd->hImc;
+    if (!hIMC && (dwContextFlags & 1))
+        hIMC = (HIMC)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_ICONTEXT);
 
-    data->lastVK = VK_PROCESSKEY;
+Quit:
+    pClientImc = ImmLockClientImc(hIMC);
+    if (IS_NULL_UNEXPECTEDLY(pClientImc))
+        return NULL;
+
+    if ((dwContextFlags & 2) && (pClientImc->dwFlags & CLIENTIMC_DISABLEIME))
+        hIMC = NULL;
 
-    return (msg_count > 0);
+    ImmUnlockClientImc(pClientImc);
+    return hIMC;
 }
 
 /***********************************************************************
-*              ImmProcessKey(IMM32.@)
-*       ( Undocumented, called from user32.dll )
-*/
-BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown)
+ *             ImmGetContext (IMM32.@)
+ */
+HIMC WINAPI ImmGetContext(HWND hWnd)
 {
-    InputContextData *data;
-    HIMC imc = ImmGetContext(hwnd);
-    BYTE state[256];
-
-    TRACE("%p %p %x %x %x\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown);
+    TRACE("(%p)\n", hWnd);
+    if (IS_NULL_UNEXPECTEDLY(hWnd))
+        return NULL;
+    return ImmGetSaveContext(hWnd, 2);
+}
 
-    if (imc)
-        data = imc;
-    else
-        return FALSE;
+/***********************************************************************
+ *             ImmLockIMC(IMM32.@)
+ *
+ * NOTE: This is not ImmLockIMCC. Don't confuse.
+ */
+LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
+{
+    TRACE("(%p)\n", hIMC);
+    return Imm32InternalLockIMC(hIMC, TRUE);
+}
 
-    /* Make sure we are inputting to the correct keyboard */
-    if (data->immKbd->hkl != hKL)
-    {
-        ImmHkl *new_hkl = IMM_GetImmHkl(hKL);
-        if (new_hkl)
-        {
-            data->immKbd->pImeSelect(imc, FALSE);
-            data->immKbd->uSelected--;
-            data->immKbd = new_hkl;
-            data->immKbd->pImeSelect(imc, TRUE);
-            data->immKbd->uSelected++;
-        }
-        else
-            return FALSE;
-    }
+/***********************************************************************
+*              ImmUnlockIMC(IMM32.@)
+*/
+BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
+{
+    PCLIENTIMC pClientImc;
 
-    if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey)
+    pClientImc = ImmLockClientImc(hIMC);
+    if (IS_NULL_UNEXPECTEDLY(pClientImc))
         return FALSE;
 
-    GetKeyboardState(state);
-    if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state))
-    {
-        data->lastVK = vKey;
-        return TRUE;
-    }
+    if (pClientImc->hInputContext)
+        LocalUnlock(pClientImc->hInputContext);
 
-    data->lastVK = VK_PROCESSKEY;
-    return FALSE;
+    InterlockedDecrement(&pClientImc->cLockObj);
+    ImmUnlockClientImc(pClientImc);
+    return TRUE;
 }
 
 /***********************************************************************
-*              ImmDisableTextFrameService(IMM32.@)
-*/
-BOOL WINAPI ImmDisableTextFrameService(DWORD dwThreadId)
+ *             ImmReleaseContext (IMM32.@)
+ */
+BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
 {
-    FIXME("Stub\n");
-    return FALSE;
+    TRACE("(%p, %p)\n", hWnd, hIMC);
+    UNREFERENCED_PARAMETER(hWnd);
+    UNREFERENCED_PARAMETER(hIMC);
+    return TRUE; // Do nothing. This is correct.
 }
 
 /***********************************************************************
@@ -4622,8 +1102,8 @@ BOOL WINAPI ImmEnumInputContext(DWORD dwThreadId, IMCENUMPROC lpfn, LPARAM lPara
 
     TRACE("(%lu, %p, %p)\n", dwThreadId, lpfn, lParam);
 
-    dwCount = Imm32AllocAndBuildHimcList(dwThreadId, &phList);
-    if (!dwCount)
+    dwCount = Imm32BuildHimcList(dwThreadId, &phList);
+    if (IS_ZERO_UNEXPECTEDLY(dwCount))
         return FALSE;
 
     for (dwIndex = 0; dwIndex < dwCount; ++dwIndex)
@@ -4634,42 +1114,120 @@ BOOL WINAPI ImmEnumInputContext(DWORD dwThreadId, IMCENUMPROC lpfn, LPARAM lPara
             break;
     }
 
-    HeapFree(g_hImm32Heap, 0, phList);
+    ImmLocalFree(phList);
     return ret;
 }
 
 /***********************************************************************
- *              ImmGetHotKey(IMM32.@)
+ *              ImmSetActiveContext(IMM32.@)
  */
-
-BOOL WINAPI
-ImmGetHotKey(IN DWORD dwHotKey,
-             OUT LPUINT lpuModifiers,
-             OUT LPUINT lpuVKey,
-             OUT LPHKL lphKL)
+BOOL WINAPI ImmSetActiveContext(HWND hWnd, HIMC hIMC, BOOL fActive)
 {
-    TRACE("%lx, %p, %p, %p\n", dwHotKey, lpuModifiers, lpuVKey, lphKL);
-    if (lpuModifiers && lpuVKey)
-        return NtUserGetImeHotKey(dwHotKey, lpuModifiers, lpuVKey, lphKL);
-    return FALSE;
-}
+    PCLIENTIMC pClientImc;
+    LPINPUTCONTEXTDX pIC;
+    PIMEDPI pImeDpi;
+    HIMC hOldIMC;
+    HKL hKL;
+    BOOL fOpen = FALSE;
+    DWORD dwConversion = 0, dwShowFlags = ISC_SHOWUIALL;
+    HWND hwndDefIME;
+
+    TRACE("(%p, %p, %d)\n", hWnd, hIMC, fActive);
+
+    if (!IS_IMM_MODE())
+    {
+        TRACE("\n");
+        return FALSE;
+    }
+
+    pClientImc = ImmLockClientImc(hIMC);
+
+    if (!fActive)
+    {
+        if (pClientImc)
+            pClientImc->dwFlags &= ~CLIENTIMC_ACTIVE;
+    }
+    else if (hIMC)
+    {
+        if (IS_NULL_UNEXPECTEDLY(pClientImc))
+            return FALSE;
+
+        pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
+        if (IS_NULL_UNEXPECTEDLY(pIC))
+        {
+            ImmUnlockClientImc(pClientImc);
+            return FALSE;
+        }
+
+        pIC->hWnd = hWnd;
+        pClientImc->dwFlags |= CLIENTIMC_ACTIVE;
+
+        if (pIC->dwUIFlags & 2)
+            dwShowFlags = (ISC_SHOWUIGUIDELINE | ISC_SHOWUIALLCANDIDATEWINDOW);
+
+        fOpen = pIC->fOpen;
+        dwConversion = pIC->fdwConversion;
+
+        ImmUnlockIMC(hIMC);
+    }
+    else
+    {
+        hOldIMC = ImmGetSaveContext(hWnd, 1);
+        pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hOldIMC);
+        if (pIC)
+        {
+            pIC->hWnd = hWnd;
+            ImmUnlockIMC(hOldIMC);
+        }
+    }
+
+    hKL = GetKeyboardLayout(0);
+    if (IS_CICERO_MODE() && !IS_16BIT_MODE())
+    {
+        CtfImeSetActiveContextAlways(hIMC, fActive, hWnd, hKL);
+        hKL = GetKeyboardLayout(0);
+    }
+
+    pImeDpi = ImmLockImeDpi(hKL);
+    if (pImeDpi)
+    {
+        if (IS_IME_HKL(hKL))
+            pImeDpi->ImeSetActiveContext(hIMC, fActive);
+        ImmUnlockImeDpi(pImeDpi);
+    }
+
+    if (IsWindow(hWnd))
+    {
+        SendMessageW(hWnd, WM_IME_SETCONTEXT, fActive, dwShowFlags);
+        if (fActive)
+            NtUserNotifyIMEStatus(hWnd, fOpen, dwConversion);
+    }
+    else if (!fActive)
+    {
+        hwndDefIME = ImmGetDefaultIMEWnd(NULL);
+        if (hwndDefIME)
+            SendMessageW(hwndDefIME, WM_IME_SETCONTEXT, 0, dwShowFlags);
+    }
+
+    if (pClientImc)
+        ImmUnlockClientImc(pClientImc);
 
-/***********************************************************************
- *              ImmDisableLegacyIME(IMM32.@)
- */
-BOOL WINAPI ImmDisableLegacyIME(void)
-{
-    FIXME("stub\n");
     return TRUE;
 }
 
 /***********************************************************************
- *              ImmSetActiveContext(IMM32.@)
+ *              ImmWINNLSGetEnableStatus (IMM32.@)
  */
-BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC hIMC, BOOL fFlag)
+
+BOOL WINAPI ImmWINNLSGetEnableStatus(HWND hWnd)
 {
-    FIXME("(%p, %p, %d): stub\n", hwnd, hIMC, fFlag);
-    return FALSE;
+    if (!Imm32IsSystemJapaneseOrKorean())
+    {
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+        return FALSE;
+    }
+
+    return !!ImmGetSaveContext(hWnd, 2);
 }
 
 /***********************************************************************
@@ -4681,104 +1239,75 @@ BOOL WINAPI ImmSetActiveContextConsoleIME(HWND hwnd, BOOL fFlag)
     TRACE("(%p, %d)\n", hwnd, fFlag);
 
     hIMC = ImmGetContext(hwnd);
-    if (hIMC)
-        return ImmSetActiveContext(hwnd, hIMC, fFlag);
-    return FALSE;
-}
-
-/***********************************************************************
-*              ImmRegisterClient(IMM32.@)
-*       ( Undocumented, called from user32.dll )
-*/
-BOOL WINAPI ImmRegisterClient(PSHAREDINFO ptr, HINSTANCE hMod)
-{
-    g_SharedInfo = *ptr;
-    g_psi = g_SharedInfo.psi;
-    return Imm32InitInstance(hMod);
+    if (IS_NULL_UNEXPECTEDLY(hIMC))
+        return FALSE;
+    return ImmSetActiveContext(hwnd, hIMC, fFlag);
 }
 
 /***********************************************************************
- *             CtfImmIsTextFrameServiceDisabled(IMM32.@)
+ *              GetKeyboardLayoutCP (IMM32.@)
  */
-BOOL WINAPI CtfImmIsTextFrameServiceDisabled(VOID)
+UINT WINAPI GetKeyboardLayoutCP(_In_ LANGID wLangId)
 {
-    PTEB pTeb = NtCurrentTeb();
-    if (((PW32CLIENTINFO)pTeb->Win32ClientInfo)->CI_flags & CI_TFSDISABLED)
-        return TRUE;
-    return FALSE;
-}
+    WCHAR szText[8];
+    static LANGID s_wKeyboardLangIdCache = 0;
+    static UINT s_uKeyboardLayoutCPCache = 0;
 
-/***********************************************************************
- *              ImmGetImeInfoEx (IMM32.@)
- */
+    TRACE("(%u)\n", wLangId);
 
-static BOOL APIENTRY Imm32GetImeInfoEx(PIMEINFOEX pImeInfoEx, IMEINFOEXCLASS SearchType)
-{
-    return NtUserGetImeInfoEx(pImeInfoEx, SearchType);
+    if (wLangId == s_wKeyboardLangIdCache)
+        return s_uKeyboardLayoutCPCache;
+
+    if (!GetLocaleInfoW(wLangId, LOCALE_IDEFAULTANSICODEPAGE, szText, _countof(szText)))
+        return 0;
+
+    s_wKeyboardLangIdCache = wLangId;
+    szText[_countof(szText) - 1] = UNICODE_NULL; /* Avoid buffer overrun */
+    s_uKeyboardLayoutCPCache = wcstol(szText, NULL, 10);
+    return s_uKeyboardLayoutCPCache;
 }
 
-BOOL WINAPI
-ImmGetImeInfoEx(PIMEINFOEX pImeInfoEx,
-                IMEINFOEXCLASS SearchType,
-                PVOID pvSearchKey)
+#ifndef NDEBUG
+VOID APIENTRY Imm32UnitTest(VOID)
 {
-    BOOL bDisabled = FALSE;
-    HKL hKL;
-    PTEB pTeb;
-
-    switch (SearchType)
+    if (0)
     {
-        case ImeInfoExKeyboardLayout:
-            break;
-
-        case ImeInfoExImeWindow:
-            bDisabled = CtfImmIsTextFrameServiceDisabled();
-            SearchType = ImeInfoExKeyboardLayout;
-            break;
-
-        case ImeInfoExImeFileName:
-            StringCchCopyW(pImeInfoEx->wszImeFile, _countof(pImeInfoEx->wszImeFile),
-                           pvSearchKey);
-            goto Quit;
-    }
+        DWORD dwValue;
+        WCHAR szText[64];
 
-    hKL = *(HKL*)pvSearchKey;
-    pImeInfoEx->hkl = hKL;
+        Imm32StrToUInt(L"123", &dwValue, 10);
+        ASSERT(dwValue == 123);
+        Imm32StrToUInt(L"100", &dwValue, 16);
+        ASSERT(dwValue == 0x100);
 
-    if (!IS_IME_HKL(hKL))
-    {
-        if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
-        {
-            pTeb = NtCurrentTeb();
-            if (((PW32CLIENTINFO)pTeb->Win32ClientInfo)->W32ClientInfo[0] & 2)
-                return FALSE;
-            if (!bDisabled)
-                goto Quit;
-        }
-        return FALSE;
+        Imm32UIntToStr(123, 10, szText, _countof(szText));
+        ASSERT(lstrcmpW(szText, L"123") == 0);
+        Imm32UIntToStr(0x100, 16, szText, _countof(szText));
+        ASSERT(lstrcmpW(szText, L"100") == 0);
     }
-
-Quit:
-    return Imm32GetImeInfoEx(pImeInfoEx, SearchType);
 }
+#endif
 
 BOOL WINAPI User32InitializeImmEntryTable(DWORD);
 
-BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
+BOOL
+WINAPI
+ImmDllInitialize(
+    _In_ HINSTANCE hDll,
+    _In_ ULONG dwReason,
+    _In_opt_ PVOID pReserved)
 {
     HKL hKL;
-    HWND hWnd;
-    PTEB pTeb;
+    HIMC hIMC;
 
-    TRACE("(%p, 0x%X, %p)\n", hinstDLL, fdwReason, lpReserved);
+    TRACE("(%p, 0x%X, %p)\n", hDll, dwReason, pReserved);
 
-    switch (fdwReason)
+    switch (dwReason)
     {
         case DLL_PROCESS_ATTACH:
-            //Imm32GenerateRandomSeed(hinstDLL, 1, lpReserved); // Non-sense
-            if (!Imm32InitInstance(hinstDLL))
+            if (!ImmInitializeGlobals(hDll))
             {
-                ERR("Imm32InitInstance failed\n");
+                ERR("ImmInitializeGlobals failed\n");
                 return FALSE;
             }
             if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
@@ -4786,26 +1315,26 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
                 ERR("User32InitializeImmEntryTable failed\n");
                 return FALSE;
             }
+#ifndef NDEBUG
+            Imm32UnitTest();
+#endif
             break;
 
         case DLL_THREAD_ATTACH:
             break;
 
         case DLL_THREAD_DETACH:
-            if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
-                return TRUE;
-
-            pTeb = NtCurrentTeb();
-            if (pTeb->Win32ThreadInfo == NULL)
+            if (!IS_IMM_MODE() || NtCurrentTeb()->Win32ThreadInfo == NULL)
                 return TRUE;
 
             hKL = GetKeyboardLayout(0);
-            hWnd = (HWND)Imm32GetThreadState(THREADSTATE_CAPTUREWINDOW);
-            Imm32CleanupContext(hWnd, hKL, TRUE);
+            hIMC = (HIMC)NtUserGetThreadState(THREADSTATE_DEFAULTINPUTCONTEXT);
+            Imm32DestroyInputContext(hIMC, hKL, TRUE);
             break;
 
         case DLL_PROCESS_DETACH:
-            RtlDeleteCriticalSection(&g_csImeDpi);
+            RtlDeleteCriticalSection(&gcsImeDpi);
+            TRACE("imm32.dll is unloaded\n");
             break;
     }