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