xref: /reactos/dll/win32/imm32/ime.c (revision 09dde2cf)
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 (GetWin32ClientInfo()->dwTIFlags & TIF_16BIT)
58         dwSysInfoFlags |= IME_SYSINFO_WOW16;
59 
60     if (IS_IME_HKL(pImeDpi->hKL))
61     {
62         if (!pImeDpi->ImeInquire(pImeInfo, szUIClass, dwSysInfoFlags))
63         {
64             ERR("\n");
65             return FALSE;
66         }
67     }
68     else if (IS_CICERO_MODE() && !IS_16BIT_MODE())
69     {
70         if (!pImeDpi->CtfImeInquireExW(pImeInfo, szUIClass, dwSysInfoFlags, pImeDpi->hKL))
71         {
72             ERR("\n");
73             return FALSE;
74         }
75     }
76     else
77     {
78         ERR("\n");
79         return FALSE;
80     }
81 
82     szUIClass[_countof(szUIClass) - 1] = UNICODE_NULL; /* Avoid buffer overrun */
83 
84     if (pImeInfo->dwPrivateDataSize < sizeof(DWORD))
85         pImeInfo->dwPrivateDataSize = sizeof(DWORD);
86 
87 #define VALID_IME_PROP (IME_PROP_AT_CARET              | \
88                         IME_PROP_SPECIAL_UI            | \
89                         IME_PROP_CANDLIST_START_FROM_1 | \
90                         IME_PROP_UNICODE               | \
91                         IME_PROP_COMPLETE_ON_UNSELECT  | \
92                         IME_PROP_END_UNLOAD            | \
93                         IME_PROP_KBD_CHAR_FIRST        | \
94                         IME_PROP_IGNORE_UPKEYS         | \
95                         IME_PROP_NEED_ALTKEY           | \
96                         IME_PROP_NO_KEYS_ON_CLOSE      | \
97                         IME_PROP_ACCEPT_WIDE_VKEY)
98 #define VALID_CMODE_CAPS (IME_CMODE_ALPHANUMERIC | \
99                           IME_CMODE_NATIVE       | \
100                           IME_CMODE_KATAKANA     | \
101                           IME_CMODE_LANGUAGE     | \
102                           IME_CMODE_FULLSHAPE    | \
103                           IME_CMODE_ROMAN        | \
104                           IME_CMODE_CHARCODE     | \
105                           IME_CMODE_HANJACONVERT | \
106                           IME_CMODE_SOFTKBD      | \
107                           IME_CMODE_NOCONVERSION | \
108                           IME_CMODE_EUDC         | \
109                           IME_CMODE_SYMBOL       | \
110                           IME_CMODE_FIXED)
111 #define VALID_SMODE_CAPS (IME_SMODE_NONE          | \
112                           IME_SMODE_PLAURALCLAUSE | \
113                           IME_SMODE_SINGLECONVERT | \
114                           IME_SMODE_AUTOMATIC     | \
115                           IME_SMODE_PHRASEPREDICT | \
116                           IME_SMODE_CONVERSATION)
117 #define VALID_UI_CAPS (UI_CAP_2700    | \
118                        UI_CAP_ROT90   | \
119                        UI_CAP_ROTANY  | \
120                        UI_CAP_SOFTKBD)
121 #define VALID_SCS_CAPS (SCS_CAP_COMPSTR            | \
122                         SCS_CAP_MAKEREAD           | \
123                         SCS_CAP_SETRECONVERTSTRING)
124 #define VALID_SELECT_CAPS (SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE)
125 
126     if (pImeInfo->fdwProperty & ~VALID_IME_PROP)
127     {
128         ERR("Bad flags\n");
129         return FALSE;
130     }
131     if (pImeInfo->fdwConversionCaps & ~VALID_CMODE_CAPS)
132     {
133         ERR("Bad flags\n");
134         return FALSE;
135     }
136     if (pImeInfo->fdwSentenceCaps & ~VALID_SMODE_CAPS)
137     {
138         ERR("Bad flags\n");
139         return FALSE;
140     }
141     if (pImeInfo->fdwUICaps & ~VALID_UI_CAPS)
142     {
143         ERR("Bad flags\n");
144         return FALSE;
145     }
146     if (pImeInfo->fdwSCSCaps & ~VALID_SCS_CAPS)
147     {
148         ERR("Bad flags\n");
149         return FALSE;
150     }
151     if (pImeInfo->fdwSelectCaps & ~VALID_SELECT_CAPS)
152     {
153         ERR("Bad flags\n");
154         return FALSE;
155     }
156 
157 #undef VALID_IME_PROP
158 #undef VALID_CMODE_CAPS
159 #undef VALID_SMODE_CAPS
160 #undef VALID_UI_CAPS
161 #undef VALID_SCS_CAPS
162 #undef VALID_SELECT_CAPS
163 
164     if (pImeInfo->fdwProperty & IME_PROP_UNICODE)
165     {
166         StringCchCopyW(pImeDpi->szUIClass, _countof(pImeDpi->szUIClass), szUIClass);
167     }
168     else
169     {
170         if (pImeDpi->uCodePage != GetACP() && pImeDpi->uCodePage != CP_ACP)
171             return FALSE;
172 
173         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPSTR)szUIClass, -1,
174                             pImeDpi->szUIClass, _countof(pImeDpi->szUIClass));
175 
176         pImeDpi->szUIClass[_countof(pImeDpi->szUIClass) - 1] = UNICODE_NULL;
177     }
178 
179     if (!GetClassInfoW(pImeDpi->hInst, pImeDpi->szUIClass, &wcW))
180     {
181         ERR("\n");
182         return FALSE;
183     }
184 
185     return TRUE;
186 }
187 
188 /* Define stub IME functions */
189 #define DEFINE_IME_ENTRY(type, name, params, optional) \
190     type APIENTRY Stub##name params { \
191         FIXME("%s: Why stub called?\n", #name); \
192         return (type)0; \
193     }
194 #include "imetable.h"
195 #undef DEFINE_IME_ENTRY
196 
197 // Win: LoadIME
198 BOOL APIENTRY Imm32LoadIME(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi)
199 {
200     WCHAR szPath[MAX_PATH];
201     HINSTANCE hIME;
202     FARPROC fn;
203     BOOL ret = FALSE;
204 
205     if (!Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile))
206         return FALSE;
207 
208     pImeDpi->hInst = hIME = LoadLibraryW(szPath);
209     if (hIME == NULL)
210     {
211         ERR("LoadLibraryW(%s) failed\n", debugstr_w(szPath));
212         return FALSE;
213     }
214 
215     /* Populate the table by stub IME functions */
216 #define DEFINE_IME_ENTRY(type, name, params, optional) pImeDpi->name = Stub##name;
217 #include "imetable.h"
218 #undef DEFINE_IME_ENTRY
219 
220     /* Populate the table by real IME functions */
221 #define DEFINE_IME_ENTRY(type, name, params, optional) \
222     do { \
223         fn = GetProcAddress(hIME, #name); \
224         if (fn) pImeDpi->name = (FN_##name)fn; \
225         else if (!(optional)) { \
226             ERR("'%s' not found in IME module '%s'.\n", #name, debugstr_w(szPath)); \
227             goto Failed; \
228         } \
229     } while (0);
230 #include "imetable.h"
231 #undef DEFINE_IME_ENTRY
232 
233     if (Imm32InquireIme(pImeDpi))
234     {
235         ret = TRUE;
236     }
237     else
238     {
239 Failed:
240         ret = FALSE;
241         FreeLibrary(pImeDpi->hInst);
242         pImeDpi->hInst = NULL;
243     }
244 
245     if (pImeInfoEx->fLoadFlag == 0)
246     {
247         if (ret)
248         {
249             C_ASSERT(sizeof(pImeInfoEx->wszUIClass) == sizeof(pImeDpi->szUIClass));
250             pImeInfoEx->ImeInfo = pImeDpi->ImeInfo;
251             RtlCopyMemory(pImeInfoEx->wszUIClass, pImeDpi->szUIClass,
252                           sizeof(pImeInfoEx->wszUIClass));
253             pImeInfoEx->fLoadFlag = 2;
254         }
255         else
256         {
257             pImeInfoEx->fLoadFlag = 1;
258         }
259 
260         NtUserSetImeInfoEx(pImeInfoEx);
261     }
262 
263     return ret;
264 }
265 
266 // Win: LoadImeDpi
267 PIMEDPI APIENTRY Imm32LoadImeDpi(HKL hKL, BOOL bLock)
268 {
269     IMEINFOEX ImeInfoEx;
270     CHARSETINFO ci;
271     PIMEDPI pImeDpiNew, pImeDpiFound;
272     UINT uCodePage;
273     LCID lcid;
274 
275     if (!IS_IME_HKL(hKL))
276     {
277         TRACE("\n");
278         return NULL;
279     }
280 
281     if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL))
282     {
283         ERR("\n");
284         return NULL;
285     }
286 
287     if (ImeInfoEx.fLoadFlag == 1)
288     {
289         ERR("\n");
290         return NULL;
291     }
292 
293     pImeDpiNew = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(IMEDPI));
294     if (IS_NULL_UNEXPECTEDLY(pImeDpiNew))
295         return NULL;
296 
297     pImeDpiNew->hKL = hKL;
298 
299     lcid = LOWORD(hKL);
300     if (TranslateCharsetInfo((LPDWORD)(DWORD_PTR)lcid, &ci, TCI_SRCLOCALE))
301         uCodePage = ci.ciACP;
302     else
303         uCodePage = CP_ACP;
304     pImeDpiNew->uCodePage = uCodePage;
305 
306     if (!Imm32LoadIME(&ImeInfoEx, pImeDpiNew))
307     {
308         ERR("\n");
309         ImmLocalFree(pImeDpiNew);
310         return FALSE;
311     }
312 
313     RtlEnterCriticalSection(&gcsImeDpi);
314 
315     pImeDpiFound = Imm32FindImeDpi(hKL);
316     if (pImeDpiFound)
317     {
318         if (!bLock)
319             pImeDpiFound->dwFlags &= ~IMEDPI_FLAG_LOCKED;
320 
321         RtlLeaveCriticalSection(&gcsImeDpi);
322         Imm32FreeIME(pImeDpiNew, FALSE);
323         ImmLocalFree(pImeDpiNew);
324         return pImeDpiFound;
325     }
326     else
327     {
328         if (bLock)
329         {
330             pImeDpiNew->dwFlags |= IMEDPI_FLAG_LOCKED;
331             pImeDpiNew->cLockObj = 1;
332         }
333 
334         pImeDpiNew->pNext = gpImeDpiList;
335         gpImeDpiList = pImeDpiNew;
336 
337         RtlLeaveCriticalSection(&gcsImeDpi);
338         return pImeDpiNew;
339     }
340 }
341 
342 // Win: FindOrLoadImeDpi
343 PIMEDPI APIENTRY Imm32FindOrLoadImeDpi(HKL hKL)
344 {
345     PIMEDPI pImeDpi;
346 
347     if (!IS_IME_HKL(hKL) && (!IS_CICERO_MODE() || IS_16BIT_MODE()))
348     {
349         TRACE("\n");
350         return NULL;
351     }
352 
353     pImeDpi = ImmLockImeDpi(hKL);
354     if (pImeDpi == NULL)
355         pImeDpi = Imm32LoadImeDpi(hKL, TRUE);
356     return pImeDpi;
357 }
358 
359 static LRESULT APIENTRY
360 ImeDpi_Escape(PIMEDPI pImeDpi, HIMC hIMC, UINT uSubFunc, LPVOID lpData, HKL hKL)
361 {
362     if (IS_IME_HKL(hKL))
363         return pImeDpi->ImeEscape(hIMC, uSubFunc, lpData);
364     if (IS_CICERO_MODE() && !IS_16BIT_MODE())
365         return pImeDpi->CtfImeEscapeEx(hIMC, uSubFunc, lpData, hKL);
366 
367     return 0;
368 }
369 
370 // Win: ImmUnloadIME
371 BOOL APIENTRY Imm32ReleaseIME(HKL hKL)
372 {
373     BOOL ret = TRUE;
374     PIMEDPI pImeDpi0, pImeDpi1;
375 
376     RtlEnterCriticalSection(&gcsImeDpi);
377 
378     for (pImeDpi0 = gpImeDpiList; pImeDpi0; pImeDpi0 = pImeDpi0->pNext)
379     {
380         if (pImeDpi0->hKL == hKL)
381             break;
382     }
383 
384     if (!pImeDpi0)
385         goto Quit;
386 
387     if (pImeDpi0->cLockObj)
388     {
389         pImeDpi0->dwFlags |= IMEDPI_FLAG_UNLOADED;
390         ret = FALSE;
391         goto Quit;
392     }
393 
394     if (gpImeDpiList == pImeDpi0)
395     {
396         gpImeDpiList = pImeDpi0->pNext;
397     }
398     else if (gpImeDpiList)
399     {
400         for (pImeDpi1 = gpImeDpiList; pImeDpi1; pImeDpi1 = pImeDpi1->pNext)
401         {
402             if (pImeDpi1->pNext == pImeDpi0)
403             {
404                 pImeDpi1->pNext = pImeDpi0->pNext;
405                 break;
406             }
407         }
408     }
409 
410     Imm32FreeIME(pImeDpi0, TRUE);
411     ImmLocalFree(pImeDpi0);
412 
413 Quit:
414     RtlLeaveCriticalSection(&gcsImeDpi);
415     return ret;
416 }
417 
418 // We will transport the IME menu items by using a flat memory block via
419 // a file mapping object beyond the boundary of a process.
420 
421 #define MAX_IMEMENU_BITMAP_BYTES 0xF00
422 
423 typedef struct tagIMEMENUITEM
424 {
425     IMEMENUITEMINFOW Info;
426     BYTE abChecked[MAX_IMEMENU_BITMAP_BYTES];
427     BYTE abUnchecked[MAX_IMEMENU_BITMAP_BYTES];
428     BYTE abItem[MAX_IMEMENU_BITMAP_BYTES];
429 } IMEMENUITEM, *PIMEMENUITEM;
430 
431 typedef struct tagIMEMENU
432 {
433     DWORD dwVersion;
434     DWORD dwFlags;
435     DWORD dwType;
436     DWORD dwItemCount;
437     IMEMENUITEMINFOW Parent;
438     IMEMENUITEM Items[ANYSIZE_ARRAY];
439 } IMEMENU, *PIMEMENU;
440 
441 /***********************************************************************
442  *		ImmPutImeMenuItemsIntoMappedFile (IMM32.@)
443  *
444  * Called from user32.dll to transport the IME menu items by using a
445  * file mapping object. This function is provided for WM_IME_SYSTEM:IMS_GETIMEMENU
446  * handling.
447  */
448 LRESULT WINAPI ImmPutImeMenuItemsIntoMappedFile(HIMC hIMC)
449 {
450     LRESULT ret = FALSE;
451     HANDLE hMapping;
452     PIMEMENU pView;
453     LPIMEMENUITEMINFOW pParent = NULL, pItems = NULL;
454     DWORD i, cItems, cbItems = 0;
455 
456     hMapping = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"ImmMenuInfo");
457     pView = MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
458     if (IS_NULL_UNEXPECTEDLY(pView))
459         goto Quit;
460 
461     if (pView->dwVersion != 1)
462     {
463         ERR("\n");
464         goto Quit;
465     }
466 
467     if (pView->Parent.cbSize > 0)
468         pParent = &pView->Parent;
469 
470     if (pView->dwItemCount > 0)
471     {
472         cbItems = pView->dwItemCount * sizeof(IMEMENUITEMINFOW);
473         pItems = ImmLocalAlloc(HEAP_ZERO_MEMORY, cbItems);
474         if (IS_NULL_UNEXPECTEDLY(pItems))
475             goto Quit;
476     }
477 
478     cItems = ImmGetImeMenuItemsW(hIMC, pView->dwFlags, pView->dwType, pParent, pItems, cbItems);
479     pView->dwItemCount = cItems;
480     if (IS_ZERO_UNEXPECTEDLY(cItems))
481         goto Quit;
482 
483     if (pItems)
484     {
485         for (i = 0; i < cItems; ++i)
486         {
487             pView->Items[i].Info = pItems[i];
488 
489             // store bitmaps to bytes
490             if (pItems[i].hbmpChecked)
491             {
492                 Imm32StoreBitmapToBytes(pItems[i].hbmpChecked, pView->Items[i].abChecked,
493                                         MAX_IMEMENU_BITMAP_BYTES);
494                 DeleteObject(pItems[i].hbmpChecked);
495             }
496             if (pItems[i].hbmpUnchecked)
497             {
498                 Imm32StoreBitmapToBytes(pItems[i].hbmpUnchecked, pView->Items[i].abUnchecked,
499                                         MAX_IMEMENU_BITMAP_BYTES);
500                 DeleteObject(pItems[i].hbmpUnchecked);
501             }
502             if (pItems[i].hbmpItem)
503             {
504                 Imm32StoreBitmapToBytes(pItems[i].hbmpItem, pView->Items[i].abItem,
505                                         MAX_IMEMENU_BITMAP_BYTES);
506                 DeleteObject(pItems[i].hbmpItem);
507             }
508         }
509     }
510 
511     ret = TRUE;
512 
513 Quit:
514     if (pItems)
515         ImmLocalFree(pItems);
516     if (pView)
517         UnmapViewOfFile(pView);
518     if (hMapping)
519         CloseHandle(hMapping);
520     return ret;
521 }
522 
523 // Win: ImmGetImeMenuItemsInterProcess
524 DWORD APIENTRY
525 Imm32GetImeMenuItemWInterProcess(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPVOID lpImeParentMenu,
526                                  LPVOID lpImeMenu, DWORD dwSize)
527 {
528     HANDLE hMapping;
529     PIMEMENU pView;
530     DWORD i, cbView, dwItemCount, ret = 0;
531     HWND hImeWnd;
532     PIMEMENUITEM pGotItem;
533     LPIMEMENUITEMINFOW pSetInfo;
534 
535     hImeWnd = (HWND)NtUserQueryInputContext(hIMC, QIC_DEFAULTWINDOWIME);
536     if (!hImeWnd || !IsWindow(hImeWnd))
537     {
538         ERR("\n");
539         return 0;
540     }
541 
542     dwItemCount = (lpImeMenu ? (dwSize / sizeof(IMEMENUITEMINFOW)) : 0);
543     cbView = sizeof(IMEMENU) + ((size_t)dwItemCount - 1) * sizeof(IMEMENUITEM);
544 
545     RtlEnterCriticalSection(&gcsImeDpi);
546 
547     // create a file mapping
548     hMapping = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
549                                   0, cbView, L"ImmMenuInfo");
550     pView = MapViewOfFile(hMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
551     if (IS_NULL_UNEXPECTEDLY(pView))
552         goto Quit;
553 
554     ZeroMemory(pView, cbView);
555     pView->dwVersion = 1;
556     pView->dwFlags = dwFlags;
557     pView->dwType = dwType;
558     pView->dwItemCount = dwItemCount;
559     if (lpImeParentMenu)
560     {
561         pView->Parent = *(LPIMEMENUITEMINFOW)lpImeParentMenu;
562         pView->Parent.cbSize = sizeof(IMEMENUITEMINFOW);
563     }
564 
565     if (!SendMessageW(hImeWnd, WM_IME_SYSTEM, IMS_GETIMEMENU, (LPARAM)hIMC))
566     {
567         ERR("\n");
568         goto Quit;
569     }
570 
571     ret = pView->dwItemCount;
572 
573     if (!lpImeMenu)
574         goto Quit;
575 
576     for (i = 0; i < ret; ++i)
577     {
578         pGotItem = &(pView->Items[i]);
579         pSetInfo = &((LPIMEMENUITEMINFOW)lpImeMenu)[i];
580 
581         *pSetInfo = pGotItem->Info;
582 
583         // load bitmaps from bytes
584         if (pSetInfo->hbmpChecked)
585         {
586             pSetInfo->hbmpChecked = Imm32LoadBitmapFromBytes(pGotItem->abChecked);
587         }
588         if (pSetInfo->hbmpUnchecked)
589         {
590             pSetInfo->hbmpUnchecked = Imm32LoadBitmapFromBytes(pGotItem->abUnchecked);
591         }
592         if (pSetInfo->hbmpItem)
593         {
594             pSetInfo->hbmpItem = Imm32LoadBitmapFromBytes(pGotItem->abItem);
595         }
596     }
597 
598 Quit:
599     RtlLeaveCriticalSection(&gcsImeDpi);
600     if (pView)
601         UnmapViewOfFile(pView);
602     if (hMapping)
603         CloseHandle(hMapping);
604     return ret;
605 }
606 
607 // Win: ImmGetImeMenuItemsWorker
608 DWORD APIENTRY
609 ImmGetImeMenuItemsAW(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPVOID lpImeParentMenu,
610                      LPVOID lpImeMenu, DWORD dwSize, BOOL bTargetIsAnsi)
611 {
612     DWORD ret = 0, cbTotal, dwProcessId, dwThreadId, iItem;
613     LPINPUTCONTEXT pIC;
614     PIMEDPI pImeDpi = NULL;
615     IMEMENUITEMINFOA ParentA;
616     IMEMENUITEMINFOW ParentW;
617     LPIMEMENUITEMINFOA pItemA;
618     LPIMEMENUITEMINFOW pItemW;
619     LPVOID pNewItems = NULL, pNewParent = NULL;
620     BOOL bImcIsAnsi;
621     HKL hKL;
622 
623     if (IS_NULL_UNEXPECTEDLY(hIMC))
624         return 0;
625 
626     dwProcessId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTPROCESSID);
627     if (IS_ZERO_UNEXPECTEDLY(dwProcessId))
628         return 0;
629 
630     if (dwProcessId != GetCurrentProcessId())
631     {
632         if (bTargetIsAnsi)
633             return 0;
634         return Imm32GetImeMenuItemWInterProcess(hIMC, dwFlags, dwType, lpImeParentMenu,
635                                                 lpImeMenu, dwSize);
636     }
637 
638     pIC = ImmLockIMC(hIMC);
639     if (IS_NULL_UNEXPECTEDLY(pIC))
640         return 0;
641 
642     dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
643     if (IS_ZERO_UNEXPECTEDLY(dwThreadId))
644     {
645         ImmUnlockIMC(hIMC);
646         return 0;
647     }
648 
649     hKL = GetKeyboardLayout(dwThreadId);
650     pImeDpi = ImmLockImeDpi(hKL);
651     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
652     {
653         ImmUnlockIMC(hIMC);
654         return 0;
655     }
656 
657     bImcIsAnsi = Imm32IsImcAnsi(hIMC);
658 
659     if (bImcIsAnsi != bTargetIsAnsi)
660     {
661         if (bTargetIsAnsi)
662         {
663             if (lpImeParentMenu)
664                 pNewParent = &ParentW;
665 
666             if (lpImeMenu)
667             {
668                 cbTotal = ((dwSize / sizeof(IMEMENUITEMINFOA)) * sizeof(IMEMENUITEMINFOW));
669                 pNewItems = ImmLocalAlloc(0, cbTotal);
670                 if (IS_NULL_UNEXPECTEDLY(pNewItems))
671                     goto Quit;
672             }
673         }
674         else
675         {
676             if (lpImeParentMenu)
677                 pNewParent = &ParentA;
678 
679             if (lpImeMenu)
680             {
681                 cbTotal = ((dwSize / sizeof(IMEMENUITEMINFOW)) * sizeof(IMEMENUITEMINFOA));
682                 pNewItems = ImmLocalAlloc(0, cbTotal);
683                 if (IS_NULL_UNEXPECTEDLY(pNewItems))
684                     goto Quit;
685             }
686         }
687     }
688     else
689     {
690         pNewItems = lpImeMenu;
691         pNewParent = lpImeParentMenu;
692     }
693 
694     ret = pImeDpi->ImeGetImeMenuItems(hIMC, dwFlags, dwType, pNewParent, pNewItems, dwSize);
695     if (IS_ZERO_UNEXPECTEDLY(ret) || !lpImeMenu)
696         goto Quit;
697 
698     if (bImcIsAnsi != bTargetIsAnsi)
699     {
700         if (bTargetIsAnsi)
701         {
702             if (pNewParent)
703                 Imm32ImeMenuWideToAnsi(pNewParent, lpImeParentMenu, pImeDpi->uCodePage);
704 
705             pItemW = pNewItems;
706             pItemA = lpImeMenu;
707             for (iItem = 0; iItem < ret; ++iItem, ++pItemW, ++pItemA)
708             {
709                 if (!Imm32ImeMenuWideToAnsi(pItemW, pItemA, pImeDpi->uCodePage))
710                 {
711                     ERR("\n");
712                     ret = 0;
713                     break;
714                 }
715             }
716         }
717         else
718         {
719             if (pNewParent)
720                 Imm32ImeMenuAnsiToWide(pNewParent, lpImeParentMenu, pImeDpi->uCodePage, TRUE);
721 
722             pItemA = pNewItems;
723             pItemW = lpImeMenu;
724             for (iItem = 0; iItem < dwSize; ++iItem, ++pItemA, ++pItemW)
725             {
726                 if (!Imm32ImeMenuAnsiToWide(pItemA, pItemW, pImeDpi->uCodePage, TRUE))
727                 {
728                     ERR("\n");
729                     ret = 0;
730                     break;
731                 }
732             }
733         }
734     }
735 
736 Quit:
737     if (pNewItems != lpImeMenu)
738         ImmLocalFree(pNewItems);
739     ImmUnlockImeDpi(pImeDpi);
740     ImmUnlockIMC(hIMC);
741     TRACE("ret: 0x%X\n", ret);
742     return ret;
743 }
744 
745 /***********************************************************************
746  *		ImmInstallIMEA (IMM32.@)
747  */
748 HKL WINAPI ImmInstallIMEA(LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
749 {
750     HKL hKL = NULL;
751     LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL;
752 
753     TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText));
754 
755     pszFileNameW = Imm32WideFromAnsi(CP_ACP, lpszIMEFileName);
756     if (IS_NULL_UNEXPECTEDLY(pszFileNameW))
757         goto Quit;
758 
759     pszLayoutTextW = Imm32WideFromAnsi(CP_ACP, lpszLayoutText);
760     if (IS_NULL_UNEXPECTEDLY(pszLayoutTextW))
761         goto Quit;
762 
763     hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW);
764 
765 Quit:
766     ImmLocalFree(pszFileNameW);
767     ImmLocalFree(pszLayoutTextW);
768     return hKL;
769 }
770 
771 /***********************************************************************
772  *		ImmInstallIMEW (IMM32.@)
773  */
774 HKL WINAPI ImmInstallIMEW(LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
775 {
776     WCHAR szImeFileName[MAX_PATH], szImeDestPath[MAX_PATH], szImeKey[20];
777     IMEINFOEX InfoEx;
778     LPWSTR pchFilePart;
779     UINT iLayout, cLayouts;
780     HKL hNewKL;
781     WORD wLangID;
782     PREG_IME pLayouts = NULL;
783 
784     TRACE("(%s, %s)\n", debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText));
785 
786     GetFullPathNameW(lpszIMEFileName, _countof(szImeFileName), szImeFileName, &pchFilePart);
787     CharUpperW(szImeFileName);
788     if (IS_NULL_UNEXPECTEDLY(pchFilePart))
789         return NULL;
790 
791     /* Load the IME version info */
792     InfoEx.hkl = hNewKL = NULL;
793     StringCchCopyW(InfoEx.wszImeFile, _countof(InfoEx.wszImeFile), pchFilePart);
794     if (!Imm32LoadImeVerInfo(&InfoEx) || !InfoEx.hkl)
795     {
796         ERR("\n");
797         return NULL;
798     }
799     wLangID = LOWORD(InfoEx.hkl);
800 
801     /* Get the IME layouts from registry */
802     cLayouts = Imm32GetImeLayout(NULL, 0);
803     if (cLayouts)
804     {
805         pLayouts = ImmLocalAlloc(0, cLayouts * sizeof(REG_IME));
806         if (IS_NULL_UNEXPECTEDLY(pLayouts))
807             return NULL;
808 
809         if (!Imm32GetImeLayout(pLayouts, cLayouts))
810         {
811             ERR("\n");
812             ImmLocalFree(pLayouts);
813             return NULL;
814         }
815 
816         for (iLayout = 0; iLayout < cLayouts; ++iLayout)
817         {
818             if (lstrcmpiW(pLayouts[iLayout].szFileName, pchFilePart) == 0)
819             {
820                 if (wLangID != LOWORD(pLayouts[iLayout].hKL))
821                 {
822                     ERR("\n");
823                     goto Quit; /* The language is different */
824                 }
825 
826                 hNewKL = pLayouts[iLayout].hKL; /* Found */
827                 break;
828             }
829         }
830     }
831 
832     /* If the IME for the specified filename is valid, then unload it now */
833     if (ImmGetImeInfoEx(&InfoEx, ImeInfoExImeFileName, pchFilePart) &&
834         !UnloadKeyboardLayout(InfoEx.hkl))
835     {
836         ERR("\n");
837         hNewKL = NULL;
838         goto Quit;
839     }
840 
841     Imm32GetSystemLibraryPath(szImeDestPath, _countof(szImeDestPath), pchFilePart);
842     CharUpperW(szImeDestPath);
843 
844     /* If the source and the destination pathnames were different, then copy the IME file */
845     if (lstrcmpiW(szImeFileName, szImeDestPath) != 0 &&
846         !Imm32CopyImeFile(szImeFileName, szImeDestPath))
847     {
848         ERR("\n");
849         hNewKL = NULL;
850         goto Quit;
851     }
852 
853     if (hNewKL == NULL)
854         hNewKL = Imm32AssignNewLayout(cLayouts, pLayouts, wLangID);
855 
856     if (hNewKL)
857     {
858         /* Write the IME layout to registry */
859         if (Imm32WriteImeLayout(hNewKL, pchFilePart, lpszLayoutText))
860         {
861             /* Load the keyboard layout */
862             StringCchPrintfW(szImeKey, _countof(szImeKey), L"%08X", (DWORD)(DWORD_PTR)hNewKL);
863             hNewKL = LoadKeyboardLayoutW(szImeKey, KLF_REPLACELANG);
864         }
865         else
866         {
867             ERR("\n");
868             hNewKL = NULL;
869         }
870     }
871 
872 Quit:
873     ImmLocalFree(pLayouts);
874     return hNewKL;
875 }
876 
877 /***********************************************************************
878  *		ImmIsIME (IMM32.@)
879  */
880 BOOL WINAPI ImmIsIME(HKL hKL)
881 {
882     IMEINFOEX info;
883     TRACE("(%p)\n", hKL);
884     return !!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayoutTFS, &hKL);
885 }
886 
887 /***********************************************************************
888  *		ImmGetDefaultIMEWnd (IMM32.@)
889  */
890 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
891 {
892     if (!IS_IMM_MODE())
893     {
894         TRACE("\n");
895         return NULL;
896     }
897 
898     if (hWnd == NULL)
899         return (HWND)NtUserGetThreadState(THREADSTATE_DEFAULTIMEWINDOW);
900 
901     return (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_IME);
902 }
903 
904 /***********************************************************************
905  *		ImmNotifyIME (IMM32.@)
906  */
907 BOOL WINAPI ImmNotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
908 {
909     HKL hKL;
910     PIMEDPI pImeDpi;
911     BOOL ret;
912 
913     TRACE("(%p, %lu, %lu, %lu)\n", hIMC, dwAction, dwIndex, dwValue);
914 
915     if (hIMC && IS_CROSS_THREAD_HIMC(hIMC))
916         return FALSE;
917 
918     hKL = GetKeyboardLayout(0);
919     pImeDpi = ImmLockImeDpi(hKL);
920     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
921         return FALSE;
922 
923     ret = pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue);
924     ImmUnlockImeDpi(pImeDpi);
925     return ret;
926 }
927 
928 /***********************************************************************
929  *              ImmDisableLegacyIME(IMM32.@)
930  */
931 BOOL WINAPI ImmDisableLegacyIME(void)
932 {
933     FIXME("stub\n");
934     return TRUE;
935 }
936 
937 /***********************************************************************
938  *              ImmGetImeInfoEx (IMM32.@)
939  */
940 BOOL WINAPI
941 ImmGetImeInfoEx(PIMEINFOEX pImeInfoEx, IMEINFOEXCLASS SearchType, PVOID pvSearchKey)
942 {
943     HKL hKL;
944     if (SearchType == ImeInfoExKeyboardLayout || SearchType == ImeInfoExKeyboardLayoutTFS)
945     {
946         hKL = *(HKL*)pvSearchKey;
947         pImeInfoEx->hkl = hKL;
948 
949         if (SearchType == ImeInfoExKeyboardLayoutTFS)
950         {
951             if (!IS_IME_HKL(hKL))
952             {
953                 if (CtfImmIsTextFrameServiceDisabled() || !IS_CICERO_MODE() || IS_16BIT_MODE())
954                 {
955                     TRACE("\n");
956                     return FALSE;
957                 }
958             }
959 
960             SearchType = ImeInfoExKeyboardLayout;
961         }
962         else
963         {
964             if (!IS_IME_HKL(hKL))
965             {
966                 TRACE("\n");
967                 return FALSE;
968             }
969         }
970     }
971     else if (SearchType == ImeInfoExImeFileName)
972     {
973         StringCchCopyW(pImeInfoEx->wszImeFile, _countof(pImeInfoEx->wszImeFile),
974                        pvSearchKey);
975     }
976     else
977     {
978         return FALSE;
979     }
980 
981     return NtUserGetImeInfoEx(pImeInfoEx, SearchType);
982 }
983 
984 /***********************************************************************
985  *		ImmLockImeDpi (IMM32.@)
986  */
987 PIMEDPI WINAPI ImmLockImeDpi(HKL hKL)
988 {
989     PIMEDPI pImeDpi = NULL;
990 
991     TRACE("(%p)\n", hKL);
992 
993     RtlEnterCriticalSection(&gcsImeDpi);
994 
995     /* Find by hKL */
996     for (pImeDpi = gpImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext)
997     {
998         if (pImeDpi->hKL == hKL) /* found */
999         {
1000             /* lock if possible */
1001             if (pImeDpi->dwFlags & IMEDPI_FLAG_UNLOADED)
1002                 pImeDpi = NULL;
1003             else
1004                 ++(pImeDpi->cLockObj);
1005             break;
1006         }
1007     }
1008 
1009     RtlLeaveCriticalSection(&gcsImeDpi);
1010     return pImeDpi;
1011 }
1012 
1013 /***********************************************************************
1014  *		ImmUnlockImeDpi (IMM32.@)
1015  */
1016 VOID WINAPI ImmUnlockImeDpi(PIMEDPI pImeDpi)
1017 {
1018     PIMEDPI *ppEntry;
1019 
1020     TRACE("(%p)\n", pImeDpi);
1021 
1022     if (pImeDpi == NULL)
1023         return;
1024 
1025     RtlEnterCriticalSection(&gcsImeDpi);
1026 
1027     /* unlock */
1028     --(pImeDpi->cLockObj);
1029     if (pImeDpi->cLockObj != 0)
1030     {
1031         RtlLeaveCriticalSection(&gcsImeDpi);
1032         return;
1033     }
1034 
1035     if ((pImeDpi->dwFlags & IMEDPI_FLAG_UNLOADED) == 0)
1036     {
1037         if ((pImeDpi->dwFlags & IMEDPI_FLAG_LOCKED) == 0 ||
1038             (pImeDpi->ImeInfo.fdwProperty & IME_PROP_END_UNLOAD) == 0)
1039         {
1040             RtlLeaveCriticalSection(&gcsImeDpi);
1041             return;
1042         }
1043     }
1044 
1045     /* Remove from list */
1046     for (ppEntry = &gpImeDpiList; *ppEntry; ppEntry = &((*ppEntry)->pNext))
1047     {
1048         if (*ppEntry == pImeDpi) /* found */
1049         {
1050             *ppEntry = pImeDpi->pNext;
1051             break;
1052         }
1053     }
1054 
1055     Imm32FreeIME(pImeDpi, TRUE);
1056     ImmLocalFree(pImeDpi);
1057 
1058     RtlLeaveCriticalSection(&gcsImeDpi);
1059 }
1060 
1061 /***********************************************************************
1062  *		ImmLoadIME (IMM32.@)
1063  */
1064 BOOL WINAPI ImmLoadIME(HKL hKL)
1065 {
1066     PIMEDPI pImeDpi;
1067 
1068     if (!IS_IME_HKL(hKL) && (!IS_CICERO_MODE() || IS_16BIT_MODE()))
1069     {
1070         TRACE("\n");
1071         return FALSE;
1072     }
1073 
1074     pImeDpi = Imm32FindImeDpi(hKL);
1075     if (pImeDpi == NULL)
1076         pImeDpi = Imm32LoadImeDpi(hKL, FALSE);
1077     return (pImeDpi != NULL);
1078 }
1079 
1080 /***********************************************************************
1081  *		ImmDisableIME (IMM32.@)
1082  */
1083 BOOL WINAPI ImmDisableIME(DWORD dwThreadId)
1084 {
1085     return NtUserDisableThreadIme(dwThreadId);
1086 }
1087 
1088 /***********************************************************************
1089  *		ImmGetDescriptionA (IMM32.@)
1090  */
1091 UINT WINAPI ImmGetDescriptionA(HKL hKL, LPSTR lpszDescription, UINT uBufLen)
1092 {
1093     IMEINFOEX info;
1094     size_t cch;
1095 
1096     TRACE("(%p,%p,%d)\n", hKL, lpszDescription, uBufLen);
1097 
1098     if (!IS_IME_HKL(hKL))
1099     {
1100         TRACE("\n");
1101         return 0;
1102     }
1103 
1104     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL))
1105     {
1106         ERR("\n");
1107         return 0;
1108     }
1109 
1110     StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
1111     cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeDescription, (INT)cch,
1112                               lpszDescription, uBufLen, NULL, NULL);
1113     if (uBufLen)
1114         lpszDescription[cch] = 0;
1115     return (UINT)cch;
1116 }
1117 
1118 /***********************************************************************
1119  *		ImmGetDescriptionW (IMM32.@)
1120  */
1121 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
1122 {
1123     IMEINFOEX info;
1124     size_t cch;
1125 
1126     TRACE("(%p, %p, %d)\n", hKL, lpszDescription, uBufLen);
1127 
1128     if (!IS_IME_HKL(hKL))
1129     {
1130         TRACE("\n");
1131         return 0;
1132     }
1133 
1134     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL))
1135     {
1136         ERR("\n");
1137         return 0;
1138     }
1139 
1140     if (uBufLen != 0)
1141         StringCchCopyW(lpszDescription, uBufLen, info.wszImeDescription);
1142 
1143     StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
1144     return (UINT)cch;
1145 }
1146 
1147 /***********************************************************************
1148  *		ImmGetIMEFileNameA (IMM32.@)
1149  */
1150 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
1151 {
1152     BOOL bDefUsed;
1153     IMEINFOEX info;
1154     size_t cch;
1155 
1156     TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen);
1157 
1158     if (!IS_IME_HKL(hKL))
1159     {
1160         TRACE("\n");
1161         if (uBufLen > 0)
1162             lpszFileName[0] = 0;
1163         return 0;
1164     }
1165 
1166     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL))
1167     {
1168         ERR("\n");
1169         if (uBufLen > 0)
1170             lpszFileName[0] = 0;
1171         return 0;
1172     }
1173 
1174     StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch);
1175 
1176     cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeFile, (INT)cch,
1177                               lpszFileName, uBufLen, NULL, &bDefUsed);
1178     if (uBufLen == 0)
1179         return (UINT)cch;
1180 
1181     if (cch > uBufLen - 1)
1182         cch = uBufLen - 1;
1183 
1184     lpszFileName[cch] = 0;
1185     return (UINT)cch;
1186 }
1187 
1188 /***********************************************************************
1189  *		ImmGetIMEFileNameW (IMM32.@)
1190  */
1191 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
1192 {
1193     IMEINFOEX info;
1194     size_t cch;
1195 
1196     TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen);
1197 
1198     if (!IS_IME_HKL(hKL))
1199     {
1200         TRACE("\n");
1201         if (uBufLen > 0)
1202             lpszFileName[0] = 0;
1203         return 0;
1204     }
1205 
1206     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL))
1207     {
1208         ERR("\n");
1209         if (uBufLen > 0)
1210             lpszFileName[0] = 0;
1211         return 0;
1212     }
1213 
1214     StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch);
1215     if (uBufLen == 0)
1216         return (UINT)cch;
1217 
1218     StringCchCopyNW(lpszFileName, uBufLen, info.wszImeFile, cch);
1219 
1220     if (cch > uBufLen - 1)
1221         cch = uBufLen - 1;
1222 
1223     lpszFileName[cch] = 0;
1224     return (UINT)cch;
1225 }
1226 
1227 /***********************************************************************
1228  *		ImmGetProperty (IMM32.@)
1229  */
1230 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
1231 {
1232     IMEINFOEX ImeInfoEx;
1233     LPIMEINFO pImeInfo;
1234     DWORD dwValue;
1235     PIMEDPI pImeDpi = NULL;
1236 
1237     TRACE("(%p, %lu)\n", hKL, fdwIndex);
1238 
1239     if (!IS_IME_HKL(hKL))
1240     {
1241         TRACE("\n");
1242         return FALSE;
1243     }
1244 
1245     if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL))
1246     {
1247         ERR("\n");
1248         return FALSE;
1249     }
1250 
1251     if (fdwIndex == IGP_GETIMEVERSION)
1252         return ImeInfoEx.dwImeWinVersion;
1253 
1254     if (ImeInfoEx.fLoadFlag != 2)
1255     {
1256         pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1257         if (IS_NULL_UNEXPECTEDLY(pImeDpi))
1258             return FALSE;
1259 
1260         pImeInfo = &pImeDpi->ImeInfo;
1261     }
1262     else
1263     {
1264         pImeInfo = &ImeInfoEx.ImeInfo;
1265     }
1266 
1267     switch (fdwIndex)
1268     {
1269         case IGP_PROPERTY:      dwValue = pImeInfo->fdwProperty; break;
1270         case IGP_CONVERSION:    dwValue = pImeInfo->fdwConversionCaps; break;
1271         case IGP_SENTENCE:      dwValue = pImeInfo->fdwSentenceCaps; break;
1272         case IGP_UI:            dwValue = pImeInfo->fdwUICaps; break;
1273         case IGP_SETCOMPSTR:    dwValue = pImeInfo->fdwSCSCaps; break;
1274         case IGP_SELECT:        dwValue = pImeInfo->fdwSelectCaps; break;
1275         default:                dwValue = 0; break;
1276     }
1277 
1278     if (pImeDpi)
1279         ImmUnlockImeDpi(pImeDpi);
1280     return dwValue;
1281 }
1282 
1283 /***********************************************************************
1284  *		ImmEscapeA (IMM32.@)
1285  */
1286 LRESULT WINAPI ImmEscapeA(HKL hKL, HIMC hIMC, UINT uSubFunc, LPVOID lpData)
1287 {
1288     LRESULT ret;
1289     PIMEDPI pImeDpi;
1290     INT cch;
1291     CHAR szA[MAX_IMM_FILENAME];
1292     WCHAR szW[MAX_IMM_FILENAME];
1293 
1294     TRACE("(%p, %p, %u, %p)\n", hKL, hIMC, uSubFunc, lpData);
1295 
1296     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1297     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
1298         return 0;
1299 
1300     if (!ImeDpi_IsUnicode(pImeDpi) || !lpData) /* No conversion needed */
1301     {
1302         ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1303         ImmUnlockImeDpi(pImeDpi);
1304         return ret;
1305     }
1306 
1307     switch (uSubFunc)
1308     {
1309         case IME_ESC_SEQUENCE_TO_INTERNAL:
1310             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1311 
1312             cch = 0;
1313             if (HIWORD(ret))
1314                 szW[cch++] = HIWORD(ret);
1315             if (LOWORD(ret))
1316                 szW[cch++] = LOWORD(ret);
1317 
1318             cch = WideCharToMultiByte(pImeDpi->uCodePage, 0, szW, cch, szA, _countof(szA),
1319                                       NULL, NULL);
1320             switch (cch)
1321             {
1322                 case 1:
1323                     ret = MAKEWORD(szA[0], 0);
1324                     break;
1325                 case 2:
1326                     ret = MAKEWORD(szA[1], szA[0]);
1327                     break;
1328                 case 3:
1329                     ret = MAKELONG(MAKEWORD(szA[2], szA[1]), MAKEWORD(szA[0], 0));
1330                     break;
1331                 case 4:
1332                     ret = MAKELONG(MAKEWORD(szA[3], szA[2]), MAKEWORD(szA[1], szA[0]));
1333                     break;
1334                 default:
1335                     ret = 0;
1336                     break;
1337             }
1338             break;
1339 
1340         case IME_ESC_GET_EUDC_DICTIONARY:
1341         case IME_ESC_IME_NAME:
1342         case IME_ESC_GETHELPFILENAME:
1343             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, szW, hKL);
1344             if (ret)
1345             {
1346                 szW[_countof(szW) - 1] = UNICODE_NULL; /* Avoid buffer overrun */
1347                 WideCharToMultiByte(pImeDpi->uCodePage, 0, szW, -1,
1348                                     lpData, MAX_IMM_FILENAME, NULL, NULL);
1349                 ((LPSTR)lpData)[MAX_IMM_FILENAME - 1] = 0;
1350             }
1351             break;
1352 
1353         case IME_ESC_SET_EUDC_DICTIONARY:
1354         case IME_ESC_HANJA_MODE:
1355             MultiByteToWideChar(pImeDpi->uCodePage, MB_PRECOMPOSED,
1356                                 lpData, -1, szW, _countof(szW));
1357             szW[_countof(szW) - 1] = UNICODE_NULL; /* Avoid buffer overrun */
1358             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, szW, hKL);
1359             break;
1360 
1361         default:
1362             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1363             break;
1364     }
1365 
1366     ImmUnlockImeDpi(pImeDpi);
1367     TRACE("ret: %p\n", ret);
1368     return ret;
1369 }
1370 
1371 /***********************************************************************
1372  *		ImmEscapeW (IMM32.@)
1373  */
1374 LRESULT WINAPI ImmEscapeW(HKL hKL, HIMC hIMC, UINT uSubFunc, LPVOID lpData)
1375 {
1376     LRESULT ret;
1377     PIMEDPI pImeDpi;
1378     INT cch;
1379     CHAR szA[MAX_IMM_FILENAME];
1380     WCHAR szW[MAX_IMM_FILENAME];
1381     WORD word;
1382 
1383     TRACE("(%p, %p, %u, %p)\n", hKL, hIMC, uSubFunc, lpData);
1384 
1385     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1386     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
1387         return 0;
1388 
1389     if (ImeDpi_IsUnicode(pImeDpi) || !lpData) /* No conversion needed */
1390     {
1391         ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1392         ImmUnlockImeDpi(pImeDpi);
1393         return ret;
1394     }
1395 
1396     switch (uSubFunc)
1397     {
1398         case IME_ESC_SEQUENCE_TO_INTERNAL:
1399             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1400 
1401             word = LOWORD(ret);
1402             cch = 0;
1403             if (HIBYTE(word))
1404                 szA[cch++] = HIBYTE(word);
1405             if (LOBYTE(word))
1406                 szA[cch++] = LOBYTE(word);
1407 
1408             cch = MultiByteToWideChar(pImeDpi->uCodePage, MB_PRECOMPOSED,
1409                                       szA, cch, szW, _countof(szW));
1410             switch (cch)
1411             {
1412                 case 1:  ret = szW[0]; break;
1413                 case 2:  ret = MAKELONG(szW[1], szW[0]); break;
1414                 default: ret = 0; break;
1415             }
1416             break;
1417 
1418         case IME_ESC_GET_EUDC_DICTIONARY:
1419         case IME_ESC_IME_NAME:
1420         case IME_ESC_GETHELPFILENAME:
1421             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, szA, hKL);
1422             if (ret)
1423             {
1424                 szA[_countof(szA) - 1] = 0;
1425                 MultiByteToWideChar(pImeDpi->uCodePage, MB_PRECOMPOSED,
1426                                     szA, -1, lpData, MAX_IMM_FILENAME);
1427                 ((LPWSTR)lpData)[MAX_IMM_FILENAME - 1] = UNICODE_NULL; /* Avoid buffer overrun */
1428             }
1429             break;
1430 
1431         case IME_ESC_SET_EUDC_DICTIONARY:
1432         case IME_ESC_HANJA_MODE:
1433             WideCharToMultiByte(pImeDpi->uCodePage, 0,
1434                                 lpData, -1, szA, _countof(szA), NULL, NULL);
1435             szA[_countof(szA) - 1] = 0;
1436             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, szA, hKL);
1437             break;
1438 
1439         default:
1440             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1441             break;
1442     }
1443 
1444     ImmUnlockImeDpi(pImeDpi);
1445     TRACE("ret: %p\n", ret);
1446     return ret;
1447 }
1448 
1449 /***********************************************************************
1450  *		ImmGetOpenStatus (IMM32.@)
1451  */
1452 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
1453 {
1454     BOOL ret;
1455     LPINPUTCONTEXT pIC;
1456 
1457     TRACE("(%p)\n", hIMC);
1458 
1459     if (IS_NULL_UNEXPECTEDLY(hIMC))
1460         return FALSE;
1461 
1462     pIC = ImmLockIMC(hIMC);
1463     if (IS_NULL_UNEXPECTEDLY(pIC))
1464         return FALSE;
1465 
1466     ret = pIC->fOpen;
1467     ImmUnlockIMC(hIMC);
1468     TRACE("ret: %d\n", ret);
1469     return ret;
1470 }
1471 
1472 /***********************************************************************
1473  *		ImmSetOpenStatus (IMM32.@)
1474  */
1475 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
1476 {
1477     DWORD dwConversion;
1478     LPINPUTCONTEXT pIC;
1479     HWND hWnd;
1480     BOOL bHasChange = FALSE;
1481 
1482     TRACE("(%p, %d)\n", hIMC, fOpen);
1483 
1484     if (IS_CROSS_THREAD_HIMC(hIMC))
1485         return FALSE;
1486 
1487     pIC = ImmLockIMC(hIMC);
1488     if (IS_NULL_UNEXPECTEDLY(pIC))
1489         return FALSE;
1490 
1491     if (pIC->fOpen != fOpen)
1492     {
1493         pIC->fOpen = fOpen;
1494         hWnd = pIC->hWnd;
1495         dwConversion = pIC->fdwConversion;
1496         bHasChange = TRUE;
1497     }
1498 
1499     ImmUnlockIMC(hIMC);
1500 
1501     if (bHasChange)
1502     {
1503         Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
1504                            IMC_SETOPENSTATUS, IMN_SETOPENSTATUS, 0);
1505         NtUserNotifyIMEStatus(hWnd, fOpen, dwConversion);
1506     }
1507     else
1508     {
1509         TRACE("No change.\n");
1510     }
1511 
1512     return TRUE;
1513 }
1514 
1515 /***********************************************************************
1516  *		ImmGetStatusWindowPos (IMM32.@)
1517  */
1518 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1519 {
1520     LPINPUTCONTEXT pIC;
1521     BOOL ret;
1522 
1523     TRACE("(%p, %p)\n", hIMC, lpptPos);
1524 
1525     pIC = ImmLockIMC(hIMC);
1526     if (IS_NULL_UNEXPECTEDLY(pIC))
1527         return FALSE;
1528 
1529     ret = !!(pIC->fdwInit & INIT_STATUSWNDPOS);
1530     if (ret)
1531         *lpptPos = pIC->ptStatusWndPos;
1532 
1533     ImmUnlockIMC(hIMC);
1534     return ret;
1535 }
1536 
1537 /***********************************************************************
1538  *		ImmSetStatusWindowPos (IMM32.@)
1539  */
1540 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1541 {
1542     LPINPUTCONTEXT pIC;
1543     HWND hWnd;
1544 
1545     TRACE("(%p, {%ld, %ld})\n", hIMC, lpptPos->x, lpptPos->y);
1546 
1547     if (IS_CROSS_THREAD_HIMC(hIMC))
1548         return FALSE;
1549 
1550     pIC = ImmLockIMC(hIMC);
1551     if (IS_NULL_UNEXPECTEDLY(pIC))
1552         return FALSE;
1553 
1554     hWnd = pIC->hWnd;
1555     pIC->ptStatusWndPos = *lpptPos;
1556     pIC->fdwInit |= INIT_STATUSWNDPOS;
1557 
1558     ImmUnlockIMC(hIMC);
1559 
1560     Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
1561                        IMC_SETSTATUSWINDOWPOS, IMN_SETSTATUSWINDOWPOS, 0);
1562     return TRUE;
1563 }
1564 
1565 /***********************************************************************
1566  *		ImmGetCompositionWindow (IMM32.@)
1567  */
1568 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1569 {
1570     LPINPUTCONTEXT pIC;
1571     BOOL ret = FALSE;
1572 
1573     TRACE("(%p, %p)\n", hIMC, lpCompForm);
1574 
1575     pIC = ImmLockIMC(hIMC);
1576     if (IS_NULL_UNEXPECTEDLY(pIC))
1577         return FALSE;
1578 
1579     if (pIC->fdwInit & INIT_COMPFORM)
1580     {
1581         *lpCompForm = pIC->cfCompForm;
1582         ret = TRUE;
1583     }
1584 
1585     ImmUnlockIMC(hIMC);
1586     return ret;
1587 }
1588 
1589 /***********************************************************************
1590  *		ImmSetCompositionWindow (IMM32.@)
1591  */
1592 BOOL WINAPI ImmSetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1593 {
1594     LPINPUTCONTEXTDX pIC;
1595     HWND hWnd;
1596 
1597     if (IS_CROSS_THREAD_HIMC(hIMC))
1598         return FALSE;
1599 
1600     pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1601     if (IS_NULL_UNEXPECTEDLY(pIC))
1602         return FALSE;
1603 
1604     pIC->cfCompForm = *lpCompForm;
1605     pIC->fdwInit |= INIT_COMPFORM;
1606 
1607     if (pIC->dwUIFlags & 0x8)
1608         pIC->dwUIFlags &= ~0x8;
1609     else
1610         pIC->dwUIFlags &= ~0x2;
1611 
1612     hWnd = pIC->hWnd;
1613 
1614     ImmUnlockIMC(hIMC);
1615 
1616     Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
1617                        IMC_SETCOMPOSITIONWINDOW, IMN_SETCOMPOSITIONWINDOW, 0);
1618     return TRUE;
1619 }
1620 
1621 /***********************************************************************
1622  *		ImmGetCompositionFontA (IMM32.@)
1623  */
1624 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1625 {
1626     PCLIENTIMC pClientImc;
1627     BOOL ret = FALSE, bWide;
1628     LPINPUTCONTEXT pIC;
1629 
1630     TRACE("(%p, %p)\n", hIMC, lplf);
1631 
1632     pClientImc = ImmLockClientImc(hIMC);
1633     if (IS_NULL_UNEXPECTEDLY(pClientImc))
1634         return FALSE;
1635 
1636     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
1637     ImmUnlockClientImc(pClientImc);
1638 
1639     pIC = ImmLockIMC(hIMC);
1640     if (IS_NULL_UNEXPECTEDLY(pIC))
1641         return FALSE;
1642 
1643     if (pIC->fdwInit & INIT_LOGFONT)
1644     {
1645         if (bWide)
1646             LogFontWideToAnsi(&pIC->lfFont.W, lplf);
1647         else
1648             *lplf = pIC->lfFont.A;
1649 
1650         ret = TRUE;
1651     }
1652 
1653     ImmUnlockIMC(hIMC);
1654     return ret;
1655 }
1656 
1657 /***********************************************************************
1658  *		ImmGetCompositionFontW (IMM32.@)
1659  */
1660 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1661 {
1662     PCLIENTIMC pClientImc;
1663     BOOL bWide;
1664     LPINPUTCONTEXT pIC;
1665     BOOL ret = FALSE;
1666 
1667     TRACE("(%p, %p)\n", hIMC, lplf);
1668 
1669     pClientImc = ImmLockClientImc(hIMC);
1670     if (IS_NULL_UNEXPECTEDLY(pClientImc))
1671         return FALSE;
1672 
1673     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
1674     ImmUnlockClientImc(pClientImc);
1675 
1676     pIC = ImmLockIMC(hIMC);
1677     if (IS_NULL_UNEXPECTEDLY(pIC))
1678         return FALSE;
1679 
1680     if (pIC->fdwInit & INIT_LOGFONT)
1681     {
1682         if (bWide)
1683             *lplf = pIC->lfFont.W;
1684         else
1685             LogFontAnsiToWide(&pIC->lfFont.A, lplf);
1686 
1687         ret = TRUE;
1688     }
1689 
1690     ImmUnlockIMC(hIMC);
1691     return ret;
1692 }
1693 
1694 /***********************************************************************
1695  *		ImmSetCompositionFontA (IMM32.@)
1696  */
1697 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1698 {
1699     LOGFONTW lfW;
1700     PCLIENTIMC pClientImc;
1701     BOOL bWide;
1702     LPINPUTCONTEXTDX pIC;
1703     LANGID LangID;
1704     HWND hWnd;
1705 
1706     TRACE("(%p, %p)\n", hIMC, lplf);
1707 
1708     if (IS_CROSS_THREAD_HIMC(hIMC))
1709         return FALSE;
1710 
1711     pClientImc = ImmLockClientImc(hIMC);
1712     if (IS_NULL_UNEXPECTEDLY(pClientImc))
1713         return FALSE;
1714 
1715     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
1716     ImmUnlockClientImc(pClientImc);
1717 
1718     if (bWide)
1719     {
1720         LogFontAnsiToWide(lplf, &lfW);
1721         return ImmSetCompositionFontW(hIMC, &lfW);
1722     }
1723 
1724     pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1725     if (IS_NULL_UNEXPECTEDLY(pIC))
1726         return FALSE;
1727 
1728     if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */
1729     {
1730         LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
1731         if (PRIMARYLANGID(LangID) == LANG_JAPANESE &&
1732             !(pIC->dwUIFlags & 2) &&
1733             pIC->cfCompForm.dwStyle != CFS_DEFAULT)
1734         {
1735             PostMessageA(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
1736         }
1737     }
1738 
1739     pIC->lfFont.A = *lplf;
1740     pIC->fdwInit |= INIT_LOGFONT;
1741     hWnd = pIC->hWnd;
1742 
1743     ImmUnlockIMC(hIMC);
1744 
1745     Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT,
1746                        IMN_SETCOMPOSITIONFONT, 0);
1747     return TRUE;
1748 }
1749 
1750 /***********************************************************************
1751  *		ImmSetCompositionFontW (IMM32.@)
1752  */
1753 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1754 {
1755     LOGFONTA lfA;
1756     PCLIENTIMC pClientImc;
1757     BOOL bWide;
1758     HWND hWnd;
1759     LPINPUTCONTEXTDX pIC;
1760     LANGID LangID;
1761 
1762     TRACE("(%p, %p)\n", hIMC, lplf);
1763 
1764     if (IS_CROSS_THREAD_HIMC(hIMC))
1765         return FALSE;
1766 
1767     pClientImc = ImmLockClientImc(hIMC);
1768     if (IS_NULL_UNEXPECTEDLY(pClientImc))
1769         return FALSE;
1770 
1771     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
1772     ImmUnlockClientImc(pClientImc);
1773 
1774     if (!bWide)
1775     {
1776         LogFontWideToAnsi(lplf, &lfA);
1777         return ImmSetCompositionFontA(hIMC, &lfA);
1778     }
1779 
1780     pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1781     if (IS_NULL_UNEXPECTEDLY(pIC))
1782         return FALSE;
1783 
1784     if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */
1785     {
1786         LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
1787         if (PRIMARYLANGID(LangID) == LANG_JAPANESE &&
1788             !(pIC->dwUIFlags & 2) &&
1789             pIC->cfCompForm.dwStyle != CFS_DEFAULT)
1790         {
1791             PostMessageW(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
1792         }
1793     }
1794 
1795     pIC->lfFont.W = *lplf;
1796     pIC->fdwInit |= INIT_LOGFONT;
1797     hWnd = pIC->hWnd;
1798 
1799     ImmUnlockIMC(hIMC);
1800 
1801     Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT,
1802                        IMN_SETCOMPOSITIONFONT, 0);
1803     return TRUE;
1804 }
1805 
1806 /***********************************************************************
1807  *		ImmGetConversionListA (IMM32.@)
1808  */
1809 DWORD WINAPI
1810 ImmGetConversionListA(HKL hKL, HIMC hIMC, LPCSTR pSrc, LPCANDIDATELIST lpDst,
1811                       DWORD dwBufLen, UINT uFlag)
1812 {
1813     DWORD ret = 0;
1814     UINT cb;
1815     LPWSTR pszSrcW = NULL;
1816     LPCANDIDATELIST pCL = NULL;
1817     PIMEDPI pImeDpi;
1818 
1819     TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_a(pSrc),
1820           lpDst, dwBufLen, uFlag);
1821 
1822     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1823     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
1824         return 0;
1825 
1826     if (!ImeDpi_IsUnicode(pImeDpi)) /* No conversion needed */
1827     {
1828         ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag);
1829         ImmUnlockImeDpi(pImeDpi);
1830         return ret;
1831     }
1832 
1833     if (pSrc)
1834     {
1835         pszSrcW = Imm32WideFromAnsi(pImeDpi->uCodePage, pSrc);
1836         if (IS_NULL_UNEXPECTEDLY(pszSrcW))
1837             goto Quit;
1838     }
1839 
1840     cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, NULL, 0, uFlag);
1841     if (IS_ZERO_UNEXPECTEDLY(cb))
1842         goto Quit;
1843 
1844     pCL = ImmLocalAlloc(0, cb);
1845     if (IS_NULL_UNEXPECTEDLY(pCL))
1846         goto Quit;
1847 
1848     cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, pCL, cb, uFlag);
1849     if (IS_ZERO_UNEXPECTEDLY(cb))
1850         goto Quit;
1851 
1852     ret = CandidateListWideToAnsi(pCL, lpDst, dwBufLen, pImeDpi->uCodePage);
1853 
1854 Quit:
1855     ImmLocalFree(pszSrcW);
1856     ImmLocalFree(pCL);
1857     ImmUnlockImeDpi(pImeDpi);
1858     TRACE("ret: 0x%X\n", ret);
1859     return ret;
1860 }
1861 
1862 /***********************************************************************
1863  *		ImmGetConversionListW (IMM32.@)
1864  */
1865 DWORD WINAPI
1866 ImmGetConversionListW(HKL hKL, HIMC hIMC, LPCWSTR pSrc, LPCANDIDATELIST lpDst,
1867                       DWORD dwBufLen, UINT uFlag)
1868 {
1869     DWORD ret = 0;
1870     INT cb;
1871     PIMEDPI pImeDpi;
1872     LPCANDIDATELIST pCL = NULL;
1873     LPSTR pszSrcA = NULL;
1874 
1875     TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_w(pSrc),
1876           lpDst, dwBufLen, uFlag);
1877 
1878     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1879     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
1880         return 0;
1881 
1882     if (ImeDpi_IsUnicode(pImeDpi)) /* No conversion needed */
1883     {
1884         ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag);
1885         ImmUnlockImeDpi(pImeDpi);
1886         return ret;
1887     }
1888 
1889     if (pSrc)
1890     {
1891         pszSrcA = Imm32AnsiFromWide(pImeDpi->uCodePage, pSrc);
1892         if (IS_NULL_UNEXPECTEDLY(pszSrcA))
1893             goto Quit;
1894     }
1895 
1896     cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, NULL, 0, uFlag);
1897     if (IS_ZERO_UNEXPECTEDLY(cb))
1898         goto Quit;
1899 
1900     pCL = ImmLocalAlloc(0, cb);
1901     if (IS_NULL_UNEXPECTEDLY(pCL))
1902         goto Quit;
1903 
1904     cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, pCL, cb, uFlag);
1905     if (IS_ZERO_UNEXPECTEDLY(cb))
1906         goto Quit;
1907 
1908     ret = CandidateListAnsiToWide(pCL, lpDst, dwBufLen, pImeDpi->uCodePage);
1909 
1910 Quit:
1911     ImmLocalFree(pszSrcA);
1912     ImmLocalFree(pCL);
1913     ImmUnlockImeDpi(pImeDpi);
1914     TRACE("ret: 0x%X\n", ret);
1915     return ret;
1916 }
1917 
1918 /***********************************************************************
1919  *		ImmGetConversionStatus (IMM32.@)
1920  */
1921 BOOL WINAPI ImmGetConversionStatus(HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
1922 {
1923     LPINPUTCONTEXT pIC;
1924 
1925     TRACE("(%p %p %p)\n", hIMC, lpfdwConversion, lpfdwSentence);
1926 
1927     pIC = ImmLockIMC(hIMC);
1928     if (IS_NULL_UNEXPECTEDLY(pIC))
1929         return FALSE;
1930 
1931     if (lpfdwConversion)
1932     {
1933         *lpfdwConversion = pIC->fdwConversion;
1934         TRACE("0x%X\n", *lpfdwConversion);
1935     }
1936 
1937     if (lpfdwSentence)
1938     {
1939         *lpfdwSentence = pIC->fdwSentence;
1940         TRACE("0x%X\n", *lpfdwSentence);
1941     }
1942 
1943     ImmUnlockIMC(hIMC);
1944     return TRUE;
1945 }
1946 
1947 /***********************************************************************
1948  *		ImmSetConversionStatus (IMM32.@)
1949  */
1950 BOOL WINAPI ImmSetConversionStatus(HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
1951 {
1952     HKL hKL;
1953     LPINPUTCONTEXT pIC;
1954     DWORD dwOldConversion, dwOldSentence;
1955     BOOL fOpen = FALSE, fConversionChange = FALSE, fSentenceChange = FALSE, fUseCicero = FALSE;
1956     HWND hWnd;
1957 
1958     TRACE("(%p, 0x%lX, 0x%lX)\n", hIMC, fdwConversion, fdwSentence);
1959 
1960     hKL = GetKeyboardLayout(0);
1961     if (!IS_IME_HKL(hKL) && IS_CICERO_MODE() && !IS_16BIT_MODE())
1962         fUseCicero = TRUE;
1963 
1964     if (IS_CROSS_THREAD_HIMC(hIMC))
1965         return FALSE;
1966 
1967     pIC = ImmLockIMC(hIMC);
1968     if (IS_NULL_UNEXPECTEDLY(pIC))
1969         return FALSE;
1970 
1971     if (pIC->fdwConversion != fdwConversion)
1972     {
1973         dwOldConversion = pIC->fdwConversion;
1974         pIC->fdwConversion = fdwConversion;
1975         fConversionChange = TRUE;
1976     }
1977 
1978     if (pIC->fdwSentence != fdwSentence)
1979     {
1980         dwOldSentence = pIC->fdwSentence;
1981         pIC->fdwSentence = fdwSentence;
1982         fSentenceChange = TRUE;
1983     }
1984 
1985     hWnd = pIC->hWnd;
1986     fOpen = pIC->fOpen;
1987     ImmUnlockIMC(hIMC);
1988 
1989     if (fConversionChange || fUseCicero)
1990     {
1991         Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldConversion,
1992                            IMC_SETCONVERSIONMODE, IMN_SETCONVERSIONMODE, 0);
1993         if (fConversionChange)
1994             NtUserNotifyIMEStatus(hWnd, fOpen, fdwConversion);
1995     }
1996 
1997     if (fSentenceChange || fUseCicero)
1998     {
1999         Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldSentence,
2000                            IMC_SETSENTENCEMODE, IMN_SETSENTENCEMODE, 0);
2001     }
2002 
2003     return TRUE;
2004 }
2005 
2006 /***********************************************************************
2007  *		ImmConfigureIMEA (IMM32.@)
2008  */
2009 BOOL WINAPI ImmConfigureIMEA(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
2010 {
2011     BOOL ret = FALSE;
2012     PIMEDPI pImeDpi;
2013     REGISTERWORDW RegWordW;
2014     LPREGISTERWORDA pRegWordA;
2015 
2016     TRACE("(%p, %p, 0x%lX, %p)\n", hKL, hWnd, dwMode, lpData);
2017 
2018     if (IS_NULL_UNEXPECTEDLY(ValidateHwnd(hWnd)) || IS_CROSS_PROCESS_HWND(hWnd))
2019         return FALSE;
2020 
2021     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
2022     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
2023         return FALSE;
2024 
2025     RtlZeroMemory(&RegWordW, sizeof(RegWordW));
2026 
2027     if (!ImeDpi_IsUnicode(pImeDpi) || !lpData || dwMode != IME_CONFIG_REGISTERWORD)
2028         goto DoIt; /* No conversion needed */
2029 
2030     pRegWordA = lpData;
2031 
2032     if (pRegWordA->lpReading)
2033     {
2034         RegWordW.lpReading = Imm32WideFromAnsi(pImeDpi->uCodePage, pRegWordA->lpReading);
2035         if (IS_NULL_UNEXPECTEDLY(RegWordW.lpReading))
2036             goto Quit;
2037     }
2038 
2039     if (pRegWordA->lpWord)
2040     {
2041         RegWordW.lpWord = Imm32WideFromAnsi(pImeDpi->uCodePage, pRegWordA->lpWord);
2042         if (IS_NULL_UNEXPECTEDLY(RegWordW.lpWord))
2043             goto Quit;
2044     }
2045 
2046     lpData = &RegWordW;
2047 
2048 DoIt:
2049     SendMessageW(hWnd, WM_IME_SYSTEM, 0x1B, 0);
2050     ret = pImeDpi->ImeConfigure(hKL, hWnd, dwMode, lpData);
2051     SendMessageW(hWnd, WM_IME_SYSTEM, 0x1A, 0);
2052 
2053 Quit:
2054     ImmLocalFree(RegWordW.lpReading);
2055     ImmLocalFree(RegWordW.lpWord);
2056     ImmUnlockImeDpi(pImeDpi);
2057     TRACE("ret: %d\n", ret);
2058     return ret;
2059 }
2060 
2061 /***********************************************************************
2062  *		ImmConfigureIMEW (IMM32.@)
2063  */
2064 BOOL WINAPI ImmConfigureIMEW(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
2065 {
2066     BOOL ret = FALSE;
2067     PIMEDPI pImeDpi;
2068     REGISTERWORDA RegWordA;
2069     LPREGISTERWORDW pRegWordW;
2070 
2071     TRACE("(%p, %p, 0x%lX, %p)\n", hKL, hWnd, dwMode, lpData);
2072 
2073     if (IS_NULL_UNEXPECTEDLY(ValidateHwnd(hWnd)) || IS_CROSS_PROCESS_HWND(hWnd))
2074         return FALSE;
2075 
2076     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
2077     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
2078         return FALSE;
2079 
2080     RtlZeroMemory(&RegWordA, sizeof(RegWordA));
2081 
2082     if (ImeDpi_IsUnicode(pImeDpi) || !lpData || dwMode != IME_CONFIG_REGISTERWORD)
2083         goto DoIt; /* No conversion needed */
2084 
2085     pRegWordW = lpData;
2086 
2087     if (pRegWordW->lpReading)
2088     {
2089         RegWordA.lpReading = Imm32AnsiFromWide(pImeDpi->uCodePage, pRegWordW->lpReading);
2090         if (IS_NULL_UNEXPECTEDLY(RegWordA.lpReading))
2091             goto Quit;
2092     }
2093 
2094     if (pRegWordW->lpWord)
2095     {
2096         RegWordA.lpWord = Imm32AnsiFromWide(pImeDpi->uCodePage, pRegWordW->lpWord);
2097         if (IS_NULL_UNEXPECTEDLY(RegWordA.lpWord))
2098             goto Quit;
2099     }
2100 
2101     lpData = &RegWordA;
2102 
2103 DoIt:
2104     SendMessageW(hWnd, WM_IME_SYSTEM, 0x1B, 0);
2105     ret = pImeDpi->ImeConfigure(hKL, hWnd, dwMode, lpData);
2106     SendMessageW(hWnd, WM_IME_SYSTEM, 0x1A, 0);
2107 
2108 Quit:
2109     ImmLocalFree(RegWordA.lpReading);
2110     ImmLocalFree(RegWordA.lpWord);
2111     ImmUnlockImeDpi(pImeDpi);
2112     TRACE("ret: %d\n", ret);
2113     return ret;
2114 }
2115 
2116 /***********************************************************************
2117  *		ImmGetImeMenuItemsA (IMM32.@)
2118  */
2119 DWORD WINAPI
2120 ImmGetImeMenuItemsA(HIMC hIMC, DWORD dwFlags, DWORD dwType,
2121                     LPIMEMENUITEMINFOA lpImeParentMenu,
2122                     LPIMEMENUITEMINFOA lpImeMenu, DWORD dwSize)
2123 {
2124     TRACE("(%p, 0x%lX, 0x%lX, %p, %p, 0x%lX)\n",
2125           hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize);
2126     return ImmGetImeMenuItemsAW(hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize, TRUE);
2127 }
2128 
2129 /***********************************************************************
2130  *		ImmGetImeMenuItemsW (IMM32.@)
2131  */
2132 DWORD WINAPI
2133 ImmGetImeMenuItemsW(HIMC hIMC, DWORD dwFlags, DWORD dwType,
2134                     LPIMEMENUITEMINFOW lpImeParentMenu,
2135                     LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize)
2136 {
2137     TRACE("(%p, 0x%lX, 0x%lX, %p, %p, 0x%lX)\n",
2138           hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize);
2139     return ImmGetImeMenuItemsAW(hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize, FALSE);
2140 }
2141 
2142 /***********************************************************************
2143  *		ImmWINNLSEnableIME (IMM32.@)
2144  */
2145 BOOL WINAPI ImmWINNLSEnableIME(HWND hWnd, BOOL enable)
2146 {
2147     HIMC hIMC;
2148     PCLIENTIMC pClientImc;
2149     HWND hImeWnd;
2150     BOOL bImeWnd, ret;
2151 
2152     TRACE("(%p, %d)\n", hWnd, enable);
2153 
2154     if (!Imm32IsSystemJapaneseOrKorean())
2155     {
2156         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2157         return FALSE;
2158     }
2159 
2160     hIMC = (HIMC)NtUserGetThreadState(THREADSTATE_DEFAULTINPUTCONTEXT);
2161     if (IS_NULL_UNEXPECTEDLY(hIMC))
2162         return FALSE;
2163 
2164     pClientImc = ImmLockClientImc(hIMC);
2165     if (IS_NULL_UNEXPECTEDLY(pClientImc))
2166         return FALSE;
2167 
2168     ret = !(pClientImc->dwFlags & CLIENTIMC_DISABLEIME);
2169     if (!!enable == ret)
2170     {
2171         TRACE("Same\n");
2172         ImmUnlockClientImc(pClientImc);
2173         return ret;
2174     }
2175 
2176     if (!IsWindow(hWnd))
2177         hWnd = GetFocus();
2178 
2179     hImeWnd = ImmGetDefaultIMEWnd(hWnd);
2180     bImeWnd = IsWindow(hImeWnd);
2181     if (bImeWnd)
2182         ImmSetActiveContext(hWnd, (enable ? NULL : hIMC), FALSE);
2183 
2184     if (enable)
2185         pClientImc->dwFlags &= ~CLIENTIMC_DISABLEIME;
2186     else
2187         pClientImc->dwFlags |= CLIENTIMC_DISABLEIME;
2188 
2189     ImmUnlockClientImc(pClientImc);
2190 
2191     if (bImeWnd)
2192         ImmSetActiveContext(hWnd, (enable ? hIMC : NULL), TRUE);
2193 
2194     return ret;
2195 }
2196