[IMM32] Rewrite ImmRequestMessageA/W (#4002)

- Re-implement ImmRequestMessageA and ImmRequestMessageW functions.
- Add IchWideFromAnsi, IchAnsiFromWide, Imm32RequestError, Imm32ReconvertSize, Imm32ConvertReconvert, and Imm32ProcessRequest helper functions.
CORE-11700
This commit is contained in:
Katayama Hirofumi MZ 2021-10-09 07:40:56 +09:00 committed by GitHub
parent 4e9c898363
commit 264a128f03
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 378 additions and 32 deletions

View file

@ -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.@)
*/

View file

@ -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

View file

@ -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);
}

View file

@ -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);

View file

@ -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))