[IMM32] Rewrite ImmAssociateContextEx (#3961)
[reactos.git] / dll / win32 / imm32 / imm.c
1 /*
2 * PROJECT: ReactOS IMM32
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Implementing Far-Eastern languages input
5 * COPYRIGHT: Copyright 1998 Patrik Stridvall
6 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
7 * Copyright 2017 James Tabor <james.tabor@reactos.org>
8 * Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org>
9 * Copyright 2020 Oleg Dubinskiy <oleg.dubinskij2013@yandex.ua>
10 * Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
11 */
12
13 #include "precomp.h"
14
15 WINE_DEFAULT_DEBUG_CHANNEL(imm);
16
17 HMODULE g_hImm32Inst = NULL;
18 PSERVERINFO g_psi = NULL;
19 SHAREDINFO g_SharedInfo = { NULL };
20 BYTE g_bClientRegd = FALSE;
21
22 static BOOL APIENTRY Imm32InitInstance(HMODULE hMod)
23 {
24 NTSTATUS status;
25
26 if (hMod)
27 g_hImm32Inst = hMod;
28
29 if (g_bClientRegd)
30 return TRUE;
31
32 status = RtlInitializeCriticalSection(&g_csImeDpi);
33 if (NT_ERROR(status))
34 return FALSE;
35
36 g_bClientRegd = TRUE;
37 return TRUE;
38 }
39
40 /***********************************************************************
41 * ImmRegisterClient(IMM32.@)
42 * ( Undocumented, called from user32.dll )
43 */
44 BOOL WINAPI ImmRegisterClient(PSHAREDINFO ptr, HINSTANCE hMod)
45 {
46 g_SharedInfo = *ptr;
47 g_psi = g_SharedInfo.psi;
48 return Imm32InitInstance(hMod);
49 }
50
51 /***********************************************************************
52 * ImmLoadLayout (IMM32.@)
53 */
54 HKL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx)
55 {
56 DWORD cbData;
57 UNICODE_STRING UnicodeString;
58 HKEY hLayoutKey = NULL, hLayoutsKey = NULL;
59 LONG error;
60 NTSTATUS Status;
61 WCHAR szLayout[MAX_PATH];
62
63 TRACE("(%p, %p)\n", hKL, pImeInfoEx);
64
65 if (IS_IME_HKL(hKL) ||
66 !g_psi || !(g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED) ||
67 ((PW32CLIENTINFO)NtCurrentTeb()->Win32ClientInfo)->W32ClientInfo[0] & 2)
68 {
69 UnicodeString.Buffer = szLayout;
70 UnicodeString.MaximumLength = sizeof(szLayout);
71 Status = RtlIntegerToUnicodeString((DWORD_PTR)hKL, 16, &UnicodeString);
72 if (!NT_SUCCESS(Status))
73 return NULL;
74
75 error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hLayoutsKey);
76 if (error)
77 return NULL;
78
79 error = RegOpenKeyW(hLayoutsKey, szLayout, &hLayoutKey);
80 }
81 else
82 {
83 error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_IMM, &hLayoutKey);
84 }
85
86 if (error)
87 {
88 ERR("RegOpenKeyW error: 0x%08lX\n", error);
89 hKL = NULL;
90 }
91 else
92 {
93 cbData = sizeof(pImeInfoEx->wszImeFile);
94 error = RegQueryValueExW(hLayoutKey, L"Ime File", 0, 0,
95 (LPBYTE)pImeInfoEx->wszImeFile, &cbData);
96 if (error)
97 hKL = NULL;
98 }
99
100 RegCloseKey(hLayoutKey);
101 if (hLayoutsKey)
102 RegCloseKey(hLayoutsKey);
103 return hKL;
104 }
105
106 typedef struct _tagImmHkl
107 {
108 struct list entry;
109 HKL hkl;
110 HMODULE hIME;
111 IMEINFO imeInfo;
112 WCHAR imeClassName[17]; /* 16 character max */
113 ULONG uSelected;
114 HWND UIWnd;
115
116 /* Function Pointers */
117 BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, const WCHAR *);
118 BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *);
119 BOOL (WINAPI *pImeDestroy)(UINT);
120 LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *);
121 BOOL (WINAPI *pImeSelect)(HIMC, BOOL);
122 BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL);
123 UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, DWORD *, UINT, HIMC);
124 BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD);
125 BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *);
126 BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *);
127 UINT (WINAPI *pImeEnumRegisterWord)(REGISTERWORDENUMPROCW, const WCHAR *, DWORD, const WCHAR *, void *);
128 BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void *, DWORD, const void *, DWORD);
129 DWORD (WINAPI *pImeConversionList)(HIMC, const WCHAR *, CANDIDATELIST *, DWORD, UINT);
130 BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *);
131 UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *);
132 DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD);
133 } ImmHkl;
134
135 typedef struct tagInputContextData
136 {
137 DWORD dwLock;
138 INPUTCONTEXT IMC;
139 DWORD threadID;
140
141 ImmHkl *immKbd;
142 UINT lastVK;
143 BOOL threadDefault;
144 DWORD magic;
145 } InputContextData;
146
147 #define WINE_IMC_VALID_MAGIC 0x56434D49
148
149 static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0};
150 static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
151 static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0};
152 static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0};
153
154 static inline BOOL is_himc_ime_unicode(const InputContextData *data)
155 {
156 return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE);
157 }
158
159 static InputContextData* get_imc_data(HIMC hIMC)
160 {
161 InputContextData *data = (InputContextData *)hIMC;
162
163 if (hIMC == NULL)
164 return NULL;
165
166 if(IsBadReadPtr(data, sizeof(InputContextData)) || data->magic != WINE_IMC_VALID_MAGIC)
167 {
168 SetLastError(ERROR_INVALID_HANDLE);
169 return NULL;
170 }
171 return data;
172 }
173
174 static HIMC get_default_context( HWND hwnd )
175 {
176 FIXME("Don't use this function\n");
177 return FALSE;
178 }
179
180 static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC)
181 {
182 InputContextData *data;
183
184 if (hWnd)
185 {
186 DWORD thread = GetWindowThreadProcessId(hWnd, NULL);
187 if (thread != GetCurrentThreadId()) return TRUE;
188 }
189 data = get_imc_data(hIMC);
190 if (data && data->threadID != GetCurrentThreadId())
191 return TRUE;
192
193 return FALSE;
194 }
195
196 /***********************************************************************
197 * ImmAssociateContext (IMM32.@)
198 */
199 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
200 {
201 HIMC old = NULL;
202 InputContextData *data = get_imc_data(hIMC);
203
204 TRACE("(%p, %p):\n", hWnd, hIMC);
205
206 if(hIMC && !data)
207 return NULL;
208
209 /*
210 * If already associated just return
211 */
212 if (hIMC && data->IMC.hWnd == hWnd)
213 return hIMC;
214
215 if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC))
216 return NULL;
217
218 if (hWnd)
219 {
220 HIMC defaultContext = get_default_context( hWnd );
221 old = RemovePropW(hWnd,szwWineIMCProperty);
222
223 if (old == NULL)
224 old = defaultContext;
225 else if (old == (HIMC)-1)
226 old = NULL;
227
228 if (hIMC != defaultContext)
229 {
230 if (hIMC == NULL) /* Meaning disable imm for that window*/
231 SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1);
232 else
233 SetPropW(hWnd,szwWineIMCProperty,hIMC);
234 }
235
236 if (old)
237 {
238 InputContextData *old_data = (InputContextData *)old;
239 if (old_data->IMC.hWnd == hWnd)
240 old_data->IMC.hWnd = NULL;
241 }
242 }
243
244 if (!hIMC)
245 return old;
246
247 if(GetActiveWindow() == data->IMC.hWnd)
248 {
249 SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL);
250 data->IMC.hWnd = hWnd;
251 SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL);
252 }
253
254 return old;
255 }
256
257 /***********************************************************************
258 * ImmAssociateContextEx (IMM32.@)
259 */
260 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
261 {
262 HWND hwndFocus;
263 PWND pFocusWnd;
264 HIMC hOldIMC = NULL;
265 DWORD dwValue;
266
267 TRACE("(%p, %p, 0x%lX)\n", hWnd, hIMC, dwFlags);
268
269 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
270 return FALSE;
271
272 if (hIMC && !(dwFlags & IACE_DEFAULT) && Imm32IsCrossThreadAccess(hIMC))
273 return FALSE;
274
275 hwndFocus = (HWND)NtUserQueryWindow(hWnd, QUERY_WINDOW_FOCUS);
276 pFocusWnd = ValidateHwndNoErr(hwndFocus);
277 if (pFocusWnd)
278 hOldIMC = pFocusWnd->hImc;
279
280 dwValue = NtUserAssociateInputContext(hWnd, hIMC, dwFlags);
281 switch (dwValue)
282 {
283 case 0:
284 return TRUE;
285
286 case 1:
287 pFocusWnd = ValidateHwndNoErr(hwndFocus);
288 if (pFocusWnd)
289 {
290 hIMC = pFocusWnd->hImc;
291 if (hIMC != hOldIMC)
292 {
293 ImmSetActiveContext(hwndFocus, hOldIMC, FALSE);
294 ImmSetActiveContext(hwndFocus, hIMC, TRUE);
295 }
296 }
297 return TRUE;
298
299 default:
300 return FALSE;
301 }
302 }
303
304 /***********************************************************************
305 * ImmCreateContext (IMM32.@)
306 */
307 HIMC WINAPI ImmCreateContext(void)
308 {
309 PCLIENTIMC pClientImc;
310 HIMC hIMC;
311
312 TRACE("()\n");
313
314 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
315 return NULL;
316
317 pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
318 if (pClientImc == NULL)
319 return NULL;
320
321 hIMC = NtUserCreateInputContext(pClientImc);
322 if (hIMC == NULL)
323 {
324 HeapFree(g_hImm32Heap, 0, pClientImc);
325 return NULL;
326 }
327
328 RtlInitializeCriticalSection(&pClientImc->cs);
329
330 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
331 pClientImc->unknown = NtUserGetThreadState(13);
332
333 return hIMC;
334 }
335
336 static VOID APIENTRY Imm32CleanupContextExtra(LPINPUTCONTEXT pIC)
337 {
338 FIXME("We have to do something do here");
339 }
340
341 static PCLIENTIMC APIENTRY Imm32FindClientImc(HIMC hIMC)
342 {
343 // FIXME
344 return NULL;
345 }
346
347 BOOL APIENTRY Imm32CleanupContext(HIMC hIMC, HKL hKL, BOOL bKeep)
348 {
349 PIMEDPI pImeDpi;
350 LPINPUTCONTEXT pIC;
351 PCLIENTIMC pClientImc;
352
353 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32) || hIMC == NULL)
354 return FALSE;
355
356 FIXME("We have do something to do here\n");
357 pClientImc = Imm32FindClientImc(hIMC);
358 if (!pClientImc)
359 return FALSE;
360
361 if (pClientImc->hImc == NULL)
362 {
363 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1;
364 ImmUnlockClientImc(pClientImc);
365 if (!bKeep)
366 return NtUserDestroyInputContext(hIMC);
367 return TRUE;
368 }
369
370 pIC = ImmLockIMC(hIMC);
371 if (pIC == NULL)
372 {
373 ImmUnlockClientImc(pClientImc);
374 return FALSE;
375 }
376
377 FIXME("We have do something to do here\n");
378
379 if (pClientImc->hKL == hKL)
380 {
381 pImeDpi = ImmLockImeDpi(hKL);
382 if (pImeDpi != NULL)
383 {
384 if (IS_IME_HKL(hKL))
385 {
386 pImeDpi->ImeSelect(hIMC, FALSE);
387 }
388 else if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
389 {
390 FIXME("We have do something to do here\n");
391 }
392 ImmUnlockImeDpi(pImeDpi);
393 }
394 pClientImc->hKL = NULL;
395 }
396
397 ImmDestroyIMCC(pIC->hPrivate);
398 ImmDestroyIMCC(pIC->hMsgBuf);
399 ImmDestroyIMCC(pIC->hGuideLine);
400 ImmDestroyIMCC(pIC->hCandInfo);
401 ImmDestroyIMCC(pIC->hCompStr);
402
403 Imm32CleanupContextExtra(pIC);
404
405 ImmUnlockIMC(hIMC);
406
407 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1;
408 ImmUnlockClientImc(pClientImc);
409
410 if (!bKeep)
411 return NtUserDestroyInputContext(hIMC);
412
413 return TRUE;
414 }
415
416 /***********************************************************************
417 * ImmDestroyContext (IMM32.@)
418 */
419 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
420 {
421 HKL hKL;
422
423 TRACE("(%p)\n", hIMC);
424
425 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
426 return FALSE;
427
428 if (Imm32IsCrossThreadAccess(hIMC))
429 return FALSE;
430
431 hKL = GetKeyboardLayout(0);
432 return Imm32CleanupContext(hIMC, hKL, FALSE);
433 }
434
435 static PCLIENTIMC APIENTRY Imm32GetClientImcCache(void)
436 {
437 // FIXME: Do something properly here
438 return NULL;
439 }
440
441 /***********************************************************************
442 * ImmLockClientImc (IMM32.@)
443 */
444 PCLIENTIMC WINAPI ImmLockClientImc(HIMC hImc)
445 {
446 PCLIENTIMC pClientImc;
447
448 TRACE("(%p)\n", hImc);
449
450 if (hImc == NULL)
451 return NULL;
452
453 pClientImc = Imm32GetClientImcCache();
454 if (!pClientImc)
455 {
456 pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
457 if (!pClientImc)
458 return NULL;
459
460 RtlInitializeCriticalSection(&pClientImc->cs);
461
462 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
463 pClientImc->unknown = NtUserGetThreadState(13);
464
465 if (!NtUserUpdateInputContext(hImc, 0, pClientImc))
466 {
467 HeapFree(g_hImm32Heap, 0, pClientImc);
468 return NULL;
469 }
470
471 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN2;
472 }
473 else
474 {
475 if (pClientImc->dwFlags & CLIENTIMC_UNKNOWN1)
476 return NULL;
477 }
478
479 InterlockedIncrement(&pClientImc->cLockObj);
480 return pClientImc;
481 }
482
483 /***********************************************************************
484 * ImmUnlockClientImc (IMM32.@)
485 */
486 VOID WINAPI ImmUnlockClientImc(PCLIENTIMC pClientImc)
487 {
488 LONG cLocks;
489 HIMC hImc;
490
491 TRACE("(%p)\n", pClientImc);
492
493 cLocks = InterlockedDecrement(&pClientImc->cLockObj);
494 if (cLocks != 0 || !(pClientImc->dwFlags & CLIENTIMC_UNKNOWN1))
495 return;
496
497 hImc = pClientImc->hImc;
498 if (hImc)
499 LocalFree(hImc);
500
501 RtlDeleteCriticalSection(&pClientImc->cs);
502 HeapFree(g_hImm32Heap, 0, pClientImc);
503 }
504
505 static HIMC APIENTRY Imm32GetContextEx(HWND hWnd, DWORD dwContextFlags)
506 {
507 HIMC hIMC;
508 PCLIENTIMC pClientImc;
509 PWND pWnd;
510
511 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
512 return NULL;
513
514 if (!hWnd)
515 {
516 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
517 hIMC = (HIMC)NtUserGetThreadState(4);
518 goto Quit;
519 }
520
521 pWnd = ValidateHwndNoErr(hWnd);
522 if (!pWnd || Imm32IsCrossProcessAccess(hWnd))
523 return NULL;
524
525 hIMC = pWnd->hImc;
526 if (!hIMC && (dwContextFlags & 1))
527 hIMC = (HIMC)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_ICONTEXT);
528
529 Quit:
530 pClientImc = ImmLockClientImc(hIMC);
531 if (pClientImc == NULL)
532 return NULL;
533 if ((dwContextFlags & 2) && (pClientImc->dwFlags & CLIENTIMC_UNKNOWN3))
534 hIMC = NULL;
535 ImmUnlockClientImc(pClientImc);
536 return hIMC;
537 }
538
539
540 /* Helpers for the GetCompositionString functions */
541
542 /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
543 length is always in bytes. */
544 static INT
545 CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst,
546 INT dst_len, BOOL unicode)
547 {
548 int char_size = unicode ? sizeof(WCHAR) : sizeof(char);
549 INT ret;
550
551 if (is_himc_ime_unicode(data) ^ unicode)
552 {
553 if (unicode)
554 ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR));
555 else
556 ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL);
557 ret *= char_size;
558 }
559 else
560 {
561 if (dst_len)
562 {
563 ret = min(src_len * char_size, dst_len);
564 memcpy(dst, src, ret);
565 }
566 else
567 ret = src_len * char_size;
568 }
569
570 return ret;
571 }
572
573 /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
574 passed mode. String length is in characters, attributes are in byte arrays. */
575 static INT
576 CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string,
577 INT str_len, BYTE *dst, INT dst_len, BOOL unicode)
578 {
579 union
580 {
581 const void *str;
582 const WCHAR *strW;
583 const char *strA;
584 } string;
585 INT rc;
586
587 string.str = comp_string;
588
589 if (is_himc_ime_unicode(data) && !unicode)
590 {
591 rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL);
592 if (dst_len)
593 {
594 int i, j = 0, k = 0;
595
596 if (rc < dst_len)
597 dst_len = rc;
598 for (i = 0; i < str_len; ++i)
599 {
600 int len;
601
602 len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL);
603 for (; len > 0; --len)
604 {
605 dst[j++] = src[k];
606
607 if (j >= dst_len)
608 goto end;
609 }
610 ++k;
611 }
612 end:
613 rc = j;
614 }
615 }
616 else if (!is_himc_ime_unicode(data) && unicode)
617 {
618 rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0);
619 if (dst_len)
620 {
621 int i, j = 0;
622
623 if (rc < dst_len)
624 dst_len = rc;
625 for (i = 0; i < str_len; ++i)
626 {
627 if (IsDBCSLeadByte(string.strA[i]))
628 continue;
629
630 dst[j++] = src[i];
631
632 if (j >= dst_len)
633 break;
634 }
635 rc = j;
636 }
637 }
638 else
639 {
640 memcpy(dst, src, min(src_len, dst_len));
641 rc = src_len;
642 }
643
644 return rc;
645 }
646
647 static INT
648 CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource,
649 LPBYTE target, INT tlen, BOOL unicode )
650 {
651 INT rc;
652
653 if (is_himc_ime_unicode(data) && !unicode)
654 {
655 if (tlen)
656 {
657 int i;
658
659 if (slen < tlen)
660 tlen = slen;
661 tlen /= sizeof (DWORD);
662 for (i = 0; i < tlen; ++i)
663 {
664 ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
665 ((DWORD *)source)[i],
666 NULL, 0,
667 NULL, NULL);
668 }
669 rc = sizeof (DWORD) * i;
670 }
671 else
672 rc = slen;
673 }
674 else if (!is_himc_ime_unicode(data) && unicode)
675 {
676 if (tlen)
677 {
678 int i;
679
680 if (slen < tlen)
681 tlen = slen;
682 tlen /= sizeof (DWORD);
683 for (i = 0; i < tlen; ++i)
684 {
685 ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
686 ((DWORD *)source)[i],
687 NULL, 0);
688 }
689 rc = sizeof (DWORD) * i;
690 }
691 else
692 rc = slen;
693 }
694 else
695 {
696 memcpy( target, source, min(slen,tlen));
697 rc = slen;
698 }
699
700 return rc;
701 }
702
703 static INT
704 CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode)
705 {
706 int rc;
707
708 if (is_himc_ime_unicode(data) && !unicode)
709 {
710 rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
711 }
712 else if (!is_himc_ime_unicode(data) && unicode)
713 {
714 rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
715 }
716 else
717 rc = offset;
718
719 return rc;
720 }
721
722 static LONG
723 ImmGetCompositionStringT(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
724 DWORD dwBufLen, BOOL unicode)
725 {
726 LONG rc = 0;
727 InputContextData *data = get_imc_data(hIMC);
728 LPCOMPOSITIONSTRING compstr;
729 LPBYTE compdata;
730
731 TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
732
733 if (!data)
734 return FALSE;
735
736 if (!data->IMC.hCompStr)
737 return FALSE;
738
739 compdata = ImmLockIMCC(data->IMC.hCompStr);
740 compstr = (LPCOMPOSITIONSTRING)compdata;
741
742 switch (dwIndex)
743 {
744 case GCS_RESULTSTR:
745 TRACE("GCS_RESULTSTR\n");
746 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
747 break;
748 case GCS_COMPSTR:
749 TRACE("GCS_COMPSTR\n");
750 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
751 break;
752 case GCS_COMPATTR:
753 TRACE("GCS_COMPATTR\n");
754 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
755 compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
756 lpBuf, dwBufLen, unicode);
757 break;
758 case GCS_COMPCLAUSE:
759 TRACE("GCS_COMPCLAUSE\n");
760 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
761 compdata + compstr->dwCompStrOffset,
762 lpBuf, dwBufLen, unicode);
763 break;
764 case GCS_RESULTCLAUSE:
765 TRACE("GCS_RESULTCLAUSE\n");
766 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
767 compdata + compstr->dwResultStrOffset,
768 lpBuf, dwBufLen, unicode);
769 break;
770 case GCS_RESULTREADSTR:
771 TRACE("GCS_RESULTREADSTR\n");
772 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
773 break;
774 case GCS_RESULTREADCLAUSE:
775 TRACE("GCS_RESULTREADCLAUSE\n");
776 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
777 compdata + compstr->dwResultStrOffset,
778 lpBuf, dwBufLen, unicode);
779 break;
780 case GCS_COMPREADSTR:
781 TRACE("GCS_COMPREADSTR\n");
782 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
783 break;
784 case GCS_COMPREADATTR:
785 TRACE("GCS_COMPREADATTR\n");
786 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
787 compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
788 lpBuf, dwBufLen, unicode);
789 break;
790 case GCS_COMPREADCLAUSE:
791 TRACE("GCS_COMPREADCLAUSE\n");
792 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
793 compdata + compstr->dwCompStrOffset,
794 lpBuf, dwBufLen, unicode);
795 break;
796 case GCS_CURSORPOS:
797 TRACE("GCS_CURSORPOS\n");
798 rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
799 break;
800 case GCS_DELTASTART:
801 TRACE("GCS_DELTASTART\n");
802 rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
803 break;
804 default:
805 FIXME("Unhandled index 0x%x\n",dwIndex);
806 break;
807 }
808
809 ImmUnlockIMCC(data->IMC.hCompStr);
810
811 return rc;
812 }
813
814 /***********************************************************************
815 * ImmGetCompositionStringA (IMM32.@)
816 */
817 LONG WINAPI ImmGetCompositionStringA(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
818 {
819 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
820 }
821
822 /***********************************************************************
823 * ImmGetCompositionStringW (IMM32.@)
824 */
825 LONG WINAPI ImmGetCompositionStringW(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
826 {
827 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
828 }
829
830 /***********************************************************************
831 * ImmGetContext (IMM32.@)
832 */
833 HIMC WINAPI ImmGetContext(HWND hWnd)
834 {
835 TRACE("(%p)\n", hWnd);
836 if (hWnd == NULL)
837 return NULL;
838 return Imm32GetContextEx(hWnd, 2);
839 }
840
841 /***********************************************************************
842 * CtfImmIsCiceroEnabled (IMM32.@)
843 */
844 BOOL WINAPI CtfImmIsCiceroEnabled(VOID)
845 {
846 return (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED));
847 }
848
849 /***********************************************************************
850 * ImmInstallIMEA (IMM32.@)
851 */
852 HKL WINAPI ImmInstallIMEA(LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
853 {
854 HKL hKL = NULL;
855 LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL;
856
857 TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText));
858
859 pszFileNameW = Imm32WideFromAnsi(lpszIMEFileName);
860 if (pszFileNameW == NULL)
861 goto Quit;
862
863 pszLayoutTextW = Imm32WideFromAnsi(lpszLayoutText);
864 if (pszLayoutTextW == NULL)
865 goto Quit;
866
867 hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW);
868
869 Quit:
870 if (pszFileNameW)
871 HeapFree(g_hImm32Heap, 0, pszFileNameW);
872 if (pszLayoutTextW)
873 HeapFree(g_hImm32Heap, 0, pszLayoutTextW);
874 return hKL;
875 }
876
877 /***********************************************************************
878 * ImmInstallIMEW (IMM32.@)
879 */
880 HKL WINAPI ImmInstallIMEW(LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
881 {
882 INT lcid = GetUserDefaultLCID();
883 INT count;
884 HKL hkl;
885 DWORD rc;
886 HKEY hkey;
887 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
888
889 TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
890 debugstr_w(lpszLayoutText));
891
892 /* Start with 2. e001 will be blank and so default to the wine internal IME */
893 count = 2;
894
895 while (count < 0xfff)
896 {
897 DWORD disposition = 0;
898
899 hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
900 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
901
902 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
903 if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
904 break;
905 else if (rc == ERROR_SUCCESS)
906 RegCloseKey(hkey);
907
908 count++;
909 }
910
911 if (count == 0xfff)
912 {
913 WARN("Unable to find slot to install IME\n");
914 return 0;
915 }
916
917 if (rc == ERROR_SUCCESS)
918 {
919 rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName,
920 (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
921 if (rc == ERROR_SUCCESS)
922 rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText,
923 (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
924 RegCloseKey(hkey);
925 return hkl;
926 }
927 else
928 {
929 WARN("Unable to set IME registry values\n");
930 return 0;
931 }
932 }
933
934 /***********************************************************************
935 * ImmLockIMC(IMM32.@)
936 */
937 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
938 {
939 InputContextData *data = get_imc_data(hIMC);
940
941 if (!data)
942 return NULL;
943 data->dwLock++;
944 return &data->IMC;
945 }
946
947 /***********************************************************************
948 * ImmUnlockIMC(IMM32.@)
949 */
950 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
951 {
952 PCLIENTIMC pClientImc;
953 HIMC hClientImc;
954
955 pClientImc = ImmLockClientImc(hIMC);
956 if (pClientImc == NULL)
957 return FALSE;
958
959 hClientImc = pClientImc->hImc;
960 if (hClientImc)
961 LocalUnlock(hClientImc);
962
963 InterlockedDecrement(&pClientImc->cLockObj);
964 ImmUnlockClientImc(pClientImc);
965 return TRUE;
966 }
967
968 /***********************************************************************
969 * ImmRequestMessageA(IMM32.@)
970 */
971 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
972 {
973 InputContextData *data = get_imc_data(hIMC);
974
975 TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
976
977 if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
978
979 SetLastError(ERROR_INVALID_HANDLE);
980 return 0;
981 }
982
983 /***********************************************************************
984 * ImmRequestMessageW(IMM32.@)
985 */
986 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
987 {
988 InputContextData *data = get_imc_data(hIMC);
989
990 TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
991
992 if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
993
994 SetLastError(ERROR_INVALID_HANDLE);
995 return 0;
996 }
997
998 /***********************************************************************
999 * ImmReleaseContext (IMM32.@)
1000 */
1001 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
1002 {
1003 TRACE("(%p, %p)\n", hWnd, hIMC);
1004 UNREFERENCED_PARAMETER(hWnd);
1005 UNREFERENCED_PARAMETER(hIMC);
1006 return TRUE; // Do nothing. This is correct.
1007 }
1008
1009 /***********************************************************************
1010 * ImmSetCompositionStringA (IMM32.@)
1011 */
1012 BOOL WINAPI
1013 ImmSetCompositionStringA(HIMC hIMC, DWORD dwIndex,
1014 LPCVOID lpComp, DWORD dwCompLen,
1015 LPCVOID lpRead, DWORD dwReadLen)
1016 {
1017 DWORD comp_len;
1018 DWORD read_len;
1019 WCHAR *CompBuffer = NULL;
1020 WCHAR *ReadBuffer = NULL;
1021 BOOL rc;
1022 InputContextData *data = get_imc_data(hIMC);
1023
1024 TRACE("(%p, %d, %p, %d, %p, %d):\n",
1025 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1026
1027 if (!data)
1028 return FALSE;
1029
1030 if (!(dwIndex == SCS_SETSTR ||
1031 dwIndex == SCS_CHANGEATTR ||
1032 dwIndex == SCS_CHANGECLAUSE ||
1033 dwIndex == SCS_SETRECONVERTSTRING ||
1034 dwIndex == SCS_QUERYRECONVERTSTRING))
1035 return FALSE;
1036
1037 if (!is_himc_ime_unicode(data))
1038 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
1039 dwCompLen, lpRead, dwReadLen);
1040
1041 comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
1042 if (comp_len)
1043 {
1044 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
1045 MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
1046 }
1047
1048 read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
1049 if (read_len)
1050 {
1051 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
1052 MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
1053 }
1054
1055 rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
1056 ReadBuffer, read_len);
1057
1058 HeapFree(GetProcessHeap(), 0, CompBuffer);
1059 HeapFree(GetProcessHeap(), 0, ReadBuffer);
1060
1061 return rc;
1062 }
1063
1064 /***********************************************************************
1065 * ImmSetCompositionStringW (IMM32.@)
1066 */
1067 BOOL WINAPI
1068 ImmSetCompositionStringW(HIMC hIMC, DWORD dwIndex,
1069 LPCVOID lpComp, DWORD dwCompLen,
1070 LPCVOID lpRead, DWORD dwReadLen)
1071 {
1072 DWORD comp_len;
1073 DWORD read_len;
1074 CHAR *CompBuffer = NULL;
1075 CHAR *ReadBuffer = NULL;
1076 BOOL rc;
1077 InputContextData *data = get_imc_data(hIMC);
1078
1079 TRACE("(%p, %d, %p, %d, %p, %d):\n",
1080 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1081
1082 if (!data)
1083 return FALSE;
1084
1085 if (!(dwIndex == SCS_SETSTR ||
1086 dwIndex == SCS_CHANGEATTR ||
1087 dwIndex == SCS_CHANGECLAUSE ||
1088 dwIndex == SCS_SETRECONVERTSTRING ||
1089 dwIndex == SCS_QUERYRECONVERTSTRING))
1090 return FALSE;
1091
1092 if (is_himc_ime_unicode(data))
1093 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
1094 dwCompLen, lpRead, dwReadLen);
1095
1096 comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
1097 NULL);
1098 if (comp_len)
1099 {
1100 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
1101 WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
1102 NULL, NULL);
1103 }
1104
1105 read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
1106 NULL);
1107 if (read_len)
1108 {
1109 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
1110 WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
1111 NULL, NULL);
1112 }
1113
1114 rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
1115 ReadBuffer, read_len);
1116
1117 HeapFree(GetProcessHeap(), 0, CompBuffer);
1118 HeapFree(GetProcessHeap(), 0, ReadBuffer);
1119
1120 return rc;
1121 }
1122
1123 /***********************************************************************
1124 * ImmCreateSoftKeyboard(IMM32.@)
1125 */
1126 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
1127 {
1128 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
1129 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1130 return 0;
1131 }
1132
1133 /***********************************************************************
1134 * ImmDestroySoftKeyboard(IMM32.@)
1135 */
1136 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
1137 {
1138 TRACE("(%p)\n", hSoftWnd);
1139 return DestroyWindow(hSoftWnd);
1140 }
1141
1142 /***********************************************************************
1143 * ImmShowSoftKeyboard(IMM32.@)
1144 */
1145 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
1146 {
1147 TRACE("(%p, %d)\n", hSoftWnd, nCmdShow);
1148 if (hSoftWnd)
1149 return ShowWindow(hSoftWnd, nCmdShow);
1150 return FALSE;
1151 }
1152
1153 /***********************************************************************
1154 * ImmDisableTextFrameService(IMM32.@)
1155 */
1156 BOOL WINAPI ImmDisableTextFrameService(DWORD dwThreadId)
1157 {
1158 FIXME("Stub\n");
1159 return FALSE;
1160 }
1161
1162 /***********************************************************************
1163 * ImmEnumInputContext(IMM32.@)
1164 */
1165 BOOL WINAPI ImmEnumInputContext(DWORD dwThreadId, IMCENUMPROC lpfn, LPARAM lParam)
1166 {
1167 HIMC *phList;
1168 DWORD dwIndex, dwCount;
1169 BOOL ret = TRUE;
1170 HIMC hIMC;
1171
1172 TRACE("(%lu, %p, %p)\n", dwThreadId, lpfn, lParam);
1173
1174 dwCount = Imm32AllocAndBuildHimcList(dwThreadId, &phList);
1175 if (!dwCount)
1176 return FALSE;
1177
1178 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex)
1179 {
1180 hIMC = phList[dwIndex];
1181 ret = (*lpfn)(hIMC, lParam);
1182 if (!ret)
1183 break;
1184 }
1185
1186 HeapFree(g_hImm32Heap, 0, phList);
1187 return ret;
1188 }
1189
1190 /***********************************************************************
1191 * ImmSetActiveContext(IMM32.@)
1192 */
1193 BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC hIMC, BOOL fFlag)
1194 {
1195 FIXME("(%p, %p, %d): stub\n", hwnd, hIMC, fFlag);
1196 return FALSE;
1197 }
1198
1199 /***********************************************************************
1200 * ImmSetActiveContextConsoleIME(IMM32.@)
1201 */
1202 BOOL WINAPI ImmSetActiveContextConsoleIME(HWND hwnd, BOOL fFlag)
1203 {
1204 HIMC hIMC;
1205 TRACE("(%p, %d)\n", hwnd, fFlag);
1206
1207 hIMC = ImmGetContext(hwnd);
1208 if (hIMC)
1209 return ImmSetActiveContext(hwnd, hIMC, fFlag);
1210 return FALSE;
1211 }
1212
1213 /***********************************************************************
1214 * ImmGetImeMenuItemsA (IMM32.@)
1215 */
1216 DWORD WINAPI
1217 ImmGetImeMenuItemsA(HIMC hIMC, DWORD dwFlags, DWORD dwType,
1218 LPIMEMENUITEMINFOA lpImeParentMenu,
1219 LPIMEMENUITEMINFOA lpImeMenu, DWORD dwSize)
1220 {
1221 InputContextData *data = get_imc_data(hIMC);
1222 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
1223 lpImeParentMenu, lpImeMenu, dwSize);
1224
1225 if (!data)
1226 {
1227 SetLastError(ERROR_INVALID_HANDLE);
1228 return 0;
1229 }
1230
1231 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
1232 {
1233 if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
1234 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1235 (IMEMENUITEMINFOW*)lpImeParentMenu,
1236 (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
1237 else
1238 {
1239 IMEMENUITEMINFOW lpImeParentMenuW;
1240 IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
1241 DWORD rc;
1242
1243 if (lpImeParentMenu)
1244 parent = &lpImeParentMenuW;
1245 if (lpImeMenu)
1246 {
1247 int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
1248 dwSize = count * sizeof(IMEMENUITEMINFOW);
1249 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
1250 }
1251 else
1252 lpImeMenuW = NULL;
1253
1254 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1255 parent, lpImeMenuW, dwSize);
1256
1257 if (lpImeParentMenu)
1258 {
1259 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
1260 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
1261 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
1262 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
1263 NULL, NULL);
1264 }
1265 if (lpImeMenu && rc)
1266 {
1267 unsigned int i;
1268 for (i = 0; i < rc; i++)
1269 {
1270 memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
1271 lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
1272 WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
1273 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
1274 NULL, NULL);
1275 }
1276 }
1277 HeapFree(GetProcessHeap(),0,lpImeMenuW);
1278 return rc;
1279 }
1280 }
1281 else
1282 return 0;
1283 }
1284
1285 /***********************************************************************
1286 * ImmGetImeMenuItemsW (IMM32.@)
1287 */
1288 DWORD WINAPI
1289 ImmGetImeMenuItemsW(HIMC hIMC, DWORD dwFlags, DWORD dwType,
1290 LPIMEMENUITEMINFOW lpImeParentMenu,
1291 LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize)
1292 {
1293 InputContextData *data = get_imc_data(hIMC);
1294 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
1295 lpImeParentMenu, lpImeMenu, dwSize);
1296
1297 if (!data)
1298 {
1299 SetLastError(ERROR_INVALID_HANDLE);
1300 return 0;
1301 }
1302
1303 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
1304 {
1305 if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
1306 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1307 lpImeParentMenu, lpImeMenu, dwSize);
1308 else
1309 {
1310 IMEMENUITEMINFOA lpImeParentMenuA;
1311 IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
1312 DWORD rc;
1313
1314 if (lpImeParentMenu)
1315 parent = &lpImeParentMenuA;
1316 if (lpImeMenu)
1317 {
1318 int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
1319 dwSize = count * sizeof(IMEMENUITEMINFOA);
1320 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
1321 }
1322 else
1323 lpImeMenuA = NULL;
1324
1325 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1326 (IMEMENUITEMINFOW*)parent,
1327 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
1328
1329 if (lpImeParentMenu)
1330 {
1331 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
1332 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
1333 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
1334 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
1335 }
1336 if (lpImeMenu && rc)
1337 {
1338 unsigned int i;
1339 for (i = 0; i < rc; i++)
1340 {
1341 memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
1342 lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
1343 MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
1344 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
1345 }
1346 }
1347 HeapFree(GetProcessHeap(),0,lpImeMenuA);
1348 return rc;
1349 }
1350 }
1351 else
1352 return 0;
1353 }
1354
1355 BOOL WINAPI User32InitializeImmEntryTable(DWORD);
1356
1357 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
1358 {
1359 HKL hKL;
1360 HIMC hIMC;
1361 PTEB pTeb;
1362
1363 TRACE("(%p, 0x%X, %p)\n", hinstDLL, fdwReason, lpReserved);
1364
1365 switch (fdwReason)
1366 {
1367 case DLL_PROCESS_ATTACH:
1368 //Imm32GenerateRandomSeed(hinstDLL, 1, lpReserved); // Non-sense
1369 if (!Imm32InitInstance(hinstDLL))
1370 {
1371 ERR("Imm32InitInstance failed\n");
1372 return FALSE;
1373 }
1374 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
1375 {
1376 ERR("User32InitializeImmEntryTable failed\n");
1377 return FALSE;
1378 }
1379 break;
1380
1381 case DLL_THREAD_ATTACH:
1382 break;
1383
1384 case DLL_THREAD_DETACH:
1385 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
1386 return TRUE;
1387
1388 pTeb = NtCurrentTeb();
1389 if (pTeb->Win32ThreadInfo == NULL)
1390 return TRUE;
1391
1392 hKL = GetKeyboardLayout(0);
1393 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
1394 hIMC = (HIMC)NtUserGetThreadState(4);
1395 Imm32CleanupContext(hIMC, hKL, TRUE);
1396 break;
1397
1398 case DLL_PROCESS_DETACH:
1399 RtlDeleteCriticalSection(&g_csImeDpi);
1400 TRACE("imm32.dll is unloaded\n");
1401 break;
1402 }
1403
1404 return TRUE;
1405 }