https://git.reactos.org/?p=reactos.git;a=commitdiff;h=264a128f03f97d10653cf7...
commit 264a128f03f97d10653cf74ac81bed9336fbddaa Author: Katayama Hirofumi MZ katayama.hirofumi.mz@gmail.com AuthorDate: Sat Oct 9 07:40:56 2021 +0900 Commit: GitHub noreply@github.com CommitDate: Sat Oct 9 07:40:56 2021 +0900
[IMM32] Rewrite ImmRequestMessageA/W (#4002)
- Re-implement ImmRequestMessageA and ImmRequestMessageW functions. - Add IchWideFromAnsi, IchAnsiFromWide, Imm32RequestError, Imm32ReconvertSize, Imm32ConvertReconvert, and Imm32ProcessRequest helper functions. CORE-11700 --- dll/win32/imm32/imm.c | 30 ---- dll/win32/imm32/imm32.spec | 4 +- dll/win32/imm32/keymsg.c | 335 +++++++++++++++++++++++++++++++++++++++++++++ dll/win32/imm32/precomp.h | 2 + dll/win32/imm32/utils.c | 39 ++++++ 5 files changed, 378 insertions(+), 32 deletions(-)
diff --git a/dll/win32/imm32/imm.c b/dll/win32/imm32/imm.c index db537ad9bf0..69cd4281a55 100644 --- a/dll/win32/imm32/imm.c +++ b/dll/win32/imm32/imm.c @@ -1483,36 +1483,6 @@ BOOL WINAPI ImmUnlockIMC(HIMC hIMC) return TRUE; }
-/*********************************************************************** - * ImmRequestMessageA(IMM32.@) - */ -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) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); - - SetLastError(ERROR_INVALID_HANDLE); - return 0; -} - -/*********************************************************************** - * ImmRequestMessageW(IMM32.@) - */ -LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam) -{ - InputContextData *data = get_imc_data(hIMC); - - TRACE("%p %ld %ld\n", hIMC, wParam, wParam); - - if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); - - SetLastError(ERROR_INVALID_HANDLE); - return 0; -} - /*********************************************************************** * ImmReleaseContext (IMM32.@) */ diff --git a/dll/win32/imm32/imm32.spec b/dll/win32/imm32/imm32.spec index 09ca424fdc0..02217013950 100644 --- a/dll/win32/imm32/imm32.spec +++ b/dll/win32/imm32/imm32.spec @@ -87,8 +87,8 @@ @ stdcall ImmRegisterWordA(long str long str) @ stdcall ImmRegisterWordW(long wstr long wstr) @ stdcall ImmReleaseContext(ptr ptr) -@ stdcall ImmRequestMessageA(ptr long long) -@ stdcall ImmRequestMessageW(ptr long long) +@ stdcall ImmRequestMessageA(ptr ptr ptr) +@ stdcall ImmRequestMessageW(ptr ptr ptr) @ stdcall ImmSendIMEMessageExA(ptr ptr) @ stdcall ImmSendIMEMessageExW(ptr ptr) @ stub ImmSendMessageToActiveDefImeWndW diff --git a/dll/win32/imm32/keymsg.c b/dll/win32/imm32/keymsg.c index c8dc8670158..168382559e4 100644 --- a/dll/win32/imm32/keymsg.c +++ b/dll/win32/imm32/keymsg.c @@ -349,6 +349,323 @@ BOOL APIENTRY Imm32SendChange(BOOL bProcess) return ImmEnumInputContext((bProcess ? -1 : 0), Imm32SendChangeProc, 0); }
+VOID APIENTRY Imm32RequestError(DWORD dwError) +{ + FIXME("()\n"); + SetLastError(dwError); +} + +DWORD APIENTRY Imm32ReconvertSize(DWORD dwSize, BOOL bAnsi, BOOL bConvert) +{ + DWORD dwOffset; + if (dwSize < sizeof(RECONVERTSTRING)) + return 0; + if (!bConvert) + return dwSize; + dwOffset = dwSize - sizeof(RECONVERTSTRING); + if (bAnsi) + dwOffset /= sizeof(WCHAR); + else + dwOffset *= sizeof(WCHAR); + return sizeof(RECONVERTSTRING) + dwOffset; +} + +DWORD APIENTRY +Imm32ConvertReconvert(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc, BOOL bAnsi, + UINT uCodePage) +{ + DWORD ret = sizeof(RECONVERTSTRING), cch0, cch1, cchDest; + + if ((pSrc->dwVersion != 0) || (pDest->dwVersion != 0)) + return 0; + + pDest->dwStrOffset = sizeof(RECONVERTSTRING); + + /* + * See RECONVERTSTRING structure: + * https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/RECONVERTSTRING.html + * + * The dwCompStrOffset and dwTargetOffset members are the relative position of dwStrOffset. + * dwStrLen, dwCompStrLen, and dwTargetStrLen are the TCHAR count. dwStrOffset, + * dwCompStrOffset, and dwTargetStrOffset are the byte offset. + */ + if (bAnsi) /* Ansi <-- Wide */ + { + LPCWSTR pchSrc = (LPCWSTR)((LPCSTR)pSrc + pSrc->dwStrOffset); + LPSTR pchDest = (LPSTR)pDest + pDest->dwStrOffset; + + cchDest = WideCharToMultiByte(uCodePage, 0, pchSrc, pSrc->dwStrLen, + pchDest, pSrc->dwStrLen, NULL, NULL); + + /* dwCompStrOffset */ + cch1 = pSrc->dwCompStrOffset / sizeof(WCHAR); + cch0 = IchAnsiFromWide(cch1, pchSrc, uCodePage); + pDest->dwCompStrOffset = cch0 * sizeof(CHAR); + + /* dwCompStrLen */ + cch0 = IchAnsiFromWide(cch1 + pSrc->dwCompStrLen, pchSrc, uCodePage); + pDest->dwCompStrLen = cch0 * sizeof(CHAR) - pDest->dwCompStrOffset; + + /* dwTargetStrOffset */ + cch1 = pSrc->dwTargetStrOffset / sizeof(WCHAR); + cch0 = IchAnsiFromWide(cch1, pchSrc, uCodePage); + pDest->dwTargetStrOffset = cch0 * sizeof(CHAR); + + /* dwTargetStrLen */ + cch0 = IchAnsiFromWide(cch1 + pSrc->dwTargetStrLen, pchSrc, uCodePage); + pDest->dwTargetStrLen = cch0 * sizeof(CHAR) - pDest->dwTargetStrOffset; + + /* dwStrLen */ + pDest->dwStrLen = cchDest; + pchDest[cchDest] = 0; + + ret += (cchDest + 1) * sizeof(CHAR); + } + else /* Wide <-- Ansi */ + { + LPCSTR pchSrc = (LPCSTR)pSrc + pSrc->dwStrOffset; + LPWSTR pchDest = (LPWSTR)((LPBYTE)pDest + pDest->dwStrOffset); + + cchDest = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pchSrc, pSrc->dwStrLen, + pchDest, pSrc->dwStrLen); + + /* dwCompStrOffset */ + cch0 = IchWideFromAnsi(pSrc->dwCompStrOffset, pchSrc, uCodePage); + pDest->dwCompStrOffset = cch0 * sizeof(WCHAR); + + /* dwCompStrLen */ + cch0 = IchWideFromAnsi(pSrc->dwCompStrOffset + pSrc->dwCompStrLen, pchSrc, uCodePage); + pDest->dwCompStrLen = (cch0 * sizeof(WCHAR) - pDest->dwCompStrOffset) / sizeof(WCHAR); + + /* dwTargetStrOffset */ + cch0 = IchWideFromAnsi(pSrc->dwTargetStrOffset, pchSrc, uCodePage); + pDest->dwTargetStrOffset = cch0 * sizeof(WCHAR); + + /* dwTargetStrLen */ + cch0 = IchWideFromAnsi(pSrc->dwTargetStrOffset + pSrc->dwTargetStrLen, pchSrc, uCodePage); + pDest->dwTargetStrLen = (cch0 * sizeof(WCHAR) - pSrc->dwTargetStrOffset) / sizeof(WCHAR); + + /* dwStrLen */ + pDest->dwStrLen = cchDest; + pchDest[cchDest] = 0; + + ret += (cchDest + 1) * sizeof(WCHAR); + } + + return ret; +} + +LRESULT APIENTRY +Imm32ProcessRequest(HIMC hIMC, PWND pWnd, DWORD dwCommand, LPVOID pData, BOOL bAnsiAPI) +{ + HWND hWnd; + DWORD ret = 0, dwCharPos, cchCompStr; + LPVOID pCS, pTempData = pData; + LPRECONVERTSTRING pRS; + LPIMECHARPOSITION pICP; + PCLIENTIMC pClientImc; + UINT uCodePage = CP_ACP; + BOOL bAnsiWnd = !!(pWnd->state & WNDS_ANSIWINDOWPROC); + static const size_t acbData[7 * 2] = + { + /* UNICODE */ + sizeof(COMPOSITIONFORM), sizeof(CANDIDATEFORM), sizeof(LOGFONTW), + sizeof(RECONVERTSTRING), sizeof(RECONVERTSTRING), + sizeof(IMECHARPOSITION), sizeof(RECONVERTSTRING), + /* ANSI */ + sizeof(COMPOSITIONFORM), sizeof(CANDIDATEFORM), sizeof(LOGFONTA), + sizeof(RECONVERTSTRING), sizeof(RECONVERTSTRING), + sizeof(IMECHARPOSITION), sizeof(RECONVERTSTRING), + }; + + if (dwCommand == 0 || dwCommand > IMR_DOCUMENTFEED) + return 0; /* Out of range */ + + if (pData && IsBadWritePtr(pData, acbData[bAnsiAPI * 7 + dwCommand - 1])) + return 0; /* Invalid pointer */ + + /* Sanity check */ + switch (dwCommand) + { + case IMR_RECONVERTSTRING: case IMR_DOCUMENTFEED: + pRS = pData; + if (pRS && (pRS->dwVersion != 0 || pRS->dwSize < sizeof(RECONVERTSTRING))) + { + Imm32RequestError(ERROR_INVALID_PARAMETER); + return 0; + } + break; + + case IMR_CONFIRMRECONVERTSTRING: + pRS = pData; + if (!pRS || pRS->dwVersion != 0) + { + Imm32RequestError(ERROR_INVALID_PARAMETER); + return 0; + } + break; + + default: + if (!pData) + { + Imm32RequestError(ERROR_INVALID_PARAMETER); + return 0; + } + break; + } + + pClientImc = ImmLockClientImc(hIMC); + if (pClientImc) + { + uCodePage = pClientImc->uCodePage; + ImmUnlockClientImc(pClientImc); + } + + /* Prepare */ + switch (dwCommand) + { + case IMR_COMPOSITIONFONT: + if (bAnsiAPI == bAnsiWnd) + goto DoIt; + if (bAnsiWnd) + pTempData = Imm32HeapAlloc(0, sizeof(LOGFONTA)); + else + pTempData = Imm32HeapAlloc(0, sizeof(LOGFONTW)); + if (!pTempData) + return 0; + break; + + case IMR_RECONVERTSTRING: case IMR_CONFIRMRECONVERTSTRING: case IMR_DOCUMENTFEED: + if (bAnsiAPI == bAnsiWnd || !pData) + goto DoIt; + + pRS = pData; + ret = Imm32ReconvertSize(pRS->dwSize, FALSE, bAnsiWnd); + pTempData = Imm32HeapAlloc(0, ret + sizeof(WCHAR)); + if (!pTempData) + return 0; + + pRS = pTempData; + pRS->dwSize = ret; + pRS->dwVersion = 0; + + if (dwCommand == IMR_CONFIRMRECONVERTSTRING) + Imm32ConvertReconvert(pData, pTempData, bAnsiWnd, uCodePage); + break; + + case IMR_QUERYCHARPOSITION: + if (bAnsiAPI == bAnsiWnd) + goto DoIt; + + pICP = pData; + dwCharPos = pICP->dwCharPos; + + if (bAnsiAPI) + { + cchCompStr = ImmGetCompositionStringA(hIMC, GCS_COMPSTR, NULL, 0); + if (!cchCompStr) + return 0; + + pCS = Imm32HeapAlloc(0, (cchCompStr + 1) * sizeof(CHAR)); + if (!pCS) + return 0; + + ImmGetCompositionStringA(hIMC, GCS_COMPSTR, pCS, cchCompStr); + pICP->dwCharPos = IchWideFromAnsi(pICP->dwCharPos, pCS, uCodePage); + } + else + { + cchCompStr = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0); + if (!cchCompStr) + return 0; + + pCS = Imm32HeapAlloc(0, (cchCompStr + 1) * sizeof(WCHAR)); + if (!pCS) + return 0; + + ImmGetCompositionStringW(hIMC, GCS_COMPSTR, pCS, cchCompStr); + pICP->dwCharPos = IchAnsiFromWide(pICP->dwCharPos, pCS, uCodePage); + } + + Imm32HeapFree(pCS); + break; + + default: + break; + } + +DoIt: + /* The main task */ + hWnd = pWnd->head.h; + if (bAnsiWnd) + ret = SendMessageA(hWnd, WM_IME_REQUEST, dwCommand, (LPARAM)pTempData); + else + ret = SendMessageW(hWnd, WM_IME_REQUEST, dwCommand, (LPARAM)pTempData); + + if (bAnsiAPI == bAnsiWnd) + goto Quit; + + /* Get back to caller */ + switch (dwCommand) + { + case IMR_COMPOSITIONFONT: + if (bAnsiAPI) + LogFontWideToAnsi(pTempData, pData); + else + LogFontAnsiToWide(pTempData, pData); + break; + + case IMR_RECONVERTSTRING: case IMR_DOCUMENTFEED: + if (!ret) + goto Quit; + + ret = Imm32ReconvertSize(ret, TRUE, bAnsiWnd); + if (ret < sizeof(RECONVERTSTRING) || + (pTempData && !Imm32ConvertReconvert(pData, pTempData, bAnsiAPI, uCodePage))) + { + ret = 0; + } + break; + + case IMR_QUERYCHARPOSITION: + pICP->dwCharPos = dwCharPos; + break; + + default: + break; + } + +Quit: + if (pTempData != pData) + Imm32HeapFree(pTempData); + return ret; +} + +LRESULT APIENTRY Imm32RequestMessageAW(HIMC hIMC, WPARAM wParam, LPARAM lParam, BOOL bAnsi) +{ + LRESULT ret = 0; + LPINPUTCONTEXT pIC; + HWND hWnd; + PWND pWnd = NULL; + + if (!hIMC || Imm32IsCrossThreadAccess(hIMC)) + return FALSE; + + pIC = ImmLockIMC(hIMC); + if (!pIC) + return FALSE; + + hWnd = pIC->hWnd; + if (hWnd) + pWnd = ValidateHwndNoErr(hWnd); + + if (pWnd && pWnd->head.pti == NtCurrentTeb()->Win32ThreadInfo) + ret = Imm32ProcessRequest(hIMC, pWnd, (DWORD)wParam, (LPVOID)lParam, bAnsi); + + ImmUnlockIMC(hIMC); + return ret; +} + /*********************************************************************** * ImmIsUIMessageA (IMM32.@) */ @@ -798,3 +1115,21 @@ Quit: return ret; #undef MSG_COUNT } + +/*********************************************************************** + * ImmRequestMessageA(IMM32.@) + */ +LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam) +{ + TRACE("(%p, %p, %p)\n", hIMC, wParam, lParam); + return Imm32RequestMessageAW(hIMC, wParam, lParam, TRUE); +} + +/*********************************************************************** + * ImmRequestMessageW(IMM32.@) + */ +LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam) +{ + TRACE("(%p, %p, %p)\n", hIMC, wParam, lParam); + return Imm32RequestMessageAW(hIMC, wParam, lParam, FALSE); +} diff --git a/dll/win32/imm32/precomp.h b/dll/win32/imm32/precomp.h index 4ca77e11fbf..17f46493c88 100644 --- a/dll/win32/imm32/precomp.h +++ b/dll/win32/imm32/precomp.h @@ -81,6 +81,8 @@ LPVOID APIENTRY Imm32HeapAlloc(DWORD dwFlags, DWORD dwBytes);
LPWSTR APIENTRY Imm32WideFromAnsi(LPCSTR pszA); LPSTR APIENTRY Imm32AnsiFromWide(LPCWSTR pszW); +DWORD APIENTRY IchWideFromAnsi(DWORD cchAnsi, LPCSTR pchAnsi, UINT uCodePage); +DWORD APIENTRY IchAnsiFromWide(DWORD cchWide, LPCWSTR pchWide, UINT uCodePage); PIMEDPI APIENTRY ImmLockOrLoadImeDpi(HKL hKL); LPINPUTCONTEXT APIENTRY Imm32LockIMCEx(HIMC hIMC, BOOL fSelect); BOOL APIENTRY Imm32ReleaseIME(HKL hKL); diff --git a/dll/win32/imm32/utils.c b/dll/win32/imm32/utils.c index 7024ec8f19f..20790f78110 100644 --- a/dll/win32/imm32/utils.c +++ b/dll/win32/imm32/utils.c @@ -50,6 +50,45 @@ LPSTR APIENTRY Imm32AnsiFromWide(LPCWSTR pszW) return pszA; }
+DWORD APIENTRY IchWideFromAnsi(DWORD cchAnsi, LPCSTR pchAnsi, UINT uCodePage) +{ + DWORD cchWide; + for (cchWide = 0; cchAnsi; ++cchWide) + { + if (IsDBCSLeadByteEx(uCodePage, *pchAnsi)) + { + if (cchAnsi <= 1) + { + ++cchWide; + break; + } + else + { + cchAnsi -= 2; + pchAnsi += 2; + } + } + else + { + --cchAnsi; + ++pchAnsi; + } + } + return cchWide; +} + +DWORD APIENTRY IchAnsiFromWide(DWORD cchWide, LPCWSTR pchWide, UINT uCodePage) +{ + DWORD cb, cchAnsi; + for (cchAnsi = 0; cchWide; ++cchAnsi, ++pchWide, --cchWide) + { + cb = WideCharToMultiByte(uCodePage, 0, pchWide, 1, NULL, 0, NULL, NULL); + if (cb > 1) + ++cchAnsi; + } + return cchAnsi; +} + BOOL Imm32GetSystemLibraryPath(LPWSTR pszPath, DWORD cchPath, LPCWSTR pszFileName) { if (!pszFileName[0] || !GetSystemDirectoryW(pszPath, cchPath))