Aric Stewart : imm32: Restrict cross-thread association and destruction.

Alexandre Julliard julliard at wine.codeweavers.com
Thu Feb 26 09:17:00 CST 2015


Module: wine
Branch: master
Commit: fdf37fe7443f13a16ea68fc44d96cece20bad70b
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=fdf37fe7443f13a16ea68fc44d96cece20bad70b

Author: Aric Stewart <aric at codeweavers.com>
Date:   Wed Feb 25 11:45:26 2015 -0600

imm32: Restrict cross-thread association and destruction.

---

 dlls/imm32/imm.c         | 23 ++++++++++++++++++-
 dlls/imm32/tests/imm32.c | 59 +++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 78 insertions(+), 4 deletions(-)

diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c
index 2b3804e..481f98f 100644
--- a/dlls/imm32/imm.c
+++ b/dlls/imm32/imm.c
@@ -74,6 +74,7 @@ typedef struct tagInputContextData
 {
         DWORD           dwLock;
         INPUTCONTEXT    IMC;
+        DWORD           threadID;
 
         ImmHkl          *immKbd;
         UINT            lastVK;
@@ -523,6 +524,22 @@ static IMMThreadData* IMM_GetInitializedThreadData(HWND hWnd)
     return thread_data;
 }
 
+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.@)
  */
@@ -543,6 +560,9 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
     if (hIMC && data->IMC.hWnd == hWnd)
         return hIMC;
 
+    if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC))
+        return NULL;
+
     thread_data = IMM_GetInitializedThreadData(hWnd);
     if (!thread_data)
         return NULL;
@@ -770,6 +790,7 @@ HIMC WINAPI ImmCreateContext(void)
         IMM_DestroyContext(new_context);
         return 0;
     }
+    new_context->threadID = GetCurrentThreadId();
     SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)GetKeyboardLayout(0));
 
     new_context->immKbd->uSelected++;
@@ -809,7 +830,7 @@ static BOOL IMM_DestroyContext(HIMC hIMC)
  */
 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
 {
-    if (!IMM_IsDefaultContext(hIMC))
+    if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC))
         return IMM_DestroyContext(hIMC);
     else
         return FALSE;
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c
index 34e82c6..d7854c6 100644
--- a/dlls/imm32/tests/imm32.c
+++ b/dlls/imm32/tests/imm32.c
@@ -416,6 +416,7 @@ typedef struct _igc_threadinfo {
     HWND hwnd;
     HANDLE event;
     HIMC himc;
+    HIMC u_himc;
 } igc_threadinfo;
 
 
@@ -424,6 +425,7 @@ static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam)
     HIMC h1,h2;
     HWND hwnd2;
     COMPOSITIONFORM cf;
+    CANDIDATEFORM cdf;
     POINT pt;
     MSG msg;
 
@@ -452,6 +454,13 @@ static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam)
     /* priming for later tests */
     ImmSetCompositionWindow(h1, &cf);
     ImmSetStatusWindowPos(h1, &pt);
+    info->u_himc = ImmCreateContext();
+    ImmSetOpenStatus(info->u_himc, TRUE);
+    cdf.dwIndex = 0;
+    cdf.dwStyle = CFS_CANDIDATEPOS;
+    cdf.ptCurrentPos.x = 0;
+    cdf.ptCurrentPos.y = 0;
+    ImmSetCandidateWindow(info->u_himc, &cdf);
 
     SetEvent(info->event);
 
@@ -487,15 +496,23 @@ static void test_ImmThreads(void)
     ok(himc != otherHimc, "Windows from other threads should have different himc\n");
     ok(otherHimc == threadinfo.himc, "Context from other thread should not change in main thread\n");
 
-    if (0) /* FIXME: Causes wine to hang */
-    {
     h1 = ImmAssociateContext(hwnd,otherHimc);
     ok(h1 == NULL, "Should fail to be able to Associate a default context from a different thread\n");
     h1 = ImmGetContext(hwnd);
     ok(h1 == himc, "Context for window should remain unchanged\n");
     ImmReleaseContext(hwnd,h1);
-    }
 
+    h1 = ImmAssociateContext(hwnd, threadinfo.u_himc);
+    ok (h1 == NULL, "Should fail to associate a context from a different thread\n");
+    h1 = ImmGetContext(hwnd);
+    ok(h1 == himc, "Context for window should remain unchanged\n");
+    ImmReleaseContext(hwnd,h1);
+
+    h1 = ImmAssociateContext(threadinfo.hwnd, threadinfo.u_himc);
+    ok (h1 == NULL, "Should fail to associate a context from a different thread into a window from that thread.\n");
+    h1 = ImmGetContext(threadinfo.hwnd);
+    ok(h1 == threadinfo.himc, "Context for window should remain unchanged\n");
+    ImmReleaseContext(threadinfo.hwnd,h1);
 
     /* OpenStatus */
     rc = ImmSetOpenStatus(himc, TRUE);
@@ -509,8 +526,12 @@ static void test_ImmThreads(void)
 
     rc = ImmSetOpenStatus(otherHimc, TRUE);
     todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
+    rc = ImmSetOpenStatus(threadinfo.u_himc, TRUE);
+    todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
     rc = ImmGetOpenStatus(otherHimc);
     todo_wine ok(rc == 0, "ImmGetOpenStatus failed\n");
+    rc = ImmGetOpenStatus(threadinfo.u_himc);
+    ok (rc == 1 || broken(rc == 0), "ImmGetOpenStatus should return 1\n");
     rc = ImmSetOpenStatus(otherHimc, FALSE);
     todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
     rc = ImmGetOpenStatus(otherHimc);
@@ -524,8 +545,12 @@ static void test_ImmThreads(void)
 
     rc = ImmGetCompositionFontA(otherHimc, &lf);
     ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont failed\n");
+    rc = ImmGetCompositionFontA(threadinfo.u_himc, &lf);
+    ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont user himc failed\n");
     rc = ImmSetCompositionFontA(otherHimc, &lf);
     todo_wine ok(rc == 0, "ImmSetCompositionFont should fail\n");
+    rc = ImmSetCompositionFontA(threadinfo.u_himc, &lf);
+    todo_wine ok(rc == 0, "ImmSetCompositionFont should fail\n");
 
     /* CompositionWindow */
     rc = ImmSetCompositionWindow(himc, &cf);
@@ -535,8 +560,12 @@ static void test_ImmThreads(void)
 
     rc = ImmSetCompositionWindow(otherHimc, &cf);
     todo_wine ok(rc == 0, "ImmSetCompositionWindow should fail\n");
+    rc = ImmSetCompositionWindow(threadinfo.u_himc, &cf);
+    todo_wine ok(rc == 0, "ImmSetCompositionWindow should fail\n");
     rc = ImmGetCompositionWindow(otherHimc, &cf);
     ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n");
+    rc = ImmGetCompositionWindow(threadinfo.u_himc, &cf);
+    ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n");
 
     /* ConversionStatus */
     rc = ImmGetConversionStatus(himc, &status, &sentence);
@@ -546,8 +575,12 @@ static void test_ImmThreads(void)
 
     rc = ImmGetConversionStatus(otherHimc, &status, &sentence);
     ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n");
+    rc = ImmGetConversionStatus(threadinfo.u_himc, &status, &sentence);
+    ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n");
     rc = ImmSetConversionStatus(otherHimc, status, sentence);
     todo_wine ok(rc == 0, "ImmSetConversionStatus should fail\n");
+    rc = ImmSetConversionStatus(threadinfo.u_himc, status, sentence);
+    todo_wine ok(rc == 0, "ImmSetConversionStatus should fail\n");
 
     /* StatusWindowPos */
     rc = ImmSetStatusWindowPos(himc, &pt);
@@ -557,8 +590,24 @@ static void test_ImmThreads(void)
 
     rc = ImmSetStatusWindowPos(otherHimc, &pt);
     todo_wine ok(rc == 0, "ImmSetStatusWindowPos should fail\n");
+    rc = ImmSetStatusWindowPos(threadinfo.u_himc, &pt);
+    todo_wine ok(rc == 0, "ImmSetStatusWindowPos should fail\n");
     rc = ImmGetStatusWindowPos(otherHimc, &pt);
     ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n");
+    rc = ImmGetStatusWindowPos(threadinfo.u_himc, &pt);
+    ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n");
+
+    h1 = ImmAssociateContext(threadinfo.hwnd, NULL);
+    ok (h1 == otherHimc, "ImmAssociateContext cross thread with NULL should work\n");
+    h1 = ImmGetContext(threadinfo.hwnd);
+    ok (h1 == NULL, "CrossThread window context should be NULL\n");
+    h1 = ImmAssociateContext(threadinfo.hwnd, h1);
+    ok (h1 == NULL, "Resetting cross thread context should fail\n");
+    h1 = ImmGetContext(threadinfo.hwnd);
+    ok (h1 == NULL, "CrossThread window context should still be NULL\n");
+
+    rc = ImmDestroyContext(threadinfo.u_himc);
+    ok (rc == 0, "ImmDestroyContext Cross Thread should fail\n");
 
     /* Candidate Window */
     rc = ImmGetCandidateWindow(himc, 0, &cdf);
@@ -576,6 +625,10 @@ static void test_ImmThreads(void)
     ok (rc == 0, "ImmGetCandidateWindow should fail\n");
     rc = ImmSetCandidateWindow(otherHimc, &cdf);
     todo_wine ok (rc == 0, "ImmSetCandidateWindow should fail\n");
+    rc = ImmGetCandidateWindow(threadinfo.u_himc, 0, &cdf);
+    ok (rc == 1 || broken( rc == 0), "ImmGetCandidateWindow should succeed\n");
+    rc = ImmSetCandidateWindow(threadinfo.u_himc, &cdf);
+    todo_wine ok (rc == 0, "ImmSetCandidateWindow should fail\n");
 
     ImmReleaseContext(threadinfo.hwnd,otherHimc);
     ImmReleaseContext(hwnd,himc);




More information about the wine-cvs mailing list