https://git.reactos.org/?p=reactos.git;a=commitdiff;h=264a128f03f97d10653cf…
commit 264a128f03f97d10653cf74ac81bed9336fbddaa
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sat Oct 9 07:40:56 2021 +0900
Commit: GitHub <noreply(a)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))