xref: /reactos/win32ss/user/user32/misc/imm.c (revision dcf0788f)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS user32.dll
4  * FILE:            win32ss/user/user32/misc/imm.c
5  * PURPOSE:         User32.dll Imm functions
6  * PROGRAMMERS:     Dmitry Chapyshev (dmitry@reactos.org)
7  *                  Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
8  */
9 
10 #include <user32.h>
11 #include <strsafe.h>
12 #include <immdev.h>
13 
14 WINE_DEFAULT_DEBUG_CHANNEL(user32);
15 
16 #define IMM_INIT_MAGIC 0x19650412
17 #define MAX_CANDIDATEFORM 4
18 
19 /* Is != NULL when we have loaded the IMM ourselves */
20 HINSTANCE ghImm32 = NULL; // Win: ghImm32
21 
22 BOOL gbImmInitializing = FALSE; // Win: bImmInitializing
23 
24 INT gfConIme = -1; // Win: gfConIme
25 
IntGetTopLevelWindow(HWND hWnd)26 HWND FASTCALL IntGetTopLevelWindow(HWND hWnd)
27 {
28     DWORD style;
29 
30     for (; hWnd; hWnd = GetParent(hWnd))
31     {
32         style = (DWORD)GetWindowLongPtrW(hWnd, GWL_STYLE);
33         if (!(style & WS_CHILD))
34             break;
35     }
36 
37     return hWnd;
38 }
39 
40 /* define stub functions */
41 #undef DEFINE_IMM_ENTRY
42 #define DEFINE_IMM_ENTRY(type, name, params, retval, retkind) \
43     static type WINAPI IMMSTUB_##name params { IMM_RETURN_##retkind((type)retval); }
44 #include "immtable.h"
45 
46 // Win: gImmApiEntries
47 Imm32ApiTable gImmApiEntries = {
48 /* initialize by stubs */
49 #undef DEFINE_IMM_ENTRY
50 #define DEFINE_IMM_ENTRY(type, name, params, retval, retkind) \
51     IMMSTUB_##name,
52 #include "immtable.h"
53 };
54 
55 // Win: GetImmFileName
56 HRESULT
User32GetImmFileName(_Out_ LPWSTR lpBuffer,_In_ size_t cchBuffer)57 User32GetImmFileName(_Out_ LPWSTR lpBuffer, _In_ size_t cchBuffer)
58 {
59     UINT length = GetSystemDirectoryW(lpBuffer, cchBuffer);
60     if (length && length < cchBuffer)
61     {
62         StringCchCatW(lpBuffer, cchBuffer, L"\\");
63         return StringCchCatW(lpBuffer, cchBuffer, L"imm32.dll");
64     }
65     return StringCchCopyW(lpBuffer, cchBuffer, L"imm32.dll");
66 }
67 
68 // @unimplemented
69 // Win: _InitializeImmEntryTable
IntInitializeImmEntryTable(VOID)70 static BOOL IntInitializeImmEntryTable(VOID)
71 {
72     WCHAR ImmFile[MAX_PATH];
73     HMODULE imm32 = ghImm32;
74 
75     /* Check whether the IMM table has already been initialized */
76     if (IMM_FN(ImmWINNLSEnableIME) != IMMSTUB_ImmWINNLSEnableIME)
77         return TRUE;
78 
79     User32GetImmFileName(ImmFile, _countof(ImmFile));
80     TRACE("File %S\n", ImmFile);
81 
82     /* If IMM32 is already loaded, use it without increasing reference count. */
83     if (imm32 == NULL)
84         imm32 = GetModuleHandleW(ImmFile);
85 
86     /*
87      * Loading imm32.dll will call imm32!DllMain function.
88      * imm32!DllMain calls User32InitializeImmEntryTable.
89      * Thus, if imm32.dll was loaded, the table has been loaded.
90      */
91     if (imm32 == NULL)
92     {
93         imm32 = ghImm32 = LoadLibraryW(ImmFile);
94         if (imm32 == NULL)
95         {
96             ERR("Did not load imm32.dll!\n");
97             return FALSE;
98         }
99         return TRUE;
100     }
101 
102 /* load imm procedures */
103 #undef DEFINE_IMM_ENTRY
104 #define DEFINE_IMM_ENTRY(type, name, params, retval, retkind) \
105     do { \
106         FN_##name proc = (FN_##name)GetProcAddress(imm32, #name); \
107         if (!proc) { \
108             ERR("Could not load %s\n", #name); \
109             return FALSE; \
110         } \
111         IMM_FN(name) = proc; \
112     } while (0);
113 #include "immtable.h"
114 
115     return TRUE;
116 }
117 
118 // Win: InitializeImmEntryTable
InitializeImmEntryTable(VOID)119 BOOL WINAPI InitializeImmEntryTable(VOID)
120 {
121     gbImmInitializing = TRUE;
122     return IntInitializeImmEntryTable();
123 }
124 
125 // Win: User32InitializeImmEntryTable
User32InitializeImmEntryTable(DWORD magic)126 BOOL WINAPI User32InitializeImmEntryTable(DWORD magic)
127 {
128     TRACE("Imm (%x)\n", magic);
129 
130     if (magic != IMM_INIT_MAGIC)
131         return FALSE;
132 
133     /* Check whether the IMM table has already been initialized */
134     if (IMM_FN(ImmWINNLSEnableIME) != IMMSTUB_ImmWINNLSEnableIME)
135         return TRUE;
136 
137     IntInitializeImmEntryTable();
138 
139     if (ghImm32 == NULL && !gbImmInitializing)
140     {
141         WCHAR ImmFile[MAX_PATH];
142         User32GetImmFileName(ImmFile, _countof(ImmFile));
143         ghImm32 = LoadLibraryW(ImmFile);
144         if (ghImm32 == NULL)
145         {
146             ERR("Did not load imm32.dll!\n");
147             return FALSE;
148         }
149     }
150 
151     return IMM_FN(ImmRegisterClient)(&gSharedInfo, ghImm32);
152 }
153 
154 // Win: ImeIsUsableContext
User32CanSetImeWindowToImc(HIMC hIMC,HWND hImeWnd)155 static BOOL User32CanSetImeWindowToImc(HIMC hIMC, HWND hImeWnd)
156 {
157     PIMC pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT);
158     return pIMC && (!pIMC->hImeWnd || pIMC->hImeWnd == hImeWnd || !ValidateHwnd(pIMC->hImeWnd));
159 }
160 
161 // Win: GetIMEShowStatus
User32GetImeShowStatus(VOID)162 static BOOL User32GetImeShowStatus(VOID)
163 {
164     return (BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_GETIMESHOWSTATUS);
165 }
166 
167 /* Sends a message to the IME UI window. */
168 /* Win: SendMessageToUI(pimeui, uMsg, wParam, lParam, !unicode) */
169 static LRESULT
User32SendImeUIMessage(PIMEUI pimeui,UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL unicode)170 User32SendImeUIMessage(PIMEUI pimeui, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL unicode)
171 {
172     LRESULT ret = 0;
173     HWND hwndUI = pimeui->hwndUI;
174     PWND pwnd, pwndUI;
175 
176     ASSERT(pimeui->spwnd != NULL);
177 
178     pwnd = pimeui->spwnd;
179     pwndUI = ValidateHwnd(hwndUI);
180     if (!pwnd || (pwnd->state & WNDS_DESTROYED) || (pwnd->state2 & WNDS2_INDESTROY) ||
181         !pwndUI || (pwndUI->state & WNDS_DESTROYED) || (pwndUI->state2 & WNDS2_INDESTROY))
182     {
183         return 0;
184     }
185 
186     InterlockedIncrement(&pimeui->nCntInIMEProc);
187 
188     if (unicode)
189         ret = SendMessageW(hwndUI, uMsg, wParam, lParam);
190     else
191         ret = SendMessageA(hwndUI, uMsg, wParam, lParam);
192 
193     InterlockedDecrement(&pimeui->nCntInIMEProc);
194 
195     return ret;
196 }
197 
198 // Win: SendOpenStatusNotify
User32NotifyOpenStatus(PIMEUI pimeui,HWND hwndIMC,BOOL bOpen)199 static VOID User32NotifyOpenStatus(PIMEUI pimeui, HWND hwndIMC, BOOL bOpen)
200 {
201     WPARAM wParam = (bOpen ? IMN_OPENSTATUSWINDOW : IMN_CLOSESTATUSWINDOW);
202 
203     ASSERT(pimeui->spwnd != NULL);
204 
205     pimeui->fShowStatus = bOpen;
206 
207     if (LOWORD(GetWin32ClientInfo()->dwExpWinVer) >= 0x400)
208         SendMessageW(hwndIMC, WM_IME_NOTIFY, wParam, 0);
209     else
210         User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, wParam, 0, TRUE);
211 }
212 
213 // Win: ImeMarkUsedContext
User32SetImeWindowOfImc(HIMC hIMC,HWND hImeWnd)214 static VOID User32SetImeWindowOfImc(HIMC hIMC, HWND hImeWnd)
215 {
216     PIMC pIMC = ValidateHandle(hIMC, TYPE_INPUTCONTEXT);
217     if (!pIMC || pIMC->hImeWnd == hImeWnd)
218         return;
219 
220     NtUserUpdateInputContext(hIMC, UIC_IMEWINDOW, (ULONG_PTR)hImeWnd);
221 }
222 
223 // Win: ImeSetImc
User32UpdateImcOfImeUI(PIMEUI pimeui,HIMC hNewIMC)224 static VOID User32UpdateImcOfImeUI(PIMEUI pimeui, HIMC hNewIMC)
225 {
226     HWND hImeWnd;
227     HIMC hOldIMC = pimeui->hIMC;
228 
229     ASSERT(pimeui->spwnd != NULL);
230     hImeWnd = UserHMGetHandle(pimeui->spwnd);
231 
232     if (hNewIMC == hOldIMC)
233         return;
234 
235     if (hOldIMC)
236         User32SetImeWindowOfImc(hOldIMC, NULL);
237 
238     pimeui->hIMC = hNewIMC;
239 
240     if (hNewIMC)
241         User32SetImeWindowOfImc(hNewIMC, hImeWnd);
242 }
243 
244 /* Handles WM_IME_NOTIFY message of the default IME window. */
245 /* Win: ImeNotifyHandler */
ImeWnd_OnImeNotify(PIMEUI pimeui,WPARAM wParam,LPARAM lParam)246 static LRESULT ImeWnd_OnImeNotify(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
247 {
248     LRESULT ret = 0;
249     HIMC hIMC;
250     LPINPUTCONTEXT pIC;
251     HWND hwndUI, hwndIMC, hImeWnd, hwndOwner;
252 
253     ASSERT(pimeui->spwnd != NULL);
254 
255     switch (wParam)
256     {
257         case IMN_SETCONVERSIONMODE:
258         case IMN_SETOPENSTATUS:
259             hIMC = pimeui->hIMC;
260             pIC = IMM_FN(ImmLockIMC)(hIMC);
261             if (pIC)
262             {
263                 hwndIMC = pimeui->hwndIMC;
264                 if (IsWindow(hwndIMC))
265                 {
266                     NtUserNotifyIMEStatus(hwndIMC, pIC->fOpen, pIC->fdwConversion);
267                 }
268                 else if (gfConIme == TRUE && pimeui->spwnd)
269                 {
270                     hImeWnd = UserHMGetHandle(pimeui->spwnd);
271                     hwndOwner = GetWindow(hImeWnd, GW_OWNER);
272                     if (hwndOwner)
273                     {
274                         NtUserNotifyIMEStatus(hwndOwner, pIC->fOpen, pIC->fdwConversion);
275                     }
276                 }
277 
278                 IMM_FN(ImmUnlockIMC)(hIMC);
279             }
280             /* FALL THROUGH */
281         default:
282             ret = User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, wParam, lParam, TRUE);
283             break;
284 
285         case IMN_PRIVATE:
286             hwndUI = pimeui->hwndUI;
287             if (IsWindow(hwndUI))
288                 ret = SendMessageW(hwndUI, WM_IME_NOTIFY, wParam, lParam);
289             break;
290     }
291 
292     return ret;
293 }
294 
295 /* Creates the IME UI window. */
296 /* Win: CreateIMEUI */
User32CreateImeUIWindow(PIMEUI pimeui,HKL hKL)297 static HWND User32CreateImeUIWindow(PIMEUI pimeui, HKL hKL)
298 {
299     IMEINFOEX ImeInfoEx;
300     PIMEDPI pImeDpi;
301     WNDCLASSW wc;
302     HWND hwndUI = NULL;
303     CHAR szUIClass[32];
304     PWND pwnd = pimeui->spwnd;
305 
306     ASSERT(pimeui->spwnd != NULL);
307 
308     if (!pwnd || !IMM_FN(ImmGetImeInfoEx)(&ImeInfoEx, ImeInfoExKeyboardLayout, &hKL))
309         return NULL;
310 
311     pImeDpi = IMM_FN(ImmLockImeDpi)(hKL);
312     if (!pImeDpi)
313         return NULL;
314 
315     if (!GetClassInfoW(pImeDpi->hInst, ImeInfoEx.wszUIClass, &wc))
316         goto Quit;
317 
318     if (ImeInfoEx.ImeInfo.fdwProperty & IME_PROP_UNICODE)
319     {
320         hwndUI = CreateWindowW(ImeInfoEx.wszUIClass, ImeInfoEx.wszUIClass, WS_POPUP | WS_DISABLED,
321                                0, 0, 0, 0, UserHMGetHandle(pwnd), 0, wc.hInstance, NULL);
322     }
323     else
324     {
325         WideCharToMultiByte(CP_ACP, 0, ImeInfoEx.wszUIClass, -1,
326                             szUIClass, _countof(szUIClass), NULL, NULL);
327         szUIClass[_countof(szUIClass) - 1] = 0;
328 
329         hwndUI = CreateWindowA(szUIClass, szUIClass, WS_POPUP | WS_DISABLED,
330                                0, 0, 0, 0, UserHMGetHandle(pwnd), 0, wc.hInstance, NULL);
331     }
332 
333     if (hwndUI)
334         NtUserSetWindowLongPtr(hwndUI, IMMGWLP_IMC, (LONG_PTR)pimeui->hIMC, FALSE);
335 
336 Quit:
337     IMM_FN(ImmUnlockImeDpi)(pImeDpi);
338     return hwndUI;
339 }
340 
341 /* Initializes the default IME window. */
342 /* Win: ImeWndCreateHandler */
ImeWnd_OnCreate(PIMEUI pimeui,LPCREATESTRUCT lpCS)343 static INT ImeWnd_OnCreate(PIMEUI pimeui, LPCREATESTRUCT lpCS)
344 {
345     PWND pParentWnd, pWnd = pimeui->spwnd;
346     HIMC hIMC = NULL;
347 
348     if (!pWnd || (pWnd->style & (WS_DISABLED | WS_POPUP)) != (WS_DISABLED | WS_POPUP))
349         return -1;
350 
351     pParentWnd = ValidateHwnd(lpCS->hwndParent);
352     if (pParentWnd)
353     {
354         hIMC = pParentWnd->hImc;
355         if (hIMC && !User32CanSetImeWindowToImc(hIMC, UserHMGetHandle(pWnd)))
356             hIMC = NULL;
357     }
358 
359     User32UpdateImcOfImeUI(pimeui, hIMC);
360 
361     pimeui->fShowStatus = FALSE;
362     pimeui->nCntInIMEProc = 0;
363     pimeui->fActivate = FALSE;
364     pimeui->fDestroy = FALSE;
365     pimeui->hwndIMC = NULL;
366     pimeui->hKL = GetWin32ClientInfo()->hKL;
367     pimeui->fCtrlShowStatus = TRUE;
368     pimeui->dwLastStatus = 0;
369 
370     return 0;
371 }
372 
373 /* Destroys the IME UI window. */
374 /* Win: DestroyIMEUI */
User32DestroyImeUIWindow(PIMEUI pimeui)375 static VOID User32DestroyImeUIWindow(PIMEUI pimeui)
376 {
377     HWND hwndUI = pimeui->hwndUI;
378 
379     if (IsWindow(hwndUI))
380     {
381         pimeui->fDestroy = TRUE;
382         NtUserDestroyWindow(hwndUI);
383     }
384 
385     pimeui->fShowStatus = pimeui->fDestroy = FALSE;
386     pimeui->hwndUI = NULL;
387 }
388 
389 /* Handles WM_IME_SELECT message of the default IME window. */
390 /* Win: ImeSelectHandler */
ImeWnd_OnImeSelect(PIMEUI pimeui,WPARAM wParam,LPARAM lParam)391 static VOID ImeWnd_OnImeSelect(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
392 {
393     HKL hKL;
394     HWND hwndUI, hwndIMC = pimeui->hwndIMC;
395 
396     if (wParam)
397     {
398         pimeui->hKL = hKL = (HKL)lParam;
399 
400         if (!pimeui->fActivate)
401             return;
402 
403         pimeui->hwndUI = hwndUI = User32CreateImeUIWindow(pimeui, hKL);
404         if (hwndUI)
405             User32SendImeUIMessage(pimeui, WM_IME_SELECT, wParam, lParam, TRUE);
406 
407         if (User32GetImeShowStatus() && pimeui->fCtrlShowStatus)
408         {
409             if (!pimeui->fShowStatus && pimeui->fActivate && IsWindow(hwndIMC))
410                 User32NotifyOpenStatus(pimeui, hwndIMC, TRUE);
411         }
412     }
413     else
414     {
415         if (pimeui->fShowStatus && pimeui->fActivate && IsWindow(hwndIMC))
416             User32NotifyOpenStatus(pimeui, hwndIMC, FALSE);
417 
418         User32SendImeUIMessage(pimeui, WM_IME_SELECT, wParam, lParam, TRUE);
419         User32DestroyImeUIWindow(pimeui);
420         pimeui->hKL = NULL;
421     }
422 }
423 
424 /* Handles WM_IME_CONTROL message of the default IME window. */
425 /* Win: ImeControlHandler(pimeui, wParam, lParam, !unicode) */
426 static LRESULT
ImeWnd_OnImeControl(PIMEUI pimeui,WPARAM wParam,LPARAM lParam,BOOL unicode)427 ImeWnd_OnImeControl(PIMEUI pimeui, WPARAM wParam, LPARAM lParam, BOOL unicode)
428 {
429     HIMC hIMC = pimeui->hIMC;
430     DWORD dwConversion, dwSentence;
431     POINT pt;
432 
433     if (IS_CICERO_MODE())
434     {
435         if (wParam == IMC_OPENSTATUSWINDOW)
436         {
437             IMM_FN(CtfImmRestoreToolbarWnd)(pimeui->dwLastStatus);
438             pimeui->dwLastStatus = 0;
439         }
440         else if (wParam == IMC_CLOSESTATUSWINDOW)
441         {
442             pimeui->dwLastStatus = IMM_FN(CtfImmHideToolbarWnd)();
443         }
444     }
445 
446     if (!hIMC)
447         return 0;
448 
449     switch (wParam)
450     {
451         case IMC_GETCONVERSIONMODE:
452             if (!IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence))
453                 return 1;
454             return dwConversion;
455 
456         case IMC_GETSENTENCEMODE:
457             if (!IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence))
458                 return 1;
459             return dwSentence;
460 
461         case IMC_GETOPENSTATUS:
462             return IMM_FN(ImmGetOpenStatus)(hIMC);
463 
464         case IMC_SETCONVERSIONMODE:
465             if (!IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence) ||
466                 !IMM_FN(ImmSetConversionStatus)(hIMC, (DWORD)lParam, dwSentence))
467             {
468                 return 1;
469             }
470             break;
471 
472         case IMC_SETSENTENCEMODE:
473             if (!IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence) ||
474                 !IMM_FN(ImmSetConversionStatus)(hIMC, dwConversion, (DWORD)lParam))
475             {
476                 return 1;
477             }
478             break;
479 
480         case IMC_SETOPENSTATUS:
481             if (!IMM_FN(ImmSetOpenStatus)(hIMC, (BOOL)lParam))
482                 return 1;
483             break;
484 
485         case IMC_GETCANDIDATEPOS:
486         case IMC_GETCOMPOSITIONWINDOW:
487         case IMC_GETSOFTKBDPOS:
488         case IMC_SETSOFTKBDPOS:
489         case IMC_GETSTATUSWINDOWPOS:
490             return User32SendImeUIMessage(pimeui, WM_IME_CONTROL, wParam, lParam, unicode);
491 
492         case IMC_SETCANDIDATEPOS:
493             if (!IMM_FN(ImmSetCandidateWindow)(hIMC, (LPCANDIDATEFORM)lParam))
494                 return 1;
495             break;
496 
497         case IMC_GETCOMPOSITIONFONT:
498             if (unicode)
499             {
500                 if (!IMM_FN(ImmGetCompositionFontW)(hIMC, (LPLOGFONTW)lParam))
501                     return 1;
502             }
503             else
504             {
505                 if (!IMM_FN(ImmGetCompositionFontA)(hIMC, (LPLOGFONTA)lParam))
506                     return 1;
507             }
508             break;
509 
510         case IMC_SETCOMPOSITIONFONT:
511             if (unicode)
512             {
513                 if (!IMM_FN(ImmSetCompositionFontW)(hIMC, (LPLOGFONTW)lParam))
514                     return 1;
515             }
516             else
517             {
518                 if (!IMM_FN(ImmSetCompositionFontA)(hIMC, (LPLOGFONTA)lParam))
519                     return 1;
520             }
521             break;
522 
523         case IMC_SETCOMPOSITIONWINDOW:
524             if (!IMM_FN(ImmSetCompositionWindow)(hIMC, (LPCOMPOSITIONFORM)lParam))
525                 return 1;
526             break;
527 
528         case IMC_SETSTATUSWINDOWPOS:
529             pt.x = GET_X_LPARAM(lParam);
530             pt.y = GET_Y_LPARAM(lParam);
531             if (!IMM_FN(ImmSetStatusWindowPos)(hIMC, &pt))
532                 return 1;
533             break;
534 
535         case IMC_CLOSESTATUSWINDOW:
536             if (pimeui->fShowStatus && User32GetImeShowStatus())
537             {
538                 pimeui->fShowStatus = FALSE;
539                 User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0, TRUE);
540             }
541             pimeui->fCtrlShowStatus = FALSE;
542             break;
543 
544         case IMC_OPENSTATUSWINDOW:
545             if (!pimeui->fShowStatus && User32GetImeShowStatus())
546             {
547                 pimeui->fShowStatus = TRUE;
548                 User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, IMN_OPENSTATUSWINDOW, 0, TRUE);
549             }
550             pimeui->fCtrlShowStatus = TRUE;
551             break;
552 
553         default:
554             break;
555     }
556 
557     return 0;
558 }
559 
560 /* Modify the IME activation status. */
561 /* Win: FocusSetIMCContext */
User32SetImeActivenessOfWindow(HWND hWnd,BOOL bActive)562 static VOID FASTCALL User32SetImeActivenessOfWindow(HWND hWnd, BOOL bActive)
563 {
564     HIMC hIMC;
565 
566     if (!hWnd || !IsWindow(hWnd))
567     {
568         IMM_FN(ImmSetActiveContext)(NULL, NULL, bActive);
569         return;
570     }
571 
572     hIMC = IMM_FN(ImmGetContext)(hWnd);
573     IMM_FN(ImmSetActiveContext)(hWnd, hIMC, bActive);
574     IMM_FN(ImmReleaseContext)(hWnd, hIMC);
575 }
576 
577 /* Win: CtfLoadThreadLayout */
CtfLoadThreadLayout(PIMEUI pimeui)578 VOID FASTCALL CtfLoadThreadLayout(PIMEUI pimeui)
579 {
580     IMM_FN(CtfImmTIMActivate)(pimeui->hKL);
581     pimeui->hKL = GetWin32ClientInfo()->hKL;
582     IMM_FN(ImmLoadIME)(pimeui->hKL);
583     pimeui->hwndUI = NULL;
584 }
585 
586 /* Open the IME help or check the existence of the IME help. */
587 static LRESULT FASTCALL
User32DoImeHelp(PIMEUI pimeui,WPARAM wParam,LPARAM lParam)588 User32DoImeHelp(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
589 {
590     WCHAR szHelpFile[MAX_PATH];
591     DWORD ret, dwEsc = IME_ESC_GETHELPFILENAME;
592     size_t cch;
593 
594     /* Is there any IME help file? */
595     ret = IMM_FN(ImmEscapeW)(pimeui->hKL, pimeui->hIMC, IME_ESC_QUERY_SUPPORT, &dwEsc);
596     if (!ret || !lParam)
597         return ret;
598 
599     /* Get the help filename */
600     if (IMM_FN(ImmEscapeW)(pimeui->hKL, pimeui->hIMC, IME_ESC_GETHELPFILENAME, szHelpFile))
601     {
602         /* Check filename extension */
603         cch = wcslen(szHelpFile);
604         if (cch > 4 && _wcsicmp(&szHelpFile[cch - 4], L".HLP") == 0)
605         {
606             /* Open the old-style help */
607             TRACE("szHelpFile: %s\n", debugstr_w(szHelpFile));
608             WinHelpW(NULL, szHelpFile, HELP_FINDER, 0);
609         }
610         else
611         {
612             /* Open the new-style help */
613             FIXME("(%p, %p, %p): %s\n", pimeui, wParam, lParam, debugstr_w(szHelpFile));
614             ret = FALSE;
615         }
616     }
617 
618     return ret;
619 }
620 
621 /* Handles WM_IME_SYSTEM message of the default IME window. */
622 /* Win: ImeSystemHandler */
ImeWnd_OnImeSystem(PIMEUI pimeui,WPARAM wParam,LPARAM lParam)623 static LRESULT ImeWnd_OnImeSystem(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
624 {
625     LRESULT ret = 0;
626     LPINPUTCONTEXTDX pIC;
627     HIMC hIMC = pimeui->hIMC;
628     LPCANDIDATEFORM pCandForm;
629     LPCOMPOSITIONFORM pCompForm;
630     DWORD dwConversion, dwSentence;
631     HWND hImeWnd;
632     BOOL bCompForm;
633     CANDIDATEFORM CandForm;
634     COMPOSITIONFORM CompForm;
635     UINT iCandForm;
636 
637     ASSERT(pimeui->spwnd != NULL);
638 
639     switch (wParam)
640     {
641         case IMS_NOTIFYIMESHOW:
642             if (User32GetImeShowStatus() == !lParam)
643             {
644                 hImeWnd = UserHMGetHandle(pimeui->spwnd);
645                 NtUserCallHwndParamLock(hImeWnd, lParam, TWOPARAM_ROUTINE_IMESHOWSTATUSCHANGE);
646             }
647             break;
648 
649         case IMS_UPDATEIMEUI:
650             if (!hIMC)
651                 break;
652 
653             bCompForm = TRUE;
654             pIC = IMM_FN(ImmLockIMC)(hIMC);
655             if (pIC)
656             {
657                 bCompForm = !(pIC->dwUIFlags & 0x2);
658                 IMM_FN(ImmUnlockIMC)(hIMC);
659             }
660 
661             if (!IsWindow(pimeui->hwndIMC))
662                 break;
663 
664             if (bCompForm && IMM_FN(ImmGetCompositionWindow)(hIMC, &CompForm))
665             {
666                 if (CompForm.dwStyle)
667                     IMM_FN(ImmSetCompositionWindow)(hIMC, &CompForm);
668             }
669 
670             for (iCandForm = 0; iCandForm < MAX_CANDIDATEFORM; ++iCandForm)
671             {
672                 if (IMM_FN(ImmGetCandidateWindow)(hIMC, iCandForm, &CandForm))
673                 {
674                     if (CandForm.dwStyle)
675                         IMM_FN(ImmSetCandidateWindow)(hIMC, &CandForm);
676                 }
677             }
678             break;
679 
680         case IMS_SETCANDFORM:
681             pIC = IMM_FN(ImmLockIMC)(hIMC);
682             if (!pIC)
683                 break;
684 
685             pCandForm = &pIC->cfCandForm[lParam];
686             IMM_FN(ImmSetCandidateWindow)(hIMC, pCandForm);
687             IMM_FN(ImmUnlockIMC)(hIMC);
688             break;
689 
690         case IMS_SETCOMPFONT:
691             pIC = IMM_FN(ImmLockIMC)(hIMC);
692             if (!pIC)
693                 break;
694 
695             IMM_FN(ImmSetCompositionFontW)(hIMC, &pIC->lfFont.W);
696             IMM_FN(ImmUnlockIMC)(hIMC);
697             break;
698 
699         case IMS_SETCOMPFORM:
700             pIC = IMM_FN(ImmLockIMC)(hIMC);
701             if (!pIC)
702                 break;
703 
704             pCompForm = &pIC->cfCompForm;
705             pIC->dwUIFlags |= 0x8;
706             IMM_FN(ImmSetCompositionWindow)(hIMC, pCompForm);
707             IMM_FN(ImmUnlockIMC)(hIMC);
708             break;
709 
710         case IMS_CONFIGURE:
711             IMM_FN(ImmConfigureIMEW)((HKL)lParam, pimeui->hwndIMC, IME_CONFIG_GENERAL, NULL);
712             break;
713 
714         case IMS_SETOPENSTATUS:
715             if (hIMC)
716                 IMM_FN(ImmSetOpenStatus)(hIMC, (BOOL)lParam);
717             break;
718 
719         case IMS_FREELAYOUT:
720             ret = IMM_FN(ImmFreeLayout)((HKL)lParam);
721             break;
722 
723         case 0x13:
724             FIXME("\n");
725             break;
726 
727         case IMS_GETCONVSTATUS:
728             IMM_FN(ImmGetConversionStatus)(hIMC, &dwConversion, &dwSentence);
729             ret = dwConversion;
730             break;
731 
732         case IMS_IMEHELP:
733             return User32DoImeHelp(pimeui, wParam, lParam);
734 
735         case IMS_IMEACTIVATE:
736             User32SetImeActivenessOfWindow((HWND)lParam, TRUE);
737             break;
738 
739         case IMS_IMEDEACTIVATE:
740             User32SetImeActivenessOfWindow((HWND)lParam, FALSE);
741             break;
742 
743         case IMS_ACTIVATELAYOUT:
744             ret = IMM_FN(ImmActivateLayout)((HKL)lParam);
745             break;
746 
747         case IMS_GETIMEMENU:
748             ret = IMM_FN(ImmPutImeMenuItemsIntoMappedFile)((HIMC)lParam);
749             break;
750 
751         case 0x1D:
752             FIXME("\n");
753             break;
754 
755         case IMS_GETCONTEXT:
756             ret = (ULONG_PTR)IMM_FN(ImmGetContext)((HWND)lParam);
757             break;
758 
759         case IMS_SENDNOTIFICATION:
760         case IMS_COMPLETECOMPSTR:
761         case IMS_SETLANGBAND:
762         case IMS_UNSETLANGBAND:
763             ret = IMM_FN(ImmSystemHandler)(hIMC, wParam, lParam);
764             break;
765 
766         case IMS_LOADTHREADLAYOUT:
767             CtfLoadThreadLayout(pimeui);
768             break;
769 
770         default:
771             break;
772     }
773 
774     return ret;
775 }
776 
777 /* Handles WM_IME_SETCONTEXT message of the default IME window. */
778 /* Win: ImeSetContextHandler */
ImeWnd_OnImeSetContext(PIMEUI pimeui,WPARAM wParam,LPARAM lParam)779 LRESULT ImeWnd_OnImeSetContext(PIMEUI pimeui, WPARAM wParam, LPARAM lParam)
780 {
781     LRESULT ret;
782     HIMC hIMC;
783     LPINPUTCONTEXTDX pIC;
784     HWND hwndFocus, hwndOldImc, hwndNewImc, hImeWnd, hwndActive, hwndOwner;
785     PWND pwndFocus, pImeWnd, pwndOwner;
786     COMPOSITIONFORM CompForm;
787 
788     pimeui->fActivate = !!wParam;
789     hwndOldImc = pimeui->hwndIMC;
790     ASSERT(pimeui->spwnd != NULL);
791 
792     if (wParam)
793     {
794         if (!pimeui->hwndUI)
795             pimeui->hwndUI = User32CreateImeUIWindow(pimeui, pimeui->hKL);
796 
797         if (gfConIme == -1)
798         {
799             gfConIme = (INT)NtUserGetThreadState(THREADSTATE_CHECKCONIME);
800             if (gfConIme)
801                 pimeui->fCtrlShowStatus = FALSE;
802         }
803 
804         hImeWnd = UserHMGetHandle(pimeui->spwnd);
805 
806         if (gfConIme)
807         {
808             hwndOwner = GetWindow(hImeWnd, GW_OWNER);
809             pwndOwner = ValidateHwnd(hwndOwner);
810             if (pwndOwner)
811             {
812                 User32UpdateImcOfImeUI(pimeui, pwndOwner->hImc);
813 
814                 if (pimeui->hwndUI)
815                     SetWindowLongPtrW(pimeui->hwndUI, IMMGWLP_IMC, (LONG_PTR)pwndOwner->hImc);
816             }
817 
818             return User32SendImeUIMessage(pimeui, WM_IME_SETCONTEXT, wParam, lParam, TRUE);
819         }
820 
821         hwndFocus = (HWND)NtUserQueryWindow(hImeWnd, QUERY_WINDOW_FOCUS);
822 
823         hIMC = IMM_FN(ImmGetContext)(hwndFocus);
824 
825         if (hIMC && !User32CanSetImeWindowToImc(hIMC, hImeWnd))
826         {
827             User32UpdateImcOfImeUI(pimeui, NULL);
828             return 0;
829         }
830 
831         User32UpdateImcOfImeUI(pimeui, hIMC);
832 
833         if (pimeui->hwndUI)
834             SetWindowLongPtrW(pimeui->hwndUI, IMMGWLP_IMC, (LONG_PTR)hIMC);
835 
836         if (hIMC)
837         {
838             pIC = IMM_FN(ImmLockIMC)(hIMC);
839             if (!pIC)
840                 return 0;
841 
842             if (hwndFocus != pIC->hWnd)
843             {
844                 IMM_FN(ImmUnlockIMC)(hIMC);
845                 return 0;
846             }
847 
848             if ((pIC->dwUIFlags & 0x40000) && hwndOldImc != hwndFocus)
849             {
850                 RtlZeroMemory(&CompForm, sizeof(CompForm));
851                 IMM_FN(ImmSetCompositionWindow)(hIMC, &CompForm);
852 
853                 pIC->dwUIFlags &= ~0x40000;
854             }
855 
856             IMM_FN(ImmUnlockIMC)(hIMC);
857 
858             hImeWnd = UserHMGetHandle(pimeui->spwnd);
859             if (NtUserSetImeOwnerWindow(hImeWnd, hwndFocus))
860                 pimeui->hwndIMC = hwndFocus;
861         }
862         else
863         {
864             pimeui->hwndIMC = hwndFocus;
865 
866             hImeWnd = UserHMGetHandle(pimeui->spwnd);
867             NtUserSetImeOwnerWindow(hImeWnd, NULL);
868         }
869     }
870 
871     ret = User32SendImeUIMessage(pimeui, WM_IME_SETCONTEXT, wParam, lParam, TRUE);
872 
873     if (!pimeui->spwnd)
874         return 0;
875 
876     if (!pimeui->fCtrlShowStatus || !User32GetImeShowStatus())
877         return ret;
878 
879     hImeWnd = UserHMGetHandle(pimeui->spwnd);
880     hwndFocus = (HWND)NtUserQueryWindow(hImeWnd, QUERY_WINDOW_FOCUS);
881     pwndFocus = ValidateHwnd(hwndFocus);
882 
883     if (wParam)
884     {
885         pImeWnd = ValidateHwnd(hImeWnd);
886         if (pwndFocus && pImeWnd && pImeWnd->head.pti == pwndFocus->head.pti)
887         {
888             hwndNewImc = pimeui->hwndIMC;
889             if (pimeui->fShowStatus)
890             {
891                 if (hwndOldImc && hwndNewImc && hwndOldImc != hwndNewImc &&
892                     IntGetTopLevelWindow(hwndOldImc) != IntGetTopLevelWindow(hwndNewImc))
893                 {
894                     User32NotifyOpenStatus(pimeui, hwndOldImc, FALSE);
895                     User32NotifyOpenStatus(pimeui, hwndNewImc, TRUE);
896                 }
897             }
898             else
899             {
900                 if (ValidateHwnd(hwndNewImc))
901                     User32NotifyOpenStatus(pimeui, hwndNewImc, TRUE);
902             }
903         }
904 
905         pImeWnd = pimeui->spwnd;
906         hImeWnd = (pImeWnd ? UserHMGetHandle(pImeWnd) : NULL);
907         if (hImeWnd)
908             NtUserCallHwndLock(hImeWnd, HWNDLOCK_ROUTINE_CHECKIMESHOWSTATUSINTHRD);
909     }
910     else
911     {
912         pImeWnd = pimeui->spwnd;
913         hImeWnd = UserHMGetHandle(pImeWnd);
914         hwndActive = (HWND)NtUserQueryWindow(hImeWnd, QUERY_WINDOW_ACTIVE);
915         if (!pwndFocus || !hwndActive || pImeWnd->head.pti != pwndFocus->head.pti)
916         {
917             if (IsWindow(hwndOldImc))
918             {
919                 User32NotifyOpenStatus(pimeui, hwndOldImc, FALSE);
920             }
921             else
922             {
923                 pimeui->fShowStatus = FALSE;
924                 User32SendImeUIMessage(pimeui, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0, TRUE);
925             }
926         }
927     }
928 
929     return ret;
930 }
931 
932 /* The window procedure of the default IME window */
933 /* Win: ImeWndProcWorker(pWnd, msg, wParam, lParam, !unicode) */
934 LRESULT WINAPI
ImeWndProc_common(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam,BOOL unicode)935 ImeWndProc_common(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode) // ReactOS
936 {
937     PWND pWnd;
938     PIMEUI pimeui;
939     LRESULT ret;
940 
941     pWnd = ValidateHwnd(hwnd);
942     if (pWnd == NULL)
943     {
944         ERR("hwnd was %p\n", hwnd);
945         return 0;
946     }
947 
948     if (!pWnd->fnid)
949     {
950         NtUserSetWindowFNID(hwnd, FNID_IME);
951     }
952     else if (pWnd->fnid != FNID_IME)
953     {
954         ERR("fnid was 0x%x\n", pWnd->fnid);
955         return 0;
956     }
957 
958     pimeui = (PIMEUI)GetWindowLongPtrW(hwnd, 0);
959     if (pimeui == NULL)
960     {
961         pimeui = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMEUI));
962         if (pimeui == NULL)
963         {
964             ERR("HeapAlloc failed\n");
965             NtUserSetWindowFNID(hwnd, FNID_DESTROY);
966             DestroyWindow(hwnd);
967             return 0;
968         }
969 
970         SetWindowLongPtrW(hwnd, 0, (LONG_PTR)pimeui);
971         pimeui->spwnd = pWnd;
972     }
973 
974     if (IS_CICERO_MODE())
975     {
976         ret = IMM_FN(CtfImmDispatchDefImeMessage)(hwnd, msg, wParam, lParam);
977         if (ret)
978             return ret;
979     }
980 
981     if (pimeui->nCntInIMEProc > 0)
982     {
983         switch (msg)
984         {
985             case WM_IME_CHAR:
986             case WM_IME_COMPOSITIONFULL:
987             case WM_IME_CONTROL:
988             case WM_IME_REQUEST:
989             case WM_IME_SELECT:
990             case WM_IME_SETCONTEXT:
991             case WM_IME_STARTCOMPOSITION:
992             case WM_IME_COMPOSITION:
993             case WM_IME_ENDCOMPOSITION:
994                 return 0;
995 
996             case WM_IME_NOTIFY:
997                 if (wParam < IMN_PRIVATE || IS_IME_HKL(pimeui->hKL) || !IS_CICERO_MODE())
998                     return 0;
999                 break;
1000 
1001             case WM_IME_SYSTEM:
1002                 switch (wParam)
1003                 {
1004                     case 0x03:
1005                     case 0x10:
1006                     case 0x13:
1007                         break;
1008 
1009                     default:
1010                         return 0;
1011                 }
1012                 break;
1013 
1014             default:
1015                 goto Finish;
1016         }
1017     }
1018 
1019     if ((pWnd->state2 & WNDS2_INDESTROY) || (pWnd->state & WNDS_DESTROYED))
1020     {
1021         switch (msg)
1022         {
1023             case WM_DESTROY:
1024             case WM_NCDESTROY:
1025             case WM_FINALDESTROY:
1026                 break;
1027 
1028             default:
1029                 return 0;
1030         }
1031     }
1032 
1033     switch (msg)
1034     {
1035         case WM_CREATE:
1036             return ImeWnd_OnCreate(pimeui, (LPCREATESTRUCT)lParam);
1037 
1038         case WM_DESTROY:
1039             User32DestroyImeUIWindow(pimeui);
1040             return 0;
1041 
1042         case WM_NCDESTROY:
1043         case WM_FINALDESTROY:
1044             pimeui->spwnd = NULL;
1045             HeapFree(GetProcessHeap(), 0, pimeui);
1046             NtUserSetWindowFNID(hwnd, FNID_DESTROY);
1047             break;
1048 
1049         case WM_ERASEBKGND:
1050             return TRUE;
1051 
1052         case WM_PAINT:
1053             return 0;
1054 
1055         case WM_IME_STARTCOMPOSITION:
1056         case WM_IME_COMPOSITION:
1057         case WM_IME_ENDCOMPOSITION:
1058             return User32SendImeUIMessage(pimeui, msg, wParam, lParam, unicode);
1059 
1060         case WM_IME_CONTROL:
1061             return ImeWnd_OnImeControl(pimeui, wParam, lParam, unicode);
1062 
1063         case WM_IME_NOTIFY:
1064             return ImeWnd_OnImeNotify(pimeui, wParam, lParam);
1065 
1066         case WM_IME_REQUEST:
1067             return 0;
1068 
1069         case WM_IME_SELECT:
1070             ImeWnd_OnImeSelect(pimeui, wParam, lParam);
1071             return (LRESULT)pimeui;
1072 
1073         case WM_IME_SETCONTEXT:
1074             return ImeWnd_OnImeSetContext(pimeui, wParam, lParam);
1075 
1076         case WM_IME_SYSTEM:
1077             return ImeWnd_OnImeSystem(pimeui, wParam, lParam);
1078 
1079         default:
1080             break;
1081     }
1082 
1083 Finish:
1084     if (unicode)
1085         return DefWindowProcW(hwnd, msg, wParam, lParam);
1086     return DefWindowProcA(hwnd, msg, wParam, lParam);
1087 }
1088 
1089 // Win: ImeWndProcA
ImeWndProcA(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)1090 LRESULT WINAPI ImeWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1091 {
1092     return ImeWndProc_common(hwnd, msg, wParam, lParam, FALSE);
1093 }
1094 
1095 // Win: ImeWndProcW
ImeWndProcW(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)1096 LRESULT WINAPI ImeWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1097 {
1098     return ImeWndProc_common(hwnd, msg, wParam, lParam, TRUE);
1099 }
1100 
1101 // Win: UpdatePerUserImmEnabling
UpdatePerUserImmEnabling(VOID)1102 BOOL WINAPI UpdatePerUserImmEnabling(VOID)
1103 {
1104     HMODULE imm32;
1105     BOOL ret;
1106 
1107     ret = NtUserCallNoParam(NOPARAM_ROUTINE_UPDATEPERUSERIMMENABLING);
1108     if (!ret || !(gpsi->dwSRVIFlags & SRVINFO_IMM32))
1109         return FALSE;
1110 
1111     imm32 = GetModuleHandleW(L"imm32.dll");
1112     if (imm32)
1113         return TRUE;
1114 
1115     imm32 = LoadLibraryW(L"imm32.dll");
1116     if (imm32 == NULL)
1117     {
1118         ERR("Imm32 not installed!\n");
1119         ret = FALSE;
1120     }
1121 
1122     return ret;
1123 }
1124 
1125 BOOL
1126 WINAPI
RegisterIMEClass(VOID)1127 RegisterIMEClass(VOID)
1128 {
1129     ATOM atom;
1130     WNDCLASSEXW WndClass = { sizeof(WndClass) };
1131 
1132     WndClass.lpszClassName  = L"IME";
1133     WndClass.style          = CS_GLOBALCLASS;
1134     WndClass.lpfnWndProc    = ImeWndProcW;
1135     WndClass.cbWndExtra     = sizeof(LONG_PTR);
1136     WndClass.hCursor        = LoadCursorW(NULL, IDC_ARROW);
1137 
1138     atom = RegisterClassExWOWW(&WndClass, 0, FNID_IME, 0, FALSE);
1139     if (!atom)
1140     {
1141         ERR("Failed to register IME Class!\n");
1142         return FALSE;
1143     }
1144 
1145     RegisterDefaultClasses |= ICLASS_TO_MASK(ICLS_IME);
1146     TRACE("RegisterIMEClass atom = %u\n", atom);
1147     return TRUE;
1148 }
1149 
1150 /*
1151  * @implemented
1152  */
1153 BOOL
1154 WINAPI
IMPSetIMEW(HWND hwnd,LPIMEPROW ime)1155 IMPSetIMEW(HWND hwnd, LPIMEPROW ime)
1156 {
1157     return IMM_FN(ImmIMPSetIMEW)(hwnd, ime);
1158 }
1159 
1160 /*
1161  * @implemented
1162  */
1163 BOOL
1164 WINAPI
IMPQueryIMEW(LPIMEPROW ime)1165 IMPQueryIMEW(LPIMEPROW ime)
1166 {
1167     return IMM_FN(ImmIMPQueryIMEW)(ime);
1168 }
1169 
1170 /*
1171  * @implemented
1172  */
1173 BOOL
1174 WINAPI
IMPGetIMEW(HWND hwnd,LPIMEPROW ime)1175 IMPGetIMEW(HWND hwnd, LPIMEPROW ime)
1176 {
1177     return IMM_FN(ImmIMPGetIMEW)(hwnd, ime);
1178 }
1179 
1180 /*
1181  * @implemented
1182  */
1183 BOOL
1184 WINAPI
IMPSetIMEA(HWND hwnd,LPIMEPROA ime)1185 IMPSetIMEA(HWND hwnd, LPIMEPROA ime)
1186 {
1187     return IMM_FN(ImmIMPSetIMEA)(hwnd, ime);
1188 }
1189 
1190 /*
1191  * @implemented
1192  */
1193 BOOL
1194 WINAPI
IMPQueryIMEA(LPIMEPROA ime)1195 IMPQueryIMEA(LPIMEPROA ime)
1196 {
1197     return IMM_FN(ImmIMPQueryIMEA)(ime);
1198 }
1199 
1200 /*
1201  * @implemented
1202  */
1203 BOOL
1204 WINAPI
IMPGetIMEA(HWND hwnd,LPIMEPROA ime)1205 IMPGetIMEA(HWND hwnd, LPIMEPROA ime)
1206 {
1207     return IMM_FN(ImmIMPGetIMEA)(hwnd, ime);
1208 }
1209 
1210 /*
1211  * @implemented
1212  */
1213 LRESULT
1214 WINAPI
SendIMEMessageExW(HWND hwnd,LPARAM lParam)1215 SendIMEMessageExW(HWND hwnd, LPARAM lParam)
1216 {
1217     return IMM_FN(ImmSendIMEMessageExW)(hwnd, lParam);
1218 }
1219 
1220 /*
1221  * @implemented
1222  */
1223 LRESULT
1224 WINAPI
SendIMEMessageExA(HWND hwnd,LPARAM lParam)1225 SendIMEMessageExA(HWND hwnd, LPARAM lParam)
1226 {
1227     return IMM_FN(ImmSendIMEMessageExA)(hwnd, lParam);
1228 }
1229 
1230 /*
1231  * @implemented
1232  */
1233 BOOL
1234 WINAPI
WINNLSEnableIME(HWND hwnd,BOOL enable)1235 WINNLSEnableIME(HWND hwnd, BOOL enable)
1236 {
1237     return IMM_FN(ImmWINNLSEnableIME)(hwnd, enable);
1238 }
1239 
1240 /*
1241  * @implemented
1242  */
1243 BOOL
1244 WINAPI
WINNLSGetEnableStatus(HWND hwnd)1245 WINNLSGetEnableStatus(HWND hwnd)
1246 {
1247     return IMM_FN(ImmWINNLSGetEnableStatus)(hwnd);
1248 }
1249 
1250 /*
1251  * @implemented
1252  */
1253 UINT
1254 WINAPI
WINNLSGetIMEHotkey(HWND hwnd)1255 WINNLSGetIMEHotkey(HWND hwnd)
1256 {
1257     return FALSE;
1258 }
1259