1 /* 2 * PROJECT: ReactOS IMM32 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Implementing Far-Eastern languages input 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 HMODULE g_hImm32Inst = NULL; 18 PSERVERINFO g_psi = NULL; 19 SHAREDINFO g_SharedInfo = { NULL }; 20 BYTE g_bClientRegd = FALSE; 21 22 static BOOL APIENTRY Imm32InitInstance(HMODULE hMod) 23 { 24 NTSTATUS status; 25 26 if (hMod) 27 g_hImm32Inst = hMod; 28 29 if (g_bClientRegd) 30 return TRUE; 31 32 status = RtlInitializeCriticalSection(&g_csImeDpi); 33 if (NT_ERROR(status)) 34 return FALSE; 35 36 g_bClientRegd = TRUE; 37 return TRUE; 38 } 39 40 /*********************************************************************** 41 * ImmRegisterClient(IMM32.@) 42 * ( Undocumented, called from user32.dll ) 43 */ 44 BOOL WINAPI ImmRegisterClient(PSHAREDINFO ptr, HINSTANCE hMod) 45 { 46 g_SharedInfo = *ptr; 47 g_psi = g_SharedInfo.psi; 48 return Imm32InitInstance(hMod); 49 } 50 51 /*********************************************************************** 52 * ImmLoadLayout (IMM32.@) 53 */ 54 HKL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx) 55 { 56 DWORD cbData; 57 UNICODE_STRING UnicodeString; 58 HKEY hLayoutKey = NULL, hLayoutsKey = NULL; 59 LONG error; 60 NTSTATUS Status; 61 WCHAR szLayout[MAX_PATH]; 62 63 TRACE("(%p, %p)\n", hKL, pImeInfoEx); 64 65 if (IS_IME_HKL(hKL) || 66 !g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED) || 67 ((PW32CLIENTINFO)NtCurrentTeb()->Win32ClientInfo)->W32ClientInfo[0] & 2) 68 { 69 UnicodeString.Buffer = szLayout; 70 UnicodeString.MaximumLength = sizeof(szLayout); 71 Status = RtlIntegerToUnicodeString((DWORD_PTR)hKL, 16, &UnicodeString); 72 if (!NT_SUCCESS(Status)) 73 return NULL; 74 75 error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hLayoutsKey); 76 if (error) 77 return NULL; 78 79 error = RegOpenKeyW(hLayoutsKey, szLayout, &hLayoutKey); 80 } 81 else 82 { 83 error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_IMM, &hLayoutKey); 84 } 85 86 if (error) 87 { 88 ERR("RegOpenKeyW error: 0x%08lX\n", error); 89 hKL = NULL; 90 } 91 else 92 { 93 cbData = sizeof(pImeInfoEx->wszImeFile); 94 error = RegQueryValueExW(hLayoutKey, L"Ime File", 0, 0, 95 (LPBYTE)pImeInfoEx->wszImeFile, &cbData); 96 if (error) 97 hKL = NULL; 98 } 99 100 RegCloseKey(hLayoutKey); 101 if (hLayoutsKey) 102 RegCloseKey(hLayoutsKey); 103 return hKL; 104 } 105 106 typedef struct _tagImmHkl 107 { 108 struct list entry; 109 HKL hkl; 110 HMODULE hIME; 111 IMEINFO imeInfo; 112 WCHAR imeClassName[17]; /* 16 character max */ 113 ULONG uSelected; 114 HWND UIWnd; 115 116 /* Function Pointers */ 117 BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, const WCHAR *); 118 BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *); 119 BOOL (WINAPI *pImeDestroy)(UINT); 120 LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *); 121 BOOL (WINAPI *pImeSelect)(HIMC, BOOL); 122 BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL); 123 UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, DWORD *, UINT, HIMC); 124 BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD); 125 BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *); 126 BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *); 127 UINT (WINAPI *pImeEnumRegisterWord)(REGISTERWORDENUMPROCW, const WCHAR *, DWORD, const WCHAR *, void *); 128 BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void *, DWORD, const void *, DWORD); 129 DWORD (WINAPI *pImeConversionList)(HIMC, const WCHAR *, CANDIDATELIST *, DWORD, UINT); 130 BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *); 131 UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *); 132 DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD); 133 } ImmHkl; 134 135 typedef struct tagInputContextData 136 { 137 DWORD dwLock; 138 INPUTCONTEXT IMC; 139 DWORD threadID; 140 141 ImmHkl *immKbd; 142 UINT lastVK; 143 BOOL threadDefault; 144 DWORD magic; 145 } InputContextData; 146 147 #define WINE_IMC_VALID_MAGIC 0x56434D49 148 149 typedef struct _tagIMMThreadData 150 { 151 struct list entry; 152 DWORD threadID; 153 HIMC defaultContext; 154 HWND hwndDefault; 155 BOOL disableIME; 156 DWORD windowRefs; 157 } IMMThreadData; 158 159 static struct list ImmHklList = LIST_INIT(ImmHklList); 160 static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList); 161 162 static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0}; 163 164 static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0}; 165 static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0}; 166 static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0}; 167 168 static inline BOOL is_himc_ime_unicode(const InputContextData *data) 169 { 170 return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE); 171 } 172 173 static inline BOOL is_kbd_ime_unicode(const ImmHkl *hkl) 174 { 175 return !!(hkl->imeInfo.fdwProperty & IME_PROP_UNICODE); 176 } 177 178 static InputContextData* get_imc_data(HIMC hIMC); 179 180 static inline WCHAR *strdupAtoW( const char *str ) 181 { 182 WCHAR *ret = NULL; 183 if (str) 184 { 185 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); 186 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 187 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); 188 } 189 return ret; 190 } 191 192 static inline CHAR *strdupWtoA( const WCHAR *str ) 193 { 194 CHAR *ret = NULL; 195 if (str) 196 { 197 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); 198 if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) 199 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); 200 } 201 return ret; 202 } 203 204 static HMODULE load_graphics_driver(void) 205 { 206 static const WCHAR display_device_guid_propW[] = { 207 '_','_','w','i','n','e','_','d','i','s','p','l','a','y','_', 208 'd','e','v','i','c','e','_','g','u','i','d',0 }; 209 static const WCHAR key_pathW[] = { 210 'S','y','s','t','e','m','\\', 211 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 212 'C','o','n','t','r','o','l','\\', 213 'V','i','d','e','o','\\','{',0}; 214 static const WCHAR displayW[] = {'}','\\','0','0','0','0',0}; 215 static const WCHAR driverW[] = {'G','r','a','p','h','i','c','s','D','r','i','v','e','r',0}; 216 217 HMODULE ret = 0; 218 HKEY hkey; 219 DWORD size; 220 WCHAR path[MAX_PATH]; 221 WCHAR key[ARRAY_SIZE( key_pathW ) + ARRAY_SIZE( displayW ) + 40]; 222 UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), display_device_guid_propW )); 223 224 if (!guid_atom) return 0; 225 memcpy( key, key_pathW, sizeof(key_pathW) ); 226 if (!GlobalGetAtomNameW( guid_atom, key + lstrlenW(key), 40 )) return 0; 227 lstrcatW( key, displayW ); 228 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0; 229 size = sizeof(path); 230 if (!RegQueryValueExW( hkey, driverW, NULL, NULL, (BYTE *)path, &size )) ret = LoadLibraryW( path ); 231 RegCloseKey( hkey ); 232 TRACE( "%s %p\n", debugstr_w(path), ret ); 233 return ret; 234 } 235 236 /* ImmHkl loading and freeing */ 237 #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);} 238 static ImmHkl *IMM_GetImmHkl(HKL hkl) 239 { 240 ImmHkl *ptr; 241 WCHAR filename[MAX_PATH]; 242 243 TRACE("Seeking ime for keyboard %p\n",hkl); 244 245 LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry) 246 { 247 if (ptr->hkl == hkl) 248 return ptr; 249 } 250 /* not found... create it */ 251 252 ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl)); 253 254 ptr->hkl = hkl; 255 if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename); 256 if (!ptr->hIME) ptr->hIME = load_graphics_driver(); 257 if (ptr->hIME) 258 { 259 LOAD_FUNCPTR(ImeInquire); 260 if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL)) 261 { 262 FreeLibrary(ptr->hIME); 263 ptr->hIME = NULL; 264 } 265 else 266 { 267 LOAD_FUNCPTR(ImeDestroy); 268 LOAD_FUNCPTR(ImeSelect); 269 if (!ptr->pImeSelect || !ptr->pImeDestroy) 270 { 271 FreeLibrary(ptr->hIME); 272 ptr->hIME = NULL; 273 } 274 else 275 { 276 LOAD_FUNCPTR(ImeConfigure); 277 LOAD_FUNCPTR(ImeEscape); 278 LOAD_FUNCPTR(ImeSetActiveContext); 279 LOAD_FUNCPTR(ImeToAsciiEx); 280 LOAD_FUNCPTR(NotifyIME); 281 LOAD_FUNCPTR(ImeRegisterWord); 282 LOAD_FUNCPTR(ImeUnregisterWord); 283 LOAD_FUNCPTR(ImeEnumRegisterWord); 284 LOAD_FUNCPTR(ImeSetCompositionString); 285 LOAD_FUNCPTR(ImeConversionList); 286 LOAD_FUNCPTR(ImeProcessKey); 287 LOAD_FUNCPTR(ImeGetRegisterWordStyle); 288 LOAD_FUNCPTR(ImeGetImeMenuItems); 289 /* make sure our classname is WCHAR */ 290 if (!is_kbd_ime_unicode(ptr)) 291 { 292 WCHAR bufW[17]; 293 MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName, 294 -1, bufW, 17); 295 lstrcpyW(ptr->imeClassName, bufW); 296 } 297 } 298 } 299 } 300 list_add_head(&ImmHklList,&ptr->entry); 301 302 return ptr; 303 } 304 #undef LOAD_FUNCPTR 305 306 static InputContextData* get_imc_data(HIMC hIMC) 307 { 308 InputContextData *data = (InputContextData *)hIMC; 309 310 if (hIMC == NULL) 311 return NULL; 312 313 if(IsBadReadPtr(data, sizeof(InputContextData)) || data->magic != WINE_IMC_VALID_MAGIC) 314 { 315 SetLastError(ERROR_INVALID_HANDLE); 316 return NULL; 317 } 318 return data; 319 } 320 321 static HIMC get_default_context( HWND hwnd ) 322 { 323 FIXME("Don't use this function\n"); 324 return FALSE; 325 } 326 327 static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC) 328 { 329 InputContextData *data; 330 331 if (hWnd) 332 { 333 DWORD thread = GetWindowThreadProcessId(hWnd, NULL); 334 if (thread != GetCurrentThreadId()) return TRUE; 335 } 336 data = get_imc_data(hIMC); 337 if (data && data->threadID != GetCurrentThreadId()) 338 return TRUE; 339 340 return FALSE; 341 } 342 343 /*********************************************************************** 344 * ImmAssociateContext (IMM32.@) 345 */ 346 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC) 347 { 348 HIMC old = NULL; 349 InputContextData *data = get_imc_data(hIMC); 350 351 TRACE("(%p, %p):\n", hWnd, hIMC); 352 353 if(hIMC && !data) 354 return NULL; 355 356 /* 357 * If already associated just return 358 */ 359 if (hIMC && data->IMC.hWnd == hWnd) 360 return hIMC; 361 362 if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC)) 363 return NULL; 364 365 if (hWnd) 366 { 367 HIMC defaultContext = get_default_context( hWnd ); 368 old = RemovePropW(hWnd,szwWineIMCProperty); 369 370 if (old == NULL) 371 old = defaultContext; 372 else if (old == (HIMC)-1) 373 old = NULL; 374 375 if (hIMC != defaultContext) 376 { 377 if (hIMC == NULL) /* Meaning disable imm for that window*/ 378 SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1); 379 else 380 SetPropW(hWnd,szwWineIMCProperty,hIMC); 381 } 382 383 if (old) 384 { 385 InputContextData *old_data = (InputContextData *)old; 386 if (old_data->IMC.hWnd == hWnd) 387 old_data->IMC.hWnd = NULL; 388 } 389 } 390 391 if (!hIMC) 392 return old; 393 394 if(GetActiveWindow() == data->IMC.hWnd) 395 { 396 SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL); 397 data->IMC.hWnd = hWnd; 398 SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL); 399 } 400 401 return old; 402 } 403 404 /* 405 * Helper function for ImmAssociateContextEx 406 */ 407 static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam) 408 { 409 HIMC hImc = (HIMC)lParam; 410 ImmAssociateContext(hwnd,hImc); 411 return TRUE; 412 } 413 414 /*********************************************************************** 415 * ImmAssociateContextEx (IMM32.@) 416 */ 417 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags) 418 { 419 TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags); 420 421 if (!hWnd) 422 return FALSE; 423 424 switch (dwFlags) 425 { 426 case 0: 427 ImmAssociateContext(hWnd,hIMC); 428 return TRUE; 429 case IACE_DEFAULT: 430 { 431 HIMC defaultContext = get_default_context( hWnd ); 432 if (!defaultContext) return FALSE; 433 ImmAssociateContext(hWnd,defaultContext); 434 return TRUE; 435 } 436 case IACE_IGNORENOCONTEXT: 437 if (GetPropW(hWnd,szwWineIMCProperty)) 438 ImmAssociateContext(hWnd,hIMC); 439 return TRUE; 440 case IACE_CHILDREN: 441 EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC); 442 return TRUE; 443 default: 444 FIXME("Unknown dwFlags 0x%x\n",dwFlags); 445 return FALSE; 446 } 447 } 448 449 /*********************************************************************** 450 * ImmConfigureIMEA (IMM32.@) 451 */ 452 BOOL WINAPI ImmConfigureIMEA(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) 453 { 454 ImmHkl *immHkl = IMM_GetImmHkl(hKL); 455 456 TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData); 457 458 if (dwMode == IME_CONFIG_REGISTERWORD && !lpData) 459 return FALSE; 460 461 if (immHkl->hIME && immHkl->pImeConfigure) 462 { 463 if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl)) 464 return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData); 465 else 466 { 467 REGISTERWORDW rww; 468 REGISTERWORDA *rwa = lpData; 469 BOOL rc; 470 471 rww.lpReading = strdupAtoW(rwa->lpReading); 472 rww.lpWord = strdupAtoW(rwa->lpWord); 473 rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww); 474 HeapFree(GetProcessHeap(),0,rww.lpReading); 475 HeapFree(GetProcessHeap(),0,rww.lpWord); 476 return rc; 477 } 478 } 479 else 480 return FALSE; 481 } 482 483 /*********************************************************************** 484 * ImmConfigureIMEW (IMM32.@) 485 */ 486 BOOL WINAPI ImmConfigureIMEW(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) 487 { 488 ImmHkl *immHkl = IMM_GetImmHkl(hKL); 489 490 TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData); 491 492 if (dwMode == IME_CONFIG_REGISTERWORD && !lpData) 493 return FALSE; 494 495 if (immHkl->hIME && immHkl->pImeConfigure) 496 { 497 if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl)) 498 return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData); 499 else 500 { 501 REGISTERWORDW *rww = lpData; 502 REGISTERWORDA rwa; 503 BOOL rc; 504 505 rwa.lpReading = strdupWtoA(rww->lpReading); 506 rwa.lpWord = strdupWtoA(rww->lpWord); 507 rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa); 508 HeapFree(GetProcessHeap(),0,rwa.lpReading); 509 HeapFree(GetProcessHeap(),0,rwa.lpWord); 510 return rc; 511 } 512 } 513 else 514 return FALSE; 515 } 516 517 /*********************************************************************** 518 * ImmCreateContext (IMM32.@) 519 */ 520 HIMC WINAPI ImmCreateContext(void) 521 { 522 PCLIENTIMC pClientImc; 523 HIMC hIMC; 524 525 TRACE("()\n"); 526 527 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32)) 528 return NULL; 529 530 pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC)); 531 if (pClientImc == NULL) 532 return NULL; 533 534 hIMC = NtUserCreateInputContext(pClientImc); 535 if (hIMC == NULL) 536 { 537 HeapFree(g_hImm32Heap, 0, pClientImc); 538 return NULL; 539 } 540 541 RtlInitializeCriticalSection(&pClientImc->cs); 542 543 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken. 544 pClientImc->unknown = NtUserGetThreadState(13); 545 546 return hIMC; 547 } 548 549 static VOID APIENTRY Imm32CleanupContextExtra(LPINPUTCONTEXT pIC) 550 { 551 FIXME("We have to do something do here"); 552 } 553 554 static PCLIENTIMC APIENTRY Imm32FindClientImc(HIMC hIMC) 555 { 556 // FIXME 557 return NULL; 558 } 559 560 BOOL APIENTRY Imm32CleanupContext(HIMC hIMC, HKL hKL, BOOL bKeep) 561 { 562 PIMEDPI pImeDpi; 563 LPINPUTCONTEXT pIC; 564 PCLIENTIMC pClientImc; 565 566 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32) || hIMC == NULL) 567 return FALSE; 568 569 FIXME("We have do something to do here\n"); 570 pClientImc = Imm32FindClientImc(hIMC); 571 if (!pClientImc) 572 return FALSE; 573 574 if (pClientImc->hImc == NULL) 575 { 576 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1; 577 ImmUnlockClientImc(pClientImc); 578 if (!bKeep) 579 return NtUserDestroyInputContext(hIMC); 580 return TRUE; 581 } 582 583 pIC = ImmLockIMC(hIMC); 584 if (pIC == NULL) 585 { 586 ImmUnlockClientImc(pClientImc); 587 return FALSE; 588 } 589 590 FIXME("We have do something to do here\n"); 591 592 if (pClientImc->hKL == hKL) 593 { 594 pImeDpi = ImmLockImeDpi(hKL); 595 if (pImeDpi != NULL) 596 { 597 if (IS_IME_HKL(hKL)) 598 { 599 pImeDpi->ImeSelect(hIMC, FALSE); 600 } 601 else if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)) 602 { 603 FIXME("We have do something to do here\n"); 604 } 605 ImmUnlockImeDpi(pImeDpi); 606 } 607 pClientImc->hKL = NULL; 608 } 609 610 ImmDestroyIMCC(pIC->hPrivate); 611 ImmDestroyIMCC(pIC->hMsgBuf); 612 ImmDestroyIMCC(pIC->hGuideLine); 613 ImmDestroyIMCC(pIC->hCandInfo); 614 ImmDestroyIMCC(pIC->hCompStr); 615 616 Imm32CleanupContextExtra(pIC); 617 618 ImmUnlockIMC(hIMC); 619 620 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1; 621 ImmUnlockClientImc(pClientImc); 622 623 if (!bKeep) 624 return NtUserDestroyInputContext(hIMC); 625 626 return TRUE; 627 } 628 629 /*********************************************************************** 630 * ImmDestroyContext (IMM32.@) 631 */ 632 BOOL WINAPI ImmDestroyContext(HIMC hIMC) 633 { 634 HKL hKL; 635 636 TRACE("(%p)\n", hIMC); 637 638 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32)) 639 return FALSE; 640 641 if (Imm32IsCrossThreadAccess(hIMC)) 642 return FALSE; 643 644 hKL = GetKeyboardLayout(0); 645 return Imm32CleanupContext(hIMC, hKL, FALSE); 646 } 647 648 static inline BOOL EscapeRequiresWA(UINT uEscape) 649 { 650 if (uEscape == IME_ESC_GET_EUDC_DICTIONARY || 651 uEscape == IME_ESC_SET_EUDC_DICTIONARY || 652 uEscape == IME_ESC_IME_NAME || 653 uEscape == IME_ESC_GETHELPFILENAME) 654 return TRUE; 655 return FALSE; 656 } 657 658 /*********************************************************************** 659 * ImmEscapeA (IMM32.@) 660 */ 661 LRESULT WINAPI ImmEscapeA(HKL hKL, HIMC hIMC, UINT uEscape, LPVOID lpData) 662 { 663 ImmHkl *immHkl = IMM_GetImmHkl(hKL); 664 TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData); 665 666 if (immHkl->hIME && immHkl->pImeEscape) 667 { 668 if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl)) 669 return immHkl->pImeEscape(hIMC,uEscape,lpData); 670 else 671 { 672 WCHAR buffer[81]; /* largest required buffer should be 80 */ 673 LRESULT rc; 674 if (uEscape == IME_ESC_SET_EUDC_DICTIONARY) 675 { 676 MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81); 677 rc = immHkl->pImeEscape(hIMC,uEscape,buffer); 678 } 679 else 680 { 681 rc = immHkl->pImeEscape(hIMC,uEscape,buffer); 682 WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL); 683 } 684 return rc; 685 } 686 } 687 else 688 return 0; 689 } 690 691 /*********************************************************************** 692 * ImmEscapeW (IMM32.@) 693 */ 694 LRESULT WINAPI ImmEscapeW(HKL hKL, HIMC hIMC, UINT uEscape, LPVOID lpData) 695 { 696 ImmHkl *immHkl = IMM_GetImmHkl(hKL); 697 TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData); 698 699 if (immHkl->hIME && immHkl->pImeEscape) 700 { 701 if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl)) 702 return immHkl->pImeEscape(hIMC,uEscape,lpData); 703 else 704 { 705 CHAR buffer[81]; /* largest required buffer should be 80 */ 706 LRESULT rc; 707 if (uEscape == IME_ESC_SET_EUDC_DICTIONARY) 708 { 709 WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL); 710 rc = immHkl->pImeEscape(hIMC,uEscape,buffer); 711 } 712 else 713 { 714 rc = immHkl->pImeEscape(hIMC,uEscape,buffer); 715 MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80); 716 } 717 return rc; 718 } 719 } 720 else 721 return 0; 722 } 723 724 static PCLIENTIMC APIENTRY Imm32GetClientImcCache(void) 725 { 726 // FIXME: Do something properly here 727 return NULL; 728 } 729 730 /*********************************************************************** 731 * ImmLockClientImc (IMM32.@) 732 */ 733 PCLIENTIMC WINAPI ImmLockClientImc(HIMC hImc) 734 { 735 PCLIENTIMC pClientImc; 736 737 TRACE("(%p)\n", hImc); 738 739 if (hImc == NULL) 740 return NULL; 741 742 pClientImc = Imm32GetClientImcCache(); 743 if (!pClientImc) 744 { 745 pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC)); 746 if (!pClientImc) 747 return NULL; 748 749 RtlInitializeCriticalSection(&pClientImc->cs); 750 751 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken. 752 pClientImc->unknown = NtUserGetThreadState(13); 753 754 if (!NtUserUpdateInputContext(hImc, 0, pClientImc)) 755 { 756 HeapFree(g_hImm32Heap, 0, pClientImc); 757 return NULL; 758 } 759 760 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN2; 761 } 762 else 763 { 764 if (pClientImc->dwFlags & CLIENTIMC_UNKNOWN1) 765 return NULL; 766 } 767 768 InterlockedIncrement(&pClientImc->cLockObj); 769 return pClientImc; 770 } 771 772 /*********************************************************************** 773 * ImmUnlockClientImc (IMM32.@) 774 */ 775 VOID WINAPI ImmUnlockClientImc(PCLIENTIMC pClientImc) 776 { 777 LONG cLocks; 778 HIMC hImc; 779 780 TRACE("(%p)\n", pClientImc); 781 782 cLocks = InterlockedDecrement(&pClientImc->cLockObj); 783 if (cLocks != 0 || !(pClientImc->dwFlags & CLIENTIMC_UNKNOWN1)) 784 return; 785 786 hImc = pClientImc->hImc; 787 if (hImc) 788 LocalFree(hImc); 789 790 RtlDeleteCriticalSection(&pClientImc->cs); 791 HeapFree(g_hImm32Heap, 0, pClientImc); 792 } 793 794 static HIMC APIENTRY Imm32GetContextEx(HWND hWnd, DWORD dwContextFlags) 795 { 796 HIMC hIMC; 797 PCLIENTIMC pClientImc; 798 PWND pWnd; 799 800 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_IMM32)) 801 return NULL; 802 803 if (!hWnd) 804 { 805 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken. 806 hIMC = (HIMC)NtUserGetThreadState(4); 807 goto Quit; 808 } 809 810 pWnd = ValidateHwndNoErr(hWnd); 811 if (!pWnd || Imm32IsCrossProcessAccess(hWnd)) 812 return NULL; 813 814 hIMC = pWnd->hImc; 815 if (!hIMC && (dwContextFlags & 1)) 816 hIMC = (HIMC)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_ICONTEXT); 817 818 Quit: 819 pClientImc = ImmLockClientImc(hIMC); 820 if (pClientImc == NULL) 821 return NULL; 822 if ((dwContextFlags & 2) && (pClientImc->dwFlags & CLIENTIMC_UNKNOWN3)) 823 hIMC = NULL; 824 ImmUnlockClientImc(pClientImc); 825 return hIMC; 826 } 827 828 829 /* Helpers for the GetCompositionString functions */ 830 831 /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer 832 length is always in bytes. */ 833 static INT 834 CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst, 835 INT dst_len, BOOL unicode) 836 { 837 int char_size = unicode ? sizeof(WCHAR) : sizeof(char); 838 INT ret; 839 840 if (is_himc_ime_unicode(data) ^ unicode) 841 { 842 if (unicode) 843 ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR)); 844 else 845 ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL); 846 ret *= char_size; 847 } 848 else 849 { 850 if (dst_len) 851 { 852 ret = min(src_len * char_size, dst_len); 853 memcpy(dst, src, ret); 854 } 855 else 856 ret = src_len * char_size; 857 } 858 859 return ret; 860 } 861 862 /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to 863 passed mode. String length is in characters, attributes are in byte arrays. */ 864 static INT 865 CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string, 866 INT str_len, BYTE *dst, INT dst_len, BOOL unicode) 867 { 868 union 869 { 870 const void *str; 871 const WCHAR *strW; 872 const char *strA; 873 } string; 874 INT rc; 875 876 string.str = comp_string; 877 878 if (is_himc_ime_unicode(data) && !unicode) 879 { 880 rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL); 881 if (dst_len) 882 { 883 int i, j = 0, k = 0; 884 885 if (rc < dst_len) 886 dst_len = rc; 887 for (i = 0; i < str_len; ++i) 888 { 889 int len; 890 891 len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL); 892 for (; len > 0; --len) 893 { 894 dst[j++] = src[k]; 895 896 if (j >= dst_len) 897 goto end; 898 } 899 ++k; 900 } 901 end: 902 rc = j; 903 } 904 } 905 else if (!is_himc_ime_unicode(data) && unicode) 906 { 907 rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0); 908 if (dst_len) 909 { 910 int i, j = 0; 911 912 if (rc < dst_len) 913 dst_len = rc; 914 for (i = 0; i < str_len; ++i) 915 { 916 if (IsDBCSLeadByte(string.strA[i])) 917 continue; 918 919 dst[j++] = src[i]; 920 921 if (j >= dst_len) 922 break; 923 } 924 rc = j; 925 } 926 } 927 else 928 { 929 memcpy(dst, src, min(src_len, dst_len)); 930 rc = src_len; 931 } 932 933 return rc; 934 } 935 936 static INT 937 CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource, 938 LPBYTE target, INT tlen, BOOL unicode ) 939 { 940 INT rc; 941 942 if (is_himc_ime_unicode(data) && !unicode) 943 { 944 if (tlen) 945 { 946 int i; 947 948 if (slen < tlen) 949 tlen = slen; 950 tlen /= sizeof (DWORD); 951 for (i = 0; i < tlen; ++i) 952 { 953 ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, 954 ((DWORD *)source)[i], 955 NULL, 0, 956 NULL, NULL); 957 } 958 rc = sizeof (DWORD) * i; 959 } 960 else 961 rc = slen; 962 } 963 else if (!is_himc_ime_unicode(data) && unicode) 964 { 965 if (tlen) 966 { 967 int i; 968 969 if (slen < tlen) 970 tlen = slen; 971 tlen /= sizeof (DWORD); 972 for (i = 0; i < tlen; ++i) 973 { 974 ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, 975 ((DWORD *)source)[i], 976 NULL, 0); 977 } 978 rc = sizeof (DWORD) * i; 979 } 980 else 981 rc = slen; 982 } 983 else 984 { 985 memcpy( target, source, min(slen,tlen)); 986 rc = slen; 987 } 988 989 return rc; 990 } 991 992 static INT 993 CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode) 994 { 995 int rc; 996 997 if (is_himc_ime_unicode(data) && !unicode) 998 { 999 rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL); 1000 } 1001 else if (!is_himc_ime_unicode(data) && unicode) 1002 { 1003 rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0); 1004 } 1005 else 1006 rc = offset; 1007 1008 return rc; 1009 } 1010 1011 static LONG 1012 ImmGetCompositionStringT(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, 1013 DWORD dwBufLen, BOOL unicode) 1014 { 1015 LONG rc = 0; 1016 InputContextData *data = get_imc_data(hIMC); 1017 LPCOMPOSITIONSTRING compstr; 1018 LPBYTE compdata; 1019 1020 TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen); 1021 1022 if (!data) 1023 return FALSE; 1024 1025 if (!data->IMC.hCompStr) 1026 return FALSE; 1027 1028 compdata = ImmLockIMCC(data->IMC.hCompStr); 1029 compstr = (LPCOMPOSITIONSTRING)compdata; 1030 1031 switch (dwIndex) 1032 { 1033 case GCS_RESULTSTR: 1034 TRACE("GCS_RESULTSTR\n"); 1035 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode); 1036 break; 1037 case GCS_COMPSTR: 1038 TRACE("GCS_COMPSTR\n"); 1039 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode); 1040 break; 1041 case GCS_COMPATTR: 1042 TRACE("GCS_COMPATTR\n"); 1043 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen, 1044 compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, 1045 lpBuf, dwBufLen, unicode); 1046 break; 1047 case GCS_COMPCLAUSE: 1048 TRACE("GCS_COMPCLAUSE\n"); 1049 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen, 1050 compdata + compstr->dwCompStrOffset, 1051 lpBuf, dwBufLen, unicode); 1052 break; 1053 case GCS_RESULTCLAUSE: 1054 TRACE("GCS_RESULTCLAUSE\n"); 1055 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen, 1056 compdata + compstr->dwResultStrOffset, 1057 lpBuf, dwBufLen, unicode); 1058 break; 1059 case GCS_RESULTREADSTR: 1060 TRACE("GCS_RESULTREADSTR\n"); 1061 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode); 1062 break; 1063 case GCS_RESULTREADCLAUSE: 1064 TRACE("GCS_RESULTREADCLAUSE\n"); 1065 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen, 1066 compdata + compstr->dwResultStrOffset, 1067 lpBuf, dwBufLen, unicode); 1068 break; 1069 case GCS_COMPREADSTR: 1070 TRACE("GCS_COMPREADSTR\n"); 1071 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode); 1072 break; 1073 case GCS_COMPREADATTR: 1074 TRACE("GCS_COMPREADATTR\n"); 1075 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen, 1076 compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, 1077 lpBuf, dwBufLen, unicode); 1078 break; 1079 case GCS_COMPREADCLAUSE: 1080 TRACE("GCS_COMPREADCLAUSE\n"); 1081 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen, 1082 compdata + compstr->dwCompStrOffset, 1083 lpBuf, dwBufLen, unicode); 1084 break; 1085 case GCS_CURSORPOS: 1086 TRACE("GCS_CURSORPOS\n"); 1087 rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode); 1088 break; 1089 case GCS_DELTASTART: 1090 TRACE("GCS_DELTASTART\n"); 1091 rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode); 1092 break; 1093 default: 1094 FIXME("Unhandled index 0x%x\n",dwIndex); 1095 break; 1096 } 1097 1098 ImmUnlockIMCC(data->IMC.hCompStr); 1099 1100 return rc; 1101 } 1102 1103 /*********************************************************************** 1104 * ImmGetCompositionStringA (IMM32.@) 1105 */ 1106 LONG WINAPI ImmGetCompositionStringA(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen) 1107 { 1108 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE); 1109 } 1110 1111 /*********************************************************************** 1112 * ImmGetCompositionStringW (IMM32.@) 1113 */ 1114 LONG WINAPI ImmGetCompositionStringW(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen) 1115 { 1116 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE); 1117 } 1118 1119 /*********************************************************************** 1120 * ImmGetContext (IMM32.@) 1121 */ 1122 HIMC WINAPI ImmGetContext(HWND hWnd) 1123 { 1124 TRACE("(%p)\n", hWnd); 1125 if (hWnd == NULL) 1126 return NULL; 1127 return Imm32GetContextEx(hWnd, 2); 1128 } 1129 1130 /*********************************************************************** 1131 * CtfImmIsCiceroEnabled (IMM32.@) 1132 */ 1133 BOOL WINAPI CtfImmIsCiceroEnabled(VOID) 1134 { 1135 return (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED)); 1136 } 1137 1138 /*********************************************************************** 1139 * ImmInstallIMEA (IMM32.@) 1140 */ 1141 HKL WINAPI ImmInstallIMEA(LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText) 1142 { 1143 HKL hKL = NULL; 1144 LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL; 1145 1146 TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText)); 1147 1148 pszFileNameW = Imm32WideFromAnsi(lpszIMEFileName); 1149 if (pszFileNameW == NULL) 1150 goto Quit; 1151 1152 pszLayoutTextW = Imm32WideFromAnsi(lpszLayoutText); 1153 if (pszLayoutTextW == NULL) 1154 goto Quit; 1155 1156 hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW); 1157 1158 Quit: 1159 if (pszFileNameW) 1160 HeapFree(g_hImm32Heap, 0, pszFileNameW); 1161 if (pszLayoutTextW) 1162 HeapFree(g_hImm32Heap, 0, pszLayoutTextW); 1163 return hKL; 1164 } 1165 1166 /*********************************************************************** 1167 * ImmInstallIMEW (IMM32.@) 1168 */ 1169 HKL WINAPI ImmInstallIMEW(LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText) 1170 { 1171 INT lcid = GetUserDefaultLCID(); 1172 INT count; 1173 HKL hkl; 1174 DWORD rc; 1175 HKEY hkey; 1176 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8]; 1177 1178 TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName), 1179 debugstr_w(lpszLayoutText)); 1180 1181 /* Start with 2. e001 will be blank and so default to the wine internal IME */ 1182 count = 2; 1183 1184 while (count < 0xfff) 1185 { 1186 DWORD disposition = 0; 1187 1188 hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count ); 1189 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl); 1190 1191 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition); 1192 if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY) 1193 break; 1194 else if (rc == ERROR_SUCCESS) 1195 RegCloseKey(hkey); 1196 1197 count++; 1198 } 1199 1200 if (count == 0xfff) 1201 { 1202 WARN("Unable to find slot to install IME\n"); 1203 return 0; 1204 } 1205 1206 if (rc == ERROR_SUCCESS) 1207 { 1208 rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName, 1209 (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR)); 1210 if (rc == ERROR_SUCCESS) 1211 rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText, 1212 (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR)); 1213 RegCloseKey(hkey); 1214 return hkl; 1215 } 1216 else 1217 { 1218 WARN("Unable to set IME registry values\n"); 1219 return 0; 1220 } 1221 } 1222 1223 /*********************************************************************** 1224 * ImmLockIMC(IMM32.@) 1225 */ 1226 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC) 1227 { 1228 InputContextData *data = get_imc_data(hIMC); 1229 1230 if (!data) 1231 return NULL; 1232 data->dwLock++; 1233 return &data->IMC; 1234 } 1235 1236 /*********************************************************************** 1237 * ImmUnlockIMC(IMM32.@) 1238 */ 1239 BOOL WINAPI ImmUnlockIMC(HIMC hIMC) 1240 { 1241 PCLIENTIMC pClientImc; 1242 HIMC hClientImc; 1243 1244 pClientImc = ImmLockClientImc(hIMC); 1245 if (pClientImc == NULL) 1246 return FALSE; 1247 1248 hClientImc = pClientImc->hImc; 1249 if (hClientImc) 1250 LocalUnlock(hClientImc); 1251 1252 InterlockedDecrement(&pClientImc->cLockObj); 1253 ImmUnlockClientImc(pClientImc); 1254 return TRUE; 1255 } 1256 1257 /*********************************************************************** 1258 * ImmRequestMessageA(IMM32.@) 1259 */ 1260 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam) 1261 { 1262 InputContextData *data = get_imc_data(hIMC); 1263 1264 TRACE("%p %ld %ld\n", hIMC, wParam, wParam); 1265 1266 if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); 1267 1268 SetLastError(ERROR_INVALID_HANDLE); 1269 return 0; 1270 } 1271 1272 /*********************************************************************** 1273 * ImmRequestMessageW(IMM32.@) 1274 */ 1275 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam) 1276 { 1277 InputContextData *data = get_imc_data(hIMC); 1278 1279 TRACE("%p %ld %ld\n", hIMC, wParam, wParam); 1280 1281 if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); 1282 1283 SetLastError(ERROR_INVALID_HANDLE); 1284 return 0; 1285 } 1286 1287 /*********************************************************************** 1288 * ImmReleaseContext (IMM32.@) 1289 */ 1290 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC) 1291 { 1292 TRACE("(%p, %p)\n", hWnd, hIMC); 1293 UNREFERENCED_PARAMETER(hWnd); 1294 UNREFERENCED_PARAMETER(hIMC); 1295 return TRUE; // Do nothing. This is correct. 1296 } 1297 1298 /*********************************************************************** 1299 * ImmSetCompositionStringA (IMM32.@) 1300 */ 1301 BOOL WINAPI 1302 ImmSetCompositionStringA(HIMC hIMC, DWORD dwIndex, 1303 LPCVOID lpComp, DWORD dwCompLen, 1304 LPCVOID lpRead, DWORD dwReadLen) 1305 { 1306 DWORD comp_len; 1307 DWORD read_len; 1308 WCHAR *CompBuffer = NULL; 1309 WCHAR *ReadBuffer = NULL; 1310 BOOL rc; 1311 InputContextData *data = get_imc_data(hIMC); 1312 1313 TRACE("(%p, %d, %p, %d, %p, %d):\n", 1314 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); 1315 1316 if (!data) 1317 return FALSE; 1318 1319 if (!(dwIndex == SCS_SETSTR || 1320 dwIndex == SCS_CHANGEATTR || 1321 dwIndex == SCS_CHANGECLAUSE || 1322 dwIndex == SCS_SETRECONVERTSTRING || 1323 dwIndex == SCS_QUERYRECONVERTSTRING)) 1324 return FALSE; 1325 1326 if (!is_himc_ime_unicode(data)) 1327 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp, 1328 dwCompLen, lpRead, dwReadLen); 1329 1330 comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0); 1331 if (comp_len) 1332 { 1333 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR)); 1334 MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len); 1335 } 1336 1337 read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0); 1338 if (read_len) 1339 { 1340 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR)); 1341 MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len); 1342 } 1343 1344 rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len, 1345 ReadBuffer, read_len); 1346 1347 HeapFree(GetProcessHeap(), 0, CompBuffer); 1348 HeapFree(GetProcessHeap(), 0, ReadBuffer); 1349 1350 return rc; 1351 } 1352 1353 /*********************************************************************** 1354 * ImmSetCompositionStringW (IMM32.@) 1355 */ 1356 BOOL WINAPI 1357 ImmSetCompositionStringW(HIMC hIMC, DWORD dwIndex, 1358 LPCVOID lpComp, DWORD dwCompLen, 1359 LPCVOID lpRead, DWORD dwReadLen) 1360 { 1361 DWORD comp_len; 1362 DWORD read_len; 1363 CHAR *CompBuffer = NULL; 1364 CHAR *ReadBuffer = NULL; 1365 BOOL rc; 1366 InputContextData *data = get_imc_data(hIMC); 1367 1368 TRACE("(%p, %d, %p, %d, %p, %d):\n", 1369 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); 1370 1371 if (!data) 1372 return FALSE; 1373 1374 if (!(dwIndex == SCS_SETSTR || 1375 dwIndex == SCS_CHANGEATTR || 1376 dwIndex == SCS_CHANGECLAUSE || 1377 dwIndex == SCS_SETRECONVERTSTRING || 1378 dwIndex == SCS_QUERYRECONVERTSTRING)) 1379 return FALSE; 1380 1381 if (is_himc_ime_unicode(data)) 1382 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp, 1383 dwCompLen, lpRead, dwReadLen); 1384 1385 comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL, 1386 NULL); 1387 if (comp_len) 1388 { 1389 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len); 1390 WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len, 1391 NULL, NULL); 1392 } 1393 1394 read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL, 1395 NULL); 1396 if (read_len) 1397 { 1398 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len); 1399 WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len, 1400 NULL, NULL); 1401 } 1402 1403 rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len, 1404 ReadBuffer, read_len); 1405 1406 HeapFree(GetProcessHeap(), 0, CompBuffer); 1407 HeapFree(GetProcessHeap(), 0, ReadBuffer); 1408 1409 return rc; 1410 } 1411 1412 /*********************************************************************** 1413 * ImmCreateSoftKeyboard(IMM32.@) 1414 */ 1415 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y) 1416 { 1417 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y); 1418 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1419 return 0; 1420 } 1421 1422 /*********************************************************************** 1423 * ImmDestroySoftKeyboard(IMM32.@) 1424 */ 1425 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd) 1426 { 1427 TRACE("(%p)\n", hSoftWnd); 1428 return DestroyWindow(hSoftWnd); 1429 } 1430 1431 /*********************************************************************** 1432 * ImmShowSoftKeyboard(IMM32.@) 1433 */ 1434 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow) 1435 { 1436 TRACE("(%p, %d)\n", hSoftWnd, nCmdShow); 1437 if (hSoftWnd) 1438 return ShowWindow(hSoftWnd, nCmdShow); 1439 return FALSE; 1440 } 1441 1442 /*********************************************************************** 1443 * ImmDisableTextFrameService(IMM32.@) 1444 */ 1445 BOOL WINAPI ImmDisableTextFrameService(DWORD dwThreadId) 1446 { 1447 FIXME("Stub\n"); 1448 return FALSE; 1449 } 1450 1451 /*********************************************************************** 1452 * ImmEnumInputContext(IMM32.@) 1453 */ 1454 BOOL WINAPI ImmEnumInputContext(DWORD dwThreadId, IMCENUMPROC lpfn, LPARAM lParam) 1455 { 1456 HIMC *phList; 1457 DWORD dwIndex, dwCount; 1458 BOOL ret = TRUE; 1459 HIMC hIMC; 1460 1461 TRACE("(%lu, %p, %p)\n", dwThreadId, lpfn, lParam); 1462 1463 dwCount = Imm32AllocAndBuildHimcList(dwThreadId, &phList); 1464 if (!dwCount) 1465 return FALSE; 1466 1467 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex) 1468 { 1469 hIMC = phList[dwIndex]; 1470 ret = (*lpfn)(hIMC, lParam); 1471 if (!ret) 1472 break; 1473 } 1474 1475 HeapFree(g_hImm32Heap, 0, phList); 1476 return ret; 1477 } 1478 1479 /*********************************************************************** 1480 * ImmSetActiveContext(IMM32.@) 1481 */ 1482 BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC hIMC, BOOL fFlag) 1483 { 1484 FIXME("(%p, %p, %d): stub\n", hwnd, hIMC, fFlag); 1485 return FALSE; 1486 } 1487 1488 /*********************************************************************** 1489 * ImmSetActiveContextConsoleIME(IMM32.@) 1490 */ 1491 BOOL WINAPI ImmSetActiveContextConsoleIME(HWND hwnd, BOOL fFlag) 1492 { 1493 HIMC hIMC; 1494 TRACE("(%p, %d)\n", hwnd, fFlag); 1495 1496 hIMC = ImmGetContext(hwnd); 1497 if (hIMC) 1498 return ImmSetActiveContext(hwnd, hIMC, fFlag); 1499 return FALSE; 1500 } 1501 1502 /*********************************************************************** 1503 * ImmGetImeMenuItemsA (IMM32.@) 1504 */ 1505 DWORD WINAPI 1506 ImmGetImeMenuItemsA(HIMC hIMC, DWORD dwFlags, DWORD dwType, 1507 LPIMEMENUITEMINFOA lpImeParentMenu, 1508 LPIMEMENUITEMINFOA lpImeMenu, DWORD dwSize) 1509 { 1510 InputContextData *data = get_imc_data(hIMC); 1511 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType, 1512 lpImeParentMenu, lpImeMenu, dwSize); 1513 1514 if (!data) 1515 { 1516 SetLastError(ERROR_INVALID_HANDLE); 1517 return 0; 1518 } 1519 1520 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems) 1521 { 1522 if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu)) 1523 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, 1524 (IMEMENUITEMINFOW*)lpImeParentMenu, 1525 (IMEMENUITEMINFOW*)lpImeMenu, dwSize); 1526 else 1527 { 1528 IMEMENUITEMINFOW lpImeParentMenuW; 1529 IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL; 1530 DWORD rc; 1531 1532 if (lpImeParentMenu) 1533 parent = &lpImeParentMenuW; 1534 if (lpImeMenu) 1535 { 1536 int count = dwSize / sizeof(LPIMEMENUITEMINFOA); 1537 dwSize = count * sizeof(IMEMENUITEMINFOW); 1538 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize); 1539 } 1540 else 1541 lpImeMenuW = NULL; 1542 1543 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, 1544 parent, lpImeMenuW, dwSize); 1545 1546 if (lpImeParentMenu) 1547 { 1548 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA)); 1549 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem; 1550 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString, 1551 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE, 1552 NULL, NULL); 1553 } 1554 if (lpImeMenu && rc) 1555 { 1556 unsigned int i; 1557 for (i = 0; i < rc; i++) 1558 { 1559 memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA)); 1560 lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem; 1561 WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString, 1562 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE, 1563 NULL, NULL); 1564 } 1565 } 1566 HeapFree(GetProcessHeap(),0,lpImeMenuW); 1567 return rc; 1568 } 1569 } 1570 else 1571 return 0; 1572 } 1573 1574 /*********************************************************************** 1575 * ImmGetImeMenuItemsW (IMM32.@) 1576 */ 1577 DWORD WINAPI 1578 ImmGetImeMenuItemsW(HIMC hIMC, DWORD dwFlags, DWORD dwType, 1579 LPIMEMENUITEMINFOW lpImeParentMenu, 1580 LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize) 1581 { 1582 InputContextData *data = get_imc_data(hIMC); 1583 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType, 1584 lpImeParentMenu, lpImeMenu, dwSize); 1585 1586 if (!data) 1587 { 1588 SetLastError(ERROR_INVALID_HANDLE); 1589 return 0; 1590 } 1591 1592 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems) 1593 { 1594 if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu)) 1595 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, 1596 lpImeParentMenu, lpImeMenu, dwSize); 1597 else 1598 { 1599 IMEMENUITEMINFOA lpImeParentMenuA; 1600 IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL; 1601 DWORD rc; 1602 1603 if (lpImeParentMenu) 1604 parent = &lpImeParentMenuA; 1605 if (lpImeMenu) 1606 { 1607 int count = dwSize / sizeof(LPIMEMENUITEMINFOW); 1608 dwSize = count * sizeof(IMEMENUITEMINFOA); 1609 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize); 1610 } 1611 else 1612 lpImeMenuA = NULL; 1613 1614 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, 1615 (IMEMENUITEMINFOW*)parent, 1616 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize); 1617 1618 if (lpImeParentMenu) 1619 { 1620 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA)); 1621 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem; 1622 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString, 1623 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE); 1624 } 1625 if (lpImeMenu && rc) 1626 { 1627 unsigned int i; 1628 for (i = 0; i < rc; i++) 1629 { 1630 memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA)); 1631 lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem; 1632 MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString, 1633 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE); 1634 } 1635 } 1636 HeapFree(GetProcessHeap(),0,lpImeMenuA); 1637 return rc; 1638 } 1639 } 1640 else 1641 return 0; 1642 } 1643 1644 BOOL WINAPI User32InitializeImmEntryTable(DWORD); 1645 1646 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) 1647 { 1648 HKL hKL; 1649 HIMC hIMC; 1650 PTEB pTeb; 1651 1652 TRACE("(%p, 0x%X, %p)\n", hinstDLL, fdwReason, lpReserved); 1653 1654 switch (fdwReason) 1655 { 1656 case DLL_PROCESS_ATTACH: 1657 //Imm32GenerateRandomSeed(hinstDLL, 1, lpReserved); // Non-sense 1658 if (!Imm32InitInstance(hinstDLL)) 1659 { 1660 ERR("Imm32InitInstance failed\n"); 1661 return FALSE; 1662 } 1663 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC)) 1664 { 1665 ERR("User32InitializeImmEntryTable failed\n"); 1666 return FALSE; 1667 } 1668 break; 1669 1670 case DLL_THREAD_ATTACH: 1671 break; 1672 1673 case DLL_THREAD_DETACH: 1674 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32)) 1675 return TRUE; 1676 1677 pTeb = NtCurrentTeb(); 1678 if (pTeb->Win32ThreadInfo == NULL) 1679 return TRUE; 1680 1681 hKL = GetKeyboardLayout(0); 1682 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken. 1683 hIMC = (HIMC)NtUserGetThreadState(4); 1684 Imm32CleanupContext(hIMC, hKL, TRUE); 1685 break; 1686 1687 case DLL_PROCESS_DETACH: 1688 RtlDeleteCriticalSection(&g_csImeDpi); 1689 TRACE("imm32.dll is unloaded\n"); 1690 break; 1691 } 1692 1693 return TRUE; 1694 } 1695