[IMM32] Rewrite ImmEscapeA/W (#3959)
[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 * Helper function for ImmAssociateContextEx
259 */
260 static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam)
261 {
262 HIMC hImc = (HIMC)lParam;
263 ImmAssociateContext(hwnd,hImc);
264 return TRUE;
265 }
266
267 /***********************************************************************
268 * ImmAssociateContextEx (IMM32.@)
269 */
270 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
271 {
272 TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags);
273
274 if (!hWnd)
275 return FALSE;
276
277 switch (dwFlags)
278 {
279 case 0:
280 ImmAssociateContext(hWnd,hIMC);
281 return TRUE;
282 case IACE_DEFAULT:
283 {
284 HIMC defaultContext = get_default_context( hWnd );
285 if (!defaultContext) return FALSE;
286 ImmAssociateContext(hWnd,defaultContext);
287 return TRUE;
288 }
289 case IACE_IGNORENOCONTEXT:
290 if (GetPropW(hWnd,szwWineIMCProperty))
291 ImmAssociateContext(hWnd,hIMC);
292 return TRUE;
293 case IACE_CHILDREN:
294 EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC);
295 return TRUE;
296 default:
297 FIXME("Unknown dwFlags 0x%x\n",dwFlags);
298 return FALSE;
299 }
300 }
301
302 /***********************************************************************
303 * ImmCreateContext (IMM32.@)
304 */
305 HIMC WINAPI ImmCreateContext(void)
306 {
307 PCLIENTIMC pClientImc;
308 HIMC hIMC;
309
310 TRACE("()\n");
311
312 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
313 return NULL;
314
315 pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
316 if (pClientImc == NULL)
317 return NULL;
318
319 hIMC = NtUserCreateInputContext(pClientImc);
320 if (hIMC == NULL)
321 {
322 HeapFree(g_hImm32Heap, 0, pClientImc);
323 return NULL;
324 }
325
326 RtlInitializeCriticalSection(&pClientImc->cs);
327
328 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
329 pClientImc->unknown = NtUserGetThreadState(13);
330
331 return hIMC;
332 }
333
334 static VOID APIENTRY Imm32CleanupContextExtra(LPINPUTCONTEXT pIC)
335 {
336 FIXME("We have to do something do here");
337 }
338
339 static PCLIENTIMC APIENTRY Imm32FindClientImc(HIMC hIMC)
340 {
341 // FIXME
342 return NULL;
343 }
344
345 BOOL APIENTRY Imm32CleanupContext(HIMC hIMC, HKL hKL, BOOL bKeep)
346 {
347 PIMEDPI pImeDpi;
348 LPINPUTCONTEXT pIC;
349 PCLIENTIMC pClientImc;
350
351 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32) || hIMC == NULL)
352 return FALSE;
353
354 FIXME("We have do something to do here\n");
355 pClientImc = Imm32FindClientImc(hIMC);
356 if (!pClientImc)
357 return FALSE;
358
359 if (pClientImc->hImc == NULL)
360 {
361 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1;
362 ImmUnlockClientImc(pClientImc);
363 if (!bKeep)
364 return NtUserDestroyInputContext(hIMC);
365 return TRUE;
366 }
367
368 pIC = ImmLockIMC(hIMC);
369 if (pIC == NULL)
370 {
371 ImmUnlockClientImc(pClientImc);
372 return FALSE;
373 }
374
375 FIXME("We have do something to do here\n");
376
377 if (pClientImc->hKL == hKL)
378 {
379 pImeDpi = ImmLockImeDpi(hKL);
380 if (pImeDpi != NULL)
381 {
382 if (IS_IME_HKL(hKL))
383 {
384 pImeDpi->ImeSelect(hIMC, FALSE);
385 }
386 else if (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED))
387 {
388 FIXME("We have do something to do here\n");
389 }
390 ImmUnlockImeDpi(pImeDpi);
391 }
392 pClientImc->hKL = NULL;
393 }
394
395 ImmDestroyIMCC(pIC->hPrivate);
396 ImmDestroyIMCC(pIC->hMsgBuf);
397 ImmDestroyIMCC(pIC->hGuideLine);
398 ImmDestroyIMCC(pIC->hCandInfo);
399 ImmDestroyIMCC(pIC->hCompStr);
400
401 Imm32CleanupContextExtra(pIC);
402
403 ImmUnlockIMC(hIMC);
404
405 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN1;
406 ImmUnlockClientImc(pClientImc);
407
408 if (!bKeep)
409 return NtUserDestroyInputContext(hIMC);
410
411 return TRUE;
412 }
413
414 /***********************************************************************
415 * ImmDestroyContext (IMM32.@)
416 */
417 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
418 {
419 HKL hKL;
420
421 TRACE("(%p)\n", hIMC);
422
423 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
424 return FALSE;
425
426 if (Imm32IsCrossThreadAccess(hIMC))
427 return FALSE;
428
429 hKL = GetKeyboardLayout(0);
430 return Imm32CleanupContext(hIMC, hKL, FALSE);
431 }
432
433 static PCLIENTIMC APIENTRY Imm32GetClientImcCache(void)
434 {
435 // FIXME: Do something properly here
436 return NULL;
437 }
438
439 /***********************************************************************
440 * ImmLockClientImc (IMM32.@)
441 */
442 PCLIENTIMC WINAPI ImmLockClientImc(HIMC hImc)
443 {
444 PCLIENTIMC pClientImc;
445
446 TRACE("(%p)\n", hImc);
447
448 if (hImc == NULL)
449 return NULL;
450
451 pClientImc = Imm32GetClientImcCache();
452 if (!pClientImc)
453 {
454 pClientImc = Imm32HeapAlloc(HEAP_ZERO_MEMORY, sizeof(CLIENTIMC));
455 if (!pClientImc)
456 return NULL;
457
458 RtlInitializeCriticalSection(&pClientImc->cs);
459
460 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
461 pClientImc->unknown = NtUserGetThreadState(13);
462
463 if (!NtUserUpdateInputContext(hImc, 0, pClientImc))
464 {
465 HeapFree(g_hImm32Heap, 0, pClientImc);
466 return NULL;
467 }
468
469 pClientImc->dwFlags |= CLIENTIMC_UNKNOWN2;
470 }
471 else
472 {
473 if (pClientImc->dwFlags & CLIENTIMC_UNKNOWN1)
474 return NULL;
475 }
476
477 InterlockedIncrement(&pClientImc->cLockObj);
478 return pClientImc;
479 }
480
481 /***********************************************************************
482 * ImmUnlockClientImc (IMM32.@)
483 */
484 VOID WINAPI ImmUnlockClientImc(PCLIENTIMC pClientImc)
485 {
486 LONG cLocks;
487 HIMC hImc;
488
489 TRACE("(%p)\n", pClientImc);
490
491 cLocks = InterlockedDecrement(&pClientImc->cLockObj);
492 if (cLocks != 0 || !(pClientImc->dwFlags & CLIENTIMC_UNKNOWN1))
493 return;
494
495 hImc = pClientImc->hImc;
496 if (hImc)
497 LocalFree(hImc);
498
499 RtlDeleteCriticalSection(&pClientImc->cs);
500 HeapFree(g_hImm32Heap, 0, pClientImc);
501 }
502
503 static HIMC APIENTRY Imm32GetContextEx(HWND hWnd, DWORD dwContextFlags)
504 {
505 HIMC hIMC;
506 PCLIENTIMC pClientImc;
507 PWND pWnd;
508
509 if (!g_psi || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
510 return NULL;
511
512 if (!hWnd)
513 {
514 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
515 hIMC = (HIMC)NtUserGetThreadState(4);
516 goto Quit;
517 }
518
519 pWnd = ValidateHwndNoErr(hWnd);
520 if (!pWnd || Imm32IsCrossProcessAccess(hWnd))
521 return NULL;
522
523 hIMC = pWnd->hImc;
524 if (!hIMC && (dwContextFlags & 1))
525 hIMC = (HIMC)NtUserQueryWindow(hWnd, QUERY_WINDOW_DEFAULT_ICONTEXT);
526
527 Quit:
528 pClientImc = ImmLockClientImc(hIMC);
529 if (pClientImc == NULL)
530 return NULL;
531 if ((dwContextFlags & 2) && (pClientImc->dwFlags & CLIENTIMC_UNKNOWN3))
532 hIMC = NULL;
533 ImmUnlockClientImc(pClientImc);
534 return hIMC;
535 }
536
537
538 /* Helpers for the GetCompositionString functions */
539
540 /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
541 length is always in bytes. */
542 static INT
543 CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst,
544 INT dst_len, BOOL unicode)
545 {
546 int char_size = unicode ? sizeof(WCHAR) : sizeof(char);
547 INT ret;
548
549 if (is_himc_ime_unicode(data) ^ unicode)
550 {
551 if (unicode)
552 ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR));
553 else
554 ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL);
555 ret *= char_size;
556 }
557 else
558 {
559 if (dst_len)
560 {
561 ret = min(src_len * char_size, dst_len);
562 memcpy(dst, src, ret);
563 }
564 else
565 ret = src_len * char_size;
566 }
567
568 return ret;
569 }
570
571 /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
572 passed mode. String length is in characters, attributes are in byte arrays. */
573 static INT
574 CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string,
575 INT str_len, BYTE *dst, INT dst_len, BOOL unicode)
576 {
577 union
578 {
579 const void *str;
580 const WCHAR *strW;
581 const char *strA;
582 } string;
583 INT rc;
584
585 string.str = comp_string;
586
587 if (is_himc_ime_unicode(data) && !unicode)
588 {
589 rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL);
590 if (dst_len)
591 {
592 int i, j = 0, k = 0;
593
594 if (rc < dst_len)
595 dst_len = rc;
596 for (i = 0; i < str_len; ++i)
597 {
598 int len;
599
600 len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL);
601 for (; len > 0; --len)
602 {
603 dst[j++] = src[k];
604
605 if (j >= dst_len)
606 goto end;
607 }
608 ++k;
609 }
610 end:
611 rc = j;
612 }
613 }
614 else if (!is_himc_ime_unicode(data) && unicode)
615 {
616 rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0);
617 if (dst_len)
618 {
619 int i, j = 0;
620
621 if (rc < dst_len)
622 dst_len = rc;
623 for (i = 0; i < str_len; ++i)
624 {
625 if (IsDBCSLeadByte(string.strA[i]))
626 continue;
627
628 dst[j++] = src[i];
629
630 if (j >= dst_len)
631 break;
632 }
633 rc = j;
634 }
635 }
636 else
637 {
638 memcpy(dst, src, min(src_len, dst_len));
639 rc = src_len;
640 }
641
642 return rc;
643 }
644
645 static INT
646 CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource,
647 LPBYTE target, INT tlen, BOOL unicode )
648 {
649 INT rc;
650
651 if (is_himc_ime_unicode(data) && !unicode)
652 {
653 if (tlen)
654 {
655 int i;
656
657 if (slen < tlen)
658 tlen = slen;
659 tlen /= sizeof (DWORD);
660 for (i = 0; i < tlen; ++i)
661 {
662 ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
663 ((DWORD *)source)[i],
664 NULL, 0,
665 NULL, NULL);
666 }
667 rc = sizeof (DWORD) * i;
668 }
669 else
670 rc = slen;
671 }
672 else if (!is_himc_ime_unicode(data) && unicode)
673 {
674 if (tlen)
675 {
676 int i;
677
678 if (slen < tlen)
679 tlen = slen;
680 tlen /= sizeof (DWORD);
681 for (i = 0; i < tlen; ++i)
682 {
683 ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
684 ((DWORD *)source)[i],
685 NULL, 0);
686 }
687 rc = sizeof (DWORD) * i;
688 }
689 else
690 rc = slen;
691 }
692 else
693 {
694 memcpy( target, source, min(slen,tlen));
695 rc = slen;
696 }
697
698 return rc;
699 }
700
701 static INT
702 CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode)
703 {
704 int rc;
705
706 if (is_himc_ime_unicode(data) && !unicode)
707 {
708 rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
709 }
710 else if (!is_himc_ime_unicode(data) && unicode)
711 {
712 rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
713 }
714 else
715 rc = offset;
716
717 return rc;
718 }
719
720 static LONG
721 ImmGetCompositionStringT(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
722 DWORD dwBufLen, BOOL unicode)
723 {
724 LONG rc = 0;
725 InputContextData *data = get_imc_data(hIMC);
726 LPCOMPOSITIONSTRING compstr;
727 LPBYTE compdata;
728
729 TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
730
731 if (!data)
732 return FALSE;
733
734 if (!data->IMC.hCompStr)
735 return FALSE;
736
737 compdata = ImmLockIMCC(data->IMC.hCompStr);
738 compstr = (LPCOMPOSITIONSTRING)compdata;
739
740 switch (dwIndex)
741 {
742 case GCS_RESULTSTR:
743 TRACE("GCS_RESULTSTR\n");
744 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
745 break;
746 case GCS_COMPSTR:
747 TRACE("GCS_COMPSTR\n");
748 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
749 break;
750 case GCS_COMPATTR:
751 TRACE("GCS_COMPATTR\n");
752 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
753 compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
754 lpBuf, dwBufLen, unicode);
755 break;
756 case GCS_COMPCLAUSE:
757 TRACE("GCS_COMPCLAUSE\n");
758 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
759 compdata + compstr->dwCompStrOffset,
760 lpBuf, dwBufLen, unicode);
761 break;
762 case GCS_RESULTCLAUSE:
763 TRACE("GCS_RESULTCLAUSE\n");
764 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
765 compdata + compstr->dwResultStrOffset,
766 lpBuf, dwBufLen, unicode);
767 break;
768 case GCS_RESULTREADSTR:
769 TRACE("GCS_RESULTREADSTR\n");
770 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
771 break;
772 case GCS_RESULTREADCLAUSE:
773 TRACE("GCS_RESULTREADCLAUSE\n");
774 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
775 compdata + compstr->dwResultStrOffset,
776 lpBuf, dwBufLen, unicode);
777 break;
778 case GCS_COMPREADSTR:
779 TRACE("GCS_COMPREADSTR\n");
780 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
781 break;
782 case GCS_COMPREADATTR:
783 TRACE("GCS_COMPREADATTR\n");
784 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
785 compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
786 lpBuf, dwBufLen, unicode);
787 break;
788 case GCS_COMPREADCLAUSE:
789 TRACE("GCS_COMPREADCLAUSE\n");
790 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
791 compdata + compstr->dwCompStrOffset,
792 lpBuf, dwBufLen, unicode);
793 break;
794 case GCS_CURSORPOS:
795 TRACE("GCS_CURSORPOS\n");
796 rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
797 break;
798 case GCS_DELTASTART:
799 TRACE("GCS_DELTASTART\n");
800 rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
801 break;
802 default:
803 FIXME("Unhandled index 0x%x\n",dwIndex);
804 break;
805 }
806
807 ImmUnlockIMCC(data->IMC.hCompStr);
808
809 return rc;
810 }
811
812 /***********************************************************************
813 * ImmGetCompositionStringA (IMM32.@)
814 */
815 LONG WINAPI ImmGetCompositionStringA(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
816 {
817 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
818 }
819
820 /***********************************************************************
821 * ImmGetCompositionStringW (IMM32.@)
822 */
823 LONG WINAPI ImmGetCompositionStringW(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
824 {
825 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
826 }
827
828 /***********************************************************************
829 * ImmGetContext (IMM32.@)
830 */
831 HIMC WINAPI ImmGetContext(HWND hWnd)
832 {
833 TRACE("(%p)\n", hWnd);
834 if (hWnd == NULL)
835 return NULL;
836 return Imm32GetContextEx(hWnd, 2);
837 }
838
839 /***********************************************************************
840 * CtfImmIsCiceroEnabled (IMM32.@)
841 */
842 BOOL WINAPI CtfImmIsCiceroEnabled(VOID)
843 {
844 return (g_psi && (g_psi->dwSRVIFlags & SRVINFO_CICERO_ENABLED));
845 }
846
847 /***********************************************************************
848 * ImmInstallIMEA (IMM32.@)
849 */
850 HKL WINAPI ImmInstallIMEA(LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
851 {
852 HKL hKL = NULL;
853 LPWSTR pszFileNameW = NULL, pszLayoutTextW = NULL;
854
855 TRACE("(%s, %s)\n", debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText));
856
857 pszFileNameW = Imm32WideFromAnsi(lpszIMEFileName);
858 if (pszFileNameW == NULL)
859 goto Quit;
860
861 pszLayoutTextW = Imm32WideFromAnsi(lpszLayoutText);
862 if (pszLayoutTextW == NULL)
863 goto Quit;
864
865 hKL = ImmInstallIMEW(pszFileNameW, pszLayoutTextW);
866
867 Quit:
868 if (pszFileNameW)
869 HeapFree(g_hImm32Heap, 0, pszFileNameW);
870 if (pszLayoutTextW)
871 HeapFree(g_hImm32Heap, 0, pszLayoutTextW);
872 return hKL;
873 }
874
875 /***********************************************************************
876 * ImmInstallIMEW (IMM32.@)
877 */
878 HKL WINAPI ImmInstallIMEW(LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
879 {
880 INT lcid = GetUserDefaultLCID();
881 INT count;
882 HKL hkl;
883 DWORD rc;
884 HKEY hkey;
885 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
886
887 TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
888 debugstr_w(lpszLayoutText));
889
890 /* Start with 2. e001 will be blank and so default to the wine internal IME */
891 count = 2;
892
893 while (count < 0xfff)
894 {
895 DWORD disposition = 0;
896
897 hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
898 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
899
900 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
901 if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
902 break;
903 else if (rc == ERROR_SUCCESS)
904 RegCloseKey(hkey);
905
906 count++;
907 }
908
909 if (count == 0xfff)
910 {
911 WARN("Unable to find slot to install IME\n");
912 return 0;
913 }
914
915 if (rc == ERROR_SUCCESS)
916 {
917 rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName,
918 (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
919 if (rc == ERROR_SUCCESS)
920 rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText,
921 (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
922 RegCloseKey(hkey);
923 return hkl;
924 }
925 else
926 {
927 WARN("Unable to set IME registry values\n");
928 return 0;
929 }
930 }
931
932 /***********************************************************************
933 * ImmLockIMC(IMM32.@)
934 */
935 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
936 {
937 InputContextData *data = get_imc_data(hIMC);
938
939 if (!data)
940 return NULL;
941 data->dwLock++;
942 return &data->IMC;
943 }
944
945 /***********************************************************************
946 * ImmUnlockIMC(IMM32.@)
947 */
948 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
949 {
950 PCLIENTIMC pClientImc;
951 HIMC hClientImc;
952
953 pClientImc = ImmLockClientImc(hIMC);
954 if (pClientImc == NULL)
955 return FALSE;
956
957 hClientImc = pClientImc->hImc;
958 if (hClientImc)
959 LocalUnlock(hClientImc);
960
961 InterlockedDecrement(&pClientImc->cLockObj);
962 ImmUnlockClientImc(pClientImc);
963 return TRUE;
964 }
965
966 /***********************************************************************
967 * ImmRequestMessageA(IMM32.@)
968 */
969 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
970 {
971 InputContextData *data = get_imc_data(hIMC);
972
973 TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
974
975 if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
976
977 SetLastError(ERROR_INVALID_HANDLE);
978 return 0;
979 }
980
981 /***********************************************************************
982 * ImmRequestMessageW(IMM32.@)
983 */
984 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
985 {
986 InputContextData *data = get_imc_data(hIMC);
987
988 TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
989
990 if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
991
992 SetLastError(ERROR_INVALID_HANDLE);
993 return 0;
994 }
995
996 /***********************************************************************
997 * ImmReleaseContext (IMM32.@)
998 */
999 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
1000 {
1001 TRACE("(%p, %p)\n", hWnd, hIMC);
1002 UNREFERENCED_PARAMETER(hWnd);
1003 UNREFERENCED_PARAMETER(hIMC);
1004 return TRUE; // Do nothing. This is correct.
1005 }
1006
1007 /***********************************************************************
1008 * ImmSetCompositionStringA (IMM32.@)
1009 */
1010 BOOL WINAPI
1011 ImmSetCompositionStringA(HIMC hIMC, DWORD dwIndex,
1012 LPCVOID lpComp, DWORD dwCompLen,
1013 LPCVOID lpRead, DWORD dwReadLen)
1014 {
1015 DWORD comp_len;
1016 DWORD read_len;
1017 WCHAR *CompBuffer = NULL;
1018 WCHAR *ReadBuffer = NULL;
1019 BOOL rc;
1020 InputContextData *data = get_imc_data(hIMC);
1021
1022 TRACE("(%p, %d, %p, %d, %p, %d):\n",
1023 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1024
1025 if (!data)
1026 return FALSE;
1027
1028 if (!(dwIndex == SCS_SETSTR ||
1029 dwIndex == SCS_CHANGEATTR ||
1030 dwIndex == SCS_CHANGECLAUSE ||
1031 dwIndex == SCS_SETRECONVERTSTRING ||
1032 dwIndex == SCS_QUERYRECONVERTSTRING))
1033 return FALSE;
1034
1035 if (!is_himc_ime_unicode(data))
1036 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
1037 dwCompLen, lpRead, dwReadLen);
1038
1039 comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
1040 if (comp_len)
1041 {
1042 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
1043 MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
1044 }
1045
1046 read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
1047 if (read_len)
1048 {
1049 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
1050 MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
1051 }
1052
1053 rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
1054 ReadBuffer, read_len);
1055
1056 HeapFree(GetProcessHeap(), 0, CompBuffer);
1057 HeapFree(GetProcessHeap(), 0, ReadBuffer);
1058
1059 return rc;
1060 }
1061
1062 /***********************************************************************
1063 * ImmSetCompositionStringW (IMM32.@)
1064 */
1065 BOOL WINAPI
1066 ImmSetCompositionStringW(HIMC hIMC, DWORD dwIndex,
1067 LPCVOID lpComp, DWORD dwCompLen,
1068 LPCVOID lpRead, DWORD dwReadLen)
1069 {
1070 DWORD comp_len;
1071 DWORD read_len;
1072 CHAR *CompBuffer = NULL;
1073 CHAR *ReadBuffer = NULL;
1074 BOOL rc;
1075 InputContextData *data = get_imc_data(hIMC);
1076
1077 TRACE("(%p, %d, %p, %d, %p, %d):\n",
1078 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1079
1080 if (!data)
1081 return FALSE;
1082
1083 if (!(dwIndex == SCS_SETSTR ||
1084 dwIndex == SCS_CHANGEATTR ||
1085 dwIndex == SCS_CHANGECLAUSE ||
1086 dwIndex == SCS_SETRECONVERTSTRING ||
1087 dwIndex == SCS_QUERYRECONVERTSTRING))
1088 return FALSE;
1089
1090 if (is_himc_ime_unicode(data))
1091 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
1092 dwCompLen, lpRead, dwReadLen);
1093
1094 comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
1095 NULL);
1096 if (comp_len)
1097 {
1098 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
1099 WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
1100 NULL, NULL);
1101 }
1102
1103 read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
1104 NULL);
1105 if (read_len)
1106 {
1107 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
1108 WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
1109 NULL, NULL);
1110 }
1111
1112 rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
1113 ReadBuffer, read_len);
1114
1115 HeapFree(GetProcessHeap(), 0, CompBuffer);
1116 HeapFree(GetProcessHeap(), 0, ReadBuffer);
1117
1118 return rc;
1119 }
1120
1121 /***********************************************************************
1122 * ImmCreateSoftKeyboard(IMM32.@)
1123 */
1124 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
1125 {
1126 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
1127 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1128 return 0;
1129 }
1130
1131 /***********************************************************************
1132 * ImmDestroySoftKeyboard(IMM32.@)
1133 */
1134 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
1135 {
1136 TRACE("(%p)\n", hSoftWnd);
1137 return DestroyWindow(hSoftWnd);
1138 }
1139
1140 /***********************************************************************
1141 * ImmShowSoftKeyboard(IMM32.@)
1142 */
1143 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
1144 {
1145 TRACE("(%p, %d)\n", hSoftWnd, nCmdShow);
1146 if (hSoftWnd)
1147 return ShowWindow(hSoftWnd, nCmdShow);
1148 return FALSE;
1149 }
1150
1151 /***********************************************************************
1152 * ImmDisableTextFrameService(IMM32.@)
1153 */
1154 BOOL WINAPI ImmDisableTextFrameService(DWORD dwThreadId)
1155 {
1156 FIXME("Stub\n");
1157 return FALSE;
1158 }
1159
1160 /***********************************************************************
1161 * ImmEnumInputContext(IMM32.@)
1162 */
1163 BOOL WINAPI ImmEnumInputContext(DWORD dwThreadId, IMCENUMPROC lpfn, LPARAM lParam)
1164 {
1165 HIMC *phList;
1166 DWORD dwIndex, dwCount;
1167 BOOL ret = TRUE;
1168 HIMC hIMC;
1169
1170 TRACE("(%lu, %p, %p)\n", dwThreadId, lpfn, lParam);
1171
1172 dwCount = Imm32AllocAndBuildHimcList(dwThreadId, &phList);
1173 if (!dwCount)
1174 return FALSE;
1175
1176 for (dwIndex = 0; dwIndex < dwCount; ++dwIndex)
1177 {
1178 hIMC = phList[dwIndex];
1179 ret = (*lpfn)(hIMC, lParam);
1180 if (!ret)
1181 break;
1182 }
1183
1184 HeapFree(g_hImm32Heap, 0, phList);
1185 return ret;
1186 }
1187
1188 /***********************************************************************
1189 * ImmSetActiveContext(IMM32.@)
1190 */
1191 BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC hIMC, BOOL fFlag)
1192 {
1193 FIXME("(%p, %p, %d): stub\n", hwnd, hIMC, fFlag);
1194 return FALSE;
1195 }
1196
1197 /***********************************************************************
1198 * ImmSetActiveContextConsoleIME(IMM32.@)
1199 */
1200 BOOL WINAPI ImmSetActiveContextConsoleIME(HWND hwnd, BOOL fFlag)
1201 {
1202 HIMC hIMC;
1203 TRACE("(%p, %d)\n", hwnd, fFlag);
1204
1205 hIMC = ImmGetContext(hwnd);
1206 if (hIMC)
1207 return ImmSetActiveContext(hwnd, hIMC, fFlag);
1208 return FALSE;
1209 }
1210
1211 /***********************************************************************
1212 * ImmGetImeMenuItemsA (IMM32.@)
1213 */
1214 DWORD WINAPI
1215 ImmGetImeMenuItemsA(HIMC hIMC, DWORD dwFlags, DWORD dwType,
1216 LPIMEMENUITEMINFOA lpImeParentMenu,
1217 LPIMEMENUITEMINFOA lpImeMenu, DWORD dwSize)
1218 {
1219 InputContextData *data = get_imc_data(hIMC);
1220 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
1221 lpImeParentMenu, lpImeMenu, dwSize);
1222
1223 if (!data)
1224 {
1225 SetLastError(ERROR_INVALID_HANDLE);
1226 return 0;
1227 }
1228
1229 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
1230 {
1231 if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
1232 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1233 (IMEMENUITEMINFOW*)lpImeParentMenu,
1234 (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
1235 else
1236 {
1237 IMEMENUITEMINFOW lpImeParentMenuW;
1238 IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
1239 DWORD rc;
1240
1241 if (lpImeParentMenu)
1242 parent = &lpImeParentMenuW;
1243 if (lpImeMenu)
1244 {
1245 int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
1246 dwSize = count * sizeof(IMEMENUITEMINFOW);
1247 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
1248 }
1249 else
1250 lpImeMenuW = NULL;
1251
1252 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1253 parent, lpImeMenuW, dwSize);
1254
1255 if (lpImeParentMenu)
1256 {
1257 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
1258 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
1259 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
1260 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
1261 NULL, NULL);
1262 }
1263 if (lpImeMenu && rc)
1264 {
1265 unsigned int i;
1266 for (i = 0; i < rc; i++)
1267 {
1268 memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
1269 lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
1270 WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
1271 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
1272 NULL, NULL);
1273 }
1274 }
1275 HeapFree(GetProcessHeap(),0,lpImeMenuW);
1276 return rc;
1277 }
1278 }
1279 else
1280 return 0;
1281 }
1282
1283 /***********************************************************************
1284 * ImmGetImeMenuItemsW (IMM32.@)
1285 */
1286 DWORD WINAPI
1287 ImmGetImeMenuItemsW(HIMC hIMC, DWORD dwFlags, DWORD dwType,
1288 LPIMEMENUITEMINFOW lpImeParentMenu,
1289 LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize)
1290 {
1291 InputContextData *data = get_imc_data(hIMC);
1292 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
1293 lpImeParentMenu, lpImeMenu, dwSize);
1294
1295 if (!data)
1296 {
1297 SetLastError(ERROR_INVALID_HANDLE);
1298 return 0;
1299 }
1300
1301 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
1302 {
1303 if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
1304 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1305 lpImeParentMenu, lpImeMenu, dwSize);
1306 else
1307 {
1308 IMEMENUITEMINFOA lpImeParentMenuA;
1309 IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
1310 DWORD rc;
1311
1312 if (lpImeParentMenu)
1313 parent = &lpImeParentMenuA;
1314 if (lpImeMenu)
1315 {
1316 int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
1317 dwSize = count * sizeof(IMEMENUITEMINFOA);
1318 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
1319 }
1320 else
1321 lpImeMenuA = NULL;
1322
1323 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
1324 (IMEMENUITEMINFOW*)parent,
1325 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
1326
1327 if (lpImeParentMenu)
1328 {
1329 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
1330 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
1331 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
1332 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
1333 }
1334 if (lpImeMenu && rc)
1335 {
1336 unsigned int i;
1337 for (i = 0; i < rc; i++)
1338 {
1339 memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
1340 lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
1341 MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
1342 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
1343 }
1344 }
1345 HeapFree(GetProcessHeap(),0,lpImeMenuA);
1346 return rc;
1347 }
1348 }
1349 else
1350 return 0;
1351 }
1352
1353 BOOL WINAPI User32InitializeImmEntryTable(DWORD);
1354
1355 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
1356 {
1357 HKL hKL;
1358 HIMC hIMC;
1359 PTEB pTeb;
1360
1361 TRACE("(%p, 0x%X, %p)\n", hinstDLL, fdwReason, lpReserved);
1362
1363 switch (fdwReason)
1364 {
1365 case DLL_PROCESS_ATTACH:
1366 //Imm32GenerateRandomSeed(hinstDLL, 1, lpReserved); // Non-sense
1367 if (!Imm32InitInstance(hinstDLL))
1368 {
1369 ERR("Imm32InitInstance failed\n");
1370 return FALSE;
1371 }
1372 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
1373 {
1374 ERR("User32InitializeImmEntryTable failed\n");
1375 return FALSE;
1376 }
1377 break;
1378
1379 case DLL_THREAD_ATTACH:
1380 break;
1381
1382 case DLL_THREAD_DETACH:
1383 if (g_psi == NULL || !(g_psi->dwSRVIFlags & SRVINFO_IMM32))
1384 return TRUE;
1385
1386 pTeb = NtCurrentTeb();
1387 if (pTeb->Win32ThreadInfo == NULL)
1388 return TRUE;
1389
1390 hKL = GetKeyboardLayout(0);
1391 // FIXME: NtUserGetThreadState and enum ThreadStateRoutines are broken.
1392 hIMC = (HIMC)NtUserGetThreadState(4);
1393 Imm32CleanupContext(hIMC, hKL, TRUE);
1394 break;
1395
1396 case DLL_PROCESS_DETACH:
1397 RtlDeleteCriticalSection(&g_csImeDpi);
1398 TRACE("imm32.dll is unloaded\n");
1399 break;
1400 }
1401
1402 return TRUE;
1403 }