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