winedbg: Don't dereference possibly NULL thread pointer.
[wine/zf.git] / dlls / imm32 / imm.c
blob9d2a09f22bea34194a04955f379482093f1b0a08
1 /*
2 * IMM32 library
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <stdio.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30 #include "wine/debug.h"
31 #include "imm.h"
32 #include "ddk/imm.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "wine/list.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(imm);
39 #define IMM_INIT_MAGIC 0x19650412
40 BOOL WINAPI User32InitializeImmEntryTable(DWORD);
42 typedef struct _tagImmHkl{
43 struct list entry;
44 HKL hkl;
45 HMODULE hIME;
46 IMEINFO imeInfo;
47 WCHAR imeClassName[17]; /* 16 character max */
48 ULONG uSelected;
49 HWND UIWnd;
51 /* Function Pointers */
52 BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, const WCHAR *);
53 BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *);
54 BOOL (WINAPI *pImeDestroy)(UINT);
55 LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *);
56 BOOL (WINAPI *pImeSelect)(HIMC, BOOL);
57 BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL);
58 UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, DWORD *, UINT, HIMC);
59 BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD);
60 BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *);
61 BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *);
62 UINT (WINAPI *pImeEnumRegisterWord)(REGISTERWORDENUMPROCW, const WCHAR *, DWORD, const WCHAR *, void *);
63 BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void *, DWORD, const void *, DWORD);
64 DWORD (WINAPI *pImeConversionList)(HIMC, const WCHAR *, CANDIDATELIST *, DWORD, UINT);
65 BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *);
66 UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *);
67 DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD);
68 } ImmHkl;
70 typedef struct tagInputContextData
72 DWORD dwLock;
73 INPUTCONTEXT IMC;
74 DWORD threadID;
76 ImmHkl *immKbd;
77 UINT lastVK;
78 BOOL threadDefault;
79 DWORD magic;
80 } InputContextData;
82 #define WINE_IMC_VALID_MAGIC 0x56434D49
84 typedef struct _tagTRANSMSG {
85 UINT message;
86 WPARAM wParam;
87 LPARAM lParam;
88 } TRANSMSG, *LPTRANSMSG;
90 typedef struct _tagIMMThreadData {
91 struct list entry;
92 DWORD threadID;
93 HIMC defaultContext;
94 HWND hwndDefault;
95 BOOL disableIME;
96 DWORD windowRefs;
97 } IMMThreadData;
99 static struct list ImmHklList = LIST_INIT(ImmHklList);
100 static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
102 static const WCHAR szwWineIMCProperty[] = L"WineImmHIMCProperty";
103 static const WCHAR szImeRegFmt[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx";
105 static CRITICAL_SECTION threaddata_cs;
106 static CRITICAL_SECTION_DEBUG critsect_debug =
108 0, 0, &threaddata_cs,
109 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
110 0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") }
112 static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
113 static BOOL disable_ime;
115 static inline BOOL is_himc_ime_unicode(const InputContextData *data)
117 return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE);
120 static inline BOOL is_kbd_ime_unicode(const ImmHkl *hkl)
122 return !!(hkl->imeInfo.fdwProperty & IME_PROP_UNICODE);
125 static BOOL IMM_DestroyContext(HIMC hIMC);
126 static InputContextData* get_imc_data(HIMC hIMC);
128 static inline WCHAR *strdupAtoW( const char *str )
130 WCHAR *ret = NULL;
131 if (str)
133 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
134 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
135 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
137 return ret;
140 static inline CHAR *strdupWtoA( const WCHAR *str )
142 CHAR *ret = NULL;
143 if (str)
145 DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
146 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
147 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
149 return ret;
152 static DWORD convert_candidatelist_WtoA(
153 LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
155 DWORD ret, i, len;
157 ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
158 if ( lpDst && dwBufLen > 0 )
160 *lpDst = *lpSrc;
161 lpDst->dwOffset[0] = ret;
164 for ( i = 0; i < lpSrc->dwCount; i++)
166 LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
168 if ( lpDst && dwBufLen > 0 )
170 LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
172 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1,
173 (LPSTR)dest, dwBufLen, NULL, NULL);
175 if ( i + 1 < lpSrc->dwCount )
176 lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(char);
177 dwBufLen -= len * sizeof(char);
179 else
180 len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, NULL, 0, NULL, NULL);
182 ret += len * sizeof(char);
185 if ( lpDst )
186 lpDst->dwSize = ret;
188 return ret;
191 static DWORD convert_candidatelist_AtoW(
192 LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen)
194 DWORD ret, i, len;
196 ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] );
197 if ( lpDst && dwBufLen > 0 )
199 *lpDst = *lpSrc;
200 lpDst->dwOffset[0] = ret;
203 for ( i = 0; i < lpSrc->dwCount; i++)
205 LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i];
207 if ( lpDst && dwBufLen > 0 )
209 LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i];
211 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1,
212 (LPWSTR)dest, dwBufLen);
214 if ( i + 1 < lpSrc->dwCount )
215 lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(WCHAR);
216 dwBufLen -= len * sizeof(WCHAR);
218 else
219 len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, NULL, 0);
221 ret += len * sizeof(WCHAR);
224 if ( lpDst )
225 lpDst->dwSize = ret;
227 return ret;
230 static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread)
232 IMMThreadData *data;
233 DWORD process;
235 if (hwnd)
237 if (!(thread = GetWindowThreadProcessId(hwnd, &process))) return NULL;
238 if (process != GetCurrentProcessId()) return NULL;
240 else if (thread)
242 HANDLE h = OpenThread(THREAD_QUERY_INFORMATION, FALSE, thread);
243 if (!h) return NULL;
244 process = GetProcessIdOfThread(h);
245 CloseHandle(h);
246 if (process != GetCurrentProcessId()) return NULL;
248 else
249 thread = GetCurrentThreadId();
251 EnterCriticalSection(&threaddata_cs);
252 LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
253 if (data->threadID == thread) return data;
255 data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
256 data->threadID = thread;
257 list_add_head(&ImmThreadDataList,&data->entry);
258 TRACE("Thread Data Created (%x)\n",thread);
259 return data;
262 static BOOL IMM_IsDefaultContext(HIMC imc)
264 InputContextData *data = get_imc_data(imc);
266 if (!data)
267 return FALSE;
269 return data->threadDefault;
272 static void IMM_FreeThreadData(void)
274 IMMThreadData *data;
276 EnterCriticalSection(&threaddata_cs);
277 LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry)
279 if (data->threadID == GetCurrentThreadId())
281 list_remove(&data->entry);
282 LeaveCriticalSection(&threaddata_cs);
283 IMM_DestroyContext(data->defaultContext);
284 HeapFree(GetProcessHeap(),0,data);
285 TRACE("Thread Data Destroyed\n");
286 return;
289 LeaveCriticalSection(&threaddata_cs);
292 static HMODULE load_graphics_driver(void)
294 static const WCHAR key_pathW[] = L"System\\CurrentControlSet\\Control\\Video\\{";
295 static const WCHAR displayW[] = L"}\\0000";
297 HMODULE ret = 0;
298 HKEY hkey;
299 DWORD size;
300 WCHAR path[MAX_PATH];
301 WCHAR key[ARRAY_SIZE( key_pathW ) + ARRAY_SIZE( displayW ) + 40];
302 UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), L"__wine_display_device_guid" ));
304 if (!guid_atom) return 0;
305 memcpy( key, key_pathW, sizeof(key_pathW) );
306 if (!GlobalGetAtomNameW( guid_atom, key + lstrlenW(key), 40 )) return 0;
307 lstrcatW( key, displayW );
308 if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0;
309 size = sizeof(path);
310 if (!RegQueryValueExW( hkey, L"GraphicsDriver", NULL, NULL, (BYTE *)path, &size ))
311 ret = LoadLibraryW( path );
312 RegCloseKey( hkey );
313 TRACE( "%s %p\n", debugstr_w(path), ret );
314 return ret;
317 /* ImmHkl loading and freeing */
318 #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);}
319 static ImmHkl *IMM_GetImmHkl(HKL hkl)
321 ImmHkl *ptr;
322 WCHAR filename[MAX_PATH];
324 TRACE("Seeking ime for keyboard %p\n",hkl);
326 LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry)
328 if (ptr->hkl == hkl)
329 return ptr;
331 /* not found... create it */
333 ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl));
335 ptr->hkl = hkl;
336 if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename);
337 if (!ptr->hIME) ptr->hIME = load_graphics_driver();
338 if (ptr->hIME)
340 LOAD_FUNCPTR(ImeInquire);
341 if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL))
343 FreeLibrary(ptr->hIME);
344 ptr->hIME = NULL;
346 else
348 LOAD_FUNCPTR(ImeDestroy);
349 LOAD_FUNCPTR(ImeSelect);
350 if (!ptr->pImeSelect || !ptr->pImeDestroy)
352 FreeLibrary(ptr->hIME);
353 ptr->hIME = NULL;
355 else
357 LOAD_FUNCPTR(ImeConfigure);
358 LOAD_FUNCPTR(ImeEscape);
359 LOAD_FUNCPTR(ImeSetActiveContext);
360 LOAD_FUNCPTR(ImeToAsciiEx);
361 LOAD_FUNCPTR(NotifyIME);
362 LOAD_FUNCPTR(ImeRegisterWord);
363 LOAD_FUNCPTR(ImeUnregisterWord);
364 LOAD_FUNCPTR(ImeEnumRegisterWord);
365 LOAD_FUNCPTR(ImeSetCompositionString);
366 LOAD_FUNCPTR(ImeConversionList);
367 LOAD_FUNCPTR(ImeProcessKey);
368 LOAD_FUNCPTR(ImeGetRegisterWordStyle);
369 LOAD_FUNCPTR(ImeGetImeMenuItems);
370 /* make sure our classname is WCHAR */
371 if (!is_kbd_ime_unicode(ptr))
373 WCHAR bufW[17];
374 MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName,
375 -1, bufW, 17);
376 lstrcpyW(ptr->imeClassName, bufW);
381 list_add_head(&ImmHklList,&ptr->entry);
383 return ptr;
385 #undef LOAD_FUNCPTR
387 HWND WINAPI __wine_get_ui_window(HKL hkl)
389 ImmHkl *immHkl = IMM_GetImmHkl(hkl);
390 return immHkl->UIWnd;
393 static void IMM_FreeAllImmHkl(void)
395 ImmHkl *ptr,*cursor2;
397 LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &ImmHklList, ImmHkl, entry)
399 list_remove(&ptr->entry);
400 if (ptr->hIME)
402 ptr->pImeDestroy(1);
403 FreeLibrary(ptr->hIME);
405 if (ptr->UIWnd)
406 DestroyWindow(ptr->UIWnd);
407 HeapFree(GetProcessHeap(),0,ptr);
411 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
413 TRACE("%p, %x, %p\n",hInstDLL,fdwReason,lpReserved);
414 switch (fdwReason)
416 case DLL_PROCESS_ATTACH:
417 if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC))
419 return FALSE;
421 break;
422 case DLL_THREAD_ATTACH:
423 break;
424 case DLL_THREAD_DETACH:
425 IMM_FreeThreadData();
426 break;
427 case DLL_PROCESS_DETACH:
428 if (lpReserved) break;
429 IMM_FreeThreadData();
430 IMM_FreeAllImmHkl();
431 break;
433 return TRUE;
436 /* for posting messages as the IME */
437 static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
439 HWND target = GetFocus();
440 if (!target)
441 PostMessageW(data->IMC.hWnd,msg,wParam,lParam);
442 else
443 PostMessageW(target, msg, wParam, lParam);
446 /* for sending messages as the IME */
447 static void ImmInternalSendIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
449 HWND target = GetFocus();
450 if (!target)
451 SendMessageW(data->IMC.hWnd,msg,wParam,lParam);
452 else
453 SendMessageW(target, msg, wParam, lParam);
456 static LRESULT ImmInternalSendIMENotify(InputContextData *data, WPARAM notify, LPARAM lParam)
458 HWND target;
460 target = data->IMC.hWnd;
461 if (!target) target = GetFocus();
463 if (target)
464 return SendMessageW(target, WM_IME_NOTIFY, notify, lParam);
466 return 0;
469 static HIMCC ImmCreateBlankCompStr(void)
471 HIMCC rc;
472 LPCOMPOSITIONSTRING ptr;
473 rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
474 ptr = ImmLockIMCC(rc);
475 memset(ptr,0,sizeof(COMPOSITIONSTRING));
476 ptr->dwSize = sizeof(COMPOSITIONSTRING);
477 ImmUnlockIMCC(rc);
478 return rc;
481 static InputContextData* get_imc_data(HIMC hIMC)
483 InputContextData *data = hIMC;
485 if (hIMC == NULL)
486 return NULL;
488 if(IsBadReadPtr(data, sizeof(InputContextData)) || data->magic != WINE_IMC_VALID_MAGIC)
490 SetLastError(ERROR_INVALID_HANDLE);
491 return NULL;
493 return data;
496 static HIMC get_default_context( HWND hwnd )
498 HIMC ret;
499 IMMThreadData* thread_data = IMM_GetThreadData( hwnd, 0 );
501 if (!thread_data) return 0;
503 if (thread_data->defaultContext)
505 ret = thread_data->defaultContext;
506 LeaveCriticalSection(&threaddata_cs);
507 return ret;
510 /* can't create a default context in another thread */
511 if (thread_data->threadID != GetCurrentThreadId())
513 LeaveCriticalSection(&threaddata_cs);
514 return 0;
517 LeaveCriticalSection(&threaddata_cs);
519 ret = ImmCreateContext();
520 if (!ret) return 0;
521 ((InputContextData*)ret)->threadDefault = TRUE;
523 /* thread_data is in the current thread so we can assume it's still valid */
524 EnterCriticalSection(&threaddata_cs);
526 if (thread_data->defaultContext) /* someone beat us */
528 IMM_DestroyContext( ret );
529 ret = thread_data->defaultContext;
531 else thread_data->defaultContext = ret;
533 LeaveCriticalSection(&threaddata_cs);
534 return ret;
537 static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC)
539 InputContextData *data;
541 if (hWnd)
543 DWORD thread = GetWindowThreadProcessId(hWnd, NULL);
544 if (thread != GetCurrentThreadId()) return TRUE;
546 data = get_imc_data(hIMC);
547 if (data && data->threadID != GetCurrentThreadId())
548 return TRUE;
550 return FALSE;
553 /***********************************************************************
554 * ImmAssociateContext (IMM32.@)
556 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
558 HIMC old = NULL;
559 InputContextData *data = get_imc_data(hIMC);
561 TRACE("(%p, %p):\n", hWnd, hIMC);
563 if(hIMC && !data)
564 return NULL;
567 * If already associated just return
569 if (hIMC && data->IMC.hWnd == hWnd)
570 return hIMC;
572 if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC))
573 return NULL;
575 if (hWnd)
577 HIMC defaultContext = get_default_context( hWnd );
578 old = RemovePropW(hWnd,szwWineIMCProperty);
580 if (old == NULL)
581 old = defaultContext;
582 else if (old == (HIMC)-1)
583 old = NULL;
585 if (hIMC != defaultContext)
587 if (hIMC == NULL) /* Meaning disable imm for that window*/
588 SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1);
589 else
590 SetPropW(hWnd,szwWineIMCProperty,hIMC);
593 if (old)
595 InputContextData *old_data = old;
596 if (old_data->IMC.hWnd == hWnd)
597 old_data->IMC.hWnd = NULL;
601 if (!hIMC)
602 return old;
604 SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL);
605 data->IMC.hWnd = hWnd;
606 SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL);
608 return old;
613 * Helper function for ImmAssociateContextEx
615 static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam)
617 HIMC hImc = (HIMC)lParam;
618 ImmAssociateContext(hwnd,hImc);
619 return TRUE;
622 /***********************************************************************
623 * ImmAssociateContextEx (IMM32.@)
625 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
627 TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags);
629 if (!hWnd)
630 return FALSE;
632 switch (dwFlags)
634 case 0:
635 ImmAssociateContext(hWnd,hIMC);
636 return TRUE;
637 case IACE_DEFAULT:
639 HIMC defaultContext = get_default_context( hWnd );
640 if (!defaultContext) return FALSE;
641 ImmAssociateContext(hWnd,defaultContext);
642 return TRUE;
644 case IACE_IGNORENOCONTEXT:
645 if (GetPropW(hWnd,szwWineIMCProperty))
646 ImmAssociateContext(hWnd,hIMC);
647 return TRUE;
648 case IACE_CHILDREN:
649 EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC);
650 return TRUE;
651 default:
652 FIXME("Unknown dwFlags 0x%x\n",dwFlags);
653 return FALSE;
657 /***********************************************************************
658 * ImmConfigureIMEA (IMM32.@)
660 BOOL WINAPI ImmConfigureIMEA(
661 HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
663 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
665 TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
667 if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
668 return FALSE;
670 if (immHkl->hIME && immHkl->pImeConfigure)
672 if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl))
673 return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
674 else
676 REGISTERWORDW rww;
677 REGISTERWORDA *rwa = lpData;
678 BOOL rc;
680 rww.lpReading = strdupAtoW(rwa->lpReading);
681 rww.lpWord = strdupAtoW(rwa->lpWord);
682 rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww);
683 HeapFree(GetProcessHeap(),0,rww.lpReading);
684 HeapFree(GetProcessHeap(),0,rww.lpWord);
685 return rc;
688 else
689 return FALSE;
692 /***********************************************************************
693 * ImmConfigureIMEW (IMM32.@)
695 BOOL WINAPI ImmConfigureIMEW(
696 HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
698 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
700 TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
702 if (dwMode == IME_CONFIG_REGISTERWORD && !lpData)
703 return FALSE;
705 if (immHkl->hIME && immHkl->pImeConfigure)
707 if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl))
708 return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
709 else
711 REGISTERWORDW *rww = lpData;
712 REGISTERWORDA rwa;
713 BOOL rc;
715 rwa.lpReading = strdupWtoA(rww->lpReading);
716 rwa.lpWord = strdupWtoA(rww->lpWord);
717 rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa);
718 HeapFree(GetProcessHeap(),0,rwa.lpReading);
719 HeapFree(GetProcessHeap(),0,rwa.lpWord);
720 return rc;
723 else
724 return FALSE;
727 /***********************************************************************
728 * ImmCreateContext (IMM32.@)
730 HIMC WINAPI ImmCreateContext(void)
732 InputContextData *new_context;
733 LPGUIDELINE gl;
734 LPCANDIDATEINFO ci;
735 int i;
737 new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData));
739 /* Load the IME */
740 new_context->immKbd = IMM_GetImmHkl(GetKeyboardLayout(0));
742 if (!new_context->immKbd->hIME)
744 TRACE("IME dll could not be loaded\n");
745 HeapFree(GetProcessHeap(),0,new_context);
746 return 0;
749 /* the HIMCCs are never NULL */
750 new_context->IMC.hCompStr = ImmCreateBlankCompStr();
751 new_context->IMC.hMsgBuf = ImmCreateIMCC(0);
752 new_context->IMC.hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO));
753 ci = ImmLockIMCC(new_context->IMC.hCandInfo);
754 memset(ci,0,sizeof(CANDIDATEINFO));
755 ci->dwSize = sizeof(CANDIDATEINFO);
756 ImmUnlockIMCC(new_context->IMC.hCandInfo);
757 new_context->IMC.hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE));
758 gl = ImmLockIMCC(new_context->IMC.hGuideLine);
759 memset(gl,0,sizeof(GUIDELINE));
760 gl->dwSize = sizeof(GUIDELINE);
761 ImmUnlockIMCC(new_context->IMC.hGuideLine);
763 for (i = 0; i < ARRAY_SIZE(new_context->IMC.cfCandForm); i++)
764 new_context->IMC.cfCandForm[i].dwIndex = ~0u;
766 /* Initialize the IME Private */
767 new_context->IMC.hPrivate = ImmCreateIMCC(new_context->immKbd->imeInfo.dwPrivateDataSize);
769 new_context->IMC.fdwConversion = new_context->immKbd->imeInfo.fdwConversionCaps;
770 new_context->IMC.fdwSentence = new_context->immKbd->imeInfo.fdwSentenceCaps;
772 if (!new_context->immKbd->pImeSelect(new_context, TRUE))
774 TRACE("Selection of IME failed\n");
775 IMM_DestroyContext(new_context);
776 return 0;
778 new_context->threadID = GetCurrentThreadId();
779 SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->immKbd);
781 new_context->immKbd->uSelected++;
782 TRACE("Created context %p\n",new_context);
784 new_context->magic = WINE_IMC_VALID_MAGIC;
785 return new_context;
788 static BOOL IMM_DestroyContext(HIMC hIMC)
790 InputContextData *data = get_imc_data(hIMC);
792 TRACE("Destroying %p\n",hIMC);
794 if (!data)
795 return FALSE;
797 data->immKbd->uSelected --;
798 data->immKbd->pImeSelect(hIMC, FALSE);
799 SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd);
801 ImmDestroyIMCC(data->IMC.hCompStr);
802 ImmDestroyIMCC(data->IMC.hCandInfo);
803 ImmDestroyIMCC(data->IMC.hGuideLine);
804 ImmDestroyIMCC(data->IMC.hPrivate);
805 ImmDestroyIMCC(data->IMC.hMsgBuf);
807 data->magic = 0;
808 HeapFree(GetProcessHeap(),0,data);
810 return TRUE;
813 /***********************************************************************
814 * ImmDestroyContext (IMM32.@)
816 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
818 if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC))
819 return IMM_DestroyContext(hIMC);
820 else
821 return FALSE;
824 /***********************************************************************
825 * ImmDisableIME (IMM32.@)
827 BOOL WINAPI ImmDisableIME(DWORD idThread)
829 if (idThread == (DWORD)-1)
830 disable_ime = TRUE;
831 else {
832 IMMThreadData *thread_data = IMM_GetThreadData(NULL, idThread);
833 if (!thread_data) return FALSE;
834 thread_data->disableIME = TRUE;
835 LeaveCriticalSection(&threaddata_cs);
837 return TRUE;
840 /***********************************************************************
841 * ImmEnumRegisterWordA (IMM32.@)
843 UINT WINAPI ImmEnumRegisterWordA(
844 HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc,
845 LPCSTR lpszReading, DWORD dwStyle,
846 LPCSTR lpszRegister, LPVOID lpData)
848 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
849 TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc,
850 debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister), lpData);
851 if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
853 if (!is_kbd_ime_unicode(immHkl))
854 return immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
855 (LPCWSTR)lpszReading, dwStyle, (LPCWSTR)lpszRegister, lpData);
856 else
858 LPWSTR lpszwReading = strdupAtoW(lpszReading);
859 LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
860 BOOL rc;
862 rc = immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc,
863 lpszwReading, dwStyle, lpszwRegister,
864 lpData);
866 HeapFree(GetProcessHeap(),0,lpszwReading);
867 HeapFree(GetProcessHeap(),0,lpszwRegister);
868 return rc;
871 else
872 return 0;
875 /***********************************************************************
876 * ImmEnumRegisterWordW (IMM32.@)
878 UINT WINAPI ImmEnumRegisterWordW(
879 HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc,
880 LPCWSTR lpszReading, DWORD dwStyle,
881 LPCWSTR lpszRegister, LPVOID lpData)
883 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
884 TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc,
885 debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), lpData);
886 if (immHkl->hIME && immHkl->pImeEnumRegisterWord)
888 if (is_kbd_ime_unicode(immHkl))
889 return immHkl->pImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle,
890 lpszRegister, lpData);
891 else
893 LPSTR lpszaReading = strdupWtoA(lpszReading);
894 LPSTR lpszaRegister = strdupWtoA(lpszRegister);
895 BOOL rc;
897 rc = immHkl->pImeEnumRegisterWord(lpfnEnumProc, (LPCWSTR)lpszaReading,
898 dwStyle, (LPCWSTR)lpszaRegister, lpData);
900 HeapFree(GetProcessHeap(),0,lpszaReading);
901 HeapFree(GetProcessHeap(),0,lpszaRegister);
902 return rc;
905 else
906 return 0;
909 static inline BOOL EscapeRequiresWA(UINT uEscape)
911 if (uEscape == IME_ESC_GET_EUDC_DICTIONARY ||
912 uEscape == IME_ESC_SET_EUDC_DICTIONARY ||
913 uEscape == IME_ESC_IME_NAME ||
914 uEscape == IME_ESC_GETHELPFILENAME)
915 return TRUE;
916 return FALSE;
919 /***********************************************************************
920 * ImmEscapeA (IMM32.@)
922 LRESULT WINAPI ImmEscapeA(
923 HKL hKL, HIMC hIMC,
924 UINT uEscape, LPVOID lpData)
926 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
927 TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
929 if (immHkl->hIME && immHkl->pImeEscape)
931 if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl))
932 return immHkl->pImeEscape(hIMC,uEscape,lpData);
933 else
935 WCHAR buffer[81]; /* largest required buffer should be 80 */
936 LRESULT rc;
937 if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
939 MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81);
940 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
942 else
944 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
945 WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL);
947 return rc;
950 else
951 return 0;
954 /***********************************************************************
955 * ImmEscapeW (IMM32.@)
957 LRESULT WINAPI ImmEscapeW(
958 HKL hKL, HIMC hIMC,
959 UINT uEscape, LPVOID lpData)
961 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
962 TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData);
964 if (immHkl->hIME && immHkl->pImeEscape)
966 if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl))
967 return immHkl->pImeEscape(hIMC,uEscape,lpData);
968 else
970 CHAR buffer[81]; /* largest required buffer should be 80 */
971 LRESULT rc;
972 if (uEscape == IME_ESC_SET_EUDC_DICTIONARY)
974 WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL);
975 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
977 else
979 rc = immHkl->pImeEscape(hIMC,uEscape,buffer);
980 MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80);
982 return rc;
985 else
986 return 0;
989 /***********************************************************************
990 * ImmGetCandidateListA (IMM32.@)
992 DWORD WINAPI ImmGetCandidateListA(
993 HIMC hIMC, DWORD dwIndex,
994 LPCANDIDATELIST lpCandList, DWORD dwBufLen)
996 InputContextData *data = get_imc_data(hIMC);
997 LPCANDIDATEINFO candinfo;
998 LPCANDIDATELIST candlist;
999 DWORD ret = 0;
1001 TRACE("%p, %d, %p, %d\n", hIMC, dwIndex, lpCandList, dwBufLen);
1003 if (!data || !data->IMC.hCandInfo)
1004 return 0;
1006 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1007 if (dwIndex >= candinfo->dwCount || dwIndex >= ARRAY_SIZE(candinfo->dwOffset))
1008 goto done;
1010 candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
1011 if ( !candlist->dwSize || !candlist->dwCount )
1012 goto done;
1014 if ( !is_himc_ime_unicode(data) )
1016 ret = candlist->dwSize;
1017 if ( lpCandList && dwBufLen >= ret )
1018 memcpy(lpCandList, candlist, ret);
1020 else
1021 ret = convert_candidatelist_WtoA( candlist, lpCandList, dwBufLen);
1023 done:
1024 ImmUnlockIMCC(data->IMC.hCandInfo);
1025 return ret;
1028 /***********************************************************************
1029 * ImmGetCandidateListCountA (IMM32.@)
1031 DWORD WINAPI ImmGetCandidateListCountA(
1032 HIMC hIMC, LPDWORD lpdwListCount)
1034 InputContextData *data = get_imc_data(hIMC);
1035 LPCANDIDATEINFO candinfo;
1036 DWORD ret, count;
1038 TRACE("%p, %p\n", hIMC, lpdwListCount);
1040 if (!data || !lpdwListCount || !data->IMC.hCandInfo)
1041 return 0;
1043 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1045 *lpdwListCount = count = candinfo->dwCount;
1047 if ( !is_himc_ime_unicode(data) )
1048 ret = candinfo->dwSize;
1049 else
1051 ret = sizeof(CANDIDATEINFO);
1052 while ( count-- )
1053 ret += ImmGetCandidateListA(hIMC, count, NULL, 0);
1056 ImmUnlockIMCC(data->IMC.hCandInfo);
1057 return ret;
1060 /***********************************************************************
1061 * ImmGetCandidateListCountW (IMM32.@)
1063 DWORD WINAPI ImmGetCandidateListCountW(
1064 HIMC hIMC, LPDWORD lpdwListCount)
1066 InputContextData *data = get_imc_data(hIMC);
1067 LPCANDIDATEINFO candinfo;
1068 DWORD ret, count;
1070 TRACE("%p, %p\n", hIMC, lpdwListCount);
1072 if (!data || !lpdwListCount || !data->IMC.hCandInfo)
1073 return 0;
1075 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1077 *lpdwListCount = count = candinfo->dwCount;
1079 if ( is_himc_ime_unicode(data) )
1080 ret = candinfo->dwSize;
1081 else
1083 ret = sizeof(CANDIDATEINFO);
1084 while ( count-- )
1085 ret += ImmGetCandidateListW(hIMC, count, NULL, 0);
1088 ImmUnlockIMCC(data->IMC.hCandInfo);
1089 return ret;
1092 /***********************************************************************
1093 * ImmGetCandidateListW (IMM32.@)
1095 DWORD WINAPI ImmGetCandidateListW(
1096 HIMC hIMC, DWORD dwIndex,
1097 LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1099 InputContextData *data = get_imc_data(hIMC);
1100 LPCANDIDATEINFO candinfo;
1101 LPCANDIDATELIST candlist;
1102 DWORD ret = 0;
1104 TRACE("%p, %d, %p, %d\n", hIMC, dwIndex, lpCandList, dwBufLen);
1106 if (!data || !data->IMC.hCandInfo)
1107 return 0;
1109 candinfo = ImmLockIMCC(data->IMC.hCandInfo);
1110 if (dwIndex >= candinfo->dwCount || dwIndex >= ARRAY_SIZE(candinfo->dwOffset))
1111 goto done;
1113 candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]);
1114 if ( !candlist->dwSize || !candlist->dwCount )
1115 goto done;
1117 if ( is_himc_ime_unicode(data) )
1119 ret = candlist->dwSize;
1120 if ( lpCandList && dwBufLen >= ret )
1121 memcpy(lpCandList, candlist, ret);
1123 else
1124 ret = convert_candidatelist_AtoW( candlist, lpCandList, dwBufLen);
1126 done:
1127 ImmUnlockIMCC(data->IMC.hCandInfo);
1128 return ret;
1131 /***********************************************************************
1132 * ImmGetCandidateWindow (IMM32.@)
1134 BOOL WINAPI ImmGetCandidateWindow(
1135 HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate)
1137 InputContextData *data = get_imc_data(hIMC);
1139 TRACE("%p, %d, %p\n", hIMC, dwIndex, lpCandidate);
1141 if (!data || !lpCandidate)
1142 return FALSE;
1144 if (dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm))
1145 return FALSE;
1147 if (data->IMC.cfCandForm[dwIndex].dwIndex != dwIndex)
1148 return FALSE;
1150 *lpCandidate = data->IMC.cfCandForm[dwIndex];
1152 return TRUE;
1155 /***********************************************************************
1156 * ImmGetCompositionFontA (IMM32.@)
1158 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1160 LOGFONTW lfW;
1161 BOOL rc;
1163 TRACE("(%p, %p):\n", hIMC, lplf);
1165 rc = ImmGetCompositionFontW(hIMC,&lfW);
1166 if (!rc || !lplf)
1167 return FALSE;
1169 memcpy(lplf,&lfW,sizeof(LOGFONTA));
1170 WideCharToMultiByte(CP_ACP, 0, lfW.lfFaceName, -1, lplf->lfFaceName,
1171 LF_FACESIZE, NULL, NULL);
1172 return TRUE;
1175 /***********************************************************************
1176 * ImmGetCompositionFontW (IMM32.@)
1178 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1180 InputContextData *data = get_imc_data(hIMC);
1182 TRACE("(%p, %p):\n", hIMC, lplf);
1184 if (!data || !lplf)
1185 return FALSE;
1187 *lplf = data->IMC.lfFont.W;
1189 return TRUE;
1193 /* Helpers for the GetCompositionString functions */
1195 /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer
1196 length is always in bytes. */
1197 static INT CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst,
1198 INT dst_len, BOOL unicode)
1200 int char_size = unicode ? sizeof(WCHAR) : sizeof(char);
1201 INT ret;
1203 if (is_himc_ime_unicode(data) ^ unicode)
1205 if (unicode)
1206 ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR));
1207 else
1208 ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL);
1209 ret *= char_size;
1211 else
1213 if (dst_len)
1215 ret = min(src_len * char_size, dst_len);
1216 memcpy(dst, src, ret);
1218 else
1219 ret = src_len * char_size;
1222 return ret;
1225 /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to
1226 passed mode. String length is in characters, attributes are in byte arrays. */
1227 static INT CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string,
1228 INT str_len, BYTE *dst, INT dst_len, BOOL unicode)
1230 union
1232 const void *str;
1233 const WCHAR *strW;
1234 const char *strA;
1235 } string;
1236 INT rc;
1238 string.str = comp_string;
1240 if (is_himc_ime_unicode(data) && !unicode)
1242 rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL);
1243 if (dst_len)
1245 int i, j = 0, k = 0;
1247 if (rc < dst_len)
1248 dst_len = rc;
1249 for (i = 0; i < str_len; ++i)
1251 int len;
1253 len = WideCharToMultiByte(CP_ACP, 0, string.strW + i, 1, NULL, 0, NULL, NULL);
1254 for (; len > 0; --len)
1256 dst[j++] = src[k];
1258 if (j >= dst_len)
1259 goto end;
1261 ++k;
1263 end:
1264 rc = j;
1267 else if (!is_himc_ime_unicode(data) && unicode)
1269 rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0);
1270 if (dst_len)
1272 int i, j = 0;
1274 if (rc < dst_len)
1275 dst_len = rc;
1276 for (i = 0; i < str_len; ++i)
1278 if (IsDBCSLeadByte(string.strA[i]))
1279 continue;
1281 dst[j++] = src[i];
1283 if (j >= dst_len)
1284 break;
1286 rc = j;
1289 else
1291 memcpy(dst, src, min(src_len, dst_len));
1292 rc = src_len;
1295 return rc;
1298 static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource,
1299 LPBYTE target, INT tlen, BOOL unicode )
1301 INT rc;
1303 if (is_himc_ime_unicode(data) && !unicode)
1305 if (tlen)
1307 int i;
1309 if (slen < tlen)
1310 tlen = slen;
1311 tlen /= sizeof (DWORD);
1312 for (i = 0; i < tlen; ++i)
1314 ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource,
1315 ((DWORD *)source)[i],
1316 NULL, 0,
1317 NULL, NULL);
1319 rc = sizeof (DWORD) * i;
1321 else
1322 rc = slen;
1324 else if (!is_himc_ime_unicode(data) && unicode)
1326 if (tlen)
1328 int i;
1330 if (slen < tlen)
1331 tlen = slen;
1332 tlen /= sizeof (DWORD);
1333 for (i = 0; i < tlen; ++i)
1335 ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource,
1336 ((DWORD *)source)[i],
1337 NULL, 0);
1339 rc = sizeof (DWORD) * i;
1341 else
1342 rc = slen;
1344 else
1346 memcpy( target, source, min(slen,tlen));
1347 rc = slen;
1350 return rc;
1353 static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode)
1355 int rc;
1357 if (is_himc_ime_unicode(data) && !unicode)
1359 rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL);
1361 else if (!is_himc_ime_unicode(data) && unicode)
1363 rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0);
1365 else
1366 rc = offset;
1368 return rc;
1371 static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf,
1372 DWORD dwBufLen, BOOL unicode)
1374 LONG rc = 0;
1375 InputContextData *data = get_imc_data(hIMC);
1376 LPCOMPOSITIONSTRING compstr;
1377 LPBYTE compdata;
1379 TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
1381 if (!data)
1382 return FALSE;
1384 if (!data->IMC.hCompStr)
1385 return FALSE;
1387 compdata = ImmLockIMCC(data->IMC.hCompStr);
1388 compstr = (LPCOMPOSITIONSTRING)compdata;
1390 switch (dwIndex)
1392 case GCS_RESULTSTR:
1393 TRACE("GCS_RESULTSTR\n");
1394 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode);
1395 break;
1396 case GCS_COMPSTR:
1397 TRACE("GCS_COMPSTR\n");
1398 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode);
1399 break;
1400 case GCS_COMPATTR:
1401 TRACE("GCS_COMPATTR\n");
1402 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen,
1403 compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen,
1404 lpBuf, dwBufLen, unicode);
1405 break;
1406 case GCS_COMPCLAUSE:
1407 TRACE("GCS_COMPCLAUSE\n");
1408 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen,
1409 compdata + compstr->dwCompStrOffset,
1410 lpBuf, dwBufLen, unicode);
1411 break;
1412 case GCS_RESULTCLAUSE:
1413 TRACE("GCS_RESULTCLAUSE\n");
1414 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen,
1415 compdata + compstr->dwResultStrOffset,
1416 lpBuf, dwBufLen, unicode);
1417 break;
1418 case GCS_RESULTREADSTR:
1419 TRACE("GCS_RESULTREADSTR\n");
1420 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode);
1421 break;
1422 case GCS_RESULTREADCLAUSE:
1423 TRACE("GCS_RESULTREADCLAUSE\n");
1424 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen,
1425 compdata + compstr->dwResultStrOffset,
1426 lpBuf, dwBufLen, unicode);
1427 break;
1428 case GCS_COMPREADSTR:
1429 TRACE("GCS_COMPREADSTR\n");
1430 rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode);
1431 break;
1432 case GCS_COMPREADATTR:
1433 TRACE("GCS_COMPREADATTR\n");
1434 rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen,
1435 compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen,
1436 lpBuf, dwBufLen, unicode);
1437 break;
1438 case GCS_COMPREADCLAUSE:
1439 TRACE("GCS_COMPREADCLAUSE\n");
1440 rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen,
1441 compdata + compstr->dwCompStrOffset,
1442 lpBuf, dwBufLen, unicode);
1443 break;
1444 case GCS_CURSORPOS:
1445 TRACE("GCS_CURSORPOS\n");
1446 rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode);
1447 break;
1448 case GCS_DELTASTART:
1449 TRACE("GCS_DELTASTART\n");
1450 rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode);
1451 break;
1452 default:
1453 FIXME("Unhandled index 0x%x\n",dwIndex);
1454 break;
1457 ImmUnlockIMCC(data->IMC.hCompStr);
1459 return rc;
1462 /***********************************************************************
1463 * ImmGetCompositionStringA (IMM32.@)
1465 LONG WINAPI ImmGetCompositionStringA(
1466 HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
1468 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE);
1472 /***********************************************************************
1473 * ImmGetCompositionStringW (IMM32.@)
1475 LONG WINAPI ImmGetCompositionStringW(
1476 HIMC hIMC, DWORD dwIndex,
1477 LPVOID lpBuf, DWORD dwBufLen)
1479 return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE);
1482 /***********************************************************************
1483 * ImmGetCompositionWindow (IMM32.@)
1485 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1487 InputContextData *data = get_imc_data(hIMC);
1489 TRACE("(%p, %p)\n", hIMC, lpCompForm);
1491 if (!data)
1492 return FALSE;
1494 *lpCompForm = data->IMC.cfCompForm;
1495 return TRUE;
1498 /***********************************************************************
1499 * ImmGetContext (IMM32.@)
1502 HIMC WINAPI ImmGetContext(HWND hWnd)
1504 HIMC rc;
1506 TRACE("%p\n", hWnd);
1508 if (!IsWindow(hWnd))
1510 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1511 return NULL;
1514 rc = GetPropW(hWnd,szwWineIMCProperty);
1515 if (rc == (HIMC)-1)
1516 rc = NULL;
1517 else if (rc == NULL)
1518 rc = get_default_context( hWnd );
1520 if (rc)
1522 InputContextData *data = rc;
1523 data->IMC.hWnd = hWnd;
1526 TRACE("returning %p\n", rc);
1528 return rc;
1531 /***********************************************************************
1532 * ImmGetConversionListA (IMM32.@)
1534 DWORD WINAPI ImmGetConversionListA(
1535 HKL hKL, HIMC hIMC,
1536 LPCSTR pSrc, LPCANDIDATELIST lpDst,
1537 DWORD dwBufLen, UINT uFlag)
1539 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1540 TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_a(pSrc), lpDst,
1541 dwBufLen, uFlag);
1542 if (immHkl->hIME && immHkl->pImeConversionList)
1544 if (!is_kbd_ime_unicode(immHkl))
1545 return immHkl->pImeConversionList(hIMC,(LPCWSTR)pSrc,lpDst,dwBufLen,uFlag);
1546 else
1548 LPCANDIDATELIST lpwDst;
1549 DWORD ret = 0, len;
1550 LPWSTR pwSrc = strdupAtoW(pSrc);
1552 len = immHkl->pImeConversionList(hIMC, pwSrc, NULL, 0, uFlag);
1553 lpwDst = HeapAlloc(GetProcessHeap(), 0, len);
1554 if ( lpwDst )
1556 immHkl->pImeConversionList(hIMC, pwSrc, lpwDst, len, uFlag);
1557 ret = convert_candidatelist_WtoA( lpwDst, lpDst, dwBufLen);
1558 HeapFree(GetProcessHeap(), 0, lpwDst);
1560 HeapFree(GetProcessHeap(), 0, pwSrc);
1562 return ret;
1565 else
1566 return 0;
1569 /***********************************************************************
1570 * ImmGetConversionListW (IMM32.@)
1572 DWORD WINAPI ImmGetConversionListW(
1573 HKL hKL, HIMC hIMC,
1574 LPCWSTR pSrc, LPCANDIDATELIST lpDst,
1575 DWORD dwBufLen, UINT uFlag)
1577 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1578 TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_w(pSrc), lpDst,
1579 dwBufLen, uFlag);
1580 if (immHkl->hIME && immHkl->pImeConversionList)
1582 if (is_kbd_ime_unicode(immHkl))
1583 return immHkl->pImeConversionList(hIMC,pSrc,lpDst,dwBufLen,uFlag);
1584 else
1586 LPCANDIDATELIST lpaDst;
1587 DWORD ret = 0, len;
1588 LPSTR paSrc = strdupWtoA(pSrc);
1590 len = immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, NULL, 0, uFlag);
1591 lpaDst = HeapAlloc(GetProcessHeap(), 0, len);
1592 if ( lpaDst )
1594 immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, lpaDst, len, uFlag);
1595 ret = convert_candidatelist_AtoW( lpaDst, lpDst, dwBufLen);
1596 HeapFree(GetProcessHeap(), 0, lpaDst);
1598 HeapFree(GetProcessHeap(), 0, paSrc);
1600 return ret;
1603 else
1604 return 0;
1607 /***********************************************************************
1608 * ImmGetConversionStatus (IMM32.@)
1610 BOOL WINAPI ImmGetConversionStatus(
1611 HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
1613 InputContextData *data = get_imc_data(hIMC);
1615 TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence);
1617 if (!data)
1618 return FALSE;
1620 if (lpfdwConversion)
1621 *lpfdwConversion = data->IMC.fdwConversion;
1622 if (lpfdwSentence)
1623 *lpfdwSentence = data->IMC.fdwSentence;
1625 return TRUE;
1628 static BOOL needs_ime_window(HWND hwnd)
1630 WCHAR classW[8];
1632 if (GetClassNameW(hwnd, classW, ARRAY_SIZE(classW)) && !lstrcmpW(classW, L"IME"))
1633 return FALSE;
1634 if (GetClassLongPtrW(hwnd, GCL_STYLE) & CS_IME) return FALSE;
1636 return TRUE;
1639 /***********************************************************************
1640 * __wine_register_window (IMM32.@)
1642 BOOL WINAPI __wine_register_window(HWND hwnd)
1644 HWND new = NULL;
1645 IMMThreadData *thread_data;
1646 TRACE("(%p)\n", hwnd);
1648 if (!needs_ime_window(hwnd))
1649 return FALSE;
1651 thread_data = IMM_GetThreadData(hwnd, 0);
1652 if (!thread_data)
1653 return FALSE;
1655 if (thread_data->disableIME || disable_ime)
1657 TRACE("IME for this thread is disabled\n");
1658 LeaveCriticalSection(&threaddata_cs);
1659 return FALSE;
1661 thread_data->windowRefs++;
1662 TRACE("windowRefs=%u, hwndDefault=%p\n",
1663 thread_data->windowRefs, thread_data->hwndDefault);
1665 /* Create default IME window */
1666 if (thread_data->windowRefs == 1)
1668 /* Do not create the window inside of a critical section */
1669 LeaveCriticalSection(&threaddata_cs);
1670 new = CreateWindowExW( 0, L"IME", L"Default IME",
1671 WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS,
1672 0, 0, 1, 1, 0, 0, 0, 0);
1673 /* thread_data is in the current thread so we can assume it's still valid */
1674 EnterCriticalSection(&threaddata_cs);
1675 /* See if anyone beat us */
1676 if (thread_data->hwndDefault == NULL)
1678 thread_data->hwndDefault = new;
1679 new = NULL;
1680 TRACE("Default is %p\n", thread_data->hwndDefault);
1684 LeaveCriticalSection(&threaddata_cs);
1686 /* Clean up an unused new window outside of the critical section */
1687 if (new != NULL)
1688 DestroyWindow(new);
1689 return TRUE;
1692 /***********************************************************************
1693 * __wine_unregister_window (IMM32.@)
1695 void WINAPI __wine_unregister_window(HWND hwnd)
1697 HWND to_destroy = 0;
1698 IMMThreadData *thread_data;
1699 TRACE("(%p)\n", hwnd);
1701 thread_data = IMM_GetThreadData(hwnd, 0);
1702 if (!thread_data) return;
1704 thread_data->windowRefs--;
1705 TRACE("windowRefs=%u, hwndDefault=%p\n",
1706 thread_data->windowRefs, thread_data->hwndDefault);
1708 /* Destroy default IME window */
1709 if (thread_data->windowRefs == 0 && thread_data->hwndDefault)
1711 to_destroy = thread_data->hwndDefault;
1712 thread_data->hwndDefault = NULL;
1714 LeaveCriticalSection(&threaddata_cs);
1716 if (to_destroy) DestroyWindow( to_destroy );
1719 /***********************************************************************
1720 * ImmGetDefaultIMEWnd (IMM32.@)
1722 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
1724 HWND ret;
1725 IMMThreadData* thread_data = IMM_GetThreadData(hWnd, 0);
1726 if (!thread_data)
1727 return NULL;
1728 ret = thread_data->hwndDefault;
1729 LeaveCriticalSection(&threaddata_cs);
1730 TRACE("Default is %p\n",ret);
1731 return ret;
1734 /***********************************************************************
1735 * ImmGetDescriptionA (IMM32.@)
1737 UINT WINAPI ImmGetDescriptionA(
1738 HKL hKL, LPSTR lpszDescription, UINT uBufLen)
1740 WCHAR *buf;
1741 DWORD len;
1743 TRACE("%p %p %d\n", hKL, lpszDescription, uBufLen);
1745 /* find out how many characters in the unicode buffer */
1746 len = ImmGetDescriptionW( hKL, NULL, 0 );
1747 if (!len)
1748 return 0;
1750 /* allocate a buffer of that size */
1751 buf = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR) );
1752 if( !buf )
1753 return 0;
1755 /* fetch the unicode buffer */
1756 len = ImmGetDescriptionW( hKL, buf, len + 1 );
1758 /* convert it back to ASCII */
1759 len = WideCharToMultiByte( CP_ACP, 0, buf, len + 1,
1760 lpszDescription, uBufLen, NULL, NULL );
1762 HeapFree( GetProcessHeap(), 0, buf );
1764 if (len == 0)
1765 return 0;
1767 return len - 1;
1770 /***********************************************************************
1771 * ImmGetDescriptionW (IMM32.@)
1773 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
1775 FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen);
1777 if (!hKL) return 0;
1778 if (!uBufLen) return lstrlenW(L"Wine XIM" );
1779 lstrcpynW( lpszDescription, L"Wine XIM", uBufLen );
1780 return lstrlenW( lpszDescription );
1783 /***********************************************************************
1784 * ImmGetGuideLineA (IMM32.@)
1786 DWORD WINAPI ImmGetGuideLineA(
1787 HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
1789 FIXME("(%p, %d, %s, %d): stub\n",
1790 hIMC, dwIndex, debugstr_a(lpBuf), dwBufLen
1792 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1793 return 0;
1796 /***********************************************************************
1797 * ImmGetGuideLineW (IMM32.@)
1799 DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
1801 FIXME("(%p, %d, %s, %d): stub\n",
1802 hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen
1804 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1805 return 0;
1808 /***********************************************************************
1809 * ImmGetIMEFileNameA (IMM32.@)
1811 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
1813 LPWSTR bufW = NULL;
1814 UINT wBufLen = uBufLen;
1815 UINT rc;
1817 if (uBufLen && lpszFileName)
1818 bufW = HeapAlloc(GetProcessHeap(),0,uBufLen * sizeof(WCHAR));
1819 else /* We need this to get the number of byte required */
1821 bufW = HeapAlloc(GetProcessHeap(),0,MAX_PATH * sizeof(WCHAR));
1822 wBufLen = MAX_PATH;
1825 rc = ImmGetIMEFileNameW(hKL,bufW,wBufLen);
1827 if (rc > 0)
1829 if (uBufLen && lpszFileName)
1830 rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, lpszFileName,
1831 uBufLen, NULL, NULL);
1832 else /* get the length */
1833 rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL,
1834 NULL);
1837 HeapFree(GetProcessHeap(),0,bufW);
1838 return rc;
1841 /***********************************************************************
1842 * ImmGetIMEFileNameW (IMM32.@)
1844 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
1846 HKEY hkey;
1847 DWORD length;
1848 DWORD rc;
1849 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
1851 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hKL );
1852 rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey);
1853 if (rc != ERROR_SUCCESS)
1855 SetLastError(rc);
1856 return 0;
1859 length = 0;
1860 rc = RegGetValueW(hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, NULL, &length);
1862 if (rc != ERROR_SUCCESS)
1864 RegCloseKey(hkey);
1865 SetLastError(rc);
1866 return 0;
1868 if (length > uBufLen * sizeof(WCHAR) || !lpszFileName)
1870 RegCloseKey(hkey);
1871 if (lpszFileName)
1873 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1874 return 0;
1876 else
1877 return length / sizeof(WCHAR);
1880 RegGetValueW(hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, lpszFileName, &length);
1882 RegCloseKey(hkey);
1884 return length / sizeof(WCHAR);
1887 /***********************************************************************
1888 * ImmGetOpenStatus (IMM32.@)
1890 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
1892 InputContextData *data = get_imc_data(hIMC);
1893 static int i;
1895 if (!data)
1896 return FALSE;
1898 TRACE("(%p): semi-stub\n", hIMC);
1900 if (!i++)
1901 FIXME("(%p): semi-stub\n", hIMC);
1903 return data->IMC.fOpen;
1906 /***********************************************************************
1907 * ImmGetProperty (IMM32.@)
1909 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
1911 DWORD rc = 0;
1912 ImmHkl *kbd;
1914 TRACE("(%p, %d)\n", hKL, fdwIndex);
1915 kbd = IMM_GetImmHkl(hKL);
1917 if (kbd && kbd->hIME)
1919 switch (fdwIndex)
1921 case IGP_PROPERTY: rc = kbd->imeInfo.fdwProperty; break;
1922 case IGP_CONVERSION: rc = kbd->imeInfo.fdwConversionCaps; break;
1923 case IGP_SENTENCE: rc = kbd->imeInfo.fdwSentenceCaps; break;
1924 case IGP_SETCOMPSTR: rc = kbd->imeInfo.fdwSCSCaps; break;
1925 case IGP_SELECT: rc = kbd->imeInfo.fdwSelectCaps; break;
1926 case IGP_GETIMEVERSION: rc = IMEVER_0400; break;
1927 case IGP_UI: rc = 0; break;
1928 default: rc = 0;
1931 return rc;
1934 /***********************************************************************
1935 * ImmGetRegisterWordStyleA (IMM32.@)
1937 UINT WINAPI ImmGetRegisterWordStyleA(
1938 HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
1940 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1941 TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
1942 if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
1944 if (!is_kbd_ime_unicode(immHkl))
1945 return immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)lpStyleBuf);
1946 else
1948 STYLEBUFW sbw;
1949 UINT rc;
1951 rc = immHkl->pImeGetRegisterWordStyle(nItem,&sbw);
1952 WideCharToMultiByte(CP_ACP, 0, sbw.szDescription, -1,
1953 lpStyleBuf->szDescription, 32, NULL, NULL);
1954 lpStyleBuf->dwStyle = sbw.dwStyle;
1955 return rc;
1958 else
1959 return 0;
1962 /***********************************************************************
1963 * ImmGetRegisterWordStyleW (IMM32.@)
1965 UINT WINAPI ImmGetRegisterWordStyleW(
1966 HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
1968 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
1969 TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf);
1970 if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle)
1972 if (is_kbd_ime_unicode(immHkl))
1973 return immHkl->pImeGetRegisterWordStyle(nItem,lpStyleBuf);
1974 else
1976 STYLEBUFA sba;
1977 UINT rc;
1979 rc = immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)&sba);
1980 MultiByteToWideChar(CP_ACP, 0, sba.szDescription, -1,
1981 lpStyleBuf->szDescription, 32);
1982 lpStyleBuf->dwStyle = sba.dwStyle;
1983 return rc;
1986 else
1987 return 0;
1990 /***********************************************************************
1991 * ImmGetStatusWindowPos (IMM32.@)
1993 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1995 InputContextData *data = get_imc_data(hIMC);
1997 TRACE("(%p, %p)\n", hIMC, lpptPos);
1999 if (!data || !lpptPos)
2000 return FALSE;
2002 *lpptPos = data->IMC.ptStatusWndPos;
2004 return TRUE;
2007 /***********************************************************************
2008 * ImmGetVirtualKey (IMM32.@)
2010 UINT WINAPI ImmGetVirtualKey(HWND hWnd)
2012 OSVERSIONINFOA version;
2013 InputContextData *data = ImmGetContext( hWnd );
2014 TRACE("%p\n", hWnd);
2016 if ( data )
2017 return data->lastVK;
2019 version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2020 GetVersionExA( &version );
2021 switch(version.dwPlatformId)
2023 case VER_PLATFORM_WIN32_WINDOWS:
2024 return VK_PROCESSKEY;
2025 case VER_PLATFORM_WIN32_NT:
2026 return 0;
2027 default:
2028 FIXME("%d not supported\n",version.dwPlatformId);
2029 return VK_PROCESSKEY;
2033 /***********************************************************************
2034 * ImmInstallIMEA (IMM32.@)
2036 HKL WINAPI ImmInstallIMEA(
2037 LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
2039 LPWSTR lpszwIMEFileName;
2040 LPWSTR lpszwLayoutText;
2041 HKL hkl;
2043 TRACE ("(%s, %s)\n", debugstr_a(lpszIMEFileName),
2044 debugstr_a(lpszLayoutText));
2046 lpszwIMEFileName = strdupAtoW(lpszIMEFileName);
2047 lpszwLayoutText = strdupAtoW(lpszLayoutText);
2049 hkl = ImmInstallIMEW(lpszwIMEFileName, lpszwLayoutText);
2051 HeapFree(GetProcessHeap(),0,lpszwIMEFileName);
2052 HeapFree(GetProcessHeap(),0,lpszwLayoutText);
2053 return hkl;
2056 /***********************************************************************
2057 * ImmInstallIMEW (IMM32.@)
2059 HKL WINAPI ImmInstallIMEW(
2060 LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
2062 INT lcid = GetUserDefaultLCID();
2063 INT count;
2064 HKL hkl;
2065 DWORD rc;
2066 HKEY hkey;
2067 WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8];
2069 TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName),
2070 debugstr_w(lpszLayoutText));
2072 /* Start with 2. e001 will be blank and so default to the wine internal IME */
2073 count = 2;
2075 while (count < 0xfff)
2077 DWORD disposition = 0;
2079 hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count );
2080 wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl);
2082 rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition);
2083 if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
2084 break;
2085 else if (rc == ERROR_SUCCESS)
2086 RegCloseKey(hkey);
2088 count++;
2091 if (count == 0xfff)
2093 WARN("Unable to find slot to install IME\n");
2094 return 0;
2097 if (rc == ERROR_SUCCESS)
2099 rc = RegSetValueExW(hkey, L"Ime File", 0, REG_SZ, (const BYTE*)lpszIMEFileName,
2100 (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR));
2101 if (rc == ERROR_SUCCESS)
2102 rc = RegSetValueExW(hkey, L"Layout Text", 0, REG_SZ, (const BYTE*)lpszLayoutText,
2103 (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR));
2104 RegCloseKey(hkey);
2105 return hkl;
2107 else
2109 WARN("Unable to set IME registry values\n");
2110 return 0;
2114 /***********************************************************************
2115 * ImmIsIME (IMM32.@)
2117 BOOL WINAPI ImmIsIME(HKL hKL)
2119 ImmHkl *ptr;
2120 TRACE("(%p):\n", hKL);
2121 ptr = IMM_GetImmHkl(hKL);
2122 return (ptr && ptr->hIME);
2125 /***********************************************************************
2126 * ImmIsUIMessageA (IMM32.@)
2128 BOOL WINAPI ImmIsUIMessageA(
2129 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2131 TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
2132 if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2133 (msg == WM_IME_SETCONTEXT) ||
2134 (msg == WM_IME_NOTIFY) ||
2135 (msg == WM_IME_COMPOSITIONFULL) ||
2136 (msg == WM_IME_SELECT) ||
2137 (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2139 if (hWndIME)
2140 SendMessageA(hWndIME, msg, wParam, lParam);
2142 return TRUE;
2144 return FALSE;
2147 /***********************************************************************
2148 * ImmIsUIMessageW (IMM32.@)
2150 BOOL WINAPI ImmIsUIMessageW(
2151 HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
2153 TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
2154 if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2155 (msg == WM_IME_SETCONTEXT) ||
2156 (msg == WM_IME_NOTIFY) ||
2157 (msg == WM_IME_COMPOSITIONFULL) ||
2158 (msg == WM_IME_SELECT) ||
2159 (msg == 0x287 /* FIXME: WM_IME_SYSTEM */))
2161 if (hWndIME)
2162 SendMessageW(hWndIME, msg, wParam, lParam);
2164 return TRUE;
2166 return FALSE;
2169 /***********************************************************************
2170 * ImmNotifyIME (IMM32.@)
2172 BOOL WINAPI ImmNotifyIME(
2173 HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
2175 InputContextData *data = get_imc_data(hIMC);
2177 TRACE("(%p, %d, %d, %d)\n",
2178 hIMC, dwAction, dwIndex, dwValue);
2180 if (hIMC == NULL)
2182 SetLastError(ERROR_SUCCESS);
2183 return FALSE;
2186 if (!data || ! data->immKbd->pNotifyIME)
2188 return FALSE;
2191 return data->immKbd->pNotifyIME(hIMC,dwAction,dwIndex,dwValue);
2194 /***********************************************************************
2195 * ImmRegisterWordA (IMM32.@)
2197 BOOL WINAPI ImmRegisterWordA(
2198 HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
2200 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2201 TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
2202 debugstr_a(lpszRegister));
2203 if (immHkl->hIME && immHkl->pImeRegisterWord)
2205 if (!is_kbd_ime_unicode(immHkl))
2206 return immHkl->pImeRegisterWord((LPCWSTR)lpszReading,dwStyle,
2207 (LPCWSTR)lpszRegister);
2208 else
2210 LPWSTR lpszwReading = strdupAtoW(lpszReading);
2211 LPWSTR lpszwRegister = strdupAtoW(lpszRegister);
2212 BOOL rc;
2214 rc = immHkl->pImeRegisterWord(lpszwReading,dwStyle,lpszwRegister);
2215 HeapFree(GetProcessHeap(),0,lpszwReading);
2216 HeapFree(GetProcessHeap(),0,lpszwRegister);
2217 return rc;
2220 else
2221 return FALSE;
2224 /***********************************************************************
2225 * ImmRegisterWordW (IMM32.@)
2227 BOOL WINAPI ImmRegisterWordW(
2228 HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
2230 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2231 TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
2232 debugstr_w(lpszRegister));
2233 if (immHkl->hIME && immHkl->pImeRegisterWord)
2235 if (is_kbd_ime_unicode(immHkl))
2236 return immHkl->pImeRegisterWord(lpszReading,dwStyle,lpszRegister);
2237 else
2239 LPSTR lpszaReading = strdupWtoA(lpszReading);
2240 LPSTR lpszaRegister = strdupWtoA(lpszRegister);
2241 BOOL rc;
2243 rc = immHkl->pImeRegisterWord((LPCWSTR)lpszaReading,dwStyle,
2244 (LPCWSTR)lpszaRegister);
2245 HeapFree(GetProcessHeap(),0,lpszaReading);
2246 HeapFree(GetProcessHeap(),0,lpszaRegister);
2247 return rc;
2250 else
2251 return FALSE;
2254 /***********************************************************************
2255 * ImmReleaseContext (IMM32.@)
2257 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
2259 static BOOL shown = FALSE;
2261 if (!shown) {
2262 FIXME("(%p, %p): stub\n", hWnd, hIMC);
2263 shown = TRUE;
2265 return TRUE;
2268 /***********************************************************************
2269 * ImmRequestMessageA(IMM32.@)
2271 LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam)
2273 InputContextData *data = get_imc_data(hIMC);
2275 TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
2277 if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
2279 SetLastError(ERROR_INVALID_HANDLE);
2280 return 0;
2283 /***********************************************************************
2284 * ImmRequestMessageW(IMM32.@)
2286 LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
2288 InputContextData *data = get_imc_data(hIMC);
2290 TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
2292 if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
2294 SetLastError(ERROR_INVALID_HANDLE);
2295 return 0;
2298 /***********************************************************************
2299 * ImmSetCandidateWindow (IMM32.@)
2301 BOOL WINAPI ImmSetCandidateWindow(
2302 HIMC hIMC, LPCANDIDATEFORM lpCandidate)
2304 InputContextData *data = get_imc_data(hIMC);
2306 TRACE("(%p, %p)\n", hIMC, lpCandidate);
2308 if (!data || !lpCandidate)
2309 return FALSE;
2311 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2312 return FALSE;
2314 TRACE("\t%x, %x, %s, %s\n",
2315 lpCandidate->dwIndex, lpCandidate->dwStyle,
2316 wine_dbgstr_point(&lpCandidate->ptCurrentPos),
2317 wine_dbgstr_rect(&lpCandidate->rcArea));
2319 if (lpCandidate->dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm))
2320 return FALSE;
2322 data->IMC.cfCandForm[lpCandidate->dwIndex] = *lpCandidate;
2323 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS);
2324 ImmInternalSendIMENotify(data, IMN_SETCANDIDATEPOS, 1 << lpCandidate->dwIndex);
2326 return TRUE;
2329 /***********************************************************************
2330 * ImmSetCompositionFontA (IMM32.@)
2332 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
2334 InputContextData *data = get_imc_data(hIMC);
2335 TRACE("(%p, %p)\n", hIMC, lplf);
2337 if (!data || !lplf)
2339 SetLastError(ERROR_INVALID_HANDLE);
2340 return FALSE;
2343 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2344 return FALSE;
2346 memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
2347 MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
2348 LF_FACESIZE);
2349 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
2350 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
2352 return TRUE;
2355 /***********************************************************************
2356 * ImmSetCompositionFontW (IMM32.@)
2358 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
2360 InputContextData *data = get_imc_data(hIMC);
2361 TRACE("(%p, %p)\n", hIMC, lplf);
2363 if (!data || !lplf)
2365 SetLastError(ERROR_INVALID_HANDLE);
2366 return FALSE;
2369 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2370 return FALSE;
2372 data->IMC.lfFont.W = *lplf;
2373 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT);
2374 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
2376 return TRUE;
2379 /***********************************************************************
2380 * ImmSetCompositionStringA (IMM32.@)
2382 BOOL WINAPI ImmSetCompositionStringA(
2383 HIMC hIMC, DWORD dwIndex,
2384 LPCVOID lpComp, DWORD dwCompLen,
2385 LPCVOID lpRead, DWORD dwReadLen)
2387 DWORD comp_len;
2388 DWORD read_len;
2389 WCHAR *CompBuffer = NULL;
2390 WCHAR *ReadBuffer = NULL;
2391 BOOL rc;
2392 InputContextData *data = get_imc_data(hIMC);
2394 TRACE("(%p, %d, %p, %d, %p, %d):\n",
2395 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2397 if (!data)
2398 return FALSE;
2400 if (!(dwIndex == SCS_SETSTR ||
2401 dwIndex == SCS_CHANGEATTR ||
2402 dwIndex == SCS_CHANGECLAUSE ||
2403 dwIndex == SCS_SETRECONVERTSTRING ||
2404 dwIndex == SCS_QUERYRECONVERTSTRING))
2405 return FALSE;
2407 if (!is_himc_ime_unicode(data))
2408 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
2409 dwCompLen, lpRead, dwReadLen);
2411 comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
2412 if (comp_len)
2414 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
2415 MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
2418 read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
2419 if (read_len)
2421 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
2422 MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
2425 rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
2426 ReadBuffer, read_len);
2428 HeapFree(GetProcessHeap(), 0, CompBuffer);
2429 HeapFree(GetProcessHeap(), 0, ReadBuffer);
2431 return rc;
2434 /***********************************************************************
2435 * ImmSetCompositionStringW (IMM32.@)
2437 BOOL WINAPI ImmSetCompositionStringW(
2438 HIMC hIMC, DWORD dwIndex,
2439 LPCVOID lpComp, DWORD dwCompLen,
2440 LPCVOID lpRead, DWORD dwReadLen)
2442 DWORD comp_len;
2443 DWORD read_len;
2444 CHAR *CompBuffer = NULL;
2445 CHAR *ReadBuffer = NULL;
2446 BOOL rc;
2447 InputContextData *data = get_imc_data(hIMC);
2449 TRACE("(%p, %d, %p, %d, %p, %d):\n",
2450 hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2452 if (!data)
2453 return FALSE;
2455 if (!(dwIndex == SCS_SETSTR ||
2456 dwIndex == SCS_CHANGEATTR ||
2457 dwIndex == SCS_CHANGECLAUSE ||
2458 dwIndex == SCS_SETRECONVERTSTRING ||
2459 dwIndex == SCS_QUERYRECONVERTSTRING))
2460 return FALSE;
2462 if (is_himc_ime_unicode(data))
2463 return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp,
2464 dwCompLen, lpRead, dwReadLen);
2466 comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL,
2467 NULL);
2468 if (comp_len)
2470 CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len);
2471 WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len,
2472 NULL, NULL);
2475 read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL,
2476 NULL);
2477 if (read_len)
2479 ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len);
2480 WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len,
2481 NULL, NULL);
2484 rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len,
2485 ReadBuffer, read_len);
2487 HeapFree(GetProcessHeap(), 0, CompBuffer);
2488 HeapFree(GetProcessHeap(), 0, ReadBuffer);
2490 return rc;
2493 /***********************************************************************
2494 * ImmSetCompositionWindow (IMM32.@)
2496 BOOL WINAPI ImmSetCompositionWindow(
2497 HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
2499 BOOL reshow = FALSE;
2500 InputContextData *data = get_imc_data(hIMC);
2502 TRACE("(%p, %p)\n", hIMC, lpCompForm);
2503 if (lpCompForm)
2504 TRACE("\t%x, %s, %s\n", lpCompForm->dwStyle,
2505 wine_dbgstr_point(&lpCompForm->ptCurrentPos),
2506 wine_dbgstr_rect(&lpCompForm->rcArea));
2508 if (!data)
2510 SetLastError(ERROR_INVALID_HANDLE);
2511 return FALSE;
2514 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2515 return FALSE;
2517 data->IMC.cfCompForm = *lpCompForm;
2519 if (IsWindowVisible(data->immKbd->UIWnd))
2521 reshow = TRUE;
2522 ShowWindow(data->immKbd->UIWnd,SW_HIDE);
2525 /* FIXME: this is a partial stub */
2527 if (reshow)
2528 ShowWindow(data->immKbd->UIWnd,SW_SHOWNOACTIVATE);
2530 ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0);
2531 return TRUE;
2534 /***********************************************************************
2535 * ImmSetConversionStatus (IMM32.@)
2537 BOOL WINAPI ImmSetConversionStatus(
2538 HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
2540 DWORD oldConversion, oldSentence;
2541 InputContextData *data = get_imc_data(hIMC);
2543 TRACE("%p %d %d\n", hIMC, fdwConversion, fdwSentence);
2545 if (!data)
2547 SetLastError(ERROR_INVALID_HANDLE);
2548 return FALSE;
2551 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2552 return FALSE;
2554 if ( fdwConversion != data->IMC.fdwConversion )
2556 oldConversion = data->IMC.fdwConversion;
2557 data->IMC.fdwConversion = fdwConversion;
2558 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE);
2559 ImmInternalSendIMENotify(data, IMN_SETCONVERSIONMODE, 0);
2561 if ( fdwSentence != data->IMC.fdwSentence )
2563 oldSentence = data->IMC.fdwSentence;
2564 data->IMC.fdwSentence = fdwSentence;
2565 ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE);
2566 ImmInternalSendIMENotify(data, IMN_SETSENTENCEMODE, 0);
2569 return TRUE;
2572 /***********************************************************************
2573 * ImmSetOpenStatus (IMM32.@)
2575 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
2577 InputContextData *data = get_imc_data(hIMC);
2579 TRACE("%p %d\n", hIMC, fOpen);
2581 if (!data)
2583 SetLastError(ERROR_INVALID_HANDLE);
2584 return FALSE;
2587 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2588 return FALSE;
2590 if (data->immKbd->UIWnd == NULL)
2592 /* create the ime window */
2593 data->immKbd->UIWnd = CreateWindowExW( WS_EX_TOOLWINDOW,
2594 data->immKbd->imeClassName, NULL, WS_POPUP, 0, 0, 1, 1, 0,
2595 0, data->immKbd->hIME, 0);
2596 SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
2598 else if (fOpen)
2599 SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data);
2601 if (!fOpen != !data->IMC.fOpen)
2603 data->IMC.fOpen = fOpen;
2604 ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS);
2605 ImmInternalSendIMENotify(data, IMN_SETOPENSTATUS, 0);
2608 return TRUE;
2611 /***********************************************************************
2612 * ImmSetStatusWindowPos (IMM32.@)
2614 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
2616 InputContextData *data = get_imc_data(hIMC);
2618 TRACE("(%p, %p)\n", hIMC, lpptPos);
2620 if (!data || !lpptPos)
2622 SetLastError(ERROR_INVALID_HANDLE);
2623 return FALSE;
2626 if (IMM_IsCrossThreadAccess(NULL, hIMC))
2627 return FALSE;
2629 TRACE("\t%s\n", wine_dbgstr_point(lpptPos));
2631 data->IMC.ptStatusWndPos = *lpptPos;
2632 ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS);
2633 ImmInternalSendIMENotify(data, IMN_SETSTATUSWINDOWPOS, 0);
2635 return TRUE;
2638 /***********************************************************************
2639 * ImmCreateSoftKeyboard(IMM32.@)
2641 HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y)
2643 FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y);
2644 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2645 return 0;
2648 /***********************************************************************
2649 * ImmDestroySoftKeyboard(IMM32.@)
2651 BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd)
2653 FIXME("(%p): stub\n", hSoftWnd);
2654 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2655 return FALSE;
2658 /***********************************************************************
2659 * ImmShowSoftKeyboard(IMM32.@)
2661 BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow)
2663 FIXME("(%p, %d): stub\n", hSoftWnd, nCmdShow);
2664 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2665 return FALSE;
2668 /***********************************************************************
2669 * ImmSimulateHotKey (IMM32.@)
2671 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
2673 FIXME("(%p, %d): stub\n", hWnd, dwHotKeyID);
2674 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2675 return FALSE;
2678 /***********************************************************************
2679 * ImmUnregisterWordA (IMM32.@)
2681 BOOL WINAPI ImmUnregisterWordA(
2682 HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
2684 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2685 TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle,
2686 debugstr_a(lpszUnregister));
2687 if (immHkl->hIME && immHkl->pImeUnregisterWord)
2689 if (!is_kbd_ime_unicode(immHkl))
2690 return immHkl->pImeUnregisterWord((LPCWSTR)lpszReading,dwStyle,
2691 (LPCWSTR)lpszUnregister);
2692 else
2694 LPWSTR lpszwReading = strdupAtoW(lpszReading);
2695 LPWSTR lpszwUnregister = strdupAtoW(lpszUnregister);
2696 BOOL rc;
2698 rc = immHkl->pImeUnregisterWord(lpszwReading,dwStyle,lpszwUnregister);
2699 HeapFree(GetProcessHeap(),0,lpszwReading);
2700 HeapFree(GetProcessHeap(),0,lpszwUnregister);
2701 return rc;
2704 else
2705 return FALSE;
2708 /***********************************************************************
2709 * ImmUnregisterWordW (IMM32.@)
2711 BOOL WINAPI ImmUnregisterWordW(
2712 HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
2714 ImmHkl *immHkl = IMM_GetImmHkl(hKL);
2715 TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle,
2716 debugstr_w(lpszUnregister));
2717 if (immHkl->hIME && immHkl->pImeUnregisterWord)
2719 if (is_kbd_ime_unicode(immHkl))
2720 return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister);
2721 else
2723 LPSTR lpszaReading = strdupWtoA(lpszReading);
2724 LPSTR lpszaUnregister = strdupWtoA(lpszUnregister);
2725 BOOL rc;
2727 rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle,
2728 (LPCWSTR)lpszaUnregister);
2729 HeapFree(GetProcessHeap(),0,lpszaReading);
2730 HeapFree(GetProcessHeap(),0,lpszaUnregister);
2731 return rc;
2734 else
2735 return FALSE;
2738 /***********************************************************************
2739 * ImmGetImeMenuItemsA (IMM32.@)
2741 DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2742 LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
2743 DWORD dwSize)
2745 InputContextData *data = get_imc_data(hIMC);
2746 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
2747 lpImeParentMenu, lpImeMenu, dwSize);
2749 if (!data)
2751 SetLastError(ERROR_INVALID_HANDLE);
2752 return 0;
2755 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2757 if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2758 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2759 (IMEMENUITEMINFOW*)lpImeParentMenu,
2760 (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
2761 else
2763 IMEMENUITEMINFOW lpImeParentMenuW;
2764 IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
2765 DWORD rc;
2767 if (lpImeParentMenu)
2768 parent = &lpImeParentMenuW;
2769 if (lpImeMenu)
2771 int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
2772 dwSize = count * sizeof(IMEMENUITEMINFOW);
2773 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
2775 else
2776 lpImeMenuW = NULL;
2778 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2779 parent, lpImeMenuW, dwSize);
2781 if (lpImeParentMenu)
2783 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
2784 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
2785 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
2786 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
2787 NULL, NULL);
2789 if (lpImeMenu && rc)
2791 unsigned int i;
2792 for (i = 0; i < rc; i++)
2794 memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
2795 lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
2796 WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
2797 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
2798 NULL, NULL);
2801 HeapFree(GetProcessHeap(),0,lpImeMenuW);
2802 return rc;
2805 else
2806 return 0;
2809 /***********************************************************************
2810 * ImmGetImeMenuItemsW (IMM32.@)
2812 DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2813 LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
2814 DWORD dwSize)
2816 InputContextData *data = get_imc_data(hIMC);
2817 TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
2818 lpImeParentMenu, lpImeMenu, dwSize);
2820 if (!data)
2822 SetLastError(ERROR_INVALID_HANDLE);
2823 return 0;
2826 if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2828 if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2829 return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2830 lpImeParentMenu, lpImeMenu, dwSize);
2831 else
2833 IMEMENUITEMINFOA lpImeParentMenuA;
2834 IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
2835 DWORD rc;
2837 if (lpImeParentMenu)
2838 parent = &lpImeParentMenuA;
2839 if (lpImeMenu)
2841 int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
2842 dwSize = count * sizeof(IMEMENUITEMINFOA);
2843 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
2845 else
2846 lpImeMenuA = NULL;
2848 rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2849 (IMEMENUITEMINFOW*)parent,
2850 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
2852 if (lpImeParentMenu)
2854 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
2855 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
2856 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
2857 -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
2859 if (lpImeMenu && rc)
2861 unsigned int i;
2862 for (i = 0; i < rc; i++)
2864 memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
2865 lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
2866 MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
2867 -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
2870 HeapFree(GetProcessHeap(),0,lpImeMenuA);
2871 return rc;
2874 else
2875 return 0;
2878 /***********************************************************************
2879 * ImmLockIMC(IMM32.@)
2881 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
2883 InputContextData *data = get_imc_data(hIMC);
2885 if (!data)
2886 return NULL;
2887 data->dwLock++;
2888 return &data->IMC;
2891 /***********************************************************************
2892 * ImmUnlockIMC(IMM32.@)
2894 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
2896 InputContextData *data = get_imc_data(hIMC);
2898 if (!data)
2899 return FALSE;
2900 if (data->dwLock)
2901 data->dwLock--;
2902 return TRUE;
2905 /***********************************************************************
2906 * ImmGetIMCLockCount(IMM32.@)
2908 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
2910 InputContextData *data = get_imc_data(hIMC);
2911 if (!data)
2912 return 0;
2913 return data->dwLock;
2916 /***********************************************************************
2917 * ImmCreateIMCC(IMM32.@)
2919 HIMCC WINAPI ImmCreateIMCC(DWORD size)
2921 return GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, size);
2924 /***********************************************************************
2925 * ImmDestroyIMCC(IMM32.@)
2927 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
2929 return GlobalFree(block);
2932 /***********************************************************************
2933 * ImmLockIMCC(IMM32.@)
2935 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
2937 return GlobalLock(imcc);
2940 /***********************************************************************
2941 * ImmUnlockIMCC(IMM32.@)
2943 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
2945 return GlobalUnlock(imcc);
2948 /***********************************************************************
2949 * ImmGetIMCCLockCount(IMM32.@)
2951 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
2953 return GlobalFlags(imcc) & GMEM_LOCKCOUNT;
2956 /***********************************************************************
2957 * ImmReSizeIMCC(IMM32.@)
2959 HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
2961 return GlobalReAlloc(imcc, size, GMEM_ZEROINIT | GMEM_MOVEABLE);
2964 /***********************************************************************
2965 * ImmGetIMCCSize(IMM32.@)
2967 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
2969 return GlobalSize(imcc);
2972 /***********************************************************************
2973 * ImmGenerateMessage(IMM32.@)
2975 BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
2977 InputContextData *data = get_imc_data(hIMC);
2979 if (!data)
2981 SetLastError(ERROR_INVALID_HANDLE);
2982 return FALSE;
2985 TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf);
2986 if (data->IMC.dwNumMsgBuf > 0)
2988 LPTRANSMSG lpTransMsg;
2989 HIMCC hMsgBuf;
2990 DWORD i, dwNumMsgBuf;
2992 /* We are going to detach our hMsgBuff so that if processing messages
2993 generates new messages they go into a new buffer */
2994 hMsgBuf = data->IMC.hMsgBuf;
2995 dwNumMsgBuf = data->IMC.dwNumMsgBuf;
2997 data->IMC.hMsgBuf = ImmCreateIMCC(0);
2998 data->IMC.dwNumMsgBuf = 0;
3000 lpTransMsg = ImmLockIMCC(hMsgBuf);
3001 for (i = 0; i < dwNumMsgBuf; i++)
3002 ImmInternalSendIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
3004 ImmUnlockIMCC(hMsgBuf);
3005 ImmDestroyIMCC(hMsgBuf);
3008 return TRUE;
3011 /***********************************************************************
3012 * ImmTranslateMessage(IMM32.@)
3013 * ( Undocumented, call internally and from user32.dll )
3015 BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData)
3017 InputContextData *data;
3018 HIMC imc = ImmGetContext(hwnd);
3019 BYTE state[256];
3020 UINT scancode;
3021 LPVOID list = 0;
3022 UINT msg_count;
3023 UINT uVirtKey;
3024 static const DWORD list_count = 10;
3026 TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData);
3028 if (imc)
3029 data = imc;
3030 else
3031 return FALSE;
3033 if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx || data->lastVK == VK_PROCESSKEY)
3034 return FALSE;
3036 GetKeyboardState(state);
3037 scancode = lKeyData >> 0x10 & 0xff;
3039 list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD));
3040 ((DWORD*)list)[0] = list_count;
3042 if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST)
3044 WCHAR chr;
3046 if (!is_himc_ime_unicode(data))
3047 ToAscii(data->lastVK, scancode, state, &chr, 0);
3048 else
3049 ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0));
3050 uVirtKey = MAKELONG(data->lastVK,chr);
3052 else
3053 uVirtKey = data->lastVK;
3055 msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc);
3056 TRACE("%i messages generated\n",msg_count);
3057 if (msg_count && msg_count <= list_count)
3059 UINT i;
3060 LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD));
3062 for (i = 0; i < msg_count; i++)
3063 ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam);
3065 else if (msg_count > list_count)
3066 ImmGenerateMessage(imc);
3068 HeapFree(GetProcessHeap(),0,list);
3070 data->lastVK = VK_PROCESSKEY;
3072 return (msg_count > 0);
3075 /***********************************************************************
3076 * ImmProcessKey(IMM32.@)
3077 * ( Undocumented, called from user32.dll )
3079 BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown)
3081 InputContextData *data;
3082 HIMC imc = ImmGetContext(hwnd);
3083 BYTE state[256];
3085 TRACE("%p %p %x %x %x\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown);
3087 if (imc)
3088 data = imc;
3089 else
3090 return FALSE;
3092 /* Make sure we are inputting to the correct keyboard */
3093 if (data->immKbd->hkl != hKL)
3095 ImmHkl *new_hkl = IMM_GetImmHkl(hKL);
3096 if (new_hkl)
3098 data->immKbd->pImeSelect(imc, FALSE);
3099 data->immKbd->uSelected--;
3100 data->immKbd = new_hkl;
3101 data->immKbd->pImeSelect(imc, TRUE);
3102 data->immKbd->uSelected++;
3104 else
3105 return FALSE;
3108 if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey)
3109 return FALSE;
3111 GetKeyboardState(state);
3112 if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state))
3114 data->lastVK = vKey;
3115 return TRUE;
3118 data->lastVK = VK_PROCESSKEY;
3119 return FALSE;
3122 /***********************************************************************
3123 * ImmDisableTextFrameService(IMM32.@)
3125 BOOL WINAPI ImmDisableTextFrameService(DWORD idThread)
3127 FIXME("Stub\n");
3128 return FALSE;
3131 /***********************************************************************
3132 * ImmEnumInputContext(IMM32.@)
3135 BOOL WINAPI ImmEnumInputContext(DWORD idThread, IMCENUMPROC lpfn, LPARAM lParam)
3137 FIXME("Stub\n");
3138 return FALSE;
3141 /***********************************************************************
3142 * ImmGetHotKey(IMM32.@)
3145 BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL hkl)
3147 FIXME("%x, %p, %p, %p: stub\n", hotkey, modifiers, key, hkl);
3148 return FALSE;
3151 /***********************************************************************
3152 * ImmDisableLegacyIME(IMM32.@)
3154 BOOL WINAPI ImmDisableLegacyIME(void)
3156 FIXME("stub\n");
3157 return TRUE;