imm32: Validate input context in multiple IMC functions.

Both tests and fixes improved by Aric Stewart.
This commit is contained in:
Qian Hong 2013-09-17 22:52:02 +08:00 committed by Alexandre Julliard
parent 4ad9d5f04a
commit b4b428ee9e
2 changed files with 524 additions and 49 deletions

View File

@ -74,8 +74,11 @@ typedef struct tagInputContextData
ImmHkl *immKbd;
UINT lastVK;
DWORD magic;
} InputContextData;
#define WINE_IMC_VALID_MAGIC 0x56434D49
typedef struct _tagTRANSMSG {
UINT message;
WPARAM wParam;
@ -425,16 +428,34 @@ static HIMCC ImmCreateBlankCompStr(void)
return rc;
}
static InputContextData* get_imc_data(HIMC hIMC)
{
InputContextData *data = hIMC;
if (hIMC == NULL)
return NULL;
if(IsBadReadPtr(data, sizeof(InputContextData)) || data->magic != WINE_IMC_VALID_MAGIC)
{
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
return data;
}
/***********************************************************************
* ImmAssociateContext (IMM32.@)
*/
HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
{
HIMC old = NULL;
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p):\n", hWnd, hIMC);
if(hIMC && !data)
return NULL;
if (!IMM_GetThreadData()->defaultContext)
IMM_GetThreadData()->defaultContext = ImmCreateContext();
@ -656,29 +677,32 @@ HIMC WINAPI ImmCreateContext(void)
new_context->immKbd->uSelected++;
TRACE("Created context %p\n",new_context);
new_context->magic = WINE_IMC_VALID_MAGIC;
return new_context;
}
static BOOL IMM_DestroyContext(HIMC hIMC)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("Destroying %p\n",hIMC);
if (hIMC)
{
data->immKbd->uSelected --;
data->immKbd->pImeSelect(hIMC, FALSE);
SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)GetKeyboardLayout(0));
if (!data)
return FALSE;
ImmDestroyIMCC(data->IMC.hCompStr);
ImmDestroyIMCC(data->IMC.hCandInfo);
ImmDestroyIMCC(data->IMC.hGuideLine);
ImmDestroyIMCC(data->IMC.hPrivate);
ImmDestroyIMCC(data->IMC.hMsgBuf);
data->immKbd->uSelected --;
data->immKbd->pImeSelect(hIMC, FALSE);
SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)GetKeyboardLayout(0));
ImmDestroyIMCC(data->IMC.hCompStr);
ImmDestroyIMCC(data->IMC.hCandInfo);
ImmDestroyIMCC(data->IMC.hGuideLine);
ImmDestroyIMCC(data->IMC.hPrivate);
ImmDestroyIMCC(data->IMC.hMsgBuf);
data->magic = 0;
HeapFree(GetProcessHeap(),0,data);
HeapFree(GetProcessHeap(),0,data);
}
return TRUE;
}
@ -858,7 +882,7 @@ DWORD WINAPI ImmGetCandidateListA(
HIMC hIMC, DWORD dwIndex,
LPCANDIDATELIST lpCandList, DWORD dwBufLen)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
LPCANDIDATEINFO candinfo;
LPCANDIDATELIST candlist;
DWORD ret = 0;
@ -897,7 +921,7 @@ done:
DWORD WINAPI ImmGetCandidateListCountA(
HIMC hIMC, LPDWORD lpdwListCount)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
LPCANDIDATEINFO candinfo;
DWORD ret, count;
@ -929,7 +953,7 @@ DWORD WINAPI ImmGetCandidateListCountA(
DWORD WINAPI ImmGetCandidateListCountW(
HIMC hIMC, LPDWORD lpdwListCount)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
LPCANDIDATEINFO candinfo;
DWORD ret, count;
@ -962,7 +986,7 @@ DWORD WINAPI ImmGetCandidateListW(
HIMC hIMC, DWORD dwIndex,
LPCANDIDATELIST lpCandList, DWORD dwBufLen)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
LPCANDIDATEINFO candinfo;
LPCANDIDATELIST candlist;
DWORD ret = 0;
@ -1001,7 +1025,7 @@ done:
BOOL WINAPI ImmGetCandidateWindow(
HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("%p, %d, %p\n", hIMC, dwIndex, lpCandidate);
@ -1041,7 +1065,7 @@ BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
*/
BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p):\n", hIMC, lplf);
@ -1220,7 +1244,7 @@ static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
DWORD dwBufLen, BOOL unicode)
{
LONG rc = 0;
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
LPCOMPOSITIONSTRING compstr;
LPBYTE compdata;
@ -1332,7 +1356,7 @@ LONG WINAPI ImmGetCompositionStringW(
*/
BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lpCompForm);
@ -1459,7 +1483,7 @@ DWORD WINAPI ImmGetConversionListW(
BOOL WINAPI ImmGetConversionStatus(
HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence);
@ -1640,7 +1664,7 @@ UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
*/
BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
static int i;
if (!data)
@ -1743,7 +1767,7 @@ UINT WINAPI ImmGetRegisterWordStyleW(
*/
BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lpptPos);
@ -1939,13 +1963,21 @@ BOOL WINAPI ImmIsUIMessageW(
BOOL WINAPI ImmNotifyIME(
HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %d, %d, %d)\n",
hIMC, dwAction, dwIndex, dwValue);
if (!data || ! data->immKbd->pNotifyIME)
if (hIMC == NULL)
{
SetLastError(ERROR_SUCCESS);
return FALSE;
}
if (!data || ! data->immKbd->pNotifyIME)
{
return FALSE;
}
return data->immKbd->pNotifyIME(hIMC,dwAction,dwIndex,dwValue);
}
@ -2029,9 +2061,11 @@ BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
*/
LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
{
InputContextData *data = hIMC;
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);
@ -2044,10 +2078,13 @@ LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
*/
LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
{
InputContextData *data = hIMC;
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 SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
@ -2060,7 +2097,7 @@ LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
BOOL WINAPI ImmSetCandidateWindow(
HIMC hIMC, LPCANDIDATEFORM lpCandidate)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lpCandidate);
@ -2088,11 +2125,14 @@ BOOL WINAPI ImmSetCandidateWindow(
*/
BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lplf);
if (!data || !lplf)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
@ -2108,11 +2148,14 @@ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
*/
BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lplf);
if (!data || !lplf)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
data->IMC.lfFont.W = *lplf;
ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
@ -2134,7 +2177,7 @@ BOOL WINAPI ImmSetCompositionStringA(
WCHAR *CompBuffer = NULL;
WCHAR *ReadBuffer = NULL;
BOOL rc;
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %d, %p, %d, %p, %d):\n",
hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
@ -2189,7 +2232,7 @@ BOOL WINAPI ImmSetCompositionStringW(
CHAR *CompBuffer = NULL;
CHAR *ReadBuffer = NULL;
BOOL rc;
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %d, %p, %d, %p, %d):\n",
hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
@ -2242,7 +2285,7 @@ BOOL WINAPI ImmSetCompositionWindow(
HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
{
BOOL reshow = FALSE;
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lpCompForm);
TRACE("\t%x, (%i,%i), (%i,%i - %i,%i)\n",lpCompForm->dwStyle,
@ -2250,7 +2293,10 @@ BOOL WINAPI ImmSetCompositionWindow(
lpCompForm->rcArea.left, lpCompForm->rcArea.bottom, lpCompForm->rcArea.right);
if (!data)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
data->IMC.cfCompForm = *lpCompForm;
@ -2276,12 +2322,15 @@ BOOL WINAPI ImmSetConversionStatus(
HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
{
DWORD oldConversion, oldSentence;
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("%p %d %d\n", hIMC, fdwConversion, fdwSentence);
if (!data)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if ( fdwConversion != data->IMC.fdwConversion )
{
@ -2306,12 +2355,15 @@ BOOL WINAPI ImmSetConversionStatus(
*/
BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("%p %d\n", hIMC, fOpen);
if (!data)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (data->immKbd->UIWnd == NULL)
{
@ -2339,12 +2391,15 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
*/
BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
TRACE("(%p, %p)\n", hIMC, lpptPos);
if (!data || !lpptPos)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
TRACE("\t(%i,%i)\n", lpptPos->x, lpptPos->y);
@ -2462,9 +2517,16 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
DWORD dwSize)
{
InputContextData *data = hIMC;
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))
@ -2526,9 +2588,16 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
DWORD dwSize)
{
InputContextData *data = hIMC;
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))
@ -2586,7 +2655,7 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
*/
LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
if (!data)
return NULL;
@ -2599,7 +2668,10 @@ LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
*/
BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
if (!data)
return FALSE;
if (data->dwLock)
data->dwLock--;
return TRUE;
@ -2610,7 +2682,9 @@ BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
*/
DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
if (!data)
return 0;
return data->dwLock;
}
@ -2675,7 +2749,13 @@ DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
*/
BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
{
InputContextData *data = hIMC;
InputContextData *data = get_imc_data(hIMC);
if (!data)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf);
if (data->IMC.dwNumMsgBuf > 0)

View File

@ -276,6 +276,26 @@ static void test_ImmNotifyIME(void) {
msg_spy_flush_msgs();
ImmReleaseContext(hwnd, imc);
imc = ImmCreateContext();
ImmDestroyContext(imc);
SetLastError(0xdeadbeef);
ret = ImmNotifyIME((HIMC)0xdeadcafe, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
ok (ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmNotifyIME(0x00000000, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
ok (ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_SUCCESS, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
ok (ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
}
static void test_ImmGetCompositionString(void)
@ -694,6 +714,23 @@ static void test_ImmGetIMCLockCount(void)
DWORD count, ret, i;
INPUTCONTEXT *ic;
imc = ImmCreateContext();
ImmDestroyContext(imc);
SetLastError(0xdeadbeef);
count = ImmGetIMCLockCount((HIMC)0xdeadcafe);
ok(count == 0, "Invalid IMC should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
count = ImmGetIMCLockCount(0x00000000);
ok(count == 0, "NULL IMC should return 0\n");
ret = GetLastError();
ok(ret == 0xdeadbeef, "Last Error should remain unchangedi %08x\n",ret);
count = ImmGetIMCLockCount(imc);
ok(count == 0, "Destroyed IMC should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
imc = ImmCreateContext();
count = ImmGetIMCLockCount(imc);
ok(count == 0, "expect 0, returned %d\n", count);
@ -790,16 +827,16 @@ static void test_ImmDestroyContext(void)
ret = ImmDestroyContext(imc);
ok(ret == TRUE, "Destroy a locked IMC should success!\n");
ic = ImmLockIMC(imc);
todo_wine ok(ic == NULL, "Lock a destroyed IMC should fail!\n");
ok(ic == NULL, "Lock a destroyed IMC should fail!\n");
ret = ImmUnlockIMC(imc);
todo_wine ok(ret == FALSE, "Unlock a destroyed IMC should fail!\n");
ok(ret == FALSE, "Unlock a destroyed IMC should fail!\n");
count = ImmGetIMCLockCount(imc);
todo_wine ok(count == 0, "Get lock count of a destroyed IMC should return 0!\n");
ok(count == 0, "Get lock count of a destroyed IMC should return 0!\n");
SetLastError(0xdeadbeef);
ret = ImmDestroyContext(imc);
todo_wine ok(ret == FALSE, "Destroy a destroyed IMC should fail!\n");
ok(ret == FALSE, "Destroy a destroyed IMC should fail!\n");
ret = GetLastError();
todo_wine ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
}
static void test_ImmDestroyIMCC(void)
@ -980,6 +1017,363 @@ static void test_ime_processkey(void)
DestroyWindow(hWndTest);
}
static void test_InvalidIMC(void)
{
HIMC imc_destroy;
HIMC imc_null = 0x00000000;
HIMC imc_bad = (HIMC)0xdeadcafe;
HIMC imc1, imc2, oldimc;
DWORD ret;
DWORD count;
CHAR buffer[1000];
INPUTCONTEXT *ic;
LOGFONTA lf;
memset(&lf, 0, sizeof(lf));
imc_destroy = ImmCreateContext();
ret = ImmDestroyContext(imc_destroy);
ok(ret == TRUE, "Destroy an IMC should success!\n");
/* Test associating destroyed imc */
imc1 = ImmGetContext(hwnd);
SetLastError(0xdeadbeef);
oldimc = ImmAssociateContext(hwnd, imc_destroy);
ok(!oldimc, "Associating to a destroyed imc should fail!\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
imc2 = ImmGetContext(hwnd);
ok(imc1 == imc2, "imc should not changed! imc1 %p, imc2 %p\n", imc1, imc2);
/* Test associating NULL imc, which is different to invalid imc */
oldimc = ImmAssociateContext(hwnd, imc_null);
ok(oldimc != NULL, "Associating to NULL imc should success!\n");
imc2 = ImmGetContext(hwnd);
ok(!imc2, "expect NULL, returned %p\n", imc2);
oldimc = ImmAssociateContext(hwnd, imc1);
ok(!oldimc, "expect NULL, returned %p\n", oldimc);
imc2 = ImmGetContext(hwnd);
ok(imc2 == imc1, "imc should not changed! imc2 %p, imc1 %p\n", imc2, imc1);
/* Test associating invalid imc */
imc1 = ImmGetContext(hwnd);
SetLastError(0xdeadbeef);
oldimc = ImmAssociateContext(hwnd, imc_bad);
ok(!oldimc, "Associating to a destroyed imc should fail!\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
imc2 = ImmGetContext(hwnd);
ok(imc1 == imc2, "imc should not changed! imc1 %p, imc2 %p\n", imc1, imc2);
/* Test ImmGetCandidateListA */
SetLastError(0xdeadbeef);
ret = ImmGetCandidateListA(imc_bad, 0, NULL, 0);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetCandidateListA(imc_null, 0, NULL, 0);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetCandidateListA(imc_destroy, 0, NULL, 0);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmGetCandidateListCountA*/
SetLastError(0xdeadbeef);
ret = ImmGetCandidateListCountA(imc_bad,&count);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetCandidateListCountA(imc_null,&count);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetCandidateListCountA(imc_destroy,&count);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmGetCandidateWindow */
SetLastError(0xdeadbeef);
ret = ImmGetCandidateWindow(imc_bad, 0, (LPCANDIDATEFORM)buffer);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetCandidateWindow(imc_null, 0, (LPCANDIDATEFORM)buffer);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetCandidateWindow(imc_destroy, 0, (LPCANDIDATEFORM)buffer);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmGetCompositionFontA */
SetLastError(0xdeadbeef);
ret = ImmGetCompositionFontA(imc_bad, (LPLOGFONTA)buffer);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetCompositionFontA(imc_null, (LPLOGFONTA)buffer);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetCompositionFontA(imc_destroy, (LPLOGFONTA)buffer);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmGetCompositionWindow */
SetLastError(0xdeadbeef);
ret = ImmGetCompositionWindow(imc_bad, (LPCOMPOSITIONFORM)buffer);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetCompositionWindow(imc_null, (LPCOMPOSITIONFORM)buffer);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetCompositionWindow(imc_destroy, (LPCOMPOSITIONFORM)buffer);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmGetCompositionStringA */
SetLastError(0xdeadbeef);
ret = ImmGetCompositionStringA(imc_bad, GCS_COMPSTR, NULL, 0);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetCompositionStringA(imc_null, GCS_COMPSTR, NULL, 0);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetCompositionStringA(imc_destroy, GCS_COMPSTR, NULL, 0);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmSetOpenStatus */
SetLastError(0xdeadbeef);
ret = ImmSetOpenStatus(imc_bad, 1);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmSetOpenStatus(imc_null, 1);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmSetOpenStatus(imc_destroy, 1);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmGetOpenStatus */
SetLastError(0xdeadbeef);
ret = ImmGetOpenStatus(imc_bad);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetOpenStatus(imc_null);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetOpenStatus(imc_destroy);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmGetStatusWindowPos */
SetLastError(0xdeadbeef);
ret = ImmGetStatusWindowPos(imc_bad, NULL);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetStatusWindowPos(imc_null, NULL);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetStatusWindowPos(imc_destroy, NULL);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmRequestMessageA */
SetLastError(0xdeadbeef);
ret = ImmRequestMessageA(imc_bad, WM_CHAR, 0);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmRequestMessageA(imc_null, WM_CHAR, 0);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmRequestMessageA(imc_destroy, WM_CHAR, 0);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmSetCompositionFontA */
SetLastError(0xdeadbeef);
ret = ImmSetCompositionFontA(imc_bad, &lf);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmSetCompositionFontA(imc_null, &lf);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmSetCompositionFontA(imc_destroy, &lf);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmSetCompositionWindow */
SetLastError(0xdeadbeef);
ret = ImmSetCompositionWindow(imc_bad, NULL);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmSetCompositionWindow(imc_null, NULL);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmSetCompositionWindow(imc_destroy, NULL);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmSetConversionStatus */
SetLastError(0xdeadbeef);
ret = ImmSetConversionStatus(imc_bad, 0, 0);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmSetConversionStatus(imc_null, 0, 0);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmSetConversionStatus(imc_destroy, 0, 0);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmSetStatusWindowPos */
SetLastError(0xdeadbeef);
ret = ImmSetStatusWindowPos(imc_bad, 0);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmSetStatusWindowPos(imc_null, 0);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmSetStatusWindowPos(imc_destroy, 0);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmGetImeMenuItemsA */
SetLastError(0xdeadbeef);
ret = ImmGetImeMenuItemsA(imc_bad, 0, 0, NULL, NULL, 0);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetImeMenuItemsA(imc_null, 0, 0, NULL, NULL, 0);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGetImeMenuItemsA(imc_destroy, 0, 0, NULL, NULL, 0);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmLockIMC */
SetLastError(0xdeadbeef);
ic = ImmLockIMC(imc_bad);
ok(ic == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ic = ImmLockIMC(imc_null);
ok(ic == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
SetLastError(0xdeadbeef);
ic = ImmLockIMC(imc_destroy);
ok(ic == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmUnlockIMC */
SetLastError(0xdeadbeef);
ret = ImmUnlockIMC(imc_bad);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmUnlockIMC(imc_null);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == 0xdeadbeef, "last error should remain unchanged %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmUnlockIMC(imc_destroy);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
/* Test ImmGenerateMessage */
SetLastError(0xdeadbeef);
ret = ImmGenerateMessage(imc_bad);
ok(ret == 0, "Bad IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGenerateMessage(imc_null);
ok(ret == 0, "NULL IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
SetLastError(0xdeadbeef);
ret = ImmGenerateMessage(imc_destroy);
ok(ret == 0, "Destroyed IME should return 0\n");
ret = GetLastError();
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
}
START_TEST(imm32) {
if (init())
{
@ -997,6 +1391,7 @@ START_TEST(imm32) {
test_ImmGetIMCCLockCount();
test_ImmDestroyContext();
test_ImmDestroyIMCC();
test_InvalidIMC();
msg_spy_cleanup();
/* Reinitialize the hooks to capture all windows */
msg_spy_init(NULL);