Skip to content

Instantly share code, notes, and snippets.

@katahiromz
Created February 10, 2023 04:16
Show Gist options
  • Save katahiromz/46d40dea26b191c8923de5ccd2bae310 to your computer and use it in GitHub Desktop.
Save katahiromz/46d40dea26b191c8923de5ccd2bae310 to your computer and use it in GitHub Desktop.
2k-imm32-candinfo.cpp
// 2k-imm32-candinfo.cpp
C_ASSERT(sizeof(CANDIDATELIST) == 28);
#define ROUNDUP4(n) (((n) + 3) & ~3) /* DWORD alignment */
#define CLIENTIMC_WIDE 0x1
/* dwType for NtUserQueryInputContext */
typedef enum _QUERY_INPUT_CONTEXT
{
QIC_INPUTPROCESSID = 0,
QIC_INPUTTHREADID,
QIC_DEFAULTWINDOWIME,
QIC_DEFAULTIMC
} QUERY_INPUT_CONTEXT;
// @implemented
DWORD
CandidateListWideToAnsi(const CANDIDATELIST *pWideCL, LPCANDIDATELIST pAnsiCL, DWORD dwBufLen, UINT uCodePage)
{
DWORD dwIndex, dwCount, dwTotalSize, ret;
LPDWORD pdw;
const WCHAR *pchW;
LPSTR pchA;
INT cchA, cbRemaining;
dwTotalSize = sizeof(CANDIDATELIST);
dwCount = pWideCL->dwCount;
if (dwCount > 0)
{
dwTotalSize = sizeof(CANDIDATELIST) + (dwCount - 1) * sizeof(DWORD);
for (dwIndex = 0; dwIndex < dwCount; ++dwIndex)
{
pchW = (const WCHAR *)((const BYTE *)pWideCL + pWideCL->dwOffset[dwIndex]);
cchA = WideCharToMultiByte(uCodePage, 0, pchW, -1, NULL, 0, NULL, NULL);
dwTotalSize += cchA;
}
}
ret = ROUNDUP4(dwTotalSize);
if (dwBufLen == 0)
return ret;
if (dwBufLen < ret)
return 0;
pAnsiCL->dwSize = dwBufLen;
pAnsiCL->dwStyle = pWideCL->dwStyle;
pAnsiCL->dwCount = dwCount;
pAnsiCL->dwSelection = pWideCL->dwSelection;
pAnsiCL->dwPageStart = pWideCL->dwPageStart;
pAnsiCL->dwPageSize = pWideCL->dwPageSize;
pdw = pAnsiCL->dwOffset;
*pdw = sizeof(CANDIDATELIST);
if (dwCount > 0)
*pdw = sizeof(CANDIDATELIST) + (dwCount - 1) * sizeof(DWORD);
cbRemaining = dwBufLen - *pdw;
for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pdw)
{
ASSERT(cbRemaining > 0);
ASSERT(pdw == &pAnsiCL->dwOffset[dwIndex]);
pchW = (const WCHAR *)((const BYTE *)pWideCL + pWideCL->dwOffset[dwIndex]);
pchA = (LPSTR)((LPBYTE)pAnsiCL + *pdw);
cchA = WideCharToMultiByte(uCodePage, 0, pchW, -1, pchA, cbRemaining, NULL, NULL);
cbRemaining -= cchA;
if (dwIndex + 1 < dwCount)
pdw[1] = *pdw + cchA;
}
return dwBufLen;
}
// @implemented
DWORD
CandidateListAnsiToWide(const CANDIDATELIST *pAnsiCL, LPCANDIDATELIST pWideCL, DWORD dwBufLen, UINT uCodePage)
{
DWORD ret, dwCount, dwTotalSize, dwIndex, cbW;
LPDWORD pdw;
const CHAR *pchA;
LPWSTR pchW;
INT cchW, cbRemaining;
dwTotalSize = sizeof(CANDIDATELIST);
dwCount = pAnsiCL->dwCount;
if (dwCount > 0)
{
dwTotalSize = sizeof(CANDIDATELIST) + (dwCount - 1) * sizeof(DWORD);
for (dwIndex = 0; dwIndex < dwCount; ++dwIndex)
{
pchA = (const CHAR *)((const BYTE *)pAnsiCL + pAnsiCL->dwOffset[dwIndex]);
cchW = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pchA, -1, NULL, 0);
dwTotalSize += cchW * sizeof(WCHAR);
}
}
ret = ROUNDUP4(dwTotalSize);
if (dwBufLen == 0)
return ret;
if (dwBufLen < ret)
return 0;
pWideCL->dwSize = dwBufLen;
pWideCL->dwStyle = pAnsiCL->dwStyle;
pWideCL->dwCount = dwCount;
pWideCL->dwSelection = pAnsiCL->dwSelection;
pWideCL->dwPageStart = pAnsiCL->dwPageStart;
pWideCL->dwPageSize = pAnsiCL->dwPageSize;
pdw = pWideCL->dwOffset;
*pdw = sizeof(CANDIDATELIST);
if (dwCount > 0)
*pdw = sizeof(CANDIDATELIST) + (dwCount - 1) * sizeof(DWORD);
cbRemaining = dwBufLen - *pdw;
for (dwIndex = 0; dwIndex < dwCount; ++dwIndex, ++pdw)
{
ASSERT(cbRemaining > 0);
ASSERT(pdw == &pWideCL->dwOffset[dwIndex]);
pchA = (const CHAR *)((const BYTE *)pAnsiCL + pAnsiCL->dwOffset[dwIndex]);
pchW = (LPWSTR)((LPBYTE)pWideCL + *pdw);
cchW = dwRemaining / sizeof(WCHAR);
cchW = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pchA, -1, pchW, cchW);
cbW = cchW * sizeof(WCHAR);
cbRemaining -= cbW;
if (dwIndex + 1 < dwCount)
pdw[1] = *pdw + cbW;
}
return dwBufLen;
}
// @implemented
DWORD
ImmGetCandidateListCountAW(HIMC hIMC, LPDWORD lpdwListCount, BOOL bAnsi)
{
PCLIENTIMC pClientImc;
LPINPUTCONTEXT pIC;
LPCANDIDATEINFO pCI;
DWORD dwSize, dwIndex, ret = 0;
LPCANDIDATELIST pWideCL, pAnsiCL;
if (lpdwListCount == NULL)
return 0;
*lpdwListCount = 0;
pClientImc = ImmLockClientImc(hIMC);
if (pClientImc == NULL)
return 0;
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
{
ImmUnlockClientImc(&pClientImc);
return ret;
}
pCI = (LPCANDIDATEINFO)ImmLockIMCC(pIC->hCandInfo);
if (pCI)
{
if (pCI->dwSize >= sizeof(CANDIDATEINFO))
{
/* Set the number of the list */
*lpdwListCount = pCI->dwCount;
/* Returns the total size of the destination candidate info */
if (bAnsi)
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
{
ret = sizeof(CANDIDATEINFO) + ROUNDUP4(pCI->dwPrivateSize);
for (dwIndex = 0; dwIndex < pCI->dwCount; ++dwIndex)
{
pAnsiCL = (LPCANDIDATELIST)((LPBYTE)pCI + pCI->dwOffset[dwIndex]);
dwSize = CandidateListAnsiToWide(pAnsiCL, NULL, 0, 0);
ret += dwSize;
}
}
else
{
ret = pCI->dwSize;
}
}
else
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
{
ret = pCI->dwSize;
}
else
{
ret = sizeof(CANDIDATEINFO) + ROUNDUP4(pCI->dwPrivateSize);
for (dwIndex = 0; dwIndex < pCI->dwCount; ++dwIndex)
{
pWideCL = (LPCANDIDATELIST)((LPBYTE)pCI + pCI->dwOffset[dwIndex]);
dwSize = CandidateListWideToAnsi(pWideCL, NULL, 0, 0);
ret += dwSize;
}
}
}
}
ImmUnlockIMCC(pIC->hCandInfo);
}
ImmUnlockIMC(hIMC);
ImmUnlockClientImc(&pClientImc);
return ret;
}
// @implemented
DWORD
ImmGetCandidateListAW(HIMC hIMC, DWORD dwIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen, BOOL bAnsi)
{
PCLIENTIMC pClientImc;
LPINPUTCONTEXT pIC;
LPCANDIDATEINFO pCI;
LPCANDIDATELIST pSrcCL;
DWORD cbList, ret = 0;
pClientImc = ImmLockClientImc(hIMC);
if (pClientImc == NULL)
return 0;
pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
{
ImmUnlockClientImc(pClientImc);
return 0;
}
pCI = (LPCANDIDATEINFO)ImmLockIMCC(pIC->hCandInfo);
if (pCI)
{
if (pCI->dwSize >= sizeof(CANDIDATEINFO) && dwIndex < pCI->dwCount)
{
/* Get cbList from candidate info */
pSrcCL = (LPCANDIDATELIST)((LPBYTE)pCI + pCI->dwOffset[dwIndex]);
if (!bAnsi)
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
{
cbList = pSrcCL->dwSize;
}
else
{
cbList = CandidateListAnsiToWide(pSrcCL, NULL, 0, 0);
}
}
else
{
if (!(pClientImc->dwFlags & CLIENTIMC_WIDE))
{
cbList = pSrcCL->dwSize;
}
else
{
cbList = CandidateListWideToAnsi(pSrcCL, NULL, 0, 0);
}
}
if (dwBufLen == 0 || cbList == 0)
{
ret = cbList; /* Returns the list size */
}
else if (lpCandidate && dwBufLen >= cbList)
{
/* Copy/Convert the list to lpCandList */
if (bAnsi)
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
{
ret = CandidateListWideToAnsi(pSrcCL, lpCandList, cbList, 0);
}
else
{
CopyMemory(lpCandList, pSrcCL, cbList);
ret = cbList;
}
}
else
{
if (pClientImc->dwFlags & CLIENTIMC_WIDE)
{
CopyMemory(lpCandList, pSrcCL, cbList);
ret = cbList;
}
else
{
ret = CandidateListAnsiToWide(pSrcCL, lpCandList, cbList, 0);
}
}
}
}
ImmUnlockIMCC(pIC->hCandInfo);
}
ImmUnlockIMC(hIMC);
ImmUnlockClientImc(pClientImc);
return ret;
}
// @implemented
DWORD WINAPI ImmGetCandidateListA(HIMC hIMC, DWORD dwIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen)
{
return ImmGetCandidateListAW(hIMC, dwIndex, lpCandList, dwBufLen, TRUE);
}
// @implemented
DWORD WINAPI ImmGetCandidateListW(HIMC hIMC, DWORD deIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen)
{
return ImmGetCandidateListAW(hIMC, deIndex, lpCandList, dwBufLen, FALSE);
}
// @implemented
DWORD WINAPI ImmGetCandidateListCountA(HIMC hIMC, LPDWORD lpdwListCount)
{
return ImmGetCandidateListCountAW(hIMC, lpdwListCount, TRUE);
}
// @implemented
DWORD WINAPI ImmGetCandidateListCountW(HIMC hIMC, LPDWORD lpdwListCount)
{
return ImmGetCandidateListCountAW(hIMC, lpdwListCount, FALSE);
}
// @implemented
BOOL WINAPI ImmGetCandidateWindow(HIMC hIMC,DWORD dwIndex,LPCANDIDATEFORM lpCandidate)
{
LPINPUTCONTEXT pIC = ImmLockIMC(hIMC);
if (pIC == NULL)
return FALSE;
//ImmUnlockIMC(hIMC); // これはWin2k側の間違いかworkaroundと思われる。Win2k3にはない。
if (pIC->cfCandForm[dwIndex].dwIndex == (DWORD)-1)
{
ImmUnlockIMC(hIMC);
return FALSE;
}
*lpCandidate = pIC->cfCandForm[dwIndex];
ImmUnlockIMC(hIMC);
return TRUE;
}
// @implemented
BOOL WINAPI ImmSetCandidateWindow(HIMC hIMC, LPCANDIDATEFORM lpCandidate)
{
HWND hwnd;
DWORD dwImeThreadId, dwCurThreadId;
LPINPUTCONTEXT pIC;
if (lpCandidate->dwIndex >= 4)
return FALSE;
dwImeThreadId = NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
dwCurThreadId = GetCurrentThreadId();
if (dwImeThreadId != dwCurThreadId)
return FALSE;
pIC = ImmLockIMC(hIMC)
if (pIC == NULL)
return FALSE+
pIC->cfCandForm[lpCandidate->dwIndex] = *lpCandidate;
hwnd = pIC->hWnd;
ImmUnlockIMC(hIMC);
Imm32MakeIMENotify(hIMC, hwnd, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS,
IMN_SETCANDIDATEPOS, (1 << lpCandidate->dwIndex));
return TRUE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment