xref: /reactos/dll/win32/imm32/ime.c (revision 08d10098)
1 /*
2  * PROJECT:     ReactOS IMM32
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Implementing IME manipulation of IMM32
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-2022 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
10  */
11 
12 #include "precomp.h"
13 
14 WINE_DEFAULT_DEBUG_CHANNEL(imm);
15 
16 RTL_CRITICAL_SECTION gcsImeDpi; // Win: gcsImeDpi
17 PIMEDPI gpImeDpiList = NULL; // Win: gpImeDpi
18 
19 // Win: ImmGetImeDpi
20 PIMEDPI APIENTRY Imm32FindImeDpi(HKL hKL)
21 {
22     PIMEDPI pImeDpi;
23 
24     RtlEnterCriticalSection(&gcsImeDpi);
25     for (pImeDpi = gpImeDpiList; pImeDpi != NULL; pImeDpi = pImeDpi->pNext)
26     {
27         if (pImeDpi->hKL == hKL)
28             break;
29     }
30     RtlLeaveCriticalSection(&gcsImeDpi);
31 
32     return pImeDpi;
33 }
34 
35 // Win: UnloadIME
36 VOID APIENTRY Imm32FreeIME(PIMEDPI pImeDpi, BOOL bDestroy)
37 {
38     if (pImeDpi->hInst == NULL)
39         return;
40     if (bDestroy)
41         pImeDpi->ImeDestroy(0);
42     FreeLibrary(pImeDpi->hInst);
43     pImeDpi->hInst = NULL;
44 }
45 
46 // Win: InquireIme
47 BOOL APIENTRY Imm32InquireIme(PIMEDPI pImeDpi)
48 {
49     WCHAR szUIClass[64];
50     WNDCLASSW wcW;
51     DWORD dwSysInfoFlags = 0;
52     LPIMEINFO pImeInfo = &pImeDpi->ImeInfo;
53 
54     if (NtUserGetThreadState(THREADSTATE_ISWINLOGON2))
55         dwSysInfoFlags |= IME_SYSINFO_WINLOGON;
56 
57     if (IS_IME_HKL(pImeDpi->hKL))
58     {
59         if (!pImeDpi->ImeInquire(pImeInfo, szUIClass, dwSysInfoFlags))
60             return FALSE;
61     }
62     else if (Imm32IsCiceroMode() && pImeDpi->CtfImeInquireExW)
63     {
64         if (!pImeDpi->CtfImeInquireExW(pImeInfo, szUIClass, dwSysInfoFlags, pImeDpi->hKL))
65             return FALSE;
66     }
67     else
68     {
69         return FALSE;
70     }
71 
72     szUIClass[_countof(szUIClass) - 1] = 0;
73 
74     if (pImeInfo->dwPrivateDataSize == 0)
75         pImeInfo->dwPrivateDataSize = sizeof(DWORD);
76 
77 #define VALID_IME_PROP (IME_PROP_AT_CARET              | \
78                         IME_PROP_SPECIAL_UI            | \
79                         IME_PROP_CANDLIST_START_FROM_1 | \
80                         IME_PROP_UNICODE               | \
81                         IME_PROP_COMPLETE_ON_UNSELECT  | \
82                         IME_PROP_END_UNLOAD            | \
83                         IME_PROP_KBD_CHAR_FIRST        | \
84                         IME_PROP_IGNORE_UPKEYS         | \
85                         IME_PROP_NEED_ALTKEY           | \
86                         IME_PROP_NO_KEYS_ON_CLOSE      | \
87                         IME_PROP_ACCEPT_WIDE_VKEY)
88 #define VALID_CMODE_CAPS (IME_CMODE_ALPHANUMERIC | \
89                           IME_CMODE_NATIVE       | \
90                           IME_CMODE_KATAKANA     | \
91                           IME_CMODE_LANGUAGE     | \
92                           IME_CMODE_FULLSHAPE    | \
93                           IME_CMODE_ROMAN        | \
94                           IME_CMODE_CHARCODE     | \
95                           IME_CMODE_HANJACONVERT | \
96                           IME_CMODE_SOFTKBD      | \
97                           IME_CMODE_NOCONVERSION | \
98                           IME_CMODE_EUDC         | \
99                           IME_CMODE_SYMBOL       | \
100                           IME_CMODE_FIXED)
101 #define VALID_SMODE_CAPS (IME_SMODE_NONE          | \
102                           IME_SMODE_PLAURALCLAUSE | \
103                           IME_SMODE_SINGLECONVERT | \
104                           IME_SMODE_AUTOMATIC     | \
105                           IME_SMODE_PHRASEPREDICT | \
106                           IME_SMODE_CONVERSATION)
107 #define VALID_UI_CAPS (UI_CAP_2700    | \
108                        UI_CAP_ROT90   | \
109                        UI_CAP_ROTANY  | \
110                        UI_CAP_SOFTKBD)
111 #define VALID_SCS_CAPS (SCS_CAP_COMPSTR            | \
112                         SCS_CAP_MAKEREAD           | \
113                         SCS_CAP_SETRECONVERTSTRING)
114 #define VALID_SELECT_CAPS (SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE)
115 
116     if (pImeInfo->fdwProperty & ~VALID_IME_PROP)
117         return FALSE;
118     if (pImeInfo->fdwConversionCaps & ~VALID_CMODE_CAPS)
119         return FALSE;
120     if (pImeInfo->fdwSentenceCaps & ~VALID_SMODE_CAPS)
121         return FALSE;
122     if (pImeInfo->fdwUICaps & ~VALID_UI_CAPS)
123         return FALSE;
124     if (pImeInfo->fdwSCSCaps & ~VALID_SCS_CAPS)
125         return FALSE;
126     if (pImeInfo->fdwSelectCaps & ~VALID_SELECT_CAPS)
127         return FALSE;
128 
129 #undef VALID_IME_PROP
130 #undef VALID_CMODE_CAPS
131 #undef VALID_SMODE_CAPS
132 #undef VALID_UI_CAPS
133 #undef VALID_SCS_CAPS
134 #undef VALID_SELECT_CAPS
135 
136     if (pImeInfo->fdwProperty & IME_PROP_UNICODE)
137     {
138         StringCchCopyW(pImeDpi->szUIClass, _countof(pImeDpi->szUIClass), szUIClass);
139     }
140     else
141     {
142         if (pImeDpi->uCodePage != GetACP() && pImeDpi->uCodePage)
143             return FALSE;
144 
145         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPSTR)szUIClass, -1,
146                             pImeDpi->szUIClass, _countof(pImeDpi->szUIClass));
147     }
148 
149     return GetClassInfoW(pImeDpi->hInst, pImeDpi->szUIClass, &wcW);
150 }
151 
152 // Win: LoadIME
153 BOOL APIENTRY Imm32LoadIME(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi)
154 {
155     WCHAR szPath[MAX_PATH];
156     HINSTANCE hIME;
157     FARPROC fn;
158     BOOL ret = FALSE;
159 
160     if (!Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile))
161         return FALSE;
162 
163     hIME = GetModuleHandleW(szPath);
164     if (hIME == NULL)
165     {
166         hIME = LoadLibraryW(szPath);
167         if (hIME == NULL)
168         {
169             ERR("Imm32LoadIME: LoadLibraryW(%S) failed\n", szPath);
170             return FALSE;
171         }
172     }
173     pImeDpi->hInst = hIME;
174 
175 #define DEFINE_IME_ENTRY(type, name, params, optional) \
176     do { \
177         fn = GetProcAddress(hIME, #name); \
178         if (fn) pImeDpi->name = (FN_##name)fn; \
179         else if (!(optional)) { \
180             ERR("'%s' not found in the IME module '%s'.\n", #name, debugstr_w(szPath)); \
181             goto Failed; \
182         } \
183     } while (0);
184 #include "imetable.h"
185 #undef DEFINE_IME_ENTRY
186 
187     if (Imm32InquireIme(pImeDpi))
188     {
189         ret = TRUE;
190     }
191     else
192     {
193         ERR("Imm32InquireIme failed\n");
194 Failed:
195         ret = FALSE;
196         FreeLibrary(pImeDpi->hInst);
197         pImeDpi->hInst = NULL;
198     }
199 
200     if (pImeInfoEx->fLoadFlag == 0)
201     {
202         if (ret)
203         {
204             C_ASSERT(sizeof(pImeInfoEx->wszUIClass) == sizeof(pImeDpi->szUIClass));
205             pImeInfoEx->ImeInfo = pImeDpi->ImeInfo;
206             RtlCopyMemory(pImeInfoEx->wszUIClass, pImeDpi->szUIClass,
207                           sizeof(pImeInfoEx->wszUIClass));
208             pImeInfoEx->fLoadFlag = 2;
209         }
210         else
211         {
212             pImeInfoEx->fLoadFlag = 1;
213         }
214 
215         NtUserSetImeInfoEx(pImeInfoEx);
216     }
217 
218     return ret;
219 }
220 
221 // Win: LoadImeDpi
222 PIMEDPI APIENTRY Ime32LoadImeDpi(HKL hKL, BOOL bLock)
223 {
224     IMEINFOEX ImeInfoEx;
225     CHARSETINFO ci;
226     PIMEDPI pImeDpiNew, pImeDpiFound;
227     UINT uCodePage;
228     LCID lcid;
229 
230     if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL) ||
231         ImeInfoEx.fLoadFlag == 1)
232     {
233         return NULL;
234     }
235 
236     pImeDpiNew = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(IMEDPI));
237     if (pImeDpiNew == NULL)
238         return NULL;
239 
240     pImeDpiNew->hKL = hKL;
241 
242     lcid = LOWORD(hKL);
243     if (TranslateCharsetInfo((LPDWORD)(DWORD_PTR)lcid, &ci, TCI_SRCLOCALE))
244         uCodePage = ci.ciACP;
245     else
246         uCodePage = CP_ACP;
247     pImeDpiNew->uCodePage = uCodePage;
248 
249     if (!Imm32LoadIME(&ImeInfoEx, pImeDpiNew))
250     {
251         ImmLocalFree(pImeDpiNew);
252         return FALSE;
253     }
254 
255     RtlEnterCriticalSection(&gcsImeDpi);
256 
257     pImeDpiFound = Imm32FindImeDpi(hKL);
258     if (pImeDpiFound)
259     {
260         if (!bLock)
261             pImeDpiFound->dwFlags &= ~IMEDPI_FLAG_LOCKED;
262 
263         RtlLeaveCriticalSection(&gcsImeDpi);
264         Imm32FreeIME(pImeDpiNew, FALSE);
265         ImmLocalFree(pImeDpiNew);
266         return pImeDpiFound;
267     }
268     else
269     {
270         if (bLock)
271         {
272             pImeDpiNew->dwFlags |= IMEDPI_FLAG_LOCKED;
273             pImeDpiNew->cLockObj = 1;
274         }
275 
276         pImeDpiNew->pNext = gpImeDpiList;
277         gpImeDpiList = pImeDpiNew;
278 
279         RtlLeaveCriticalSection(&gcsImeDpi);
280         return pImeDpiNew;
281     }
282 }
283 
284 // Win: FindOrLoadImeDpi
285 PIMEDPI APIENTRY Imm32FindOrLoadImeDpi(HKL hKL)
286 {
287     PIMEDPI pImeDpi;
288 
289     if (!IS_IME_HKL(hKL) && (!Imm32IsCiceroMode() || Imm32Is16BitMode()))
290         return NULL;
291 
292     pImeDpi = ImmLockImeDpi(hKL);
293     if (pImeDpi == NULL)
294         pImeDpi = Ime32LoadImeDpi(hKL, TRUE);
295     return pImeDpi;
296 }
297 
298 static LRESULT APIENTRY
299 ImeDpi_Escape(PIMEDPI pImeDpi, HIMC hIMC, UINT uSubFunc, LPVOID lpData, HKL hKL)
300 {
301     if (IS_IME_HKL(hKL))
302         return pImeDpi->ImeEscape(hIMC, uSubFunc, lpData);
303 
304     if (Imm32IsCiceroMode() && pImeDpi->CtfImeEscapeEx)
305         return pImeDpi->CtfImeEscapeEx(hIMC, uSubFunc, lpData, hKL);
306 
307     return 0;
308 }
309 
310 // Win: ImmUnloadIME
311 BOOL APIENTRY Imm32ReleaseIME(HKL hKL)
312 {
313     BOOL ret = TRUE;
314     PIMEDPI pImeDpi0, pImeDpi1;
315 
316     RtlEnterCriticalSection(&gcsImeDpi);
317 
318     for (pImeDpi0 = gpImeDpiList; pImeDpi0; pImeDpi0 = pImeDpi0->pNext)
319     {
320         if (pImeDpi0->hKL == hKL)
321             break;
322     }
323 
324     if (!pImeDpi0)
325         goto Quit;
326 
327     if (pImeDpi0->cLockObj)
328     {
329         pImeDpi0->dwFlags |= IMEDPI_FLAG_UNKNOWN;
330         ret = FALSE;
331         goto Quit;
332     }
333 
334     if (gpImeDpiList == pImeDpi0)
335     {
336         gpImeDpiList = pImeDpi0->pNext;
337     }
338     else if (gpImeDpiList)
339     {
340         for (pImeDpi1 = gpImeDpiList; pImeDpi1; pImeDpi1 = pImeDpi1->pNext)
341         {
342             if (pImeDpi1->pNext == pImeDpi0)
343             {
344                 pImeDpi1->pNext = pImeDpi0->pNext;
345                 break;
346             }
347         }
348     }
349 
350     Imm32FreeIME(pImeDpi0, TRUE);
351     ImmLocalFree(pImeDpi0);
352 
353 Quit:
354     RtlLeaveCriticalSection(&gcsImeDpi);
355     return ret;
356 }
357 
358 // Win: ImmGetImeMenuItemsInterProcess
359 DWORD APIENTRY
360 Imm32GetImeMenuItemWCrossProcess(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPVOID lpImeParentMenu,
361                                  LPVOID lpImeMenu, DWORD dwSize)
362 {
363     FIXME("We have to do something\n");
364     return 0;
365 }
366 
367 // Win: ImmGetImeMenuItemsWorker
368 DWORD APIENTRY
369 ImmGetImeMenuItemsAW(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPVOID lpImeParentMenu,
370                      LPVOID lpImeMenu, DWORD dwSize, BOOL bTargetIsAnsi)
371 {
372     DWORD ret = 0, cbTotal, dwProcessId, dwThreadId, iItem;
373     LPINPUTCONTEXT pIC;
374     PIMEDPI pImeDpi = NULL;
375     IMEMENUITEMINFOA ParentA;
376     IMEMENUITEMINFOW ParentW;
377     LPIMEMENUITEMINFOA pItemA;
378     LPIMEMENUITEMINFOW pItemW;
379     LPVOID pNewItems = NULL, pNewParent = NULL;
380     BOOL bImcIsAnsi;
381     HKL hKL;
382 
383     if (!hIMC)
384         return 0;
385 
386     dwProcessId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTPROCESSID);
387     if (dwProcessId == 0)
388         return 0;
389 
390     if (dwProcessId != GetCurrentProcessId())
391     {
392         if (bTargetIsAnsi)
393             return 0;
394         return Imm32GetImeMenuItemWCrossProcess(hIMC, dwFlags, dwType, lpImeParentMenu,
395                                                 lpImeMenu, dwSize);
396     }
397 
398     pIC = ImmLockIMC(hIMC);
399     if (pIC == NULL)
400         return 0;
401 
402     dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
403     if (dwThreadId == 0)
404     {
405         ImmUnlockIMC(hIMC);
406         return 0;
407     }
408 
409     hKL = GetKeyboardLayout(dwThreadId);
410     pImeDpi = ImmLockImeDpi(hKL);
411     if (!pImeDpi)
412     {
413         ImmUnlockIMC(hIMC);
414         return 0;
415     }
416 
417     if (pImeDpi->ImeGetImeMenuItems == NULL)
418         goto Quit;
419 
420     bImcIsAnsi = Imm32IsImcAnsi(hIMC);
421 
422     if (bImcIsAnsi != bTargetIsAnsi)
423     {
424         if (bTargetIsAnsi)
425         {
426             if (lpImeParentMenu)
427                 pNewParent = &ParentW;
428 
429             if (lpImeMenu)
430             {
431                 cbTotal = ((dwSize / sizeof(IMEMENUITEMINFOA)) * sizeof(IMEMENUITEMINFOW));
432                 pNewItems = ImmLocalAlloc(0, cbTotal);
433                 if (!pNewItems)
434                     goto Quit;
435             }
436         }
437         else
438         {
439             if (lpImeParentMenu)
440                 pNewParent = &ParentA;
441 
442             if (lpImeMenu)
443             {
444                 cbTotal = ((dwSize / sizeof(IMEMENUITEMINFOW)) * sizeof(IMEMENUITEMINFOA));
445                 pNewItems = ImmLocalAlloc(0, cbTotal);
446                 if (!pNewItems)
447                     goto Quit;
448             }
449         }
450     }
451     else
452     {
453         pNewItems = lpImeMenu;
454         pNewParent = lpImeParentMenu;
455     }
456 
457     ret = pImeDpi->ImeGetImeMenuItems(hIMC, dwFlags, dwType, pNewParent, pNewItems, dwSize);
458     if (!ret || !lpImeMenu)
459         goto Quit;
460 
461     if (bImcIsAnsi != bTargetIsAnsi)
462     {
463         if (bTargetIsAnsi)
464         {
465             if (pNewParent)
466                 Imm32ImeMenuWideToAnsi(pNewParent, lpImeParentMenu, CP_ACP);
467 
468             pItemW = pNewItems;
469             pItemA = lpImeMenu;
470             for (iItem = 0; iItem < ret; ++iItem, ++pItemW, ++pItemA)
471             {
472                 if (!Imm32ImeMenuWideToAnsi(pItemW, pItemA, CP_ACP))
473                 {
474                     ret = 0;
475                     break;
476                 }
477             }
478         }
479         else
480         {
481             if (pNewParent)
482                 Imm32ImeMenuAnsiToWide(pNewParent, lpImeParentMenu, pImeDpi->uCodePage, TRUE);
483 
484             pItemA = pNewItems;
485             pItemW = lpImeMenu;
486             for (iItem = 0; iItem < dwSize; ++iItem, ++pItemA, ++pItemW)
487             {
488                 if (!Imm32ImeMenuAnsiToWide(pItemA, pItemW, pImeDpi->uCodePage, TRUE))
489                 {
490                     ret = 0;
491                     break;
492                 }
493             }
494         }
495     }
496 
497 Quit:
498     if (pNewItems != lpImeMenu)
499         ImmLocalFree(pNewItems);
500     ImmUnlockImeDpi(pImeDpi);
501     ImmUnlockIMC(hIMC);
502     return ret;
503 }
504 
505 /***********************************************************************
506  *		ImmInstallIMEA (IMM32.@)
507  */
508 HKL WINAPI ImmInstallIMEA(LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
509 {
510     HKL hKL = NULL;
511     LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL;
512 
513     TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText));
514 
515     pszFileNameW = Imm32WideFromAnsi(lpszIMEFileName);
516     if (!pszFileNameW)
517         goto Quit;
518 
519     pszLayoutTextW = Imm32WideFromAnsi(lpszLayoutText);
520     if (!pszLayoutTextW)
521         goto Quit;
522 
523     hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW);
524 
525 Quit:
526     ImmLocalFree(pszFileNameW);
527     ImmLocalFree(pszLayoutTextW);
528     return hKL;
529 }
530 
531 /***********************************************************************
532  *		ImmInstallIMEW (IMM32.@)
533  */
534 HKL WINAPI ImmInstallIMEW(LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
535 {
536     WCHAR szImeFileName[MAX_PATH], szImeDestPath[MAX_PATH], szImeKey[20];
537     IMEINFOEX InfoEx;
538     LPWSTR pchFilePart;
539     UINT iLayout, cLayouts;
540     HKL hNewKL;
541     WORD wLangID;
542     PREG_IME pLayouts = NULL;
543 
544     TRACE("(%s, %s)\n", debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText));
545 
546     GetFullPathNameW(lpszIMEFileName, _countof(szImeFileName), szImeFileName, &pchFilePart);
547     CharUpperW(szImeFileName);
548     if (!pchFilePart)
549         return NULL;
550 
551     /* Load the IME version info */
552     InfoEx.hkl = hNewKL = NULL;
553     StringCchCopyW(InfoEx.wszImeFile, _countof(InfoEx.wszImeFile), pchFilePart);
554     if (Imm32LoadImeVerInfo(&InfoEx) && InfoEx.hkl)
555         wLangID = LOWORD(InfoEx.hkl);
556     else
557         return NULL;
558 
559     /* Get the IME layouts from registry */
560     cLayouts = Imm32GetImeLayout(NULL, 0);
561     if (cLayouts)
562     {
563         pLayouts = ImmLocalAlloc(0, cLayouts * sizeof(REG_IME));
564         if (!pLayouts || !Imm32GetImeLayout(pLayouts, cLayouts))
565         {
566             ImmLocalFree(pLayouts);
567             return NULL;
568         }
569 
570         for (iLayout = 0; iLayout < cLayouts; ++iLayout)
571         {
572             if (lstrcmpiW(pLayouts[iLayout].szFileName, pchFilePart) == 0)
573             {
574                 if (wLangID != LOWORD(pLayouts[iLayout].hKL))
575                     goto Quit; /* The language is different */
576 
577                 hNewKL = pLayouts[iLayout].hKL; /* Found */
578                 break;
579             }
580         }
581     }
582 
583     /* If the IME for the specified filename is valid, then unload it now */
584     if (ImmGetImeInfoEx(&InfoEx, ImeInfoExImeFileName, pchFilePart) &&
585         !UnloadKeyboardLayout(InfoEx.hkl))
586     {
587         hNewKL = NULL;
588         goto Quit;
589     }
590 
591     Imm32GetSystemLibraryPath(szImeDestPath, _countof(szImeDestPath), pchFilePart);
592     CharUpperW(szImeDestPath);
593 
594     /* If the source and the destination pathnames were different, then copy the IME file */
595     if (lstrcmpiW(szImeFileName, szImeDestPath) != 0 &&
596         !Imm32CopyImeFile(szImeFileName, szImeDestPath))
597     {
598         hNewKL = NULL;
599         goto Quit;
600     }
601 
602     if (hNewKL == NULL)
603         hNewKL = Imm32AssignNewLayout(cLayouts, pLayouts, wLangID);
604 
605     if (hNewKL)
606     {
607         /* Write the IME layout to registry */
608         if (Imm32WriteImeLayout(hNewKL, pchFilePart, lpszLayoutText))
609         {
610             /* Load the keyboard layout */
611             Imm32UIntToStr((DWORD)(DWORD_PTR)hNewKL, 16, szImeKey, _countof(szImeKey));
612             hNewKL = LoadKeyboardLayoutW(szImeKey, KLF_REPLACELANG);
613         }
614         else
615         {
616             hNewKL = NULL;
617         }
618     }
619 
620 Quit:
621     ImmLocalFree(pLayouts);
622     return hNewKL;
623 }
624 
625 /***********************************************************************
626  *		ImmIsIME (IMM32.@)
627  */
628 BOOL WINAPI ImmIsIME(HKL hKL)
629 {
630     IMEINFOEX info;
631     TRACE("(%p)\n", hKL);
632     return !!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayoutTFS, &hKL);
633 }
634 
635 /***********************************************************************
636  *		ImmGetDefaultIMEWnd (IMM32.@)
637  */
638 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
639 {
640     if (!IS_IMM_MODE())
641         return NULL;
642 
643     if (hWnd == NULL)
644         return (HWND)NtUserGetThreadState(THREADSTATE_DEFAULTIMEWINDOW);
645 
646     return (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_IME);
647 }
648 
649 /***********************************************************************
650  *		ImmNotifyIME (IMM32.@)
651  */
652 BOOL WINAPI ImmNotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
653 {
654     HKL hKL;
655     PIMEDPI pImeDpi;
656     BOOL ret;
657 
658     TRACE("(%p, %lu, %lu, %lu)\n", hIMC, dwAction, dwIndex, dwValue);
659 
660     if (hIMC && Imm32IsCrossThreadAccess(hIMC))
661         return FALSE;
662 
663     hKL = GetKeyboardLayout(0);
664     pImeDpi = ImmLockImeDpi(hKL);
665     if (pImeDpi == NULL)
666         return FALSE;
667 
668     ret = pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue);
669     ImmUnlockImeDpi(pImeDpi);
670     return ret;
671 }
672 
673 /***********************************************************************
674  *              ImmDisableLegacyIME(IMM32.@)
675  */
676 BOOL WINAPI ImmDisableLegacyIME(void)
677 {
678     FIXME("stub\n");
679     return TRUE;
680 }
681 
682 /***********************************************************************
683  *              ImmGetImeInfoEx (IMM32.@)
684  */
685 BOOL WINAPI
686 ImmGetImeInfoEx(PIMEINFOEX pImeInfoEx, IMEINFOEXCLASS SearchType, PVOID pvSearchKey)
687 {
688     HKL hKL;
689     if (SearchType == ImeInfoExKeyboardLayout || SearchType == ImeInfoExKeyboardLayoutTFS)
690     {
691         hKL = *(HKL*)pvSearchKey;
692         pImeInfoEx->hkl = hKL;
693 
694         if (SearchType == ImeInfoExKeyboardLayoutTFS)
695         {
696             if (!IS_IME_HKL(hKL))
697             {
698                 if (!CtfImmIsTextFrameServiceDisabled() ||
699                     !Imm32IsCiceroMode() || Imm32Is16BitMode())
700                 {
701                     return FALSE;
702                 }
703             }
704 
705             SearchType = ImeInfoExKeyboardLayout;
706         }
707         else
708         {
709             if (!IS_IME_HKL(hKL))
710                 return FALSE;
711         }
712     }
713     else if (SearchType == ImeInfoExImeFileName)
714     {
715         StringCchCopyW(pImeInfoEx->wszImeFile, _countof(pImeInfoEx->wszImeFile),
716                        pvSearchKey);
717     }
718     else
719     {
720         return FALSE;
721     }
722 
723     return NtUserGetImeInfoEx(pImeInfoEx, SearchType);
724 }
725 
726 /***********************************************************************
727  *		ImmLockImeDpi (IMM32.@)
728  */
729 PIMEDPI WINAPI ImmLockImeDpi(HKL hKL)
730 {
731     PIMEDPI pImeDpi = NULL;
732 
733     TRACE("(%p)\n", hKL);
734 
735     RtlEnterCriticalSection(&gcsImeDpi);
736 
737     /* Find by hKL */
738     for (pImeDpi = gpImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext)
739     {
740         if (pImeDpi->hKL == hKL) /* found */
741         {
742             /* lock if possible */
743             if (pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN)
744                 pImeDpi = NULL;
745             else
746                 ++(pImeDpi->cLockObj);
747             break;
748         }
749     }
750 
751     RtlLeaveCriticalSection(&gcsImeDpi);
752     return pImeDpi;
753 }
754 
755 /***********************************************************************
756  *		ImmUnlockImeDpi (IMM32.@)
757  */
758 VOID WINAPI ImmUnlockImeDpi(PIMEDPI pImeDpi)
759 {
760     PIMEDPI *ppEntry;
761 
762     TRACE("(%p)\n", pImeDpi);
763 
764     if (pImeDpi == NULL)
765         return;
766 
767     RtlEnterCriticalSection(&gcsImeDpi);
768 
769     /* unlock */
770     --(pImeDpi->cLockObj);
771     if (pImeDpi->cLockObj != 0)
772     {
773         RtlLeaveCriticalSection(&gcsImeDpi);
774         return;
775     }
776 
777     if ((pImeDpi->dwFlags & IMEDPI_FLAG_UNKNOWN) == 0)
778     {
779         if ((pImeDpi->dwFlags & IMEDPI_FLAG_LOCKED) == 0 ||
780             (pImeDpi->ImeInfo.fdwProperty & IME_PROP_END_UNLOAD) == 0)
781         {
782             RtlLeaveCriticalSection(&gcsImeDpi);
783             return;
784         }
785     }
786 
787     /* Remove from list */
788     for (ppEntry = &gpImeDpiList; *ppEntry; ppEntry = &((*ppEntry)->pNext))
789     {
790         if (*ppEntry == pImeDpi) /* found */
791         {
792             *ppEntry = pImeDpi->pNext;
793             break;
794         }
795     }
796 
797     Imm32FreeIME(pImeDpi, TRUE);
798     ImmLocalFree(pImeDpi);
799 
800     RtlLeaveCriticalSection(&gcsImeDpi);
801 }
802 
803 /***********************************************************************
804  *		ImmLoadIME (IMM32.@)
805  */
806 BOOL WINAPI ImmLoadIME(HKL hKL)
807 {
808     PIMEDPI pImeDpi;
809 
810     if (!IS_IME_HKL(hKL) && (!Imm32IsCiceroMode() || Imm32Is16BitMode()))
811         return FALSE;
812 
813     pImeDpi = Imm32FindImeDpi(hKL);
814     if (pImeDpi == NULL)
815         pImeDpi = Ime32LoadImeDpi(hKL, FALSE);
816     return (pImeDpi != NULL);
817 }
818 
819 /***********************************************************************
820  *		ImmDisableIME (IMM32.@)
821  */
822 BOOL WINAPI ImmDisableIME(DWORD dwThreadId)
823 {
824     return NtUserDisableThreadIme(dwThreadId);
825 }
826 
827 /***********************************************************************
828  *		ImmGetDescriptionA (IMM32.@)
829  */
830 UINT WINAPI ImmGetDescriptionA(HKL hKL, LPSTR lpszDescription, UINT uBufLen)
831 {
832     IMEINFOEX info;
833     size_t cch;
834 
835     TRACE("(%p,%p,%d)\n", hKL, lpszDescription, uBufLen);
836 
837     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
838         return 0;
839 
840     StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
841     cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeDescription, (INT)cch,
842                               lpszDescription, uBufLen, NULL, NULL);
843     if (uBufLen)
844         lpszDescription[cch] = 0;
845     return (UINT)cch;
846 }
847 
848 /***********************************************************************
849  *		ImmGetDescriptionW (IMM32.@)
850  */
851 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
852 {
853     IMEINFOEX info;
854     size_t cch;
855 
856     TRACE("(%p, %p, %d)\n", hKL, lpszDescription, uBufLen);
857 
858     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
859         return 0;
860 
861     if (uBufLen != 0)
862         StringCchCopyW(lpszDescription, uBufLen, info.wszImeDescription);
863 
864     StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
865     return (UINT)cch;
866 }
867 
868 /***********************************************************************
869  *		ImmGetIMEFileNameA (IMM32.@)
870  */
871 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
872 {
873     BOOL bDefUsed;
874     IMEINFOEX info;
875     size_t cch;
876 
877     TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen);
878 
879     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
880     {
881         if (uBufLen > 0)
882             lpszFileName[0] = 0;
883         return 0;
884     }
885 
886     StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch);
887 
888     cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeFile, (INT)cch,
889                               lpszFileName, uBufLen, NULL, &bDefUsed);
890     if (uBufLen == 0)
891         return (UINT)cch;
892 
893     if (cch > uBufLen - 1)
894         cch = uBufLen - 1;
895 
896     lpszFileName[cch] = 0;
897     return (UINT)cch;
898 }
899 
900 /***********************************************************************
901  *		ImmGetIMEFileNameW (IMM32.@)
902  */
903 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
904 {
905     IMEINFOEX info;
906     size_t cch;
907 
908     TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen);
909 
910     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL) || !IS_IME_HKL(hKL))
911     {
912         if (uBufLen > 0)
913             lpszFileName[0] = 0;
914         return 0;
915     }
916 
917     StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch);
918     if (uBufLen == 0)
919         return (UINT)cch;
920 
921     StringCchCopyNW(lpszFileName, uBufLen, info.wszImeFile, cch);
922 
923     if (cch > uBufLen - 1)
924         cch = uBufLen - 1;
925 
926     lpszFileName[cch] = 0;
927     return (UINT)cch;
928 }
929 
930 /***********************************************************************
931  *		ImmGetProperty (IMM32.@)
932  */
933 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
934 {
935     IMEINFOEX ImeInfoEx;
936     LPIMEINFO pImeInfo;
937     DWORD dwValue;
938     PIMEDPI pImeDpi = NULL;
939 
940     TRACE("(%p, %lu)\n", hKL, fdwIndex);
941 
942     if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL))
943         return FALSE;
944 
945     if (fdwIndex == IGP_GETIMEVERSION)
946         return ImeInfoEx.dwImeWinVersion;
947 
948     if (ImeInfoEx.fLoadFlag != 2)
949     {
950         pImeDpi = Imm32FindOrLoadImeDpi(hKL);
951         if (pImeDpi == NULL)
952             return FALSE;
953 
954         pImeInfo = &pImeDpi->ImeInfo;
955     }
956     else
957     {
958         pImeInfo = &ImeInfoEx.ImeInfo;
959     }
960 
961     switch (fdwIndex)
962     {
963         case IGP_PROPERTY:      dwValue = pImeInfo->fdwProperty; break;
964         case IGP_CONVERSION:    dwValue = pImeInfo->fdwConversionCaps; break;
965         case IGP_SENTENCE:      dwValue = pImeInfo->fdwSentenceCaps; break;
966         case IGP_UI:            dwValue = pImeInfo->fdwUICaps; break;
967         case IGP_SETCOMPSTR:    dwValue = pImeInfo->fdwSCSCaps; break;
968         case IGP_SELECT:        dwValue = pImeInfo->fdwSelectCaps; break;
969         default:                dwValue = 0; break;
970     }
971 
972     if (pImeDpi)
973         ImmUnlockImeDpi(pImeDpi);
974     return dwValue;
975 }
976 
977 /***********************************************************************
978  *		ImmEscapeA (IMM32.@)
979  */
980 LRESULT WINAPI ImmEscapeA(HKL hKL, HIMC hIMC, UINT uSubFunc, LPVOID lpData)
981 {
982     LRESULT ret;
983     PIMEDPI pImeDpi;
984     INT cch;
985     CHAR szA[MAX_IMM_FILENAME];
986     WCHAR szW[MAX_IMM_FILENAME];
987 
988     TRACE("(%p, %p, %u, %p)\n", hKL, hIMC, uSubFunc, lpData);
989 
990     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
991     if (!pImeDpi)
992         return 0;
993 
994     if (!ImeDpi_IsUnicode(pImeDpi) || !lpData)
995     {
996         ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
997         ImmUnlockImeDpi(pImeDpi);
998         return ret;
999     }
1000 
1001     switch (uSubFunc)
1002     {
1003         case IME_ESC_SEQUENCE_TO_INTERNAL:
1004             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1005 
1006             cch = 0;
1007             if (HIWORD(ret))
1008                 szW[cch++] = HIWORD(ret);
1009             if (LOWORD(ret))
1010                 szW[cch++] = LOWORD(ret);
1011 
1012             cch = WideCharToMultiByte(pImeDpi->uCodePage, 0, szW, cch, szA, _countof(szA),
1013                                       NULL, NULL);
1014             switch (cch)
1015             {
1016                 case 1:
1017                     ret = MAKEWORD(szA[0], 0);
1018                     break;
1019                 case 2:
1020                     ret = MAKEWORD(szA[1], szA[0]);
1021                     break;
1022                 case 3:
1023                     ret = MAKELONG(MAKEWORD(szA[2], szA[1]), MAKEWORD(szA[0], 0));
1024                     break;
1025                 case 4:
1026                     ret = MAKELONG(MAKEWORD(szA[3], szA[2]), MAKEWORD(szA[1], szA[0]));
1027                     break;
1028                 default:
1029                     ret = 0;
1030                     break;
1031             }
1032             break;
1033 
1034         case IME_ESC_GET_EUDC_DICTIONARY:
1035         case IME_ESC_IME_NAME:
1036         case IME_ESC_GETHELPFILENAME:
1037             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, szW, hKL);
1038             if (ret)
1039             {
1040                 szW[_countof(szW) - 1] = 0;
1041                 WideCharToMultiByte(pImeDpi->uCodePage, 0, szW, -1,
1042                                     lpData, MAX_IMM_FILENAME, NULL, NULL);
1043                 ((LPSTR)lpData)[MAX_IMM_FILENAME - 1] = 0;
1044             }
1045             break;
1046 
1047         case IME_ESC_SET_EUDC_DICTIONARY:
1048         case IME_ESC_HANJA_MODE:
1049             MultiByteToWideChar(pImeDpi->uCodePage, MB_PRECOMPOSED,
1050                                 lpData, -1, szW, _countof(szW));
1051             szW[_countof(szW) - 1] = 0;
1052             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, szW, hKL);
1053             break;
1054 
1055         default:
1056             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1057             break;
1058     }
1059 
1060     ImmUnlockImeDpi(pImeDpi);
1061     return ret;
1062 }
1063 
1064 /***********************************************************************
1065  *		ImmEscapeW (IMM32.@)
1066  */
1067 LRESULT WINAPI ImmEscapeW(HKL hKL, HIMC hIMC, UINT uSubFunc, LPVOID lpData)
1068 {
1069     LRESULT ret;
1070     PIMEDPI pImeDpi;
1071     INT cch;
1072     CHAR szA[MAX_IMM_FILENAME];
1073     WCHAR szW[MAX_IMM_FILENAME];
1074     WORD word;
1075 
1076     TRACE("(%p, %p, %u, %p)\n", hKL, hIMC, uSubFunc, lpData);
1077 
1078     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1079     if (!pImeDpi)
1080         return 0;
1081 
1082     if (ImeDpi_IsUnicode(pImeDpi) || !lpData)
1083     {
1084         ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1085         ImmUnlockImeDpi(pImeDpi);
1086         return ret;
1087     }
1088 
1089     switch (uSubFunc)
1090     {
1091         case IME_ESC_SEQUENCE_TO_INTERNAL:
1092             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1093 
1094             word = LOWORD(ret);
1095             cch = 0;
1096             if (HIBYTE(word))
1097                 szA[cch++] = HIBYTE(word);
1098             if (LOBYTE(word))
1099                 szA[cch++] = LOBYTE(word);
1100 
1101             cch = MultiByteToWideChar(pImeDpi->uCodePage, MB_PRECOMPOSED,
1102                                       szA, cch, szW, _countof(szW));
1103             switch (cch)
1104             {
1105                 case 1:  ret = szW[0]; break;
1106                 case 2:  ret = MAKELONG(szW[1], szW[0]); break;
1107                 default: ret = 0; break;
1108             }
1109             break;
1110 
1111         case IME_ESC_GET_EUDC_DICTIONARY:
1112         case IME_ESC_IME_NAME:
1113         case IME_ESC_GETHELPFILENAME:
1114             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, szA, hKL);
1115             if (ret)
1116             {
1117                 szA[_countof(szA) - 1] = 0;
1118                 MultiByteToWideChar(pImeDpi->uCodePage, MB_PRECOMPOSED,
1119                                     szA, -1, lpData, MAX_IMM_FILENAME);
1120                 ((LPWSTR)lpData)[MAX_IMM_FILENAME - 1] = 0;
1121             }
1122             break;
1123 
1124         case IME_ESC_SET_EUDC_DICTIONARY:
1125         case IME_ESC_HANJA_MODE:
1126             WideCharToMultiByte(pImeDpi->uCodePage, 0,
1127                                 lpData, -1, szA, _countof(szA), NULL, NULL);
1128             szA[_countof(szA) - 1] = 0;
1129             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, szA, hKL);
1130             break;
1131 
1132         default:
1133             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1134             break;
1135     }
1136 
1137     ImmUnlockImeDpi(pImeDpi);
1138     return ret;
1139 }
1140 
1141 /***********************************************************************
1142  *		ImmGetOpenStatus (IMM32.@)
1143  */
1144 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
1145 {
1146     BOOL ret;
1147     LPINPUTCONTEXT pIC;
1148 
1149     TRACE("(%p)\n", hIMC);
1150 
1151     if (!hIMC)
1152         return FALSE;
1153 
1154     pIC = ImmLockIMC(hIMC);
1155     if (!pIC)
1156         return FALSE;
1157 
1158     ret = pIC->fOpen;
1159 
1160     ImmUnlockIMC(hIMC);
1161     return ret;
1162 }
1163 
1164 /***********************************************************************
1165  *		ImmSetOpenStatus (IMM32.@)
1166  */
1167 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
1168 {
1169     DWORD dwConversion;
1170     LPINPUTCONTEXT pIC;
1171     HWND hWnd;
1172     BOOL bHasChange = FALSE;
1173 
1174     TRACE("(%p, %d)\n", hIMC, fOpen);
1175 
1176     if (Imm32IsCrossThreadAccess(hIMC))
1177         return FALSE;
1178 
1179     pIC = ImmLockIMC(hIMC);
1180     if (pIC == NULL)
1181         return FALSE;
1182 
1183     if (pIC->fOpen != fOpen)
1184     {
1185         pIC->fOpen = fOpen;
1186         hWnd = pIC->hWnd;
1187         dwConversion = pIC->fdwConversion;
1188         bHasChange = TRUE;
1189     }
1190 
1191     ImmUnlockIMC(hIMC);
1192 
1193     if (bHasChange)
1194     {
1195         Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
1196                            IMC_SETOPENSTATUS, IMN_SETOPENSTATUS, 0);
1197         NtUserNotifyIMEStatus(hWnd, fOpen, dwConversion);
1198     }
1199 
1200     return TRUE;
1201 }
1202 
1203 /***********************************************************************
1204  *		ImmGetStatusWindowPos (IMM32.@)
1205  */
1206 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1207 {
1208     LPINPUTCONTEXT pIC;
1209     BOOL ret;
1210 
1211     TRACE("(%p, %p)\n", hIMC, lpptPos);
1212 
1213     pIC = ImmLockIMC(hIMC);
1214     if (pIC == NULL)
1215         return FALSE;
1216 
1217     ret = !!(pIC->fdwInit & INIT_STATUSWNDPOS);
1218     if (ret)
1219         *lpptPos = pIC->ptStatusWndPos;
1220 
1221     ImmUnlockIMC(hIMC);
1222     return ret;
1223 }
1224 
1225 /***********************************************************************
1226  *		ImmSetStatusWindowPos (IMM32.@)
1227  */
1228 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1229 {
1230     LPINPUTCONTEXT pIC;
1231     HWND hWnd;
1232 
1233     TRACE("(%p, {%ld, %ld})\n", hIMC, lpptPos->x, lpptPos->y);
1234 
1235     if (Imm32IsCrossThreadAccess(hIMC))
1236         return FALSE;
1237 
1238     pIC = ImmLockIMC(hIMC);
1239     if (!pIC)
1240         return FALSE;
1241 
1242     hWnd = pIC->hWnd;
1243     pIC->ptStatusWndPos = *lpptPos;
1244     pIC->fdwInit |= INIT_STATUSWNDPOS;
1245 
1246     ImmUnlockIMC(hIMC);
1247 
1248     Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
1249                        IMC_SETSTATUSWINDOWPOS, IMN_SETSTATUSWINDOWPOS, 0);
1250     return TRUE;
1251 }
1252 
1253 /***********************************************************************
1254  *		ImmGetCompositionWindow (IMM32.@)
1255  */
1256 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1257 {
1258     LPINPUTCONTEXT pIC;
1259     BOOL ret = FALSE;
1260 
1261     TRACE("(%p, %p)\n", hIMC, lpCompForm);
1262 
1263     pIC = ImmLockIMC(hIMC);
1264     if (!pIC)
1265         return FALSE;
1266 
1267     if (pIC->fdwInit & INIT_COMPFORM)
1268     {
1269         *lpCompForm = pIC->cfCompForm;
1270         ret = TRUE;
1271     }
1272 
1273     ImmUnlockIMC(hIMC);
1274     return ret;
1275 }
1276 
1277 /***********************************************************************
1278  *		ImmSetCompositionWindow (IMM32.@)
1279  */
1280 BOOL WINAPI ImmSetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1281 {
1282     LPINPUTCONTEXT pIC;
1283     HWND hWnd;
1284 
1285     if (Imm32IsCrossThreadAccess(hIMC))
1286         return FALSE;
1287 
1288     pIC = ImmLockIMC(hIMC);
1289     if (pIC == NULL)
1290         return FALSE;
1291 
1292     pIC->cfCompForm = *lpCompForm;
1293     pIC->fdwInit |= INIT_COMPFORM;
1294 
1295     hWnd = pIC->hWnd;
1296 
1297     ImmUnlockIMC(hIMC);
1298 
1299     Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
1300                        IMC_SETCOMPOSITIONWINDOW, IMN_SETCOMPOSITIONWINDOW, 0);
1301     return TRUE;
1302 }
1303 
1304 /***********************************************************************
1305  *		ImmGetCompositionFontA (IMM32.@)
1306  */
1307 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1308 {
1309     PCLIENTIMC pClientImc;
1310     BOOL ret = FALSE, bWide;
1311     LPINPUTCONTEXT pIC;
1312 
1313     TRACE("(%p, %p)\n", hIMC, lplf);
1314 
1315     pClientImc = ImmLockClientImc(hIMC);
1316     if (pClientImc == NULL)
1317         return FALSE;
1318 
1319     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
1320     ImmUnlockClientImc(pClientImc);
1321 
1322     pIC = ImmLockIMC(hIMC);
1323     if (pIC == NULL)
1324         return FALSE;
1325 
1326     if (pIC->fdwInit & INIT_LOGFONT)
1327     {
1328         if (bWide)
1329             LogFontWideToAnsi(&pIC->lfFont.W, lplf);
1330         else
1331             *lplf = pIC->lfFont.A;
1332 
1333         ret = TRUE;
1334     }
1335 
1336     ImmUnlockIMC(hIMC);
1337     return ret;
1338 }
1339 
1340 /***********************************************************************
1341  *		ImmGetCompositionFontW (IMM32.@)
1342  */
1343 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1344 {
1345     PCLIENTIMC pClientImc;
1346     BOOL bWide;
1347     LPINPUTCONTEXT pIC;
1348     BOOL ret = FALSE;
1349 
1350     TRACE("(%p, %p)\n", hIMC, lplf);
1351 
1352     pClientImc = ImmLockClientImc(hIMC);
1353     if (pClientImc == NULL)
1354         return FALSE;
1355 
1356     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
1357     ImmUnlockClientImc(pClientImc);
1358 
1359     pIC = ImmLockIMC(hIMC);
1360     if (pIC == NULL)
1361         return FALSE;
1362 
1363     if (pIC->fdwInit & INIT_LOGFONT)
1364     {
1365         if (bWide)
1366             *lplf = pIC->lfFont.W;
1367         else
1368             LogFontAnsiToWide(&pIC->lfFont.A, lplf);
1369 
1370         ret = TRUE;
1371     }
1372 
1373     ImmUnlockIMC(hIMC);
1374     return ret;
1375 }
1376 
1377 /***********************************************************************
1378  *		ImmSetCompositionFontA (IMM32.@)
1379  */
1380 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1381 {
1382     LOGFONTW lfW;
1383     PCLIENTIMC pClientImc;
1384     BOOL bWide;
1385     LPINPUTCONTEXTDX pIC;
1386     LCID lcid;
1387     HWND hWnd;
1388     PTEB pTeb;
1389 
1390     TRACE("(%p, %p)\n", hIMC, lplf);
1391 
1392     if (Imm32IsCrossThreadAccess(hIMC))
1393         return FALSE;
1394 
1395     pClientImc = ImmLockClientImc(hIMC);
1396     if (pClientImc == NULL)
1397         return FALSE;
1398 
1399     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
1400     ImmUnlockClientImc(pClientImc);
1401 
1402     if (bWide)
1403     {
1404         LogFontAnsiToWide(lplf, &lfW);
1405         return ImmSetCompositionFontW(hIMC, &lfW);
1406     }
1407 
1408     pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1409     if (pIC == NULL)
1410         return FALSE;
1411 
1412     pTeb = NtCurrentTeb();
1413     if (pTeb->Win32ClientInfo[2] < 0x400)
1414     {
1415         lcid = GetSystemDefaultLCID();
1416         if (PRIMARYLANGID(lcid) == LANG_JAPANESE && !(pIC->dwUIFlags & 2) &&
1417             pIC->cfCompForm.dwStyle != CFS_DEFAULT)
1418         {
1419             PostMessageA(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
1420         }
1421     }
1422 
1423     pIC->lfFont.A = *lplf;
1424     pIC->fdwInit |= INIT_LOGFONT;
1425     hWnd = pIC->hWnd;
1426 
1427     ImmUnlockIMC(hIMC);
1428 
1429     Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT,
1430                        IMN_SETCOMPOSITIONFONT, 0);
1431     return TRUE;
1432 }
1433 
1434 /***********************************************************************
1435  *		ImmSetCompositionFontW (IMM32.@)
1436  */
1437 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1438 {
1439     LOGFONTA lfA;
1440     PCLIENTIMC pClientImc;
1441     BOOL bWide;
1442     HWND hWnd;
1443     LPINPUTCONTEXTDX pIC;
1444     PTEB pTeb;
1445     LCID lcid;
1446 
1447     TRACE("(%p, %p)\n", hIMC, lplf);
1448 
1449     if (Imm32IsCrossThreadAccess(hIMC))
1450         return FALSE;
1451 
1452     pClientImc = ImmLockClientImc(hIMC);
1453     if (pClientImc == NULL)
1454         return FALSE;
1455 
1456     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
1457     ImmUnlockClientImc(pClientImc);
1458 
1459     if (!bWide)
1460     {
1461         LogFontWideToAnsi(lplf, &lfA);
1462         return ImmSetCompositionFontA(hIMC, &lfA);
1463     }
1464 
1465     pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1466     if (pIC == NULL)
1467         return FALSE;
1468 
1469     pTeb = NtCurrentTeb();
1470     if (pTeb->Win32ClientInfo[2] < 0x400)
1471     {
1472         lcid = GetSystemDefaultLCID();
1473         if (PRIMARYLANGID(lcid) == LANG_JAPANESE &&
1474             !(pIC->dwUIFlags & 2) &&
1475             pIC->cfCompForm.dwStyle != CFS_DEFAULT)
1476         {
1477             PostMessageW(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
1478         }
1479     }
1480 
1481     pIC->lfFont.W = *lplf;
1482     pIC->fdwInit |= INIT_LOGFONT;
1483     hWnd = pIC->hWnd;
1484 
1485     ImmUnlockIMC(hIMC);
1486 
1487     Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT,
1488                        IMN_SETCOMPOSITIONFONT, 0);
1489     return TRUE;
1490 }
1491 
1492 /***********************************************************************
1493  *		ImmGetConversionListA (IMM32.@)
1494  */
1495 DWORD WINAPI
1496 ImmGetConversionListA(HKL hKL, HIMC hIMC, LPCSTR pSrc, LPCANDIDATELIST lpDst,
1497                       DWORD dwBufLen, UINT uFlag)
1498 {
1499     DWORD ret = 0;
1500     UINT cb;
1501     LPWSTR pszSrcW = NULL;
1502     LPCANDIDATELIST pCL = NULL;
1503     PIMEDPI pImeDpi;
1504 
1505     TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_a(pSrc),
1506           lpDst, dwBufLen, uFlag);
1507 
1508     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1509     if (pImeDpi == NULL)
1510         return 0;
1511 
1512     if (!ImeDpi_IsUnicode(pImeDpi))
1513     {
1514         ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag);
1515         ImmUnlockImeDpi(pImeDpi);
1516         return ret;
1517     }
1518 
1519     if (pSrc)
1520     {
1521         pszSrcW = Imm32WideFromAnsi(pSrc);
1522         if (pszSrcW == NULL)
1523             goto Quit;
1524     }
1525 
1526     cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, NULL, 0, uFlag);
1527     if (cb == 0)
1528         goto Quit;
1529 
1530     pCL = ImmLocalAlloc(0, cb);
1531     if (pCL == NULL)
1532         goto Quit;
1533 
1534     cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, pCL, cb, uFlag);
1535     if (cb == 0)
1536         goto Quit;
1537 
1538     ret = CandidateListWideToAnsi(pCL, lpDst, dwBufLen, CP_ACP);
1539 
1540 Quit:
1541     ImmLocalFree(pszSrcW);
1542     ImmLocalFree(pCL);
1543     ImmUnlockImeDpi(pImeDpi);
1544     return ret;
1545 }
1546 
1547 /***********************************************************************
1548  *		ImmGetConversionListW (IMM32.@)
1549  */
1550 DWORD WINAPI
1551 ImmGetConversionListW(HKL hKL, HIMC hIMC, LPCWSTR pSrc, LPCANDIDATELIST lpDst,
1552                       DWORD dwBufLen, UINT uFlag)
1553 {
1554     DWORD ret = 0;
1555     INT cb;
1556     PIMEDPI pImeDpi;
1557     LPCANDIDATELIST pCL = NULL;
1558     LPSTR pszSrcA = NULL;
1559 
1560     TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_w(pSrc),
1561           lpDst, dwBufLen, uFlag);
1562 
1563     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1564     if (!pImeDpi)
1565         return 0;
1566 
1567     if (ImeDpi_IsUnicode(pImeDpi))
1568     {
1569         ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag);
1570         ImmUnlockImeDpi(pImeDpi);
1571         return ret;
1572     }
1573 
1574     if (pSrc)
1575     {
1576         pszSrcA = Imm32AnsiFromWide(pSrc);
1577         if (pszSrcA == NULL)
1578             goto Quit;
1579     }
1580 
1581     cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, NULL, 0, uFlag);
1582     if (cb == 0)
1583         goto Quit;
1584 
1585     pCL = ImmLocalAlloc(0, cb);
1586     if (!pCL)
1587         goto Quit;
1588 
1589     cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, pCL, cb, uFlag);
1590     if (!cb)
1591         goto Quit;
1592 
1593     ret = CandidateListAnsiToWide(pCL, lpDst, dwBufLen, CP_ACP);
1594 
1595 Quit:
1596     ImmLocalFree(pszSrcA);
1597     ImmLocalFree(pCL);
1598     ImmUnlockImeDpi(pImeDpi);
1599     return ret;
1600 }
1601 
1602 /***********************************************************************
1603  *		ImmGetConversionStatus (IMM32.@)
1604  */
1605 BOOL WINAPI ImmGetConversionStatus(HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
1606 {
1607     LPINPUTCONTEXT pIC;
1608 
1609     TRACE("(%p %p %p)\n", hIMC, lpfdwConversion, lpfdwSentence);
1610 
1611     pIC = ImmLockIMC(hIMC);
1612     if (!pIC)
1613         return FALSE;
1614 
1615     if (lpfdwConversion)
1616         *lpfdwConversion = pIC->fdwConversion;
1617     if (lpfdwSentence)
1618         *lpfdwSentence = pIC->fdwSentence;
1619 
1620     ImmUnlockIMC(hIMC);
1621     return TRUE;
1622 }
1623 
1624 /***********************************************************************
1625  *		ImmSetConversionStatus (IMM32.@)
1626  */
1627 BOOL WINAPI ImmSetConversionStatus(HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
1628 {
1629     HKL hKL;
1630     LPINPUTCONTEXT pIC;
1631     DWORD dwOldConversion, dwOldSentence;
1632     BOOL fOpen = FALSE, fConversionChange = FALSE, fSentenceChange = FALSE, fUseCicero = FALSE;
1633     HWND hWnd;
1634 
1635     TRACE("(%p, 0x%lX, 0x%lX)\n", hIMC, fdwConversion, fdwSentence);
1636 
1637     hKL = GetKeyboardLayout(0);
1638     if (!IS_IME_HKL(hKL) && Imm32IsCiceroMode() && !Imm32Is16BitMode())
1639         fUseCicero = TRUE;
1640 
1641     if (Imm32IsCrossThreadAccess(hIMC))
1642         return FALSE;
1643 
1644     pIC = ImmLockIMC(hIMC);
1645     if (pIC == NULL)
1646         return FALSE;
1647 
1648     if (pIC->fdwConversion != fdwConversion)
1649     {
1650         dwOldConversion = pIC->fdwConversion;
1651         pIC->fdwConversion = fdwConversion;
1652         fConversionChange = TRUE;
1653     }
1654 
1655     if (pIC->fdwSentence != fdwSentence)
1656     {
1657         dwOldSentence = pIC->fdwSentence;
1658         pIC->fdwSentence = fdwSentence;
1659         fSentenceChange = TRUE;
1660     }
1661 
1662     hWnd = pIC->hWnd;
1663     fOpen = pIC->fOpen;
1664     ImmUnlockIMC(hIMC);
1665 
1666     if (fConversionChange || fUseCicero)
1667     {
1668         Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldConversion,
1669                            IMC_SETCONVERSIONMODE, IMN_SETCONVERSIONMODE, 0);
1670         if (fConversionChange)
1671             NtUserNotifyIMEStatus(hWnd, fOpen, fdwConversion);
1672     }
1673 
1674     if (fSentenceChange || fUseCicero)
1675     {
1676         Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldSentence,
1677                            IMC_SETSENTENCEMODE, IMN_SETSENTENCEMODE, 0);
1678     }
1679 
1680     return TRUE;
1681 }
1682 
1683 /***********************************************************************
1684  *		ImmConfigureIMEA (IMM32.@)
1685  */
1686 BOOL WINAPI ImmConfigureIMEA(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
1687 {
1688     BOOL ret = FALSE;
1689     PIMEDPI pImeDpi;
1690     REGISTERWORDW RegWordW;
1691     LPREGISTERWORDA pRegWordA;
1692 
1693     TRACE("(%p, %p, 0x%lX, %p)", hKL, hWnd, dwMode, lpData);
1694 
1695     if (!ValidateHwnd(hWnd) || Imm32IsCrossProcessAccess(hWnd))
1696         return FALSE;
1697 
1698     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1699     if (!pImeDpi)
1700         return FALSE;
1701 
1702     RtlZeroMemory(&RegWordW, sizeof(RegWordW));
1703 
1704     if (!ImeDpi_IsUnicode(pImeDpi) || !lpData || dwMode != IME_CONFIG_REGISTERWORD)
1705         goto DoIt;
1706 
1707     pRegWordA = lpData;
1708 
1709     if (pRegWordA->lpReading)
1710     {
1711         RegWordW.lpReading = Imm32WideFromAnsi(pRegWordA->lpReading);
1712         if (!RegWordW.lpReading)
1713             goto Quit;
1714     }
1715 
1716     if (pRegWordA->lpWord)
1717     {
1718         RegWordW.lpWord = Imm32WideFromAnsi(pRegWordA->lpWord);
1719         if (!RegWordW.lpWord)
1720             goto Quit;
1721     }
1722 
1723     lpData = &RegWordW;
1724 
1725 DoIt:
1726     SendMessageW(hWnd, WM_IME_SYSTEM, 0x1B, 0);
1727     ret = pImeDpi->ImeConfigure(hKL, hWnd, dwMode, lpData);
1728     SendMessageW(hWnd, WM_IME_SYSTEM, 0x1A, 0);
1729 
1730 Quit:
1731     ImmLocalFree(RegWordW.lpReading);
1732     ImmLocalFree(RegWordW.lpWord);
1733     ImmUnlockImeDpi(pImeDpi);
1734     return ret;
1735 }
1736 
1737 /***********************************************************************
1738  *		ImmConfigureIMEW (IMM32.@)
1739  */
1740 BOOL WINAPI ImmConfigureIMEW(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
1741 {
1742     BOOL ret = FALSE;
1743     PIMEDPI pImeDpi;
1744     REGISTERWORDA RegWordA;
1745     LPREGISTERWORDW pRegWordW;
1746 
1747     TRACE("(%p, %p, 0x%lX, %p)", hKL, hWnd, dwMode, lpData);
1748 
1749     if (!ValidateHwnd(hWnd) || Imm32IsCrossProcessAccess(hWnd))
1750         return FALSE;
1751 
1752     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1753     if (!pImeDpi)
1754         return FALSE;
1755 
1756     RtlZeroMemory(&RegWordA, sizeof(RegWordA));
1757 
1758     if (ImeDpi_IsUnicode(pImeDpi) || !lpData || dwMode != IME_CONFIG_REGISTERWORD)
1759         goto DoIt;
1760 
1761     pRegWordW = lpData;
1762 
1763     if (pRegWordW->lpReading)
1764     {
1765         RegWordA.lpReading = Imm32AnsiFromWide(pRegWordW->lpReading);
1766         if (!RegWordA.lpReading)
1767             goto Quit;
1768     }
1769 
1770     if (pRegWordW->lpWord)
1771     {
1772         RegWordA.lpWord = Imm32AnsiFromWide(pRegWordW->lpWord);
1773         if (!RegWordA.lpWord)
1774             goto Quit;
1775     }
1776 
1777     lpData = &RegWordA;
1778 
1779 DoIt:
1780     SendMessageW(hWnd, WM_IME_SYSTEM, 0x1B, 0);
1781     ret = pImeDpi->ImeConfigure(hKL, hWnd, dwMode, lpData);
1782     SendMessageW(hWnd, WM_IME_SYSTEM, 0x1A, 0);
1783 
1784 Quit:
1785     ImmLocalFree(RegWordA.lpReading);
1786     ImmLocalFree(RegWordA.lpWord);
1787     ImmUnlockImeDpi(pImeDpi);
1788     return ret;
1789 }
1790 
1791 /***********************************************************************
1792  *		ImmGetImeMenuItemsA (IMM32.@)
1793  */
1794 DWORD WINAPI
1795 ImmGetImeMenuItemsA(HIMC hIMC, DWORD dwFlags, DWORD dwType,
1796                     LPIMEMENUITEMINFOA lpImeParentMenu,
1797                     LPIMEMENUITEMINFOA lpImeMenu, DWORD dwSize)
1798 {
1799     TRACE("(%p, 0x%lX, 0x%lX, %p, %p, 0x%lX)\n",
1800           hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize);
1801     return ImmGetImeMenuItemsAW(hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize, TRUE);
1802 }
1803 
1804 /***********************************************************************
1805  *		ImmGetImeMenuItemsW (IMM32.@)
1806  */
1807 DWORD WINAPI
1808 ImmGetImeMenuItemsW(HIMC hIMC, DWORD dwFlags, DWORD dwType,
1809                     LPIMEMENUITEMINFOW lpImeParentMenu,
1810                     LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize)
1811 {
1812     TRACE("(%p, 0x%lX, 0x%lX, %p, %p, 0x%lX)\n",
1813           hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize);
1814     return ImmGetImeMenuItemsAW(hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize, FALSE);
1815 }
1816