xref: /reactos/dll/win32/imm32/ime.c (revision ec24b547)
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
Imm32FindImeDpi(HKL hKL)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
Imm32FreeIME(PIMEDPI pImeDpi,BOOL bDestroy)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
Imm32InquireIme(PIMEDPI pImeDpi)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_ISWINLOGON))
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) != S_OK)
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
Imm32LoadIME(PIMEINFOEX pImeInfoEx,PIMEDPI pImeDpi)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
Imm32LoadImeDpi(HKL hKL,BOOL bLock)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(UlongToPtr(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
Imm32FindOrLoadImeDpi(HKL hKL)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
ImeDpi_Escape(PIMEDPI pImeDpi,HIMC hIMC,UINT uSubFunc,LPVOID lpData,HKL hKL)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
Imm32ReleaseIME(HKL hKL)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  */
ImmPutImeMenuItemsIntoMappedFile(HIMC hIMC)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
Imm32GetImeMenuItemWInterProcess(HIMC hIMC,DWORD dwFlags,DWORD dwType,LPVOID lpImeParentMenu,LPVOID lpImeMenu,DWORD dwSize)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
ImmGetImeMenuItemsAW(HIMC hIMC,DWORD dwFlags,DWORD dwType,LPVOID lpImeParentMenu,LPVOID lpImeMenu,DWORD dwSize,BOOL bTargetIsAnsi)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  */
ImmInstallIMEA(LPCSTR lpszIMEFileName,LPCSTR lpszLayoutText)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  */
ImmInstallIMEW(LPCWSTR lpszIMEFileName,LPCWSTR lpszLayoutText)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", HandleToUlong(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  */
ImmIsIME(HKL hKL)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  */
ImmGetDefaultIMEWnd(HWND hWnd)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  */
ImmNotifyIME(HIMC hIMC,DWORD dwAction,DWORD dwIndex,DWORD_PTR dwValue)907 BOOL WINAPI ImmNotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD_PTR 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  *              ImmGetImeInfoEx (IMM32.@)
930  */
931 BOOL WINAPI
ImmGetImeInfoEx(PIMEINFOEX pImeInfoEx,IMEINFOEXCLASS SearchType,PVOID pvSearchKey)932 ImmGetImeInfoEx(PIMEINFOEX pImeInfoEx, IMEINFOEXCLASS SearchType, PVOID pvSearchKey)
933 {
934     HKL hKL;
935     if (SearchType == ImeInfoExKeyboardLayout || SearchType == ImeInfoExKeyboardLayoutTFS)
936     {
937         hKL = *(HKL*)pvSearchKey;
938         pImeInfoEx->hkl = hKL;
939 
940         if (SearchType == ImeInfoExKeyboardLayoutTFS)
941         {
942             if (!IS_IME_HKL(hKL))
943             {
944                 if (CtfImmIsTextFrameServiceDisabled() || !IS_CICERO_MODE() || IS_16BIT_MODE())
945                 {
946                     TRACE("\n");
947                     return FALSE;
948                 }
949             }
950 
951             SearchType = ImeInfoExKeyboardLayout;
952         }
953         else
954         {
955             if (!IS_IME_HKL(hKL))
956             {
957                 TRACE("\n");
958                 return FALSE;
959             }
960         }
961     }
962     else if (SearchType == ImeInfoExImeFileName)
963     {
964         StringCchCopyW(pImeInfoEx->wszImeFile, _countof(pImeInfoEx->wszImeFile),
965                        pvSearchKey);
966     }
967     else
968     {
969         return FALSE;
970     }
971 
972     return NtUserGetImeInfoEx(pImeInfoEx, SearchType);
973 }
974 
975 /***********************************************************************
976  *		ImmLockImeDpi (IMM32.@)
977  */
ImmLockImeDpi(HKL hKL)978 PIMEDPI WINAPI ImmLockImeDpi(HKL hKL)
979 {
980     PIMEDPI pImeDpi = NULL;
981 
982     TRACE("(%p)\n", hKL);
983 
984     RtlEnterCriticalSection(&gcsImeDpi);
985 
986     /* Find by hKL */
987     for (pImeDpi = gpImeDpiList; pImeDpi; pImeDpi = pImeDpi->pNext)
988     {
989         if (pImeDpi->hKL == hKL) /* found */
990         {
991             /* lock if possible */
992             if (pImeDpi->dwFlags & IMEDPI_FLAG_UNLOADED)
993                 pImeDpi = NULL;
994             else
995                 ++(pImeDpi->cLockObj);
996             break;
997         }
998     }
999 
1000     RtlLeaveCriticalSection(&gcsImeDpi);
1001     return pImeDpi;
1002 }
1003 
1004 /***********************************************************************
1005  *		ImmUnlockImeDpi (IMM32.@)
1006  */
ImmUnlockImeDpi(PIMEDPI pImeDpi)1007 VOID WINAPI ImmUnlockImeDpi(PIMEDPI pImeDpi)
1008 {
1009     PIMEDPI *ppEntry;
1010 
1011     TRACE("(%p)\n", pImeDpi);
1012 
1013     if (pImeDpi == NULL)
1014         return;
1015 
1016     RtlEnterCriticalSection(&gcsImeDpi);
1017 
1018     /* unlock */
1019     --(pImeDpi->cLockObj);
1020     if (pImeDpi->cLockObj != 0)
1021     {
1022         RtlLeaveCriticalSection(&gcsImeDpi);
1023         return;
1024     }
1025 
1026     if ((pImeDpi->dwFlags & IMEDPI_FLAG_UNLOADED) == 0)
1027     {
1028         if ((pImeDpi->dwFlags & IMEDPI_FLAG_LOCKED) == 0 ||
1029             (pImeDpi->ImeInfo.fdwProperty & IME_PROP_END_UNLOAD) == 0)
1030         {
1031             RtlLeaveCriticalSection(&gcsImeDpi);
1032             return;
1033         }
1034     }
1035 
1036     /* Remove from list */
1037     for (ppEntry = &gpImeDpiList; *ppEntry; ppEntry = &((*ppEntry)->pNext))
1038     {
1039         if (*ppEntry == pImeDpi) /* found */
1040         {
1041             *ppEntry = pImeDpi->pNext;
1042             break;
1043         }
1044     }
1045 
1046     Imm32FreeIME(pImeDpi, TRUE);
1047     ImmLocalFree(pImeDpi);
1048 
1049     RtlLeaveCriticalSection(&gcsImeDpi);
1050 }
1051 
1052 /***********************************************************************
1053  *		ImmLoadIME (IMM32.@)
1054  */
ImmLoadIME(HKL hKL)1055 BOOL WINAPI ImmLoadIME(HKL hKL)
1056 {
1057     PIMEDPI pImeDpi;
1058 
1059     if (!IS_IME_HKL(hKL) && (!IS_CICERO_MODE() || IS_16BIT_MODE()))
1060     {
1061         TRACE("\n");
1062         return FALSE;
1063     }
1064 
1065     pImeDpi = Imm32FindImeDpi(hKL);
1066     if (pImeDpi == NULL)
1067         pImeDpi = Imm32LoadImeDpi(hKL, FALSE);
1068     return (pImeDpi != NULL);
1069 }
1070 
1071 /***********************************************************************
1072  *		ImmDisableIME (IMM32.@)
1073  */
ImmDisableIME(DWORD dwThreadId)1074 BOOL WINAPI ImmDisableIME(DWORD dwThreadId)
1075 {
1076     return NtUserDisableThreadIme(dwThreadId);
1077 }
1078 
1079 /***********************************************************************
1080  *		ImmGetDescriptionA (IMM32.@)
1081  */
ImmGetDescriptionA(HKL hKL,LPSTR lpszDescription,UINT uBufLen)1082 UINT WINAPI ImmGetDescriptionA(HKL hKL, LPSTR lpszDescription, UINT uBufLen)
1083 {
1084     IMEINFOEX info;
1085     size_t cch;
1086 
1087     TRACE("(%p,%p,%d)\n", hKL, lpszDescription, uBufLen);
1088 
1089     if (!IS_IME_HKL(hKL))
1090     {
1091         TRACE("\n");
1092         return 0;
1093     }
1094 
1095     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL))
1096     {
1097         ERR("\n");
1098         return 0;
1099     }
1100 
1101     StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
1102     cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeDescription, (INT)cch,
1103                               lpszDescription, uBufLen, NULL, NULL);
1104     if (uBufLen)
1105         lpszDescription[cch] = 0;
1106     return (UINT)cch;
1107 }
1108 
1109 /***********************************************************************
1110  *		ImmGetDescriptionW (IMM32.@)
1111  */
ImmGetDescriptionW(HKL hKL,LPWSTR lpszDescription,UINT uBufLen)1112 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
1113 {
1114     IMEINFOEX info;
1115     size_t cch;
1116 
1117     TRACE("(%p, %p, %d)\n", hKL, lpszDescription, uBufLen);
1118 
1119     if (!IS_IME_HKL(hKL))
1120     {
1121         TRACE("\n");
1122         return 0;
1123     }
1124 
1125     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL))
1126     {
1127         ERR("\n");
1128         return 0;
1129     }
1130 
1131     if (uBufLen != 0)
1132         StringCchCopyW(lpszDescription, uBufLen, info.wszImeDescription);
1133 
1134     StringCchLengthW(info.wszImeDescription, _countof(info.wszImeDescription), &cch);
1135     return (UINT)cch;
1136 }
1137 
1138 /***********************************************************************
1139  *		ImmGetIMEFileNameA (IMM32.@)
1140  */
ImmGetIMEFileNameA(HKL hKL,LPSTR lpszFileName,UINT uBufLen)1141 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
1142 {
1143     BOOL bDefUsed;
1144     IMEINFOEX info;
1145     size_t cch;
1146 
1147     TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen);
1148 
1149     if (!IS_IME_HKL(hKL))
1150     {
1151         TRACE("\n");
1152         if (uBufLen > 0)
1153             lpszFileName[0] = 0;
1154         return 0;
1155     }
1156 
1157     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL))
1158     {
1159         ERR("\n");
1160         if (uBufLen > 0)
1161             lpszFileName[0] = 0;
1162         return 0;
1163     }
1164 
1165     StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch);
1166 
1167     cch = WideCharToMultiByte(CP_ACP, 0, info.wszImeFile, (INT)cch,
1168                               lpszFileName, uBufLen, NULL, &bDefUsed);
1169     if (uBufLen == 0)
1170         return (UINT)cch;
1171 
1172     if (cch > uBufLen - 1)
1173         cch = uBufLen - 1;
1174 
1175     lpszFileName[cch] = 0;
1176     return (UINT)cch;
1177 }
1178 
1179 /***********************************************************************
1180  *		ImmGetIMEFileNameW (IMM32.@)
1181  */
ImmGetIMEFileNameW(HKL hKL,LPWSTR lpszFileName,UINT uBufLen)1182 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
1183 {
1184     IMEINFOEX info;
1185     size_t cch;
1186 
1187     TRACE("(%p, %p, %u)\n", hKL, lpszFileName, uBufLen);
1188 
1189     if (!IS_IME_HKL(hKL))
1190     {
1191         TRACE("\n");
1192         if (uBufLen > 0)
1193             lpszFileName[0] = 0;
1194         return 0;
1195     }
1196 
1197     if (!ImmGetImeInfoEx(&info, ImeInfoExKeyboardLayout, &hKL))
1198     {
1199         ERR("\n");
1200         if (uBufLen > 0)
1201             lpszFileName[0] = 0;
1202         return 0;
1203     }
1204 
1205     StringCchLengthW(info.wszImeFile, _countof(info.wszImeFile), &cch);
1206     if (uBufLen == 0)
1207         return (UINT)cch;
1208 
1209     StringCchCopyNW(lpszFileName, uBufLen, info.wszImeFile, cch);
1210 
1211     if (cch > uBufLen - 1)
1212         cch = uBufLen - 1;
1213 
1214     lpszFileName[cch] = 0;
1215     return (UINT)cch;
1216 }
1217 
1218 /***********************************************************************
1219  *		ImmGetProperty (IMM32.@)
1220  */
ImmGetProperty(HKL hKL,DWORD fdwIndex)1221 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
1222 {
1223     IMEINFOEX ImeInfoEx;
1224     LPIMEINFO pImeInfo;
1225     DWORD dwValue;
1226     PIMEDPI pImeDpi = NULL;
1227 
1228     TRACE("(%p, %lu)\n", hKL, fdwIndex);
1229 
1230     if (!IS_IME_HKL(hKL))
1231     {
1232         TRACE("\n");
1233         return FALSE;
1234     }
1235 
1236     if (!ImmGetImeInfoEx(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL))
1237     {
1238         ERR("\n");
1239         return FALSE;
1240     }
1241 
1242     if (fdwIndex == IGP_GETIMEVERSION)
1243         return ImeInfoEx.dwImeWinVersion;
1244 
1245     if (ImeInfoEx.fLoadFlag != 2)
1246     {
1247         pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1248         if (IS_NULL_UNEXPECTEDLY(pImeDpi))
1249             return FALSE;
1250 
1251         pImeInfo = &pImeDpi->ImeInfo;
1252     }
1253     else
1254     {
1255         pImeInfo = &ImeInfoEx.ImeInfo;
1256     }
1257 
1258     switch (fdwIndex)
1259     {
1260         case IGP_PROPERTY:      dwValue = pImeInfo->fdwProperty; break;
1261         case IGP_CONVERSION:    dwValue = pImeInfo->fdwConversionCaps; break;
1262         case IGP_SENTENCE:      dwValue = pImeInfo->fdwSentenceCaps; break;
1263         case IGP_UI:            dwValue = pImeInfo->fdwUICaps; break;
1264         case IGP_SETCOMPSTR:    dwValue = pImeInfo->fdwSCSCaps; break;
1265         case IGP_SELECT:        dwValue = pImeInfo->fdwSelectCaps; break;
1266         default:                dwValue = 0; break;
1267     }
1268 
1269     if (pImeDpi)
1270         ImmUnlockImeDpi(pImeDpi);
1271     return dwValue;
1272 }
1273 
1274 /***********************************************************************
1275  *		ImmEscapeA (IMM32.@)
1276  */
ImmEscapeA(HKL hKL,HIMC hIMC,UINT uSubFunc,LPVOID lpData)1277 LRESULT WINAPI ImmEscapeA(HKL hKL, HIMC hIMC, UINT uSubFunc, LPVOID lpData)
1278 {
1279     LRESULT ret;
1280     PIMEDPI pImeDpi;
1281     INT cch;
1282     CHAR szA[MAX_IMM_FILENAME];
1283     WCHAR szW[MAX_IMM_FILENAME];
1284 
1285     TRACE("(%p, %p, %u, %p)\n", hKL, hIMC, uSubFunc, lpData);
1286 
1287     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1288     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
1289         return 0;
1290 
1291     if (!ImeDpi_IsUnicode(pImeDpi) || !lpData) /* No conversion needed */
1292     {
1293         ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1294         ImmUnlockImeDpi(pImeDpi);
1295         return ret;
1296     }
1297 
1298     switch (uSubFunc)
1299     {
1300         case IME_ESC_SEQUENCE_TO_INTERNAL:
1301             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1302 
1303             cch = 0;
1304             if (HIWORD(ret))
1305                 szW[cch++] = HIWORD(ret);
1306             if (LOWORD(ret))
1307                 szW[cch++] = LOWORD(ret);
1308 
1309             cch = WideCharToMultiByte(pImeDpi->uCodePage, 0, szW, cch, szA, _countof(szA),
1310                                       NULL, NULL);
1311             switch (cch)
1312             {
1313                 case 1:
1314                     ret = MAKEWORD(szA[0], 0);
1315                     break;
1316                 case 2:
1317                     ret = MAKEWORD(szA[1], szA[0]);
1318                     break;
1319                 case 3:
1320                     ret = MAKELONG(MAKEWORD(szA[2], szA[1]), MAKEWORD(szA[0], 0));
1321                     break;
1322                 case 4:
1323                     ret = MAKELONG(MAKEWORD(szA[3], szA[2]), MAKEWORD(szA[1], szA[0]));
1324                     break;
1325                 default:
1326                     ret = 0;
1327                     break;
1328             }
1329             break;
1330 
1331         case IME_ESC_GET_EUDC_DICTIONARY:
1332         case IME_ESC_IME_NAME:
1333         case IME_ESC_GETHELPFILENAME:
1334             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, szW, hKL);
1335             if (ret)
1336             {
1337                 szW[_countof(szW) - 1] = UNICODE_NULL; /* Avoid buffer overrun */
1338                 WideCharToMultiByte(pImeDpi->uCodePage, 0, szW, -1,
1339                                     lpData, MAX_IMM_FILENAME, NULL, NULL);
1340                 ((LPSTR)lpData)[MAX_IMM_FILENAME - 1] = 0;
1341             }
1342             break;
1343 
1344         case IME_ESC_SET_EUDC_DICTIONARY:
1345         case IME_ESC_HANJA_MODE:
1346             MultiByteToWideChar(pImeDpi->uCodePage, MB_PRECOMPOSED,
1347                                 lpData, -1, szW, _countof(szW));
1348             szW[_countof(szW) - 1] = UNICODE_NULL; /* Avoid buffer overrun */
1349             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, szW, hKL);
1350             break;
1351 
1352         default:
1353             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1354             break;
1355     }
1356 
1357     ImmUnlockImeDpi(pImeDpi);
1358     TRACE("ret: %p\n", ret);
1359     return ret;
1360 }
1361 
1362 /***********************************************************************
1363  *		ImmEscapeW (IMM32.@)
1364  */
ImmEscapeW(HKL hKL,HIMC hIMC,UINT uSubFunc,LPVOID lpData)1365 LRESULT WINAPI ImmEscapeW(HKL hKL, HIMC hIMC, UINT uSubFunc, LPVOID lpData)
1366 {
1367     LRESULT ret;
1368     PIMEDPI pImeDpi;
1369     INT cch;
1370     CHAR szA[MAX_IMM_FILENAME];
1371     WCHAR szW[MAX_IMM_FILENAME];
1372     WORD word;
1373 
1374     TRACE("(%p, %p, %u, %p)\n", hKL, hIMC, uSubFunc, lpData);
1375 
1376     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1377     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
1378         return 0;
1379 
1380     if (ImeDpi_IsUnicode(pImeDpi) || !lpData) /* No conversion needed */
1381     {
1382         ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1383         ImmUnlockImeDpi(pImeDpi);
1384         return ret;
1385     }
1386 
1387     switch (uSubFunc)
1388     {
1389         case IME_ESC_SEQUENCE_TO_INTERNAL:
1390             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1391 
1392             word = LOWORD(ret);
1393             cch = 0;
1394             if (HIBYTE(word))
1395                 szA[cch++] = HIBYTE(word);
1396             if (LOBYTE(word))
1397                 szA[cch++] = LOBYTE(word);
1398 
1399             cch = MultiByteToWideChar(pImeDpi->uCodePage, MB_PRECOMPOSED,
1400                                       szA, cch, szW, _countof(szW));
1401             switch (cch)
1402             {
1403                 case 1:  ret = szW[0]; break;
1404                 case 2:  ret = MAKELONG(szW[1], szW[0]); break;
1405                 default: ret = 0; break;
1406             }
1407             break;
1408 
1409         case IME_ESC_GET_EUDC_DICTIONARY:
1410         case IME_ESC_IME_NAME:
1411         case IME_ESC_GETHELPFILENAME:
1412             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, szA, hKL);
1413             if (ret)
1414             {
1415                 szA[_countof(szA) - 1] = 0;
1416                 MultiByteToWideChar(pImeDpi->uCodePage, MB_PRECOMPOSED,
1417                                     szA, -1, lpData, MAX_IMM_FILENAME);
1418                 ((LPWSTR)lpData)[MAX_IMM_FILENAME - 1] = UNICODE_NULL; /* Avoid buffer overrun */
1419             }
1420             break;
1421 
1422         case IME_ESC_SET_EUDC_DICTIONARY:
1423         case IME_ESC_HANJA_MODE:
1424             WideCharToMultiByte(pImeDpi->uCodePage, 0,
1425                                 lpData, -1, szA, _countof(szA), NULL, NULL);
1426             szA[_countof(szA) - 1] = 0;
1427             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, szA, hKL);
1428             break;
1429 
1430         default:
1431             ret = ImeDpi_Escape(pImeDpi, hIMC, uSubFunc, lpData, hKL);
1432             break;
1433     }
1434 
1435     ImmUnlockImeDpi(pImeDpi);
1436     TRACE("ret: %p\n", ret);
1437     return ret;
1438 }
1439 
1440 /***********************************************************************
1441  *		ImmGetOpenStatus (IMM32.@)
1442  */
ImmGetOpenStatus(HIMC hIMC)1443 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
1444 {
1445     BOOL ret;
1446     LPINPUTCONTEXT pIC;
1447 
1448     TRACE("(%p)\n", hIMC);
1449 
1450     if (IS_NULL_UNEXPECTEDLY(hIMC))
1451         return FALSE;
1452 
1453     pIC = ImmLockIMC(hIMC);
1454     if (IS_NULL_UNEXPECTEDLY(pIC))
1455         return FALSE;
1456 
1457     ret = pIC->fOpen;
1458     ImmUnlockIMC(hIMC);
1459     TRACE("ret: %d\n", ret);
1460     return ret;
1461 }
1462 
1463 /***********************************************************************
1464  *		ImmSetOpenStatus (IMM32.@)
1465  */
ImmSetOpenStatus(HIMC hIMC,BOOL fOpen)1466 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
1467 {
1468     DWORD dwConversion;
1469     LPINPUTCONTEXT pIC;
1470     HWND hWnd;
1471     BOOL bHasChange = FALSE;
1472 
1473     TRACE("(%p, %d)\n", hIMC, fOpen);
1474 
1475     if (IS_CROSS_THREAD_HIMC(hIMC))
1476         return FALSE;
1477 
1478     pIC = ImmLockIMC(hIMC);
1479     if (IS_NULL_UNEXPECTEDLY(pIC))
1480         return FALSE;
1481 
1482     if (pIC->fOpen != fOpen)
1483     {
1484         pIC->fOpen = fOpen;
1485         hWnd = pIC->hWnd;
1486         dwConversion = pIC->fdwConversion;
1487         bHasChange = TRUE;
1488     }
1489 
1490     ImmUnlockIMC(hIMC);
1491 
1492     if (bHasChange)
1493     {
1494         Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
1495                            IMC_SETOPENSTATUS, IMN_SETOPENSTATUS, 0);
1496         NtUserNotifyIMEStatus(hWnd, fOpen, dwConversion);
1497     }
1498     else
1499     {
1500         TRACE("No change.\n");
1501     }
1502 
1503     return TRUE;
1504 }
1505 
1506 /***********************************************************************
1507  *		ImmGetStatusWindowPos (IMM32.@)
1508  */
ImmGetStatusWindowPos(HIMC hIMC,LPPOINT lpptPos)1509 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1510 {
1511     LPINPUTCONTEXT pIC;
1512     BOOL ret;
1513 
1514     TRACE("(%p, %p)\n", hIMC, lpptPos);
1515 
1516     pIC = ImmLockIMC(hIMC);
1517     if (IS_NULL_UNEXPECTEDLY(pIC))
1518         return FALSE;
1519 
1520     ret = !!(pIC->fdwInit & INIT_STATUSWNDPOS);
1521     if (ret)
1522         *lpptPos = pIC->ptStatusWndPos;
1523 
1524     ImmUnlockIMC(hIMC);
1525     return ret;
1526 }
1527 
1528 /***********************************************************************
1529  *		ImmSetStatusWindowPos (IMM32.@)
1530  */
ImmSetStatusWindowPos(HIMC hIMC,LPPOINT lpptPos)1531 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1532 {
1533     LPINPUTCONTEXT pIC;
1534     HWND hWnd;
1535 
1536     TRACE("(%p, {%ld, %ld})\n", hIMC, lpptPos->x, lpptPos->y);
1537 
1538     if (IS_CROSS_THREAD_HIMC(hIMC))
1539         return FALSE;
1540 
1541     pIC = ImmLockIMC(hIMC);
1542     if (IS_NULL_UNEXPECTEDLY(pIC))
1543         return FALSE;
1544 
1545     hWnd = pIC->hWnd;
1546     pIC->ptStatusWndPos = *lpptPos;
1547     pIC->fdwInit |= INIT_STATUSWNDPOS;
1548 
1549     ImmUnlockIMC(hIMC);
1550 
1551     Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
1552                        IMC_SETSTATUSWINDOWPOS, IMN_SETSTATUSWINDOWPOS, 0);
1553     return TRUE;
1554 }
1555 
1556 /***********************************************************************
1557  *		ImmGetCompositionWindow (IMM32.@)
1558  */
ImmGetCompositionWindow(HIMC hIMC,LPCOMPOSITIONFORM lpCompForm)1559 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1560 {
1561     LPINPUTCONTEXT pIC;
1562     BOOL ret = FALSE;
1563 
1564     TRACE("(%p, %p)\n", hIMC, lpCompForm);
1565 
1566     pIC = ImmLockIMC(hIMC);
1567     if (IS_NULL_UNEXPECTEDLY(pIC))
1568         return FALSE;
1569 
1570     if (pIC->fdwInit & INIT_COMPFORM)
1571     {
1572         *lpCompForm = pIC->cfCompForm;
1573         ret = TRUE;
1574     }
1575 
1576     ImmUnlockIMC(hIMC);
1577     return ret;
1578 }
1579 
1580 /***********************************************************************
1581  *		ImmSetCompositionWindow (IMM32.@)
1582  */
ImmSetCompositionWindow(HIMC hIMC,LPCOMPOSITIONFORM lpCompForm)1583 BOOL WINAPI ImmSetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1584 {
1585     LPINPUTCONTEXTDX pIC;
1586     HWND hWnd;
1587 
1588     if (Imm32IsCrossThreadAccess(hIMC))
1589         return FALSE;
1590 
1591     pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1592     if (IS_NULL_UNEXPECTEDLY(pIC))
1593         return FALSE;
1594 
1595     pIC->cfCompForm = *lpCompForm;
1596     pIC->fdwInit |= INIT_COMPFORM;
1597 
1598     if (pIC->dwUIFlags & 0x8)
1599         pIC->dwUIFlags &= ~0x8;
1600     else
1601         pIC->dwUIFlags &= ~0x2;
1602 
1603     hWnd = pIC->hWnd;
1604 
1605     ImmUnlockIMC(hIMC);
1606 
1607     Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0,
1608                        IMC_SETCOMPOSITIONWINDOW, IMN_SETCOMPOSITIONWINDOW, 0);
1609     return TRUE;
1610 }
1611 
1612 /***********************************************************************
1613  *		ImmGetCompositionFontA (IMM32.@)
1614  */
ImmGetCompositionFontA(HIMC hIMC,LPLOGFONTA lplf)1615 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1616 {
1617     PCLIENTIMC pClientImc;
1618     BOOL ret = FALSE, bWide;
1619     LPINPUTCONTEXT pIC;
1620 
1621     TRACE("(%p, %p)\n", hIMC, lplf);
1622 
1623     pClientImc = ImmLockClientImc(hIMC);
1624     if (IS_NULL_UNEXPECTEDLY(pClientImc))
1625         return FALSE;
1626 
1627     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
1628     ImmUnlockClientImc(pClientImc);
1629 
1630     pIC = ImmLockIMC(hIMC);
1631     if (IS_NULL_UNEXPECTEDLY(pIC))
1632         return FALSE;
1633 
1634     if (pIC->fdwInit & INIT_LOGFONT)
1635     {
1636         if (bWide)
1637             LogFontWideToAnsi(&pIC->lfFont.W, lplf);
1638         else
1639             *lplf = pIC->lfFont.A;
1640 
1641         ret = TRUE;
1642     }
1643 
1644     ImmUnlockIMC(hIMC);
1645     return ret;
1646 }
1647 
1648 /***********************************************************************
1649  *		ImmGetCompositionFontW (IMM32.@)
1650  */
ImmGetCompositionFontW(HIMC hIMC,LPLOGFONTW lplf)1651 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1652 {
1653     PCLIENTIMC pClientImc;
1654     BOOL bWide;
1655     LPINPUTCONTEXT pIC;
1656     BOOL ret = FALSE;
1657 
1658     TRACE("(%p, %p)\n", hIMC, lplf);
1659 
1660     pClientImc = ImmLockClientImc(hIMC);
1661     if (IS_NULL_UNEXPECTEDLY(pClientImc))
1662         return FALSE;
1663 
1664     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
1665     ImmUnlockClientImc(pClientImc);
1666 
1667     pIC = ImmLockIMC(hIMC);
1668     if (IS_NULL_UNEXPECTEDLY(pIC))
1669         return FALSE;
1670 
1671     if (pIC->fdwInit & INIT_LOGFONT)
1672     {
1673         if (bWide)
1674             *lplf = pIC->lfFont.W;
1675         else
1676             LogFontAnsiToWide(&pIC->lfFont.A, lplf);
1677 
1678         ret = TRUE;
1679     }
1680 
1681     ImmUnlockIMC(hIMC);
1682     return ret;
1683 }
1684 
1685 /***********************************************************************
1686  *		ImmSetCompositionFontA (IMM32.@)
1687  */
ImmSetCompositionFontA(HIMC hIMC,LPLOGFONTA lplf)1688 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1689 {
1690     LOGFONTW lfW;
1691     PCLIENTIMC pClientImc;
1692     BOOL bWide;
1693     LPINPUTCONTEXTDX pIC;
1694     LANGID LangID;
1695     HWND hWnd;
1696 
1697     TRACE("(%p, %p)\n", hIMC, lplf);
1698 
1699     if (IS_CROSS_THREAD_HIMC(hIMC))
1700         return FALSE;
1701 
1702     pClientImc = ImmLockClientImc(hIMC);
1703     if (IS_NULL_UNEXPECTEDLY(pClientImc))
1704         return FALSE;
1705 
1706     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
1707     ImmUnlockClientImc(pClientImc);
1708 
1709     if (bWide)
1710     {
1711         LogFontAnsiToWide(lplf, &lfW);
1712         return ImmSetCompositionFontW(hIMC, &lfW);
1713     }
1714 
1715     pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1716     if (IS_NULL_UNEXPECTEDLY(pIC))
1717         return FALSE;
1718 
1719     if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */
1720     {
1721         LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
1722         if (PRIMARYLANGID(LangID) == LANG_JAPANESE &&
1723             !(pIC->dwUIFlags & 2) &&
1724             pIC->cfCompForm.dwStyle != CFS_DEFAULT)
1725         {
1726             PostMessageA(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
1727         }
1728     }
1729 
1730     pIC->lfFont.A = *lplf;
1731     pIC->fdwInit |= INIT_LOGFONT;
1732     hWnd = pIC->hWnd;
1733 
1734     ImmUnlockIMC(hIMC);
1735 
1736     Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT,
1737                        IMN_SETCOMPOSITIONFONT, 0);
1738     return TRUE;
1739 }
1740 
1741 /***********************************************************************
1742  *		ImmSetCompositionFontW (IMM32.@)
1743  */
ImmSetCompositionFontW(HIMC hIMC,LPLOGFONTW lplf)1744 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1745 {
1746     LOGFONTA lfA;
1747     PCLIENTIMC pClientImc;
1748     BOOL bWide;
1749     HWND hWnd;
1750     LPINPUTCONTEXTDX pIC;
1751     LANGID LangID;
1752 
1753     TRACE("(%p, %p)\n", hIMC, lplf);
1754 
1755     if (IS_CROSS_THREAD_HIMC(hIMC))
1756         return FALSE;
1757 
1758     pClientImc = ImmLockClientImc(hIMC);
1759     if (IS_NULL_UNEXPECTEDLY(pClientImc))
1760         return FALSE;
1761 
1762     bWide = (pClientImc->dwFlags & CLIENTIMC_WIDE);
1763     ImmUnlockClientImc(pClientImc);
1764 
1765     if (!bWide)
1766     {
1767         LogFontWideToAnsi(lplf, &lfA);
1768         return ImmSetCompositionFontA(hIMC, &lfA);
1769     }
1770 
1771     pIC = (LPINPUTCONTEXTDX)ImmLockIMC(hIMC);
1772     if (IS_NULL_UNEXPECTEDLY(pIC))
1773         return FALSE;
1774 
1775     if (GetWin32ClientInfo()->dwExpWinVer < _WIN32_WINNT_NT4) /* old version (3.x)? */
1776     {
1777         LangID = LANGIDFROMLCID(GetSystemDefaultLCID());
1778         if (PRIMARYLANGID(LangID) == LANG_JAPANESE &&
1779             !(pIC->dwUIFlags & 2) &&
1780             pIC->cfCompForm.dwStyle != CFS_DEFAULT)
1781         {
1782             PostMessageW(pIC->hWnd, WM_IME_REPORT, IR_CHANGECONVERT, 0);
1783         }
1784     }
1785 
1786     pIC->lfFont.W = *lplf;
1787     pIC->fdwInit |= INIT_LOGFONT;
1788     hWnd = pIC->hWnd;
1789 
1790     ImmUnlockIMC(hIMC);
1791 
1792     Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT,
1793                        IMN_SETCOMPOSITIONFONT, 0);
1794     return TRUE;
1795 }
1796 
1797 /***********************************************************************
1798  *		ImmGetConversionListA (IMM32.@)
1799  */
1800 DWORD WINAPI
ImmGetConversionListA(HKL hKL,HIMC hIMC,LPCSTR pSrc,LPCANDIDATELIST lpDst,DWORD dwBufLen,UINT uFlag)1801 ImmGetConversionListA(HKL hKL, HIMC hIMC, LPCSTR pSrc, LPCANDIDATELIST lpDst,
1802                       DWORD dwBufLen, UINT uFlag)
1803 {
1804     DWORD ret = 0;
1805     UINT cb;
1806     LPWSTR pszSrcW = NULL;
1807     LPCANDIDATELIST pCL = NULL;
1808     PIMEDPI pImeDpi;
1809 
1810     TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_a(pSrc),
1811           lpDst, dwBufLen, uFlag);
1812 
1813     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1814     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
1815         return 0;
1816 
1817     if (!ImeDpi_IsUnicode(pImeDpi)) /* No conversion needed */
1818     {
1819         ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag);
1820         ImmUnlockImeDpi(pImeDpi);
1821         return ret;
1822     }
1823 
1824     if (pSrc)
1825     {
1826         pszSrcW = Imm32WideFromAnsi(pImeDpi->uCodePage, pSrc);
1827         if (IS_NULL_UNEXPECTEDLY(pszSrcW))
1828             goto Quit;
1829     }
1830 
1831     cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, NULL, 0, uFlag);
1832     if (IS_ZERO_UNEXPECTEDLY(cb))
1833         goto Quit;
1834 
1835     pCL = ImmLocalAlloc(0, cb);
1836     if (IS_NULL_UNEXPECTEDLY(pCL))
1837         goto Quit;
1838 
1839     cb = pImeDpi->ImeConversionList(hIMC, pszSrcW, pCL, cb, uFlag);
1840     if (IS_ZERO_UNEXPECTEDLY(cb))
1841         goto Quit;
1842 
1843     ret = CandidateListWideToAnsi(pCL, lpDst, dwBufLen, pImeDpi->uCodePage);
1844 
1845 Quit:
1846     ImmLocalFree(pszSrcW);
1847     ImmLocalFree(pCL);
1848     ImmUnlockImeDpi(pImeDpi);
1849     TRACE("ret: 0x%X\n", ret);
1850     return ret;
1851 }
1852 
1853 /***********************************************************************
1854  *		ImmGetConversionListW (IMM32.@)
1855  */
1856 DWORD WINAPI
ImmGetConversionListW(HKL hKL,HIMC hIMC,LPCWSTR pSrc,LPCANDIDATELIST lpDst,DWORD dwBufLen,UINT uFlag)1857 ImmGetConversionListW(HKL hKL, HIMC hIMC, LPCWSTR pSrc, LPCANDIDATELIST lpDst,
1858                       DWORD dwBufLen, UINT uFlag)
1859 {
1860     DWORD ret = 0;
1861     INT cb;
1862     PIMEDPI pImeDpi;
1863     LPCANDIDATELIST pCL = NULL;
1864     LPSTR pszSrcA = NULL;
1865 
1866     TRACE("(%p, %p, %s, %p, %lu, 0x%lX)\n", hKL, hIMC, debugstr_w(pSrc),
1867           lpDst, dwBufLen, uFlag);
1868 
1869     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
1870     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
1871         return 0;
1872 
1873     if (ImeDpi_IsUnicode(pImeDpi)) /* No conversion needed */
1874     {
1875         ret = pImeDpi->ImeConversionList(hIMC, pSrc, lpDst, dwBufLen, uFlag);
1876         ImmUnlockImeDpi(pImeDpi);
1877         return ret;
1878     }
1879 
1880     if (pSrc)
1881     {
1882         pszSrcA = Imm32AnsiFromWide(pImeDpi->uCodePage, pSrc);
1883         if (IS_NULL_UNEXPECTEDLY(pszSrcA))
1884             goto Quit;
1885     }
1886 
1887     cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, NULL, 0, uFlag);
1888     if (IS_ZERO_UNEXPECTEDLY(cb))
1889         goto Quit;
1890 
1891     pCL = ImmLocalAlloc(0, cb);
1892     if (IS_NULL_UNEXPECTEDLY(pCL))
1893         goto Quit;
1894 
1895     cb = pImeDpi->ImeConversionList(hIMC, pszSrcA, pCL, cb, uFlag);
1896     if (IS_ZERO_UNEXPECTEDLY(cb))
1897         goto Quit;
1898 
1899     ret = CandidateListAnsiToWide(pCL, lpDst, dwBufLen, pImeDpi->uCodePage);
1900 
1901 Quit:
1902     ImmLocalFree(pszSrcA);
1903     ImmLocalFree(pCL);
1904     ImmUnlockImeDpi(pImeDpi);
1905     TRACE("ret: 0x%X\n", ret);
1906     return ret;
1907 }
1908 
1909 /***********************************************************************
1910  *		ImmGetConversionStatus (IMM32.@)
1911  */
ImmGetConversionStatus(HIMC hIMC,LPDWORD lpfdwConversion,LPDWORD lpfdwSentence)1912 BOOL WINAPI ImmGetConversionStatus(HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
1913 {
1914     LPINPUTCONTEXT pIC;
1915 
1916     TRACE("(%p %p %p)\n", hIMC, lpfdwConversion, lpfdwSentence);
1917 
1918     pIC = ImmLockIMC(hIMC);
1919     if (IS_NULL_UNEXPECTEDLY(pIC))
1920         return FALSE;
1921 
1922     if (lpfdwConversion)
1923     {
1924         *lpfdwConversion = pIC->fdwConversion;
1925         TRACE("0x%X\n", *lpfdwConversion);
1926     }
1927 
1928     if (lpfdwSentence)
1929     {
1930         *lpfdwSentence = pIC->fdwSentence;
1931         TRACE("0x%X\n", *lpfdwSentence);
1932     }
1933 
1934     ImmUnlockIMC(hIMC);
1935     return TRUE;
1936 }
1937 
1938 /***********************************************************************
1939  *		ImmSetConversionStatus (IMM32.@)
1940  */
ImmSetConversionStatus(HIMC hIMC,DWORD fdwConversion,DWORD fdwSentence)1941 BOOL WINAPI ImmSetConversionStatus(HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
1942 {
1943     HKL hKL;
1944     LPINPUTCONTEXT pIC;
1945     DWORD dwOldConversion, dwOldSentence;
1946     BOOL fOpen = FALSE, fConversionChange = FALSE, fSentenceChange = FALSE, fUseCicero = FALSE;
1947     HWND hWnd;
1948 
1949     TRACE("(%p, 0x%lX, 0x%lX)\n", hIMC, fdwConversion, fdwSentence);
1950 
1951     hKL = GetKeyboardLayout(0);
1952     if (!IS_IME_HKL(hKL) && IS_CICERO_MODE() && !IS_16BIT_MODE())
1953         fUseCicero = TRUE;
1954 
1955     if (IS_CROSS_THREAD_HIMC(hIMC))
1956         return FALSE;
1957 
1958     pIC = ImmLockIMC(hIMC);
1959     if (IS_NULL_UNEXPECTEDLY(pIC))
1960         return FALSE;
1961 
1962     if (pIC->fdwConversion != fdwConversion)
1963     {
1964         dwOldConversion = pIC->fdwConversion;
1965         pIC->fdwConversion = fdwConversion;
1966         fConversionChange = TRUE;
1967     }
1968 
1969     if (pIC->fdwSentence != fdwSentence)
1970     {
1971         dwOldSentence = pIC->fdwSentence;
1972         pIC->fdwSentence = fdwSentence;
1973         fSentenceChange = TRUE;
1974     }
1975 
1976     hWnd = pIC->hWnd;
1977     fOpen = pIC->fOpen;
1978     ImmUnlockIMC(hIMC);
1979 
1980     if (fConversionChange || fUseCicero)
1981     {
1982         Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldConversion,
1983                            IMC_SETCONVERSIONMODE, IMN_SETCONVERSIONMODE, 0);
1984         if (fConversionChange)
1985             NtUserNotifyIMEStatus(hWnd, fOpen, fdwConversion);
1986     }
1987 
1988     if (fSentenceChange || fUseCicero)
1989     {
1990         Imm32MakeIMENotify(hIMC, hWnd, NI_CONTEXTUPDATED, dwOldSentence,
1991                            IMC_SETSENTENCEMODE, IMN_SETSENTENCEMODE, 0);
1992     }
1993 
1994     return TRUE;
1995 }
1996 
1997 /***********************************************************************
1998  *		ImmConfigureIMEA (IMM32.@)
1999  */
ImmConfigureIMEA(HKL hKL,HWND hWnd,DWORD dwMode,LPVOID lpData)2000 BOOL WINAPI ImmConfigureIMEA(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
2001 {
2002     BOOL ret = FALSE;
2003     PIMEDPI pImeDpi;
2004     REGISTERWORDW RegWordW;
2005     LPREGISTERWORDA pRegWordA;
2006 
2007     TRACE("(%p, %p, 0x%lX, %p)\n", hKL, hWnd, dwMode, lpData);
2008 
2009     if (IS_NULL_UNEXPECTEDLY(ValidateHwnd(hWnd)) || IS_CROSS_PROCESS_HWND(hWnd))
2010         return FALSE;
2011 
2012     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
2013     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
2014         return FALSE;
2015 
2016     RtlZeroMemory(&RegWordW, sizeof(RegWordW));
2017 
2018     if (!ImeDpi_IsUnicode(pImeDpi) || !lpData || dwMode != IME_CONFIG_REGISTERWORD)
2019         goto DoIt; /* No conversion needed */
2020 
2021     pRegWordA = lpData;
2022 
2023     if (pRegWordA->lpReading)
2024     {
2025         RegWordW.lpReading = Imm32WideFromAnsi(pImeDpi->uCodePage, pRegWordA->lpReading);
2026         if (IS_NULL_UNEXPECTEDLY(RegWordW.lpReading))
2027             goto Quit;
2028     }
2029 
2030     if (pRegWordA->lpWord)
2031     {
2032         RegWordW.lpWord = Imm32WideFromAnsi(pImeDpi->uCodePage, pRegWordA->lpWord);
2033         if (IS_NULL_UNEXPECTEDLY(RegWordW.lpWord))
2034             goto Quit;
2035     }
2036 
2037     lpData = &RegWordW;
2038 
2039 DoIt:
2040     SendMessageW(hWnd, WM_IME_SYSTEM, 0x1B, 0);
2041     ret = pImeDpi->ImeConfigure(hKL, hWnd, dwMode, lpData);
2042     SendMessageW(hWnd, WM_IME_SYSTEM, 0x1A, 0);
2043 
2044 Quit:
2045     ImmLocalFree(RegWordW.lpReading);
2046     ImmLocalFree(RegWordW.lpWord);
2047     ImmUnlockImeDpi(pImeDpi);
2048     TRACE("ret: %d\n", ret);
2049     return ret;
2050 }
2051 
2052 /***********************************************************************
2053  *		ImmConfigureIMEW (IMM32.@)
2054  */
ImmConfigureIMEW(HKL hKL,HWND hWnd,DWORD dwMode,LPVOID lpData)2055 BOOL WINAPI ImmConfigureIMEW(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
2056 {
2057     BOOL ret = FALSE;
2058     PIMEDPI pImeDpi;
2059     REGISTERWORDA RegWordA;
2060     LPREGISTERWORDW pRegWordW;
2061 
2062     TRACE("(%p, %p, 0x%lX, %p)\n", hKL, hWnd, dwMode, lpData);
2063 
2064     if (IS_NULL_UNEXPECTEDLY(ValidateHwnd(hWnd)) || IS_CROSS_PROCESS_HWND(hWnd))
2065         return FALSE;
2066 
2067     pImeDpi = Imm32FindOrLoadImeDpi(hKL);
2068     if (IS_NULL_UNEXPECTEDLY(pImeDpi))
2069         return FALSE;
2070 
2071     RtlZeroMemory(&RegWordA, sizeof(RegWordA));
2072 
2073     if (ImeDpi_IsUnicode(pImeDpi) || !lpData || dwMode != IME_CONFIG_REGISTERWORD)
2074         goto DoIt; /* No conversion needed */
2075 
2076     pRegWordW = lpData;
2077 
2078     if (pRegWordW->lpReading)
2079     {
2080         RegWordA.lpReading = Imm32AnsiFromWide(pImeDpi->uCodePage, pRegWordW->lpReading);
2081         if (IS_NULL_UNEXPECTEDLY(RegWordA.lpReading))
2082             goto Quit;
2083     }
2084 
2085     if (pRegWordW->lpWord)
2086     {
2087         RegWordA.lpWord = Imm32AnsiFromWide(pImeDpi->uCodePage, pRegWordW->lpWord);
2088         if (IS_NULL_UNEXPECTEDLY(RegWordA.lpWord))
2089             goto Quit;
2090     }
2091 
2092     lpData = &RegWordA;
2093 
2094 DoIt:
2095     SendMessageW(hWnd, WM_IME_SYSTEM, 0x1B, 0);
2096     ret = pImeDpi->ImeConfigure(hKL, hWnd, dwMode, lpData);
2097     SendMessageW(hWnd, WM_IME_SYSTEM, 0x1A, 0);
2098 
2099 Quit:
2100     ImmLocalFree(RegWordA.lpReading);
2101     ImmLocalFree(RegWordA.lpWord);
2102     ImmUnlockImeDpi(pImeDpi);
2103     TRACE("ret: %d\n", ret);
2104     return ret;
2105 }
2106 
2107 /***********************************************************************
2108  *		ImmGetImeMenuItemsA (IMM32.@)
2109  */
2110 DWORD WINAPI
ImmGetImeMenuItemsA(HIMC hIMC,DWORD dwFlags,DWORD dwType,LPIMEMENUITEMINFOA lpImeParentMenu,LPIMEMENUITEMINFOA lpImeMenu,DWORD dwSize)2111 ImmGetImeMenuItemsA(HIMC hIMC, DWORD dwFlags, DWORD dwType,
2112                     LPIMEMENUITEMINFOA lpImeParentMenu,
2113                     LPIMEMENUITEMINFOA lpImeMenu, DWORD dwSize)
2114 {
2115     TRACE("(%p, 0x%lX, 0x%lX, %p, %p, 0x%lX)\n",
2116           hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize);
2117     return ImmGetImeMenuItemsAW(hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize, TRUE);
2118 }
2119 
2120 /***********************************************************************
2121  *		ImmGetImeMenuItemsW (IMM32.@)
2122  */
2123 DWORD WINAPI
ImmGetImeMenuItemsW(HIMC hIMC,DWORD dwFlags,DWORD dwType,LPIMEMENUITEMINFOW lpImeParentMenu,LPIMEMENUITEMINFOW lpImeMenu,DWORD dwSize)2124 ImmGetImeMenuItemsW(HIMC hIMC, DWORD dwFlags, DWORD dwType,
2125                     LPIMEMENUITEMINFOW lpImeParentMenu,
2126                     LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize)
2127 {
2128     TRACE("(%p, 0x%lX, 0x%lX, %p, %p, 0x%lX)\n",
2129           hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize);
2130     return ImmGetImeMenuItemsAW(hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize, FALSE);
2131 }
2132 
2133 /***********************************************************************
2134  *		ImmWINNLSEnableIME (IMM32.@)
2135  */
ImmWINNLSEnableIME(HWND hWnd,BOOL enable)2136 BOOL WINAPI ImmWINNLSEnableIME(HWND hWnd, BOOL enable)
2137 {
2138     HIMC hIMC;
2139     PCLIENTIMC pClientImc;
2140     HWND hImeWnd;
2141     BOOL bImeWnd, ret;
2142 
2143     TRACE("(%p, %d)\n", hWnd, enable);
2144 
2145     if (!Imm32IsSystemJapaneseOrKorean())
2146     {
2147         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2148         return FALSE;
2149     }
2150 
2151     hIMC = (HIMC)NtUserGetThreadState(THREADSTATE_DEFAULTINPUTCONTEXT);
2152     if (IS_NULL_UNEXPECTEDLY(hIMC))
2153         return FALSE;
2154 
2155     pClientImc = ImmLockClientImc(hIMC);
2156     if (IS_NULL_UNEXPECTEDLY(pClientImc))
2157         return FALSE;
2158 
2159     ret = !(pClientImc->dwFlags & CLIENTIMC_DISABLEIME);
2160     if (!!enable == ret)
2161     {
2162         TRACE("Same\n");
2163         ImmUnlockClientImc(pClientImc);
2164         return ret;
2165     }
2166 
2167     if (!IsWindow(hWnd))
2168         hWnd = GetFocus();
2169 
2170     hImeWnd = ImmGetDefaultIMEWnd(hWnd);
2171     bImeWnd = IsWindow(hImeWnd);
2172     if (bImeWnd)
2173         ImmSetActiveContext(hWnd, (enable ? NULL : hIMC), FALSE);
2174 
2175     if (enable)
2176         pClientImc->dwFlags &= ~CLIENTIMC_DISABLEIME;
2177     else
2178         pClientImc->dwFlags |= CLIENTIMC_DISABLEIME;
2179 
2180     ImmUnlockClientImc(pClientImc);
2181 
2182     if (bImeWnd)
2183         ImmSetActiveContext(hWnd, (enable ? hIMC : NULL), TRUE);
2184 
2185     return ret;
2186 }
2187