imm32: Restrict cross-thread association and destruction.
This commit is contained in:
parent
455ca1adb0
commit
fdf37fe744
|
@ -74,6 +74,7 @@ typedef struct tagInputContextData
|
||||||
{
|
{
|
||||||
DWORD dwLock;
|
DWORD dwLock;
|
||||||
INPUTCONTEXT IMC;
|
INPUTCONTEXT IMC;
|
||||||
|
DWORD threadID;
|
||||||
|
|
||||||
ImmHkl *immKbd;
|
ImmHkl *immKbd;
|
||||||
UINT lastVK;
|
UINT lastVK;
|
||||||
|
@ -523,6 +524,22 @@ static IMMThreadData* IMM_GetInitializedThreadData(HWND hWnd)
|
||||||
return thread_data;
|
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.@)
|
* ImmAssociateContext (IMM32.@)
|
||||||
*/
|
*/
|
||||||
|
@ -543,6 +560,9 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
|
||||||
if (hIMC && data->IMC.hWnd == hWnd)
|
if (hIMC && data->IMC.hWnd == hWnd)
|
||||||
return hIMC;
|
return hIMC;
|
||||||
|
|
||||||
|
if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
thread_data = IMM_GetInitializedThreadData(hWnd);
|
thread_data = IMM_GetInitializedThreadData(hWnd);
|
||||||
if (!thread_data)
|
if (!thread_data)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -770,6 +790,7 @@ HIMC WINAPI ImmCreateContext(void)
|
||||||
IMM_DestroyContext(new_context);
|
IMM_DestroyContext(new_context);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
new_context->threadID = GetCurrentThreadId();
|
||||||
SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)GetKeyboardLayout(0));
|
SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)GetKeyboardLayout(0));
|
||||||
|
|
||||||
new_context->immKbd->uSelected++;
|
new_context->immKbd->uSelected++;
|
||||||
|
@ -809,7 +830,7 @@ static BOOL IMM_DestroyContext(HIMC hIMC)
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI ImmDestroyContext(HIMC hIMC)
|
BOOL WINAPI ImmDestroyContext(HIMC hIMC)
|
||||||
{
|
{
|
||||||
if (!IMM_IsDefaultContext(hIMC))
|
if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC))
|
||||||
return IMM_DestroyContext(hIMC);
|
return IMM_DestroyContext(hIMC);
|
||||||
else
|
else
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
|
@ -416,6 +416,7 @@ typedef struct _igc_threadinfo {
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
HANDLE event;
|
HANDLE event;
|
||||||
HIMC himc;
|
HIMC himc;
|
||||||
|
HIMC u_himc;
|
||||||
} igc_threadinfo;
|
} igc_threadinfo;
|
||||||
|
|
||||||
|
|
||||||
|
@ -424,6 +425,7 @@ static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam)
|
||||||
HIMC h1,h2;
|
HIMC h1,h2;
|
||||||
HWND hwnd2;
|
HWND hwnd2;
|
||||||
COMPOSITIONFORM cf;
|
COMPOSITIONFORM cf;
|
||||||
|
CANDIDATEFORM cdf;
|
||||||
POINT pt;
|
POINT pt;
|
||||||
MSG msg;
|
MSG msg;
|
||||||
|
|
||||||
|
@ -452,6 +454,13 @@ static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam)
|
||||||
/* priming for later tests */
|
/* priming for later tests */
|
||||||
ImmSetCompositionWindow(h1, &cf);
|
ImmSetCompositionWindow(h1, &cf);
|
||||||
ImmSetStatusWindowPos(h1, &pt);
|
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);
|
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(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");
|
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);
|
h1 = ImmAssociateContext(hwnd,otherHimc);
|
||||||
ok(h1 == NULL, "Should fail to be able to Associate a default context from a different thread\n");
|
ok(h1 == NULL, "Should fail to be able to Associate a default context from a different thread\n");
|
||||||
h1 = ImmGetContext(hwnd);
|
h1 = ImmGetContext(hwnd);
|
||||||
ok(h1 == himc, "Context for window should remain unchanged\n");
|
ok(h1 == himc, "Context for window should remain unchanged\n");
|
||||||
ImmReleaseContext(hwnd,h1);
|
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 */
|
/* OpenStatus */
|
||||||
rc = ImmSetOpenStatus(himc, TRUE);
|
rc = ImmSetOpenStatus(himc, TRUE);
|
||||||
|
@ -509,8 +526,12 @@ static void test_ImmThreads(void)
|
||||||
|
|
||||||
rc = ImmSetOpenStatus(otherHimc, TRUE);
|
rc = ImmSetOpenStatus(otherHimc, TRUE);
|
||||||
todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
|
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);
|
rc = ImmGetOpenStatus(otherHimc);
|
||||||
todo_wine ok(rc == 0, "ImmGetOpenStatus failed\n");
|
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);
|
rc = ImmSetOpenStatus(otherHimc, FALSE);
|
||||||
todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
|
todo_wine ok(rc == 0, "ImmSetOpenStatus should fail\n");
|
||||||
rc = ImmGetOpenStatus(otherHimc);
|
rc = ImmGetOpenStatus(otherHimc);
|
||||||
|
@ -524,8 +545,12 @@ static void test_ImmThreads(void)
|
||||||
|
|
||||||
rc = ImmGetCompositionFontA(otherHimc, &lf);
|
rc = ImmGetCompositionFontA(otherHimc, &lf);
|
||||||
ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont failed\n");
|
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);
|
rc = ImmSetCompositionFontA(otherHimc, &lf);
|
||||||
todo_wine ok(rc == 0, "ImmSetCompositionFont should fail\n");
|
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 */
|
/* CompositionWindow */
|
||||||
rc = ImmSetCompositionWindow(himc, &cf);
|
rc = ImmSetCompositionWindow(himc, &cf);
|
||||||
|
@ -535,8 +560,12 @@ static void test_ImmThreads(void)
|
||||||
|
|
||||||
rc = ImmSetCompositionWindow(otherHimc, &cf);
|
rc = ImmSetCompositionWindow(otherHimc, &cf);
|
||||||
todo_wine ok(rc == 0, "ImmSetCompositionWindow should fail\n");
|
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);
|
rc = ImmGetCompositionWindow(otherHimc, &cf);
|
||||||
ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n");
|
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 */
|
/* ConversionStatus */
|
||||||
rc = ImmGetConversionStatus(himc, &status, &sentence);
|
rc = ImmGetConversionStatus(himc, &status, &sentence);
|
||||||
|
@ -546,8 +575,12 @@ static void test_ImmThreads(void)
|
||||||
|
|
||||||
rc = ImmGetConversionStatus(otherHimc, &status, &sentence);
|
rc = ImmGetConversionStatus(otherHimc, &status, &sentence);
|
||||||
ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n");
|
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);
|
rc = ImmSetConversionStatus(otherHimc, status, sentence);
|
||||||
todo_wine ok(rc == 0, "ImmSetConversionStatus should fail\n");
|
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 */
|
/* StatusWindowPos */
|
||||||
rc = ImmSetStatusWindowPos(himc, &pt);
|
rc = ImmSetStatusWindowPos(himc, &pt);
|
||||||
|
@ -557,8 +590,24 @@ static void test_ImmThreads(void)
|
||||||
|
|
||||||
rc = ImmSetStatusWindowPos(otherHimc, &pt);
|
rc = ImmSetStatusWindowPos(otherHimc, &pt);
|
||||||
todo_wine ok(rc == 0, "ImmSetStatusWindowPos should fail\n");
|
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);
|
rc = ImmGetStatusWindowPos(otherHimc, &pt);
|
||||||
ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n");
|
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 */
|
/* Candidate Window */
|
||||||
rc = ImmGetCandidateWindow(himc, 0, &cdf);
|
rc = ImmGetCandidateWindow(himc, 0, &cdf);
|
||||||
|
@ -576,6 +625,10 @@ static void test_ImmThreads(void)
|
||||||
ok (rc == 0, "ImmGetCandidateWindow should fail\n");
|
ok (rc == 0, "ImmGetCandidateWindow should fail\n");
|
||||||
rc = ImmSetCandidateWindow(otherHimc, &cdf);
|
rc = ImmSetCandidateWindow(otherHimc, &cdf);
|
||||||
todo_wine ok (rc == 0, "ImmSetCandidateWindow should fail\n");
|
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(threadinfo.hwnd,otherHimc);
|
||||||
ImmReleaseContext(hwnd,himc);
|
ImmReleaseContext(hwnd,himc);
|
||||||
|
|
Loading…
Reference in New Issue