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-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 10 */ 11 12 #include "precomp.h" 13 14 WINE_DEFAULT_DEBUG_CHANNEL(imm); 15 16 HANDLE ghImmHeap = NULL; // Win: pImmHeap 17 18 /* Win: PtiCurrent */ 19 PTHREADINFO FASTCALL Imm32CurrentPti(VOID) 20 { 21 if (NtCurrentTeb()->Win32ThreadInfo == NULL) 22 NtUserGetThreadState(THREADSTATE_GETTHREADINFO); 23 return NtCurrentTeb()->Win32ThreadInfo; 24 } 25 26 BOOL APIENTRY Imm32IsCrossThreadAccess(HIMC hIMC) 27 { 28 DWORD_PTR dwImeThreadId = NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID); 29 DWORD_PTR dwCurrentThreadId = GetCurrentThreadId(); 30 return dwImeThreadId != dwCurrentThreadId; 31 } 32 33 // Win: TestWindowProcess 34 BOOL APIENTRY Imm32IsCrossProcessAccess(HWND hWnd) 35 { 36 DWORD_PTR WndPID = NtUserQueryWindow(hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID); 37 DWORD_PTR CurrentPID = (DWORD_PTR)NtCurrentTeb()->ClientId.UniqueProcess; 38 return WndPID != CurrentPID; 39 } 40 41 // Win: StrToUInt 42 HRESULT APIENTRY 43 Imm32StrToUInt(LPCWSTR pszText, LPDWORD pdwValue, ULONG nBase) 44 { 45 NTSTATUS Status; 46 UNICODE_STRING UnicodeString; 47 RtlInitUnicodeString(&UnicodeString, pszText); 48 Status = RtlUnicodeStringToInteger(&UnicodeString, nBase, pdwValue); 49 if (!NT_SUCCESS(Status)) 50 return E_FAIL; 51 return S_OK; 52 } 53 54 // Win: UIntToStr 55 HRESULT APIENTRY 56 Imm32UIntToStr(DWORD dwValue, ULONG nBase, LPWSTR pszBuff, USHORT cchBuff) 57 { 58 NTSTATUS Status; 59 UNICODE_STRING UnicodeString; 60 UnicodeString.Buffer = pszBuff; 61 UnicodeString.MaximumLength = cchBuff * sizeof(WCHAR); 62 Status = RtlIntegerToUnicodeString(dwValue, nBase, &UnicodeString); 63 if (!NT_SUCCESS(Status)) 64 return E_FAIL; 65 return S_OK; 66 } 67 68 /* Win: CheckCountry */ 69 BOOL APIENTRY Imm32IsSystemJapaneseOrKorean(VOID) 70 { 71 LCID lcid = GetSystemDefaultLCID(); 72 LANGID LangID = LANGIDFROMLCID(lcid); 73 WORD wPrimary = PRIMARYLANGID(LangID); 74 if (wPrimary != LANG_JAPANESE || wPrimary != LANG_KOREAN) 75 { 76 TRACE("The country has no special IME support\n"); 77 return FALSE; 78 } 79 return TRUE; 80 } 81 82 typedef struct tagBITMAPCOREINFO256 83 { 84 BITMAPCOREHEADER bmciHeader; 85 RGBTRIPLE bmciColors[256]; 86 } BITMAPCOREINFO256, *PBITMAPCOREINFO256; 87 88 HBITMAP Imm32LoadBitmapFromBytes(const BYTE *pb) 89 { 90 HBITMAP hbm = NULL; 91 const BITMAPCOREINFO256 *pbmci; 92 LPVOID pvBits; 93 DWORD ib, cbBytes, cColors; 94 BITMAP bm; 95 96 cbBytes = *(const DWORD *)pb; 97 if (cbBytes == 0) 98 return NULL; 99 100 pb += sizeof(DWORD); 101 ib = sizeof(DWORD); 102 103 pbmci = (const BITMAPCOREINFO256 *)pb; 104 hbm = CreateDIBSection(NULL, (LPBITMAPINFO)pbmci, DIB_RGB_COLORS, &pvBits, NULL, 0); 105 if (!hbm || !GetObject(hbm, sizeof(BITMAP), &bm)) 106 { 107 ERR("Invalid bitmap\n"); 108 return NULL; 109 } 110 111 switch (pbmci->bmciHeader.bcBitCount) 112 { 113 case 1: cColors = 2; break; 114 case 4: cColors = 16; break; 115 case 8: cColors = 256; break; 116 case 24: case 32: 117 cColors = 0; 118 break; 119 default: 120 ERR("Invalid bitmap\n"); 121 DeleteObject(hbm); 122 return NULL; 123 } 124 125 ib += sizeof(BITMAPCOREHEADER); 126 pb += sizeof(BITMAPCOREHEADER); 127 128 ib += cColors * sizeof(RGBTRIPLE); 129 pb += cColors * sizeof(RGBTRIPLE); 130 131 ib += bm.bmWidthBytes * bm.bmHeight; 132 if (ib > cbBytes) 133 { 134 ERR("Invalid bitmap\n"); 135 DeleteObject(hbm); 136 return NULL; 137 } 138 RtlCopyMemory(pvBits, pb, bm.bmWidthBytes * bm.bmHeight); 139 140 return hbm; 141 } 142 143 BOOL Imm32StoreBitmapToBytes(HBITMAP hbm, LPBYTE pbData, DWORD cbDataMax) 144 { 145 HDC hDC; 146 BITMAP bm; 147 DWORD cbBytes, cColors; 148 BITMAPCOREINFO256 bmci; 149 BOOL ret; 150 LPBYTE pb = pbData; 151 152 *(LPDWORD)pb = 0; 153 154 if (!GetObject(hbm, sizeof(BITMAP), &bm)) 155 { 156 ERR("Invalid bitmap\n"); 157 return FALSE; 158 } 159 160 ZeroMemory(&bmci, sizeof(bmci)); 161 bmci.bmciHeader.bcSize = sizeof(BITMAPCOREHEADER); 162 bmci.bmciHeader.bcWidth = bm.bmWidth; 163 bmci.bmciHeader.bcHeight = bm.bmHeight; 164 bmci.bmciHeader.bcPlanes = 1; 165 bmci.bmciHeader.bcBitCount = bm.bmBitsPixel; 166 167 switch (bm.bmBitsPixel) 168 { 169 case 1: cColors = 2; break; 170 case 4: cColors = 16; break; 171 case 8: cColors = 256; break; 172 case 24: case 32: 173 cColors = 0; 174 break; 175 default: 176 ERR("Invalid bitmap\n"); 177 return FALSE; 178 } 179 180 cbBytes = sizeof(DWORD); 181 cbBytes += sizeof(BITMAPCOREHEADER); 182 cbBytes += cColors * sizeof(RGBTRIPLE); 183 cbBytes += bm.bmWidthBytes * bm.bmHeight; 184 if (cbBytes > cbDataMax) 185 { 186 ERR("Too small\n"); 187 return FALSE; 188 } 189 190 hDC = CreateCompatibleDC(NULL); 191 192 ret = GetDIBits(hDC, hbm, 0, bm.bmHeight, NULL, (LPBITMAPINFO)&bmci, DIB_RGB_COLORS); 193 194 if (ret) 195 { 196 *(LPDWORD)pb = cbBytes; 197 pb += sizeof(DWORD); 198 199 RtlCopyMemory(pb, &bmci.bmciHeader, sizeof(BITMAPCOREHEADER)); 200 pb += sizeof(BITMAPCOREHEADER); 201 202 RtlCopyMemory(pb, &bmci.bmciColors, cColors * sizeof(RGBTRIPLE)); 203 pb += cColors * sizeof(RGBTRIPLE); 204 205 ret = GetDIBits(hDC, hbm, 0, bm.bmHeight, pb, (LPBITMAPINFO)&bmci, DIB_RGB_COLORS); 206 if (!ret) 207 *(LPDWORD)pbData = 0; 208 } 209 210 DeleteDC(hDC); 211 212 return ret; 213 } 214 215 // Win: IsAnsiIMC 216 BOOL WINAPI Imm32IsImcAnsi(HIMC hIMC) 217 { 218 BOOL ret; 219 PCLIENTIMC pClientImc = ImmLockClientImc(hIMC); 220 if (IS_NULL_UNEXPECTEDLY(pClientImc)) 221 return -1; 222 ret = !(pClientImc->dwFlags & CLIENTIMC_WIDE); 223 ImmUnlockClientImc(pClientImc); 224 return ret; 225 } 226 227 LPWSTR APIENTRY Imm32WideFromAnsi(UINT uCodePage, LPCSTR pszA) 228 { 229 INT cch = lstrlenA(pszA); 230 LPWSTR pszW = ImmLocalAlloc(0, (cch + 1) * sizeof(WCHAR)); 231 if (IS_NULL_UNEXPECTEDLY(pszW)) 232 return NULL; 233 cch = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pszA, cch, pszW, cch + 1); 234 pszW[cch] = 0; 235 return pszW; 236 } 237 238 LPSTR APIENTRY Imm32AnsiFromWide(UINT uCodePage, LPCWSTR pszW) 239 { 240 INT cchW = lstrlenW(pszW); 241 INT cchA = (cchW + 1) * sizeof(WCHAR); 242 LPSTR pszA = ImmLocalAlloc(0, cchA); 243 if (IS_NULL_UNEXPECTEDLY(pszA)) 244 return NULL; 245 cchA = WideCharToMultiByte(uCodePage, 0, pszW, cchW, pszA, cchA, NULL, NULL); 246 pszA[cchA] = 0; 247 return pszA; 248 } 249 250 /* Converts the character index */ 251 /* Win: CalcCharacterPositionAtoW */ 252 LONG APIENTRY IchWideFromAnsi(LONG cchAnsi, LPCSTR pchAnsi, UINT uCodePage) 253 { 254 LONG cchWide; 255 for (cchWide = 0; cchAnsi > 0; ++cchWide) 256 { 257 if (IsDBCSLeadByteEx(uCodePage, *pchAnsi) && pchAnsi[1]) 258 { 259 cchAnsi -= 2; 260 pchAnsi += 2; 261 } 262 else 263 { 264 --cchAnsi; 265 ++pchAnsi; 266 } 267 } 268 return cchWide; 269 } 270 271 /* Converts the character index */ 272 /* Win: CalcCharacterPositionWtoA */ 273 LONG APIENTRY IchAnsiFromWide(LONG cchWide, LPCWSTR pchWide, UINT uCodePage) 274 { 275 LONG cb, cchAnsi; 276 for (cchAnsi = 0; cchWide > 0; ++cchAnsi, ++pchWide, --cchWide) 277 { 278 cb = WideCharToMultiByte(uCodePage, 0, pchWide, 1, NULL, 0, NULL, NULL); 279 if (cb > 1) 280 ++cchAnsi; 281 } 282 return cchAnsi; 283 } 284 285 // Win: InternalGetSystemPathName 286 BOOL Imm32GetSystemLibraryPath(LPWSTR pszPath, DWORD cchPath, LPCWSTR pszFileName) 287 { 288 if (!pszFileName[0] || !GetSystemDirectoryW(pszPath, cchPath)) 289 { 290 ERR("Invalid filename\n"); 291 return FALSE; 292 } 293 StringCchCatW(pszPath, cchPath, L"\\"); 294 StringCchCatW(pszPath, cchPath, pszFileName); 295 return TRUE; 296 } 297 298 // Win: LFontAtoLFontW 299 VOID APIENTRY LogFontAnsiToWide(const LOGFONTA *plfA, LPLOGFONTW plfW) 300 { 301 size_t cch; 302 RtlCopyMemory(plfW, plfA, offsetof(LOGFONTA, lfFaceName)); 303 StringCchLengthA(plfA->lfFaceName, _countof(plfA->lfFaceName), &cch); 304 cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plfA->lfFaceName, (INT)cch, 305 plfW->lfFaceName, _countof(plfW->lfFaceName)); 306 if (cch > _countof(plfW->lfFaceName) - 1) 307 cch = _countof(plfW->lfFaceName) - 1; 308 plfW->lfFaceName[cch] = 0; 309 } 310 311 // Win: LFontWtoLFontA 312 VOID APIENTRY LogFontWideToAnsi(const LOGFONTW *plfW, LPLOGFONTA plfA) 313 { 314 size_t cch; 315 RtlCopyMemory(plfA, plfW, offsetof(LOGFONTW, lfFaceName)); 316 StringCchLengthW(plfW->lfFaceName, _countof(plfW->lfFaceName), &cch); 317 cch = WideCharToMultiByte(CP_ACP, 0, plfW->lfFaceName, (INT)cch, 318 plfA->lfFaceName, _countof(plfA->lfFaceName), NULL, NULL); 319 if (cch > _countof(plfA->lfFaceName) - 1) 320 cch = _countof(plfA->lfFaceName) - 1; 321 plfA->lfFaceName[cch] = 0; 322 } 323 324 static PVOID FASTCALL DesktopPtrToUser(PVOID ptr) 325 { 326 PCLIENTINFO pci = GetWin32ClientInfo(); 327 PDESKTOPINFO pdi = pci->pDeskInfo; 328 329 ASSERT(ptr != NULL); 330 ASSERT(pdi != NULL); 331 if (pdi->pvDesktopBase <= ptr && ptr < pdi->pvDesktopLimit) 332 return (PVOID)((ULONG_PTR)ptr - pci->ulClientDelta); 333 else 334 return (PVOID)NtUserCallOneParam((DWORD_PTR)ptr, ONEPARAM_ROUTINE_GETDESKTOPMAPPING); 335 } 336 337 // Win: HMValidateHandleNoRip 338 LPVOID FASTCALL ValidateHandleNoErr(HANDLE hObject, UINT uType) 339 { 340 UINT index; 341 PUSER_HANDLE_TABLE ht; 342 PUSER_HANDLE_ENTRY he; 343 WORD generation; 344 LPVOID ptr; 345 346 if (!NtUserValidateHandleSecure(hObject)) 347 { 348 WARN("Not a handle\n"); 349 return NULL; 350 } 351 352 ht = gSharedInfo.aheList; /* handle table */ 353 ASSERT(ht); 354 /* ReactOS-Specific! */ 355 ASSERT(gSharedInfo.ulSharedDelta != 0); 356 he = (PUSER_HANDLE_ENTRY)((ULONG_PTR)ht->handles - gSharedInfo.ulSharedDelta); 357 358 index = (LOWORD(hObject) - FIRST_USER_HANDLE) >> 1; 359 if ((INT)index < 0 || ht->nb_handles <= index || he[index].type != uType) 360 return NULL; 361 362 if (he[index].flags & HANDLEENTRY_DESTROY) 363 return NULL; 364 365 generation = HIWORD(hObject); 366 if (generation != he[index].generation && generation && generation != 0xFFFF) 367 return NULL; 368 369 ptr = he[index].ptr; 370 if (ptr) 371 ptr = DesktopPtrToUser(ptr); 372 373 return ptr; 374 } 375 376 // Win: HMValidateHandle 377 LPVOID FASTCALL ValidateHandle(HANDLE hObject, UINT uType) 378 { 379 LPVOID pvObj = ValidateHandleNoErr(hObject, uType); 380 if (pvObj) 381 return pvObj; 382 383 if (uType == TYPE_WINDOW) 384 SetLastError(ERROR_INVALID_WINDOW_HANDLE); 385 else 386 SetLastError(ERROR_INVALID_HANDLE); 387 return NULL; 388 } 389 390 // Win: TestInputContextProcess 391 BOOL APIENTRY Imm32CheckImcProcess(PIMC pIMC) 392 { 393 HIMC hIMC; 394 DWORD_PTR dwPID1, dwPID2; 395 396 if (IS_NULL_UNEXPECTEDLY(pIMC)) 397 return FALSE; 398 399 if (pIMC->head.pti == Imm32CurrentPti()) 400 return TRUE; 401 402 hIMC = pIMC->head.h; 403 dwPID1 = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTPROCESSID); 404 dwPID2 = (DWORD_PTR)NtCurrentTeb()->ClientId.UniqueProcess; 405 if (dwPID1 != dwPID2) 406 { 407 WARN("PID 0x%X != 0x%X\n", dwPID1, dwPID2); 408 return FALSE; 409 } 410 411 return TRUE; 412 } 413 414 // Win: ImmLocalAlloc 415 LPVOID APIENTRY ImmLocalAlloc(DWORD dwFlags, DWORD dwBytes) 416 { 417 if (!ghImmHeap) 418 { 419 ghImmHeap = RtlGetProcessHeap(); 420 if (IS_NULL_UNEXPECTEDLY(ghImmHeap)) 421 return NULL; 422 } 423 return HeapAlloc(ghImmHeap, dwFlags, dwBytes); 424 } 425 426 // Win: MakeIMENotify 427 BOOL APIENTRY 428 Imm32MakeIMENotify(HIMC hIMC, HWND hwnd, DWORD dwAction, DWORD_PTR dwIndex, DWORD_PTR dwValue, 429 DWORD_PTR dwCommand, DWORD_PTR dwData) 430 { 431 DWORD dwThreadId; 432 HKL hKL; 433 PIMEDPI pImeDpi; 434 435 if (dwAction != 0) 436 { 437 dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID); 438 if (dwThreadId) 439 { 440 /* find keyboard layout and lock it */ 441 hKL = GetKeyboardLayout(dwThreadId); 442 pImeDpi = ImmLockImeDpi(hKL); 443 if (pImeDpi) 444 { 445 /* do notify */ 446 pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue); 447 448 ImmUnlockImeDpi(pImeDpi); /* unlock */ 449 } 450 } 451 } 452 453 if (hwnd && dwCommand) 454 SendMessageW(hwnd, WM_IME_NOTIFY, dwCommand, dwData); 455 456 return TRUE; 457 } 458 459 // Win: BuildHimcList 460 DWORD APIENTRY Imm32BuildHimcList(DWORD dwThreadId, HIMC **pphList) 461 { 462 #define INITIAL_COUNT 0x40 463 #define MAX_RETRY 10 464 NTSTATUS Status; 465 DWORD dwCount = INITIAL_COUNT, cRetry = 0; 466 HIMC *phNewList; 467 468 phNewList = ImmLocalAlloc(0, dwCount * sizeof(HIMC)); 469 if (IS_NULL_UNEXPECTEDLY(phNewList)) 470 return 0; 471 472 Status = NtUserBuildHimcList(dwThreadId, dwCount, phNewList, &dwCount); 473 while (Status == STATUS_BUFFER_TOO_SMALL) 474 { 475 ImmLocalFree(phNewList); 476 if (cRetry++ >= MAX_RETRY) 477 return 0; 478 479 phNewList = ImmLocalAlloc(0, dwCount * sizeof(HIMC)); 480 if (IS_NULL_UNEXPECTEDLY(phNewList)) 481 return 0; 482 483 Status = NtUserBuildHimcList(dwThreadId, dwCount, phNewList, &dwCount); 484 } 485 486 if (NT_ERROR(Status) || !dwCount) 487 { 488 ERR("Abnormal status\n"); 489 ImmLocalFree(phNewList); 490 return 0; 491 } 492 493 *pphList = phNewList; 494 return dwCount; 495 #undef INITIAL_COUNT 496 #undef MAX_RETRY 497 } 498 499 // Win: ConvertImeMenuItemInfoAtoW 500 INT APIENTRY 501 Imm32ImeMenuAnsiToWide(const IMEMENUITEMINFOA *pItemA, LPIMEMENUITEMINFOW pItemW, 502 UINT uCodePage, BOOL bBitmap) 503 { 504 INT ret; 505 pItemW->cbSize = pItemA->cbSize; 506 pItemW->fType = pItemA->fType; 507 pItemW->fState = pItemA->fState; 508 pItemW->wID = pItemA->wID; 509 if (bBitmap) 510 { 511 pItemW->hbmpChecked = pItemA->hbmpChecked; 512 pItemW->hbmpUnchecked = pItemA->hbmpUnchecked; 513 pItemW->hbmpItem = pItemA->hbmpItem; 514 } 515 pItemW->dwItemData = pItemA->dwItemData; 516 ret = MultiByteToWideChar(uCodePage, 0, pItemA->szString, -1, 517 pItemW->szString, _countof(pItemW->szString)); 518 if (ret >= _countof(pItemW->szString)) 519 { 520 ret = 0; 521 pItemW->szString[0] = 0; 522 } 523 return ret; 524 } 525 526 // Win: ConvertImeMenuItemInfoWtoA 527 INT APIENTRY 528 Imm32ImeMenuWideToAnsi(const IMEMENUITEMINFOW *pItemW, LPIMEMENUITEMINFOA pItemA, 529 UINT uCodePage) 530 { 531 INT ret; 532 pItemA->cbSize = pItemW->cbSize; 533 pItemA->fType = pItemW->fType; 534 pItemA->fState = pItemW->fState; 535 pItemA->wID = pItemW->wID; 536 pItemA->hbmpChecked = pItemW->hbmpChecked; 537 pItemA->hbmpUnchecked = pItemW->hbmpUnchecked; 538 pItemA->dwItemData = pItemW->dwItemData; 539 pItemA->hbmpItem = pItemW->hbmpItem; 540 ret = WideCharToMultiByte(uCodePage, 0, pItemW->szString, -1, 541 pItemA->szString, _countof(pItemA->szString), NULL, NULL); 542 if (ret >= _countof(pItemA->szString)) 543 { 544 ret = 0; 545 pItemA->szString[0] = 0; 546 } 547 return ret; 548 } 549 550 // Win: GetImeModeSaver 551 PIME_STATE APIENTRY 552 Imm32FetchImeState(LPINPUTCONTEXTDX pIC, HKL hKL) 553 { 554 PIME_STATE pState; 555 WORD Lang = PRIMARYLANGID(LOWORD(hKL)); 556 for (pState = pIC->pState; pState; pState = pState->pNext) 557 { 558 if (pState->wLang == Lang) 559 break; 560 } 561 if (!pState) 562 { 563 pState = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(IME_STATE)); 564 if (pState) 565 { 566 pState->wLang = Lang; 567 pState->pNext = pIC->pState; 568 pIC->pState = pState; 569 } 570 } 571 return pState; 572 } 573 574 // Win: GetImePrivateModeSaver 575 PIME_SUBSTATE APIENTRY 576 Imm32FetchImeSubState(PIME_STATE pState, HKL hKL) 577 { 578 PIME_SUBSTATE pSubState; 579 for (pSubState = pState->pSubState; pSubState; pSubState = pSubState->pNext) 580 { 581 if (pSubState->hKL == hKL) 582 return pSubState; 583 } 584 pSubState = ImmLocalAlloc(0, sizeof(IME_SUBSTATE)); 585 if (!pSubState) 586 return NULL; 587 pSubState->dwValue = 0; 588 pSubState->hKL = hKL; 589 pSubState->pNext = pState->pSubState; 590 pState->pSubState = pSubState; 591 return pSubState; 592 } 593 594 // Win: RestorePrivateMode 595 BOOL APIENTRY 596 Imm32LoadImeStateSentence(LPINPUTCONTEXTDX pIC, PIME_STATE pState, HKL hKL) 597 { 598 PIME_SUBSTATE pSubState = Imm32FetchImeSubState(pState, hKL); 599 if (IS_NULL_UNEXPECTEDLY(pSubState)) 600 return FALSE; 601 602 pIC->fdwSentence |= pSubState->dwValue; 603 return TRUE; 604 } 605 606 // Win: SavePrivateMode 607 BOOL APIENTRY 608 Imm32SaveImeStateSentence(LPINPUTCONTEXTDX pIC, PIME_STATE pState, HKL hKL) 609 { 610 PIME_SUBSTATE pSubState = Imm32FetchImeSubState(pState, hKL); 611 if (IS_NULL_UNEXPECTEDLY(pSubState)) 612 return FALSE; 613 614 pSubState->dwValue = (pIC->fdwSentence & 0xffff0000); 615 return TRUE; 616 } 617 618 /* 619 * See RECONVERTSTRING structure: 620 * https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/RECONVERTSTRING.html 621 * 622 * The dwCompStrOffset and dwTargetOffset members are the relative position of dwStrOffset. 623 * dwStrLen, dwCompStrLen, and dwTargetStrLen are the TCHAR count. dwStrOffset, 624 * dwCompStrOffset, and dwTargetStrOffset are the byte offset. 625 */ 626 627 DWORD APIENTRY 628 Imm32ReconvertWideFromAnsi(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc, UINT uCodePage) 629 { 630 DWORD cch0, cchDest, cbDest; 631 LPCSTR pchSrc = (LPCSTR)pSrc + pSrc->dwStrOffset; 632 LPWSTR pchDest; 633 634 if (pSrc->dwVersion != 0) 635 { 636 ERR("\n"); 637 return 0; 638 } 639 640 cchDest = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pchSrc, pSrc->dwStrLen, 641 NULL, 0); 642 cbDest = sizeof(RECONVERTSTRING) + (cchDest + 1) * sizeof(WCHAR); 643 if (!pDest) 644 return cbDest; 645 646 if (pDest->dwSize < cbDest) 647 { 648 ERR("Too small\n"); 649 return 0; 650 } 651 652 /* dwSize */ 653 pDest->dwSize = cbDest; 654 655 /* dwVersion */ 656 pDest->dwVersion = 0; 657 658 /* dwStrOffset */ 659 pDest->dwStrOffset = sizeof(RECONVERTSTRING); 660 661 /* dwCompStrOffset */ 662 cch0 = IchWideFromAnsi(pSrc->dwCompStrOffset, pchSrc, uCodePage); 663 pDest->dwCompStrOffset = cch0 * sizeof(WCHAR); 664 665 /* dwCompStrLen */ 666 cch0 = IchWideFromAnsi(pSrc->dwCompStrOffset + pSrc->dwCompStrLen, pchSrc, uCodePage); 667 pDest->dwCompStrLen = (cch0 * sizeof(WCHAR) - pDest->dwCompStrOffset) / sizeof(WCHAR); 668 669 /* dwTargetStrOffset */ 670 cch0 = IchWideFromAnsi(pSrc->dwTargetStrOffset, pchSrc, uCodePage); 671 pDest->dwTargetStrOffset = cch0 * sizeof(WCHAR); 672 673 /* dwTargetStrLen */ 674 cch0 = IchWideFromAnsi(pSrc->dwTargetStrOffset + pSrc->dwTargetStrLen, pchSrc, uCodePage); 675 pDest->dwTargetStrLen = (cch0 * sizeof(WCHAR) - pSrc->dwTargetStrOffset) / sizeof(WCHAR); 676 677 /* dwStrLen */ 678 pDest->dwStrLen = cchDest; 679 680 /* the string */ 681 pchDest = (LPWSTR)((LPBYTE)pDest + pDest->dwStrOffset); 682 cchDest = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pchSrc, pSrc->dwStrLen, 683 pchDest, cchDest); 684 pchDest[cchDest] = 0; 685 686 TRACE("cbDest: 0x%X\n", cbDest); 687 return cbDest; 688 } 689 690 DWORD APIENTRY 691 Imm32ReconvertAnsiFromWide(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc, UINT uCodePage) 692 { 693 DWORD cch0, cch1, cchDest, cbDest; 694 LPCWSTR pchSrc = (LPCWSTR)((LPCSTR)pSrc + pSrc->dwStrOffset); 695 LPSTR pchDest; 696 697 if (pSrc->dwVersion != 0) 698 { 699 ERR("\n"); 700 return 0; 701 } 702 703 cchDest = WideCharToMultiByte(uCodePage, 0, pchSrc, pSrc->dwStrLen, 704 NULL, 0, NULL, NULL); 705 cbDest = sizeof(RECONVERTSTRING) + (cchDest + 1) * sizeof(CHAR); 706 if (!pDest) 707 return cbDest; 708 709 if (pDest->dwSize < cbDest) 710 { 711 ERR("Too small\n"); 712 return 0; 713 } 714 715 /* dwSize */ 716 pDest->dwSize = cbDest; 717 718 /* dwVersion */ 719 pDest->dwVersion = 0; 720 721 /* dwStrOffset */ 722 pDest->dwStrOffset = sizeof(RECONVERTSTRING); 723 724 /* dwCompStrOffset */ 725 cch1 = pSrc->dwCompStrOffset / sizeof(WCHAR); 726 cch0 = IchAnsiFromWide(cch1, pchSrc, uCodePage); 727 pDest->dwCompStrOffset = cch0 * sizeof(CHAR); 728 729 /* dwCompStrLen */ 730 cch0 = IchAnsiFromWide(cch1 + pSrc->dwCompStrLen, pchSrc, uCodePage); 731 pDest->dwCompStrLen = cch0 * sizeof(CHAR) - pDest->dwCompStrOffset; 732 733 /* dwTargetStrOffset */ 734 cch1 = pSrc->dwTargetStrOffset / sizeof(WCHAR); 735 cch0 = IchAnsiFromWide(cch1, pchSrc, uCodePage); 736 pDest->dwTargetStrOffset = cch0 * sizeof(CHAR); 737 738 /* dwTargetStrLen */ 739 cch0 = IchAnsiFromWide(cch1 + pSrc->dwTargetStrLen, pchSrc, uCodePage); 740 pDest->dwTargetStrLen = cch0 * sizeof(CHAR) - pDest->dwTargetStrOffset; 741 742 /* dwStrLen */ 743 pDest->dwStrLen = cchDest; 744 745 /* the string */ 746 pchDest = (LPSTR)pDest + pDest->dwStrOffset; 747 cchDest = WideCharToMultiByte(uCodePage, 0, pchSrc, pSrc->dwStrLen, 748 pchDest, cchDest, NULL, NULL); 749 pchDest[cchDest] = 0; 750 751 TRACE("cchDest: 0x%X\n", cchDest); 752 return cbDest; 753 } 754 755 typedef BOOL (WINAPI *FN_GetFileVersionInfoW)(LPCWSTR, DWORD, DWORD, LPVOID); 756 typedef DWORD (WINAPI *FN_GetFileVersionInfoSizeW)(LPCWSTR, LPDWORD); 757 typedef BOOL (WINAPI *FN_VerQueryValueW)(LPCVOID, LPCWSTR, LPVOID*, PUINT); 758 759 static FN_GetFileVersionInfoW s_fnGetFileVersionInfoW = NULL; 760 static FN_GetFileVersionInfoSizeW s_fnGetFileVersionInfoSizeW = NULL; 761 static FN_VerQueryValueW s_fnVerQueryValueW = NULL; 762 763 // Win: LoadFixVersionInfo 764 static BOOL APIENTRY Imm32LoadImeFixedInfo(PIMEINFOEX pInfoEx, LPCVOID pVerInfo) 765 { 766 UINT cbFixed = 0; 767 VS_FIXEDFILEINFO *pFixed; 768 if (!s_fnVerQueryValueW(pVerInfo, L"\\", (LPVOID*)&pFixed, &cbFixed) || !cbFixed) 769 { 770 ERR("Fixed version info not available\n"); 771 return FALSE; 772 } 773 774 /* NOTE: The IME module must contain a version info of input method driver. */ 775 if (pFixed->dwFileType != VFT_DRV || pFixed->dwFileSubtype != VFT2_DRV_INPUTMETHOD) 776 { 777 ERR("DLL is not an IME\n"); 778 return FALSE; 779 } 780 781 pInfoEx->dwProdVersion = pFixed->dwProductVersionMS; 782 pInfoEx->dwImeWinVersion = 0x40000; 783 return TRUE; 784 } 785 786 // Win: GetVersionDatum 787 static LPWSTR APIENTRY 788 Imm32GetVerInfoValue(LPCVOID pVerInfo, LPWSTR pszKey, DWORD cchKey, LPCWSTR pszName) 789 { 790 size_t cchExtra; 791 LPWSTR pszValue; 792 UINT cbValue = 0; 793 794 StringCchLengthW(pszKey, cchKey, &cchExtra); 795 796 StringCchCatW(pszKey, cchKey, pszName); 797 s_fnVerQueryValueW(pVerInfo, pszKey, (LPVOID*)&pszValue, &cbValue); 798 pszKey[cchExtra] = 0; 799 800 return (cbValue ? pszValue : NULL); 801 } 802 803 // Win: LoadVarVersionInfo 804 BOOL APIENTRY Imm32LoadImeLangAndDesc(PIMEINFOEX pInfoEx, LPCVOID pVerInfo) 805 { 806 BOOL ret; 807 WCHAR szKey[80]; 808 LPWSTR pszDesc; 809 LPWORD pw; 810 UINT cbData; 811 LANGID LangID; 812 813 /* Getting the version info. See VerQueryValue */ 814 ret = s_fnVerQueryValueW(pVerInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&pw, &cbData); 815 if (!ret || !cbData) 816 { 817 ERR("Translation not available\n"); 818 return FALSE; 819 } 820 821 if (pInfoEx->hkl == NULL) 822 pInfoEx->hkl = (HKL)(DWORD_PTR)*pw; 823 824 /* Try the current language and the Unicode codepage (0x04B0) */ 825 LangID = LANGIDFROMLCID(GetThreadLocale()); 826 StringCchPrintfW(szKey, _countof(szKey), L"\\StringFileInfo\\%04X04B0\\", LangID); 827 pszDesc = Imm32GetVerInfoValue(pVerInfo, szKey, _countof(szKey), L"FileDescription"); 828 if (!pszDesc) 829 { 830 /* Retry the language and codepage of the IME module */ 831 StringCchPrintfW(szKey, _countof(szKey), L"\\StringFileInfo\\%04X%04X\\", pw[0], pw[1]); 832 pszDesc = Imm32GetVerInfoValue(pVerInfo, szKey, _countof(szKey), L"FileDescription"); 833 } 834 835 /* The description */ 836 if (pszDesc) 837 StringCchCopyW(pInfoEx->wszImeDescription, _countof(pInfoEx->wszImeDescription), pszDesc); 838 else 839 pInfoEx->wszImeDescription[0] = 0; 840 841 return TRUE; 842 } 843 844 // Win: LoadVersionInfo 845 BOOL APIENTRY Imm32LoadImeVerInfo(PIMEINFOEX pImeInfoEx) 846 { 847 HINSTANCE hinstVersion; 848 BOOL ret = FALSE, bLoaded = FALSE; 849 WCHAR szPath[MAX_PATH]; 850 LPVOID pVerInfo; 851 DWORD cbVerInfo, dwHandle; 852 853 /* Load version.dll to use the version info API */ 854 Imm32GetSystemLibraryPath(szPath, _countof(szPath), L"version.dll"); 855 hinstVersion = GetModuleHandleW(szPath); 856 if (!hinstVersion) 857 { 858 hinstVersion = LoadLibraryW(szPath); 859 if (IS_NULL_UNEXPECTEDLY(hinstVersion)) 860 return FALSE; 861 862 bLoaded = TRUE; 863 } 864 865 #define GET_FN(name) do { \ 866 s_fn##name = (FN_##name)GetProcAddress(hinstVersion, #name); \ 867 if (!s_fn##name) goto Quit; \ 868 } while (0) 869 GET_FN(GetFileVersionInfoW); 870 GET_FN(GetFileVersionInfoSizeW); 871 GET_FN(VerQueryValueW); 872 #undef GET_FN 873 874 /* The path of the IME module */ 875 Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile); 876 877 cbVerInfo = s_fnGetFileVersionInfoSizeW(szPath, &dwHandle); 878 if (IS_ZERO_UNEXPECTEDLY(cbVerInfo)) 879 goto Quit; 880 881 pVerInfo = ImmLocalAlloc(0, cbVerInfo); 882 if (IS_NULL_UNEXPECTEDLY(pVerInfo)) 883 goto Quit; 884 885 /* Load the version info of the IME module */ 886 if (s_fnGetFileVersionInfoW(szPath, dwHandle, cbVerInfo, pVerInfo) && 887 Imm32LoadImeFixedInfo(pImeInfoEx, pVerInfo)) 888 { 889 ret = Imm32LoadImeLangAndDesc(pImeInfoEx, pVerInfo); 890 } 891 892 ImmLocalFree(pVerInfo); 893 894 Quit: 895 if (bLoaded) 896 FreeLibrary(hinstVersion); 897 TRACE("ret: %d\n", ret); 898 return ret; 899 } 900 901 // Win: AssignNewLayout 902 HKL APIENTRY Imm32AssignNewLayout(UINT cKLs, const REG_IME *pLayouts, WORD wLangID) 903 { 904 UINT iKL, wID, wLow = 0xE0FF, wHigh = 0xE01F, wNextID = 0; 905 906 for (iKL = 0; iKL < cKLs; ++iKL) 907 { 908 wHigh = max(wHigh, HIWORD(pLayouts[iKL].hKL)); 909 wLow = min(wLow, HIWORD(pLayouts[iKL].hKL)); 910 } 911 912 if (wHigh < 0xE0FF) 913 { 914 wNextID = wHigh + 1; 915 } 916 else if (wLow > 0xE001) 917 { 918 wNextID = wLow - 1; 919 } 920 else 921 { 922 for (wID = 0xE020; wID <= 0xE0FF; ++wID) 923 { 924 for (iKL = 0; iKL < cKLs; ++iKL) 925 { 926 if (LOWORD(pLayouts[iKL].hKL) == wLangID && 927 HIWORD(pLayouts[iKL].hKL) == wID) 928 { 929 break; 930 } 931 } 932 933 if (iKL >= cKLs) 934 break; 935 } 936 937 if (wID <= 0xE0FF) 938 wNextID = wID; 939 } 940 941 if (!wNextID) 942 return NULL; 943 944 return (HKL)(DWORD_PTR)MAKELONG(wLangID, wNextID); 945 } 946 947 // Win: GetImeLayout 948 UINT APIENTRY Imm32GetImeLayout(PREG_IME pLayouts, UINT cLayouts) 949 { 950 HKEY hkeyLayouts, hkeyIME; 951 WCHAR szImeFileName[80], szImeKey[20]; 952 UINT iKey, nCount; 953 DWORD cbData; 954 LONG lError; 955 ULONG Value; 956 HKL hKL; 957 958 /* Open the registry keyboard layouts */ 959 lError = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hkeyLayouts); 960 if (IS_ERROR_UNEXPECTEDLY(lError)) 961 return 0; 962 963 for (iKey = nCount = 0; ; ++iKey) 964 { 965 /* Get the key name */ 966 lError = RegEnumKeyW(hkeyLayouts, iKey, szImeKey, _countof(szImeKey)); 967 if (lError != ERROR_SUCCESS) 968 break; 969 970 if (szImeKey[0] != L'E' && szImeKey[0] != L'e') 971 continue; /* Not an IME layout */ 972 973 if (pLayouts == NULL) /* for counting only */ 974 { 975 ++nCount; 976 continue; 977 } 978 979 if (cLayouts <= nCount) 980 break; 981 982 lError = RegOpenKeyW(hkeyLayouts, szImeKey, &hkeyIME); /* Open the IME key */ 983 if (IS_ERROR_UNEXPECTEDLY(lError)) 984 continue; 985 986 /* Load the "Ime File" value */ 987 szImeFileName[0] = 0; 988 cbData = sizeof(szImeFileName); 989 RegQueryValueExW(hkeyIME, L"Ime File", NULL, NULL, (LPBYTE)szImeFileName, &cbData); 990 szImeFileName[_countof(szImeFileName) - 1] = UNICODE_NULL; /* Avoid buffer overrun */ 991 992 RegCloseKey(hkeyIME); 993 994 /* We don't allow the invalid "IME File" values for security reason */ 995 if (!szImeFileName[0] || wcscspn(szImeFileName, L":\\/") != wcslen(szImeFileName)) 996 { 997 WARN("\n"); 998 continue; 999 } 1000 1001 Imm32StrToUInt(szImeKey, &Value, 16); 1002 hKL = (HKL)(DWORD_PTR)Value; 1003 if (!IS_IME_HKL(hKL)) /* Not an IME */ 1004 { 1005 WARN("\n"); 1006 continue; 1007 } 1008 1009 /* Store the IME key and the IME filename */ 1010 pLayouts[nCount].hKL = hKL; 1011 StringCchCopyW(pLayouts[nCount].szImeKey, _countof(pLayouts[nCount].szImeKey), szImeKey); 1012 CharUpperW(szImeFileName); 1013 StringCchCopyW(pLayouts[nCount].szFileName, _countof(pLayouts[nCount].szFileName), 1014 szImeFileName); 1015 ++nCount; 1016 } 1017 1018 RegCloseKey(hkeyLayouts); 1019 return nCount; 1020 } 1021 1022 // Win: WriteImeLayout 1023 BOOL APIENTRY Imm32WriteImeLayout(HKL hKL, LPCWSTR pchFilePart, LPCWSTR pszLayoutText) 1024 { 1025 UINT iPreload; 1026 HKEY hkeyLayouts, hkeyIME, hkeyPreload; 1027 WCHAR szImeKey[20], szPreloadNumber[20], szPreloadKey[20]; 1028 DWORD cbData; 1029 LANGID LangID; 1030 LONG lError; 1031 LPCWSTR pszLayoutFile; 1032 1033 /* Open the registry keyboard layouts */ 1034 lError = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hkeyLayouts); 1035 if (IS_ERROR_UNEXPECTEDLY(lError)) 1036 return FALSE; 1037 1038 /* Get the IME key from hKL */ 1039 StringCchPrintf(szImeKey, _countof(szImeKey), L"%08X", (DWORD)(DWORD_PTR)hKL); 1040 1041 /* Create a registry IME key */ 1042 lError = RegCreateKeyW(hkeyLayouts, szImeKey, &hkeyIME); 1043 if (IS_ERROR_UNEXPECTEDLY(lError)) 1044 goto Failure; 1045 1046 /* Write "Ime File" */ 1047 cbData = (wcslen(pchFilePart) + 1) * sizeof(WCHAR); 1048 lError = RegSetValueExW(hkeyIME, L"Ime File", 0, REG_SZ, (LPBYTE)pchFilePart, cbData); 1049 if (IS_ERROR_UNEXPECTEDLY(lError)) 1050 goto Failure; 1051 1052 /* Write "Layout Text" */ 1053 cbData = (wcslen(pszLayoutText) + 1) * sizeof(WCHAR); 1054 lError = RegSetValueExW(hkeyIME, L"Layout Text", 0, REG_SZ, (LPBYTE)pszLayoutText, cbData); 1055 if (IS_ERROR_UNEXPECTEDLY(lError)) 1056 goto Failure; 1057 1058 /* Choose "Layout File" from hKL */ 1059 LangID = LOWORD(hKL); 1060 switch (LOBYTE(LangID)) 1061 { 1062 case LANG_JAPANESE: pszLayoutFile = L"kbdjpn.dll"; break; 1063 case LANG_KOREAN: pszLayoutFile = L"kbdkor.dll"; break; 1064 default: pszLayoutFile = L"kbdus.dll"; break; 1065 } 1066 1067 /* Write "Layout File" */ 1068 cbData = (wcslen(pszLayoutFile) + 1) * sizeof(WCHAR); 1069 lError = RegSetValueExW(hkeyIME, L"Layout File", 0, REG_SZ, (LPBYTE)pszLayoutFile, cbData); 1070 if (IS_ERROR_UNEXPECTEDLY(lError)) 1071 goto Failure; 1072 1073 RegCloseKey(hkeyIME); 1074 RegCloseKey(hkeyLayouts); 1075 1076 /* Create "Preload" key */ 1077 RegCreateKeyW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", &hkeyPreload); 1078 1079 #define MAX_PRELOAD 0x400 1080 for (iPreload = 1; iPreload < MAX_PRELOAD; ++iPreload) 1081 { 1082 Imm32UIntToStr(iPreload, 10, szPreloadNumber, _countof(szPreloadNumber)); 1083 1084 /* Load the key of the preload number */ 1085 cbData = sizeof(szPreloadKey); 1086 lError = RegQueryValueExW(hkeyPreload, szPreloadNumber, NULL, NULL, 1087 (LPBYTE)szPreloadKey, &cbData); 1088 szPreloadKey[_countof(szPreloadKey) - 1] = UNICODE_NULL; /* Avoid buffer overrun */ 1089 1090 if (lError != ERROR_SUCCESS || lstrcmpiW(szImeKey, szPreloadKey) == 0) 1091 break; /* Found an empty room or the same key */ 1092 } 1093 1094 if (iPreload >= MAX_PRELOAD) /* Not found */ 1095 { 1096 ERR("\n"); 1097 RegCloseKey(hkeyPreload); 1098 return FALSE; 1099 } 1100 #undef MAX_PRELOAD 1101 1102 /* Write the IME key to the preload number */ 1103 cbData = (wcslen(szImeKey) + 1) * sizeof(WCHAR); 1104 lError = RegSetValueExW(hkeyPreload, szPreloadNumber, 0, REG_SZ, (LPBYTE)szImeKey, cbData); 1105 RegCloseKey(hkeyPreload); 1106 return lError == ERROR_SUCCESS; 1107 1108 Failure: 1109 RegCloseKey(hkeyIME); 1110 RegDeleteKeyW(hkeyLayouts, szImeKey); 1111 RegCloseKey(hkeyLayouts); 1112 return FALSE; 1113 } 1114 1115 typedef INT (WINAPI *FN_LZOpenFileW)(LPWSTR, LPOFSTRUCT, WORD); 1116 typedef LONG (WINAPI *FN_LZCopy)(INT, INT); 1117 typedef VOID (WINAPI *FN_LZClose)(INT); 1118 1119 // Win: CopyImeFile 1120 BOOL APIENTRY Imm32CopyImeFile(LPWSTR pszOldFile, LPCWSTR pszNewFile) 1121 { 1122 BOOL ret = FALSE, bLoaded = FALSE; 1123 HMODULE hinstLZ32; 1124 WCHAR szLZ32Path[MAX_PATH]; 1125 CHAR szDestA[MAX_PATH]; 1126 OFSTRUCT OFStruct; 1127 FN_LZOpenFileW fnLZOpenFileW; 1128 FN_LZCopy fnLZCopy; 1129 FN_LZClose fnLZClose; 1130 HFILE hfDest, hfSrc; 1131 1132 /* Load LZ32.dll for copying/decompressing file */ 1133 Imm32GetSystemLibraryPath(szLZ32Path, _countof(szLZ32Path), L"LZ32"); 1134 hinstLZ32 = GetModuleHandleW(szLZ32Path); 1135 if (!hinstLZ32) 1136 { 1137 hinstLZ32 = LoadLibraryW(szLZ32Path); 1138 if (IS_NULL_UNEXPECTEDLY(hinstLZ32)) 1139 return FALSE; 1140 bLoaded = TRUE; 1141 } 1142 1143 #define GET_FN(name) do { \ 1144 fn##name = (FN_##name)GetProcAddress(hinstLZ32, #name); \ 1145 if (!fn##name) goto Quit; \ 1146 } while (0) 1147 GET_FN(LZOpenFileW); 1148 GET_FN(LZCopy); 1149 GET_FN(LZClose); 1150 #undef GET_FN 1151 1152 if (!WideCharToMultiByte(CP_ACP, 0, pszNewFile, -1, szDestA, _countof(szDestA), NULL, NULL)) 1153 goto Quit; 1154 szDestA[_countof(szDestA) - 1] = 0; 1155 1156 hfSrc = fnLZOpenFileW(pszOldFile, &OFStruct, OF_READ); 1157 if (hfSrc < 0) 1158 goto Quit; 1159 1160 hfDest = OpenFile(szDestA, &OFStruct, OF_CREATE); 1161 if (hfDest != HFILE_ERROR) 1162 { 1163 ret = (fnLZCopy(hfSrc, hfDest) >= 0); 1164 _lclose(hfDest); 1165 } 1166 1167 fnLZClose(hfSrc); 1168 1169 Quit: 1170 if (bLoaded) 1171 FreeLibrary(hinstLZ32); 1172 return ret; 1173 } 1174 1175 /*********************************************************************** 1176 * ImmCreateIMCC(IMM32.@) 1177 */ 1178 HIMCC WINAPI ImmCreateIMCC(DWORD size) 1179 { 1180 if (size < sizeof(DWORD)) 1181 size = sizeof(DWORD); 1182 return LocalAlloc(LHND, size); 1183 } 1184 1185 /*********************************************************************** 1186 * ImmDestroyIMCC(IMM32.@) 1187 */ 1188 HIMCC WINAPI ImmDestroyIMCC(HIMCC block) 1189 { 1190 if (block) 1191 return LocalFree(block); 1192 return NULL; 1193 } 1194 1195 /*********************************************************************** 1196 * ImmLockIMCC(IMM32.@) 1197 */ 1198 LPVOID WINAPI ImmLockIMCC(HIMCC imcc) 1199 { 1200 if (imcc) 1201 return LocalLock(imcc); 1202 return NULL; 1203 } 1204 1205 /*********************************************************************** 1206 * ImmUnlockIMCC(IMM32.@) 1207 */ 1208 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc) 1209 { 1210 if (imcc) 1211 return LocalUnlock(imcc); 1212 return FALSE; 1213 } 1214 1215 /*********************************************************************** 1216 * ImmGetIMCCLockCount(IMM32.@) 1217 */ 1218 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc) 1219 { 1220 return LocalFlags(imcc) & LMEM_LOCKCOUNT; 1221 } 1222 1223 /*********************************************************************** 1224 * ImmReSizeIMCC(IMM32.@) 1225 */ 1226 HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size) 1227 { 1228 if (!imcc) 1229 return NULL; 1230 return LocalReAlloc(imcc, size, LHND); 1231 } 1232 1233 /*********************************************************************** 1234 * ImmGetIMCCSize(IMM32.@) 1235 */ 1236 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc) 1237 { 1238 if (imcc) 1239 return LocalSize(imcc); 1240 return 0; 1241 } 1242 1243 /*********************************************************************** 1244 * ImmGetIMCLockCount(IMM32.@) 1245 */ 1246 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC) 1247 { 1248 DWORD ret; 1249 HANDLE hInputContext; 1250 PCLIENTIMC pClientImc; 1251 1252 pClientImc = ImmLockClientImc(hIMC); 1253 if (IS_NULL_UNEXPECTEDLY(pClientImc)) 1254 return 0; 1255 1256 ret = 0; 1257 hInputContext = pClientImc->hInputContext; 1258 if (hInputContext) 1259 ret = (LocalFlags(hInputContext) & LMEM_LOCKCOUNT); 1260 1261 ImmUnlockClientImc(pClientImc); 1262 return ret; 1263 } 1264 1265 /*********************************************************************** 1266 * ImmIMPGetIMEA(IMM32.@) 1267 */ 1268 BOOL WINAPI ImmIMPGetIMEA(HWND hWnd, LPIMEPROA pImePro) 1269 { 1270 FIXME("(%p, %p)\n", hWnd, pImePro); 1271 return FALSE; 1272 } 1273 1274 /*********************************************************************** 1275 * ImmIMPGetIMEW(IMM32.@) 1276 */ 1277 BOOL WINAPI ImmIMPGetIMEW(HWND hWnd, LPIMEPROW pImePro) 1278 { 1279 FIXME("(%p, %p)\n", hWnd, pImePro); 1280 return FALSE; 1281 } 1282 1283 /*********************************************************************** 1284 * ImmIMPQueryIMEA(IMM32.@) 1285 */ 1286 BOOL WINAPI ImmIMPQueryIMEA(LPIMEPROA pImePro) 1287 { 1288 FIXME("(%p)\n", pImePro); 1289 return FALSE; 1290 } 1291 1292 /*********************************************************************** 1293 * ImmIMPQueryIMEW(IMM32.@) 1294 */ 1295 BOOL WINAPI ImmIMPQueryIMEW(LPIMEPROW pImePro) 1296 { 1297 FIXME("(%p)\n", pImePro); 1298 return FALSE; 1299 } 1300 1301 /*********************************************************************** 1302 * ImmIMPSetIMEA(IMM32.@) 1303 */ 1304 BOOL WINAPI ImmIMPSetIMEA(HWND hWnd, LPIMEPROA pImePro) 1305 { 1306 FIXME("(%p, %p)\n", hWnd, pImePro); 1307 return FALSE; 1308 } 1309 1310 /*********************************************************************** 1311 * ImmIMPSetIMEW(IMM32.@) 1312 */ 1313 BOOL WINAPI ImmIMPSetIMEW(HWND hWnd, LPIMEPROW pImePro) 1314 { 1315 FIXME("(%p, %p)\n", hWnd, pImePro); 1316 return FALSE; 1317 } 1318