[IMM32] Move Imm(Get|Set)CompositionStringA/W (#4021)
[reactos.git] / dll / win32 / imm32 / imm.c
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) || !Imm32IsCiceroMode() || Imm32Is16BitMode())
66 {
67 UnicodeString.Buffer = szLayout;
68 UnicodeString.MaximumLength = sizeof(szLayout);
69 Status = RtlIntegerToUnicodeString((DWORD_PTR)hKL, 16, &UnicodeString);
70 if (!NT_SUCCESS(Status))
71 return NULL;
72
73 error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hLayoutsKey);
74 if (error)
75 return NULL;
76
77 error = RegOpenKeyW(hLayoutsKey, szLayout, &hLayoutKey);
78 }
79 else
80 {
81 error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_IMM, &hLayoutKey);
82 }
83
84 if (error)
85 {
86 ERR("RegOpenKeyW error: 0x%08lX\n", error);
87 hKL = NULL;
88 }
89 else
90 {
91 cbData = sizeof(pImeInfoEx->wszImeFile);
92 error = RegQueryValueExW(hLayoutKey, L"Ime File", 0, 0,
93 (LPBYTE)pImeInfoEx->wszImeFile, &cbData);
94 if (error)
95 hKL = NULL;
96 }
97
98 RegCloseKey(hLayoutKey);
99 if (hLayoutsKey)
100 RegCloseKey(hLayoutsKey);
101 return hKL;
102 }
103
104 /***********************************************************************
105 * ImmFreeLayout (IMM32.@)
106 */
107 BOOL WINAPI ImmFreeLayout(DWORD dwUnknown)
108 {
109 WCHAR szKBD[9];
110 UINT iKL, cKLs;
111 HKL hOldKL, hNewKL, *pList;
112 PIMEDPI pImeDpi;
113 LANGID LangID;
114
115 TRACE("(0x%lX)\n", dwUnknown);
116
117 hOldKL = GetKeyboardLayout(0);
118
119 if (dwUnknown == 1)
120 {
121 if (!IS_IME_HKL(hOldKL))
122 return TRUE;
123
124 LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
125
126 cKLs = GetKeyboardLayoutList(0, NULL);
127 if (cKLs)
128 {
129 pList = Imm32HeapAlloc(0, cKLs * sizeof(HKL));
130 if (pList == NULL)
131 return FALSE;
132
133 cKLs = GetKeyboardLayoutList(cKLs, pList);
134 for (iKL = 0; iKL < cKLs; ++iKL)
135 {
136 if (!IS_IME_HKL(pList[iKL]))
137 {
138 LangID = LOWORD(pList[iKL]);
139 break;
140 }
141 }
142
143 Imm32HeapFree(pList);
144 }
145
146 StringCchPrintfW(szKBD, _countof(szKBD), L"%08X", LangID);
147 if (!LoadKeyboardLayoutW(szKBD, KLF_ACTIVATE))
148 LoadKeyboardLayoutW(L"00000409", KLF_ACTIVATE | 0x200);
149 }
150 else if (dwUnknown == 2)
151 {
152 RtlEnterCriticalSection(&g_csImeDpi);
153 Retry:
154 for (pImeDpi = g_pImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext)
155 {
156 if (Imm32ReleaseIME(pImeDpi->hKL))
157 goto Retry;
158 }
159 RtlLeaveCriticalSection(&g_csImeDpi);
160 }
161 else
162 {
163 hNewKL = (HKL)(DWORD_PTR)dwUnknown;
164 if (IS_IME_HKL(hNewKL) && hNewKL != hOldKL)
165 Imm32ReleaseIME(hNewKL);
166 }
167
168 return TRUE;
169 }
170
171 VOID APIENTRY Imm32SelectLayout(HKL hNewKL, HKL hOldKL, HIMC hIMC)
172 {
173 PCLIENTIMC pClientImc;
174 LPINPUTCONTEXTDX pIC;
175 LPGUIDELINE pGL;
176 LPCANDIDATEINFO pCI;
177 LPCOMPOSITIONSTRING pCS;
178 LOGFONTA LogFontA;
179 LOGFONTW LogFontW;
180 BOOL fOpen, bIsNewHKLIme = TRUE, bIsOldHKLIme = TRUE, bClientWide, bNewDpiWide;
181 DWORD cbNewPrivate = 0, cbOldPrivate = 0, dwConversion, dwSentence, dwSize, dwNewSize;
182 PIMEDPI pNewImeDpi = NULL, pOldImeDpi = NULL;
183 HANDLE hPrivate;
184 PIME_STATE pNewState = NULL, pOldState = NULL;
185
186 pClientImc = ImmLockClientImc(hIMC);
187 if (!pClientImc)
188 return;
189
190 pNewImeDpi = ImmLockImeDpi(hNewKL);
191
192 if (hNewKL != hOldKL)
193 pOldImeDpi = ImmLockImeDpi(hOldKL);
194
195 if (pNewImeDpi)
196 {
197 cbNewPrivate = pNewImeDpi->ImeInfo.dwPrivateDataSize;
198 pClientImc->uCodePage = pNewImeDpi->uCodePage;
199 }
200 else
201 {
202 pClientImc->uCodePage = CP_ACP;
203 }
204
205 if (cbNewPrivate < sizeof(DWORD))
206 cbNewPrivate = sizeof(DWORD);
207
208 if (pOldImeDpi)
209 cbOldPrivate = pOldImeDpi->ImeInfo.dwPrivateDataSize;
210
211 if (cbOldPrivate < sizeof(DWORD))
212 cbOldPrivate = sizeof(DWORD);
213
214 if (pClientImc->hKL == hOldKL)
215 {
216 if (pOldImeDpi)
217 {
218 if (IS_IME_HKL(hOldKL))
219 pOldImeDpi->ImeSelect(hIMC, FALSE);
220 else if (Imm32IsCiceroMode() && !Imm32Is16BitMode() && pOldImeDpi->CtfImeSelectEx)
221 pOldImeDpi->CtfImeSelectEx(hIMC, FALSE, hOldKL);
222 }
223 pClientImc->hKL = NULL;
224 }
225
226 if (CtfImmIsTextFrameServiceDisabled())
227 {
228 if (Imm32IsImmMode() && !Imm32IsCiceroMode())
229 {
230 bIsNewHKLIme = IS_IME_HKL(hNewKL);
231 bIsOldHKLIme = IS_IME_HKL(hOldKL);
232 }
233 }
234
235 pIC = (LPINPUTCONTEXTDX)Imm32LockIMCEx(hIMC, FALSE);
236 if (!pIC)
237 {
238 if (pNewImeDpi)
239 {
240 if (IS_IME_HKL(hNewKL))
241 pNewImeDpi->ImeSelect(hIMC, TRUE);
242 else if (Imm32IsCiceroMode() && !Imm32Is16BitMode() && pNewImeDpi->CtfImeSelectEx)
243 pNewImeDpi->CtfImeSelectEx(hIMC, TRUE, hNewKL);
244
245 pClientImc->hKL = hNewKL;
246 }
247 }
248 else
249 {
250 dwConversion = pIC->fdwConversion;
251 dwSentence = pIC->fdwSentence;
252 fOpen = pIC->fOpen;
253
254 if (pNewImeDpi)
255 {
256 bClientWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
257 bNewDpiWide = ImeDpi_IsUnicode(pNewImeDpi);
258 if (bClientWide && !bNewDpiWide)
259 {
260 if (pIC->fdwInit & INIT_LOGFONT)
261 {
262 LogFontWideToAnsi(&pIC->lfFont.W, &LogFontA);
263 pIC->lfFont.A = LogFontA;
264 }
265 pClientImc->dwFlags &= ~CLIENTIMC_WIDE;
266 }
267 else if (!bClientWide && bNewDpiWide)
268 {
269 if (pIC->fdwInit & INIT_LOGFONT)
270 {
271 LogFontAnsiToWide(&pIC->lfFont.A, &LogFontW);
272 pIC->lfFont.W = LogFontW;
273 }
274 pClientImc->dwFlags |= CLIENTIMC_WIDE;
275 }
276 }
277
278 if (cbOldPrivate != cbNewPrivate)
279 {
280 hPrivate = ImmReSizeIMCC(pIC->hPrivate, cbNewPrivate);
281 if (!hPrivate)
282 {
283 ImmDestroyIMCC(pIC->hPrivate);
284 hPrivate = ImmCreateIMCC(cbNewPrivate);
285 }
286 pIC->hPrivate = hPrivate;
287 }
288
289 #define MAX_IMCC_SIZE 0x1000
290 dwSize = ImmGetIMCCSize(pIC->hMsgBuf);
291 if (ImmGetIMCCLockCount(pIC->hMsgBuf) || dwSize > MAX_IMCC_SIZE)
292 {
293 ImmDestroyIMCC(pIC->hMsgBuf);
294 pIC->hMsgBuf = ImmCreateIMCC(sizeof(UINT));
295 pIC->dwNumMsgBuf = 0;
296 }
297
298 dwSize = ImmGetIMCCSize(pIC->hGuideLine);
299 dwNewSize = sizeof(GUIDELINE);
300 if (ImmGetIMCCLockCount(pIC->hGuideLine) ||
301 dwSize < dwNewSize || dwSize > MAX_IMCC_SIZE)
302 {
303 ImmDestroyIMCC(pIC->hGuideLine);
304 pIC->hGuideLine = ImmCreateIMCC(dwNewSize);
305 pGL = ImmLockIMCC(pIC->hGuideLine);
306 if (pGL)
307 {
308 pGL->dwSize = dwNewSize;
309 ImmUnlockIMCC(pIC->hGuideLine);
310 }
311 }
312
313 dwSize = ImmGetIMCCSize(pIC->hCandInfo);
314 dwNewSize = sizeof(CANDIDATEINFO);
315 if (ImmGetIMCCLockCount(pIC->hCandInfo) ||
316 dwSize < dwNewSize || dwSize > MAX_IMCC_SIZE)
317 {
318 ImmDestroyIMCC(pIC->hCandInfo);
319 pIC->hCandInfo = ImmCreateIMCC(dwNewSize);
320 pCI = ImmLockIMCC(pIC->hCandInfo);
321 if (pCI)
322 {
323 pCI->dwSize = dwNewSize;
324 ImmUnlockIMCC(pIC->hCandInfo);
325 }
326 }
327
328 dwSize = ImmGetIMCCSize(pIC->hCompStr);
329 dwNewSize = sizeof(COMPOSITIONSTRING);
330 if (ImmGetIMCCLockCount(pIC->hCompStr) ||
331 dwSize < dwNewSize || dwSize > MAX_IMCC_SIZE)
332 {
333 ImmDestroyIMCC(pIC->hCompStr);
334 pIC->hCompStr = ImmCreateIMCC(dwNewSize);
335 pCS = ImmLockIMCC(pIC->hCompStr);
336 if (pCS)
337 {
338 pCS->dwSize = dwNewSize;
339 ImmUnlockIMCC(pIC->hCompStr);
340 }
341 }
342 #undef MAX_IMCC_SIZE
343
344 if (pOldImeDpi && bIsOldHKLIme)
345 {
346 pOldState = Imm32FetchImeState(pIC, hOldKL);
347 if (pOldState)
348 Imm32SaveImeStateSentence(pIC, pOldState, hOldKL);
349 }
350
351 if (pNewImeDpi && bIsNewHKLIme)
352 pNewState = Imm32FetchImeState(pIC, hNewKL);
353
354 if (pOldState != pNewState)
355 {
356 if (pOldState)
357 {
358 pOldState->fOpen = !!pIC->fOpen;
359 pOldState->dwConversion = (pIC->fdwConversion & ~IME_CMODE_EUDC);
360 pOldState->dwSentence = pIC->fdwSentence;
361 pOldState->dwInit = pIC->fdwInit;
362 }
363
364 if (pNewState)
365 {
366 if (pIC->dwChange & INPUTCONTEXTDX_CHANGE_FORCE_OPEN)
367 {
368 pIC->dwChange &= ~INPUTCONTEXTDX_CHANGE_FORCE_OPEN;
369 pIC->fOpen = TRUE;
370 }
371 else
372 {
373 pIC->fOpen = pNewState->fOpen;
374 }
375
376 pIC->fdwConversion = (pNewState->dwConversion & ~IME_CMODE_EUDC);
377 pIC->fdwSentence = pNewState->dwSentence;
378 pIC->fdwInit = pNewState->dwInit;
379 }
380 }
381
382 if (pNewState)
383 Imm32LoadImeStateSentence(pIC, pNewState, hNewKL);
384
385 if (pNewImeDpi)
386 {
387 if (IS_IME_HKL(hNewKL))
388 pNewImeDpi->ImeSelect(hIMC, TRUE);
389 else if (Imm32IsCiceroMode() && !Imm32Is16BitMode() && pNewImeDpi->CtfImeSelectEx)
390 pNewImeDpi->CtfImeSelectEx(hIMC, TRUE, hNewKL);
391
392 pClientImc->hKL = hNewKL;
393 }
394
395 pIC->dwChange = 0;
396 if (pIC->fOpen != fOpen)
397 pIC->dwChange |= INPUTCONTEXTDX_CHANGE_OPEN;
398 if (pIC->fdwConversion != dwConversion)
399 pIC->dwChange |= INPUTCONTEXTDX_CHANGE_CONVERSION;
400 if (pIC->fdwSentence != dwSentence)
401 pIC->dwChange |= INPUTCONTEXTDX_CHANGE_SENTENCE;
402
403 ImmUnlockIMC(hIMC);
404 }
405
406 ImmUnlockImeDpi(pOldImeDpi);
407 ImmUnlockImeDpi(pNewImeDpi);
408 ImmUnlockClientImc(pClientImc);
409 }
410
411 typedef struct SELECT_LAYOUT
412 {
413 HKL hNewKL;
414 HKL hOldKL;
415 } SELECT_LAYOUT, *LPSELECT_LAYOUT;
416
417 static BOOL CALLBACK Imm32SelectLayoutProc(HIMC hIMC, LPARAM lParam)
418 {
419 LPSELECT_LAYOUT pSelect = (LPSELECT_LAYOUT)lParam;
420 Imm32SelectLayout(pSelect->hNewKL, pSelect->hOldKL, hIMC);
421 return TRUE;
422 }
423
424 static BOOL CALLBACK Imm32NotifyCompStrProc(HIMC hIMC, LPARAM lParam)
425 {
426 ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, (DWORD)lParam, 0);
427 return TRUE;
428 }
429
430 /***********************************************************************
431 * ImmActivateLayout (IMM32.@)
432 */
433 BOOL WINAPI ImmActivateLayout(HKL hKL)
434 {
435 PIMEDPI pImeDpi;
436 HKL hOldKL;
437 LPARAM lParam;
438 HWND hwndDefIME = NULL;
439 SELECT_LAYOUT SelectLayout;
440
441 hOldKL = GetKeyboardLayout(0);
442
443 if (hOldKL == hKL && !(GetWin32ClientInfo()->CI_flags & CI_IMMACTIVATE))
444 return TRUE;
445
446 ImmLoadIME(hKL);
447
448 if (hOldKL != hKL)
449 {
450 pImeDpi = ImmLockImeDpi(hOldKL);
451 if (pImeDpi)
452 {
453 if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_COMPLETE_ON_UNSELECT)
454 lParam = CPS_COMPLETE;
455 else
456 lParam = CPS_CANCEL;
457 ImmUnlockImeDpi(pImeDpi);
458
459 ImmEnumInputContext(0, Imm32NotifyCompStrProc, lParam);
460 }
461
462 hwndDefIME = ImmGetDefaultIMEWnd(NULL);
463 if (IsWindow(hwndDefIME))
464 SendMessageW(hwndDefIME, WM_IME_SELECT, FALSE, (LPARAM)hOldKL);
465
466 NtUserSetThreadLayoutHandles(hKL, hOldKL);
467 }
468
469 SelectLayout.hNewKL = hKL;
470 SelectLayout.hOldKL = hOldKL;
471 ImmEnumInputContext(0, Imm32SelectLayoutProc, (LPARAM)&SelectLayout);
472
473 if (IsWindow(hwndDefIME))
474 SendMessageW(hwndDefIME, WM_IME_SELECT, TRUE, (LPARAM)hKL);
475
476 return TRUE;
477 }
478
479 static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
480 static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0};
481 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};
482
483 static VOID APIENTRY Imm32CiceroSetActiveContext(HIMC hIMC, BOOL fActive, HWND hWnd, HKL hKL)
484 {
485 FIXME("We have to do something\n");
486 }
487
488 /***********************************************************************
489 * ImmAssociateContext (IMM32.@)
490 */
491 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
492 {
493 PWND pWnd;
494 HWND hwndFocus;
495 DWORD dwValue;
496 HIMC hOldIMC;
497
498 TRACE("(%p, %p)\n", hWnd, hIMC);
499
500 if (!Imm32IsImmMode())
501 return NULL;
502
503 pWnd = ValidateHwndNoErr(hWnd);
504 if (!pWnd)
505 return NULL;
506
507 if (hIMC && Imm32IsCrossThreadAccess(hIMC))
508 return NULL;
509
510 hOldIMC = pWnd->hImc;
511 if (hOldIMC == hIMC)
512 return hIMC;
513
514 dwValue = NtUserAssociateInputContext(hWnd, hIMC, 0);
515 if (dwValue == 0)
516 return hOldIMC;
517 if (dwValue != 1)
518 return NULL;
519
520 hwndFocus = (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_FOCUS);
521 if (hwndFocus == hWnd)
522 {
523 ImmSetActiveContext(hWnd, hOldIMC, FALSE);
524 ImmSetActiveContext(hWnd, hIMC, TRUE);
525 }
526
527 return hOldIMC;
528 }
529
530 /***********************************************************************
531 * ImmAssociateContextEx (IMM32.@)
532 */
533 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
534 {
535 HWND hwndFocus;
536 PWND pFocusWnd;
537 HIMC hOldIMC = NULL;
538 DWORD dwValue;
539
540 TRACE("(%p, %p, 0x%lX)\n", hWnd, hIMC, dwFlags);
541
542 if (!Imm32IsImmMode())
543 return FALSE;
544
545 if (hIMC && !(dwFlags & IACE_DEFAULT) && Imm32IsCrossThreadAccess(hIMC))
546 return FALSE;
547
548 hwndFocus = (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_FOCUS);
549 pFocusWnd = ValidateHwndNoErr(hwndFocus);
550 if (pFocusWnd)
551 hOldIMC = pFocusWnd->hImc;
552
553 dwValue = NtUserAssociateInputContext(hWnd, hIMC, dwFlags);
554 switch (dwValue)
555 {
556 case 0:
557 return TRUE;
558
559 case 1:
560 pFocusWnd = ValidateHwndNoErr(hwndFocus);
561 if (pFocusWnd)
562 {
563 hIMC = pFocusWnd->hImc;
564 if (hIMC != hOldIMC)
565 {
566 ImmSetActiveContext(hwndFocus, hOldIMC, FALSE);
567 ImmSetActiveContext(hwndFocus, hIMC, TRUE);
568 }
569 }
570 return TRUE;
571
572 default:
573 return FALSE;
574 }
575 }
576
577 /***********************************************************************
578 * ImmCreateContext (IMM32.@)
579 */
580 HIMC WINAPI ImmCreateContext(void)
581 {
582 PCLIENTIMC pClientImc;
583 HIMC hIMC;
584
585 TRACE("()\n");
586
587 if (!Imm32IsImmMode())
588 return NULL;
589
590 pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
591 if (pClientImc == NULL)
592 return NULL;
593
594 hIMC = NtUserCreateInputContext(pClientImc);
595 if (hIMC == NULL)
596 {
597 Imm32HeapFree(pClientImc);
598 return NULL;
599 }
600
601 RtlInitializeCriticalSection(&pClientImc->cs);
602
603 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
604 pClientImc->unknown = NtUserGetThreadState(13);
605
606 return hIMC;
607 }
608
609 static VOID APIENTRY Imm32FreeImeStates(LPINPUTCONTEXTDX pIC)
610 {
611 PIME_STATE pState, pStateNext;
612 PIME_SUBSTATE pSubState, pSubStateNext;
613
614 pState = pIC->pState;
615 pIC->pState = NULL;
616 for (; pState; pState = pStateNext)
617 {
618 pStateNext = pState->pNext;
619 for (pSubState = pState->pSubState; pSubState; pSubState = pSubStateNext)
620 {
621 pSubStateNext = pSubState->pNext;
622 Imm32HeapFree(pSubState);
623 }
624 Imm32HeapFree(pState);
625 }
626 }
627
628 BOOL APIENTRY Imm32CleanupContext(HIMC hIMC, HKL hKL, BOOL bKeep)
629 {
630 PIMEDPI pImeDpi;
631 LPINPUTCONTEXTDX pIC;
632 PCLIENTIMC pClientImc;
633 PIMC pIMC;
634
635 if (!Imm32IsImmMode() || hIMC == NULL)
636 return FALSE;
637
638 pIMC = ValidateHandleNoErr(hIMC, TYPE_INPUTCONTEXT);
639 if (!pIMC || pIMC->head.pti != NtCurrentTeb()->Win32ThreadInfo)
640 return FALSE;
641
642 pClientImc = (PCLIENTIMC)pIMC->dwClientImcData;
643 if (!pClientImc)
644 return FALSE;
645
646 if (pClientImc->hInputContext == NULL)
647 {
648 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1;
649 ImmUnlockClientImc(pClientImc);
650 if (!bKeep)
651 return NtUserDestroyInputContext(hIMC);
652 return TRUE;
653 }
654
655 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
656 if (pIC == NULL)
657 {
658 ImmUnlockClientImc(pClientImc);
659 return FALSE;
660 }
661
662 FIXME("We have do something to do here\n");
663
664 if (pClientImc->hKL == hKL)
665 {
666 pImeDpi = ImmLockImeDpi(hKL);
667 if (pImeDpi != NULL)
668 {
669 if (IS_IME_HKL(hKL))
670 {
671 pImeDpi->ImeSelect(hIMC, FALSE);
672 }
673 else if (Imm32IsCiceroMode() && pImeDpi->CtfImeSelectEx)
674 {
675 pImeDpi->CtfImeSelectEx(hIMC, FALSE, hKL);
676 }
677 ImmUnlockImeDpi(pImeDpi);
678 }
679 pClientImc->hKL = NULL;
680 }
681
682 pIC->hPrivate = ImmDestroyIMCC(pIC->hPrivate);
683 pIC->hMsgBuf = ImmDestroyIMCC(pIC->hMsgBuf);
684 pIC->hGuideLine = ImmDestroyIMCC(pIC->hGuideLine);
685 pIC->hCandInfo = ImmDestroyIMCC(pIC->hCandInfo);
686 pIC->hCompStr = ImmDestroyIMCC(pIC->hCompStr);
687
688 Imm32FreeImeStates(pIC);
689
690 ImmUnlockIMC(hIMC);
691
692 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1;
693 ImmUnlockClientImc(pClientImc);
694
695 if (!bKeep)
696 return NtUserDestroyInputContext(hIMC);
697
698 return TRUE;
699 }
700
701 BOOL APIENTRY
702 Imm32InitContext(HIMC hIMC, LPINPUTCONTEXT pIC, PCLIENTIMC pClientImc, HKL hKL, BOOL fSelect)
703 {
704 DWORD dwIndex, cbPrivate;
705 PIMEDPI pImeDpi = NULL;
706 LPCOMPOSITIONSTRING pCS;
707 LPCANDIDATEINFO pCI;
708 LPGUIDELINE pGL;
709 /* NOTE: Windows does recursive call ImmLockIMC here but we don't do so. */
710
711 /* Create IC components */
712 pIC->hCompStr = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
713 pIC->hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
714 pIC->hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
715 pIC->hMsgBuf = ImmCreateIMCC(sizeof(UINT));
716 if (!pIC->hCompStr || !pIC->hCandInfo || !pIC->hGuideLine || !pIC->hMsgBuf)
717 goto Fail;
718
719 /* Initialize IC components */
720 pCS = ImmLockIMCC(pIC->hCompStr);
721 if (!pCS)
722 goto Fail;
723 pCS->dwSize = sizeof(COMPOSITIONSTRING);
724 ImmUnlockIMCC(pIC->hCompStr);
725
726 pCI = ImmLockIMCC(pIC->hCandInfo);
727 if (!pCI)
728 goto Fail;
729 pCI->dwSize = sizeof(CANDIDATEINFO);
730 ImmUnlockIMCC(pIC->hCandInfo);
731
732 pGL = ImmLockIMCC(pIC->hGuideLine);
733 if (!pGL)
734 goto Fail;
735 pGL->dwSize = sizeof(GUIDELINE);
736 ImmUnlockIMCC(pIC->hGuideLine);
737
738 pIC->dwNumMsgBuf = 0;
739 pIC->fOpen = FALSE;
740 pIC->fdwConversion = pIC->fdwSentence = 0;
741
742 for (dwIndex = 0; dwIndex < MAX_CANDIDATEFORM; ++dwIndex)
743 pIC->cfCandForm[dwIndex].dwIndex = IMM_INVALID_CANDFORM;
744
745 /* Get private data size */
746 pImeDpi = ImmLockImeDpi(hKL);
747 if (!pImeDpi)
748 {
749 cbPrivate = sizeof(DWORD);
750 }
751 else
752 {
753 /* Update CLIENTIMC */
754 pClientImc->uCodePage = pImeDpi->uCodePage;
755 if (ImeDpi_IsUnicode(pImeDpi))
756 pClientImc->dwFlags |= CLIENTIMC_WIDE;
757
758 cbPrivate = pImeDpi->ImeInfo.dwPrivateDataSize;
759 }
760
761 /* Create private data */
762 pIC->hPrivate = ImmCreateIMCC(cbPrivate);
763 if (!pIC->hPrivate)
764 goto Fail;
765
766 if (pImeDpi)
767 {
768 /* Select the IME */
769 if (fSelect)
770 {
771 if (IS_IME_HKL(hKL))
772 pImeDpi->ImeSelect(hIMC, TRUE);
773 else if (Imm32IsCiceroMode() && !Imm32Is16BitMode() && pImeDpi->CtfImeSelectEx)
774 pImeDpi->CtfImeSelectEx(hIMC, TRUE, hKL);
775 }
776
777 /* Set HKL */
778 pClientImc->hKL = hKL;
779
780 ImmUnlockImeDpi(pImeDpi);
781 }
782
783 return TRUE;
784
785 Fail:
786 if (pImeDpi)
787 ImmUnlockImeDpi(pImeDpi);
788
789 pIC->hMsgBuf = ImmDestroyIMCC(pIC->hMsgBuf);
790 pIC->hGuideLine = ImmDestroyIMCC(pIC->hGuideLine);
791 pIC->hCandInfo = ImmDestroyIMCC(pIC->hCandInfo);
792 pIC->hCompStr = ImmDestroyIMCC(pIC->hCompStr);
793 return FALSE;
794 }
795
796 LPINPUTCONTEXT APIENTRY Imm32LockIMCEx(HIMC hIMC, BOOL fSelect)
797 {
798 HANDLE hIC;
799 LPINPUTCONTEXT pIC = NULL;
800 PCLIENTIMC pClientImc;
801 WORD Word;
802 DWORD dwThreadId;
803 HKL hKL, hNewKL;
804 PIMEDPI pImeDpi = NULL;
805 BOOL bInited;
806
807 pClientImc = ImmLockClientImc(hIMC);
808 if (!pClientImc)
809 return NULL;
810
811 RtlEnterCriticalSection(&pClientImc->cs);
812
813 if (!pClientImc->hInputContext)
814 {
815 dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, 1);
816
817 if (dwThreadId == GetCurrentThreadId() && Imm32IsCiceroMode() && !Imm32Is16BitMode())
818 {
819 hKL = GetKeyboardLayout(0);
820 Word = LOWORD(hKL);
821 hNewKL = (HKL)(DWORD_PTR)MAKELONG(Word, Word);
822
823 pImeDpi = ImmLockOrLoadImeDpi(hNewKL);
824 if (pImeDpi)
825 {
826 FIXME("We have to do something here\n");
827 }
828 }
829
830 if (!NtUserQueryInputContext(hIMC, 2))
831 {
832 RtlLeaveCriticalSection(&pClientImc->cs);
833 goto Quit;
834 }
835
836 hIC = LocalAlloc(LHND, sizeof(INPUTCONTEXTDX));
837 if (!hIC)
838 {
839 RtlLeaveCriticalSection(&pClientImc->cs);
840 goto Quit;
841 }
842 pClientImc->hInputContext = hIC;
843
844 pIC = LocalLock(pClientImc->hInputContext);
845 if (!pIC)
846 {
847 pClientImc->hInputContext = LocalFree(pClientImc->hInputContext);
848 RtlLeaveCriticalSection(&pClientImc->cs);
849 goto Quit;
850 }
851
852 hKL = GetKeyboardLayout(dwThreadId);
853 // bInited = Imm32InitContext(hIMC, hKL, fSelect);
854 bInited = Imm32InitContext(hIMC, pIC, pClientImc, hKL, fSelect);
855 LocalUnlock(pClientImc->hInputContext);
856
857 if (!bInited)
858 {
859 pIC = NULL;
860 pClientImc->hInputContext = LocalFree(pClientImc->hInputContext);
861 RtlLeaveCriticalSection(&pClientImc->cs);
862 goto Quit;
863 }
864 }
865
866 FIXME("We have to do something here\n");
867
868 RtlLeaveCriticalSection(&pClientImc->cs);
869 pIC = LocalLock(pClientImc->hInputContext);
870 InterlockedIncrement(&pClientImc->cLockObj);
871
872 Quit:
873 ImmUnlockClientImc(pClientImc);
874 return pIC;
875 }
876
877 /***********************************************************************
878 * ImmDestroyContext (IMM32.@)
879 */
880 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
881 {
882 HKL hKL;
883
884 TRACE("(%p)\n", hIMC);
885
886 if (!Imm32IsImmMode())
887 return FALSE;
888
889 if (Imm32IsCrossThreadAccess(hIMC))
890 return FALSE;
891
892 hKL = GetKeyboardLayout(0);
893 return Imm32CleanupContext(hIMC, hKL, FALSE);
894 }
895
896 /***********************************************************************
897 * ImmLockClientImc (IMM32.@)
898 */
899 PCLIENTIMC WINAPI ImmLockClientImc(HIMC hImc)
900 {
901 PIMC pIMC;
902 PCLIENTIMC pClientImc;
903
904 TRACE("(%p)\n", hImc);
905
906 if (hImc == NULL)
907 return NULL;
908
909 pIMC = ValidateHandleNoErr(hImc, TYPE_INPUTCONTEXT);
910 if (pIMC == NULL || !Imm32CheckImcProcess(pIMC))
911 return NULL;
912
913 pClientImc = (PCLIENTIMC)pIMC->dwClientImcData;
914 if (!pClientImc)
915 {
916 pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
917 if (!pClientImc)
918 return NULL;
919
920 RtlInitializeCriticalSection(&pClientImc->cs);
921
922 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
923 pClientImc->unknown = NtUserGetThreadState(13);
924
925 if (!NtUserUpdateInputContext(hImc, 0, pClientImc))
926 {
927 Imm32HeapFree(pClientImc);
928 return NULL;
929 }
930
931 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN2;
932 }
933 else
934 {
935 if (pClientImc->dwFlags & CLIENTIMC_UNKNOWN1)
936 return NULL;
937 }
938
939 InterlockedIncrement(&pClientImc->cLockObj);
940 return pClientImc;
941 }
942
943 /***********************************************************************
944 * ImmUnlockClientImc (IMM32.@)
945 */
946 VOID WINAPI ImmUnlockClientImc(PCLIENTIMC pClientImc)
947 {
948 LONG cLocks;
949 HANDLE hInputContext;
950
951 TRACE("(%p)\n", pClientImc);
952
953 cLocks = InterlockedDecrement(&pClientImc->cLockObj);
954 if (cLocks != 0 || !(pClientImc->dwFlags & CLIENTIMC_UNKNOWN1))
955 return;
956
957 hInputContext = pClientImc->hInputContext;
958 if (hInputContext)
959 LocalFree(hInputContext);
960
961 RtlDeleteCriticalSection(&pClientImc->cs);
962 Imm32HeapFree(pClientImc);
963 }
964
965 static HIMC APIENTRY Imm32GetContextEx(HWND hWnd, DWORD dwContextFlags)
966 {
967 HIMC hIMC;
968 PCLIENTIMC pClientImc;
969 PWND pWnd;
970
971 if (!Imm32IsImmMode())
972 return NULL;
973
974 if (!hWnd)
975 {
976 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
977 hIMC = (HIMC)NtUserGetThreadState(4);
978 goto Quit;
979 }
980
981 pWnd = ValidateHwndNoErr(hWnd);
982 if (!pWnd || Imm32IsCrossProcessAccess(hWnd))
983 return NULL;
984
985 hIMC = pWnd->hImc;
986 if (!hIMC && (dwContextFlags & 1))
987 hIMC = (HIMC)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_ICONTEXT);
988
989 Quit:
990 pClientImc = ImmLockClientImc(hIMC);
991 if (pClientImc == NULL)
992 return NULL;
993 if ((dwContextFlags & 2) && (pClientImc->dwFlags & CLIENTIMC_UNKNOWN3))
994 hIMC = NULL;
995 ImmUnlockClientImc(pClientImc);
996 return hIMC;
997 }
998
999 /***********************************************************************
1000 * ImmGetContext (IMM32.@)
1001 */
1002 HIMC WINAPI ImmGetContext(HWND hWnd)
1003 {
1004 TRACE("(%p)\n", hWnd);
1005 if (hWnd == NULL)
1006 return NULL;
1007 return Imm32GetContextEx(hWnd, 2);
1008 }
1009
1010 /***********************************************************************
1011 * CtfImmIsCiceroEnabled (IMM32.@)
1012 */
1013 BOOL WINAPI CtfImmIsCiceroEnabled(VOID)
1014 {
1015 return Imm32IsCiceroMode();
1016 }
1017
1018 /***********************************************************************
1019 * ImmInstallIMEA (IMM32.@)
1020 */
1021 HKL WINAPI ImmInstallIMEA(LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
1022 {
1023 HKL hKL = NULL;
1024 LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL;
1025
1026 TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText));
1027
1028 pszFileNameW = Imm32WideFromAnsi(lpszIMEFileName);
1029 if (pszFileNameW == NULL)
1030 goto Quit;
1031
1032 pszLayoutTextW = Imm32WideFromAnsi(lpszLayoutText);
1033 if (pszLayoutTextW == NULL)
1034 goto Quit;
1035
1036 hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW);
1037
1038 Quit:
1039 Imm32HeapFree(pszFileNameW);
1040 Imm32HeapFree(pszLayoutTextW);
1041 return hKL;
1042 }
1043
1044 /***********************************************************************
1045 * ImmInstallIMEW (IMM32.@)
1046 */
1047 HKL WINAPI ImmInstallIMEW(LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
1048 {
1049 INT lcid = GetUserDefaultLCID();
1050 INT count;
1051 HKL hkl;
1052 DWORD rc;
1053 HKEY hkey;
1054 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
1055
1056 TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
1057 debugstr_w(lpszLayoutText));
1058
1059 /* Start with 2. e001 will be blank and so default to the wine internal IME */
1060 count = 2;
1061
1062 while (count < 0xfff)
1063 {
1064 DWORD disposition = 0;
1065
1066 hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
1067 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
1068
1069 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
1070 if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
1071 break;
1072 else if (rc == ERROR_SUCCESS)
1073 RegCloseKey(hkey);
1074
1075 count++;
1076 }
1077
1078 if (count == 0xfff)
1079 {
1080 WARN("Unable to find slot to install IME\n");
1081 return 0;
1082 }
1083
1084 if (rc == ERROR_SUCCESS)
1085 {
1086 rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName,
1087 (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
1088 if (rc == ERROR_SUCCESS)
1089 rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText,
1090 (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
1091 RegCloseKey(hkey);
1092 return hkl;
1093 }
1094 else
1095 {
1096 WARN("Unable to set IME registry values\n");
1097 return 0;
1098 }
1099 }
1100
1101 /***********************************************************************
1102 * ImmLockIMC(IMM32.@)
1103 *
1104 * NOTE: This is not ImmLockIMCC. Don't confuse.
1105 */
1106 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
1107 {
1108 TRACE("(%p)\n", hIMC);
1109 return Imm32LockIMCEx(hIMC, TRUE);
1110 }
1111
1112 /***********************************************************************
1113 * ImmUnlockIMC(IMM32.@)
1114 */
1115 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
1116 {
1117 PCLIENTIMC pClientImc;
1118
1119 pClientImc = ImmLockClientImc(hIMC);
1120 if (pClientImc == NULL)
1121 return FALSE;
1122
1123 if (pClientImc->hInputContext)
1124 LocalUnlock(pClientImc->hInputContext);
1125
1126 InterlockedDecrement(&pClientImc->cLockObj);
1127 ImmUnlockClientImc(pClientImc);
1128 return TRUE;
1129 }
1130
1131 /***********************************************************************
1132 * ImmReleaseContext (IMM32.@)
1133 */
1134 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
1135 {
1136 TRACE("(%p, %p)\n", hWnd, hIMC);
1137 UNREFERENCED_PARAMETER(hWnd);
1138 UNREFERENCED_PARAMETER(hIMC);
1139 return TRUE; // Do nothing. This is correct.
1140 }
1141
1142 /***********************************************************************
1143 * ImmCreateSoftKeyboard(IMM32.@)
1144 */
1145 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
1146 {
1147 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
1148 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1149 return 0;
1150 }
1151
1152 /***********************************************************************
1153 * ImmDestroySoftKeyboard(IMM32.@)
1154 */
1155 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
1156 {
1157 TRACE("(%p)\n", hSoftWnd);
1158 return DestroyWindow(hSoftWnd);
1159 }
1160
1161 /***********************************************************************
1162 * ImmShowSoftKeyboard(IMM32.@)
1163 */
1164 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
1165 {
1166 TRACE("(%p, %d)\n", hSoftWnd, nCmdShow);
1167 if (hSoftWnd)
1168 return ShowWindow(hSoftWnd, nCmdShow);
1169 return FALSE;
1170 }
1171
1172 /***********************************************************************
1173 * ImmDisableTextFrameService(IMM32.@)
1174 */
1175 BOOL WINAPI ImmDisableTextFrameService(DWORD dwThreadId)
1176 {
1177 FIXME("Stub\n");
1178 return FALSE;
1179 }
1180
1181 /***********************************************************************
1182 * ImmEnumInputContext(IMM32.@)
1183 */
1184 BOOL WINAPI ImmEnumInputContext(DWORD dwThreadId, IMCENUMPROC lpfn, LPARAM lParam)
1185 {
1186 HIMC *phList;
1187 DWORD dwIndex, dwCount;
1188 BOOL ret = TRUE;
1189 HIMC hIMC;
1190
1191 TRACE("(%lu, %p, %p)\n", dwThreadId, lpfn, lParam);
1192
1193 dwCount = Imm32AllocAndBuildHimcList(dwThreadId, &phList);
1194 if (!dwCount)
1195 return FALSE;
1196
1197 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex)
1198 {
1199 hIMC = phList[dwIndex];
1200 ret = (*lpfn)(hIMC, lParam);
1201 if (!ret)
1202 break;
1203 }
1204
1205 Imm32HeapFree(phList);
1206 return ret;
1207 }
1208
1209 /***********************************************************************
1210 * ImmSetActiveContext(IMM32.@)
1211 */
1212 BOOL WINAPI ImmSetActiveContext(HWND hWnd, HIMC hIMC, BOOL fActive)
1213 {
1214 PCLIENTIMC pClientImc;
1215 LPINPUTCONTEXTDX pIC;
1216 PIMEDPI pImeDpi;
1217 HKL hKL;
1218 BOOL fOpen = FALSE;
1219 DWORD dwConversion = 0, iShow = ISC_SHOWUIALL;
1220 HWND hwndDefIME;
1221
1222 TRACE("(%p, %p, %d)\n", hWnd, hIMC, fActive);
1223
1224 if (!Imm32IsImmMode())
1225 return FALSE;
1226
1227 pClientImc = ImmLockClientImc(hIMC);
1228
1229 if (!fActive)
1230 {
1231 if (pClientImc)
1232 pClientImc->dwFlags &= ~CLIENTIMC_UNKNOWN4;
1233 }
1234 else if (hIMC)
1235 {
1236 if (!pClientImc)
1237 return FALSE;
1238
1239 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1240 if (!pIC)
1241 {
1242 ImmUnlockClientImc(pClientImc);
1243 return FALSE;
1244 }
1245
1246 pIC->hWnd = hWnd;
1247 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN5;
1248
1249 if (pIC->dwUIFlags & 2)
1250 iShow = (ISC_SHOWUIGUIDELINE | ISC_SHOWUIALLCANDIDATEWINDOW);
1251
1252 fOpen = pIC->fOpen;
1253 dwConversion = pIC->fdwConversion;
1254
1255 ImmUnlockIMC(hIMC);
1256 }
1257 else
1258 {
1259 hIMC = Imm32GetContextEx(hWnd, TRUE);
1260 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1261 if (pIC)
1262 {
1263 pIC->hWnd = hWnd;
1264 ImmUnlockIMC(hIMC);
1265 }
1266 hIMC = NULL;
1267 }
1268
1269 hKL = GetKeyboardLayout(0);
1270
1271 if (Imm32IsCiceroMode() && !Imm32Is16BitMode())
1272 {
1273 Imm32CiceroSetActiveContext(hIMC, fActive, hWnd, hKL);
1274 hKL = GetKeyboardLayout(0);
1275 }
1276
1277 pImeDpi = ImmLockImeDpi(hKL);
1278 if (pImeDpi)
1279 {
1280 if (IS_IME_HKL(hKL))
1281 pImeDpi->ImeSetActiveContext(hIMC, fActive);
1282 ImmUnlockImeDpi(pImeDpi);
1283 }
1284
1285 if (IsWindow(hWnd))
1286 {
1287 SendMessageW(hWnd, WM_IME_SETCONTEXT, fActive, iShow);
1288 if (fActive)
1289 NtUserNotifyIMEStatus(hWnd, fOpen, dwConversion);
1290 }
1291 else if (!fActive)
1292 {
1293 hwndDefIME = ImmGetDefaultIMEWnd(NULL);
1294 if (hwndDefIME)
1295 SendMessageW(hwndDefIME, WM_IME_SETCONTEXT, 0, iShow);
1296 }
1297
1298 if (pClientImc)
1299 ImmUnlockClientImc(pClientImc);
1300
1301 return TRUE;
1302 }
1303
1304 /***********************************************************************
1305 * ImmSetActiveContextConsoleIME(IMM32.@)
1306 */
1307 BOOL WINAPI ImmSetActiveContextConsoleIME(HWND hwnd, BOOL fFlag)
1308 {
1309 HIMC hIMC;
1310 TRACE("(%p, %d)\n", hwnd, fFlag);
1311
1312 hIMC = ImmGetContext(hwnd);
1313 if (hIMC)
1314 return ImmSetActiveContext(hwnd, hIMC, fFlag);
1315 return FALSE;
1316 }
1317
1318 BOOL WINAPI User32InitializeImmEntryTable(DWORD);
1319
1320 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
1321 {
1322 HKL hKL;
1323 HIMC hIMC;
1324 PTEB pTeb;
1325
1326 TRACE("(%p, 0x%X, %p)\n", hinstDLL, fdwReason, lpReserved);
1327
1328 switch (fdwReason)
1329 {
1330 case DLL_PROCESS_ATTACH:
1331 if (!Imm32InitInstance(hinstDLL))
1332 {
1333 ERR("Imm32InitInstance failed\n");
1334 return FALSE;
1335 }
1336 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
1337 {
1338 ERR("User32InitializeImmEntryTable failed\n");
1339 return FALSE;
1340 }
1341 break;
1342
1343 case DLL_THREAD_ATTACH:
1344 break;
1345
1346 case DLL_THREAD_DETACH:
1347 if (!Imm32IsImmMode())
1348 return TRUE;
1349
1350 pTeb = NtCurrentTeb();
1351 if (pTeb->Win32ThreadInfo == NULL)
1352 return TRUE;
1353
1354 hKL = GetKeyboardLayout(0);
1355 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
1356 hIMC = (HIMC)NtUserGetThreadState(4);
1357 Imm32CleanupContext(hIMC, hKL, TRUE);
1358 break;
1359
1360 case DLL_PROCESS_DETACH:
1361 RtlDeleteCriticalSection(&g_csImeDpi);
1362 TRACE("imm32.dll is unloaded\n");
1363 break;
1364 }
1365
1366 return TRUE;
1367 }