1 /* 2 * PROJECT: ReactOS IMM32 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Implementing IMM32 helper functions 5 * COPYRIGHT: Copyright 1998 Patrik Stridvall 6 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart 7 * Copyright 2017 James Tabor <james.tabor@reactos.org> 8 * Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org> 9 * Copyright 2020 Oleg Dubinskiy <oleg.dubinskij2013@yandex.ua> 10 * Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 11 */ 12 13 #include "precomp.h" 14 15 WINE_DEFAULT_DEBUG_CHANNEL(imm); 16 17 HANDLE g_hImm32Heap = NULL; 18 19 HRESULT APIENTRY 20 Imm32StrToUInt(LPCWSTR pszText, LPDWORD pdwValue, ULONG nBase) 21 { 22 NTSTATUS Status; 23 UNICODE_STRING UnicodeString; 24 RtlInitUnicodeString(&UnicodeString, pszText); 25 Status = RtlUnicodeStringToInteger(&UnicodeString, nBase, pdwValue); 26 if (!NT_SUCCESS(Status)) 27 return E_FAIL; 28 return S_OK; 29 } 30 31 HRESULT APIENTRY 32 Imm32UIntToStr(DWORD dwValue, ULONG nBase, LPWSTR pszBuff, USHORT cchBuff) 33 { 34 NTSTATUS Status; 35 UNICODE_STRING UnicodeString; 36 UnicodeString.Buffer = pszBuff; 37 UnicodeString.MaximumLength = cchBuff * sizeof(WCHAR); 38 Status = RtlIntegerToUnicodeString(dwValue, nBase, &UnicodeString); 39 if (!NT_SUCCESS(Status)) 40 return E_FAIL; 41 return S_OK; 42 } 43 44 BOOL WINAPI Imm32IsImcAnsi(HIMC hIMC) 45 { 46 BOOL ret; 47 PCLIENTIMC pClientImc = ImmLockClientImc(hIMC); 48 if (!pClientImc) 49 return -1; 50 ret = !(pClientImc->dwFlags & CLIENTIMC_WIDE); 51 ImmUnlockClientImc(pClientImc); 52 return ret; 53 } 54 55 LPWSTR APIENTRY Imm32WideFromAnsi(LPCSTR pszA) 56 { 57 INT cch = lstrlenA(pszA); 58 LPWSTR pszW = Imm32HeapAlloc(0, (cch + 1) * sizeof(WCHAR)); 59 if (pszW == NULL) 60 return NULL; 61 cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszA, cch, pszW, cch + 1); 62 pszW[cch] = 0; 63 return pszW; 64 } 65 66 LPSTR APIENTRY Imm32AnsiFromWide(LPCWSTR pszW) 67 { 68 INT cchW = lstrlenW(pszW); 69 INT cchA = (cchW + 1) * sizeof(WCHAR); 70 LPSTR pszA = Imm32HeapAlloc(0, cchA); 71 if (!pszA) 72 return NULL; 73 cchA = WideCharToMultiByte(CP_ACP, 0, pszW, cchW, pszA, cchA, NULL, NULL); 74 pszA[cchA] = 0; 75 return pszA; 76 } 77 78 /* Converts the character index */ 79 LONG APIENTRY IchWideFromAnsi(LONG cchAnsi, LPCSTR pchAnsi, UINT uCodePage) 80 { 81 LONG cchWide; 82 for (cchWide = 0; cchAnsi > 0; ++cchWide) 83 { 84 if (IsDBCSLeadByteEx(uCodePage, *pchAnsi) && pchAnsi[1]) 85 { 86 cchAnsi -= 2; 87 pchAnsi += 2; 88 } 89 else 90 { 91 --cchAnsi; 92 ++pchAnsi; 93 } 94 } 95 return cchWide; 96 } 97 98 /* Converts the character index */ 99 LONG APIENTRY IchAnsiFromWide(LONG cchWide, LPCWSTR pchWide, UINT uCodePage) 100 { 101 LONG cb, cchAnsi; 102 for (cchAnsi = 0; cchWide > 0; ++cchAnsi, ++pchWide, --cchWide) 103 { 104 cb = WideCharToMultiByte(uCodePage, 0, pchWide, 1, NULL, 0, NULL, NULL); 105 if (cb > 1) 106 ++cchAnsi; 107 } 108 return cchAnsi; 109 } 110 111 BOOL Imm32GetSystemLibraryPath(LPWSTR pszPath, DWORD cchPath, LPCWSTR pszFileName) 112 { 113 if (!pszFileName[0] || !GetSystemDirectoryW(pszPath, cchPath)) 114 return FALSE; 115 StringCchCatW(pszPath, cchPath, L"\\"); 116 StringCchCatW(pszPath, cchPath, pszFileName); 117 return TRUE; 118 } 119 120 VOID APIENTRY LogFontAnsiToWide(const LOGFONTA *plfA, LPLOGFONTW plfW) 121 { 122 size_t cch; 123 RtlCopyMemory(plfW, plfA, offsetof(LOGFONTA, lfFaceName)); 124 StringCchLengthA(plfA->lfFaceName, _countof(plfA->lfFaceName), &cch); 125 cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plfA->lfFaceName, (INT)cch, 126 plfW->lfFaceName, _countof(plfW->lfFaceName)); 127 if (cch > _countof(plfW->lfFaceName) - 1) 128 cch = _countof(plfW->lfFaceName) - 1; 129 plfW->lfFaceName[cch] = 0; 130 } 131 132 VOID APIENTRY LogFontWideToAnsi(const LOGFONTW *plfW, LPLOGFONTA plfA) 133 { 134 size_t cch; 135 RtlCopyMemory(plfA, plfW, offsetof(LOGFONTW, lfFaceName)); 136 StringCchLengthW(plfW->lfFaceName, _countof(plfW->lfFaceName), &cch); 137 cch = WideCharToMultiByte(CP_ACP, 0, plfW->lfFaceName, (INT)cch, 138 plfA->lfFaceName, _countof(plfA->lfFaceName), NULL, NULL); 139 if (cch > _countof(plfA->lfFaceName) - 1) 140 cch = _countof(plfA->lfFaceName) - 1; 141 plfA->lfFaceName[cch] = 0; 142 } 143 144 LPVOID FASTCALL ValidateHandleNoErr(HANDLE hObject, UINT uType) 145 { 146 INT index; 147 PUSER_HANDLE_TABLE ht; 148 PUSER_HANDLE_ENTRY he; 149 WORD generation; 150 151 if (!NtUserValidateHandleSecure(hObject)) 152 return NULL; 153 154 ht = g_SharedInfo.aheList; /* handle table */ 155 ASSERT(ht); 156 /* ReactOS-Specific! */ 157 ASSERT(g_SharedInfo.ulSharedDelta != 0); 158 he = (PUSER_HANDLE_ENTRY)((ULONG_PTR)ht->handles - g_SharedInfo.ulSharedDelta); 159 160 index = (LOWORD(hObject) - FIRST_USER_HANDLE) >> 1; 161 if (index < 0 || ht->nb_handles <= index || he[index].type != uType) 162 return NULL; 163 164 generation = HIWORD(hObject); 165 if (generation != he[index].generation && generation && generation != 0xFFFF) 166 return NULL; 167 168 return &he[index]; 169 } 170 171 PWND FASTCALL ValidateHwndNoErr(HWND hwnd) 172 { 173 /* See if the window is cached */ 174 PCLIENTINFO ClientInfo = GetWin32ClientInfo(); 175 if (hwnd == ClientInfo->CallbackWnd.hWnd) 176 return ClientInfo->CallbackWnd.pWnd; 177 178 return ValidateHandleNoErr(hwnd, TYPE_WINDOW); 179 } 180 181 BOOL APIENTRY Imm32CheckImcProcess(PIMC pIMC) 182 { 183 HIMC hIMC; 184 DWORD dwProcessID; 185 if (pIMC->head.pti == NtCurrentTeb()->Win32ThreadInfo) 186 return TRUE; 187 188 hIMC = pIMC->head.h; 189 dwProcessID = NtUserQueryInputContext(hIMC, 0); 190 return dwProcessID == (DWORD_PTR)NtCurrentTeb()->ClientId.UniqueProcess; 191 } 192 193 LPVOID APIENTRY Imm32HeapAlloc(DWORD dwFlags, DWORD dwBytes) 194 { 195 if (!g_hImm32Heap) 196 { 197 g_hImm32Heap = RtlGetProcessHeap(); 198 if (g_hImm32Heap == NULL) 199 return NULL; 200 } 201 return HeapAlloc(g_hImm32Heap, dwFlags, dwBytes); 202 } 203 204 BOOL APIENTRY 205 Imm32NotifyAction(HIMC hIMC, HWND hwnd, DWORD dwAction, DWORD_PTR dwIndex, DWORD_PTR dwValue, 206 DWORD_PTR dwCommand, DWORD_PTR dwData) 207 { 208 DWORD dwThreadId; 209 HKL hKL; 210 PIMEDPI pImeDpi; 211 212 if (dwAction) 213 { 214 dwThreadId = NtUserQueryInputContext(hIMC, 1); 215 if (dwThreadId) 216 { 217 /* find keyboard layout and lock it */ 218 hKL = GetKeyboardLayout(dwThreadId); 219 pImeDpi = ImmLockImeDpi(hKL); 220 if (pImeDpi) 221 { 222 /* do notify */ 223 pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue); 224 225 ImmUnlockImeDpi(pImeDpi); /* unlock */ 226 } 227 } 228 } 229 230 if (hwnd && dwCommand) 231 SendMessageW(hwnd, WM_IME_NOTIFY, dwCommand, dwData); 232 233 return TRUE; 234 } 235 236 DWORD APIENTRY Imm32AllocAndBuildHimcList(DWORD dwThreadId, HIMC **pphList) 237 { 238 #define INITIAL_COUNT 0x40 239 #define MAX_RETRY 10 240 NTSTATUS Status; 241 DWORD dwCount = INITIAL_COUNT, cRetry = 0; 242 HIMC *phNewList; 243 244 phNewList = Imm32HeapAlloc(0, dwCount * sizeof(HIMC)); 245 if (phNewList == NULL) 246 return 0; 247 248 Status = NtUserBuildHimcList(dwThreadId, dwCount, phNewList, &dwCount); 249 while (Status == STATUS_BUFFER_TOO_SMALL) 250 { 251 Imm32HeapFree(phNewList); 252 if (cRetry++ >= MAX_RETRY) 253 return 0; 254 255 phNewList = Imm32HeapAlloc(0, dwCount * sizeof(HIMC)); 256 if (phNewList == NULL) 257 return 0; 258 259 Status = NtUserBuildHimcList(dwThreadId, dwCount, phNewList, &dwCount); 260 } 261 262 if (NT_ERROR(Status) || !dwCount) 263 { 264 Imm32HeapFree(phNewList); 265 return 0; 266 } 267 268 *pphList = phNewList; 269 return dwCount; 270 #undef INITIAL_COUNT 271 #undef MAX_RETRY 272 } 273 274 INT APIENTRY 275 Imm32ImeMenuAnsiToWide(const IMEMENUITEMINFOA *pItemA, LPIMEMENUITEMINFOW pItemW, 276 UINT uCodePage, BOOL bBitmap) 277 { 278 INT ret; 279 pItemW->cbSize = pItemA->cbSize; 280 pItemW->fType = pItemA->fType; 281 pItemW->fState = pItemA->fState; 282 pItemW->wID = pItemA->wID; 283 if (bBitmap) 284 { 285 pItemW->hbmpChecked = pItemA->hbmpChecked; 286 pItemW->hbmpUnchecked = pItemA->hbmpUnchecked; 287 pItemW->hbmpItem = pItemA->hbmpItem; 288 } 289 pItemW->dwItemData = pItemA->dwItemData; 290 ret = MultiByteToWideChar(uCodePage, 0, pItemA->szString, -1, 291 pItemW->szString, _countof(pItemW->szString)); 292 if (ret >= _countof(pItemW->szString)) 293 { 294 ret = 0; 295 pItemW->szString[0] = 0; 296 } 297 return ret; 298 } 299 300 INT APIENTRY 301 Imm32ImeMenuWideToAnsi(const IMEMENUITEMINFOW *pItemW, LPIMEMENUITEMINFOA pItemA, 302 UINT uCodePage) 303 { 304 INT ret; 305 pItemA->cbSize = pItemW->cbSize; 306 pItemA->fType = pItemW->fType; 307 pItemA->fState = pItemW->fState; 308 pItemA->wID = pItemW->wID; 309 pItemA->hbmpChecked = pItemW->hbmpChecked; 310 pItemA->hbmpUnchecked = pItemW->hbmpUnchecked; 311 pItemA->dwItemData = pItemW->dwItemData; 312 pItemA->hbmpItem = pItemW->hbmpItem; 313 ret = WideCharToMultiByte(uCodePage, 0, pItemW->szString, -1, 314 pItemA->szString, _countof(pItemA->szString), NULL, NULL); 315 if (ret >= _countof(pItemA->szString)) 316 { 317 ret = 0; 318 pItemA->szString[0] = 0; 319 } 320 return ret; 321 } 322 323 PIME_STATE APIENTRY 324 Imm32FetchImeState(LPINPUTCONTEXTDX pIC, HKL hKL) 325 { 326 PIME_STATE pState; 327 WORD Lang = PRIMARYLANGID(LOWORD(hKL)); 328 for (pState = pIC->pState; pState; pState = pState->pNext) 329 { 330 if (pState->wLang == Lang) 331 break; 332 } 333 if (!pState) 334 { 335 pState = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(IME_STATE)); 336 if (pState) 337 { 338 pState->wLang = Lang; 339 pState->pNext = pIC->pState; 340 pIC->pState = pState; 341 } 342 } 343 return pState; 344 } 345 346 PIME_SUBSTATE APIENTRY 347 Imm32FetchImeSubState(PIME_STATE pState, HKL hKL) 348 { 349 PIME_SUBSTATE pSubState; 350 for (pSubState = pState->pSubState; pSubState; pSubState = pSubState->pNext) 351 { 352 if (pSubState->hKL == hKL) 353 return pSubState; 354 } 355 pSubState = Imm32HeapAlloc(0, sizeof(IME_SUBSTATE)); 356 if (!pSubState) 357 return NULL; 358 pSubState->dwValue = 0; 359 pSubState->hKL = hKL; 360 pSubState->pNext = pState->pSubState; 361 pState->pSubState = pSubState; 362 return pSubState; 363 } 364 365 BOOL APIENTRY 366 Imm32LoadImeStateSentence(LPINPUTCONTEXTDX pIC, PIME_STATE pState, HKL hKL) 367 { 368 PIME_SUBSTATE pSubState = Imm32FetchImeSubState(pState, hKL); 369 if (pSubState) 370 { 371 pIC->fdwSentence |= pSubState->dwValue; 372 return TRUE; 373 } 374 return FALSE; 375 } 376 377 BOOL APIENTRY 378 Imm32SaveImeStateSentence(LPINPUTCONTEXTDX pIC, PIME_STATE pState, HKL hKL) 379 { 380 PIME_SUBSTATE pSubState = Imm32FetchImeSubState(pState, hKL); 381 if (pSubState) 382 { 383 pSubState->dwValue = (pIC->fdwSentence & 0xffff0000); 384 return TRUE; 385 } 386 return FALSE; 387 } 388 389 /* 390 * See RECONVERTSTRING structure: 391 * https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/RECONVERTSTRING.html 392 * 393 * The dwCompStrOffset and dwTargetOffset members are the relative position of dwStrOffset. 394 * dwStrLen, dwCompStrLen, and dwTargetStrLen are the TCHAR count. dwStrOffset, 395 * dwCompStrOffset, and dwTargetStrOffset are the byte offset. 396 */ 397 398 DWORD APIENTRY 399 Imm32ReconvertWideFromAnsi(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc, UINT uCodePage) 400 { 401 DWORD cch0, cchDest, cbDest; 402 LPCSTR pchSrc = (LPCSTR)pSrc + pSrc->dwStrOffset; 403 LPWSTR pchDest; 404 405 if (pSrc->dwVersion != 0) 406 return 0; 407 408 cchDest = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pchSrc, pSrc->dwStrLen, 409 NULL, 0); 410 cbDest = sizeof(RECONVERTSTRING) + (cchDest + 1) * sizeof(WCHAR); 411 if (!pDest) 412 return cbDest; 413 414 if (pDest->dwSize < cbDest) 415 return 0; 416 417 /* dwSize */ 418 pDest->dwSize = cbDest; 419 420 /* dwVersion */ 421 pDest->dwVersion = 0; 422 423 /* dwStrOffset */ 424 pDest->dwStrOffset = sizeof(RECONVERTSTRING); 425 426 /* dwCompStrOffset */ 427 cch0 = IchWideFromAnsi(pSrc->dwCompStrOffset, pchSrc, uCodePage); 428 pDest->dwCompStrOffset = cch0 * sizeof(WCHAR); 429 430 /* dwCompStrLen */ 431 cch0 = IchWideFromAnsi(pSrc->dwCompStrOffset + pSrc->dwCompStrLen, pchSrc, uCodePage); 432 pDest->dwCompStrLen = (cch0 * sizeof(WCHAR) - pDest->dwCompStrOffset) / sizeof(WCHAR); 433 434 /* dwTargetStrOffset */ 435 cch0 = IchWideFromAnsi(pSrc->dwTargetStrOffset, pchSrc, uCodePage); 436 pDest->dwTargetStrOffset = cch0 * sizeof(WCHAR); 437 438 /* dwTargetStrLen */ 439 cch0 = IchWideFromAnsi(pSrc->dwTargetStrOffset + pSrc->dwTargetStrLen, pchSrc, uCodePage); 440 pDest->dwTargetStrLen = (cch0 * sizeof(WCHAR) - pSrc->dwTargetStrOffset) / sizeof(WCHAR); 441 442 /* dwStrLen */ 443 pDest->dwStrLen = cchDest; 444 445 /* the string */ 446 pchDest = (LPWSTR)((LPBYTE)pDest + pDest->dwStrOffset); 447 cchDest = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pchSrc, pSrc->dwStrLen, 448 pchDest, cchDest); 449 pchDest[cchDest] = 0; 450 451 return cbDest; 452 } 453 454 DWORD APIENTRY 455 Imm32ReconvertAnsiFromWide(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc, UINT uCodePage) 456 { 457 DWORD cch0, cch1, cchDest, cbDest; 458 LPCWSTR pchSrc = (LPCWSTR)((LPCSTR)pSrc + pSrc->dwStrOffset); 459 LPSTR pchDest; 460 461 if (pSrc->dwVersion != 0) 462 return 0; 463 464 cchDest = WideCharToMultiByte(uCodePage, 0, pchSrc, pSrc->dwStrLen, 465 NULL, 0, NULL, NULL); 466 cbDest = sizeof(RECONVERTSTRING) + (cchDest + 1) * sizeof(CHAR); 467 if (!pDest) 468 return cbDest; 469 470 if (pDest->dwSize < cbDest) 471 return 0; 472 473 /* dwSize */ 474 pDest->dwSize = cbDest; 475 476 /* dwVersion */ 477 pDest->dwVersion = 0; 478 479 /* dwStrOffset */ 480 pDest->dwStrOffset = sizeof(RECONVERTSTRING); 481 482 /* dwCompStrOffset */ 483 cch1 = pSrc->dwCompStrOffset / sizeof(WCHAR); 484 cch0 = IchAnsiFromWide(cch1, pchSrc, uCodePage); 485 pDest->dwCompStrOffset = cch0 * sizeof(CHAR); 486 487 /* dwCompStrLen */ 488 cch0 = IchAnsiFromWide(cch1 + pSrc->dwCompStrLen, pchSrc, uCodePage); 489 pDest->dwCompStrLen = cch0 * sizeof(CHAR) - pDest->dwCompStrOffset; 490 491 /* dwTargetStrOffset */ 492 cch1 = pSrc->dwTargetStrOffset / sizeof(WCHAR); 493 cch0 = IchAnsiFromWide(cch1, pchSrc, uCodePage); 494 pDest->dwTargetStrOffset = cch0 * sizeof(CHAR); 495 496 /* dwTargetStrLen */ 497 cch0 = IchAnsiFromWide(cch1 + pSrc->dwTargetStrLen, pchSrc, uCodePage); 498 pDest->dwTargetStrLen = cch0 * sizeof(CHAR) - pDest->dwTargetStrOffset; 499 500 /* dwStrLen */ 501 pDest->dwStrLen = cchDest; 502 503 /* the string */ 504 pchDest = (LPSTR)pDest + pDest->dwStrOffset; 505 cchDest = WideCharToMultiByte(uCodePage, 0, pchSrc, pSrc->dwStrLen, 506 pchDest, cchDest, NULL, NULL); 507 pchDest[cchDest] = 0; 508 509 return cbDest; 510 } 511 512 typedef BOOL (WINAPI *FN_GetFileVersionInfoW)(LPCWSTR, DWORD, DWORD, LPVOID); 513 typedef DWORD (WINAPI *FN_GetFileVersionInfoSizeW)(LPCWSTR, LPDWORD); 514 typedef BOOL (WINAPI *FN_VerQueryValueW)(LPCVOID, LPCWSTR, LPVOID*, PUINT); 515 516 static FN_GetFileVersionInfoW s_fnGetFileVersionInfoW = NULL; 517 static FN_GetFileVersionInfoSizeW s_fnGetFileVersionInfoSizeW = NULL; 518 static FN_VerQueryValueW s_fnVerQueryValueW = NULL; 519 520 static BOOL APIENTRY Imm32LoadImeFixedInfo(PIMEINFOEX pInfoEx, LPCVOID pVerInfo) 521 { 522 UINT cbFixed = 0; 523 VS_FIXEDFILEINFO *pFixed; 524 if (!s_fnVerQueryValueW(pVerInfo, L"\\", (LPVOID*)&pFixed, &cbFixed) || !cbFixed) 525 return FALSE; 526 527 /* NOTE: The IME module must contain a version info of input method driver. */ 528 if (pFixed->dwFileType != VFT_DRV || pFixed->dwFileSubtype != VFT2_DRV_INPUTMETHOD) 529 return FALSE; 530 531 pInfoEx->dwProdVersion = pFixed->dwProductVersionMS; 532 pInfoEx->dwImeWinVersion = 0x40000; 533 return TRUE; 534 } 535 536 static LPWSTR APIENTRY 537 Imm32GetVerInfoValue(LPCVOID pVerInfo, LPWSTR pszKey, DWORD cchKey, LPCWSTR pszName) 538 { 539 size_t cchExtra; 540 LPWSTR pszValue; 541 UINT cbValue = 0; 542 543 StringCchLengthW(pszKey, cchKey, &cchExtra); 544 545 StringCchCatW(pszKey, cchKey, pszName); 546 s_fnVerQueryValueW(pVerInfo, pszKey, (LPVOID*)&pszValue, &cbValue); 547 pszKey[cchExtra] = 0; 548 549 return (cbValue ? pszValue : NULL); 550 } 551 552 BOOL APIENTRY Imm32LoadImeLangAndDesc(PIMEINFOEX pInfoEx, LPCVOID pVerInfo) 553 { 554 BOOL ret; 555 WCHAR szKey[80]; 556 LPWSTR pszDesc; 557 LPWORD pw; 558 UINT cbData; 559 LANGID LangID; 560 561 /* Getting the version info. See VerQueryValue */ 562 ret = s_fnVerQueryValueW(pVerInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&pw, &cbData); 563 if (!ret || !cbData) 564 return FALSE; 565 566 if (pInfoEx->hkl == NULL) 567 pInfoEx->hkl = (HKL)(DWORD_PTR)*pw; /* This is an invalid HKL */ 568 569 /* Try the current language and the Unicode codepage (0x04B0) */ 570 LangID = LANGIDFROMLCID(GetThreadLocale()); 571 StringCchPrintfW(szKey, _countof(szKey), L"\\StringFileInfo\\%04X04B0\\", LangID); 572 pszDesc = Imm32GetVerInfoValue(pVerInfo, szKey, _countof(szKey), L"FileDescription"); 573 if (!pszDesc) 574 { 575 /* Retry the language and codepage of the IME module */ 576 StringCchPrintfW(szKey, _countof(szKey), L"\\StringFileInfo\\%04X%04X\\", pw[0], pw[1]); 577 pszDesc = Imm32GetVerInfoValue(pVerInfo, szKey, _countof(szKey), L"FileDescription"); 578 } 579 580 /* The description */ 581 if (pszDesc) 582 StringCchCopyW(pInfoEx->wszImeDescription, _countof(pInfoEx->wszImeDescription), pszDesc); 583 else 584 pInfoEx->wszImeDescription[0] = 0; 585 586 return TRUE; 587 } 588 589 BOOL APIENTRY Imm32LoadImeVerInfo(PIMEINFOEX pImeInfoEx) 590 { 591 HINSTANCE hinstVersion; 592 BOOL ret = FALSE, bLoaded = FALSE; 593 WCHAR szPath[MAX_PATH]; 594 LPVOID pVerInfo; 595 DWORD cbVerInfo, dwHandle; 596 597 /* Load version.dll to use the version info API */ 598 Imm32GetSystemLibraryPath(szPath, _countof(szPath), L"version.dll"); 599 hinstVersion = GetModuleHandleW(szPath); 600 if (!hinstVersion) 601 { 602 hinstVersion = LoadLibraryW(szPath); 603 if (!hinstVersion) 604 return FALSE; 605 bLoaded = TRUE; 606 } 607 608 #define GET_FN(name) do { \ 609 s_fn##name = (FN_##name)GetProcAddress(hinstVersion, #name); \ 610 if (!s_fn##name) goto Quit; \ 611 } while (0) 612 GET_FN(GetFileVersionInfoW); 613 GET_FN(GetFileVersionInfoSizeW); 614 GET_FN(VerQueryValueW); 615 #undef GET_FN 616 617 /* The path of the IME module */ 618 Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile); 619 620 cbVerInfo = s_fnGetFileVersionInfoSizeW(szPath, &dwHandle); 621 if (!cbVerInfo) 622 goto Quit; 623 624 pVerInfo = Imm32HeapAlloc(0, cbVerInfo); 625 if (!pVerInfo) 626 goto Quit; 627 628 /* Load the version info of the IME module */ 629 if (s_fnGetFileVersionInfoW(szPath, dwHandle, cbVerInfo, pVerInfo) && 630 Imm32LoadImeFixedInfo(pImeInfoEx, pVerInfo)) 631 { 632 ret = Imm32LoadImeLangAndDesc(pImeInfoEx, pVerInfo); 633 } 634 635 Imm32HeapFree(pVerInfo); 636 637 Quit: 638 if (bLoaded) 639 FreeLibrary(hinstVersion); 640 return ret; 641 } 642 643 HKL APIENTRY Imm32GetNextHKL(UINT cKLs, const REG_IME *pLayouts, WORD wLangID) 644 { 645 UINT iKL, wID, wLow = 0xE0FF, wHigh = 0xE01F, wNextID = 0; 646 647 for (iKL = 0; iKL < cKLs; ++iKL) 648 { 649 wHigh = max(wHigh, HIWORD(pLayouts[iKL].hKL)); 650 wLow = min(wLow, HIWORD(pLayouts[iKL].hKL)); 651 } 652 653 if (wHigh < 0xE0FF) 654 { 655 wNextID = wHigh + 1; 656 } 657 else if (wLow > 0xE001) 658 { 659 wNextID = wLow - 1; 660 } 661 else 662 { 663 for (wID = 0xE020; wID <= 0xE0FF; ++wID) 664 { 665 for (iKL = 0; iKL < cKLs; ++iKL) 666 { 667 if (LOWORD(pLayouts[iKL].hKL) == wLangID && 668 HIWORD(pLayouts[iKL].hKL) == wID) 669 { 670 break; 671 } 672 } 673 674 if (iKL >= cKLs) 675 break; 676 } 677 678 if (wID <= 0xE0FF) 679 wNextID = wID; 680 } 681 682 if (!wNextID) 683 return NULL; 684 685 return (HKL)(DWORD_PTR)MAKELONG(wLangID, wNextID); 686 } 687 688 UINT APIENTRY Imm32GetRegImes(PREG_IME pLayouts, UINT cLayouts) 689 { 690 HKEY hkeyLayouts, hkeyIME; 691 WCHAR szImeFileName[80], szImeKey[20]; 692 UINT iKey, nCount; 693 DWORD cbData; 694 LONG lError; 695 ULONG Value; 696 HKL hKL; 697 698 /* Open the registry keyboard layouts */ 699 lError = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hkeyLayouts); 700 if (lError != ERROR_SUCCESS) 701 return 0; 702 703 for (iKey = nCount = 0; ; ++iKey) 704 { 705 /* Get the key name */ 706 lError = RegEnumKeyW(hkeyLayouts, iKey, szImeKey, _countof(szImeKey)); 707 if (lError != ERROR_SUCCESS) 708 break; 709 710 if (szImeKey[0] != L'E' && szImeKey[0] != L'e') 711 continue; /* Not an IME layout */ 712 713 if (pLayouts == NULL) /* for counting only */ 714 { 715 ++nCount; 716 continue; 717 } 718 719 if (cLayouts <= nCount) 720 break; 721 722 lError = RegOpenKeyW(hkeyLayouts, szImeKey, &hkeyIME); /* Open the IME key */ 723 if (lError != ERROR_SUCCESS) 724 break; 725 726 /* Load the "Ime File" value */ 727 szImeFileName[0] = 0; 728 cbData = sizeof(szImeFileName); 729 RegQueryValueExW(hkeyIME, L"Ime File", NULL, NULL, (LPBYTE)szImeFileName, &cbData); 730 szImeFileName[_countof(szImeFileName) - 1] = 0; 731 732 RegCloseKey(hkeyIME); 733 734 if (!szImeFileName[0]) 735 break; 736 737 Imm32StrToUInt(szImeKey, &Value, 16); 738 hKL = (HKL)(DWORD_PTR)Value; 739 if (!IS_IME_HKL(hKL)) 740 break; 741 742 /* Store the IME key and the IME filename */ 743 pLayouts[nCount].hKL = hKL; 744 StringCchCopyW(pLayouts[nCount].szImeKey, _countof(pLayouts[nCount].szImeKey), szImeKey); 745 CharUpperW(szImeFileName); 746 StringCchCopyW(pLayouts[nCount].szFileName, _countof(pLayouts[nCount].szFileName), 747 szImeFileName); 748 ++nCount; 749 } 750 751 RegCloseKey(hkeyLayouts); 752 return nCount; 753 } 754 755 BOOL APIENTRY Imm32WriteRegIme(HKL hKL, LPCWSTR pchFilePart, LPCWSTR pszLayout) 756 { 757 UINT iPreload; 758 HKEY hkeyLayouts, hkeyIME, hkeyPreload; 759 WCHAR szImeKey[20], szPreloadNumber[20], szPreloadKey[20], szImeFileName[80]; 760 DWORD cbData; 761 LANGID LangID; 762 LONG lError; 763 LPCWSTR pszLayoutFile; 764 765 /* Open the registry keyboard layouts */ 766 lError = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hkeyLayouts); 767 if (lError != ERROR_SUCCESS) 768 return FALSE; 769 770 /* Get the IME key from hKL */ 771 Imm32UIntToStr((DWORD)(DWORD_PTR)hKL, 16, szImeKey, _countof(szImeKey)); 772 773 /* Create a registry IME key */ 774 lError = RegCreateKeyW(hkeyLayouts, szImeKey, &hkeyIME); 775 if (lError != ERROR_SUCCESS) 776 goto Failure; 777 778 /* Write "Ime File" */ 779 cbData = (wcslen(pchFilePart) + 1) * sizeof(WCHAR); 780 lError = RegSetValueExW(hkeyIME, L"Ime File", 0, REG_SZ, (LPBYTE)pchFilePart, cbData); 781 if (lError != ERROR_SUCCESS) 782 goto Failure; 783 784 /* Write "Layout Text" */ 785 cbData = (wcslen(pszLayout) + 1) * sizeof(WCHAR); 786 lError = RegSetValueExW(hkeyIME, L"Layout Text", 0, REG_SZ, (LPBYTE)pszLayout, cbData); 787 if (lError != ERROR_SUCCESS) 788 goto Failure; 789 790 /* Choose "Layout File" from hKL */ 791 LangID = LOWORD(hKL); 792 switch (LOBYTE(LangID)) 793 { 794 case LANG_JAPANESE: pszLayoutFile = L"kbdjpn.dll"; break; 795 case LANG_KOREAN: pszLayoutFile = L"kbdkor.dll"; break; 796 default: pszLayoutFile = L"kbdus.dll"; break; 797 } 798 StringCchCopyW(szImeFileName, _countof(szImeFileName), pszLayoutFile); 799 800 /* Write "Layout File" */ 801 cbData = (wcslen(szImeFileName) + 1) * sizeof(WCHAR); 802 lError = RegSetValueExW(hkeyIME, L"Layout File", 0, REG_SZ, (LPBYTE)szImeFileName, cbData); 803 if (lError != ERROR_SUCCESS) 804 goto Failure; 805 806 RegCloseKey(hkeyIME); 807 RegCloseKey(hkeyLayouts); 808 809 /* Create "Preload" key */ 810 RegCreateKeyW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", &hkeyPreload); 811 812 #define MAX_PRELOAD 0x400 813 for (iPreload = 1; iPreload < MAX_PRELOAD; ++iPreload) 814 { 815 Imm32UIntToStr(iPreload, 10, szPreloadNumber, _countof(szPreloadNumber)); 816 817 /* Load the key of the preload number */ 818 cbData = sizeof(szPreloadKey); 819 lError = RegQueryValueExW(hkeyPreload, szPreloadNumber, NULL, NULL, 820 (LPBYTE)szPreloadKey, &cbData); 821 szPreloadKey[_countof(szPreloadKey) - 1] = 0; 822 823 if (lError != ERROR_SUCCESS || lstrcmpiW(szImeKey, szPreloadKey) == 0) 824 break; /* Found an empty room or the same key */ 825 } 826 827 if (iPreload >= MAX_PRELOAD) /* Not found */ 828 { 829 RegCloseKey(hkeyPreload); 830 return FALSE; 831 } 832 #undef MAX_PRELOAD 833 834 /* Write the IME key to the preload number */ 835 cbData = (wcslen(szImeKey) + 1) * sizeof(WCHAR); 836 lError = RegSetValueExW(hkeyPreload, szPreloadNumber, 0, REG_SZ, (LPBYTE)szImeKey, cbData); 837 RegCloseKey(hkeyPreload); 838 return lError == ERROR_SUCCESS; 839 840 Failure: 841 RegCloseKey(hkeyIME); 842 RegDeleteKeyW(hkeyLayouts, szImeKey); 843 RegCloseKey(hkeyLayouts); 844 return FALSE; 845 } 846 847 typedef INT (WINAPI *FN_LZOpenFileW)(LPWSTR, LPOFSTRUCT, WORD); 848 typedef LONG (WINAPI *FN_LZCopy)(INT, INT); 849 typedef VOID (WINAPI *FN_LZClose)(INT); 850 851 BOOL APIENTRY Imm32CopyFile(LPWSTR pszOldFile, LPCWSTR pszNewFile) 852 { 853 BOOL ret = FALSE, bLoaded = FALSE; 854 HMODULE hinstLZ32; 855 WCHAR szLZ32Path[MAX_PATH]; 856 CHAR szDestA[MAX_PATH]; 857 OFSTRUCT OFStruct; 858 FN_LZOpenFileW fnLZOpenFileW; 859 FN_LZCopy fnLZCopy; 860 FN_LZClose fnLZClose; 861 HFILE hfDest, hfSrc; 862 863 /* Load LZ32.dll for copying/decompressing file */ 864 Imm32GetSystemLibraryPath(szLZ32Path, _countof(szLZ32Path), L"LZ32"); 865 hinstLZ32 = GetModuleHandleW(szLZ32Path); 866 if (!hinstLZ32) 867 { 868 hinstLZ32 = LoadLibraryW(szLZ32Path); 869 if (!hinstLZ32) 870 return FALSE; 871 bLoaded = TRUE; 872 } 873 874 #define GET_FN(name) do { \ 875 fn##name = (FN_##name)GetProcAddress(hinstLZ32, #name); \ 876 if (!fn##name) goto Quit; \ 877 } while (0) 878 GET_FN(LZOpenFileW); 879 GET_FN(LZCopy); 880 GET_FN(LZClose); 881 #undef GET_FN 882 883 if (!WideCharToMultiByte(CP_ACP, 0, pszNewFile, -1, szDestA, _countof(szDestA), NULL, NULL)) 884 goto Quit; 885 szDestA[_countof(szDestA) - 1] = 0; 886 887 hfSrc = fnLZOpenFileW(pszOldFile, &OFStruct, OF_READ); 888 if (hfSrc < 0) 889 goto Quit; 890 891 hfDest = OpenFile(szDestA, &OFStruct, OF_CREATE); 892 if (hfDest != HFILE_ERROR) 893 { 894 ret = (fnLZCopy(hfSrc, hfDest) >= 0); 895 _lclose(hfDest); 896 } 897 898 fnLZClose(hfSrc); 899 900 Quit: 901 if (bLoaded) 902 FreeLibrary(hinstLZ32); 903 return ret; 904 } 905 906 /*********************************************************************** 907 * CtfImmIsTextFrameServiceDisabled(IMM32.@) 908 */ 909 BOOL WINAPI CtfImmIsTextFrameServiceDisabled(VOID) 910 { 911 return !!(GetWin32ClientInfo()->CI_flags & CI_TFSDISABLED); 912 } 913 914 /*********************************************************************** 915 * ImmCreateIMCC(IMM32.@) 916 */ 917 HIMCC WINAPI ImmCreateIMCC(DWORD size) 918 { 919 if (size < sizeof(DWORD)) 920 size = sizeof(DWORD); 921 return LocalAlloc(LHND, size); 922 } 923 924 /*********************************************************************** 925 * ImmDestroyIMCC(IMM32.@) 926 */ 927 HIMCC WINAPI ImmDestroyIMCC(HIMCC block) 928 { 929 if (block) 930 return LocalFree(block); 931 return NULL; 932 } 933 934 /*********************************************************************** 935 * ImmLockIMCC(IMM32.@) 936 */ 937 LPVOID WINAPI ImmLockIMCC(HIMCC imcc) 938 { 939 if (imcc) 940 return LocalLock(imcc); 941 return NULL; 942 } 943 944 /*********************************************************************** 945 * ImmUnlockIMCC(IMM32.@) 946 */ 947 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc) 948 { 949 if (imcc) 950 return LocalUnlock(imcc); 951 return FALSE; 952 } 953 954 /*********************************************************************** 955 * ImmGetIMCCLockCount(IMM32.@) 956 */ 957 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc) 958 { 959 return LocalFlags(imcc) & LMEM_LOCKCOUNT; 960 } 961 962 /*********************************************************************** 963 * ImmReSizeIMCC(IMM32.@) 964 */ 965 HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size) 966 { 967 if (!imcc) 968 return NULL; 969 return LocalReAlloc(imcc, size, LHND); 970 } 971 972 /*********************************************************************** 973 * ImmGetIMCCSize(IMM32.@) 974 */ 975 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc) 976 { 977 if (imcc) 978 return LocalSize(imcc); 979 return 0; 980 } 981 982 /*********************************************************************** 983 * ImmGetIMCLockCount(IMM32.@) 984 */ 985 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC) 986 { 987 DWORD ret; 988 HANDLE hInputContext; 989 PCLIENTIMC pClientImc; 990 991 pClientImc = ImmLockClientImc(hIMC); 992 if (pClientImc == NULL) 993 return 0; 994 995 ret = 0; 996 hInputContext = pClientImc->hInputContext; 997 if (hInputContext) 998 ret = (LocalFlags(hInputContext) & LMEM_LOCKCOUNT); 999 1000 ImmUnlockClientImc(pClientImc); 1001 return ret; 1002 } 1003 1004 /*********************************************************************** 1005 * ImmIMPGetIMEA(IMM32.@) 1006 */ 1007 BOOL WINAPI ImmIMPGetIMEA(HWND hWnd, LPIMEPROA pImePro) 1008 { 1009 FIXME("(%p, %p)\n", hWnd, pImePro); 1010 return FALSE; 1011 } 1012 1013 /*********************************************************************** 1014 * ImmIMPGetIMEW(IMM32.@) 1015 */ 1016 BOOL WINAPI ImmIMPGetIMEW(HWND hWnd, LPIMEPROW pImePro) 1017 { 1018 FIXME("(%p, %p)\n", hWnd, pImePro); 1019 return FALSE; 1020 } 1021 1022 /*********************************************************************** 1023 * ImmIMPQueryIMEA(IMM32.@) 1024 */ 1025 BOOL WINAPI ImmIMPQueryIMEA(LPIMEPROA pImePro) 1026 { 1027 FIXME("(%p)\n", pImePro); 1028 return FALSE; 1029 } 1030 1031 /*********************************************************************** 1032 * ImmIMPQueryIMEW(IMM32.@) 1033 */ 1034 BOOL WINAPI ImmIMPQueryIMEW(LPIMEPROW pImePro) 1035 { 1036 FIXME("(%p)\n", pImePro); 1037 return FALSE; 1038 } 1039 1040 /*********************************************************************** 1041 * ImmIMPSetIMEA(IMM32.@) 1042 */ 1043 BOOL WINAPI ImmIMPSetIMEA(HWND hWnd, LPIMEPROA pImePro) 1044 { 1045 FIXME("(%p, %p)\n", hWnd, pImePro); 1046 return FALSE; 1047 } 1048 1049 /*********************************************************************** 1050 * ImmIMPSetIMEW(IMM32.@) 1051 */ 1052 BOOL WINAPI ImmIMPSetIMEW(HWND hWnd, LPIMEPROW pImePro) 1053 { 1054 FIXME("(%p, %p)\n", hWnd, pImePro); 1055 return FALSE; 1056 } 1057