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