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