diff --git a/dll/win32/imm32/imm.c b/dll/win32/imm32/imm.c
index f3c76d2..12d2045 100644
--- a/dll/win32/imm32/imm.c
+++ b/dll/win32/imm32/imm.c
@@ -39,6 +39,9 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(imm);
 
+#define IMM_INIT_MAGIC 0x19650412
+BOOL WINAPI User32InitializeImmEntryTable(DWORD);
+
 #define MAKE_FUNCPTR(f) typeof(f) * p##f
 typedef struct _tagImmHkl{
     struct list entry;
@@ -73,9 +76,11 @@ typedef struct tagInputContextData
 {
         DWORD           dwLock;
         INPUTCONTEXT    IMC;
+        DWORD           threadID;
 
         ImmHkl          *immKbd;
         UINT            lastVK;
+        BOOL            threadDefault;
         DWORD           magic;
 } InputContextData;
 
@@ -88,21 +93,16 @@ typedef struct _tagTRANSMSG {
 } TRANSMSG, *LPTRANSMSG;
 
 typedef struct _tagIMMThreadData {
+    struct list entry;
+    DWORD threadID;
     HIMC defaultContext;
     HWND hwndDefault;
+    BOOL disableIME;
+    DWORD windowRefs;
 } IMMThreadData;
 
-static DWORD tlsIndex = 0;
 static struct list ImmHklList = LIST_INIT(ImmHklList);
-
-/* MSIME messages */
-static UINT WM_MSIME_SERVICE;
-static UINT WM_MSIME_RECONVERTOPTIONS;
-static UINT WM_MSIME_MOUSE;
-static UINT WM_MSIME_RECONVERTREQUEST;
-static UINT WM_MSIME_RECONVERT;
-static UINT WM_MSIME_QUERYPOSITION;
-static UINT WM_MSIME_DOCUMENTFEED;
+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};
 
@@ -111,14 +111,23 @@ static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t
 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 LRESULT WINAPI DefIME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
-                                        LPARAM lParam);
+static CRITICAL_SECTION threaddata_cs;
+static CRITICAL_SECTION_DEBUG critsect_debug =
+{
+    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;
 
 #define is_himc_ime_unicode(p)  (p->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE)
 #define is_kbd_ime_unicode(p)  (p->imeInfo.fdwProperty & IME_PROP_UNICODE)
 
 static BOOL IMM_DestroyContext(HIMC hIMC);
+static InputContextData* get_imc_data(HIMC hIMC);
 
 static inline WCHAR *strdupAtoW( const char *str )
 {
@@ -222,29 +231,66 @@ static DWORD convert_candidatelist_AtoW(
     return ret;
 }
 
-static IMMThreadData* IMM_GetThreadData(void)
+static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread)
 {
-    IMMThreadData* data = TlsGetValue(tlsIndex);
-    if (!data)
+    IMMThreadData *data;
+    DWORD process;
+
+    if (hwnd)
     {
-        data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
-                         sizeof(IMMThreadData));
-        TlsSetValue(tlsIndex,data);
-        TRACE("Thread Data Created\n");
+        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();
+
+    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;
 }
 
+static BOOL IMM_IsDefaultContext(HIMC imc)
+{
+    InputContextData *data = get_imc_data(imc);
+
+    if (!data)
+        return FALSE;
+
+    return data->threadDefault;
+}
+
 static void IMM_FreeThreadData(void)
 {
-    IMMThreadData* data = TlsGetValue(tlsIndex);
-    if (data)
+    IMMThreadData *data;
+
+    EnterCriticalSection(&threaddata_cs);
+    LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
     {
-        IMM_DestroyContext(data->defaultContext);
-        DestroyWindow(data->hwndDefault);
-        HeapFree(GetProcessHeap(),0,data);
-        TRACE("Thread Data Destroyed\n");
+        if (data->threadID == GetCurrentThreadId())
+        {
+            list_remove(&data->entry);
+            LeaveCriticalSection(&threaddata_cs);
+            IMM_DestroyContext(data->defaultContext);
+            HeapFree(GetProcessHeap(),0,data);
+            TRACE("Thread Data Destroyed\n");
+            return;
+        }
     }
+    LeaveCriticalSection(&threaddata_cs);
 }
 
 static HMODULE load_graphics_driver(void)
@@ -349,6 +395,12 @@ static ImmHkl *IMM_GetImmHkl(HKL hkl)
 }
 #undef LOAD_FUNCPTR
 
+HWND WINAPI __wine_get_ui_window(HKL hkl)
+{
+    ImmHkl *immHkl = IMM_GetImmHkl(hkl);
+    return immHkl->UIWnd;
+}
+
 static void IMM_FreeAllImmHkl(void)
 {
     ImmHkl *ptr,*cursor2;
@@ -367,43 +419,17 @@ static void IMM_FreeAllImmHkl(void)
     }
 }
 
-static void IMM_RegisterMessages(void)
-{
-    WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
-    WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
-    WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
-    WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
-    WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
-    WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
-    WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
-}
-
-static void IMM_RegisterIMEClass(void)
-{
-    WNDCLASSW wndClass;
-
-    ZeroMemory(&wndClass, sizeof(WNDCLASSW));
-
-    wndClass.style = CS_GLOBALCLASS;
-    wndClass.lpfnWndProc = (WNDPROC) DefIME_WindowProc;
-    wndClass.cbWndExtra = 2 * sizeof(LONG_PTR);
-    wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
-    wndClass.lpszClassName = szwIME;
-
-    RegisterClassW(&wndClass);
-}
-
 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
 {
-    TRACE("%p, %x, %p\n",hInstDLL,fdwReason,lpReserved);
+    ERR("Imm32 %p, %x, %p\n",hInstDLL,fdwReason,lpReserved);
     switch (fdwReason)
     {
         case DLL_PROCESS_ATTACH:
-            IMM_RegisterMessages();
-            tlsIndex = TlsAlloc();
-            if (tlsIndex == TLS_OUT_OF_INDEXES)
+            if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
+            {
+                ERR("Imm32 did not init User32\n");
                 return FALSE;
-            IMM_RegisterIMEClass();
+            }
             break;
         case DLL_THREAD_ATTACH:
             break;
@@ -414,8 +440,6 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
             if (lpReserved) break;
             IMM_FreeThreadData();
             IMM_FreeAllImmHkl();
-            TlsFree(tlsIndex);
-            UnregisterClassW(szwIME, NULL);
             break;
     }
     return TRUE;
@@ -431,6 +455,16 @@ static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM w
        PostMessageW(target, msg, wParam, lParam);
 }
 
+/* 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);
+}
+
 static LRESULT ImmInternalSendIMENotify(InputContextData *data, WPARAM notify, LPARAM lParam)
 {
     HWND target;
@@ -471,6 +505,63 @@ static InputContextData* get_imc_data(HIMC hIMC)
     return data;
 }
 
+static HIMC get_default_context( HWND hwnd )
+{
+    HIMC ret;
+    IMMThreadData* thread_data = IMM_GetThreadData( hwnd, 0 );
+
+    if (!thread_data) return 0;
+
+    if (thread_data->defaultContext)
+    {
+        ret = thread_data->defaultContext;
+        LeaveCriticalSection(&threaddata_cs);
+        return ret;
+    }
+
+    /* can't create a default context in another thread */
+    if (thread_data->threadID != GetCurrentThreadId())
+    {
+        LeaveCriticalSection(&threaddata_cs);
+        return 0;
+    }
+
+    LeaveCriticalSection(&threaddata_cs);
+
+    ret = ImmCreateContext();
+    if (!ret) return 0;
+    ((InputContextData*)ret)->threadDefault = TRUE;
+
+    /* thread_data is in the current thread so we can assume it's still valid */
+    EnterCriticalSection(&threaddata_cs);
+
+    if (thread_data->defaultContext) /* someone beat us */
+    {
+        IMM_DestroyContext( ret );
+        ret = thread_data->defaultContext;
+    }
+    else thread_data->defaultContext = ret;
+
+    LeaveCriticalSection(&threaddata_cs);
+    return ret;
+}
+
+static BOOL IMM_IsCrossThreadAccess(HWND hWnd,  HIMC hIMC)
+{
+    InputContextData *data;
+
+    if (hWnd)
+    {
+        DWORD thread = GetWindowThreadProcessId(hWnd, NULL);
+        if (thread != GetCurrentThreadId()) return TRUE;
+    }
+    data = get_imc_data(hIMC);
+    if (data && data->threadID != GetCurrentThreadId())
+        return TRUE;
+
+    return FALSE;
+}
+
 /***********************************************************************
  *		ImmAssociateContext (IMM32.@)
  */
@@ -484,25 +575,26 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
     if(hIMC && !data)
         return NULL;
 
-    if (!IMM_GetThreadData()->defaultContext)
-        IMM_GetThreadData()->defaultContext = ImmCreateContext();
-
     /*
      * If already associated just return
      */
     if (hIMC && data->IMC.hWnd == hWnd)
         return hIMC;
 
+    if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC))
+        return NULL;
+
     if (hWnd)
     {
+        HIMC defaultContext = get_default_context( hWnd );
         old = RemovePropW(hWnd,szwWineIMCProperty);
 
         if (old == NULL)
-            old = IMM_GetThreadData()->defaultContext;
+            old = defaultContext;
         else if (old == (HIMC)-1)
             old = NULL;
 
-        if (hIMC != IMM_GetThreadData()->defaultContext)
+        if (hIMC != defaultContext)
         {
             if (hIMC == NULL) /* Meaning disable imm for that window*/
                 SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1);
@@ -521,23 +613,9 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
     if (!hIMC)
         return old;
 
-    if (IsWindow(data->IMC.hWnd))
-    {
-        /*
-         * Post a message that your context is switching
-         */
-        SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL);
-    }
-
+    SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL);
     data->IMC.hWnd = hWnd;
-
-    if (IsWindow(data->IMC.hWnd))
-    {
-        /*
-         * Post a message that your context is switching
-         */
-        SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL);
-    }
+    SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL);
 
     return old;
 }
@@ -560,10 +638,8 @@ BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
 {
     TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags);
 
-    if (!IMM_GetThreadData()->defaultContext)
-        IMM_GetThreadData()->defaultContext = ImmCreateContext();
-
-    if (!hWnd) return FALSE;
+    if (!hWnd)
+        return FALSE;
 
     switch (dwFlags)
     {
@@ -571,8 +647,12 @@ BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
         ImmAssociateContext(hWnd,hIMC);
         return TRUE;
     case IACE_DEFAULT:
-        ImmAssociateContext(hWnd,IMM_GetThreadData()->defaultContext);
+    {
+        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);
@@ -707,7 +787,8 @@ HIMC WINAPI ImmCreateContext(void)
         IMM_DestroyContext(new_context);
         return 0;
     }
-    SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)GetKeyboardLayout(0));
+    new_context->threadID = GetCurrentThreadId();
+    SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->immKbd);
 
     new_context->immKbd->uSelected++;
     TRACE("Created context %p\n",new_context);
@@ -727,7 +808,7 @@ static BOOL IMM_DestroyContext(HIMC hIMC)
 
     data->immKbd->uSelected --;
     data->immKbd->pImeSelect(hIMC, FALSE);
-    SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)GetKeyboardLayout(0));
+    SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd);
 
     ImmDestroyIMCC(data->IMC.hCompStr);
     ImmDestroyIMCC(data->IMC.hCandInfo);
@@ -746,7 +827,7 @@ static BOOL IMM_DestroyContext(HIMC hIMC)
  */
 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
 {
-    if (hIMC != IMM_GetThreadData()->defaultContext)
+    if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC))
         return IMM_DestroyContext(hIMC);
     else
         return FALSE;
@@ -757,7 +838,14 @@ BOOL WINAPI ImmDestroyContext(HIMC hIMC)
  */
 BOOL WINAPI ImmDisableIME(DWORD idThread)
 {
-    FIXME("(%d): stub\n", idThread);
+    if (idThread == (DWORD)-1)
+        disable_ime = TRUE;
+    else {
+        IMMThreadData *thread_data = IMM_GetThreadData(NULL, idThread);
+        if (!thread_data) return FALSE;
+        thread_data->disableIME = TRUE;
+        LeaveCriticalSection(&threaddata_cs);
+    }
     return TRUE;
 }
 
@@ -1420,20 +1508,19 @@ HIMC WINAPI ImmGetContext(HWND hWnd)
         SetLastError(ERROR_INVALID_WINDOW_HANDLE);
         return NULL;
     }
-    if (!IMM_GetThreadData()->defaultContext)
-        IMM_GetThreadData()->defaultContext = ImmCreateContext();
 
     rc = GetPropW(hWnd,szwWineIMCProperty);
     if (rc == (HIMC)-1)
         rc = NULL;
     else if (rc == NULL)
-        rc = IMM_GetThreadData()->defaultContext;
+        rc = get_default_context( hWnd );
 
     if (rc)
     {
         InputContextData *data = rc;
         data->IMC.hWnd = hWnd;
     }
+
     TRACE("returning %p\n", rc);
 
     return rc;
@@ -1536,16 +1623,111 @@ BOOL WINAPI ImmGetConversionStatus(
     return TRUE;
 }
 
+static BOOL needs_ime_window(HWND hwnd)
+{
+    WCHAR classW[8];
+
+    if (GetClassNameW(hwnd, classW, sizeof(classW)/sizeof(classW[0])) &&
+        !strcmpW(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 (IMM_GetThreadData()->hwndDefault == NULL)
-        IMM_GetThreadData()->hwndDefault = CreateWindowExW( WS_EX_TOOLWINDOW,
-                    szwIME, NULL, WS_POPUP, 0, 0, 1, 1, 0, 0, 0, 0);
-    TRACE("Default is %p\n",IMM_GetThreadData()->hwndDefault);
-    return IMM_GetThreadData()->hwndDefault;
+    HWND ret;
+    IMMThreadData* thread_data = IMM_GetThreadData(hWnd, 0);
+    if (!thread_data)
+        return NULL;
+    ret = thread_data->hwndDefault;
+    LeaveCriticalSection(&threaddata_cs);
+    TRACE("Default is %p\n",ret);
+    return ret;
 }
 
 /***********************************************************************
@@ -1947,28 +2129,20 @@ BOOL WINAPI ImmIsIME(HKL hKL)
 BOOL WINAPI ImmIsUIMessageA(
   HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
 {
-    BOOL rc = FALSE;
-
     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 */) ||
-            (msg == WM_MSIME_RECONVERTOPTIONS) ||
-            (msg == WM_MSIME_MOUSE) ||
-            (msg == WM_MSIME_RECONVERTREQUEST) ||
-            (msg == WM_MSIME_RECONVERT) ||
-            (msg == WM_MSIME_QUERYPOSITION) ||
-            (msg == WM_MSIME_DOCUMENTFEED))
+            (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
     {
         if (hWndIME)
             SendMessageA(hWndIME, msg, wParam, lParam);
 
-        rc = TRUE;
+        return TRUE;
     }
-    return rc;
+    return FALSE;
 }
 
 /***********************************************************************
@@ -1977,28 +2151,20 @@ BOOL WINAPI ImmIsUIMessageA(
 BOOL WINAPI ImmIsUIMessageW(
   HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
 {
-    BOOL rc = FALSE;
-
     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 */) ||
-            (msg == WM_MSIME_RECONVERTOPTIONS) ||
-            (msg == WM_MSIME_MOUSE) ||
-            (msg == WM_MSIME_RECONVERTREQUEST) ||
-            (msg == WM_MSIME_RECONVERT) ||
-            (msg == WM_MSIME_QUERYPOSITION) ||
-            (msg == WM_MSIME_DOCUMENTFEED))
+            (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
     {
         if (hWndIME)
             SendMessageW(hWndIME, msg, wParam, lParam);
 
-        rc = TRUE;
+        return TRUE;
     }
-    return rc;
+    return FALSE;
 }
 
 /***********************************************************************
@@ -2108,13 +2274,11 @@ 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)
-        SetLastError(ERROR_INVALID_HANDLE);
 
-    if (data && IsWindow(data->IMC.hWnd))
-        return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
+    if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
 
-     return 0;
+    SetLastError(ERROR_INVALID_HANDLE);
+    return 0;
 }
 
 /***********************************************************************
@@ -2126,13 +2290,10 @@ LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
 
     TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
 
-    if (!data)
-        SetLastError(ERROR_INVALID_HANDLE);
-
-    if (data && IsWindow(data->IMC.hWnd))
-        return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
+    if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
 
-     return 0;
+    SetLastError(ERROR_INVALID_HANDLE);
+    return 0;
 }
 
 /***********************************************************************
@@ -2148,11 +2309,13 @@ BOOL WINAPI ImmSetCandidateWindow(
     if (!data || !lpCandidate)
         return FALSE;
 
-    TRACE("\t%x, %x, (%i,%i), (%i,%i - %i,%i)\n",
-            lpCandidate->dwIndex, lpCandidate->dwStyle,
-            lpCandidate->ptCurrentPos.x, lpCandidate->ptCurrentPos.y,
-            lpCandidate->rcArea.top, lpCandidate->rcArea.left,
-            lpCandidate->rcArea.bottom, lpCandidate->rcArea.right);
+    if (IMM_IsCrossThreadAccess(NULL, hIMC))
+        return FALSE;
+
+    TRACE("\t%x, %x, %s, %s\n",
+          lpCandidate->dwIndex, lpCandidate->dwStyle,
+          wine_dbgstr_point(&lpCandidate->ptCurrentPos),
+          wine_dbgstr_rect(&lpCandidate->rcArea));
 
     if ( lpCandidate->dwIndex >= (sizeof(data->IMC.cfCandForm) / sizeof(CANDIDATEFORM)) )
         return FALSE;
@@ -2178,6 +2341,9 @@ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
         return FALSE;
     }
 
+    if (IMM_IsCrossThreadAccess(NULL, hIMC))
+        return FALSE;
+
     memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
     MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
                         LF_FACESIZE);
@@ -2201,6 +2367,9 @@ BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
         return FALSE;
     }
 
+    if (IMM_IsCrossThreadAccess(NULL, hIMC))
+        return FALSE;
+
     data->IMC.lfFont.W = *lplf;
     ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
@@ -2332,9 +2501,10 @@ BOOL WINAPI ImmSetCompositionWindow(
     InputContextData *data = get_imc_data(hIMC);
 
     TRACE("(%p, %p)\n", hIMC, lpCompForm);
-    TRACE("\t%x, (%i,%i), (%i,%i - %i,%i)\n",lpCompForm->dwStyle,
-          lpCompForm->ptCurrentPos.x, lpCompForm->ptCurrentPos.y, lpCompForm->rcArea.top,
-          lpCompForm->rcArea.left, lpCompForm->rcArea.bottom, lpCompForm->rcArea.right);
+    if (lpCompForm)
+        TRACE("\t%x, %s, %s\n", lpCompForm->dwStyle,
+              wine_dbgstr_point(&lpCompForm->ptCurrentPos),
+              wine_dbgstr_rect(&lpCompForm->rcArea));
 
     if (!data)
     {
@@ -2342,6 +2512,9 @@ BOOL WINAPI ImmSetCompositionWindow(
         return FALSE;
     }
 
+    if (IMM_IsCrossThreadAccess(NULL, hIMC))
+        return FALSE;
+
     data->IMC.cfCompForm = *lpCompForm;
 
     if (IsWindowVisible(data->immKbd->UIWnd))
@@ -2376,6 +2549,9 @@ BOOL WINAPI ImmSetConversionStatus(
         return FALSE;
     }
 
+    if (IMM_IsCrossThreadAccess(NULL, hIMC))
+        return FALSE;
+
     if ( fdwConversion != data->IMC.fdwConversion )
     {
         oldConversion = data->IMC.fdwConversion;
@@ -2409,6 +2585,9 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
         return FALSE;
     }
 
+    if (IMM_IsCrossThreadAccess(NULL, hIMC))
+        return FALSE;
+
     if (data->immKbd->UIWnd == NULL)
     {
         /* create the ime window */
@@ -2445,7 +2624,10 @@ BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
         return FALSE;
     }
 
-    TRACE("\t(%i,%i)\n", lpptPos->x, lpptPos->y);
+    if (IMM_IsCrossThreadAccess(NULL, hIMC))
+        return FALSE;
+
+    TRACE("\t%s\n", wine_dbgstr_point(lpptPos));
 
     data->IMC.ptStatusWndPos = *lpptPos;
     ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS);
@@ -2805,15 +2987,23 @@ BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
     if (data->IMC.dwNumMsgBuf > 0)
     {
         LPTRANSMSG lpTransMsg;
-        DWORD i;
-
-        lpTransMsg = ImmLockIMCC(data->IMC.hMsgBuf);
-        for (i = 0; i < data->IMC.dwNumMsgBuf; i++)
-            ImmInternalPostIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
+        HIMCC hMsgBuf;
+        DWORD i, dwNumMsgBuf;
 
-        ImmUnlockIMCC(data->IMC.hMsgBuf);
+        /* 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;
 
+        data->IMC.hMsgBuf = ImmCreateIMCC(0);
         data->IMC.dwNumMsgBuf = 0;
+
+        lpTransMsg = ImmLockIMCC(hMsgBuf);
+        for (i = 0; i < dwNumMsgBuf; i++)
+            ImmInternalSendIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
+
+        ImmUnlockIMCC(hMsgBuf);
+        ImmDestroyIMCC(hMsgBuf);
     }
 
     return TRUE;
@@ -2900,6 +3090,22 @@ BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD
     else
         return FALSE;
 
+    /* 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;
+    }
+
     if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey)
         return FALSE;
 
@@ -2942,53 +3148,3 @@ BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL hkl)
     FIXME("%x, %p, %p, %p: stub\n", hotkey, modifiers, key, hkl);
     return FALSE;
 }
-
-
-/*
- * Window Proc for the Default IME window class
- */
-static LRESULT WINAPI DefIME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
-                                        LPARAM lParam)
-{
-    switch (uMsg)
-    {
-        case WM_CREATE:
-        case WM_NCCREATE:
-            return TRUE;
-        case WM_IME_STARTCOMPOSITION:
-        case WM_IME_ENDCOMPOSITION:
-        case WM_IME_COMPOSITION:
-        case WM_IME_SETCONTEXT:
-        case WM_IME_NOTIFY:
-        case WM_IME_CONTROL:
-        case WM_IME_COMPOSITIONFULL:
-        case WM_IME_SELECT:
-        case WM_IME_CHAR:
-        case WM_IME_REQUEST:
-        case WM_IME_KEYDOWN:
-        case WM_IME_KEYUP:
-        {
-           ImmHkl *immHkl = IMM_GetImmHkl(GetKeyboardLayout(0));
-           if (immHkl->UIWnd)
-                return SendMessageW(immHkl->UIWnd,uMsg,wParam,lParam);
-           else
-                return FALSE;
-        }
-        default:
-            if ((uMsg == WM_MSIME_RECONVERTOPTIONS) ||
-                (uMsg == WM_MSIME_SERVICE) ||
-                (uMsg == WM_MSIME_MOUSE) ||
-                (uMsg == WM_MSIME_RECONVERTREQUEST) ||
-                (uMsg == WM_MSIME_RECONVERT) ||
-                (uMsg == WM_MSIME_QUERYPOSITION) ||
-                (uMsg == WM_MSIME_DOCUMENTFEED))
-            {
-               ImmHkl *immHkl = IMM_GetImmHkl(GetKeyboardLayout(0));
-               if (immHkl->UIWnd)
-                   return SendMessageW(immHkl->UIWnd,uMsg,wParam,lParam);
-               else
-                   return FALSE;
-            }
-            return DefWindowProcW(hwnd, uMsg, wParam, lParam);
-    }
-}
diff --git a/dll/win32/imm32/imm32.spec b/dll/win32/imm32/imm32.spec
index 37c46ab..2be5d92 100644
--- a/dll/win32/imm32/imm32.spec
+++ b/dll/win32/imm32/imm32.spec
@@ -110,3 +110,9 @@
 @ stub ImmWINNLSEnableIME
 @ stub ImmWINNLSGetEnableStatus
 @ stub ImmWINNLSGetIMEHotkey
+
+################################################################
+# Wine internal extensions
+@ stdcall __wine_get_ui_window(ptr)
+@ stdcall __wine_register_window(long)
+@ stdcall __wine_unregister_window(long)
diff --git a/sdk/include/psdk/winbase.h b/sdk/include/psdk/winbase.h
index ec3615a..e8c14cf 100644
--- a/sdk/include/psdk/winbase.h
+++ b/sdk/include/psdk/winbase.h
@@ -2266,6 +2266,7 @@ HANDLE WINAPI GetProcessHeap(VOID);
 DWORD WINAPI GetProcessHeaps(DWORD,PHANDLE);
 #if (_WIN32_WINNT >= 0x0502)
 DWORD WINAPI GetProcessId(HANDLE);
+DWORD WINAPI GetProcessIdOfThread(HANDLE);
 #endif
 #if (_WIN32_WINNT >= 0x0500)
 BOOL WINAPI GetProcessIoCounters(_In_ HANDLE, _Out_ PIO_COUNTERS);
diff --git a/win32ss/user/ntuser/simplecall.c b/win32ss/user/ntuser/simplecall.c
index a32ed43..4be533a 100644
--- a/win32ss/user/ntuser/simplecall.c
+++ b/win32ss/user/ntuser/simplecall.c
@@ -113,6 +113,10 @@ NtUserCallNoParam(DWORD Routine)
       case NOPARAM_ROUTINE_ISCONSOLEMODE:
           RETURN( ScreenDeviceContext == NULL );
 
+      case NOPARAM_ROUTINE_UPDATEPERUSERIMMENABLING:
+          gpsi->dwSRVIFlags |= SRVINFO_IMM32; // Always set.
+          RETURN(1); // Always return TRUE.
+
       default:
          ERR("Calling invalid routine number 0x%x in NtUserCallNoParam\n", Routine);
          EngSetLastError(ERROR_INVALID_PARAMETER);
diff --git a/win32ss/user/user32/include/user32p.h b/win32ss/user/user32/include/user32p.h
index cdf9378..9bfaeec 100644
--- a/win32ss/user/user32/include/user32p.h
+++ b/win32ss/user/user32/include/user32p.h
@@ -134,5 +134,6 @@ VOID DeleteFrameBrushes(VOID);
 BOOL WINAPI GdiValidateHandle(HGDIOBJ);
 HANDLE FASTCALL UserGetProp(HWND hWnd, ATOM Atom, BOOLEAN SystemProp);
 BOOL WINAPI InitializeImmEntryTable(VOID);
+BOOL WINAPI UpdatePerUserImmEnabling(VOID);
 
 /* EOF */
diff --git a/win32ss/user/user32/misc/imm.c b/win32ss/user/user32/misc/imm.c
index a89dafe..ed05778 100644
--- a/win32ss/user/user32/misc/imm.c
+++ b/win32ss/user/user32/misc/imm.c
@@ -25,19 +25,6 @@ HINSTANCE ghImm32 = NULL;
 BOOL bImmInitializing = FALSE;
 BOOL ImmApiTableZero = TRUE;
 
-HRESULT WINAPI GetImmFileName(PWSTR lpBuffer, UINT uSize)
-{
-  UINT length;
-  STRSAFE_LPWSTR Safe = lpBuffer;
-
-  length = GetSystemDirectoryW(lpBuffer, uSize);
-  if ( length && length < uSize )
-  {
-    StringCchCatW(Safe, uSize, L"\\");
-    return StringCchCatW(Safe, uSize, L"IMM32.DLL");
-  }
-  return StringCchCopyW(Safe, uSize, L"IMM32.DLL");
-}  
 
 /*
  *  This function should not be implemented, it is used,
@@ -59,6 +46,20 @@ BOOL WINAPI IMM_ImmNotifyIME(HIMC himc, DWORD dword1, DWORD dword2, DWORD dword3
 BOOL WINAPI IMM_ImmRegisterClient(PVOID ptr, HINSTANCE hMod) { return 0; }
 UINT WINAPI IMM_ImmProcessKey(HWND hwnd, HKL hkl, UINT Vk, LPARAM lParam, DWORD HotKey) { return 0; }
 
+HRESULT WINAPI GetImmFileName(PWSTR lpBuffer, UINT uSize)
+{
+  UINT length;
+  STRSAFE_LPWSTR Safe = lpBuffer;
+
+  length = GetSystemDirectoryW(lpBuffer, uSize);
+  if ( length && length < uSize )
+  {
+    StringCchCatW(Safe, uSize, L"\\");
+    return StringCchCatW(Safe, uSize, L"imm32.dll");
+  }
+  return StringCchCopyW(Safe, uSize, L"imm32.dll");
+}  
+
 /*
  * @unimplemented
  */
@@ -189,7 +190,7 @@ BOOL WINAPI InitializeImmEntryTable(VOID)
 
 BOOL WINAPI User32InitializeImmEntryTable(DWORD magic)
 {
-    TRACE("(%x)\n", magic);
+    ERR("Imm (%x)\n", magic);
 
     if (magic != IMM_INIT_MAGIC)
         return FALSE;
@@ -285,6 +286,29 @@ LRESULT WINAPI ImeWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
     return ImeWndProc_common(hwnd, msg, wParam, lParam, TRUE);
 }
 
+BOOL
+WINAPI
+UpdatePerUserImmEnabling(VOID)
+{
+  BOOL Ret = NtUserCallNoParam(NOPARAM_ROUTINE_UPDATEPERUSERIMMENABLING);
+  if ( Ret )
+  {
+    if ( gpsi->dwSRVIFlags & SRVINFO_IMM32 )
+    {
+      HMODULE imm32 = GetModuleHandleW(L"imm32.dll");
+      if ( !imm32 )
+      {
+        ghImm32 = imm32 = LoadLibraryW(L"imm32.dll");
+        if (!imm32)
+        {
+           ERR("UPUIE: Imm32 not installed!\n");
+        }
+      }
+    }
+  }
+  return Ret;
+}
+
 static const WCHAR imeW[] = {'I','M','E',0};
 
 BOOL
@@ -311,6 +335,7 @@ RegisterIMEClass(VOID)
     if (atom)
     {
        RegisterDefaultClasses |= ICLASS_TO_MASK(ICLS_IME);
+       ERR("Register IME Class!\n");
        return TRUE;
     }
     ERR("Failed to register IME Class!\n");
diff --git a/win32ss/user/user32/misc/logon.c b/win32ss/user/user32/misc/logon.c
index abc6ee3..3df5a95 100644
--- a/win32ss/user/user32/misc/logon.c
+++ b/win32ss/user/user32/misc/logon.c
@@ -107,5 +107,8 @@ WINAPI
 UpdatePerUserSystemParameters(DWORD dwReserved,
                               BOOL bEnable)
 {
+    // Update Imm support and load Imm32.dll.
+    UpdatePerUserImmEnabling();
+
     return NtUserUpdatePerUserSystemParameters(dwReserved, bEnable);
 }
diff --git a/win32ss/user/user32/windows/defwnd.c b/win32ss/user/user32/windows/defwnd.c
index 383c293..067d656 100644
--- a/win32ss/user/user32/windows/defwnd.c
+++ b/win32ss/user/user32/windows/defwnd.c
@@ -803,75 +803,6 @@ GoSS:
 }
 
 
-/*
- * helpers for calling IMM32 (from Wine 10/22/2008)
- *
- * WM_IME_* messages are generated only by IMM32,
- * so I assume imm32 is already LoadLibrary-ed.
- */
-static HWND
-DefWndImmGetDefaultIMEWnd(HWND hwnd)
-{
-    HINSTANCE hInstIMM = GetModuleHandleW(L"imm32\0");
-    HWND (WINAPI *pFunc)(HWND);
-    HWND hwndRet = 0;
-
-    if (!hInstIMM)
-    {
-        ERR("cannot get IMM32 handle\n");
-        return 0;
-    }
-
-    pFunc = (void*) GetProcAddress(hInstIMM, "ImmGetDefaultIMEWnd");
-    if (pFunc != NULL)
-        hwndRet = (*pFunc)(hwnd);
-
-    return hwndRet;
-}
-
-
-static BOOL
-DefWndImmIsUIMessageA(HWND hwndIME, UINT msg, WPARAM wParam, LPARAM lParam)
-{
-    HINSTANCE hInstIMM = GetModuleHandleW(L"imm32\0");
-    BOOL (WINAPI *pFunc)(HWND,UINT,WPARAM,LPARAM);
-    BOOL fRet = FALSE;
-
-    if (!hInstIMM)
-    {
-        ERR("cannot get IMM32 handle\n");
-        return FALSE;
-    }
-
-    pFunc = (void*) GetProcAddress(hInstIMM, "ImmIsUIMessageA");
-    if (pFunc != NULL)
-        fRet = (*pFunc)(hwndIME, msg, wParam, lParam);
-
-    return fRet;
-}
-
-
-static BOOL
-DefWndImmIsUIMessageW(HWND hwndIME, UINT msg, WPARAM wParam, LPARAM lParam)
-{
-    HINSTANCE hInstIMM = GetModuleHandleW(L"imm32\0");
-    BOOL (WINAPI *pFunc)(HWND,UINT,WPARAM,LPARAM);
-    BOOL fRet = FALSE;
-
-    if (!hInstIMM)
-    {
-        ERR("cannot get IMM32 handle\n");
-        return FALSE;
-    }
-
-    pFunc = (void*) GetProcAddress(hInstIMM, "ImmIsUIMessageW");
-    if (pFunc != NULL)
-        fRet = (*pFunc)(hwndIME, msg, wParam, lParam);
-
-    return fRet;
-}
-
-
 LRESULT WINAPI
 RealDefWindowProcA(HWND hWnd,
                    UINT Msg,
@@ -1009,8 +940,44 @@ RealDefWindowProcA(HWND hWnd,
             break;
         }
 
-        case WM_IME_STARTCOMPOSITION:
         case WM_IME_COMPOSITION:
+        if (lParam & GCS_RESULTSTR)
+        {
+            LONG size, i;
+            unsigned char lead = 0;
+            char *buf = NULL;
+            HIMC himc = ImmGetContext( hWnd );
+
+            if (himc)
+            {
+                if ((size = ImmGetCompositionStringA( himc, GCS_RESULTSTR, NULL, 0 )))
+                {
+                    if (!(buf = HeapAlloc( GetProcessHeap(), 0, size ))) size = 0;
+                    else size = ImmGetCompositionStringA( himc, GCS_RESULTSTR, buf, size );
+                }
+                ImmReleaseContext( hWnd, himc );
+
+                for (i = 0; i < size; i++)
+                {
+                    unsigned char c = buf[i];
+                    if (!lead)
+                    {
+                        if (IsDBCSLeadByte( c ))
+                            lead = c;
+                        else
+                            SendMessageA( hWnd, WM_IME_CHAR, c, 1 );
+                    }
+                    else
+                    {
+                        SendMessageA( hWnd, WM_IME_CHAR, MAKEWORD(c, lead), 1 );
+                        lead = 0;
+                    }
+                }
+                HeapFree( GetProcessHeap(), 0, buf );
+            }
+        }
+        /* fall through */
+        case WM_IME_STARTCOMPOSITION:
         case WM_IME_ENDCOMPOSITION:
         case WM_IME_SELECT:
         case WM_IME_NOTIFY:
@@ -1018,7 +985,7 @@ RealDefWindowProcA(HWND hWnd,
         {
             HWND hwndIME;
 
-            hwndIME = DefWndImmGetDefaultIMEWnd(hWnd);
+            hwndIME = ImmGetDefaultIMEWnd(hWnd);
             if (hwndIME)
                 Result = SendMessageA(hwndIME, Msg, wParam, lParam);
             break;
@@ -1028,9 +995,9 @@ RealDefWindowProcA(HWND hWnd,
         {
             HWND hwndIME;
 
-            hwndIME = DefWndImmGetDefaultIMEWnd(hWnd);
+            hwndIME = ImmGetDefaultIMEWnd(hWnd);
             if (hwndIME)
-                Result = DefWndImmIsUIMessageA(hwndIME, Msg, wParam, lParam);
+                Result = ImmIsUIMessageA(hwndIME, Msg, wParam, lParam);
             break;
         }
 
@@ -1171,8 +1138,29 @@ RealDefWindowProcW(HWND hWnd,
             break;
         }
 
-        case WM_IME_STARTCOMPOSITION:
         case WM_IME_COMPOSITION:
+        if (lParam & GCS_RESULTSTR)
+        {
+            LONG size, i;
+            WCHAR *buf = NULL;
+            HIMC himc = ImmGetContext( hWnd );
+
+            if (himc)
+            {
+                if ((size = ImmGetCompositionStringW( himc, GCS_RESULTSTR, NULL, 0 )))
+                {
+                    if (!(buf = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) size = 0;
+                    else size = ImmGetCompositionStringW( himc, GCS_RESULTSTR, buf, size * sizeof(WCHAR) );
+                }
+                ImmReleaseContext( hWnd, himc );
+
+                for (i = 0; i < size / sizeof(WCHAR); i++)
+                    SendMessageW( hWnd, WM_IME_CHAR, buf[i], 1 );
+                HeapFree( GetProcessHeap(), 0, buf );
+            }
+        }
+        /* fall through */
+        case WM_IME_STARTCOMPOSITION:
         case WM_IME_ENDCOMPOSITION:
         case WM_IME_SELECT:
         case WM_IME_NOTIFY:
@@ -1180,7 +1168,7 @@ RealDefWindowProcW(HWND hWnd,
         {
             HWND hwndIME;
 
-            hwndIME = DefWndImmGetDefaultIMEWnd(hWnd);
+            hwndIME = ImmGetDefaultIMEWnd(hWnd);
             if (hwndIME)
                 Result = SendMessageW(hwndIME, Msg, wParam, lParam);
             break;
@@ -1190,9 +1178,9 @@ RealDefWindowProcW(HWND hWnd,
         {
             HWND hwndIME;
 
-            hwndIME = DefWndImmGetDefaultIMEWnd(hWnd);
+            hwndIME = ImmGetDefaultIMEWnd(hWnd);
             if (hwndIME)
-                Result = DefWndImmIsUIMessageW(hwndIME, Msg, wParam, lParam);
+                Result = ImmIsUIMessageW(hwndIME, Msg, wParam, lParam);
             break;
         }
 
