mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[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:
parent
4e9c898363
commit
264a128f03
5 changed files with 378 additions and 32 deletions
|
@ -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.@)
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in a new issue