69cd4281a553dee97fb7be1f42b74d3dd1d61be5
[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 typedef struct _tagImmHkl
480 {
481 struct list entry;
482 HKL hkl;
483 HMODULE hIME;
484 IMEINFO imeInfo;
485 WCHAR imeClassName[17]; /* 16 character max */
486 ULONG uSelected;
487 HWND UIWnd;
488
489 /* Function Pointers */
490 BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, const WCHAR *);
491 BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *);
492 BOOL (WINAPI *pImeDestroy)(UINT);
493 LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *);
494 BOOL (WINAPI *pImeSelect)(HIMC, BOOL);
495 BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL);
496 UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, DWORD *, UINT, HIMC);
497 BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD);
498 BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *);
499 BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *);
500 UINT (WINAPI *pImeEnumRegisterWord)(REGISTERWORDENUMPROCW, const WCHAR *, DWORD, const WCHAR *, void *);
501 BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void *, DWORD, const void *, DWORD);
502 DWORD (WINAPI *pImeConversionList)(HIMC, const WCHAR *, CANDIDATELIST *, DWORD, UINT);
503 BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *);
504 UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *);
505 DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD);
506 } ImmHkl;
507
508 typedef struct tagInputContextData
509 {
510 DWORD dwLock;
511 INPUTCONTEXT IMC;
512 DWORD threadID;
513
514 ImmHkl *immKbd;
515 UINT lastVK;
516 BOOL threadDefault;
517 DWORD magic;
518 } InputContextData;
519
520 #define WINE_IMC_VALID_MAGIC 0x56434D49
521
522 static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0};
523 static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
524 static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0};
525 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};
526
527 static inline BOOL is_himc_ime_unicode(const InputContextData *data)
528 {
529 return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE);
530 }
531
532 static InputContextData* get_imc_data(HIMC hIMC)
533 {
534 InputContextData *data = (InputContextData *)hIMC;
535
536 if (hIMC == NULL)
537 return NULL;
538
539 if(IsBadReadPtr(data, sizeof(InputContextData)) || data->magic != WINE_IMC_VALID_MAGIC)
540 {
541 SetLastError(ERROR_INVALID_HANDLE);
542 return NULL;
543 }
544 return data;
545 }
546
547 static VOID APIENTRY Imm32CiceroSetActiveContext(HIMC hIMC, BOOL fActive, HWND hWnd, HKL hKL)
548 {
549 FIXME("We have to do something\n");
550 }
551
552 /***********************************************************************
553 * ImmAssociateContext (IMM32.@)
554 */
555 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
556 {
557 PWND pWnd;
558 HWND hwndFocus;
559 DWORD dwValue;
560 HIMC hOldIMC;
561
562 TRACE("(%p, %p)\n", hWnd, hIMC);
563
564 if (!Imm32IsImmMode())
565 return NULL;
566
567 pWnd = ValidateHwndNoErr(hWnd);
568 if (!pWnd)
569 return NULL;
570
571 if (hIMC && Imm32IsCrossThreadAccess(hIMC))
572 return NULL;
573
574 hOldIMC = pWnd->hImc;
575 if (hOldIMC == hIMC)
576 return hIMC;
577
578 dwValue = NtUserAssociateInputContext(hWnd, hIMC, 0);
579 if (dwValue == 0)
580 return hOldIMC;
581 if (dwValue != 1)
582 return NULL;
583
584 hwndFocus = (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_FOCUS);
585 if (hwndFocus == hWnd)
586 {
587 ImmSetActiveContext(hWnd, hOldIMC, FALSE);
588 ImmSetActiveContext(hWnd, hIMC, TRUE);
589 }
590
591 return hOldIMC;
592 }
593
594 /***********************************************************************
595 * ImmAssociateContextEx (IMM32.@)
596 */
597 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
598 {
599 HWND hwndFocus;
600 PWND pFocusWnd;
601 HIMC hOldIMC = NULL;
602 DWORD dwValue;
603
604 TRACE("(%p, %p, 0x%lX)\n", hWnd, hIMC, dwFlags);
605
606 if (!Imm32IsImmMode())
607 return FALSE;
608
609 if (hIMC && !(dwFlags & IACE_DEFAULT) && Imm32IsCrossThreadAccess(hIMC))
610 return FALSE;
611
612 hwndFocus = (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_FOCUS);
613 pFocusWnd = ValidateHwndNoErr(hwndFocus);
614 if (pFocusWnd)
615 hOldIMC = pFocusWnd->hImc;
616
617 dwValue = NtUserAssociateInputContext(hWnd, hIMC, dwFlags);
618 switch (dwValue)
619 {
620 case 0:
621 return TRUE;
622
623 case 1:
624 pFocusWnd = ValidateHwndNoErr(hwndFocus);
625 if (pFocusWnd)
626 {
627 hIMC = pFocusWnd->hImc;
628 if (hIMC != hOldIMC)
629 {
630 ImmSetActiveContext(hwndFocus, hOldIMC, FALSE);
631 ImmSetActiveContext(hwndFocus, hIMC, TRUE);
632 }
633 }
634 return TRUE;
635
636 default:
637 return FALSE;
638 }
639 }
640
641 /***********************************************************************
642 * ImmCreateContext (IMM32.@)
643 */
644 HIMC WINAPI ImmCreateContext(void)
645 {
646 PCLIENTIMC pClientImc;
647 HIMC hIMC;
648
649 TRACE("()\n");
650
651 if (!Imm32IsImmMode())
652 return NULL;
653
654 pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
655 if (pClientImc == NULL)
656 return NULL;
657
658 hIMC = NtUserCreateInputContext(pClientImc);
659 if (hIMC == NULL)
660 {
661 Imm32HeapFree(pClientImc);
662 return NULL;
663 }
664
665 RtlInitializeCriticalSection(&pClientImc->cs);
666
667 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
668 pClientImc->unknown = NtUserGetThreadState(13);
669
670 return hIMC;
671 }
672
673 static VOID APIENTRY Imm32FreeImeStates(LPINPUTCONTEXTDX pIC)
674 {
675 PIME_STATE pState, pStateNext;
676 PIME_SUBSTATE pSubState, pSubStateNext;
677
678 pState = pIC->pState;
679 pIC->pState = NULL;
680 for (; pState; pState = pStateNext)
681 {
682 pStateNext = pState->pNext;
683 for (pSubState = pState->pSubState; pSubState; pSubState = pSubStateNext)
684 {
685 pSubStateNext = pSubState->pNext;
686 Imm32HeapFree(pSubState);
687 }
688 Imm32HeapFree(pState);
689 }
690 }
691
692 BOOL APIENTRY Imm32CleanupContext(HIMC hIMC, HKL hKL, BOOL bKeep)
693 {
694 PIMEDPI pImeDpi;
695 LPINPUTCONTEXTDX pIC;
696 PCLIENTIMC pClientImc;
697 PIMC pIMC;
698
699 if (!Imm32IsImmMode() || hIMC == NULL)
700 return FALSE;
701
702 pIMC = ValidateHandleNoErr(hIMC, TYPE_INPUTCONTEXT);
703 if (!pIMC || pIMC->head.pti != NtCurrentTeb()->Win32ThreadInfo)
704 return FALSE;
705
706 pClientImc = (PCLIENTIMC)pIMC->dwClientImcData;
707 if (!pClientImc)
708 return FALSE;
709
710 if (pClientImc->hInputContext == NULL)
711 {
712 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1;
713 ImmUnlockClientImc(pClientImc);
714 if (!bKeep)
715 return NtUserDestroyInputContext(hIMC);
716 return TRUE;
717 }
718
719 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
720 if (pIC == NULL)
721 {
722 ImmUnlockClientImc(pClientImc);
723 return FALSE;
724 }
725
726 FIXME("We have do something to do here\n");
727
728 if (pClientImc->hKL == hKL)
729 {
730 pImeDpi = ImmLockImeDpi(hKL);
731 if (pImeDpi != NULL)
732 {
733 if (IS_IME_HKL(hKL))
734 {
735 pImeDpi->ImeSelect(hIMC, FALSE);
736 }
737 else if (Imm32IsCiceroMode() && pImeDpi->CtfImeSelectEx)
738 {
739 pImeDpi->CtfImeSelectEx(hIMC, FALSE, hKL);
740 }
741 ImmUnlockImeDpi(pImeDpi);
742 }
743 pClientImc->hKL = NULL;
744 }
745
746 pIC->hPrivate = ImmDestroyIMCC(pIC->hPrivate);
747 pIC->hMsgBuf = ImmDestroyIMCC(pIC->hMsgBuf);
748 pIC->hGuideLine = ImmDestroyIMCC(pIC->hGuideLine);
749 pIC->hCandInfo = ImmDestroyIMCC(pIC->hCandInfo);
750 pIC->hCompStr = ImmDestroyIMCC(pIC->hCompStr);
751
752 Imm32FreeImeStates(pIC);
753
754 ImmUnlockIMC(hIMC);
755
756 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1;
757 ImmUnlockClientImc(pClientImc);
758
759 if (!bKeep)
760 return NtUserDestroyInputContext(hIMC);
761
762 return TRUE;
763 }
764
765 BOOL APIENTRY
766 Imm32InitContext(HIMC hIMC, LPINPUTCONTEXT pIC, PCLIENTIMC pClientImc, HKL hKL, BOOL fSelect)
767 {
768 DWORD dwIndex, cbPrivate;
769 PIMEDPI pImeDpi = NULL;
770 LPCOMPOSITIONSTRING pCS;
771 LPCANDIDATEINFO pCI;
772 LPGUIDELINE pGL;
773 /* NOTE: Windows does recursive call ImmLockIMC here but we don't do so. */
774
775 /* Create IC components */
776 pIC->hCompStr = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
777 pIC->hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
778 pIC->hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
779 pIC->hMsgBuf = ImmCreateIMCC(sizeof(UINT));
780 if (!pIC->hCompStr || !pIC->hCandInfo || !pIC->hGuideLine || !pIC->hMsgBuf)
781 goto Fail;
782
783 /* Initialize IC components */
784 pCS = ImmLockIMCC(pIC->hCompStr);
785 if (!pCS)
786 goto Fail;
787 pCS->dwSize = sizeof(COMPOSITIONSTRING);
788 ImmUnlockIMCC(pIC->hCompStr);
789
790 pCI = ImmLockIMCC(pIC->hCandInfo);
791 if (!pCI)
792 goto Fail;
793 pCI->dwSize = sizeof(CANDIDATEINFO);
794 ImmUnlockIMCC(pIC->hCandInfo);
795
796 pGL = ImmLockIMCC(pIC->hGuideLine);
797 if (!pGL)
798 goto Fail;
799 pGL->dwSize = sizeof(GUIDELINE);
800 ImmUnlockIMCC(pIC->hGuideLine);
801
802 pIC->dwNumMsgBuf = 0;
803 pIC->fOpen = FALSE;
804 pIC->fdwConversion = pIC->fdwSentence = 0;
805
806 for (dwIndex = 0; dwIndex < MAX_CANDIDATEFORM; ++dwIndex)
807 pIC->cfCandForm[dwIndex].dwIndex = IMM_INVALID_CANDFORM;
808
809 /* Get private data size */
810 pImeDpi = ImmLockImeDpi(hKL);
811 if (!pImeDpi)
812 {
813 cbPrivate = sizeof(DWORD);
814 }
815 else
816 {
817 /* Update CLIENTIMC */
818 pClientImc->uCodePage = pImeDpi->uCodePage;
819 if (ImeDpi_IsUnicode(pImeDpi))
820 pClientImc->dwFlags |= CLIENTIMC_WIDE;
821
822 cbPrivate = pImeDpi->ImeInfo.dwPrivateDataSize;
823 }
824
825 /* Create private data */
826 pIC->hPrivate = ImmCreateIMCC(cbPrivate);
827 if (!pIC->hPrivate)
828 goto Fail;
829
830 if (pImeDpi)
831 {
832 /* Select the IME */
833 if (fSelect)
834 {
835 if (IS_IME_HKL(hKL))
836 pImeDpi->ImeSelect(hIMC, TRUE);
837 else if (Imm32IsCiceroMode() && !Imm32Is16BitMode() && pImeDpi->CtfImeSelectEx)
838 pImeDpi->CtfImeSelectEx(hIMC, TRUE, hKL);
839 }
840
841 /* Set HKL */
842 pClientImc->hKL = hKL;
843
844 ImmUnlockImeDpi(pImeDpi);
845 }
846
847 return TRUE;
848
849 Fail:
850 if (pImeDpi)
851 ImmUnlockImeDpi(pImeDpi);
852
853 pIC->hMsgBuf = ImmDestroyIMCC(pIC->hMsgBuf);
854 pIC->hGuideLine = ImmDestroyIMCC(pIC->hGuideLine);
855 pIC->hCandInfo = ImmDestroyIMCC(pIC->hCandInfo);
856 pIC->hCompStr = ImmDestroyIMCC(pIC->hCompStr);
857 return FALSE;
858 }
859
860 LPINPUTCONTEXT APIENTRY Imm32LockIMCEx(HIMC hIMC, BOOL fSelect)
861 {
862 HANDLE hIC;
863 LPINPUTCONTEXT pIC = NULL;
864 PCLIENTIMC pClientImc;
865 WORD Word;
866 DWORD dwThreadId;
867 HKL hKL, hNewKL;
868 PIMEDPI pImeDpi = NULL;
869 BOOL bInited;
870
871 pClientImc = ImmLockClientImc(hIMC);
872 if (!pClientImc)
873 return NULL;
874
875 RtlEnterCriticalSection(&pClientImc->cs);
876
877 if (!pClientImc->hInputContext)
878 {
879 dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, 1);
880
881 if (dwThreadId == GetCurrentThreadId() && Imm32IsCiceroMode() && !Imm32Is16BitMode())
882 {
883 hKL = GetKeyboardLayout(0);
884 Word = LOWORD(hKL);
885 hNewKL = (HKL)(DWORD_PTR)MAKELONG(Word, Word);
886
887 pImeDpi = ImmLockOrLoadImeDpi(hNewKL);
888 if (pImeDpi)
889 {
890 FIXME("We have to do something here\n");
891 }
892 }
893
894 if (!NtUserQueryInputContext(hIMC, 2))
895 {
896 RtlLeaveCriticalSection(&pClientImc->cs);
897 goto Quit;
898 }
899
900 hIC = LocalAlloc(LHND, sizeof(INPUTCONTEXTDX));
901 if (!hIC)
902 {
903 RtlLeaveCriticalSection(&pClientImc->cs);
904 goto Quit;
905 }
906 pClientImc->hInputContext = hIC;
907
908 pIC = LocalLock(pClientImc->hInputContext);
909 if (!pIC)
910 {
911 pClientImc->hInputContext = LocalFree(pClientImc->hInputContext);
912 RtlLeaveCriticalSection(&pClientImc->cs);
913 goto Quit;
914 }
915
916 hKL = GetKeyboardLayout(dwThreadId);
917 // bInited = Imm32InitContext(hIMC, hKL, fSelect);
918 bInited = Imm32InitContext(hIMC, pIC, pClientImc, hKL, fSelect);
919 LocalUnlock(pClientImc->hInputContext);
920
921 if (!bInited)
922 {
923 pIC = NULL;
924 pClientImc->hInputContext = LocalFree(pClientImc->hInputContext);
925 RtlLeaveCriticalSection(&pClientImc->cs);
926 goto Quit;
927 }
928 }
929
930 FIXME("We have to do something here\n");
931
932 RtlLeaveCriticalSection(&pClientImc->cs);
933 pIC = LocalLock(pClientImc->hInputContext);
934 InterlockedIncrement(&pClientImc->cLockObj);
935
936 Quit:
937 ImmUnlockClientImc(pClientImc);
938 return pIC;
939 }
940
941 /***********************************************************************
942 * ImmDestroyContext (IMM32.@)
943 */
944 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
945 {
946 HKL hKL;
947
948 TRACE("(%p)\n", hIMC);
949
950 if (!Imm32IsImmMode())
951 return FALSE;
952
953 if (Imm32IsCrossThreadAccess(hIMC))
954 return FALSE;
955
956 hKL = GetKeyboardLayout(0);
957 return Imm32CleanupContext(hIMC, hKL, FALSE);
958 }
959
960 /***********************************************************************
961 * ImmLockClientImc (IMM32.@)
962 */
963 PCLIENTIMC WINAPI ImmLockClientImc(HIMC hImc)
964 {
965 PIMC pIMC;
966 PCLIENTIMC pClientImc;
967
968 TRACE("(%p)\n", hImc);
969
970 if (hImc == NULL)
971 return NULL;
972
973 pIMC = ValidateHandleNoErr(hImc, TYPE_INPUTCONTEXT);
974 if (pIMC == NULL || !Imm32CheckImcProcess(pIMC))
975 return NULL;
976
977 pClientImc = (PCLIENTIMC)pIMC->dwClientImcData;
978 if (!pClientImc)
979 {
980 pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
981 if (!pClientImc)
982 return NULL;
983
984 RtlInitializeCriticalSection(&pClientImc->cs);
985
986 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
987 pClientImc->unknown = NtUserGetThreadState(13);
988
989 if (!NtUserUpdateInputContext(hImc, 0, pClientImc))
990 {
991 Imm32HeapFree(pClientImc);
992 return NULL;
993 }
994
995 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN2;
996 }
997 else
998 {
999 if (pClientImc->dwFlags & CLIENTIMC_UNKNOWN1)
1000 return NULL;
1001 }
1002
1003 InterlockedIncrement(&pClientImc->cLockObj);
1004 return pClientImc;
1005 }
1006
1007 /***********************************************************************
1008 * ImmUnlockClientImc (IMM32.@)
1009 */
1010 VOID WINAPI ImmUnlockClientImc(PCLIENTIMC pClientImc)
1011 {
1012 LONG cLocks;
1013 HANDLE hInputContext;
1014
1015 TRACE("(%p)\n", pClientImc);
1016
1017 cLocks = InterlockedDecrement(&pClientImc->cLockObj);
1018 if (cLocks != 0 || !(pClientImc->dwFlags & CLIENTIMC_UNKNOWN1))
1019 return;
1020
1021 hInputContext = pClientImc->hInputContext;
1022 if (hInputContext)
1023 LocalFree(hInputContext);
1024
1025 RtlDeleteCriticalSection(&pClientImc->cs);
1026 Imm32HeapFree(pClientImc);
1027 }
1028
1029 static HIMC APIENTRY Imm32GetContextEx(HWND hWnd, DWORD dwContextFlags)
1030 {
1031 HIMC hIMC;
1032 PCLIENTIMC pClientImc;
1033 PWND pWnd;
1034
1035 if (!Imm32IsImmMode())
1036 return NULL;
1037
1038 if (!hWnd)
1039 {
1040 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
1041 hIMC = (HIMC)NtUserGetThreadState(4);
1042 goto Quit;
1043 }
1044
1045 pWnd = ValidateHwndNoErr(hWnd);
1046 if (!pWnd || Imm32IsCrossProcessAccess(hWnd))
1047 return NULL;
1048
1049 hIMC = pWnd->hImc;
1050 if (!hIMC && (dwContextFlags & 1))
1051 hIMC = (HIMC)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_ICONTEXT);
1052
1053 Quit:
1054 pClientImc = ImmLockClientImc(hIMC);
1055 if (pClientImc == NULL)
1056 return NULL;
1057 if ((dwContextFlags & 2) && (pClientImc->dwFlags & CLIENTIMC_UNKNOWN3))
1058 hIMC = NULL;
1059 ImmUnlockClientImc(pClientImc);
1060 return hIMC;
1061 }
1062
1063
1064 /* Helpers for the GetCompositionString functions */
1065
1066 /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
1067 length is always in bytes. */
1068 static INT
1069 CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst,
1070 INT dst_len, BOOL unicode)
1071 {
1072 int char_size = unicode ? sizeof(WCHAR) : sizeof(char);
1073 INT ret;
1074
1075 if (is_himc_ime_unicode(data) ^ unicode)
1076 {
1077 if (unicode)
1078 ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR));
1079 else
1080 ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL);
1081 ret *= char_size;
1082 }
1083 else
1084 {
1085 if (dst_len)
1086 {
1087 ret = min(src_len * char_size, dst_len);
1088 memcpy(dst, src, ret);
1089 }
1090 else
1091 ret = src_len * char_size;
1092 }
1093
1094 return ret;
1095 }
1096
1097 /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
1098 passed mode. String length is in characters, attributes are in byte arrays. */
1099 static INT
1100 CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string,
1101 INT str_len, BYTE *dst, INT dst_len, BOOL unicode)
1102 {
1103 union
1104 {
1105 const void *str;
1106 const WCHAR *strW;
1107 const char *strA;
1108 } string;
1109 INT rc;
1110
1111 string.str = comp_string;
1112
1113 if (is_himc_ime_unicode(data) && !unicode)
1114 {
1115 rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL);
1116 if (dst_len)
1117 {
1118 int i, j = 0, k = 0;
1119
1120 if (rc < dst_len)
1121 dst_len = rc;
1122 for (i = 0; i < str_len; ++i)
1123 {
1124 int len;
1125
1126 len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL);
1127 for (; len > 0; --len)
1128 {
1129 dst[j++] = src[k];
1130
1131 if (j >= dst_len)
1132 goto end;
1133 }
1134 ++k;
1135 }
1136 end:
1137 rc = j;
1138 }
1139 }
1140 else if (!is_himc_ime_unicode(data) && unicode)
1141 {
1142 rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0);
1143 if (dst_len)
1144 {
1145 int i, j = 0;
1146
1147 if (rc < dst_len)
1148 dst_len = rc;
1149 for (i = 0; i < str_len; ++i)
1150 {
1151 if (IsDBCSLeadByte(string.strA[i]))
1152 continue;
1153
1154 dst[j++] = src[i];
1155
1156 if (j >= dst_len)
1157 break;
1158 }
1159 rc = j;
1160 }
1161 }
1162 else
1163 {
1164 memcpy(dst, src, min(src_len, dst_len));
1165 rc = src_len;
1166 }
1167
1168 return rc;
1169 }
1170
1171 static INT
1172 CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource,
1173 LPBYTE target, INT tlen, BOOL unicode )
1174 {
1175 INT rc;
1176
1177 if (is_himc_ime_unicode(data) && !unicode)
1178 {
1179 if (tlen)
1180 {
1181 int i;
1182
1183 if (slen < tlen)
1184 tlen = slen;
1185 tlen /= sizeof (DWORD);
1186 for (i = 0; i < tlen; ++i)
1187 {
1188 ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
1189 ((DWORD *)source)[i],
1190 NULL, 0,
1191 NULL, NULL);
1192 }
1193 rc = sizeof (DWORD) * i;
1194 }
1195 else
1196 rc = slen;
1197 }
1198 else if (!is_himc_ime_unicode(data) && unicode)
1199 {
1200 if (tlen)
1201 {
1202 int i;
1203
1204 if (slen < tlen)
1205 tlen = slen;
1206 tlen /= sizeof (DWORD);
1207 for (i = 0; i < tlen; ++i)
1208 {
1209 ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
1210 ((DWORD *)source)[i],
1211 NULL, 0);
1212 }
1213 rc = sizeof (DWORD) * i;
1214 }
1215 else
1216 rc = slen;
1217 }
1218 else
1219 {
1220 memcpy( target, source, min(slen,tlen));
1221 rc = slen;
1222 }
1223
1224 return rc;
1225 }
1226
1227 static INT
1228 CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode)
1229 {
1230 int rc;
1231
1232 if (is_himc_ime_unicode(data) && !unicode)
1233 {
1234 rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
1235 }
1236 else if (!is_himc_ime_unicode(data) && unicode)
1237 {
1238 rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
1239 }
1240 else
1241 rc = offset;
1242
1243 return rc;
1244 }
1245
1246 static LONG
1247 ImmGetCompositionStringT(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
1248 DWORD dwBufLen, BOOL unicode)
1249 {
1250 LONG rc = 0;
1251 InputContextData *data = get_imc_data(hIMC);
1252 LPCOMPOSITIONSTRING compstr;
1253 LPBYTE compdata;
1254
1255 TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
1256
1257 if (!data)
1258 return FALSE;
1259
1260 if (!data->IMC.hCompStr)
1261 return FALSE;
1262
1263 compdata = ImmLockIMCC(data->IMC.hCompStr);
1264 compstr = (LPCOMPOSITIONSTRING)compdata;
1265
1266 switch (dwIndex)
1267 {
1268 case GCS_RESULTSTR:
1269 TRACE("GCS_RESULTSTR\n");
1270 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
1271 break;
1272 case GCS_COMPSTR:
1273 TRACE("GCS_COMPSTR\n");
1274 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
1275 break;
1276 case GCS_COMPATTR:
1277 TRACE("GCS_COMPATTR\n");
1278 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
1279 compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
1280 lpBuf, dwBufLen, unicode);
1281 break;
1282 case GCS_COMPCLAUSE:
1283 TRACE("GCS_COMPCLAUSE\n");
1284 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
1285 compdata + compstr->dwCompStrOffset,
1286 lpBuf, dwBufLen, unicode);
1287 break;
1288 case GCS_RESULTCLAUSE:
1289 TRACE("GCS_RESULTCLAUSE\n");
1290 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
1291 compdata + compstr->dwResultStrOffset,
1292 lpBuf, dwBufLen, unicode);
1293 break;
1294 case GCS_RESULTREADSTR:
1295 TRACE("GCS_RESULTREADSTR\n");
1296 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
1297 break;
1298 case GCS_RESULTREADCLAUSE:
1299 TRACE("GCS_RESULTREADCLAUSE\n");
1300 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
1301 compdata + compstr->dwResultStrOffset,
1302 lpBuf, dwBufLen, unicode);
1303 break;
1304 case GCS_COMPREADSTR:
1305 TRACE("GCS_COMPREADSTR\n");
1306 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
1307 break;
1308 case GCS_COMPREADATTR:
1309 TRACE("GCS_COMPREADATTR\n");
1310 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
1311 compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
1312 lpBuf, dwBufLen, unicode);
1313 break;
1314 case GCS_COMPREADCLAUSE:
1315 TRACE("GCS_COMPREADCLAUSE\n");
1316 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
1317 compdata + compstr->dwCompStrOffset,
1318 lpBuf, dwBufLen, unicode);
1319 break;
1320 case GCS_CURSORPOS:
1321 TRACE("GCS_CURSORPOS\n");
1322 rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
1323 break;
1324 case GCS_DELTASTART:
1325 TRACE("GCS_DELTASTART\n");
1326 rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
1327 break;
1328 default:
1329 FIXME("Unhandled index 0x%x\n",dwIndex);
1330 break;
1331 }
1332
1333 ImmUnlockIMCC(data->IMC.hCompStr);
1334
1335 return rc;
1336 }
1337
1338 /***********************************************************************
1339 * ImmGetCompositionStringA (IMM32.@)
1340 */
1341 LONG WINAPI ImmGetCompositionStringA(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
1342 {
1343 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
1344 }
1345
1346 /***********************************************************************
1347 * ImmGetCompositionStringW (IMM32.@)
1348 */
1349 LONG WINAPI ImmGetCompositionStringW(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
1350 {
1351 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
1352 }
1353
1354 /***********************************************************************
1355 * ImmGetContext (IMM32.@)
1356 */
1357 HIMC WINAPI ImmGetContext(HWND hWnd)
1358 {
1359 TRACE("(%p)\n", hWnd);
1360 if (hWnd == NULL)
1361 return NULL;
1362 return Imm32GetContextEx(hWnd, 2);
1363 }
1364
1365 /***********************************************************************
1366 * CtfImmIsCiceroEnabled (IMM32.@)
1367 */
1368 BOOL WINAPI CtfImmIsCiceroEnabled(VOID)
1369 {
1370 return Imm32IsCiceroMode();
1371 }
1372
1373 /***********************************************************************
1374 * ImmInstallIMEA (IMM32.@)
1375 */
1376 HKL WINAPI ImmInstallIMEA(LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
1377 {
1378 HKL hKL = NULL;
1379 LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL;
1380
1381 TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText));
1382
1383 pszFileNameW = Imm32WideFromAnsi(lpszIMEFileName);
1384 if (pszFileNameW == NULL)
1385 goto Quit;
1386
1387 pszLayoutTextW = Imm32WideFromAnsi(lpszLayoutText);
1388 if (pszLayoutTextW == NULL)
1389 goto Quit;
1390
1391 hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW);
1392
1393 Quit:
1394 Imm32HeapFree(pszFileNameW);
1395 Imm32HeapFree(pszLayoutTextW);
1396 return hKL;
1397 }
1398
1399 /***********************************************************************
1400 * ImmInstallIMEW (IMM32.@)
1401 */
1402 HKL WINAPI ImmInstallIMEW(LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
1403 {
1404 INT lcid = GetUserDefaultLCID();
1405 INT count;
1406 HKL hkl;
1407 DWORD rc;
1408 HKEY hkey;
1409 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
1410
1411 TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
1412 debugstr_w(lpszLayoutText));
1413
1414 /* Start with 2. e001 will be blank and so default to the wine internal IME */
1415 count = 2;
1416
1417 while (count < 0xfff)
1418 {
1419 DWORD disposition = 0;
1420
1421 hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
1422 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
1423
1424 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
1425 if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
1426 break;
1427 else if (rc == ERROR_SUCCESS)
1428 RegCloseKey(hkey);
1429
1430 count++;
1431 }
1432
1433 if (count == 0xfff)
1434 {
1435 WARN("Unable to find slot to install IME\n");
1436 return 0;
1437 }
1438
1439 if (rc == ERROR_SUCCESS)
1440 {
1441 rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName,
1442 (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
1443 if (rc == ERROR_SUCCESS)
1444 rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText,
1445 (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
1446 RegCloseKey(hkey);
1447 return hkl;
1448 }
1449 else
1450 {
1451 WARN("Unable to set IME registry values\n");
1452 return 0;
1453 }
1454 }
1455
1456 /***********************************************************************
1457 * ImmLockIMC(IMM32.@)
1458 *
1459 * NOTE: This is not ImmLockIMCC. Don't confuse.
1460 */
1461 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
1462 {
1463 TRACE("(%p)\n", hIMC);
1464 return Imm32LockIMCEx(hIMC, TRUE);
1465 }
1466
1467 /***********************************************************************
1468 * ImmUnlockIMC(IMM32.@)
1469 */
1470 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
1471 {
1472 PCLIENTIMC pClientImc;
1473
1474 pClientImc = ImmLockClientImc(hIMC);
1475 if (pClientImc == NULL)
1476 return FALSE;
1477
1478 if (pClientImc->hInputContext)
1479 LocalUnlock(pClientImc->hInputContext);
1480
1481 InterlockedDecrement(&pClientImc->cLockObj);
1482 ImmUnlockClientImc(pClientImc);
1483 return TRUE;
1484 }
1485
1486 /***********************************************************************
1487 * ImmReleaseContext (IMM32.@)
1488 */
1489 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
1490 {
1491 TRACE("(%p, %p)\n", hWnd, hIMC);
1492 UNREFERENCED_PARAMETER(hWnd);
1493 UNREFERENCED_PARAMETER(hIMC);
1494 return TRUE; // Do nothing. This is correct.
1495 }
1496
1497 /***********************************************************************
1498 * ImmSetCompositionStringA (IMM32.@)
1499 */
1500 BOOL WINAPI
1501 ImmSetCompositionStringA(HIMC hIMC, DWORD dwIndex,
1502 LPCVOID lpComp, DWORD dwCompLen,
1503 LPCVOID lpRead, DWORD dwReadLen)
1504 {
1505 DWORD comp_len;
1506 DWORD read_len;
1507 WCHAR *CompBuffer = NULL;
1508 WCHAR *ReadBuffer = NULL;
1509 BOOL rc;
1510 InputContextData *data = get_imc_data(hIMC);
1511
1512 TRACE("(%p, %d, %p, %d, %p, %d):\n",
1513 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1514
1515 if (!data)
1516 return FALSE;
1517
1518 if (!(dwIndex == SCS_SETSTR ||
1519 dwIndex == SCS_CHANGEATTR ||
1520 dwIndex == SCS_CHANGECLAUSE ||
1521 dwIndex == SCS_SETRECONVERTSTRING ||
1522 dwIndex == SCS_QUERYRECONVERTSTRING))
1523 return FALSE;
1524
1525 if (!is_himc_ime_unicode(data))
1526 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
1527 dwCompLen, lpRead, dwReadLen);
1528
1529 comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
1530 if (comp_len)
1531 {
1532 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
1533 MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
1534 }
1535
1536 read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
1537 if (read_len)
1538 {
1539 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
1540 MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
1541 }
1542
1543 rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
1544 ReadBuffer, read_len);
1545
1546 HeapFree(GetProcessHeap(), 0, CompBuffer);
1547 HeapFree(GetProcessHeap(), 0, ReadBuffer);
1548
1549 return rc;
1550 }
1551
1552 /***********************************************************************
1553 * ImmSetCompositionStringW (IMM32.@)
1554 */
1555 BOOL WINAPI
1556 ImmSetCompositionStringW(HIMC hIMC, DWORD dwIndex,
1557 LPCVOID lpComp, DWORD dwCompLen,
1558 LPCVOID lpRead, DWORD dwReadLen)
1559 {
1560 DWORD comp_len;
1561 DWORD read_len;
1562 CHAR *CompBuffer = NULL;
1563 CHAR *ReadBuffer = NULL;
1564 BOOL rc;
1565 InputContextData *data = get_imc_data(hIMC);
1566
1567 TRACE("(%p, %d, %p, %d, %p, %d):\n",
1568 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1569
1570 if (!data)
1571 return FALSE;
1572
1573 if (!(dwIndex == SCS_SETSTR ||
1574 dwIndex == SCS_CHANGEATTR ||
1575 dwIndex == SCS_CHANGECLAUSE ||
1576 dwIndex == SCS_SETRECONVERTSTRING ||
1577 dwIndex == SCS_QUERYRECONVERTSTRING))
1578 return FALSE;
1579
1580 if (is_himc_ime_unicode(data))
1581 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
1582 dwCompLen, lpRead, dwReadLen);
1583
1584 comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
1585 NULL);
1586 if (comp_len)
1587 {
1588 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
1589 WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
1590 NULL, NULL);
1591 }
1592
1593 read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
1594 NULL);
1595 if (read_len)
1596 {
1597 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
1598 WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
1599 NULL, NULL);
1600 }
1601
1602 rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
1603 ReadBuffer, read_len);
1604
1605 HeapFree(GetProcessHeap(), 0, CompBuffer);
1606 HeapFree(GetProcessHeap(), 0, ReadBuffer);
1607
1608 return rc;
1609 }
1610
1611 /***********************************************************************
1612 * ImmCreateSoftKeyboard(IMM32.@)
1613 */
1614 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
1615 {
1616 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
1617 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1618 return 0;
1619 }
1620
1621 /***********************************************************************
1622 * ImmDestroySoftKeyboard(IMM32.@)
1623 */
1624 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
1625 {
1626 TRACE("(%p)\n", hSoftWnd);
1627 return DestroyWindow(hSoftWnd);
1628 }
1629
1630 /***********************************************************************
1631 * ImmShowSoftKeyboard(IMM32.@)
1632 */
1633 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
1634 {
1635 TRACE("(%p, %d)\n", hSoftWnd, nCmdShow);
1636 if (hSoftWnd)
1637 return ShowWindow(hSoftWnd, nCmdShow);
1638 return FALSE;
1639 }
1640
1641 /***********************************************************************
1642 * ImmDisableTextFrameService(IMM32.@)
1643 */
1644 BOOL WINAPI ImmDisableTextFrameService(DWORD dwThreadId)
1645 {
1646 FIXME("Stub\n");
1647 return FALSE;
1648 }
1649
1650 /***********************************************************************
1651 * ImmEnumInputContext(IMM32.@)
1652 */
1653 BOOL WINAPI ImmEnumInputContext(DWORD dwThreadId, IMCENUMPROC lpfn, LPARAM lParam)
1654 {
1655 HIMC *phList;
1656 DWORD dwIndex, dwCount;
1657 BOOL ret = TRUE;
1658 HIMC hIMC;
1659
1660 TRACE("(%lu, %p, %p)\n", dwThreadId, lpfn, lParam);
1661
1662 dwCount = Imm32AllocAndBuildHimcList(dwThreadId, &phList);
1663 if (!dwCount)
1664 return FALSE;
1665
1666 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex)
1667 {
1668 hIMC = phList[dwIndex];
1669 ret = (*lpfn)(hIMC, lParam);
1670 if (!ret)
1671 break;
1672 }
1673
1674 Imm32HeapFree(phList);
1675 return ret;
1676 }
1677
1678 /***********************************************************************
1679 * ImmSetActiveContext(IMM32.@)
1680 */
1681 BOOL WINAPI ImmSetActiveContext(HWND hWnd, HIMC hIMC, BOOL fActive)
1682 {
1683 PCLIENTIMC pClientImc;
1684 LPINPUTCONTEXTDX pIC;
1685 PIMEDPI pImeDpi;
1686 HKL hKL;
1687 BOOL fOpen = FALSE;
1688 DWORD dwConversion = 0, iShow = ISC_SHOWUIALL;
1689 HWND hwndDefIME;
1690
1691 TRACE("(%p, %p, %d)\n", hWnd, hIMC, fActive);
1692
1693 if (!Imm32IsImmMode())
1694 return FALSE;
1695
1696 pClientImc = ImmLockClientImc(hIMC);
1697
1698 if (!fActive)
1699 {
1700 if (pClientImc)
1701 pClientImc->dwFlags &= ~CLIENTIMC_UNKNOWN4;
1702 }
1703 else if (hIMC)
1704 {
1705 if (!pClientImc)
1706 return FALSE;
1707
1708 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1709 if (!pIC)
1710 {
1711 ImmUnlockClientImc(pClientImc);
1712 return FALSE;
1713 }
1714
1715 pIC->hWnd = hWnd;
1716 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN5;
1717
1718 if (pIC->dwUIFlags & 2)
1719 iShow = (ISC_SHOWUIGUIDELINE | ISC_SHOWUIALLCANDIDATEWINDOW);
1720
1721 fOpen = pIC->fOpen;
1722 dwConversion = pIC->fdwConversion;
1723
1724 ImmUnlockIMC(hIMC);
1725 }
1726 else
1727 {
1728 hIMC = Imm32GetContextEx(hWnd, TRUE);
1729 pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1730 if (pIC)
1731 {
1732 pIC->hWnd = hWnd;
1733 ImmUnlockIMC(hIMC);
1734 }
1735 hIMC = NULL;
1736 }
1737
1738 hKL = GetKeyboardLayout(0);
1739
1740 if (Imm32IsCiceroMode() && !Imm32Is16BitMode())
1741 {
1742 Imm32CiceroSetActiveContext(hIMC, fActive, hWnd, hKL);
1743 hKL = GetKeyboardLayout(0);
1744 }
1745
1746 pImeDpi = ImmLockImeDpi(hKL);
1747 if (pImeDpi)
1748 {
1749 if (IS_IME_HKL(hKL))
1750 pImeDpi->ImeSetActiveContext(hIMC, fActive);
1751 ImmUnlockImeDpi(pImeDpi);
1752 }
1753
1754 if (IsWindow(hWnd))
1755 {
1756 SendMessageW(hWnd, WM_IME_SETCONTEXT, fActive, iShow);
1757 if (fActive)
1758 NtUserNotifyIMEStatus(hWnd, fOpen, dwConversion);
1759 }
1760 else if (!fActive)
1761 {
1762 hwndDefIME = ImmGetDefaultIMEWnd(NULL);
1763 if (hwndDefIME)
1764 SendMessageW(hwndDefIME, WM_IME_SETCONTEXT, 0, iShow);
1765 }
1766
1767 if (pClientImc)
1768 ImmUnlockClientImc(pClientImc);
1769
1770 return TRUE;
1771 }
1772
1773 /***********************************************************************
1774 * ImmSetActiveContextConsoleIME(IMM32.@)
1775 */
1776 BOOL WINAPI ImmSetActiveContextConsoleIME(HWND hwnd, BOOL fFlag)
1777 {
1778 HIMC hIMC;
1779 TRACE("(%p, %d)\n", hwnd, fFlag);
1780
1781 hIMC = ImmGetContext(hwnd);
1782 if (hIMC)
1783 return ImmSetActiveContext(hwnd, hIMC, fFlag);
1784 return FALSE;
1785 }
1786
1787 BOOL WINAPI User32InitializeImmEntryTable(DWORD);
1788
1789 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
1790 {
1791 HKL hKL;
1792 HIMC hIMC;
1793 PTEB pTeb;
1794
1795 TRACE("(%p, 0x%X, %p)\n", hinstDLL, fdwReason, lpReserved);
1796
1797 switch (fdwReason)
1798 {
1799 case DLL_PROCESS_ATTACH:
1800 if (!Imm32InitInstance(hinstDLL))
1801 {
1802 ERR("Imm32InitInstance failed\n");
1803 return FALSE;
1804 }
1805 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
1806 {
1807 ERR("User32InitializeImmEntryTable failed\n");
1808 return FALSE;
1809 }
1810 break;
1811
1812 case DLL_THREAD_ATTACH:
1813 break;
1814
1815 case DLL_THREAD_DETACH:
1816 if (!Imm32IsImmMode())
1817 return TRUE;
1818
1819 pTeb = NtCurrentTeb();
1820 if (pTeb->Win32ThreadInfo == NULL)
1821 return TRUE;
1822
1823 hKL = GetKeyboardLayout(0);
1824 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
1825 hIMC = (HIMC)NtUserGetThreadState(4);
1826 Imm32CleanupContext(hIMC, hKL, TRUE);
1827 break;
1828
1829 case DLL_PROCESS_DETACH:
1830 RtlDeleteCriticalSection(&g_csImeDpi);
1831 TRACE("imm32.dll is unloaded\n");
1832 break;
1833 }
1834
1835 return TRUE;
1836 }