You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3845 lines
120 KiB
3845 lines
120 KiB
/**************************************************************************\
|
|
* Module Name: ctxtinfo.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* Get/set routines of various Input context information for imm32.dll
|
|
*
|
|
* History:
|
|
* 26-Feb-1996 wkwok
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
// Helper function:
|
|
// Converts RECONVERTSTRING structure between ANSI and UNICODE.
|
|
extern DWORD ImmReconversionWorker(LPRECONVERTSTRING lpRecTo, LPRECONVERTSTRING lpRecFrom, BOOL bToAnsi, DWORD dwCodePage);
|
|
|
|
|
|
int UnicodeToMultiByteSize(DWORD dwCodePage, LPCWSTR pwstr)
|
|
{
|
|
char dummy[2], *lpszDummy = dummy;
|
|
return WCSToMBEx((WORD)dwCodePage, pwstr, 1, &lpszDummy, sizeof(WCHAR), FALSE);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetCompositionStringA
|
|
*
|
|
* Query composition string information specified by dwIndex.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
LONG WINAPI ImmGetCompositionStringA(
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
LPVOID lpBuf,
|
|
DWORD dwBufLen)
|
|
{
|
|
PCLIENTIMC pClientImc;
|
|
PINPUTCONTEXT pInputContext;
|
|
PCOMPOSITIONSTRING pCompStr;
|
|
BOOL fAnsi;
|
|
LONG lRet = 0;
|
|
DWORD dwCodePage;
|
|
|
|
if (dwBufLen != 0 && lpBuf == NULL) {
|
|
RIPMSG0(RIP_WARNING, "ImmGetCompositionStringW: NULL lpBuf.");
|
|
return lRet;
|
|
}
|
|
|
|
pClientImc = ImmLockClientImc(hImc);
|
|
if (pClientImc == NULL) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmGetCompositionStringA: Invalid hImc %lx.", hImc);
|
|
return lRet;
|
|
}
|
|
|
|
fAnsi = !TestICF(pClientImc, IMCF_UNICODE);
|
|
dwCodePage = CImcCodePage(pClientImc);
|
|
|
|
ImmUnlockClientImc(pClientImc);
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (pInputContext == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCompositionStringA: Lock hImc %lx failed.", hImc);
|
|
return lRet;
|
|
}
|
|
|
|
pCompStr = (PCOMPOSITIONSTRING)ImmLockIMCC(pInputContext->hCompStr);
|
|
if (pCompStr == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCompositionStringA: Lock hCompStr %x failed",
|
|
pInputContext->hCompStr);
|
|
ImmUnlockIMC(hImc);
|
|
return lRet;
|
|
}
|
|
|
|
#if !defined(CUAS_ENABLE)
|
|
lRet = InternalGetCompositionStringA(pCompStr, dwIndex,
|
|
lpBuf, dwBufLen, fAnsi, dwCodePage);
|
|
#else
|
|
lRet = InternalGetCompositionStringA(hImc, pCompStr, dwIndex,
|
|
lpBuf, dwBufLen, fAnsi, dwCodePage);
|
|
#endif
|
|
|
|
ImmUnlockIMCC(pInputContext->hCompStr);
|
|
ImmUnlockIMC(hImc);
|
|
|
|
return lRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetCompositionStringA
|
|
*
|
|
* Query composition string information specified by dwIndex.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
LONG WINAPI ImmGetCompositionStringW(
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
LPVOID lpBuf,
|
|
DWORD dwBufLen)
|
|
{
|
|
PCLIENTIMC pClientImc;
|
|
PINPUTCONTEXT pInputContext;
|
|
PCOMPOSITIONSTRING pCompStr;
|
|
BOOL fAnsi;
|
|
LONG lRet = 0;
|
|
DWORD dwCodePage;
|
|
|
|
if (dwBufLen != 0 && lpBuf == NULL) {
|
|
RIPMSG0(RIP_WARNING, "ImmGetCompositionStringW: NULL lpBuf.");
|
|
return lRet;
|
|
}
|
|
|
|
pClientImc = ImmLockClientImc(hImc);
|
|
if (pClientImc == NULL) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmGetCompositionStringW: Invalid hImc %lx.", hImc);
|
|
return lRet;
|
|
}
|
|
|
|
fAnsi = !TestICF(pClientImc, IMCF_UNICODE);
|
|
dwCodePage = CImcCodePage(pClientImc);
|
|
|
|
ImmUnlockClientImc(pClientImc);
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (pInputContext == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCompositionStringW: Lock hImc %lx failed.", hImc);
|
|
return lRet;
|
|
}
|
|
|
|
pCompStr = (PCOMPOSITIONSTRING)ImmLockIMCC(pInputContext->hCompStr);
|
|
if (pCompStr == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCompositionStringA: Lock hCompStr %x failed",
|
|
pInputContext->hCompStr);
|
|
ImmUnlockIMC(hImc);
|
|
return lRet;
|
|
}
|
|
|
|
#if !defined(CUAS_ENABLE)
|
|
lRet = InternalGetCompositionStringW(pCompStr, dwIndex,
|
|
lpBuf, dwBufLen, fAnsi, dwCodePage);
|
|
#else
|
|
lRet = InternalGetCompositionStringW(hImc, pCompStr, dwIndex,
|
|
lpBuf, dwBufLen, fAnsi, dwCodePage);
|
|
#endif
|
|
|
|
ImmUnlockIMCC(pInputContext->hCompStr);
|
|
ImmUnlockIMC(hImc);
|
|
|
|
return lRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmSetCompositionStringA
|
|
*
|
|
* Set composition string information specified by dwIndex.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI ImmSetCompositionStringA(
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
LPVOID lpComp,
|
|
DWORD dwCompLen,
|
|
LPVOID lpRead,
|
|
DWORD dwReadLen)
|
|
{
|
|
return ImmSetCompositionStringWorker(hImc, dwIndex, lpComp,
|
|
dwCompLen, lpRead, dwReadLen, TRUE);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmSetCompositionStringW
|
|
*
|
|
* Set composition string information specified by dwIndex.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI ImmSetCompositionStringW(
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
LPVOID lpComp,
|
|
DWORD dwCompLen,
|
|
LPVOID lpRead,
|
|
DWORD dwReadLen)
|
|
{
|
|
return ImmSetCompositionStringWorker(hImc, dwIndex, lpComp,
|
|
dwCompLen, lpRead, dwReadLen, FALSE);
|
|
}
|
|
|
|
|
|
LONG CompositionString(
|
|
HIMC hImc,
|
|
PINPUTCONTEXT *ppInputContext,
|
|
PCOMPOSITIONSTRING *ppCompStr,
|
|
BOOL fCheckSize)
|
|
{
|
|
PINPUTCONTEXT pInputContext;
|
|
PCOMPOSITIONSTRING pCompStr;
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (!pInputContext) {
|
|
RIPMSG1(RIP_WARNING, "CompositionString: Lock hImc %lx failed.", hImc);
|
|
return (LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
|
|
if (!pInputContext->hCompStr) {
|
|
ImmUnlockIMC(hImc);
|
|
return (LONG)IMM_ERROR_NODATA;
|
|
}
|
|
|
|
pCompStr = (PCOMPOSITIONSTRING)ImmLockIMCC(pInputContext->hCompStr);
|
|
if (!pCompStr) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"CompositionString: Lock hCompStr %lx failed.", pInputContext->hCompStr);
|
|
ImmUnlockIMC(hImc);
|
|
return (LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
|
|
if (fCheckSize && pCompStr->dwSize < sizeof(COMPOSITIONSTRING)) {
|
|
RIPMSG0(RIP_WARNING, "CompositionString: no composition string.");
|
|
ImmUnlockIMCC(pInputContext->hCompStr);
|
|
ImmUnlockIMC(hImc);
|
|
return (LONG)IMM_ERROR_NODATA;
|
|
}
|
|
|
|
*ppInputContext = pInputContext;
|
|
*ppCompStr = pCompStr;
|
|
|
|
return (1);
|
|
}
|
|
|
|
|
|
BOOL CheckAttribute(
|
|
LPBYTE lpComp, // the attr from apps
|
|
DWORD dwCompLen, // the attr length from apps
|
|
LPBYTE lpAttr, // the attr from IMC
|
|
DWORD dwAttrLen, // the attr length from IMC
|
|
LPDWORD lpClause, // the clause from IMC
|
|
DWORD dwClauseLen) // the clause length from IMC
|
|
{
|
|
DWORD dwCnt;
|
|
DWORD dwBound;
|
|
BYTE bAttr;
|
|
|
|
UNREFERENCED_PARAMETER(dwClauseLen);
|
|
|
|
if (!lpClause) {
|
|
RIPMSG0(RIP_WARNING, "CheckAttribute: no Clause. Pass it to IME.");
|
|
return (TRUE);
|
|
}
|
|
|
|
if (!lpAttr) {
|
|
RIPMSG0(RIP_WARNING, "CheckAttribute: no Attr. Not pass it to IME.");
|
|
return (FALSE);
|
|
}
|
|
|
|
if (dwCompLen != dwAttrLen) {
|
|
RIPMSG0(RIP_WARNING, "CheckAttribute: wrong length. Not pass it to IME.");
|
|
return (FALSE);
|
|
}
|
|
|
|
/*
|
|
* The attr. of chars of one clause have to be same.
|
|
*/
|
|
while (*lpClause < dwCompLen) {
|
|
dwBound = *(lpClause+1) - *lpClause;
|
|
bAttr = *lpComp++;
|
|
for (dwCnt = 1; dwCnt < dwBound; dwCnt++)
|
|
if (bAttr != *lpComp++) {
|
|
RIPMSG0(RIP_WARNING,
|
|
"CheckAttribute: mismatch clause att. Not Pass it to IME");
|
|
return (FALSE);
|
|
}
|
|
lpClause++;
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
BOOL CheckClause(
|
|
LPDWORD lpComp, // the clause from apps
|
|
DWORD dwCompLen, // the clause length from apps
|
|
LPDWORD lpClause, // the clause from IMC
|
|
DWORD dwClauseLen) // the clause length from IMC
|
|
{
|
|
UINT nCnt;
|
|
INT diff = 0;
|
|
|
|
if (!dwClauseLen || !dwCompLen) {
|
|
RIPMSG0(RIP_WARNING, "CheckClause: no Clause. Not Pass it to IME.");
|
|
return (FALSE);
|
|
}
|
|
|
|
if (*lpComp || *lpClause) {
|
|
RIPMSG0(RIP_WARNING, "CheckClause: lpClause[0] have to be ZERO.");
|
|
return (FALSE);
|
|
}
|
|
|
|
for (nCnt = 0; nCnt < (UINT)(dwClauseLen/4); nCnt++)
|
|
{
|
|
if (*lpComp++ != *lpClause++)
|
|
{
|
|
diff++;
|
|
if (dwCompLen > dwClauseLen)
|
|
lpClause--;
|
|
if (dwCompLen < dwClauseLen)
|
|
lpComp--;
|
|
}
|
|
if (diff > 1)
|
|
return (FALSE);
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
LPBYTE InternalSCS_SETSTR(
|
|
LPCVOID lpCompRead,
|
|
DWORD dwCompReadLen,
|
|
LPVOID *lplpNewCompRead,
|
|
DWORD *lpdwNewCompReadLen,
|
|
BOOL fAnsi,
|
|
DWORD dwCodePage)
|
|
{
|
|
LPBYTE lpBufRet;
|
|
DWORD dwBufSize;
|
|
LPSTR lpBufA;
|
|
LPWSTR lpBufW;
|
|
INT i;
|
|
BOOL bUDC;
|
|
|
|
if (lpCompRead == NULL || dwCompReadLen == 0)
|
|
return NULL;
|
|
|
|
dwBufSize = dwCompReadLen * sizeof(WCHAR) * 2;
|
|
|
|
lpBufRet = ImmLocalAlloc(0, dwBufSize);
|
|
if (lpBufRet == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalSCS_SETSTR: memory failure.");
|
|
return NULL;
|
|
}
|
|
|
|
lpBufW = (LPWSTR)lpBufRet;
|
|
lpBufA = (LPSTR)(lpBufW + dwCompReadLen);
|
|
|
|
if (fAnsi) {
|
|
|
|
RtlCopyMemory(lpBufA, lpCompRead, dwCompReadLen);
|
|
|
|
i = MultiByteToWideChar(dwCodePage,
|
|
(DWORD)MB_PRECOMPOSED,
|
|
(LPSTR)lpBufA, // src
|
|
(INT)dwCompReadLen,
|
|
(LPWSTR)lpBufW, // dest
|
|
(INT)dwCompReadLen);
|
|
|
|
*lplpNewCompRead = lpBufW;
|
|
*lpdwNewCompReadLen = (DWORD)(i * sizeof(WCHAR));
|
|
}
|
|
else {
|
|
|
|
RtlCopyMemory(lpBufW, lpCompRead, dwCompReadLen);
|
|
|
|
i = WideCharToMultiByte(dwCodePage,
|
|
(DWORD)0,
|
|
lpBufW, // src
|
|
(INT)dwCompReadLen/sizeof(WCHAR),
|
|
(LPSTR)lpBufA, // dest
|
|
(INT)dwCompReadLen,
|
|
(LPSTR)NULL,
|
|
(LPBOOL)&bUDC);
|
|
|
|
*lplpNewCompRead = lpBufA;
|
|
*lpdwNewCompReadLen = (DWORD)(i * sizeof(CHAR));
|
|
}
|
|
|
|
return lpBufRet;
|
|
}
|
|
|
|
|
|
LPBYTE InternalSCS_CHANGEATTR(
|
|
HIMC hImc,
|
|
LPCVOID lpCompRead,
|
|
DWORD dwCompReadLen,
|
|
DWORD dwIndex,
|
|
LPVOID *lplpNewCompRead,
|
|
DWORD *lpdwNewCompReadLen,
|
|
BOOL fAnsi,
|
|
DWORD dwCodePage)
|
|
{
|
|
LPBYTE lpBufRet;
|
|
LPBYTE lpAttr, lpAttrA, lpAttrW;
|
|
DWORD dwBufLenA, dwBufLenW;
|
|
LPSTR lpStrBufA, lpBufA;
|
|
LPWSTR lpStrBufW, lpBufW;
|
|
CHAR c;
|
|
WCHAR wc;
|
|
ULONG MultiByteSize;
|
|
|
|
if (lpCompRead == NULL || dwCompReadLen == 0)
|
|
return NULL;
|
|
|
|
if (fAnsi) {
|
|
|
|
dwBufLenA = ImmGetCompositionStringA(hImc, dwIndex, NULL, 0);
|
|
|
|
lpStrBufA = ImmLocalAlloc(0, dwBufLenA);
|
|
if (lpStrBufA == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalSCS_CHANGEATTR: memory failure.");
|
|
return NULL;
|
|
}
|
|
|
|
ImmGetCompositionStringA(hImc, dwIndex, lpStrBufA, dwBufLenA);
|
|
|
|
lpBufRet = ImmLocalAlloc(0, dwBufLenA);
|
|
if (lpBufRet == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalSCS_CHANGEATTR: memory failure.");
|
|
ImmLocalFree(lpStrBufA);
|
|
return NULL;
|
|
}
|
|
|
|
lpBufA = lpStrBufA;
|
|
lpAttrA = (LPBYTE)lpCompRead;
|
|
lpAttr = lpBufRet;
|
|
|
|
while (dwBufLenA != 0 && (c=*lpBufA++) != 0) {
|
|
if (IsDBCSLeadByteEx(dwCodePage, c)) {
|
|
if (dwBufLenA >= 2) {
|
|
*lpAttr++ = *lpAttrA++;
|
|
dwBufLenA--;
|
|
} else {
|
|
*lpAttr++ = *lpAttrA;
|
|
}
|
|
lpBufA++;
|
|
} else {
|
|
*lpAttr++ = *lpAttrA;
|
|
}
|
|
lpAttrA++;
|
|
dwBufLenA--;
|
|
}
|
|
|
|
ImmLocalFree(lpStrBufA);
|
|
}
|
|
else {
|
|
|
|
dwBufLenW = ImmGetCompositionStringW(hImc, dwIndex, NULL, 0);
|
|
|
|
lpStrBufW = ImmLocalAlloc(0, dwBufLenW);
|
|
if (lpStrBufW == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalSCS_CHANGEATTR: memory failure.");
|
|
return NULL;
|
|
}
|
|
|
|
ImmGetCompositionStringW(hImc, dwIndex, lpStrBufW, dwBufLenW);
|
|
|
|
lpBufRet = ImmLocalAlloc(0, dwBufLenW);
|
|
if (lpBufRet == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalSCS_CHANGEATTR: memory failure.");
|
|
ImmLocalFree(lpStrBufW);
|
|
return NULL;
|
|
}
|
|
|
|
lpBufW = lpStrBufW;
|
|
lpAttrW = (LPBYTE)lpCompRead;
|
|
lpAttr = lpBufRet;
|
|
|
|
while (dwBufLenW != 0 && (wc=*lpBufW++) != L'\0') {
|
|
MultiByteSize = UnicodeToMultiByteSize(dwCodePage, &wc);
|
|
if (MultiByteSize == 2) {
|
|
*lpAttr++ = *lpAttrW;
|
|
}
|
|
*lpAttr++ = *lpAttrW++;
|
|
dwBufLenW -= sizeof(WCHAR);
|
|
}
|
|
|
|
ImmLocalFree(lpStrBufW);
|
|
}
|
|
|
|
*lplpNewCompRead = lpBufRet;
|
|
*lpdwNewCompReadLen = (DWORD)(lpAttr - (PBYTE)lpBufRet);
|
|
|
|
return lpBufRet;
|
|
}
|
|
|
|
|
|
LPBYTE InternalSCS_CHANGECLAUSE(
|
|
HIMC hImc,
|
|
LPCVOID lpCompRead,
|
|
DWORD dwCompReadLen,
|
|
DWORD dwIndex,
|
|
LPDWORD *lplpNewCompRead,
|
|
DWORD *lpdwNewCompReadLen,
|
|
BOOL fAnsi,
|
|
DWORD dwCodePage)
|
|
{
|
|
LPDWORD lpdw, lpNewdw, lpBufRet;
|
|
DWORD dwBufLenA, dwBufLenW;
|
|
LPSTR lpStrBufA = NULL;
|
|
LPWSTR lpStrBufW = NULL;
|
|
INT i;
|
|
|
|
if (lpCompRead == NULL || dwCompReadLen == 0)
|
|
return NULL;
|
|
|
|
lpdw = (LPDWORD)lpCompRead;
|
|
|
|
lpBufRet = ImmLocalAlloc(0, dwCompReadLen);
|
|
if (lpBufRet == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalSCS_CHANGECLAUSE: memory failure.");
|
|
return NULL;
|
|
}
|
|
|
|
if (fAnsi) {
|
|
|
|
dwBufLenA = ImmGetCompositionStringA(hImc, dwIndex, NULL, 0);
|
|
|
|
lpStrBufA = ImmLocalAlloc(0, dwBufLenA);
|
|
if (lpStrBufA == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalSCS_CHANGECLAUSE: memory failure.");
|
|
ImmLocalFree(lpBufRet);
|
|
return NULL;
|
|
}
|
|
|
|
ImmGetCompositionStringA(hImc, dwIndex, lpStrBufA, dwBufLenA);
|
|
}
|
|
else {
|
|
|
|
dwBufLenW = ImmGetCompositionStringW(hImc, dwIndex, NULL, 0);
|
|
|
|
lpStrBufW = ImmLocalAlloc(0, dwBufLenW);
|
|
if (lpStrBufW == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalSCS_CHANGECLAUSE: memory failure.");
|
|
ImmLocalFree(lpBufRet);
|
|
return NULL;
|
|
}
|
|
|
|
ImmGetCompositionStringW(hImc, dwIndex, lpStrBufW, dwBufLenW);
|
|
}
|
|
|
|
*lplpNewCompRead = lpNewdw = lpBufRet;
|
|
*lpdwNewCompReadLen = dwCompReadLen;
|
|
|
|
for (i = 0; i < (INT)(dwCompReadLen / sizeof(DWORD)); i++) {
|
|
*lpNewdw++ = fAnsi ? CalcCharacterPositionAtoW(*lpdw++, lpStrBufA, dwCodePage)
|
|
: CalcCharacterPositionWtoA(*lpdw++, lpStrBufW, dwCodePage);
|
|
}
|
|
|
|
if (lpStrBufA) {
|
|
ImmLocalFree(lpStrBufA);
|
|
UserAssert(lpStrBufW == NULL);
|
|
} else {
|
|
UserAssert(lpStrBufW);
|
|
ImmLocalFree(lpStrBufW);
|
|
}
|
|
|
|
return (LPBYTE)lpBufRet;
|
|
}
|
|
|
|
|
|
LPBYTE InternalSCS_RECONVERTSTRING(
|
|
LPRECONVERTSTRING lpReconv,
|
|
DWORD dwReconvLen,
|
|
LPRECONVERTSTRING *lplpNewReconv,
|
|
DWORD *lpdwNewReconvLen,
|
|
BOOL fAnsi,
|
|
DWORD dwCodePage)
|
|
{
|
|
LPRECONVERTSTRING lpNewReconv;
|
|
DWORD dwBufSize;
|
|
|
|
if (lpReconv == NULL || dwReconvLen == 0)
|
|
return NULL;
|
|
|
|
if (fAnsi) {
|
|
// AtoW
|
|
dwBufSize = (lpReconv->dwSize - sizeof *lpReconv + 1) * sizeof(WCHAR) + sizeof *lpReconv;
|
|
}
|
|
else {
|
|
dwBufSize = lpReconv->dwSize + sizeof(BYTE);
|
|
}
|
|
lpNewReconv = ImmLocalAlloc(0, dwBufSize);
|
|
if (lpNewReconv == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalSCS_RECONVERTSTRING: memory failure.");
|
|
return NULL;
|
|
}
|
|
|
|
lpNewReconv->dwVersion = 0;
|
|
lpNewReconv->dwSize= dwBufSize;
|
|
|
|
lpNewReconv->dwSize = ImmReconversionWorker(lpNewReconv, lpReconv, !fAnsi, dwCodePage);
|
|
if (lpNewReconv->dwSize == 0) {
|
|
ImmLocalFree(lpNewReconv);
|
|
return NULL;;
|
|
}
|
|
*lpdwNewReconvLen = lpNewReconv->dwSize;
|
|
*lplpNewReconv = lpNewReconv;
|
|
|
|
return (LPBYTE)lpNewReconv;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmSetCompositionStringWorker
|
|
*
|
|
* Worker function of ImmSetCompositionStringA/ImmSetCompositionStringW
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL ImmSetCompositionStringWorker(
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
LPVOID lpComp,
|
|
DWORD dwCompLen,
|
|
LPVOID lpRead,
|
|
DWORD dwReadLen,
|
|
BOOL fAnsi)
|
|
{
|
|
PINPUTCONTEXT pInputContext;
|
|
PCOMPOSITIONSTRING pCompStr;
|
|
DWORD dwThreadId;
|
|
PIMEDPI pImeDpi;
|
|
LPBYTE lpCompBuf, lpReadBuf;
|
|
LPBYTE lpNewComp = NULL, lpNewRead = NULL;
|
|
DWORD dwNewCompLen, dwNewReadLen;
|
|
BOOL fRet = FALSE;
|
|
BOOL fCheckSize = TRUE;
|
|
BOOL fNeedAWConversion;
|
|
LPBYTE lpOrgComp, lpOrgRead;
|
|
DWORD dwOrgCompLen, dwOrgReadLen;
|
|
|
|
dwThreadId = GetInputContextThread(hImc);
|
|
if (dwThreadId != GetCurrentThreadId()) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmSetCompositionString: Invalid input context access %lx.", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
pImeDpi = ImmLockImeDpi(GetKeyboardLayout(dwThreadId));
|
|
if (pImeDpi == NULL)
|
|
return FALSE;
|
|
|
|
lpCompBuf = lpReadBuf = NULL;
|
|
|
|
// Backup original pointers to copyback for QUERY.
|
|
lpOrgComp = lpComp;
|
|
lpOrgRead = lpRead;
|
|
dwOrgCompLen = dwCompLen;
|
|
dwOrgReadLen = dwReadLen;
|
|
|
|
/*
|
|
* Check if we need ANSI/Unicode conversion
|
|
*/
|
|
if (( fAnsi && !(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) ||
|
|
(!fAnsi && (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE))) {
|
|
/*
|
|
* No A/W conversion needed.
|
|
*/
|
|
fNeedAWConversion = FALSE;
|
|
goto start_scs;
|
|
}
|
|
fNeedAWConversion = TRUE;
|
|
|
|
switch (dwIndex) {
|
|
case SCS_SETSTR:
|
|
if ( lpComp &&
|
|
(lpCompBuf = InternalSCS_SETSTR(lpComp, dwCompLen,
|
|
&lpNewComp, &dwNewCompLen, fAnsi, IMECodePage(pImeDpi))) == NULL)
|
|
goto callime_scs;
|
|
if ( lpRead &&
|
|
(lpReadBuf = InternalSCS_SETSTR(lpRead, dwReadLen,
|
|
&lpNewRead, &dwNewReadLen, fAnsi, IMECodePage(pImeDpi))) == NULL)
|
|
goto callime_scs;
|
|
|
|
fCheckSize = FALSE;
|
|
break;
|
|
|
|
case SCS_CHANGEATTR:
|
|
if ( lpComp &&
|
|
(lpCompBuf = InternalSCS_CHANGEATTR(
|
|
hImc, lpComp, dwCompLen, GCS_COMPSTR,
|
|
&lpNewComp, &dwNewCompLen, fAnsi, IMECodePage(pImeDpi))) == NULL)
|
|
goto callime_scs;
|
|
if ( lpRead &&
|
|
(lpReadBuf = InternalSCS_CHANGEATTR(
|
|
hImc, lpRead, dwReadLen, GCS_COMPREADSTR,
|
|
&lpNewRead, &dwNewReadLen, fAnsi, IMECodePage(pImeDpi))) == NULL)
|
|
goto callime_scs;
|
|
break;
|
|
|
|
case SCS_CHANGECLAUSE:
|
|
if ( lpComp &&
|
|
(lpCompBuf = InternalSCS_CHANGECLAUSE(
|
|
hImc, lpComp, dwCompLen, GCS_COMPSTR,
|
|
(LPDWORD *)&lpNewComp, &dwNewCompLen, fAnsi, IMECodePage(pImeDpi))) == NULL)
|
|
goto callime_scs;
|
|
if ( lpRead &&
|
|
(lpReadBuf = InternalSCS_CHANGECLAUSE(
|
|
hImc, lpRead, dwReadLen, GCS_COMPREADSTR,
|
|
(LPDWORD *)&lpNewRead, &dwNewReadLen, fAnsi, IMECodePage(pImeDpi))) == NULL)
|
|
goto callime_scs;
|
|
break;
|
|
|
|
case SCS_SETRECONVERTSTRING:
|
|
case SCS_QUERYRECONVERTSTRING:
|
|
if (lpComp &&
|
|
(lpCompBuf = InternalSCS_RECONVERTSTRING((LPRECONVERTSTRING)lpComp, dwCompLen,
|
|
(LPRECONVERTSTRING *)&lpNewComp, &dwNewCompLen,
|
|
fAnsi, IMECodePage(pImeDpi))) == NULL)
|
|
goto callime_scs;
|
|
if (lpRead &&
|
|
(lpReadBuf = InternalSCS_RECONVERTSTRING((LPRECONVERTSTRING)lpRead, dwReadLen,
|
|
(LPRECONVERTSTRING *)&lpNewRead, &dwNewReadLen,
|
|
fAnsi, IMECodePage(pImeDpi))) == NULL)
|
|
goto callime_scs;
|
|
|
|
fCheckSize = FALSE;
|
|
break;
|
|
|
|
default:
|
|
goto callime_scs;
|
|
}
|
|
|
|
if (lpCompBuf != NULL) {
|
|
lpComp = lpNewComp;
|
|
dwCompLen = dwNewCompLen;
|
|
}
|
|
|
|
if (lpReadBuf != NULL) {
|
|
lpRead = lpNewRead;
|
|
dwReadLen = dwNewReadLen;
|
|
}
|
|
|
|
start_scs:
|
|
|
|
if (CompositionString(hImc, &pInputContext, &pCompStr, fCheckSize) <= 0)
|
|
goto callime_scs;
|
|
|
|
switch (dwIndex)
|
|
{
|
|
case SCS_SETSTR:
|
|
fRet = TRUE;
|
|
break;
|
|
|
|
case SCS_CHANGEATTR:
|
|
if ( lpComp &&
|
|
!CheckAttribute((LPBYTE)lpComp, dwCompLen,
|
|
(LPBYTE)((LPBYTE)pCompStr + pCompStr->dwCompAttrOffset),
|
|
pCompStr->dwCompAttrLen,
|
|
(LPDWORD)((LPBYTE)pCompStr + pCompStr->dwCompClauseOffset),
|
|
pCompStr->dwCompClauseLen)) break;
|
|
|
|
if ( lpRead &&
|
|
!CheckAttribute((LPBYTE)lpRead, dwReadLen,
|
|
(LPBYTE)((LPBYTE)pCompStr + pCompStr->dwCompReadAttrOffset),
|
|
pCompStr->dwCompReadAttrLen,
|
|
(LPDWORD)((LPBYTE)pCompStr + pCompStr->dwCompReadClauseOffset),
|
|
pCompStr->dwCompReadClauseLen)) break;
|
|
fRet = TRUE;
|
|
break;
|
|
|
|
case SCS_CHANGECLAUSE:
|
|
if ( lpComp &&
|
|
!CheckClause((LPDWORD)lpComp, dwCompLen,
|
|
(LPDWORD)((LPBYTE)pCompStr + pCompStr->dwCompClauseOffset),
|
|
pCompStr->dwCompClauseLen)) break;
|
|
if ( lpRead &&
|
|
!CheckClause((LPDWORD)lpRead, dwReadLen,
|
|
(LPDWORD)((LPBYTE)pCompStr + pCompStr->dwCompReadClauseOffset),
|
|
pCompStr->dwCompReadClauseLen)) break;
|
|
fRet = TRUE;
|
|
break;
|
|
|
|
case SCS_SETRECONVERTSTRING:
|
|
case SCS_QUERYRECONVERTSTRING:
|
|
if (pImeDpi->ImeInfo.fdwSCSCaps & SCS_CAP_SETRECONVERTSTRING) {
|
|
fRet = TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ImmUnlockIMCC(pInputContext->hCompStr);
|
|
ImmUnlockIMC(hImc);
|
|
|
|
callime_scs:
|
|
|
|
if (fRet) {
|
|
fRet = (*pImeDpi->pfn.ImeSetCompositionString)(hImc, dwIndex,
|
|
lpComp, dwCompLen, lpRead, dwReadLen);
|
|
}
|
|
|
|
/*
|
|
* Check if we need ANSI/Unicode back conversion
|
|
*/
|
|
if (fNeedAWConversion) {
|
|
LPBYTE lpCompBufBack = NULL, lpReadBufBack = NULL;
|
|
/*
|
|
* A/W back conversion needed.
|
|
*/
|
|
switch (dwIndex) {
|
|
case SCS_QUERYRECONVERTSTRING:
|
|
if (lpOrgComp &&
|
|
(lpCompBufBack = InternalSCS_RECONVERTSTRING((LPRECONVERTSTRING)lpComp, dwCompLen,
|
|
(LPRECONVERTSTRING *)&lpNewComp, &dwNewCompLen,
|
|
!fAnsi, IMECodePage(pImeDpi)))) {
|
|
if (dwOrgCompLen < dwNewCompLen) {
|
|
// lpOrgComp buffer length is too small.
|
|
fRet = FALSE;
|
|
}
|
|
else {
|
|
RtlCopyMemory(lpOrgComp, lpNewComp, dwNewCompLen);
|
|
}
|
|
}
|
|
if (lpOrgRead &&
|
|
(lpReadBufBack = InternalSCS_RECONVERTSTRING(
|
|
(LPRECONVERTSTRING)lpRead, dwReadLen,
|
|
(LPRECONVERTSTRING *)&lpNewRead, &dwNewReadLen,
|
|
!fAnsi, IMECodePage(pImeDpi)))) {
|
|
if (dwOrgReadLen < dwNewReadLen) {
|
|
// lpOrgRead buffer length is too small.
|
|
fRet = FALSE;
|
|
}
|
|
else {
|
|
RtlCopyMemory(lpOrgRead, lpNewRead, dwNewReadLen);
|
|
}
|
|
}
|
|
}
|
|
if (lpCompBufBack != NULL)
|
|
LocalFree(lpCompBufBack);
|
|
if (lpReadBufBack != NULL)
|
|
LocalFree(lpReadBufBack);
|
|
}
|
|
|
|
if (lpCompBuf != NULL)
|
|
ImmLocalFree(lpCompBuf);
|
|
if (lpReadBuf != NULL)
|
|
ImmLocalFree(lpReadBuf);
|
|
|
|
ImmUnlockImeDpi(pImeDpi);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetCandidateListCountA
|
|
*
|
|
* Query the byte count and list count to receive all candidate list.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD WINAPI ImmGetCandidateListCountA(
|
|
HIMC hImc,
|
|
LPDWORD lpdwListCount) // the buffer pointer for list count
|
|
{
|
|
return ImmGetCandidateListCountWorker(hImc, lpdwListCount, TRUE);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetCandidateListCountW
|
|
*
|
|
* Query the byte count and list count to receive all candidate list.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD WINAPI ImmGetCandidateListCountW(
|
|
HIMC hImc,
|
|
LPDWORD lpdwListCount) // the buffer pointer for list count
|
|
{
|
|
return ImmGetCandidateListCountWorker(hImc, lpdwListCount, FALSE);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetCandidateListCountWorker
|
|
*
|
|
* Worker function of ImmGetCandidateListCountA/ImmGetCandidateListCountW.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD ImmGetCandidateListCountWorker(
|
|
HIMC hImc,
|
|
LPDWORD lpdwListCount,
|
|
BOOL fAnsi)
|
|
{
|
|
PCLIENTIMC pClientImc;
|
|
PINPUTCONTEXT pInputContext;
|
|
LPCANDIDATEINFO lpCandInfo;
|
|
DWORD dwRet = 0;
|
|
INT i;
|
|
DWORD dwCodePage;
|
|
|
|
if (lpdwListCount) {
|
|
*lpdwListCount = 0;
|
|
} else {
|
|
RIPMSG0(RIP_WARNING, "ImmGetCandidateListCount: NULL lpdwListCount.");
|
|
return dwRet;
|
|
}
|
|
|
|
pClientImc = ImmLockClientImc(hImc);
|
|
if (pClientImc == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCandidateListCount: Invalid hImc %lx.", hImc);
|
|
goto GetCandListCntExit;
|
|
}
|
|
dwCodePage = CImcCodePage(pClientImc);
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (pInputContext == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCandidateListCount: Lock hImc %lx failed.", hImc);
|
|
goto GetCandListCntUnlockClientImc;
|
|
}
|
|
|
|
lpCandInfo = (LPCANDIDATEINFO)ImmLockIMCC(pInputContext->hCandInfo);
|
|
if (!lpCandInfo) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmGetCandidateListCount: Lock hCandInfo %x failed.",
|
|
pInputContext->hCandInfo);
|
|
goto GetCandListCntUnlockIMC;
|
|
}
|
|
|
|
if (lpCandInfo->dwSize < sizeof(CANDIDATEINFO)) {
|
|
RIPMSG0(RIP_WARNING, "ImmGetCandidateListCount: no candidate list.");
|
|
goto GetCandListCntUnlockIMC;
|
|
}
|
|
|
|
*lpdwListCount = lpCandInfo->dwCount;
|
|
|
|
if (fAnsi && TestICF(pClientImc, IMCF_UNICODE)) {
|
|
LPCANDIDATELIST lpCandListW;
|
|
|
|
dwRet = DWORD_ALIGN(sizeof(CANDIDATEINFO))
|
|
+ DWORD_ALIGN(lpCandInfo->dwPrivateSize);
|
|
|
|
for (i = 0; i < (INT)lpCandInfo->dwCount; i++) {
|
|
lpCandListW = (LPCANDIDATELIST)((LPBYTE)lpCandInfo + lpCandInfo->dwOffset[i]);
|
|
dwRet += InternalGetCandidateListWtoA(lpCandListW, NULL, 0, dwCodePage);
|
|
}
|
|
}
|
|
else if (!fAnsi && !TestICF(pClientImc, IMCF_UNICODE)) {
|
|
LPCANDIDATELIST lpCandListA;
|
|
|
|
dwRet = DWORD_ALIGN(sizeof(CANDIDATEINFO))
|
|
+ DWORD_ALIGN(lpCandInfo->dwPrivateSize);
|
|
|
|
for (i = 0; i < (INT)lpCandInfo->dwCount; i++) {
|
|
lpCandListA = (LPCANDIDATELIST)((LPBYTE)lpCandInfo + lpCandInfo->dwOffset[i]);
|
|
dwRet += InternalGetCandidateListAtoW(lpCandListA, NULL, 0, dwCodePage);
|
|
}
|
|
}
|
|
else {
|
|
dwRet = lpCandInfo->dwSize;
|
|
}
|
|
|
|
ImmUnlockIMCC(pInputContext->hCandInfo);
|
|
|
|
GetCandListCntUnlockIMC:
|
|
ImmUnlockIMC(hImc);
|
|
|
|
GetCandListCntUnlockClientImc:
|
|
ImmUnlockClientImc(pClientImc);
|
|
|
|
GetCandListCntExit:
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetCandidateListA
|
|
*
|
|
* Gets the candidate list information specified by dwIndex.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD WINAPI ImmGetCandidateListA(
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
LPCANDIDATELIST lpCandList,
|
|
DWORD dwBufLen)
|
|
{
|
|
return ImmGetCandidateListWorker(hImc, dwIndex,
|
|
lpCandList, dwBufLen, TRUE);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetCandidateListW
|
|
*
|
|
* Gets the candidate list information specified by dwIndex.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD WINAPI ImmGetCandidateListW(
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
LPCANDIDATELIST lpCandList,
|
|
DWORD dwBufLen)
|
|
{
|
|
return ImmGetCandidateListWorker(hImc, dwIndex,
|
|
lpCandList, dwBufLen, FALSE);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetCandidateListWorker
|
|
*
|
|
* Worker function of ImmGetCandidateListA/ImmGetCandidateListW.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD ImmGetCandidateListWorker(
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
LPCANDIDATELIST lpCandList,
|
|
DWORD dwBufLen,
|
|
BOOL fAnsi)
|
|
{
|
|
PCLIENTIMC pClientImc;
|
|
PINPUTCONTEXT pInputContext;
|
|
LPCANDIDATEINFO lpCandInfo;
|
|
LPCANDIDATELIST lpCandListTemp;
|
|
DWORD dwBufLenTemp;
|
|
DWORD dwRet = 0;
|
|
DWORD dwCodePage;
|
|
|
|
pClientImc = ImmLockClientImc(hImc);
|
|
if (pClientImc == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCandidateList: Invalid hImc %lx.", hImc);
|
|
goto GetCandListExit;
|
|
|
|
}
|
|
|
|
dwCodePage = CImcCodePage(pClientImc);
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (pInputContext == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCandidateList: Lock hImc %lx failed.", hImc);
|
|
goto GetCandListUnlockClientImc;
|
|
}
|
|
|
|
lpCandInfo = (LPCANDIDATEINFO)ImmLockIMCC(pInputContext->hCandInfo);
|
|
if (!lpCandInfo) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCandidateList: Lock hCandInfo %x failed",
|
|
pInputContext->hCandInfo);
|
|
goto GetCandListUnlockIMC;
|
|
}
|
|
|
|
if (lpCandInfo->dwSize < sizeof(CANDIDATEINFO)) {
|
|
RIPMSG0(RIP_WARNING, "ImmGetCandidateList: no candidate list.");
|
|
goto GetCandListUnlockIMCC;
|
|
}
|
|
|
|
/*
|
|
* invalid access
|
|
*/
|
|
if (dwIndex >= lpCandInfo->dwCount) {
|
|
RIPMSG0(RIP_WARNING, "ImmGetCandidateList: dwIndex >= lpCandInfo->dwCount.");
|
|
goto GetCandListUnlockIMCC;
|
|
}
|
|
|
|
lpCandListTemp = (LPCANDIDATELIST)((LPBYTE)lpCandInfo + lpCandInfo->dwOffset[dwIndex]);
|
|
|
|
if (fAnsi && TestICF(pClientImc, IMCF_UNICODE)) {
|
|
/*
|
|
* ANSI Caller with an Unicode hImc.
|
|
*/
|
|
dwBufLenTemp = InternalGetCandidateListWtoA(lpCandListTemp, NULL, 0, dwCodePage);
|
|
}
|
|
else if (!fAnsi && !TestICF(pClientImc, IMCF_UNICODE)) {
|
|
/*
|
|
* Unicode Caller with an ANSI hImc.
|
|
*/
|
|
dwBufLenTemp = InternalGetCandidateListAtoW(lpCandListTemp, NULL, 0, dwCodePage);
|
|
}
|
|
else {
|
|
/*
|
|
* No conversion required.
|
|
*/
|
|
dwBufLenTemp = lpCandListTemp->dwSize;
|
|
}
|
|
|
|
/*
|
|
* Query buffer size or early exit on error
|
|
*/
|
|
if (dwBufLen == 0 || dwBufLenTemp == 0) {
|
|
dwRet = dwBufLenTemp;
|
|
}
|
|
else if (!lpCandList) {
|
|
RIPMSG0(RIP_WARNING, "ImmGetCandidateList: Null lpCandList.");
|
|
}
|
|
else if (dwBufLen < dwBufLenTemp) {
|
|
RIPMSG2(RIP_WARNING, "ImmGetCandidateList: dwBufLen = %d too small, require = %d.",
|
|
dwBufLen, dwBufLenTemp);
|
|
} else {
|
|
if (fAnsi && TestICF(pClientImc, IMCF_UNICODE)) {
|
|
dwRet = InternalGetCandidateListWtoA(lpCandListTemp, lpCandList, dwBufLenTemp, dwCodePage);
|
|
}
|
|
else if (!fAnsi && !TestICF(pClientImc, IMCF_UNICODE)) {
|
|
dwRet = InternalGetCandidateListAtoW(lpCandListTemp, lpCandList, dwBufLenTemp, dwCodePage);
|
|
}
|
|
else {
|
|
RtlCopyMemory((LPBYTE)lpCandList, (LPBYTE)lpCandListTemp, dwBufLenTemp);
|
|
dwRet = dwBufLenTemp;
|
|
}
|
|
}
|
|
|
|
GetCandListUnlockIMCC:
|
|
ImmUnlockIMCC(pInputContext->hCandInfo);
|
|
|
|
GetCandListUnlockIMC:
|
|
ImmUnlockIMC(hImc);
|
|
|
|
GetCandListUnlockClientImc:
|
|
ImmUnlockClientImc(pClientImc);
|
|
|
|
GetCandListExit:
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetGuideLineA
|
|
*
|
|
* Gets the guide line information reported by the IME.
|
|
*
|
|
* History:
|
|
* 26-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD WINAPI ImmGetGuideLineA(
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
LPSTR lpszBuf,
|
|
DWORD dwBufLen)
|
|
{
|
|
return ImmGetGuideLineWorker(hImc, dwIndex,
|
|
(LPBYTE)lpszBuf, dwBufLen, TRUE);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetGuideLineW
|
|
*
|
|
* Gets the guide line information reported by the IME.
|
|
*
|
|
* History:
|
|
* 26-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD WINAPI ImmGetGuideLineW(
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
LPWSTR lpwszBuf,
|
|
DWORD dwBufLen)
|
|
{
|
|
return ImmGetGuideLineWorker(hImc, dwIndex,
|
|
(LPBYTE)lpwszBuf, dwBufLen, FALSE);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetGuideLineWorker
|
|
*
|
|
* Worker function of ImmGetGuideLineA/ImmGetGuideLineW.
|
|
*
|
|
* History:
|
|
* 26-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD ImmGetGuideLineWorker(
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
LPBYTE lpBuf,
|
|
DWORD dwBufLen,
|
|
BOOL fAnsi)
|
|
{
|
|
PCLIENTIMC pClientImc;
|
|
PINPUTCONTEXT pInputContext;
|
|
LPGUIDELINE lpGuideLine;
|
|
LPBYTE lpBufTemp;
|
|
DWORD dwRet = 0;
|
|
DWORD dwBufLenNeeded;
|
|
BOOL bUDC;
|
|
DWORD dwCodePage;
|
|
|
|
pClientImc = ImmLockClientImc(hImc);
|
|
if (pClientImc == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetGuideLine: Invalid hImc %lx.", hImc);
|
|
goto GetGuideLineExit;
|
|
}
|
|
dwCodePage = CImcCodePage(pClientImc);
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (pInputContext == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetGuideLine: Lock hImc %lx failed.", hImc);
|
|
goto GetGuideLineUnlockClientImc;
|
|
}
|
|
|
|
lpGuideLine = (LPGUIDELINE)ImmLockIMCC(pInputContext->hGuideLine);
|
|
if (!lpGuideLine) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetGuideLine: Lock hGuideLine %lx failed.",
|
|
pInputContext->hGuideLine);
|
|
goto GetGuideLineUnlockIMC;
|
|
}
|
|
|
|
switch (dwIndex) {
|
|
case GGL_LEVEL:
|
|
dwRet = lpGuideLine->dwLevel;
|
|
break;
|
|
|
|
case GGL_INDEX:
|
|
dwRet = lpGuideLine->dwIndex;
|
|
break;
|
|
|
|
case GGL_STRING:
|
|
|
|
lpBufTemp = (LPBYTE)lpGuideLine + lpGuideLine->dwStrOffset;
|
|
|
|
/*
|
|
* Calculate the required buffer length.
|
|
*/
|
|
if (fAnsi && TestICF(pClientImc, IMCF_UNICODE)) {
|
|
dwBufLenNeeded = WideCharToMultiByte(dwCodePage,
|
|
(DWORD)0,
|
|
(LPWSTR)lpBufTemp,
|
|
(INT)lpGuideLine->dwStrLen,
|
|
(LPSTR)NULL,
|
|
(INT)0,
|
|
(LPSTR)NULL,
|
|
(LPBOOL)&bUDC);
|
|
}
|
|
else if (!fAnsi && !TestICF(pClientImc, IMCF_UNICODE)) {
|
|
dwBufLenNeeded = MultiByteToWideChar(dwCodePage,
|
|
(DWORD)MB_PRECOMPOSED,
|
|
(LPSTR)lpBufTemp,
|
|
(INT)lpGuideLine->dwStrLen,
|
|
(LPWSTR)NULL,
|
|
(INT)0);
|
|
dwBufLenNeeded *= sizeof(WCHAR);
|
|
}
|
|
else {
|
|
dwBufLenNeeded = lpGuideLine->dwStrLen;
|
|
/*
|
|
* The dwStrLen records the strlen and not the byte count.
|
|
*/
|
|
if (TestICF(pClientImc, IMCF_UNICODE))
|
|
dwBufLenNeeded *= sizeof(WCHAR);
|
|
}
|
|
|
|
/*
|
|
* Query GuideLine string size only or early exit on error
|
|
*/
|
|
if (dwBufLen == 0 || dwBufLenNeeded == 0) {
|
|
dwRet = dwBufLenNeeded;
|
|
goto GetGuideLineUnlockIMCC;
|
|
}
|
|
|
|
if (lpBuf == NULL || dwBufLen < dwBufLenNeeded)
|
|
goto GetGuideLineUnlockIMCC;
|
|
|
|
if (fAnsi && TestICF(pClientImc, IMCF_UNICODE)) {
|
|
dwRet = WideCharToMultiByte(dwCodePage,
|
|
(DWORD)0,
|
|
(LPWSTR)lpBufTemp,
|
|
(INT)lpGuideLine->dwStrLen,
|
|
(LPSTR)lpBuf,
|
|
(INT)dwBufLen,
|
|
(LPSTR)NULL,
|
|
(LPBOOL)&bUDC);
|
|
}
|
|
else if (!fAnsi && !TestICF(pClientImc, IMCF_UNICODE)) {
|
|
dwRet = MultiByteToWideChar(dwCodePage,
|
|
(DWORD)MB_PRECOMPOSED,
|
|
(LPSTR)lpBufTemp,
|
|
(INT)lpGuideLine->dwStrLen,
|
|
(LPWSTR)lpBuf,
|
|
(INT)dwBufLen/sizeof(WCHAR));
|
|
dwRet *= sizeof(WCHAR);
|
|
}
|
|
else {
|
|
RtlCopyMemory(lpBuf, lpBufTemp, dwBufLenNeeded);
|
|
dwRet = dwBufLenNeeded;
|
|
}
|
|
|
|
break;
|
|
|
|
case GGL_PRIVATE:
|
|
|
|
lpBufTemp = (LPBYTE)lpGuideLine + lpGuideLine->dwPrivateOffset;
|
|
|
|
/*
|
|
* The dwPrivateOffset is an offset to a CANDIDATELIST when
|
|
* lpGuideLine->dwIndex == GL_ID_REVERSECONVERSION. Do conversion
|
|
* for this case only.
|
|
*/
|
|
if (fAnsi && TestICF(pClientImc, IMCF_UNICODE) &&
|
|
lpGuideLine->dwIndex == GL_ID_REVERSECONVERSION) {
|
|
dwBufLenNeeded = InternalGetCandidateListWtoA(
|
|
(LPCANDIDATELIST)lpBufTemp, (LPCANDIDATELIST)NULL, 0, dwCodePage);
|
|
}
|
|
else if (!fAnsi && !TestICF(pClientImc, IMCF_UNICODE) &&
|
|
lpGuideLine->dwIndex == GL_ID_REVERSECONVERSION) {
|
|
dwBufLenNeeded = InternalGetCandidateListAtoW(
|
|
(LPCANDIDATELIST)lpBufTemp, (LPCANDIDATELIST)NULL, 0, dwCodePage);
|
|
}
|
|
else {
|
|
dwBufLenNeeded = lpGuideLine->dwPrivateSize;
|
|
}
|
|
|
|
/*
|
|
* Query dwPrivateSize size only or early exit on error
|
|
*/
|
|
if (dwBufLen == 0 || dwBufLenNeeded == 0) {
|
|
dwRet = dwBufLenNeeded;
|
|
goto GetGuideLineUnlockIMCC;
|
|
}
|
|
|
|
if (lpBuf == NULL || dwBufLen < dwBufLenNeeded)
|
|
goto GetGuideLineUnlockIMCC;
|
|
|
|
if (fAnsi && TestICF(pClientImc, IMCF_UNICODE) &&
|
|
lpGuideLine->dwIndex == GL_ID_REVERSECONVERSION) {
|
|
dwRet = InternalGetCandidateListWtoA(
|
|
(LPCANDIDATELIST)lpBufTemp, (LPCANDIDATELIST)lpBuf, dwBufLenNeeded, dwCodePage);
|
|
}
|
|
else if (!fAnsi && !TestICF(pClientImc, IMCF_UNICODE) &&
|
|
lpGuideLine->dwIndex == GL_ID_REVERSECONVERSION) {
|
|
dwRet = InternalGetCandidateListAtoW(
|
|
(LPCANDIDATELIST)lpBufTemp, (LPCANDIDATELIST)lpBuf, dwBufLenNeeded, dwCodePage);
|
|
}
|
|
else {
|
|
RtlCopyMemory(lpBuf, lpBufTemp, dwBufLenNeeded);
|
|
dwRet = dwBufLenNeeded;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
GetGuideLineUnlockIMCC:
|
|
ImmUnlockIMCC(pInputContext->hGuideLine);
|
|
|
|
GetGuideLineUnlockIMC:
|
|
ImmUnlockIMC(hImc);
|
|
|
|
GetGuideLineUnlockClientImc:
|
|
ImmUnlockClientImc(pClientImc);
|
|
|
|
GetGuideLineExit:
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetConversionStatus
|
|
*
|
|
* Gets current conversion status.
|
|
*
|
|
* History:
|
|
* 26-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI ImmGetConversionStatus( // Get the conversion status
|
|
HIMC hImc,
|
|
LPDWORD lpfdwConversion,
|
|
LPDWORD lpfdwSentence)
|
|
{
|
|
PINPUTCONTEXT pInputContext;
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (pInputContext == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetConversionStatus: Lock hImc %lx failed", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
if (lpfdwConversion != NULL)
|
|
*lpfdwConversion = pInputContext->fdwConversion;
|
|
|
|
if (lpfdwSentence != NULL)
|
|
*lpfdwSentence = pInputContext->fdwSentence;
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmSetConversionStatus
|
|
*
|
|
* Sets current conversion status.
|
|
*
|
|
* History:
|
|
* 26-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI ImmSetConversionStatus(
|
|
HIMC hImc,
|
|
DWORD fdwConversion,
|
|
DWORD fdwSentence)
|
|
{
|
|
PINPUTCONTEXT pInputContext;
|
|
DWORD fdwOldConversion;
|
|
DWORD fdwOldSentence;
|
|
BOOL fConvModeChg;
|
|
BOOL fSentenceChg;
|
|
HWND hWnd;
|
|
DWORD dwOpenStatus;
|
|
DWORD dwConversion;
|
|
|
|
#if defined(CUAS_ENABLE)
|
|
BOOL fMakeNotifyAlways = FALSE;
|
|
HKL hKL = GetKeyboardLayout(0);
|
|
if (!IS_IME_KBDLAYOUT(hKL) && IS_CICERO_ENABLED_AND_NOT16BIT())
|
|
fMakeNotifyAlways = TRUE;
|
|
#endif
|
|
|
|
if (GetInputContextThread(hImc) != GetCurrentThreadId()) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmSetConversionStatus: Invalid input context access %lx.", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (pInputContext == NULL) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmSetConversionStatus: Lock hImc %lx failed", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
fConvModeChg = FALSE;
|
|
fSentenceChg = FALSE;
|
|
|
|
if (pInputContext->fdwConversion != fdwConversion) {
|
|
if ((fdwConversion & IME_CMODE_LANGUAGE) == IME_CMODE_KATAKANA) {
|
|
RIPMSG0(RIP_WARNING, "ImmSetConversionStatus: wrong fdwConversion");
|
|
}
|
|
fdwOldConversion = pInputContext->fdwConversion;
|
|
pInputContext->fdwConversion = fdwConversion;
|
|
fConvModeChg = TRUE;
|
|
}
|
|
|
|
if (pInputContext->fdwSentence != fdwSentence) {
|
|
fdwOldSentence = pInputContext->fdwSentence;
|
|
pInputContext->fdwSentence = fdwSentence;
|
|
fSentenceChg = TRUE;
|
|
}
|
|
|
|
hWnd = pInputContext->hWnd;
|
|
if ( fConvModeChg ) {
|
|
|
|
dwOpenStatus = (DWORD)pInputContext->fOpen;
|
|
dwConversion = pInputContext->fdwConversion;
|
|
}
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
#ifdef LATER
|
|
// Do uNumLangVKey and uNumVKey checking later.
|
|
#endif
|
|
|
|
/*
|
|
* inform IME and UI about the conversion mode changes.
|
|
*/
|
|
#if !defined(CUAS_ENABLE)
|
|
if (fConvModeChg)
|
|
#else
|
|
if (fConvModeChg || fMakeNotifyAlways)
|
|
#endif
|
|
{
|
|
MakeIMENotify(hImc, hWnd, NI_CONTEXTUPDATED, fdwOldConversion,
|
|
IMC_SETCONVERSIONMODE, IMN_SETCONVERSIONMODE, 0L);
|
|
|
|
/*
|
|
* notify shell and keyboard the conversion mode change
|
|
*/
|
|
#if defined(CUAS_ENABLE)
|
|
if (fConvModeChg)
|
|
#endif
|
|
NtUserNotifyIMEStatus( hWnd, dwOpenStatus, dwConversion );
|
|
}
|
|
|
|
/*
|
|
* inform IME and UI about the sentence mode changes.
|
|
*/
|
|
#if !defined(CUAS_ENABLE)
|
|
if (fSentenceChg)
|
|
#else
|
|
if (fSentenceChg || fMakeNotifyAlways)
|
|
#endif
|
|
{
|
|
MakeIMENotify(hImc, hWnd, NI_CONTEXTUPDATED, fdwOldSentence,
|
|
IMC_SETSENTENCEMODE, IMN_SETSENTENCEMODE, 0L);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetOpenStatus
|
|
*
|
|
* Gets the open or close status of the IME.
|
|
*
|
|
* History:
|
|
* 26-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI ImmGetOpenStatus(
|
|
HIMC hImc)
|
|
{
|
|
PINPUTCONTEXT pInputContext;
|
|
BOOL fOpen;
|
|
|
|
if (hImc == NULL_HIMC)
|
|
return FALSE;
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (!pInputContext) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetOpenStatus: Lock hImc %lx failed", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
fOpen = pInputContext->fOpen;
|
|
ImmUnlockIMC(hImc);
|
|
|
|
return (fOpen);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmSetOpenStatus
|
|
*
|
|
* Opens or closes the IME.
|
|
*
|
|
* History:
|
|
* 26-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI ImmSetOpenStatus(
|
|
HIMC hImc,
|
|
BOOL fOpen)
|
|
{
|
|
PINPUTCONTEXT pInputContext;
|
|
HWND hWnd;
|
|
DWORD dwOpenStatus;
|
|
DWORD dwConversion;
|
|
BOOL fOpenChg = FALSE;
|
|
|
|
if (GetInputContextThread(hImc) != GetCurrentThreadId()) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmSetOpenStatus: Invalid input context access %lx.", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (!pInputContext) {
|
|
RIPMSG1(RIP_WARNING, "ImmSetOpenStatus: Lock hImc %lx failed", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
if (pInputContext->fOpen != fOpen) {
|
|
fOpenChg = TRUE;
|
|
pInputContext->fOpen = fOpen;
|
|
}
|
|
|
|
if ( fOpenChg ) {
|
|
hWnd = (HWND)pInputContext->hWnd;
|
|
dwOpenStatus = (DWORD)pInputContext->fOpen;
|
|
dwConversion = (DWORD)pInputContext->fdwConversion;
|
|
}
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
/*
|
|
* inform IME and UI about the conversion mode changes.
|
|
*/
|
|
if (fOpenChg) {
|
|
MakeIMENotify(hImc, hWnd, NI_CONTEXTUPDATED, (DWORD)0,
|
|
IMC_SETOPENSTATUS, IMN_SETOPENSTATUS, 0L);
|
|
|
|
NtUserNotifyIMEStatus( hWnd, dwOpenStatus, dwConversion );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetCompositionFontA
|
|
*
|
|
* Opens or closes the IME.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI ImmGetCompositionFontA(
|
|
HIMC hImc,
|
|
LPLOGFONTA lpLogFontA)
|
|
{
|
|
PCLIENTIMC pClientImc;
|
|
PINPUTCONTEXT pInputContext;
|
|
LOGFONTW LogFontW;
|
|
BOOL fUnicode, fRet;
|
|
|
|
pClientImc = ImmLockClientImc(hImc);
|
|
if (pClientImc == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCompositionFontA: Invalid hImc %lx.", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
fUnicode = TestICF(pClientImc, IMCF_UNICODE);
|
|
|
|
ImmUnlockClientImc(pClientImc);
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (pInputContext == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCompositionFontA: Lock hImc %lx failed.", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
if (fUnicode) {
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
if (ImmGetCompositionFontW(hImc, &LogFontW)) {
|
|
LFontWtoLFontA(&LogFontW, lpLogFontA);
|
|
return (TRUE);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if ((pInputContext->fdwInit & INIT_LOGFONT) == INIT_LOGFONT) {
|
|
*lpLogFontA = pInputContext->lfFont.A;
|
|
fRet = TRUE;
|
|
}
|
|
else {
|
|
fRet = FALSE;
|
|
}
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetCompositionFontW
|
|
*
|
|
* Opens or closes the IME.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI ImmGetCompositionFontW(
|
|
HIMC hImc,
|
|
LPLOGFONTW lpLogFontW)
|
|
{
|
|
PCLIENTIMC pClientImc;
|
|
PINPUTCONTEXT pInputContext;
|
|
LOGFONTA LogFontA;
|
|
BOOL fUnicode, fRet;
|
|
|
|
pClientImc = ImmLockClientImc(hImc);
|
|
if (pClientImc == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCompositionFontW: Invalid hImc %lx.", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
fUnicode = TestICF(pClientImc, IMCF_UNICODE);
|
|
|
|
ImmUnlockClientImc(pClientImc);
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (!pInputContext) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCompositionFontW: Lock hImc %lx failed.", hImc);
|
|
return (FALSE);
|
|
}
|
|
|
|
if (!fUnicode) {
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
if (ImmGetCompositionFontA(hImc, &LogFontA)) {
|
|
LFontAtoLFontW(&LogFontA, lpLogFontW);
|
|
return (TRUE);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if ((pInputContext->fdwInit & INIT_LOGFONT) == INIT_LOGFONT) {
|
|
*lpLogFontW = pInputContext->lfFont.W;
|
|
fRet = TRUE;
|
|
}
|
|
else {
|
|
fRet = FALSE;
|
|
}
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
BOOL WINAPI ImmSetCompositionFontA(
|
|
HIMC hImc,
|
|
LPLOGFONTA lpLogFontA)
|
|
{
|
|
PCLIENTIMC pClientImc;
|
|
PINPUTCONTEXT pInputContext;
|
|
LOGFONTW LogFontW;
|
|
HWND hWnd;
|
|
BOOL fUnicode;
|
|
|
|
if (GetInputContextThread(hImc) != GetCurrentThreadId()) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmSetCompositionFontA: Invalid input context access %lx.", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
pClientImc = ImmLockClientImc(hImc);
|
|
if (pClientImc == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmSetCompositionFontA: Invalid hImc %lx.", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
fUnicode = TestICF(pClientImc, IMCF_UNICODE);
|
|
|
|
ImmUnlockClientImc(pClientImc);
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (!pInputContext) {
|
|
RIPMSG1(RIP_WARNING, "ImmSetCompositionFontA: Lock hImc %lx failed.", hImc);
|
|
return (FALSE);
|
|
}
|
|
|
|
if (fUnicode) {
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
LFontAtoLFontW(lpLogFontA, &LogFontW);
|
|
|
|
return ImmSetCompositionFontW(hImc, &LogFontW);
|
|
}
|
|
|
|
/*
|
|
* Japanese 3.x applications need to receive 3.x compatible notification message.
|
|
*
|
|
*/
|
|
if ( (GetClientInfo()->dwExpWinVer < VER40) &&
|
|
(PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) == LANG_JAPANESE) &&
|
|
! (pInputContext->fdw31Compat & F31COMPAT_MCWHIDDEN) &&
|
|
(pInputContext->cfCompForm.dwStyle != CFS_DEFAULT) ) {
|
|
|
|
PostMessageA( pInputContext->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, (LPARAM)NULL);
|
|
}
|
|
|
|
pInputContext->lfFont.A = *lpLogFontA;
|
|
pInputContext->fdwInit |= INIT_LOGFONT;
|
|
hWnd = pInputContext->hWnd;
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
/*
|
|
* inform IME and UI about the change of composition font.
|
|
*/
|
|
MakeIMENotify(hImc, hWnd, NI_CONTEXTUPDATED, 0L,
|
|
IMC_SETCOMPOSITIONFONT, IMN_SETCOMPOSITIONFONT, 0L);
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL WINAPI ImmSetCompositionFontW(
|
|
HIMC hImc,
|
|
LPLOGFONTW lpLogFontW)
|
|
{
|
|
PCLIENTIMC pClientImc;
|
|
PINPUTCONTEXT pInputContext;
|
|
LOGFONTA LogFontA;
|
|
HWND hWnd;
|
|
BOOL fUnicode;
|
|
|
|
if (GetInputContextThread(hImc) != GetCurrentThreadId()) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmSetCompositionFontW: Invalid input context access %lx.", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
pClientImc = ImmLockClientImc(hImc);
|
|
if (pClientImc == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmSetCompositionFontW: Invalid hImc %lx.", hImc);
|
|
return (FALSE);
|
|
}
|
|
|
|
fUnicode = TestICF(pClientImc, IMCF_UNICODE);
|
|
|
|
ImmUnlockClientImc(pClientImc);
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (!pInputContext) {
|
|
RIPMSG1(RIP_WARNING, "ImmSetCompositionFontW: Lock hImc %lx failed.", hImc);
|
|
return (FALSE);
|
|
}
|
|
|
|
if (!fUnicode) {
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
LFontWtoLFontA(lpLogFontW, &LogFontA);
|
|
|
|
return ImmSetCompositionFontA(hImc, &LogFontA);
|
|
}
|
|
|
|
/*
|
|
* Japanese 3.x applications need to receive 3.x compatible notification message.
|
|
*
|
|
*/
|
|
if ( (GetClientInfo()->dwExpWinVer < VER40) &&
|
|
(PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) == LANG_JAPANESE) &&
|
|
! (pInputContext->fdw31Compat & F31COMPAT_MCWHIDDEN) &&
|
|
(pInputContext->cfCompForm.dwStyle != CFS_DEFAULT) ) {
|
|
|
|
PostMessageW( pInputContext->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, (LPARAM)NULL);
|
|
}
|
|
pInputContext->lfFont.W = *lpLogFontW;
|
|
pInputContext->fdwInit |= INIT_LOGFONT;
|
|
hWnd = pInputContext->hWnd;
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
/*
|
|
* inform IME and UI about the change of composition font.
|
|
*/
|
|
MakeIMENotify(hImc, hWnd, NI_CONTEXTUPDATED, 0L,
|
|
IMC_SETCOMPOSITIONFONT, IMN_SETCOMPOSITIONFONT, 0L);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetConversionListA
|
|
*
|
|
* Obtains the list of FE character or word from one character or word.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD WINAPI ImmGetConversionListA(
|
|
HKL hKL,
|
|
HIMC hImc,
|
|
LPCSTR lpszSrc,
|
|
LPCANDIDATELIST lpCandListA,
|
|
DWORD dwBufLen,
|
|
UINT uFlag)
|
|
{
|
|
PIMEDPI pImeDpi;
|
|
DWORD dwRet;
|
|
LPWSTR lpwszSrc;
|
|
DWORD dwBufTemp;
|
|
LPCANDIDATELIST lpCandListW;
|
|
INT i;
|
|
DWORD dwCodePage;
|
|
|
|
pImeDpi = FindOrLoadImeDpi(hKL);
|
|
|
|
if (pImeDpi == NULL) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmGetConversionListA: cannot find DPI entry for hkl=%lx", hKL);
|
|
return (0);
|
|
}
|
|
|
|
dwCodePage = IMECodePage(pImeDpi);
|
|
|
|
if (!(pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE)) {
|
|
/*
|
|
* This is an ANSI call to an ANSI IME.
|
|
*/
|
|
dwRet = (*pImeDpi->pfn.ImeConversionList.a)(hImc, lpszSrc,
|
|
lpCandListA, dwBufLen, uFlag);
|
|
ImmUnlockImeDpi(pImeDpi);
|
|
return dwRet;
|
|
}
|
|
|
|
ImmUnlockImeDpi(pImeDpi);
|
|
|
|
/*
|
|
* This is an ANSI call to an Unicode IME.
|
|
*/
|
|
if (lpszSrc != NULL) {
|
|
|
|
dwBufTemp = (strlen(lpszSrc) + 1) * sizeof(WCHAR);
|
|
|
|
lpwszSrc = ImmLocalAlloc(0, dwBufTemp);
|
|
if (lpwszSrc == NULL)
|
|
return (0);
|
|
|
|
i = MultiByteToWideChar(dwCodePage,
|
|
(DWORD)MB_PRECOMPOSED,
|
|
(LPSTR)lpszSrc, // src
|
|
(INT)strlen(lpszSrc),
|
|
(LPWSTR)lpwszSrc, // dest
|
|
(INT)dwBufTemp/sizeof(WCHAR));
|
|
|
|
lpwszSrc[i] = '\0';
|
|
}
|
|
else {
|
|
lpwszSrc = NULL;
|
|
}
|
|
|
|
/*
|
|
* Query the CandidateListW size required.
|
|
*/
|
|
dwBufTemp = ImmGetConversionListW(hKL, hImc, lpwszSrc, NULL, 0, uFlag);
|
|
|
|
if (dwBufTemp == 0 || (lpCandListW = ImmLocalAlloc(0, dwBufTemp)) == NULL) {
|
|
if (lpwszSrc)
|
|
ImmLocalFree(lpwszSrc);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Now get the actual CandidateListW.
|
|
*/
|
|
dwBufTemp = ImmGetConversionListW(hKL, hImc, lpwszSrc,
|
|
lpCandListW, dwBufTemp, uFlag);
|
|
|
|
/*
|
|
* Query the CandidateListA size required.
|
|
*/
|
|
if (dwBufTemp != 0) {
|
|
dwBufTemp = InternalGetCandidateListWtoA(lpCandListW, NULL, 0, dwCodePage);
|
|
}
|
|
|
|
if (dwBufLen == 0 || dwBufTemp == 0) {
|
|
/*
|
|
* Query required buffer size or error has happened.
|
|
*/
|
|
dwRet = dwBufTemp;
|
|
}
|
|
else if (dwBufLen < dwBufTemp) {
|
|
/*
|
|
* Not enough buffer area.
|
|
*/
|
|
dwRet = 0;
|
|
}
|
|
else {
|
|
/*
|
|
* Get the actual CandidateListA
|
|
*/
|
|
dwRet = InternalGetCandidateListWtoA(lpCandListW, lpCandListA, dwBufLen, dwCodePage);
|
|
}
|
|
|
|
if (lpwszSrc)
|
|
ImmLocalFree(lpwszSrc);
|
|
ImmLocalFree(lpCandListW);
|
|
|
|
return dwRet;
|
|
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetConversionListW
|
|
*
|
|
* Obtains the list of FE character or word from one character or word.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD WINAPI ImmGetConversionListW(
|
|
HKL hKL,
|
|
HIMC hImc,
|
|
LPCWSTR lpwszSrc,
|
|
LPCANDIDATELIST lpCandListW,
|
|
DWORD dwBufLen,
|
|
UINT uFlag)
|
|
{
|
|
PIMEDPI pImeDpi;
|
|
DWORD dwRet;
|
|
LPSTR lpszSrc;
|
|
DWORD dwBufTemp;
|
|
LPCANDIDATELIST lpCandListA;
|
|
BOOL bUDC;
|
|
INT i;
|
|
DWORD dwCodePage;
|
|
|
|
pImeDpi = FindOrLoadImeDpi(hKL);
|
|
|
|
if (pImeDpi == NULL) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmGetConversionListW: cannot find DPI entry for hkl=%lx", hKL);
|
|
return (0);
|
|
}
|
|
|
|
dwCodePage = IMECodePage(pImeDpi);
|
|
|
|
if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) {
|
|
/*
|
|
* This is an Unicode call to an Unicode IME.
|
|
*/
|
|
dwRet = (*pImeDpi->pfn.ImeConversionList.w)(hImc, lpwszSrc,
|
|
lpCandListW, dwBufLen, uFlag);
|
|
ImmUnlockImeDpi(pImeDpi);
|
|
return dwRet;
|
|
}
|
|
|
|
ImmUnlockImeDpi(pImeDpi);
|
|
|
|
/*
|
|
* This is an Unicode call to an ANSI IME.
|
|
*/
|
|
if (lpwszSrc != NULL) {
|
|
|
|
dwBufTemp = (wcslen(lpwszSrc) + 1) * sizeof(WCHAR);
|
|
|
|
lpszSrc = ImmLocalAlloc(0, dwBufTemp);
|
|
if (lpszSrc == NULL)
|
|
return (0);
|
|
|
|
i = WideCharToMultiByte(dwCodePage,
|
|
(DWORD)0,
|
|
lpwszSrc,
|
|
(INT)wcslen(lpwszSrc),
|
|
(LPSTR)lpszSrc,
|
|
(INT)dwBufTemp,
|
|
(LPSTR)NULL,
|
|
(LPBOOL)&bUDC);
|
|
|
|
lpszSrc[i] = '\0';
|
|
}
|
|
else {
|
|
lpszSrc = NULL;
|
|
}
|
|
|
|
/*
|
|
* Query the CandidateListA size required.
|
|
*/
|
|
dwBufTemp = ImmGetConversionListA(hKL, hImc, lpszSrc, NULL, 0, uFlag);
|
|
|
|
if (dwBufTemp == 0 || (lpCandListA = ImmLocalAlloc(0, dwBufTemp)) == NULL) {
|
|
if (lpszSrc)
|
|
ImmLocalFree(lpszSrc);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Now get the actual CandidateListA.
|
|
*/
|
|
dwBufTemp = ImmGetConversionListA(hKL, hImc, lpszSrc,
|
|
lpCandListA, dwBufTemp, uFlag);
|
|
|
|
/*
|
|
* Query the CandidateListW size required.
|
|
*/
|
|
if (dwBufTemp != 0) {
|
|
dwBufTemp = InternalGetCandidateListAtoW(lpCandListA, NULL, 0, dwCodePage);
|
|
}
|
|
|
|
if (dwBufLen == 0 || dwBufTemp == 0) {
|
|
/*
|
|
* Query required buffer size or error has happened.
|
|
*/
|
|
dwRet = dwBufTemp;
|
|
}
|
|
else if (dwBufLen < dwBufTemp) {
|
|
/*
|
|
* Not enough buffer area.
|
|
*/
|
|
dwRet = 0;
|
|
}
|
|
else {
|
|
/*
|
|
* Get the actual CandidateListW
|
|
*/
|
|
dwRet = InternalGetCandidateListAtoW(lpCandListA, lpCandListW, dwBufLen, dwCodePage);
|
|
}
|
|
|
|
if (lpszSrc)
|
|
ImmLocalFree(lpszSrc);
|
|
ImmLocalFree(lpCandListA);
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetStatusWindowPos
|
|
*
|
|
* Gets the position, in screen coordinates, of the status window.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI ImmGetStatusWindowPos(
|
|
HIMC hImc,
|
|
LPPOINT lpptPos)
|
|
{
|
|
PINPUTCONTEXT pInputContext;
|
|
BOOL fStatusWndPosInited;
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (!pInputContext) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetStatusWindowPos: Lock hImc %lx failed", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
fStatusWndPosInited = ((pInputContext->fdwInit & INIT_STATUSWNDPOS) == INIT_STATUSWNDPOS);
|
|
ImmUnlockIMC(hImc);
|
|
|
|
if (fStatusWndPosInited) {
|
|
*lpptPos = pInputContext->ptStatusWndPos;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL WINAPI ImmSetStatusWindowPos(
|
|
HIMC hImc,
|
|
LPPOINT lpptPos)
|
|
{
|
|
PINPUTCONTEXT pInputContext;
|
|
HWND hWnd;
|
|
|
|
if (GetInputContextThread(hImc) != GetCurrentThreadId()) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmSetStatusWindowPos: Invalid input context access %lx.", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (!pInputContext) {
|
|
RIPMSG1(RIP_WARNING, "ImmSetStatusWindowPos: Lock hImc %lx failed", hImc);
|
|
return (FALSE);
|
|
}
|
|
|
|
pInputContext->ptStatusWndPos = *lpptPos;
|
|
pInputContext->fdwInit |= INIT_STATUSWNDPOS;
|
|
|
|
hWnd = pInputContext->hWnd;
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
/*
|
|
* inform IME and UI about the change of composition font.
|
|
*/
|
|
MakeIMENotify(hImc, hWnd, NI_CONTEXTUPDATED, 0L,
|
|
IMC_SETSTATUSWINDOWPOS, IMN_SETSTATUSWINDOWPOS, 0L);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetCompositionWindow
|
|
*
|
|
* Gets the information of the composition window.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI ImmGetCompositionWindow(
|
|
HIMC hImc,
|
|
LPCOMPOSITIONFORM lpCompForm)
|
|
{
|
|
PINPUTCONTEXT pInputContext;
|
|
BOOL fCompFormInited;
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (!pInputContext) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCompositionWindow: Lock hImc %lx failed", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
fCompFormInited = ((pInputContext->fdwInit & INIT_COMPFORM) == INIT_COMPFORM);
|
|
ImmUnlockIMC(hImc);
|
|
|
|
if (fCompFormInited) {
|
|
*lpCompForm = pInputContext->cfCompForm;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL WINAPI ImmSetCompositionWindow(
|
|
HIMC hImc,
|
|
LPCOMPOSITIONFORM lpCompForm)
|
|
{
|
|
PINPUTCONTEXT pInputContext;
|
|
HWND hWnd;
|
|
|
|
if (GetInputContextThread(hImc) != GetCurrentThreadId()) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmSetCompositionWindow: Invalid input context access %lx.", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (!pInputContext) {
|
|
RIPMSG1(RIP_WARNING, "ImmSetCompositionWindow: Lock hImc %lx failed", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
pInputContext->cfCompForm = *lpCompForm;
|
|
pInputContext->fdwInit |= INIT_COMPFORM;
|
|
|
|
/*
|
|
* Only WINNLS.DLL set F31COMPAT_MCWHIDDEN.
|
|
* When the apps or edit control calls this API, we need to remove
|
|
* F31COMPAT_MCWHIDDEN.
|
|
*/
|
|
if (pInputContext->fdw31Compat & F31COMPAT_CALLFROMWINNLS)
|
|
pInputContext->fdw31Compat &= ~F31COMPAT_CALLFROMWINNLS;
|
|
else
|
|
pInputContext->fdw31Compat &= ~F31COMPAT_MCWHIDDEN;
|
|
|
|
hWnd = pInputContext->hWnd;
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
/*
|
|
* inform IME and UI about the change of composition window.
|
|
*/
|
|
MakeIMENotify(hImc, hWnd, NI_CONTEXTUPDATED, 0L,
|
|
IMC_SETCOMPOSITIONWINDOW, IMN_SETCOMPOSITIONWINDOW, 0L);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* ImmGetCandidateWindow
|
|
*
|
|
* Gets the information of the candidate window specified by dwIndex.
|
|
*
|
|
* History:
|
|
* 27-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
BOOL WINAPI ImmGetCandidateWindow(
|
|
HIMC hImc,
|
|
DWORD dwIndex,
|
|
LPCANDIDATEFORM lpCandForm)
|
|
{
|
|
PINPUTCONTEXT pInputContext;
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (!pInputContext) {
|
|
RIPMSG1(RIP_WARNING, "ImmGetCandidateWindow: Lock hImc %lx failed", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
if (pInputContext->cfCandForm[dwIndex].dwIndex == -1) {
|
|
ImmUnlockIMC(hImc);
|
|
return (FALSE);
|
|
}
|
|
|
|
*lpCandForm = pInputContext->cfCandForm[dwIndex];
|
|
ImmUnlockIMC(hImc);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL WINAPI ImmSetCandidateWindow(
|
|
HIMC hImc,
|
|
LPCANDIDATEFORM lpCandForm)
|
|
{
|
|
PINPUTCONTEXT pInputContext;
|
|
HWND hWnd;
|
|
|
|
if (lpCandForm->dwIndex >= 4) // over flow candidate index
|
|
return (FALSE);
|
|
|
|
if (GetInputContextThread(hImc) != GetCurrentThreadId()) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmSetCandidateWindow: Invalid input context access %lx.", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
pInputContext = ImmLockIMC(hImc);
|
|
if (!pInputContext) {
|
|
RIPMSG1(RIP_WARNING, "ImmSetCandidateWindow: Lock hImc %lx failed", hImc);
|
|
return FALSE;
|
|
}
|
|
|
|
pInputContext->cfCandForm[lpCandForm->dwIndex] = *lpCandForm;
|
|
|
|
hWnd = pInputContext->hWnd;
|
|
|
|
ImmUnlockIMC(hImc);
|
|
|
|
/*
|
|
* inform IME and UI about the change of composition window.
|
|
*/
|
|
MakeIMENotify(hImc, hWnd, NI_CONTEXTUPDATED, 0L, IMC_SETCANDIDATEPOS,
|
|
IMN_SETCANDIDATEPOS, (LPARAM)(0x01 << lpCandForm->dwIndex));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#define GetCompInfoA(Component) \
|
|
if (!dwBufLen) { /* query required buffer size */ \
|
|
/* not include \0 */ \
|
|
dwBufLen = pCompStr->dw ## Component ## Len * sizeof(CHAR); \
|
|
} else { \
|
|
if (dwBufLen > pCompStr->dw ## Component ## Len * sizeof(CHAR)) { \
|
|
dwBufLen = pCompStr->dw ## Component ## Len * sizeof(CHAR); \
|
|
} \
|
|
/* don't copy \0, maybe there is actually none */ \
|
|
RtlCopyMemory((LPBYTE)lpBuf, (LPBYTE)pCompStr + \
|
|
pCompStr->dw ## Component ## Offset, dwBufLen); \
|
|
}
|
|
|
|
#define GetCompInfoW(Component) \
|
|
if (!dwBufLen) { /* query required buffer size */ \
|
|
/* not include \0 */ \
|
|
dwBufLen = pCompStr->dw ## Component ## Len * sizeof(WCHAR); \
|
|
} else { \
|
|
if (dwBufLen > pCompStr->dw ## Component ## Len * sizeof(WCHAR)) { \
|
|
dwBufLen = pCompStr->dw ## Component ## Len * sizeof(WCHAR); \
|
|
} \
|
|
/* don't copy \0, maybe there is actually none */ \
|
|
RtlCopyMemory((LPBYTE)lpBuf, (LPBYTE)pCompStr + \
|
|
pCompStr->dw ## Component ## Offset, dwBufLen); \
|
|
}
|
|
|
|
#ifdef CUAS_ENABLE
|
|
|
|
#define GetPrivInfoA(pv, Component) \
|
|
if (!dwBufLen) { /* query required buffer size */ \
|
|
/* not include \0 */ \
|
|
dwBufLen = ## pv ## ->dw ## Component ## Len * sizeof(CHAR); \
|
|
} else { \
|
|
if (dwBufLen > ## pv ## ->dw ## Component ## Len * sizeof(CHAR)) { \
|
|
dwBufLen = ## pv ## ->dw ## Component ## Len * sizeof(CHAR); \
|
|
} \
|
|
/* don't copy \0, maybe there is actually none */ \
|
|
RtlCopyMemory((LPBYTE)lpBuf, (LPBYTE) ## pv ## + \
|
|
## pv ## ->dw ## Component ## Offset, dwBufLen); \
|
|
}
|
|
|
|
#define GetPrivInfoW(pv, Component) \
|
|
if (!dwBufLen) { /* query required buffer size */ \
|
|
/* not include \0 */ \
|
|
dwBufLen = ## pv ## ->dw ## Component ## Len * sizeof(WCHAR); \
|
|
} else { \
|
|
if (dwBufLen > ## pv ## ->dw ## Component ## Len * sizeof(WCHAR)) {\
|
|
dwBufLen = ## pv ## ->dw ## Component ## Len * sizeof(WCHAR); \
|
|
} \
|
|
/* don't copy \0, maybe there is actually none */ \
|
|
RtlCopyMemory((LPBYTE)lpBuf, (LPBYTE) ## pv ## + \
|
|
## pv ## ->dw ## Component ## Offset, dwBufLen); \
|
|
}
|
|
|
|
#endif // CUAS_ENABLE
|
|
|
|
/***************************************************************************\
|
|
* InternalGetCompositionStringA
|
|
*
|
|
* Internal version of ImmGetCompositionStringA.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
LONG InternalGetCompositionStringA(
|
|
#ifdef CUAS_ENABLE
|
|
HIMC hImc,
|
|
#endif // CUAS_ENABLE
|
|
PCOMPOSITIONSTRING pCompStr,
|
|
DWORD dwIndex,
|
|
LPVOID lpBuf,
|
|
DWORD dwBufLen,
|
|
BOOL fAnsiImc,
|
|
DWORD dwCodePage)
|
|
{
|
|
if (fAnsiImc) {
|
|
/*
|
|
* Composition string in input context is of ANSI style.
|
|
*/
|
|
switch (dwIndex) {
|
|
case GCS_COMPSTR:
|
|
GetCompInfoA(CompStr);
|
|
break;
|
|
case GCS_COMPATTR:
|
|
GetCompInfoA(CompAttr);
|
|
break;
|
|
case GCS_COMPREADSTR:
|
|
GetCompInfoA(CompReadStr);
|
|
break;
|
|
case GCS_COMPREADATTR:
|
|
GetCompInfoA(CompReadAttr);
|
|
break;
|
|
case GCS_COMPREADCLAUSE:
|
|
GetCompInfoA(CompReadClause);
|
|
break;
|
|
case GCS_CURSORPOS:
|
|
dwBufLen = (LONG)pCompStr->dwCursorPos;
|
|
break;
|
|
case GCS_DELTASTART:
|
|
dwBufLen = (LONG)pCompStr->dwDeltaStart;
|
|
break;
|
|
case GCS_RESULTSTR:
|
|
GetCompInfoA(ResultStr);
|
|
break;
|
|
case GCS_RESULTCLAUSE:
|
|
GetCompInfoA(ResultClause);
|
|
break;
|
|
case GCS_RESULTREADSTR:
|
|
GetCompInfoA(ResultReadStr);
|
|
break;
|
|
case GCS_RESULTREADCLAUSE:
|
|
GetCompInfoA(ResultReadClause);
|
|
break;
|
|
case GCS_COMPCLAUSE:
|
|
GetCompInfoA(CompClause);
|
|
break;
|
|
#ifdef CUAS_ENABLE
|
|
case GCS_COMPGUIDATTR:
|
|
if (CtfImmIsGuidMapEnable(hImc) && (pCompStr->dwPrivateSize >= sizeof(GUIDMAPATTRIBUTE)))
|
|
{
|
|
PGUIDMAPATTRIBUTE pGuidMap = (PGUIDMAPATTRIBUTE)((PBYTE)pCompStr + pCompStr->dwPrivateOffset);
|
|
if (pGuidMap != NULL)
|
|
{
|
|
GetPrivInfoA(pGuidMap, GuidMapAttr);
|
|
}
|
|
else
|
|
{
|
|
dwBufLen = (DWORD)(LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwBufLen = (DWORD)(LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
break;
|
|
#endif // CUAS_ENABLE
|
|
default:
|
|
dwBufLen = (DWORD)(LONG)IMM_ERROR_GENERAL;
|
|
break;
|
|
}
|
|
|
|
return (LONG)dwBufLen;
|
|
}
|
|
|
|
/*
|
|
* ANSI caller, Unicode input context/composition string.
|
|
*/
|
|
switch (dwIndex) {
|
|
case GCS_COMPSTR:
|
|
case GCS_COMPREADSTR:
|
|
case GCS_RESULTSTR:
|
|
case GCS_RESULTREADSTR:
|
|
{
|
|
DWORD dwStrSize;
|
|
LPWSTR lpStrW;
|
|
BOOL bUDC;
|
|
|
|
/*
|
|
* Get ANSI string from Unicode composition string.
|
|
*/
|
|
#if !defined(CUAS_ENABLE)
|
|
dwStrSize = InternalGetCompositionStringW(pCompStr, dwIndex,
|
|
NULL, 0, fAnsiImc, dwCodePage);
|
|
#else
|
|
dwStrSize = InternalGetCompositionStringW(hImc, pCompStr, dwIndex,
|
|
NULL, 0, fAnsiImc, dwCodePage);
|
|
#endif
|
|
|
|
lpStrW = ImmLocalAlloc(HEAP_ZERO_MEMORY, dwStrSize + sizeof(WCHAR));
|
|
if (lpStrW == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalGetCompositionStringA: memory failure.");
|
|
return (LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
|
|
#if !defined(CUAS_ENABLE)
|
|
dwStrSize = InternalGetCompositionStringW(pCompStr, dwIndex,
|
|
lpStrW, dwStrSize, fAnsiImc, dwCodePage);
|
|
#else
|
|
dwStrSize = InternalGetCompositionStringW(hImc, pCompStr, dwIndex,
|
|
lpStrW, dwStrSize, fAnsiImc, dwCodePage);
|
|
#endif
|
|
|
|
dwBufLen = WideCharToMultiByte(dwCodePage,
|
|
(DWORD)0,
|
|
lpStrW, // src
|
|
wcslen(lpStrW),
|
|
(LPSTR)lpBuf, // dest
|
|
dwBufLen,
|
|
(LPSTR)NULL,
|
|
(LPBOOL)&bUDC);
|
|
|
|
ImmLocalFree(lpStrW);
|
|
break;
|
|
}
|
|
|
|
case GCS_COMPATTR:
|
|
case GCS_COMPREADATTR:
|
|
#ifdef CUAS_ENABLE
|
|
case GCS_COMPGUIDATTR:
|
|
#endif // CUAS_ENABLE
|
|
{
|
|
DWORD dwAttrLenW, dwIndexStr, dwStrSize;
|
|
PBYTE lpAttrA, lpAttrW;
|
|
LPSTR lpStrA, lpStrT;
|
|
CHAR c;
|
|
|
|
/*
|
|
* Get ANSI attribute from Unicode composition attribute.
|
|
*/
|
|
switch (dwIndex) {
|
|
case GCS_COMPATTR:
|
|
lpAttrW = (PBYTE)pCompStr + pCompStr->dwCompAttrOffset;
|
|
dwAttrLenW = pCompStr->dwCompAttrLen;
|
|
dwIndexStr = GCS_COMPSTR;
|
|
break;
|
|
case GCS_COMPREADATTR:
|
|
lpAttrW = (PBYTE)pCompStr + pCompStr->dwCompReadAttrOffset;
|
|
dwAttrLenW = pCompStr->dwCompReadAttrLen;
|
|
dwIndexStr = GCS_COMPREADSTR;
|
|
break;
|
|
#ifdef CUAS_ENABLE
|
|
case GCS_COMPGUIDATTR:
|
|
if (CtfImmIsGuidMapEnable(hImc) && (pCompStr->dwPrivateSize >= sizeof(GUIDMAPATTRIBUTE)))
|
|
{
|
|
PGUIDMAPATTRIBUTE pGuidMap = (PGUIDMAPATTRIBUTE)((PBYTE)pCompStr + pCompStr->dwPrivateOffset);
|
|
if (pGuidMap != NULL)
|
|
{
|
|
lpAttrW = (PBYTE)pGuidMap + pGuidMap->dwGuidMapAttrOffset;
|
|
dwAttrLenW = pGuidMap->dwGuidMapAttrLen;
|
|
dwIndexStr = GCS_COMPSTR;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
return (DWORD)(LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return (DWORD)(LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
break;
|
|
#endif // CUAS_ENABLE
|
|
}
|
|
|
|
if (dwAttrLenW == 0) {
|
|
/*
|
|
* No CompAttr or CompReadAttr exists, do nothing.
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
#if !defined(CUAS_ENABLE)
|
|
dwStrSize = InternalGetCompositionStringA(pCompStr,
|
|
dwIndexStr, NULL, 0, fAnsiImc, dwCodePage);
|
|
#else
|
|
dwStrSize = InternalGetCompositionStringA(hImc, pCompStr,
|
|
dwIndexStr, NULL, 0, fAnsiImc, dwCodePage);
|
|
#endif
|
|
|
|
if (dwStrSize == (DWORD)(LONG)IMM_ERROR_GENERAL) {
|
|
RIPMSG0(RIP_WARNING, "InternalGetCompositionStringA: IMM_ERROR_GENERAL.");
|
|
return (LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
|
|
/*
|
|
* Query required size or early exit on error.
|
|
*/
|
|
if (dwBufLen == 0 || dwStrSize == 0)
|
|
return dwStrSize;
|
|
|
|
lpStrA = ImmLocalAlloc(HEAP_ZERO_MEMORY, dwStrSize + sizeof(CHAR));
|
|
if (lpStrA == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalGetCompositionStringA: memory failure.");
|
|
return (LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
|
|
#if !defined(CUAS_ENABLE)
|
|
dwStrSize = InternalGetCompositionStringA(pCompStr,
|
|
dwIndexStr, lpStrA, dwStrSize, fAnsiImc, dwCodePage);
|
|
#else
|
|
dwStrSize = InternalGetCompositionStringA(hImc, pCompStr,
|
|
dwIndexStr, lpStrA, dwStrSize, fAnsiImc, dwCodePage);
|
|
#endif
|
|
|
|
if (dwStrSize == (LONG)IMM_ERROR_GENERAL) {
|
|
RIPMSG0(RIP_WARNING, "InternalGetCompositionStringA: IMM_ERROR_GENERAL.");
|
|
ImmLocalFree(lpStrA);
|
|
return (LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
|
|
lpStrT = lpStrA;
|
|
lpAttrA = (PBYTE)lpBuf;
|
|
|
|
while ((c=*lpStrT++) != '\0' && dwBufLen != 0 && dwAttrLenW-- != 0) {
|
|
if (IsDBCSLeadByteEx(dwCodePage, c)) {
|
|
if (dwBufLen >= 2) {
|
|
*lpAttrA++ = *lpAttrW;
|
|
*lpAttrA++ = *lpAttrW;
|
|
dwBufLen--;
|
|
}
|
|
else {
|
|
*lpAttrA++ = *lpAttrW;
|
|
}
|
|
lpStrT++;
|
|
}
|
|
else {
|
|
*lpAttrA++ = *lpAttrW;
|
|
}
|
|
lpAttrW++;
|
|
dwBufLen--;
|
|
}
|
|
|
|
dwBufLen = (DWORD)(lpAttrA - (PBYTE)lpBuf);
|
|
|
|
ImmLocalFree(lpStrA);
|
|
break;
|
|
}
|
|
|
|
case GCS_COMPCLAUSE:
|
|
case GCS_COMPREADCLAUSE:
|
|
case GCS_RESULTCLAUSE:
|
|
case GCS_RESULTREADCLAUSE:
|
|
{
|
|
LPWSTR lpStrW;
|
|
DWORD dwClauseLen, dwBufLenA;
|
|
LPDWORD lpdwSrc, lpdwDst;
|
|
UINT i;
|
|
|
|
/*
|
|
* Get ANSI clause from Unicode composition clause.
|
|
*/
|
|
switch (dwIndex) {
|
|
case GCS_COMPCLAUSE:
|
|
lpStrW = (LPWSTR)((PBYTE)pCompStr + pCompStr->dwCompStrOffset);
|
|
lpdwSrc = (LPDWORD)((PBYTE)pCompStr + pCompStr->dwCompClauseOffset);
|
|
dwClauseLen = pCompStr->dwCompClauseLen;
|
|
break;
|
|
case GCS_COMPREADCLAUSE:
|
|
lpStrW = (LPWSTR)((PBYTE)pCompStr + pCompStr->dwCompReadStrOffset);
|
|
lpdwSrc = (LPDWORD)((PBYTE)pCompStr + pCompStr->dwCompReadClauseOffset);
|
|
dwClauseLen = pCompStr->dwCompReadClauseLen;
|
|
break;
|
|
case GCS_RESULTCLAUSE:
|
|
lpStrW = (LPWSTR)((PBYTE)pCompStr + pCompStr->dwResultStrOffset);
|
|
lpdwSrc = (LPDWORD)((PBYTE)pCompStr + pCompStr->dwResultClauseOffset);
|
|
dwClauseLen = pCompStr->dwResultClauseLen;
|
|
break;
|
|
case GCS_RESULTREADCLAUSE:
|
|
lpStrW = (LPWSTR)((PBYTE)pCompStr + pCompStr->dwResultReadStrOffset);
|
|
lpdwSrc = (LPDWORD)((PBYTE)pCompStr + pCompStr->dwResultReadClauseOffset);
|
|
dwClauseLen = pCompStr->dwResultReadClauseLen;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Query clause length or early exit on error.
|
|
*/
|
|
if (dwBufLen == 0 || (LONG)dwClauseLen < 0) {
|
|
dwBufLen = dwClauseLen;
|
|
break;
|
|
}
|
|
|
|
lpdwDst = (LPDWORD)lpBuf;
|
|
dwBufLenA = dwBufLen / sizeof(DWORD);
|
|
|
|
for (i = 0; i < dwClauseLen / sizeof(DWORD) && dwBufLenA != 0; i++) {
|
|
*lpdwDst++ = CalcCharacterPositionWtoA(*lpdwSrc++, lpStrW, dwCodePage);
|
|
dwBufLenA--;
|
|
}
|
|
|
|
dwBufLen = i * sizeof(DWORD);
|
|
break;
|
|
}
|
|
|
|
case GCS_CURSORPOS:
|
|
case GCS_DELTASTART:
|
|
/*
|
|
* Get ANSI cursor/delta start position from Unicode composition string.
|
|
*/
|
|
switch (dwIndex) {
|
|
case GCS_CURSORPOS:
|
|
dwBufLen = pCompStr->dwCursorPos;
|
|
break;
|
|
case GCS_DELTASTART:
|
|
dwBufLen = pCompStr->dwDeltaStart;
|
|
break;
|
|
}
|
|
|
|
if ((LONG)dwBufLen > 0) {
|
|
dwBufLen = CalcCharacterPositionWtoA(dwBufLen,
|
|
(LPWSTR)((PBYTE)pCompStr + pCompStr->dwCompStrOffset),
|
|
dwCodePage);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
dwBufLen = (DWORD)(LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
|
|
return (LONG)dwBufLen;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* InternalGetCompositionStringW
|
|
*
|
|
* Internal version of ImmGetCompositionStringW.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
LONG InternalGetCompositionStringW(
|
|
#ifdef CUAS_ENABLE
|
|
HIMC hImc,
|
|
#endif // CUAS_ENABLE
|
|
PCOMPOSITIONSTRING pCompStr,
|
|
DWORD dwIndex,
|
|
LPVOID lpBuf,
|
|
DWORD dwBufLen,
|
|
BOOL fAnsiImc,
|
|
DWORD dwCodePage)
|
|
{
|
|
if (!fAnsiImc) {
|
|
/*
|
|
* Composition string in input context is of Unicode style.
|
|
*/
|
|
switch (dwIndex) {
|
|
case GCS_COMPSTR:
|
|
GetCompInfoW(CompStr);
|
|
break;
|
|
case GCS_COMPATTR: // ANSI-only
|
|
GetCompInfoA(CompAttr);
|
|
break;
|
|
case GCS_COMPREADSTR:
|
|
GetCompInfoW(CompReadStr);
|
|
break;
|
|
case GCS_COMPREADATTR: // ANSI-only
|
|
GetCompInfoA(CompReadAttr);
|
|
break;
|
|
case GCS_COMPREADCLAUSE: // ANSI-only
|
|
GetCompInfoA(CompReadClause);
|
|
break;
|
|
case GCS_CURSORPOS:
|
|
dwBufLen = (LONG)pCompStr->dwCursorPos;
|
|
break;
|
|
case GCS_DELTASTART:
|
|
dwBufLen = (LONG)pCompStr->dwDeltaStart;
|
|
break;
|
|
case GCS_RESULTSTR:
|
|
GetCompInfoW(ResultStr);
|
|
break;
|
|
case GCS_RESULTCLAUSE: // ANSI-only
|
|
GetCompInfoA(ResultClause);
|
|
break;
|
|
case GCS_RESULTREADSTR:
|
|
GetCompInfoW(ResultReadStr);
|
|
break;
|
|
case GCS_RESULTREADCLAUSE: // ANSI-only
|
|
GetCompInfoA(ResultReadClause);
|
|
break;
|
|
case GCS_COMPCLAUSE: // ANSI-only
|
|
GetCompInfoA(CompClause);
|
|
break;
|
|
#ifdef CUAS_ENABLE
|
|
case GCS_COMPGUIDATTR: // ANSI-only
|
|
if (CtfImmIsGuidMapEnable(hImc) && (pCompStr->dwPrivateSize >= sizeof(GUIDMAPATTRIBUTE)))
|
|
{
|
|
PGUIDMAPATTRIBUTE pGuidMap = (PGUIDMAPATTRIBUTE)((PBYTE)pCompStr + pCompStr->dwPrivateOffset);
|
|
if (pGuidMap != NULL)
|
|
{
|
|
GetPrivInfoA(pGuidMap, GuidMapAttr);
|
|
}
|
|
else
|
|
{
|
|
dwBufLen = (DWORD)(LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwBufLen = (DWORD)(LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
break;
|
|
#endif // CUAS_ENABLE
|
|
default:
|
|
dwBufLen = (DWORD)IMM_ERROR_GENERAL;
|
|
break;
|
|
}
|
|
|
|
return (LONG)dwBufLen;
|
|
}
|
|
|
|
/*
|
|
* Unicode caller, ANSI input context/composition string.
|
|
*/
|
|
switch (dwIndex) {
|
|
case GCS_COMPSTR:
|
|
case GCS_COMPREADSTR:
|
|
case GCS_RESULTSTR:
|
|
case GCS_RESULTREADSTR:
|
|
{
|
|
DWORD dwStrSize;
|
|
LPSTR lpStrA;
|
|
|
|
/*
|
|
* Get Unicode string from ANSI composition string.
|
|
*/
|
|
#if !defined(CUAS_ENABLE)
|
|
dwStrSize = InternalGetCompositionStringA(pCompStr, dwIndex,
|
|
NULL, 0, fAnsiImc, dwCodePage);
|
|
#else
|
|
dwStrSize = InternalGetCompositionStringA(hImc, pCompStr, dwIndex,
|
|
NULL, 0, fAnsiImc, dwCodePage);
|
|
#endif
|
|
|
|
lpStrA = ImmLocalAlloc(HEAP_ZERO_MEMORY, dwStrSize + sizeof(CHAR));
|
|
if (lpStrA == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalGetCompositionStringW: memory failure.");
|
|
return (LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
|
|
#if !defined(CUAS_ENABLE)
|
|
dwStrSize = InternalGetCompositionStringA(pCompStr, dwIndex,
|
|
lpStrA, dwStrSize, fAnsiImc, dwCodePage);
|
|
#else
|
|
dwStrSize = InternalGetCompositionStringA(hImc, pCompStr, dwIndex,
|
|
lpStrA, dwStrSize, fAnsiImc, dwCodePage);
|
|
#endif
|
|
|
|
dwBufLen = MultiByteToWideChar(dwCodePage,
|
|
(DWORD)MB_PRECOMPOSED,
|
|
lpStrA, // src
|
|
strlen(lpStrA),
|
|
(LPWSTR)lpBuf, // dest
|
|
(INT)dwBufLen);
|
|
|
|
dwBufLen *= sizeof(WCHAR); // return number of bytes required.
|
|
|
|
ImmLocalFree(lpStrA);
|
|
break;
|
|
}
|
|
|
|
case GCS_COMPATTR:
|
|
case GCS_COMPREADATTR:
|
|
#ifdef CUAS_ENABLE
|
|
case GCS_COMPGUIDATTR:
|
|
#endif // CUAS_ENABLE
|
|
{
|
|
DWORD dwAttrLenA, dwIndexStr, dwStrSize;
|
|
PBYTE lpAttrA, lpAttrW;
|
|
LPWSTR lpStrW, lpStrT;
|
|
ULONG MultiByteSize;
|
|
WCHAR wc;
|
|
|
|
/*
|
|
* Get Unicode attribute from ANSI composition attribute.
|
|
*/
|
|
switch (dwIndex) {
|
|
case GCS_COMPATTR:
|
|
lpAttrA = (PBYTE)pCompStr + pCompStr->dwCompAttrOffset;
|
|
dwAttrLenA = pCompStr->dwCompAttrLen;
|
|
dwIndexStr = GCS_COMPSTR;
|
|
break;
|
|
case GCS_COMPREADATTR:
|
|
lpAttrA = (PBYTE)pCompStr + pCompStr->dwCompReadAttrOffset;
|
|
dwAttrLenA = pCompStr->dwCompReadAttrLen;
|
|
dwIndexStr = GCS_COMPREADSTR;
|
|
break;
|
|
#ifdef CUAS_ENABLE
|
|
case GCS_COMPGUIDATTR:
|
|
if (CtfImmIsGuidMapEnable(hImc) && (pCompStr->dwPrivateSize >= sizeof(GUIDMAPATTRIBUTE)))
|
|
{
|
|
PGUIDMAPATTRIBUTE pGuidMap = (PGUIDMAPATTRIBUTE)((PBYTE)pCompStr + pCompStr->dwPrivateOffset);
|
|
if (pGuidMap != NULL)
|
|
{
|
|
lpAttrA = (PBYTE)pGuidMap + pGuidMap->dwGuidMapAttrOffset;
|
|
dwAttrLenA = pGuidMap->dwGuidMapAttrLen;
|
|
dwIndexStr = GCS_COMPSTR;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
return (DWORD)(LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return (DWORD)(LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
break;
|
|
#endif // CUAS_ENABLE
|
|
}
|
|
|
|
if (dwAttrLenA == 0) {
|
|
/*
|
|
* No CompAttr or CompReadAttr exists, do nothing.
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
#if !defined(CUAS_ENABLE)
|
|
dwStrSize = InternalGetCompositionStringW(pCompStr,
|
|
dwIndexStr, NULL, 0, fAnsiImc, dwCodePage);
|
|
#else
|
|
dwStrSize = InternalGetCompositionStringW(hImc, pCompStr,
|
|
dwIndexStr, NULL, 0, fAnsiImc, dwCodePage);
|
|
#endif
|
|
|
|
if (dwStrSize == (DWORD)(LONG)IMM_ERROR_GENERAL) {
|
|
RIPMSG0(RIP_WARNING, "InternalGetCompositionStringA: IMM_ERROR_GENERAL.");
|
|
return (LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
|
|
/*
|
|
* Query required size or early exit on error.
|
|
*/
|
|
if (dwBufLen == 0 || dwStrSize == 0)
|
|
return dwStrSize / sizeof(WCHAR);
|
|
|
|
lpStrW = ImmLocalAlloc(HEAP_ZERO_MEMORY, dwStrSize + sizeof(WCHAR));
|
|
if (lpStrW == NULL) {
|
|
RIPMSG0(RIP_WARNING, "InternalGetCompositionStringW: memory failure.");
|
|
return (LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
|
|
#if !defined(CUAS_ENABLE)
|
|
dwStrSize = InternalGetCompositionStringW(pCompStr,
|
|
dwIndexStr, lpStrW, dwStrSize, fAnsiImc, dwCodePage);
|
|
#else
|
|
dwStrSize = InternalGetCompositionStringW(hImc, pCompStr,
|
|
dwIndexStr, lpStrW, dwStrSize, fAnsiImc, dwCodePage);
|
|
#endif
|
|
|
|
if (dwStrSize == (LONG)IMM_ERROR_GENERAL) {
|
|
RIPMSG0(RIP_WARNING, "InternalGetCompositionStringA: IMM_ERROR_GENERAL.");
|
|
ImmLocalFree(lpStrW);
|
|
return (LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
|
|
lpStrT = lpStrW;
|
|
lpAttrW = (PBYTE)lpBuf;
|
|
|
|
while ((wc=*lpStrT++) != L'\0' && dwBufLen != 0 && dwAttrLenA-- != 0) {
|
|
MultiByteSize = UnicodeToMultiByteSize(dwCodePage, &wc);
|
|
if (MultiByteSize == 2 && dwAttrLenA != 0) {
|
|
*lpAttrW++ = *lpAttrA++;
|
|
dwAttrLenA--;
|
|
}
|
|
else {
|
|
*lpAttrW++ = *lpAttrA;
|
|
}
|
|
lpAttrA++;
|
|
dwBufLen--;
|
|
}
|
|
|
|
dwBufLen = (DWORD)(lpAttrW - (PBYTE)lpBuf);
|
|
|
|
ImmLocalFree(lpStrW);
|
|
break;
|
|
}
|
|
|
|
case GCS_COMPCLAUSE:
|
|
case GCS_COMPREADCLAUSE:
|
|
case GCS_RESULTCLAUSE:
|
|
case GCS_RESULTREADCLAUSE:
|
|
{
|
|
LPSTR lpStrA;
|
|
DWORD dwClauseLen, dwBufLenW;
|
|
LPDWORD lpdwSrc, lpdwDst;
|
|
UINT i;
|
|
|
|
/*
|
|
* Get Unicode clause from ANSI composition clause.
|
|
*/
|
|
switch (dwIndex) {
|
|
case GCS_COMPCLAUSE:
|
|
lpStrA = (LPSTR)((PBYTE)pCompStr + pCompStr->dwCompStrOffset);
|
|
lpdwSrc = (LPDWORD)((PBYTE)pCompStr + pCompStr->dwCompClauseOffset);
|
|
dwClauseLen = pCompStr->dwCompClauseLen;
|
|
break;
|
|
case GCS_COMPREADCLAUSE:
|
|
lpStrA = (LPSTR)((PBYTE)pCompStr + pCompStr->dwCompReadStrOffset);
|
|
lpdwSrc = (LPDWORD)((PBYTE)pCompStr + pCompStr->dwCompReadClauseOffset);
|
|
dwClauseLen = pCompStr->dwCompReadClauseLen;
|
|
break;
|
|
case GCS_RESULTCLAUSE:
|
|
lpStrA = (LPSTR)((PBYTE)pCompStr + pCompStr->dwResultStrOffset);
|
|
lpdwSrc = (LPDWORD)((PBYTE)pCompStr + pCompStr->dwResultClauseOffset);
|
|
dwClauseLen = pCompStr->dwResultClauseLen;
|
|
break;
|
|
case GCS_RESULTREADCLAUSE:
|
|
lpStrA = (LPSTR)((PBYTE)pCompStr + pCompStr->dwResultReadStrOffset);
|
|
lpdwSrc = (LPDWORD)((PBYTE)pCompStr + pCompStr->dwResultReadClauseOffset);
|
|
dwClauseLen = pCompStr->dwResultReadClauseLen;
|
|
break;
|
|
}
|
|
|
|
|
|
/*
|
|
* Query clause length or early exit on error.
|
|
*/
|
|
if (dwBufLen == 0 || (LONG)dwClauseLen < 0) {
|
|
dwBufLen = dwClauseLen;
|
|
break;
|
|
}
|
|
|
|
lpdwDst = (LPDWORD)lpBuf;
|
|
dwBufLenW = dwBufLen / sizeof(DWORD);
|
|
|
|
for (i = 0; i < dwClauseLen / sizeof(DWORD) && dwBufLenW != 0; i++) {
|
|
*lpdwDst++ = CalcCharacterPositionAtoW(*lpdwSrc++, lpStrA, dwCodePage);
|
|
dwBufLenW--;
|
|
}
|
|
|
|
dwBufLen = i * sizeof(DWORD);
|
|
break;
|
|
}
|
|
|
|
case GCS_CURSORPOS:
|
|
case GCS_DELTASTART:
|
|
/*
|
|
* Get Unicode cursor/delta start position from ANSI composition string.
|
|
*/
|
|
switch (dwIndex) {
|
|
case GCS_CURSORPOS:
|
|
dwBufLen = pCompStr->dwCursorPos;
|
|
break;
|
|
case GCS_DELTASTART:
|
|
dwBufLen = pCompStr->dwDeltaStart;
|
|
break;
|
|
}
|
|
|
|
if ((LONG)dwBufLen > 0) {
|
|
dwBufLen = CalcCharacterPositionAtoW(dwBufLen,
|
|
(LPSTR)((PBYTE)pCompStr + pCompStr->dwCompStrOffset),
|
|
dwCodePage);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
dwBufLen = (DWORD)(LONG)IMM_ERROR_GENERAL;
|
|
}
|
|
|
|
return (LONG)dwBufLen;
|
|
}
|
|
|
|
|
|
DWORD InternalGetCandidateListAtoW(
|
|
LPCANDIDATELIST lpCandListA,
|
|
LPCANDIDATELIST lpCandListW,
|
|
DWORD dwBufLen,
|
|
DWORD dwCodePage)
|
|
{
|
|
LPWSTR lpCandStrW;
|
|
LPSTR lpCandStrA;
|
|
INT i, j;
|
|
DWORD dwCandListLen;
|
|
|
|
dwCandListLen = sizeof(CANDIDATELIST);
|
|
|
|
/*
|
|
* CANDIDATELIST has already contained the dwOffset[0]
|
|
*/
|
|
if (lpCandListA->dwCount > 0)
|
|
dwCandListLen += sizeof(DWORD) * (lpCandListA->dwCount - 1);
|
|
|
|
for (i = 0; i < (INT)lpCandListA->dwCount; i++) {
|
|
|
|
lpCandStrA = (LPSTR)((LPBYTE)lpCandListA + lpCandListA->dwOffset[i]);
|
|
|
|
j = MultiByteToWideChar(dwCodePage,
|
|
(DWORD)MB_PRECOMPOSED,
|
|
lpCandStrA,
|
|
-1,
|
|
(LPWSTR)NULL,
|
|
0);
|
|
|
|
dwCandListLen += (j * sizeof(WCHAR));
|
|
}
|
|
|
|
dwCandListLen = DWORD_ALIGN(dwCandListLen);
|
|
|
|
if (dwBufLen == 0)
|
|
return dwCandListLen;
|
|
|
|
if (dwBufLen < dwCandListLen) {
|
|
RIPMSG0(RIP_WARNING, "InternalGetCandidateListAtoW: dwBufLen too small.");
|
|
return 0;
|
|
}
|
|
|
|
lpCandListW->dwSize = dwBufLen;
|
|
lpCandListW->dwStyle = lpCandListA->dwStyle;
|
|
lpCandListW->dwCount = lpCandListA->dwCount;
|
|
lpCandListW->dwSelection = lpCandListA->dwSelection;
|
|
lpCandListW->dwPageStart = lpCandListA->dwPageStart;
|
|
lpCandListW->dwPageSize = lpCandListA->dwPageSize;
|
|
lpCandListW->dwOffset[0] = sizeof(CANDIDATELIST);
|
|
if (lpCandListW->dwCount > 0)
|
|
lpCandListW->dwOffset[0] += sizeof(DWORD) * (lpCandListW->dwCount - 1);
|
|
|
|
dwCandListLen = dwBufLen - lpCandListW->dwOffset[0];
|
|
|
|
for (i = 0; i < (INT)lpCandListW->dwCount; i++) {
|
|
|
|
lpCandStrA = (LPSTR) ((LPBYTE)lpCandListA + lpCandListA->dwOffset[i]);
|
|
lpCandStrW = (LPWSTR)((LPBYTE)lpCandListW + lpCandListW->dwOffset[i]);
|
|
|
|
j = MultiByteToWideChar(dwCodePage,
|
|
(DWORD)MB_PRECOMPOSED,
|
|
lpCandStrA,
|
|
-1,
|
|
lpCandStrW,
|
|
(INT)dwCandListLen/sizeof(WCHAR));
|
|
|
|
dwCandListLen -= (j * sizeof(WCHAR));
|
|
|
|
if (i < (INT)lpCandListW->dwCount - 1)
|
|
lpCandListW->dwOffset[i+1] = lpCandListW->dwOffset[i] + j * sizeof(WCHAR);
|
|
}
|
|
|
|
return dwBufLen;
|
|
}
|
|
|
|
|
|
DWORD InternalGetCandidateListWtoA(
|
|
LPCANDIDATELIST lpCandListW,
|
|
LPCANDIDATELIST lpCandListA,
|
|
DWORD dwBufLen,
|
|
DWORD dwCodePage)
|
|
{
|
|
LPWSTR lpCandStrW;
|
|
LPSTR lpCandStrA;
|
|
INT i, j;
|
|
DWORD dwCandListLen;
|
|
BOOL bUDC;
|
|
|
|
dwCandListLen = sizeof(CANDIDATELIST);
|
|
|
|
/*
|
|
* CANDIDATELIST has already contained the dwOffset[0]
|
|
*/
|
|
if (lpCandListW->dwCount > 0)
|
|
dwCandListLen += sizeof(DWORD) * (lpCandListW->dwCount - 1);
|
|
|
|
for (i = 0; i < (INT)lpCandListW->dwCount; i++) {
|
|
|
|
lpCandStrW = (LPWSTR)((LPBYTE)lpCandListW + lpCandListW->dwOffset[i]);
|
|
|
|
j = WideCharToMultiByte(dwCodePage,
|
|
(DWORD)0,
|
|
lpCandStrW,
|
|
-1,
|
|
(LPSTR)NULL,
|
|
(INT)0,
|
|
(LPSTR)NULL,
|
|
(LPBOOL)&bUDC);
|
|
|
|
dwCandListLen += (j * sizeof(CHAR));
|
|
}
|
|
|
|
dwCandListLen = DWORD_ALIGN(dwCandListLen);
|
|
|
|
if (dwBufLen == 0)
|
|
return dwCandListLen;
|
|
|
|
if (dwBufLen < dwCandListLen) {
|
|
RIPMSG0(RIP_WARNING, "InternalGetCandidateListWtoA: dwBufLen too small.");
|
|
return 0;
|
|
}
|
|
|
|
lpCandListA->dwSize = dwBufLen;
|
|
lpCandListA->dwStyle = lpCandListW->dwStyle;
|
|
lpCandListA->dwCount = lpCandListW->dwCount;
|
|
lpCandListA->dwSelection = lpCandListW->dwSelection;
|
|
lpCandListA->dwPageStart = lpCandListW->dwPageStart;
|
|
lpCandListA->dwPageSize = lpCandListW->dwPageSize;
|
|
lpCandListA->dwOffset[0] = sizeof(CANDIDATELIST);
|
|
if (lpCandListA->dwCount > 0)
|
|
lpCandListA->dwOffset[0] += sizeof(DWORD) * (lpCandListA->dwCount - 1);
|
|
|
|
dwCandListLen = dwBufLen - lpCandListA->dwOffset[0];
|
|
|
|
for (i = 0; i < (INT)lpCandListA->dwCount; i++) {
|
|
|
|
lpCandStrA = (LPSTR) ((LPBYTE)lpCandListA + lpCandListA->dwOffset[i]);
|
|
lpCandStrW = (LPWSTR)((LPBYTE)lpCandListW + lpCandListW->dwOffset[i]);
|
|
|
|
j = WideCharToMultiByte(dwCodePage,
|
|
(DWORD)0,
|
|
lpCandStrW,
|
|
-1,
|
|
(LPSTR)lpCandStrA,
|
|
(INT)dwCandListLen,
|
|
(LPSTR)NULL,
|
|
(LPBOOL)&bUDC);
|
|
|
|
dwCandListLen -= (j * sizeof(CHAR));
|
|
|
|
if (i < (INT)lpCandListA->dwCount - 1)
|
|
lpCandListA->dwOffset[i+1] = lpCandListA->dwOffset[i] + j * sizeof(CHAR);
|
|
}
|
|
|
|
return dwBufLen;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CalcCharacterPositionAtoW
|
|
*
|
|
* Calculate Unicode character position to ANSI character position.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD CalcCharacterPositionAtoW(
|
|
DWORD dwCharPosA,
|
|
LPSTR lpszCharStr,
|
|
DWORD dwCodePage)
|
|
{
|
|
DWORD dwCharPosW = 0;
|
|
|
|
while (dwCharPosA != 0) {
|
|
if (IsDBCSLeadByteEx(dwCodePage, *lpszCharStr)) {
|
|
if (dwCharPosA >= 2) {
|
|
dwCharPosA -= 2;
|
|
}
|
|
else {
|
|
dwCharPosA--;
|
|
}
|
|
lpszCharStr += 2;
|
|
}
|
|
else {
|
|
dwCharPosA--;
|
|
lpszCharStr++;
|
|
}
|
|
dwCharPosW++;
|
|
}
|
|
|
|
return dwCharPosW;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* CalcCharacterPositionWtoA
|
|
*
|
|
* Calculate ANSI character position to Unicode character position.
|
|
*
|
|
* History:
|
|
* 28-Feb-1995 wkwok Created
|
|
\***************************************************************************/
|
|
|
|
DWORD CalcCharacterPositionWtoA(
|
|
DWORD dwCharPosW,
|
|
LPWSTR lpwszCharStr,
|
|
DWORD dwCodePage)
|
|
{
|
|
DWORD dwCharPosA = 0;
|
|
ULONG MultiByteSize;
|
|
|
|
while (dwCharPosW != 0) {
|
|
MultiByteSize = UnicodeToMultiByteSize(dwCodePage, lpwszCharStr);
|
|
if (MultiByteSize == 2) {
|
|
dwCharPosA += 2;
|
|
}
|
|
else {
|
|
dwCharPosA++;
|
|
}
|
|
dwCharPosW--;
|
|
lpwszCharStr++;
|
|
}
|
|
|
|
return dwCharPosA;
|
|
}
|
|
|
|
|
|
VOID LFontAtoLFontW(
|
|
LPLOGFONTA lpLogFontA,
|
|
LPLOGFONTW lpLogFontW)
|
|
{
|
|
INT i;
|
|
|
|
RtlCopyMemory(lpLogFontW, lpLogFontA, sizeof(LOGFONTA)-LF_FACESIZE);
|
|
|
|
i = MultiByteToWideChar(CP_ACP, // Note: font face name should use ACP for A/W conversion.
|
|
MB_PRECOMPOSED,
|
|
lpLogFontA->lfFaceName,
|
|
strlen(lpLogFontA->lfFaceName),
|
|
lpLogFontW->lfFaceName,
|
|
LF_FACESIZE);
|
|
|
|
lpLogFontW->lfFaceName[i] = L'\0';
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID LFontWtoLFontA(
|
|
LPLOGFONTW lpLogFontW,
|
|
LPLOGFONTA lpLogFontA)
|
|
{
|
|
INT i;
|
|
BOOL bUDC;
|
|
|
|
RtlCopyMemory(lpLogFontA, lpLogFontW, sizeof(LOGFONTA)-LF_FACESIZE);
|
|
|
|
i = WideCharToMultiByte(CP_ACP, // Note: font face name should use ACP for A/W conversion.
|
|
0,
|
|
lpLogFontW->lfFaceName,
|
|
wcslen(lpLogFontW->lfFaceName),
|
|
lpLogFontA->lfFaceName,
|
|
LF_FACESIZE,
|
|
(LPSTR)NULL,
|
|
&bUDC);
|
|
|
|
lpLogFontA->lfFaceName[i] = '\0';
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL MakeIMENotify(
|
|
HIMC hImc,
|
|
HWND hWnd,
|
|
DWORD dwAction,
|
|
DWORD dwIndex,
|
|
DWORD dwValue,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
PIMEDPI pImeDpi;
|
|
DWORD dwThreadId;
|
|
|
|
#ifdef LATER
|
|
// implement MakeIMENotifyEvent() later
|
|
#endif
|
|
|
|
if (dwAction != 0 && (dwThreadId = GetInputContextThread(hImc)) != 0) {
|
|
|
|
pImeDpi = ImmLockImeDpi(GetKeyboardLayout(dwThreadId));
|
|
|
|
if (pImeDpi != NULL) {
|
|
(*pImeDpi->pfn.NotifyIME)(hImc, dwAction, dwIndex, dwValue);
|
|
ImmUnlockImeDpi(pImeDpi);
|
|
}
|
|
}
|
|
|
|
if (hWnd != NULL && wParam != 0)
|
|
SendMessage(hWnd, WM_IME_NOTIFY, wParam, lParam);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Reconversion support
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
typedef enum {FROM_IME, FROM_APP} REQ_CALLER;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// ImmGetReconvertTotalSize
|
|
//
|
|
// calculate the appropriate size of the buffer, based on caller/ansi information
|
|
//
|
|
// History:
|
|
// 28-Feb-1997 hiroyama Created
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD ImmGetReconvertTotalSize(DWORD dwSize, REQ_CALLER eCaller, BOOL bAnsiTarget)
|
|
{
|
|
if (dwSize < sizeof(RECONVERTSTRING)) {
|
|
return 0;
|
|
}
|
|
if (bAnsiTarget) {
|
|
dwSize -= sizeof(RECONVERTSTRING);
|
|
if (eCaller == FROM_IME) {
|
|
dwSize /= 2;
|
|
} else {
|
|
dwSize *= 2;
|
|
}
|
|
dwSize += sizeof(RECONVERTSTRING);
|
|
}
|
|
return dwSize;
|
|
}
|
|
|
|
DWORD ImmReconversionWorker(
|
|
LPRECONVERTSTRING lpRecTo,
|
|
LPRECONVERTSTRING lpRecFrom,
|
|
BOOL bToAnsi,
|
|
DWORD dwCodePage)
|
|
{
|
|
INT i;
|
|
DWORD dwSize = 0;
|
|
|
|
UserAssert(lpRecTo);
|
|
UserAssert(lpRecFrom);
|
|
|
|
if (lpRecFrom->dwVersion != 0 || lpRecTo->dwVersion != 0) {
|
|
RIPMSG0(RIP_WARNING, "ImmReconversionWorker: dwVersion in lpRecTo or lpRecFrom is incorrect.");
|
|
return 0;
|
|
}
|
|
// Note:
|
|
// In any IME related structures, use the following principal.
|
|
// 1) xxxStrOffset is an actual offset, i.e. byte count.
|
|
// 2) xxxStrLen is a number of characters, i.e. TCHAR count.
|
|
//
|
|
// CalcCharacterPositionXtoY() takes TCHAR count so that we
|
|
// need to adjust xxxStrOffset if it's being converted. But you
|
|
// should be careful, because the actual position of the string
|
|
// is always at something like (LPBYTE)lpStruc + lpStruc->dwStrOffset.
|
|
//
|
|
if (bToAnsi) {
|
|
// Convert W to A
|
|
lpRecTo->dwStrOffset = sizeof *lpRecTo;
|
|
i = WideCharToMultiByte(dwCodePage,
|
|
(DWORD)0,
|
|
(LPWSTR)((LPSTR)lpRecFrom + lpRecFrom->dwStrOffset), // src
|
|
(INT)lpRecFrom->dwStrLen,
|
|
(LPSTR)lpRecTo + lpRecTo->dwStrOffset, // dest
|
|
(INT)lpRecFrom->dwStrLen * DBCS_CHARSIZE,
|
|
(LPSTR)NULL,
|
|
(LPBOOL)NULL);
|
|
lpRecTo->dwCompStrOffset =
|
|
CalcCharacterPositionWtoA(lpRecFrom->dwCompStrOffset / sizeof(WCHAR),
|
|
(LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset),
|
|
dwCodePage)
|
|
* sizeof(CHAR);
|
|
|
|
lpRecTo->dwCompStrLen =
|
|
(CalcCharacterPositionWtoA(lpRecFrom->dwCompStrOffset / sizeof(WCHAR) +
|
|
lpRecFrom->dwCompStrLen,
|
|
(LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset),
|
|
dwCodePage)
|
|
* sizeof(CHAR))
|
|
- lpRecTo->dwCompStrOffset;
|
|
|
|
lpRecTo->dwTargetStrOffset =
|
|
CalcCharacterPositionWtoA(lpRecFrom->dwTargetStrOffset / sizeof(WCHAR),
|
|
(LPWSTR)((LPBYTE)lpRecFrom +
|
|
lpRecFrom->dwStrOffset),
|
|
dwCodePage)
|
|
* sizeof(CHAR);
|
|
|
|
lpRecTo->dwTargetStrLen =
|
|
(CalcCharacterPositionWtoA(lpRecFrom->dwTargetStrOffset / sizeof(WCHAR) +
|
|
lpRecFrom->dwTargetStrLen,
|
|
(LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset),
|
|
dwCodePage)
|
|
* sizeof(CHAR))
|
|
- lpRecTo->dwTargetStrOffset;
|
|
|
|
((LPSTR)lpRecTo)[lpRecTo->dwStrOffset + i] = '\0';
|
|
lpRecTo->dwStrLen = i * sizeof(CHAR);
|
|
|
|
dwSize = sizeof(RECONVERTSTRING) + ((i + 1) * sizeof(CHAR));
|
|
|
|
} else {
|
|
|
|
// AtoW
|
|
lpRecTo->dwStrOffset = sizeof *lpRecTo;
|
|
i = MultiByteToWideChar(dwCodePage,
|
|
(DWORD)MB_PRECOMPOSED,
|
|
(LPSTR)lpRecFrom + lpRecFrom->dwStrOffset, // src
|
|
(INT)lpRecFrom->dwStrLen,
|
|
(LPWSTR)((LPSTR)lpRecTo + lpRecTo->dwStrOffset), // dest
|
|
(INT)lpRecFrom->dwStrLen);
|
|
|
|
lpRecTo->dwCompStrOffset =
|
|
CalcCharacterPositionAtoW(lpRecFrom->dwCompStrOffset,
|
|
(LPSTR)lpRecFrom + lpRecFrom->dwStrOffset,
|
|
dwCodePage) * sizeof(WCHAR);
|
|
|
|
lpRecTo->dwCompStrLen =
|
|
((CalcCharacterPositionAtoW(lpRecFrom->dwCompStrOffset +
|
|
lpRecFrom->dwCompStrLen,
|
|
(LPSTR)lpRecFrom + lpRecFrom->dwStrOffset,
|
|
dwCodePage) * sizeof(WCHAR))
|
|
- lpRecTo->dwCompStrOffset) / sizeof(WCHAR);
|
|
|
|
lpRecTo->dwTargetStrOffset =
|
|
CalcCharacterPositionAtoW(lpRecFrom->dwTargetStrOffset,
|
|
(LPSTR)lpRecFrom + lpRecFrom->dwStrOffset,
|
|
dwCodePage) * sizeof(WCHAR);
|
|
|
|
lpRecTo->dwTargetStrLen =
|
|
((CalcCharacterPositionAtoW(lpRecFrom->dwTargetStrOffset +
|
|
lpRecFrom->dwTargetStrLen,
|
|
(LPSTR)lpRecFrom + lpRecFrom->dwStrOffset,
|
|
dwCodePage) * sizeof(WCHAR))
|
|
- lpRecTo->dwTargetStrOffset) / sizeof(WCHAR);
|
|
|
|
lpRecTo->dwStrLen = i; // Length is TCHAR count.
|
|
if (lpRecTo->dwSize >= (DWORD)(lpRecTo->dwStrOffset + (i + 1)* sizeof(WCHAR))) {
|
|
LPWSTR lpW = (LPWSTR)((LPSTR)lpRecTo + lpRecTo->dwStrOffset);
|
|
lpW[i] = L'\0';
|
|
}
|
|
dwSize = sizeof(RECONVERTSTRING) + ((i + 1) * sizeof(WCHAR));
|
|
}
|
|
return dwSize;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// ImmRequestMessageWorker
|
|
//
|
|
// worker function for WM_IME_REQUEST message
|
|
//
|
|
// History:
|
|
// 30-Mar-1997 hiroyama Created
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
LRESULT ImmRequestMessageWorker(HIMC hIMC, PWND pwnd, WPARAM wParam, LPARAM lParam, BOOL bAnsiOrigin)
|
|
{
|
|
// the (least) size of the structure given in lParam: for valid pointer checking
|
|
static CONST int nReqBufSize[][7] = {
|
|
{ // sizes if IME is UNICODE
|
|
sizeof(COMPOSITIONFORM), // IMR_COMPOSITIONWINDOW
|
|
sizeof(CANDIDATEFORM), // IMR_CANDIDATEWINDOW
|
|
sizeof(LOGFONTW), // IMR_COMPOSITIONFONT
|
|
sizeof(RECONVERTSTRING), // IMR_RECONVERTSTRING
|
|
sizeof(RECONVERTSTRING), // IMR_CONFIRMRECONVERTSTRING
|
|
sizeof(IMECHARPOSITION), // IMR_QUERYCHARPOSITION
|
|
sizeof(RECONVERTSTRING), // IMR_DOCUMENTFEED
|
|
},
|
|
{ // sizes if IME is ANSI
|
|
sizeof(COMPOSITIONFORM), // IMR_COMPOSITIONWINDOW
|
|
sizeof(CANDIDATEFORM), // IMR_CANDIDATEWINDOW
|
|
sizeof(LOGFONTA), // IMR_COMPOSITIONFONT
|
|
sizeof(RECONVERTSTRING), // IMR_RECONVERTSTRING
|
|
sizeof(RECONVERTSTRING), // IMR_CONFIRMRECONVERTSTRING
|
|
sizeof(IMECHARPOSITION), // IMR_QUERYCHARPOSITION
|
|
sizeof(RECONVERTSTRING), // IMR_DOCUMENTFEED
|
|
}
|
|
};
|
|
LRESULT lRet = 0L;
|
|
CONST BOOLEAN bAnsiTarget = !!TestWF(pwnd, WFANSIPROC); // TRUE if the target Window Proc is ANSI
|
|
LPBYTE lpReq = (LPBYTE)lParam; // return buffer (maybe allocated buffer)
|
|
LPBYTE lpNew = NULL; // buffer allocated within this function
|
|
DWORD dwSaveCharPos;
|
|
PCLIENTIMC pClientImc;
|
|
DWORD dwCodePage;
|
|
|
|
#define SEND_MESSAGE(bAnsi) ((bAnsi) ? SendMessageA : SendMessageW)
|
|
|
|
//////////////////////////////////////////////
|
|
// Parameter checking
|
|
|
|
// check wParam as sub messages
|
|
if (wParam == 0 || wParam > IMR_DOCUMENTFEED) { // wParam is not a proper sub message
|
|
RIPMSG1(RIP_WARNING, "ImmRequestMessageWorker: wParam(%lx) out of range.", wParam);
|
|
return 0L;
|
|
}
|
|
|
|
// Check if the pointer which is given through lParam points the proper memory block.
|
|
UserAssert(bAnsiOrigin == 0 || bAnsiOrigin == 1); // we'll use bAnsiOrigin as an index
|
|
|
|
// The first sub message IMR_COMPOSITIONWINDOW is 1, so substract 1 from wParam
|
|
if (lpReq && IsBadWritePtr(lpReq, nReqBufSize[bAnsiOrigin][wParam - 1])) {
|
|
RIPMSG0(RIP_WARNING, "ImmRequestMessageWorker: Bad pointer passed from IME to write");
|
|
return 0L;
|
|
}
|
|
|
|
// check the lpReq(==lParam): the spec does not allow lParam as NULL
|
|
// except IMR_RECONVERTSTRING and IMR_DOCUMENTFEED
|
|
if (wParam == IMR_RECONVERTSTRING || wParam == IMR_DOCUMENTFEED) {
|
|
//
|
|
// check version number
|
|
//
|
|
if (lpReq != NULL) {
|
|
LPRECONVERTSTRING lpReconv = (LPRECONVERTSTRING)lParam;
|
|
if (lpReconv->dwVersion != 0) {
|
|
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid version number: %d",
|
|
lpReconv->dwVersion);
|
|
return 0L;
|
|
}
|
|
if (lpReconv->dwSize < sizeof(RECONVERTSTRING)) {
|
|
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid dwSize: %d",
|
|
lpReconv->dwSize);
|
|
return 0L;
|
|
}
|
|
}
|
|
} else if (wParam == IMR_CONFIRMRECONVERTSTRING) {
|
|
// check if lParam is not NULL, and version of the structure is correct.
|
|
if (lpReq == NULL || ((LPRECONVERTSTRING)lpReq)->dwVersion != 0) {
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Invalid argument or invalid version number");
|
|
return 0L;
|
|
}
|
|
} else if (lpReq == NULL) {
|
|
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING,
|
|
"ImmRequestMessageWorker: lParam should not be NULL with this wParam(%lx).",
|
|
wParam);
|
|
return 0L;
|
|
}
|
|
// end parameter checking
|
|
////////////////////////////////////////////
|
|
|
|
pClientImc = ImmLockClientImc(hIMC);
|
|
if (pClientImc != NULL) {
|
|
dwCodePage = CImcCodePage(pClientImc);
|
|
ImmUnlockClientImc(pClientImc);
|
|
}
|
|
else {
|
|
dwCodePage = CP_ACP;
|
|
}
|
|
|
|
// allocate and prepare required buffer if we need A/W conversion
|
|
switch (wParam) {
|
|
case IMR_CONFIRMRECONVERTSTRING:
|
|
case IMR_RECONVERTSTRING:
|
|
case IMR_DOCUMENTFEED:
|
|
if (bAnsiOrigin != bAnsiTarget) {
|
|
if (lpReq != NULL) {
|
|
// IME wants not only the buffer size but the real reconversion information
|
|
DWORD dwSize = ImmGetReconvertTotalSize(((LPRECONVERTSTRING)lpReq)->dwSize, FROM_IME, bAnsiTarget);
|
|
LPRECONVERTSTRING lpReconv;
|
|
|
|
lpNew = ImmLocalAlloc(0, dwSize + sizeof(WCHAR));
|
|
if (lpNew == NULL) {
|
|
RIPMSG0(RIP_WARNING, "ImmRequestMessageWorker: failed to allocate a buffer for reconversion.");
|
|
return 0L;
|
|
}
|
|
lpReconv = (LPRECONVERTSTRING)lpNew;
|
|
// setup the information in the allocated structure
|
|
lpReconv->dwVersion = 0;
|
|
lpReconv->dwSize = dwSize;
|
|
|
|
//
|
|
// if it's confirmation message, we need to translate the contents
|
|
//
|
|
if (wParam == IMR_CONFIRMRECONVERTSTRING) {
|
|
ImmReconversionWorker(lpReconv, (LPRECONVERTSTRING)lParam, bAnsiTarget, dwCodePage);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IMR_COMPOSITIONFONT:
|
|
UserAssert(lpReq != NULL); // has been checked so far
|
|
if (bAnsiOrigin != bAnsiTarget) {
|
|
if (bAnsiTarget) {
|
|
lpNew = ImmLocalAlloc(0, sizeof(LOGFONTA));
|
|
} else {
|
|
lpNew = ImmLocalAlloc(0, sizeof(LOGFONTW));
|
|
}
|
|
if (lpNew == NULL) {
|
|
RIPMSG0(RIP_WARNING, "ImmRequestMessageWorker: IMR_COMPOSITIONFONT: failed to allocate memory for A/W conversion.");
|
|
return 0L;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IMR_QUERYCHARPOSITION:
|
|
UserAssert(lpReq != NULL);
|
|
if (bAnsiOrigin != bAnsiTarget) {
|
|
#define lpIMEPOS ((LPIMECHARPOSITION)lParam)
|
|
LPVOID lpstr;
|
|
DWORD dwLen;
|
|
|
|
dwSaveCharPos = lpIMEPOS->dwCharPos;
|
|
|
|
dwLen = (!bAnsiOrigin ? ImmGetCompositionStringW : ImmGetCompositionStringA)(hIMC, GCS_COMPSTR, 0, 0);
|
|
if (dwLen == 0) {
|
|
RIPMSG0(RIP_WARNING, "ImmRequestMessageWorker: IMR_QUERYCHARPOSITION no compositiong string.");
|
|
return 0L;
|
|
}
|
|
|
|
lpstr = ImmLocalAlloc(0, (dwLen + 1) * (!bAnsiOrigin ? sizeof(WCHAR) : sizeof(CHAR)));
|
|
if (lpstr == NULL) {
|
|
RIPMSG0(RIP_WARNING, "ImmRequestMessageWorker: IMR_QUERYCHARPOSITION: failed to allocate memory for A/W conversion.");
|
|
return 0L;
|
|
}
|
|
|
|
(!bAnsiOrigin ? ImmGetCompositionStringW : ImmGetCompositionStringA)(hIMC, GCS_COMPSTR, lpstr, dwLen);
|
|
if (bAnsiTarget) {
|
|
lpIMEPOS->dwCharPos = CalcCharacterPositionWtoA(lpIMEPOS->dwCharPos, lpstr, dwCodePage);
|
|
} else {
|
|
lpIMEPOS->dwCharPos = CalcCharacterPositionAtoW(lpIMEPOS->dwCharPos, lpstr, dwCodePage);
|
|
}
|
|
|
|
ImmLocalFree(lpstr);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
UserAssert(lpReq != NULL); // has been checked so far
|
|
break;
|
|
}
|
|
|
|
if (lpNew) {
|
|
// if we allocated the buffer, let lpReq point it; lpNew is used later to free memory
|
|
lpReq = lpNew;
|
|
}
|
|
|
|
//////////////////////////////////
|
|
lRet = SEND_MESSAGE(bAnsiTarget)(HW(pwnd), WM_IME_REQUEST, wParam, (LPARAM)lpReq);
|
|
//////////////////////////////////
|
|
|
|
// copy back the results from WinProc to IME's buffer (only if conversion is needed)
|
|
if (bAnsiOrigin != bAnsiTarget) {
|
|
switch (wParam) {
|
|
case IMR_RECONVERTSTRING:
|
|
case IMR_DOCUMENTFEED:
|
|
// Note: by definition, we don't have to do back-conversion for IMR_CONFIRMRECONVERTSTRING
|
|
if (lRet != 0) {
|
|
// IME wants the buffer size
|
|
lRet = ImmGetReconvertTotalSize((DWORD)lRet, FROM_APP, bAnsiTarget);
|
|
if (lRet < sizeof(RECONVERTSTRING)) {
|
|
RIPMSG1(RIP_WARNING, "ImmRequestMessageWorker: return value from application %d is invalid.", lRet);
|
|
lRet = 0;
|
|
} else if (lpReq) {
|
|
// We need to perform the A/W conversion of the contents
|
|
if (!ImmReconversionWorker((LPRECONVERTSTRING)lParam, (LPRECONVERTSTRING)lpReq, bAnsiOrigin, dwCodePage)) {
|
|
lRet = 0; // Error !
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case IMR_COMPOSITIONFONT:
|
|
if (bAnsiOrigin) {
|
|
LFontWtoLFontA((LPLOGFONTW)lpNew, (LPLOGFONTA)lParam);
|
|
} else {
|
|
LFontAtoLFontW((LPLOGFONTA)lpNew, (LPLOGFONTW)lParam);
|
|
}
|
|
break;
|
|
case IMR_QUERYCHARPOSITION:
|
|
UserAssert((LPVOID)lParam != NULL);
|
|
lpIMEPOS->dwCharPos = dwSaveCharPos;
|
|
#undef lpIMEPOS
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
if (lpNew) {
|
|
// buffer has been allocated, free it before returning
|
|
ImmLocalFree(lpNew);
|
|
}
|
|
return lRet;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* ImmRequestMessage: Send WM_IME_REQUEST message to the given HIMC window
|
|
*
|
|
* IME function
|
|
*
|
|
* 27-Feb-1997 hiroyama Created
|
|
\**************************************************************************/
|
|
LRESULT ImmRequestMessageAorW(HIMC hIMC, WPARAM wParam, LPARAM lParam, BOOL bAnsiOrigin)
|
|
{
|
|
LPINPUTCONTEXT lpInputContext;
|
|
PWND pwnd;
|
|
LRESULT lRet = 0L;
|
|
DWORD dwThreadId = GetInputContextThread(hIMC);
|
|
|
|
if (dwThreadId != GetCurrentThreadId()) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"ImmRequestMessageAorW:: Invalid input context access %lx.", hIMC);
|
|
return lRet;
|
|
}
|
|
|
|
if (hIMC == NULL || (lpInputContext = ImmLockIMC(hIMC)) == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmRequestMessage: Invalid hImc %lx.", hIMC);
|
|
return 0L;
|
|
}
|
|
|
|
// check if the window of the input context is valid
|
|
if ((pwnd = ValidateHwnd(lpInputContext->hWnd)) == NULL) {
|
|
RIPMSG1(RIP_WARNING, "ImmRequestMessage: Invalid hWnd %lx.", lpInputContext->hWnd);
|
|
} else {
|
|
// check if the message is being sent inter thread
|
|
if (PtiCurrent() != GETPTI(pwnd)) {
|
|
RIPMSG0(RIP_WARNING, "ImmRequestMessage: IME Attempt to send IMR_ message to different thread.");
|
|
} else {
|
|
lRet = ImmRequestMessageWorker(hIMC, pwnd, wParam, lParam, bAnsiOrigin);
|
|
}
|
|
}
|
|
|
|
ImmUnlockIMC(hIMC);
|
|
|
|
return lRet;
|
|
}
|
|
|
|
LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return ImmRequestMessageAorW(hIMC, wParam, lParam, TRUE /* ANSI */);
|
|
}
|
|
|
|
LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
return ImmRequestMessageAorW(hIMC, wParam, lParam, FALSE /* not ANSI */);
|
|
}
|