imm32: Implement ImmGetImeMenuItems using loaded IME.
[wine] / dlls / imm32 / imm.c
1 /*
2  * IMM32 library
3  *
4  * Copyright 1998 Patrik Stridvall
5  * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include <stdarg.h>
23 #include <stdio.h>
24
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"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(imm);
38
39 #define FROM_IME 0xcafe1337
40
41 static void (*pX11DRV_ForceXIMReset)(HWND);
42
43 typedef struct tagIMCCInternal
44 {
45     DWORD dwLock;
46     DWORD dwSize;
47 } IMCCInternal;
48
49 #define MAKE_FUNCPTR(f) typeof(f) * p##f
50 typedef struct _tagImmHkl{
51     struct list entry;
52     HKL         hkl;
53     HMODULE     hIME;
54     IMEINFO     imeInfo;
55     WCHAR       imeClassName[17]; /* 16 character max */
56     ULONG       uSelected;
57
58     /* Function Pointers */
59     MAKE_FUNCPTR(ImeInquire);
60     MAKE_FUNCPTR(ImeConfigure);
61     MAKE_FUNCPTR(ImeDestroy);
62     MAKE_FUNCPTR(ImeEscape);
63     MAKE_FUNCPTR(ImeSelect);
64     MAKE_FUNCPTR(ImeSetActiveContext);
65     MAKE_FUNCPTR(ImeToAsciiEx);
66     MAKE_FUNCPTR(NotifyIME);
67     MAKE_FUNCPTR(ImeRegisterWord);
68     MAKE_FUNCPTR(ImeUnregisterWord);
69     MAKE_FUNCPTR(ImeEnumRegisterWord);
70     MAKE_FUNCPTR(ImeSetCompositionString);
71     MAKE_FUNCPTR(ImeConversionList);
72     MAKE_FUNCPTR(ImeProcessKey);
73     MAKE_FUNCPTR(ImeGetRegisterWordStyle);
74     MAKE_FUNCPTR(ImeGetImeMenuItems);
75 } ImmHkl;
76 #undef MAKE_FUNCPTR
77
78 typedef struct tagInputContextData
79 {
80         BOOL            bInternalState;
81         BOOL            bRead;
82         BOOL            bInComposition;
83         HFONT           textfont;
84
85         DWORD           dwLock;
86         INPUTCONTEXT    IMC;
87
88         ImmHkl          *immKbd;
89 } InputContextData;
90
91 typedef struct _tagTRANSMSG {
92     UINT message;
93     WPARAM wParam;
94     LPARAM lParam;
95 } TRANSMSG, *LPTRANSMSG;
96
97 static InputContextData *root_context = NULL;
98 static HWND hwndDefault = NULL;
99 static HANDLE hImeInst;
100 static const WCHAR WC_IMECLASSNAME[] = {'I','M','E',0};
101 static ATOM atIMEClass = 0;
102
103 static struct list ImmHklList = LIST_INIT(ImmHklList);
104
105 /* MSIME messages */
106 static UINT WM_MSIME_SERVICE;
107 static UINT WM_MSIME_RECONVERTOPTIONS;
108 static UINT WM_MSIME_MOUSE;
109 static UINT WM_MSIME_RECONVERTREQUEST;
110 static UINT WM_MSIME_RECONVERT;
111 static UINT WM_MSIME_QUERYPOSITION;
112 static UINT WM_MSIME_DOCUMENTFEED;
113
114 static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0};
115 /*
116  * prototypes
117  */
118 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
119                                           LPARAM lParam);
120 static void UpdateDataInDefaultIMEWindow(HWND hwnd, BOOL showable);
121 static void ImmInternalPostIMEMessage(InputContextData*, UINT, WPARAM, LPARAM);
122 static void ImmInternalSetOpenStatus(BOOL fOpen);
123 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len);
124
125 #define is_himc_ime_unicode(p)  (p->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE)
126 #define is_kbd_ime_unicode(p)  (p->imeInfo.fdwProperty & IME_PROP_UNICODE)
127
128 static inline WCHAR *strdupAtoW( const char *str )
129 {
130     WCHAR *ret = NULL;
131     if (str)
132     {
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 );
136     }
137     return ret;
138 }
139
140 static inline CHAR *strdupWtoA( const WCHAR *str )
141 {
142     CHAR *ret = NULL;
143     if (str)
144     {
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 );
148     }
149     return ret;
150 }
151
152 static HMODULE LoadDefaultWineIME(void)
153 {
154     char buffer[MAX_PATH], libname[32], *name, *next;
155     HMODULE module = 0;
156     HKEY hkey;
157
158     TRACE("Attempting to fall back to wine default IME\n");
159
160     strcpy( buffer, "x11" );  /* default value */
161     /* @@ Wine registry key: HKCU\Software\Wine\Drivers */
162     if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Drivers", &hkey ))
163     {
164         DWORD type, count = sizeof(buffer);
165         RegQueryValueExA( hkey, "Ime", 0, &type, (LPBYTE) buffer, &count );
166         RegCloseKey( hkey );
167     }
168
169     name = buffer;
170     while (name)
171     {
172         next = strchr( name, ',' );
173         if (next) *next++ = 0;
174
175         snprintf( libname, sizeof(libname), "wine%s.drv", name );
176         if ((module = LoadLibraryA( libname )) != 0) break;
177         name = next;
178     }
179
180     return module;
181 }
182
183 /* ImmHkl loading and freeing */
184 #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);}
185 static ImmHkl *IMM_GetImmHkl(HKL hkl)
186 {
187     ImmHkl *ptr;
188     WCHAR filename[MAX_PATH];
189
190     TRACE("Seeking ime for keyboard 0x%x\n",(unsigned)hkl);
191
192     LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry)
193     {
194         if (ptr->hkl == hkl)
195             return ptr;
196     }
197     /* not found... create it */
198
199     ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl));
200
201     ptr->hkl = hkl;
202     if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename);
203     if (!ptr->hIME)
204         ptr->hIME = LoadDefaultWineIME();
205     if (ptr->hIME)
206     {
207         LOAD_FUNCPTR(ImeInquire);
208         if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL))
209         {
210             FreeLibrary(ptr->hIME);
211             ptr->hIME = NULL;
212         }
213         else
214         {
215             LOAD_FUNCPTR(ImeDestroy);
216             LOAD_FUNCPTR(ImeSelect);
217             if (!ptr->pImeSelect || !ptr->pImeDestroy)
218             {
219                 FreeLibrary(ptr->hIME);
220                 ptr->hIME = NULL;
221             }
222             else
223             {
224                 LOAD_FUNCPTR(ImeConfigure);
225                 LOAD_FUNCPTR(ImeEscape);
226                 LOAD_FUNCPTR(ImeSetActiveContext);
227                 LOAD_FUNCPTR(ImeToAsciiEx);
228                 LOAD_FUNCPTR(NotifyIME);
229                 LOAD_FUNCPTR(ImeRegisterWord);
230                 LOAD_FUNCPTR(ImeUnregisterWord);
231                 LOAD_FUNCPTR(ImeEnumRegisterWord);
232                 LOAD_FUNCPTR(ImeSetCompositionString);
233                 LOAD_FUNCPTR(ImeConversionList);
234                 LOAD_FUNCPTR(ImeProcessKey);
235                 LOAD_FUNCPTR(ImeGetRegisterWordStyle);
236                 LOAD_FUNCPTR(ImeGetImeMenuItems);
237                 /* make sure our classname is WCHAR */
238                 if (!is_kbd_ime_unicode(ptr))
239                 {
240                     WCHAR bufW[17];
241                     MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName,
242                                         -1, bufW, 17);
243                     lstrcpyW(ptr->imeClassName, bufW);
244                 }
245             }
246         }
247     }
248     list_add_head(&ImmHklList,&ptr->entry);
249
250     return ptr;
251 }
252 #undef LOAD_FUNCPTR
253
254 static void IMM_FreeAllImmHkl(void)
255 {
256     ImmHkl *ptr,*cursor2;
257
258     LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &ImmHklList, ImmHkl, entry)
259     {
260         list_remove(&ptr->entry);
261         if (ptr->hIME)
262         {
263             ptr->pImeDestroy(1);
264             FreeLibrary(ptr->hIME);
265         }
266         HeapFree(GetProcessHeap(),0,ptr);
267     }
268 }
269
270 static VOID IMM_PostResult(InputContextData *data)
271 {
272     unsigned int i;
273     LPCOMPOSITIONSTRING compstr;
274     LPBYTE compdata;
275     LPWSTR ResultStr;
276     HIMCC newCompStr;
277
278     TRACE("Posting result as IME_CHAR\n");
279     compdata = ImmLockIMCC(root_context->IMC.hCompStr);
280     compstr = (LPCOMPOSITIONSTRING)compdata;
281     ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
282
283     for (i = 0; i < compstr->dwResultStrLen; i++)
284         ImmInternalPostIMEMessage (root_context, WM_IME_CHAR, ResultStr[i], 1);
285
286     ImmUnlockIMCC(root_context->IMC.hCompStr);
287
288     /* clear the buffer */
289     newCompStr = updateResultStr(root_context->IMC.hCompStr, NULL, 0);
290     ImmDestroyIMCC(root_context->IMC.hCompStr);
291     root_context->IMC.hCompStr = newCompStr;
292 }
293
294 static void IMM_Register(void)
295 {
296     WNDCLASSW wndClass;
297     ZeroMemory(&wndClass, sizeof(WNDCLASSW));
298     wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW;
299     wndClass.lpfnWndProc = (WNDPROC) IME_WindowProc;
300     wndClass.cbClsExtra = 0;
301     wndClass.cbWndExtra = 0;
302     wndClass.hInstance = hImeInst;
303     wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
304     wndClass.hIcon = NULL;
305     wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1);
306     wndClass.lpszMenuName   = 0;
307     wndClass.lpszClassName = WC_IMECLASSNAME;
308     atIMEClass = RegisterClassW(&wndClass);
309 }
310
311 static void IMM_Unregister(void)
312 {
313     if (atIMEClass) {
314         UnregisterClassW(WC_IMECLASSNAME, NULL);
315     }
316 }
317
318 static void IMM_RegisterMessages(void)
319 {
320     WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
321     WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions");
322     WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
323     WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
324     WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
325     WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
326     WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
327 }
328
329
330 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved)
331 {
332     HMODULE x11drv;
333
334     TRACE("%p, %x, %p\n",hInstDLL,fdwReason,lpReserved);
335     switch (fdwReason)
336     {
337         case DLL_PROCESS_ATTACH:
338             DisableThreadLibraryCalls(hInstDLL);
339             hImeInst = hInstDLL;
340             IMM_RegisterMessages();
341             x11drv = GetModuleHandleA("winex11.drv");
342             if (x11drv) pX11DRV_ForceXIMReset = (void *)GetProcAddress( x11drv, "ForceXIMReset");
343             break;
344         case DLL_PROCESS_DETACH:
345             if (hwndDefault)
346             {
347                 DestroyWindow(hwndDefault);
348                 hwndDefault = 0;
349             }
350             IMM_Unregister();
351             IMM_FreeAllImmHkl();
352             break;
353     }
354     return TRUE;
355 }
356
357 /* for posting messages as the IME */
358 static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam)
359 {
360     HWND target = GetFocus();
361     if (!target)
362        PostMessageW(data->IMC.hWnd,msg,wParam,lParam);
363     else
364        PostMessageW(target, msg, wParam, lParam);
365 }
366
367 static LRESULT ImmInternalSendIMENotify(InputContextData *data, WPARAM notify, LPARAM lParam)
368 {
369     HWND target;
370
371     target = data->IMC.hWnd;
372     if (!target) target = GetFocus();
373
374     if (target)
375        return SendMessageW(target, WM_IME_NOTIFY, notify, lParam);
376
377     return 0;
378 }
379
380 static HIMCC ImmCreateBlankCompStr(void)
381 {
382     HIMCC rc;
383     LPCOMPOSITIONSTRING ptr;
384     rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING));
385     ptr = (LPCOMPOSITIONSTRING)ImmLockIMCC(rc);
386     memset(ptr,0,sizeof(COMPOSITIONSTRING));
387     ptr->dwSize = sizeof(COMPOSITIONSTRING);
388     ImmUnlockIMCC(rc);
389     return rc;
390 }
391
392 static void ImmInternalSetOpenStatus(BOOL fOpen)
393 {
394     TRACE("Setting internal state to %s\n",(fOpen)?"OPEN":"CLOSED");
395
396     if (root_context->IMC.fOpen && fOpen == FALSE)
397     {
398         ShowWindow(hwndDefault,SW_HIDE);
399         ImmDestroyIMCC(root_context->IMC.hCompStr);
400         root_context->IMC.hCompStr = ImmCreateBlankCompStr();
401     }
402
403     root_context->IMC.fOpen = fOpen;
404     root_context->bInternalState = fOpen;
405
406     ImmInternalSendIMENotify(root_context, IMN_SETOPENSTATUS, 0);
407 }
408
409 static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset,
410                        LPBYTE target, LPBYTE source, DWORD* lenParam,
411                        DWORD* offsetParam, BOOL wchars )
412 {
413      if (origLen > 0 && origOffset > 0)
414      {
415         int truelen = origLen;
416         if (wchars)
417             truelen *= sizeof(WCHAR);
418
419         memcpy(&target[currentOffset], &source[origOffset], truelen);
420
421         *lenParam = origLen;
422         *offsetParam = currentOffset;
423         currentOffset += truelen;
424      }
425      return currentOffset;
426 }
427
428 static HIMCC updateCompStr(HIMCC old, LPWSTR compstr, DWORD len)
429 {
430     /* we need to make sure the CompStr, CompClaus and CompAttr fields are all
431      * set and correct */
432     int needed_size;
433     HIMCC   rc;
434     LPBYTE newdata = NULL;
435     LPBYTE olddata = NULL;
436     LPCOMPOSITIONSTRING new_one;
437     LPCOMPOSITIONSTRING lpcs = NULL;
438     INT current_offset = 0;
439
440     TRACE("%s, %i\n",debugstr_wn(compstr,len),len);
441
442     if (old == NULL && compstr == NULL && len == 0)
443         return NULL;
444
445     if (old != NULL)
446     {
447         olddata = ImmLockIMCC(old);
448         lpcs = (LPCOMPOSITIONSTRING)olddata;
449     }
450
451     needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
452                   len + sizeof(DWORD) * 2;
453
454     if (lpcs != NULL)
455     {
456         needed_size += lpcs->dwCompReadAttrLen;
457         needed_size += lpcs->dwCompReadClauseLen;
458         needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD);
459         needed_size += lpcs->dwResultReadClauseLen;
460         needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD);
461         needed_size += lpcs->dwResultClauseLen;
462         needed_size += lpcs->dwResultStrLen * sizeof(DWORD);
463         needed_size += lpcs->dwPrivateSize;
464     }
465     rc = ImmCreateIMCC(needed_size);
466     newdata = ImmLockIMCC(rc);
467     new_one = (LPCOMPOSITIONSTRING)newdata;
468
469     new_one->dwSize = needed_size;
470     current_offset = sizeof(COMPOSITIONSTRING);
471     if (lpcs != NULL)
472     {
473         current_offset = updateField(lpcs->dwCompReadAttrLen,
474                                      lpcs->dwCompReadAttrOffset,
475                                      current_offset, newdata, olddata,
476                                      &new_one->dwCompReadAttrLen,
477                                      &new_one->dwCompReadAttrOffset, FALSE);
478
479         current_offset = updateField(lpcs->dwCompReadClauseLen,
480                                      lpcs->dwCompReadClauseOffset,
481                                      current_offset, newdata, olddata,
482                                      &new_one->dwCompReadClauseLen,
483                                      &new_one->dwCompReadClauseOffset, FALSE);
484
485         current_offset = updateField(lpcs->dwCompReadStrLen,
486                                      lpcs->dwCompReadStrOffset,
487                                      current_offset, newdata, olddata,
488                                      &new_one->dwCompReadStrLen,
489                                      &new_one->dwCompReadStrOffset, TRUE);
490
491         /* new CompAttr, CompClause, CompStr, dwCursorPos */
492         new_one->dwDeltaStart = 0;
493
494         current_offset = updateField(lpcs->dwResultReadClauseLen,
495                                      lpcs->dwResultReadClauseOffset,
496                                      current_offset, newdata, olddata,
497                                      &new_one->dwResultReadClauseLen,
498                                      &new_one->dwResultReadClauseOffset, FALSE);
499
500         current_offset = updateField(lpcs->dwResultReadStrLen,
501                                      lpcs->dwResultReadStrOffset,
502                                      current_offset, newdata, olddata,
503                                      &new_one->dwResultReadStrLen,
504                                      &new_one->dwResultReadStrOffset, TRUE);
505
506         current_offset = updateField(lpcs->dwResultClauseLen,
507                                      lpcs->dwResultClauseOffset,
508                                      current_offset, newdata, olddata,
509                                      &new_one->dwResultClauseLen,
510                                      &new_one->dwResultClauseOffset, FALSE);
511
512         current_offset = updateField(lpcs->dwResultStrLen,
513                                      lpcs->dwResultStrOffset,
514                                      current_offset, newdata, olddata,
515                                      &new_one->dwResultStrLen,
516                                      &new_one->dwResultStrOffset, TRUE);
517
518         current_offset = updateField(lpcs->dwPrivateSize,
519                                      lpcs->dwPrivateOffset,
520                                      current_offset, newdata, olddata,
521                                      &new_one->dwPrivateSize,
522                                      &new_one->dwPrivateOffset, FALSE);
523     }
524
525     /* set new data */
526     /* CompAttr */
527     new_one->dwCompAttrLen = len;
528     if (len > 0)
529     {
530         new_one->dwCompAttrOffset = current_offset;
531         memset(&newdata[current_offset],ATTR_INPUT,len);
532         current_offset += len;
533     }
534
535     /* CompClause */
536     if (len > 0)
537     {
538         new_one->dwCompClauseLen = sizeof(DWORD) * 2;
539         new_one->dwCompClauseOffset = current_offset;
540         *(DWORD*)(&newdata[current_offset]) = 0;
541         current_offset += sizeof(DWORD);
542         *(DWORD*)(&newdata[current_offset]) = len;
543         current_offset += sizeof(DWORD);
544     }
545
546     /* CompStr */
547     new_one->dwCompStrLen = len;
548     if (len > 0)
549     {
550         new_one->dwCompStrOffset = current_offset;
551         memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR));
552     }
553
554     /* CursorPos */
555     new_one->dwCursorPos = len;
556
557     ImmUnlockIMCC(rc);
558     if (lpcs)
559         ImmUnlockIMCC(old);
560
561     return rc;
562 }
563
564 static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len)
565 {
566     /* we need to make sure the ResultStr and ResultClause fields are all
567      * set and correct */
568     int needed_size;
569     HIMCC   rc;
570     LPBYTE newdata = NULL;
571     LPBYTE olddata = NULL;
572     LPCOMPOSITIONSTRING new_one;
573     LPCOMPOSITIONSTRING lpcs = NULL;
574     INT current_offset = 0;
575
576     TRACE("%s, %i\n",debugstr_wn(resultstr,len),len);
577
578     if (old == NULL && resultstr == NULL && len == 0)
579         return NULL;
580
581     if (old != NULL)
582     {
583         olddata = ImmLockIMCC(old);
584         lpcs = (LPCOMPOSITIONSTRING)olddata;
585     }
586
587     needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) +
588                   sizeof(DWORD) * 2;
589
590     if (lpcs != NULL)
591     {
592         needed_size += lpcs->dwCompReadAttrLen;
593         needed_size += lpcs->dwCompReadClauseLen;
594         needed_size += lpcs->dwCompReadStrLen * sizeof(DWORD);
595         needed_size += lpcs->dwCompAttrLen;
596         needed_size += lpcs->dwCompClauseLen;
597         needed_size += lpcs->dwCompStrLen * sizeof(DWORD);
598         needed_size += lpcs->dwResultReadClauseLen;
599         needed_size += lpcs->dwResultReadStrLen * sizeof(DWORD);
600         needed_size += lpcs->dwPrivateSize;
601     }
602     rc = ImmCreateIMCC(needed_size);
603     newdata = ImmLockIMCC(rc);
604     new_one = (LPCOMPOSITIONSTRING)newdata;
605
606     new_one->dwSize = needed_size;
607     current_offset = sizeof(COMPOSITIONSTRING);
608     if (lpcs != NULL)
609     {
610         current_offset = updateField(lpcs->dwCompReadAttrLen,
611                                      lpcs->dwCompReadAttrOffset,
612                                      current_offset, newdata, olddata,
613                                      &new_one->dwCompReadAttrLen,
614                                      &new_one->dwCompReadAttrOffset, FALSE);
615
616         current_offset = updateField(lpcs->dwCompReadClauseLen,
617                                      lpcs->dwCompReadClauseOffset,
618                                      current_offset, newdata, olddata,
619                                      &new_one->dwCompReadClauseLen,
620                                      &new_one->dwCompReadClauseOffset, FALSE);
621
622         current_offset = updateField(lpcs->dwCompReadStrLen,
623                                      lpcs->dwCompReadStrOffset,
624                                      current_offset, newdata, olddata,
625                                      &new_one->dwCompReadStrLen,
626                                      &new_one->dwCompReadStrOffset, TRUE);
627
628         current_offset = updateField(lpcs->dwCompAttrLen,
629                                      lpcs->dwCompAttrOffset,
630                                      current_offset, newdata, olddata,
631                                      &new_one->dwCompAttrLen,
632                                      &new_one->dwCompAttrOffset, FALSE);
633
634         current_offset = updateField(lpcs->dwCompClauseLen,
635                                      lpcs->dwCompClauseOffset,
636                                      current_offset, newdata, olddata,
637                                      &new_one->dwCompClauseLen,
638                                      &new_one->dwCompClauseOffset, FALSE);
639
640         current_offset = updateField(lpcs->dwCompStrLen,
641                                      lpcs->dwCompStrOffset,
642                                      current_offset, newdata, olddata,
643                                      &new_one->dwCompStrLen,
644                                      &new_one->dwCompStrOffset, TRUE);
645
646         new_one->dwCursorPos = lpcs->dwCursorPos;
647         new_one->dwDeltaStart = 0;
648
649         current_offset = updateField(lpcs->dwResultReadClauseLen,
650                                      lpcs->dwResultReadClauseOffset,
651                                      current_offset, newdata, olddata,
652                                      &new_one->dwResultReadClauseLen,
653                                      &new_one->dwResultReadClauseOffset, FALSE);
654
655         current_offset = updateField(lpcs->dwResultReadStrLen,
656                                      lpcs->dwResultReadStrOffset,
657                                      current_offset, newdata, olddata,
658                                      &new_one->dwResultReadStrLen,
659                                      &new_one->dwResultReadStrOffset, TRUE);
660
661         /* new ResultClause , ResultStr */
662
663         current_offset = updateField(lpcs->dwPrivateSize,
664                                      lpcs->dwPrivateOffset,
665                                      current_offset, newdata, olddata,
666                                      &new_one->dwPrivateSize,
667                                      &new_one->dwPrivateOffset, FALSE);
668     }
669
670     /* set new data */
671     /* ResultClause */
672     if (len > 0)
673     {
674         new_one->dwResultClauseLen = sizeof(DWORD) * 2;
675         new_one->dwResultClauseOffset = current_offset;
676         *(DWORD*)(&newdata[current_offset]) = 0;
677         current_offset += sizeof(DWORD);
678         *(DWORD*)(&newdata[current_offset]) = len;
679         current_offset += sizeof(DWORD);
680     }
681
682     /* ResultStr */
683     new_one->dwResultStrLen = len;
684     if (len > 0)
685     {
686         new_one->dwResultStrOffset = current_offset;
687         memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR));
688     }
689     ImmUnlockIMCC(rc);
690     if (lpcs)
691         ImmUnlockIMCC(old);
692
693     return rc;
694 }
695
696
697
698 /***********************************************************************
699  *              ImmAssociateContext (IMM32.@)
700  */
701 HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC)
702 {
703     HIMC old = NULL;
704     InputContextData *data = (InputContextData*)hIMC;
705
706     TRACE("(%p, %p):\n", hWnd, hIMC);
707
708     /*
709      * WINE SPECIFIC! MAY CONFLICT
710      * associate the root context we have an XIM created
711      */
712     if (hWnd == 0x000)
713     {
714         root_context = (InputContextData*)hIMC;
715     }
716
717     /*
718      * If already associated just return
719      */
720     if (hIMC && data->IMC.hWnd == hWnd)
721         return hIMC;
722
723     if (hWnd)
724     {
725         old = (HIMC)RemovePropW(hWnd,szwWineIMCProperty);
726
727         if (old == NULL)
728             old = (HIMC)root_context;
729         else if (old == (HIMC)-1)
730             old = NULL;
731
732         if (hIMC != (HIMC)root_context)
733         {
734             if (hIMC == NULL) /* Meaning disable imm for that window*/
735                 SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1);
736             else
737                 SetPropW(hWnd,szwWineIMCProperty,(HANDLE)hIMC);
738         }
739     }
740
741     if (!hIMC)
742         return old;
743
744     if (IsWindow(data->IMC.hWnd))
745     {
746         /*
747          * Post a message that your context is switching
748          */
749         SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL);
750     }
751
752     data->IMC.hWnd = hWnd;
753
754     if (IsWindow(data->IMC.hWnd))
755     {
756         /*
757          * Post a message that your context is switching
758          */
759         SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL);
760     }
761
762     return old;
763 }
764
765 /***********************************************************************
766  *              ImmAssociateContextEx (IMM32.@)
767  */
768 BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags)
769 {
770     FIXME("(%p, %p, %d): stub\n", hWnd, hIMC, dwFlags);
771     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
772     return FALSE;
773 }
774
775 /***********************************************************************
776  *              ImmConfigureIMEA (IMM32.@)
777  */
778 BOOL WINAPI ImmConfigureIMEA(
779   HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
780 {
781     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
782
783     TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
784
785     if (immHkl->hIME && immHkl->pImeConfigure)
786     {
787         if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl))
788             return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
789         else
790         {
791             REGISTERWORDW rww;
792             REGISTERWORDA *rwa = (REGISTERWORDA*)lpData;
793             BOOL rc;
794
795             rww.lpReading = strdupAtoW(rwa->lpReading);
796             rww.lpWord = strdupAtoW(rwa->lpWord);
797             rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww);
798             HeapFree(GetProcessHeap(),0,rww.lpReading);
799             HeapFree(GetProcessHeap(),0,rww.lpWord);
800             return rc;
801         }
802     }
803     else
804         return FALSE;
805 }
806
807 /***********************************************************************
808  *              ImmConfigureIMEW (IMM32.@)
809  */
810 BOOL WINAPI ImmConfigureIMEW(
811   HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData)
812 {
813     ImmHkl *immHkl = IMM_GetImmHkl(hKL);
814
815     TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData);
816
817     if (immHkl->hIME && immHkl->pImeConfigure)
818     {
819         if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl))
820             return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData);
821         else
822         {
823             REGISTERWORDW *rww = (REGISTERWORDW*)lpData;
824             REGISTERWORDA rwa;
825             BOOL rc;
826
827             rwa.lpReading = strdupWtoA(rww->lpReading);
828             rwa.lpWord = strdupWtoA(rww->lpWord);
829             rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa);
830             HeapFree(GetProcessHeap(),0,rwa.lpReading);
831             HeapFree(GetProcessHeap(),0,rwa.lpWord);
832             return rc;
833         }
834     }
835     else
836         return FALSE;
837 }
838
839 /***********************************************************************
840  *              ImmCreateContext (IMM32.@)
841  */
842 HIMC WINAPI ImmCreateContext(void)
843 {
844     InputContextData *new_context;
845
846     new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData));
847
848     /* Load the IME */
849     new_context->immKbd = IMM_GetImmHkl(GetKeyboardLayout(0));
850
851     /*
852      * Once we depend on the IME for all the processing like we should
853      * these will become hard errors and result in creation failures
854      */
855     if (!new_context->immKbd->hIME)
856         TRACE("IME dll could not be loaded\n");
857
858     /* hCompStr is never NULL */
859     new_context->IMC.hCompStr = ImmCreateBlankCompStr();
860     new_context->IMC.hMsgBuf = ImmCreateIMCC(1);
861
862     /* Initialize the IME Private */
863     new_context->IMC.hPrivate = ImmCreateIMCC(new_context->immKbd->imeInfo.dwPrivateDataSize);
864
865     if (new_context->immKbd->hIME &&
866         !new_context->immKbd->pImeSelect(new_context, TRUE))
867     {
868         TRACE("Selection of IME failed\n");
869         ImmDestroyContext(new_context);
870         return 0;
871     }
872
873     new_context->immKbd->uSelected++;
874     TRACE("Created context 0x%x\n",(UINT)new_context);
875
876     return (HIMC)new_context;
877 }
878
879 /***********************************************************************
880  *              ImmDestroyContext (IMM32.@)
881  */
882 BOOL WINAPI ImmDestroyContext(HIMC hIMC)
883 {
884     InputContextData *data = (InputContextData*)hIMC;
885
886     TRACE("Destroying %p\n",hIMC);
887
888     if (hIMC)
889     {
890         data->immKbd->uSelected --;
891         if (data->immKbd->hIME)
892             data->immKbd->pImeSelect(hIMC, FALSE);
893
894         ImmDestroyIMCC(data->IMC.hCompStr);
895         ImmDestroyIMCC(data->IMC.hCandInfo);
896         ImmDestroyIMCC(data->IMC.hGuideLine);
897         ImmDestroyIMCC(data->IMC.hPrivate);
898         ImmDestroyIMCC(data->IMC.hMsgBuf);
899
900         if (data->textfont)
901         {
902             DeleteObject(data->textfont);
903             data->textfont = NULL;
904         }
905
906         HeapFree(GetProcessHeap(),0,data);
907     }
908     return TRUE;
909 }
910
911 /***********************************************************************
912  *              ImmDisableIME (IMM32.@)
913  */
914 BOOL WINAPI ImmDisableIME(DWORD idThread)
915 {
916     FIXME("(%d): stub\n", idThread);
917     return TRUE;
918 }
919
920 /***********************************************************************
921  *              ImmEnumRegisterWordA (IMM32.@)
922  */
923 UINT WINAPI ImmEnumRegisterWordA(
924   HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc,
925   LPCSTR lpszReading, DWORD dwStyle,
926   LPCSTR lpszRegister, LPVOID lpData)
927 {
928   FIXME("(%p, %p, %s, %d, %s, %p): stub\n",
929     hKL, lpfnEnumProc,
930     debugstr_a(lpszReading), dwStyle,
931     debugstr_a(lpszRegister), lpData
932   );
933   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
934   return 0;
935 }
936
937 /***********************************************************************
938  *              ImmEnumRegisterWordW (IMM32.@)
939  */
940 UINT WINAPI ImmEnumRegisterWordW(
941   HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc,
942   LPCWSTR lpszReading, DWORD dwStyle,
943   LPCWSTR lpszRegister, LPVOID lpData)
944 {
945   FIXME("(%p, %p, %s, %d, %s, %p): stub\n",
946     hKL, lpfnEnumProc,
947     debugstr_w(lpszReading), dwStyle,
948     debugstr_w(lpszRegister), lpData
949   );
950   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
951   return 0;
952 }
953
954 /***********************************************************************
955  *              ImmEscapeA (IMM32.@)
956  */
957 LRESULT WINAPI ImmEscapeA(
958   HKL hKL, HIMC hIMC,
959   UINT uEscape, LPVOID lpData)
960 {
961   FIXME("(%p, %p, %d, %p): stub\n",
962     hKL, hIMC, uEscape, lpData
963   );
964   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
965   return 0;
966 }
967
968 /***********************************************************************
969  *              ImmEscapeW (IMM32.@)
970  */
971 LRESULT WINAPI ImmEscapeW(
972   HKL hKL, HIMC hIMC,
973   UINT uEscape, LPVOID lpData)
974 {
975   FIXME("(%p, %p, %d, %p): stub\n",
976     hKL, hIMC, uEscape, lpData
977   );
978   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
979   return 0;
980 }
981
982 /***********************************************************************
983  *              ImmGetCandidateListA (IMM32.@)
984  */
985 DWORD WINAPI ImmGetCandidateListA(
986   HIMC hIMC, DWORD deIndex,
987   LPCANDIDATELIST lpCandList, DWORD dwBufLen)
988 {
989   FIXME("(%p, %d, %p, %d): stub\n",
990     hIMC, deIndex,
991     lpCandList, dwBufLen
992   );
993   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
994   return 0;
995 }
996
997 /***********************************************************************
998  *              ImmGetCandidateListCountA (IMM32.@)
999  */
1000 DWORD WINAPI ImmGetCandidateListCountA(
1001   HIMC hIMC, LPDWORD lpdwListCount)
1002 {
1003   FIXME("(%p, %p): stub\n", hIMC, lpdwListCount);
1004   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1005   return 0;
1006 }
1007
1008 /***********************************************************************
1009  *              ImmGetCandidateListCountW (IMM32.@)
1010  */
1011 DWORD WINAPI ImmGetCandidateListCountW(
1012   HIMC hIMC, LPDWORD lpdwListCount)
1013 {
1014   FIXME("(%p, %p): stub\n", hIMC, lpdwListCount);
1015   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1016   return 0;
1017 }
1018
1019 /***********************************************************************
1020  *              ImmGetCandidateListW (IMM32.@)
1021  */
1022 DWORD WINAPI ImmGetCandidateListW(
1023   HIMC hIMC, DWORD deIndex,
1024   LPCANDIDATELIST lpCandList, DWORD dwBufLen)
1025 {
1026   FIXME("(%p, %d, %p, %d): stub\n",
1027     hIMC, deIndex,
1028     lpCandList, dwBufLen
1029   );
1030   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1031   return 0;
1032 }
1033
1034 /***********************************************************************
1035  *              ImmGetCandidateWindow (IMM32.@)
1036  */
1037 BOOL WINAPI ImmGetCandidateWindow(
1038   HIMC hIMC, DWORD dwBufLen, LPCANDIDATEFORM lpCandidate)
1039 {
1040   FIXME("(%p, %d, %p): stub\n", hIMC, dwBufLen, lpCandidate);
1041   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1042   return FALSE;
1043 }
1044
1045 /***********************************************************************
1046  *              ImmGetCompositionFontA (IMM32.@)
1047  */
1048 BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1049 {
1050     LOGFONTW lfW;
1051     BOOL rc;
1052
1053     TRACE("(%p, %p):\n", hIMC, lplf);
1054
1055     rc = ImmGetCompositionFontW(hIMC,&lfW);
1056     if (rc)
1057     {
1058         memcpy(lplf,&lfW,sizeof(LOGFONTA));
1059         WideCharToMultiByte(CP_ACP, 0, lfW.lfFaceName, -1, lplf->lfFaceName,
1060                         LF_FACESIZE, NULL, NULL);
1061     }
1062     return rc;
1063 }
1064
1065 /***********************************************************************
1066  *              ImmGetCompositionFontW (IMM32.@)
1067  */
1068 BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1069 {
1070     InputContextData *data = (InputContextData*)hIMC;
1071
1072     TRACE("(%p, %p):\n", hIMC, lplf);
1073
1074     if (!data)
1075         return FALSE;
1076
1077     *lplf = data->IMC.lfFont.W;
1078
1079     return TRUE;
1080 }
1081
1082 /***********************************************************************
1083  *              ImmGetCompositionStringA (IMM32.@)
1084  */
1085 LONG WINAPI ImmGetCompositionStringA(
1086   HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
1087 {
1088     CHAR *buf;
1089     LONG rc = 0;
1090     InputContextData *data = (InputContextData*)hIMC;
1091     LPCOMPOSITIONSTRING compstr;
1092     LPBYTE compdata;
1093
1094     TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
1095
1096     if (!data)
1097        return FALSE;
1098
1099     if (!data->IMC.hCompStr)
1100        return FALSE;
1101
1102     compdata = ImmLockIMCC(data->IMC.hCompStr);
1103     compstr = (LPCOMPOSITIONSTRING)compdata;
1104
1105     if (dwIndex == GCS_RESULTSTR && compstr->dwResultStrLen > 0 &&
1106         compstr->dwResultStrOffset > 0)
1107     {
1108         LPWSTR ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
1109
1110         TRACE("GSC_RESULTSTR %p %i\n",ResultStr,
1111                                     compstr->dwResultStrLen);
1112
1113         buf = HeapAlloc( GetProcessHeap(), 0, compstr->dwResultStrLen * 3 );
1114         rc = WideCharToMultiByte(CP_ACP, 0, ResultStr,
1115                                  compstr->dwResultStrLen , buf,
1116                                  compstr->dwResultStrLen * 3, NULL, NULL);
1117         if (dwBufLen >= rc)
1118             memcpy(lpBuf,buf,rc);
1119
1120         data->bRead = TRUE;
1121         HeapFree( GetProcessHeap(), 0, buf );
1122     }
1123     else if (dwIndex == GCS_COMPSTR && compstr->dwCompStrLen > 0 &&
1124               compstr->dwCompStrOffset > 0)
1125     {
1126         LPWSTR CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1127
1128         TRACE("GSC_COMPSTR %p %i\n", CompString, compstr->dwCompStrLen);
1129
1130         buf = HeapAlloc( GetProcessHeap(), 0, compstr->dwCompStrLen * 3 );
1131         rc = WideCharToMultiByte(CP_ACP, 0, CompString,
1132                                  compstr->dwCompStrLen, buf,
1133                                  compstr->dwCompStrLen * 3, NULL, NULL);
1134         if (dwBufLen >= rc)
1135             memcpy(lpBuf,buf,rc);
1136         HeapFree( GetProcessHeap(), 0, buf );
1137     }
1138     else if (dwIndex == GCS_COMPATTR && compstr->dwCompAttrLen > 0 &&
1139              compstr->dwCompAttrOffset > 0)
1140     {
1141         LPWSTR Compattr = (LPWSTR)(compdata + compstr->dwCompAttrOffset);
1142         TRACE("GSC_COMPATTR %p %i\n", Compattr , compstr->dwCompAttrLen);
1143
1144         rc = compstr->dwCompAttrLen;
1145         if (dwBufLen >= rc)
1146             memcpy(lpBuf,Compattr,rc);
1147     }
1148     else if (dwIndex == GCS_COMPCLAUSE && compstr->dwCompClauseLen > 0 &&
1149              compstr->dwCompClauseOffset > 0)
1150     {
1151         LPWSTR Compclause = (LPWSTR)(compdata + compstr->dwCompClauseOffset);
1152         TRACE("GSC_COMPCLAUSE %p %i\n", Compclause, compstr->dwCompClauseLen);
1153
1154         rc = compstr->dwCompClauseLen;
1155         if (dwBufLen >= compstr->dwCompClauseLen)
1156             memcpy(lpBuf,Compclause,rc);
1157     }
1158     else if (dwIndex == GCS_RESULTCLAUSE && compstr->dwResultClauseLen > 0 &&
1159              compstr->dwResultClauseOffset > 0)
1160     {
1161         LPWSTR Resultclause = (LPWSTR)(compdata + compstr->dwResultClauseOffset);
1162         TRACE("GSC_RESULTCLAUSE %p %i\n", Resultclause, compstr->dwResultClauseLen);
1163
1164         rc = compstr->dwResultClauseLen;
1165         if (dwBufLen >= compstr->dwResultClauseLen)
1166             memcpy(lpBuf,Resultclause,rc);
1167     }
1168     else if (dwIndex == GCS_CURSORPOS)
1169     {
1170         TRACE("GSC_CURSORPOS\n");
1171         rc = compstr->dwCursorPos;
1172     }
1173     else if (dwIndex == GCS_DELTASTART)
1174     {
1175         TRACE("GCS_DELTASTART\n");
1176         rc = compstr->dwDeltaStart;
1177     }
1178     else
1179     {
1180         FIXME("Unhandled index 0x%x\n",dwIndex);
1181     }
1182
1183     ImmUnlockIMCC(data->IMC.hCompStr);
1184
1185     return rc;
1186 }
1187
1188 /***********************************************************************
1189  *              ImmGetCompositionStringW (IMM32.@)
1190  */
1191 LONG WINAPI ImmGetCompositionStringW(
1192   HIMC hIMC, DWORD dwIndex,
1193   LPVOID lpBuf, DWORD dwBufLen)
1194 {
1195     LONG rc = 0;
1196     InputContextData *data = (InputContextData*)hIMC;
1197     LPCOMPOSITIONSTRING compstr;
1198     LPBYTE compdata;
1199
1200     TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen);
1201
1202     if (!data)
1203        return FALSE;
1204
1205     if (!data->IMC.hCompStr)
1206        return FALSE;
1207
1208     compdata = ImmLockIMCC(data->IMC.hCompStr);
1209     compstr = (LPCOMPOSITIONSTRING)compdata;
1210
1211     if (dwIndex == GCS_RESULTSTR && compstr->dwResultStrLen > 0 &&
1212         compstr->dwResultStrOffset > 0)
1213     {
1214         LPWSTR ResultStr = (LPWSTR)(compdata + compstr->dwResultStrOffset);
1215         data->bRead = TRUE;
1216         rc =  compstr->dwResultStrLen * sizeof(WCHAR);
1217
1218         if (dwBufLen >= rc)
1219             memcpy(lpBuf,ResultStr,rc);
1220     }
1221     else if (dwIndex == GCS_RESULTREADSTR && compstr->dwResultReadStrLen > 0 &&
1222              compstr->dwResultReadStrOffset > 0)
1223     {
1224         LPWSTR ResultReadString = (LPWSTR)(compdata + compstr->dwResultReadStrOffset);
1225
1226         rc = compstr->dwResultReadStrLen * sizeof(WCHAR);
1227         if (dwBufLen >= rc)
1228             memcpy(lpBuf,ResultReadString,rc);
1229     }
1230     else if (dwIndex == GCS_COMPSTR && compstr->dwCompStrLen > 0 &&
1231               compstr->dwCompStrOffset > 0)
1232     {
1233         LPWSTR CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
1234         rc = compstr->dwCompStrLen * sizeof(WCHAR);
1235         if (dwBufLen >= rc)
1236             memcpy(lpBuf,CompString,rc);
1237     }
1238     else if (dwIndex == GCS_COMPATTR && compstr->dwCompAttrLen > 0 &&
1239              compstr->dwCompAttrOffset > 0)
1240     {
1241
1242         LPWSTR Compattr = (LPWSTR)(compdata + compstr->dwCompAttrOffset);
1243
1244         rc = compstr->dwCompAttrLen;
1245         if (dwBufLen >= rc)
1246             memcpy(lpBuf,Compattr,rc);
1247     }
1248     else if (dwIndex == GCS_COMPCLAUSE && compstr->dwCompClauseLen > 0 &&
1249              compstr->dwCompClauseOffset > 0)
1250     {
1251         LPWSTR Compclause = (LPWSTR)(compdata + compstr->dwCompClauseOffset);
1252
1253         rc = compstr->dwCompClauseLen;
1254         if (dwBufLen >= compstr->dwCompClauseLen)
1255             memcpy(lpBuf,Compclause,rc);
1256     }
1257     else if (dwIndex == GCS_COMPREADSTR && compstr->dwCompReadStrLen > 0 &&
1258               compstr->dwCompReadStrOffset > 0)
1259     {
1260         LPWSTR CompReadString = (LPWSTR)(compdata + compstr->dwCompReadStrOffset);
1261
1262         rc = compstr->dwCompReadStrLen * sizeof(WCHAR);
1263
1264         if (dwBufLen >= rc)
1265             memcpy(lpBuf,CompReadString,rc);
1266     }
1267     else if (dwIndex == GCS_CURSORPOS)
1268     {
1269         TRACE("GSC_CURSORPOS\n");
1270         rc = compstr->dwCursorPos;
1271     }
1272     else if (dwIndex == GCS_DELTASTART)
1273     {
1274         TRACE("GCS_DELTASTART\n");
1275         rc = compstr->dwDeltaStart;
1276     }
1277     else
1278     {
1279         FIXME("Unhandled index 0x%x\n",dwIndex);
1280     }   
1281
1282     ImmUnlockIMCC(data->IMC.hCompStr);
1283
1284     return rc;
1285 }
1286
1287 /***********************************************************************
1288  *              ImmGetCompositionWindow (IMM32.@)
1289  */
1290 BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
1291 {
1292     InputContextData *data = (InputContextData*)hIMC;
1293
1294     TRACE("(%p, %p)\n", hIMC, lpCompForm);
1295
1296     if (!data)
1297         return FALSE;
1298
1299     *lpCompForm = data->IMC.cfCompForm;
1300     return 1;
1301 }
1302
1303 /***********************************************************************
1304  *              ImmGetContext (IMM32.@)
1305  *
1306  */
1307 HIMC WINAPI ImmGetContext(HWND hWnd)
1308 {
1309     HIMC rc = NULL;
1310
1311     TRACE("%p\n", hWnd);
1312
1313     rc = (HIMC)GetPropW(hWnd,szwWineIMCProperty);
1314     if (rc == (HIMC)-1)
1315         rc = NULL;
1316     else if (rc == NULL)
1317         rc = (HIMC)root_context;
1318
1319     if (rc)
1320     {
1321         InputContextData *data = (InputContextData*)rc;
1322         data->IMC.hWnd = hWnd;
1323     }
1324     TRACE("returning %p\n", rc);
1325
1326     return rc;
1327 }
1328
1329 /***********************************************************************
1330  *              ImmGetConversionListA (IMM32.@)
1331  */
1332 DWORD WINAPI ImmGetConversionListA(
1333   HKL hKL, HIMC hIMC,
1334   LPCSTR pSrc, LPCANDIDATELIST lpDst,
1335   DWORD dwBufLen, UINT uFlag)
1336 {
1337   FIXME("(%p, %p, %s, %p, %d, %d): stub\n",
1338     hKL, hIMC, debugstr_a(pSrc), lpDst, dwBufLen, uFlag
1339   );
1340   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1341   return 0;
1342 }
1343
1344 /***********************************************************************
1345  *              ImmGetConversionListW (IMM32.@)
1346  */
1347 DWORD WINAPI ImmGetConversionListW(
1348   HKL hKL, HIMC hIMC,
1349   LPCWSTR pSrc, LPCANDIDATELIST lpDst,
1350   DWORD dwBufLen, UINT uFlag)
1351 {
1352   FIXME("(%p, %p, %s, %p, %d, %d): stub\n",
1353     hKL, hIMC, debugstr_w(pSrc), lpDst, dwBufLen, uFlag
1354   );
1355   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1356   return 0;
1357 }
1358
1359 /***********************************************************************
1360  *              ImmGetConversionStatus (IMM32.@)
1361  */
1362 BOOL WINAPI ImmGetConversionStatus(
1363   HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence)
1364 {
1365     TRACE("(%p, %p, %p): best guess\n", hIMC, lpfdwConversion, lpfdwSentence);
1366     if (lpfdwConversion)
1367         *lpfdwConversion = IME_CMODE_NATIVE;
1368     if (lpfdwSentence)
1369         *lpfdwSentence = IME_SMODE_NONE;
1370     return TRUE;
1371 }
1372
1373 /***********************************************************************
1374  *              ImmGetDefaultIMEWnd (IMM32.@)
1375  */
1376 HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
1377 {
1378   static int shown = 0;
1379
1380   if (!shown) {
1381         FIXME("(%p - %p %p ): semi-stub\n", hWnd,hwndDefault, root_context);
1382         shown = 1;
1383   }
1384
1385   if (hwndDefault == NULL)
1386   {
1387         static const WCHAR the_name[] = {'I','M','E','\0'};
1388
1389         IMM_Register();
1390         hwndDefault = CreateWindowExW( WS_EX_TOOLWINDOW, WC_IMECLASSNAME,
1391                 the_name, WS_POPUP, 0, 0, 1, 1, 0, 0,
1392                 hImeInst, 0);
1393
1394         TRACE("Default created (%p)\n",hwndDefault);
1395   }
1396
1397   return hwndDefault;
1398 }
1399
1400 /***********************************************************************
1401  *              ImmGetDescriptionA (IMM32.@)
1402  */
1403 UINT WINAPI ImmGetDescriptionA(
1404   HKL hKL, LPSTR lpszDescription, UINT uBufLen)
1405 {
1406   WCHAR *buf;
1407   DWORD len;
1408
1409   TRACE("%p %p %d\n", hKL, lpszDescription, uBufLen);
1410
1411   /* find out how many characters in the unicode buffer */
1412   len = ImmGetDescriptionW( hKL, NULL, 0 );
1413
1414   /* allocate a buffer of that size */
1415   buf = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR) );
1416   if( !buf )
1417   return 0;
1418
1419   /* fetch the unicode buffer */
1420   len = ImmGetDescriptionW( hKL, buf, len + 1 );
1421
1422   /* convert it back to ASCII */
1423   len = WideCharToMultiByte( CP_ACP, 0, buf, len + 1,
1424                              lpszDescription, uBufLen, NULL, NULL );
1425
1426   HeapFree( GetProcessHeap(), 0, buf );
1427
1428   return len;
1429 }
1430
1431 /***********************************************************************
1432  *              ImmGetDescriptionW (IMM32.@)
1433  */
1434 UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen)
1435 {
1436   static const WCHAR name[] = { 'W','i','n','e',' ','X','I','M',0 };
1437
1438   FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen);
1439
1440   if (!uBufLen) return lstrlenW( name );
1441   lstrcpynW( lpszDescription, name, uBufLen );
1442   return lstrlenW( lpszDescription );
1443 }
1444
1445 /***********************************************************************
1446  *              ImmGetGuideLineA (IMM32.@)
1447  */
1448 DWORD WINAPI ImmGetGuideLineA(
1449   HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen)
1450 {
1451   FIXME("(%p, %d, %s, %d): stub\n",
1452     hIMC, dwIndex, debugstr_a(lpBuf), dwBufLen
1453   );
1454   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1455   return 0;
1456 }
1457
1458 /***********************************************************************
1459  *              ImmGetGuideLineW (IMM32.@)
1460  */
1461 DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen)
1462 {
1463   FIXME("(%p, %d, %s, %d): stub\n",
1464     hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen
1465   );
1466   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1467   return 0;
1468 }
1469
1470 /***********************************************************************
1471  *              ImmGetIMEFileNameA (IMM32.@)
1472  */
1473 UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen)
1474 {
1475     LPWSTR bufW = NULL;
1476     UINT wBufLen = uBufLen;
1477     UINT rc;
1478
1479     if (uBufLen && lpszFileName)
1480         bufW = HeapAlloc(GetProcessHeap(),0,uBufLen * sizeof(WCHAR));
1481     else /* We need this to get the number of byte required */
1482     {
1483         bufW = HeapAlloc(GetProcessHeap(),0,MAX_PATH * sizeof(WCHAR));
1484         wBufLen = MAX_PATH;
1485     }
1486
1487     rc = ImmGetIMEFileNameW(hKL,bufW,wBufLen);
1488
1489     if (rc > 0)
1490     {
1491         if (uBufLen && lpszFileName)
1492             rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, lpszFileName,
1493                                  uBufLen, NULL, NULL);
1494         else /* get the length */
1495             rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL,
1496                                      NULL);
1497     }
1498
1499     HeapFree(GetProcessHeap(),0,bufW);
1500     return rc;
1501 }
1502
1503 /***********************************************************************
1504  *              ImmGetIMEFileNameW (IMM32.@)
1505  */
1506 UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen)
1507 {
1508     static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0};
1509     static const WCHAR fmt[] = {'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','x',0};
1510
1511     HKEY hkey;
1512     DWORD length;
1513     DWORD rc;
1514     WCHAR regKey[sizeof(fmt)/sizeof(WCHAR)+8];
1515
1516     wsprintfW( regKey, fmt, (unsigned)hKL );
1517     rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey);
1518     if (rc != ERROR_SUCCESS)
1519     {
1520         SetLastError(rc);
1521         return 0;
1522     }
1523
1524     length = 0;
1525     rc = RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, NULL, &length);
1526
1527     if (rc != ERROR_SUCCESS)
1528     {
1529         RegCloseKey(hkey);
1530         SetLastError(rc);
1531         return 0;
1532     }
1533     if (length > uBufLen * sizeof(WCHAR) || !lpszFileName)
1534     {
1535         RegCloseKey(hkey);
1536         if (lpszFileName)
1537         {
1538             SetLastError(ERROR_INSUFFICIENT_BUFFER);
1539             return 0;
1540         }
1541         else
1542             return length / sizeof(WCHAR);
1543     }
1544
1545     RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, lpszFileName, &length);
1546
1547     RegCloseKey(hkey);
1548
1549     return length / sizeof(WCHAR);
1550 }
1551
1552 /***********************************************************************
1553  *              ImmGetOpenStatus (IMM32.@)
1554  */
1555 BOOL WINAPI ImmGetOpenStatus(HIMC hIMC)
1556 {
1557   InputContextData *data = (InputContextData*)hIMC;
1558
1559     if (!data)
1560         return FALSE;
1561   FIXME("(%p): semi-stub\n", hIMC);
1562
1563   return data->IMC.fOpen;
1564 }
1565
1566 /***********************************************************************
1567  *              ImmGetProperty (IMM32.@)
1568  */
1569 DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex)
1570 {
1571     DWORD rc = 0;
1572     TRACE("(%p, %d)\n", hKL, fdwIndex);
1573
1574     switch (fdwIndex)
1575     {
1576         case IGP_PROPERTY:
1577             TRACE("(%s)\n", "IGP_PROPERTY");
1578             rc = IME_PROP_UNICODE | IME_PROP_AT_CARET;
1579             break;
1580         case IGP_CONVERSION:
1581             FIXME("(%s)\n", "IGP_CONVERSION");
1582             rc = IME_CMODE_NATIVE;
1583             break;
1584         case IGP_SENTENCE:
1585             FIXME("%s)\n", "IGP_SENTENCE");
1586             rc = IME_SMODE_AUTOMATIC;
1587             break;
1588         case IGP_SETCOMPSTR:
1589             TRACE("(%s)\n", "IGP_SETCOMPSTR");
1590             rc = 0;
1591             break;
1592         case IGP_SELECT:
1593             TRACE("(%s)\n", "IGP_SELECT");
1594             rc = SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE;
1595             break;
1596         case IGP_GETIMEVERSION:
1597             TRACE("(%s)\n", "IGP_GETIMEVERSION");
1598             rc = IMEVER_0400;
1599             break;
1600         case IGP_UI:
1601             TRACE("(%s)\n", "IGP_UI");
1602             rc = 0;
1603             break;
1604         default:
1605             rc = 0;
1606     }
1607     return rc;
1608 }
1609
1610 /***********************************************************************
1611  *              ImmGetRegisterWordStyleA (IMM32.@)
1612  */
1613 UINT WINAPI ImmGetRegisterWordStyleA(
1614   HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf)
1615 {
1616   FIXME("(%p, %d, %p): stub\n", hKL, nItem, lpStyleBuf);
1617   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1618   return 0;
1619 }
1620
1621 /***********************************************************************
1622  *              ImmGetRegisterWordStyleW (IMM32.@)
1623  */
1624 UINT WINAPI ImmGetRegisterWordStyleW(
1625   HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf)
1626 {
1627   FIXME("(%p, %d, %p): stub\n", hKL, nItem, lpStyleBuf);
1628   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1629   return 0;
1630 }
1631
1632 /***********************************************************************
1633  *              ImmGetStatusWindowPos (IMM32.@)
1634  */
1635 BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
1636 {
1637   FIXME("(%p, %p): stub\n", hIMC, lpptPos);
1638   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1639   return FALSE;
1640 }
1641
1642 /***********************************************************************
1643  *              ImmGetVirtualKey (IMM32.@)
1644  */
1645 UINT WINAPI ImmGetVirtualKey(HWND hWnd)
1646 {
1647   OSVERSIONINFOA version;
1648   FIXME("(%p): stub\n", hWnd);
1649   GetVersionExA( &version );
1650   switch(version.dwPlatformId)
1651   {
1652   case VER_PLATFORM_WIN32_WINDOWS:
1653       return VK_PROCESSKEY;
1654   case VER_PLATFORM_WIN32_NT:
1655       return 0;
1656   default:
1657       FIXME("%d not supported\n",version.dwPlatformId);
1658       return VK_PROCESSKEY;
1659   }
1660 }
1661
1662 /***********************************************************************
1663  *              ImmInstallIMEA (IMM32.@)
1664  */
1665 HKL WINAPI ImmInstallIMEA(
1666   LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
1667 {
1668   FIXME("(%s, %s): stub\n",
1669     debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText)
1670   );
1671   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1672   return NULL;
1673 }
1674
1675 /***********************************************************************
1676  *              ImmInstallIMEW (IMM32.@)
1677  */
1678 HKL WINAPI ImmInstallIMEW(
1679   LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
1680 {
1681   FIXME("(%s, %s): stub\n",
1682     debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText)
1683   );
1684   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1685   return NULL;
1686 }
1687
1688 /***********************************************************************
1689  *              ImmIsIME (IMM32.@)
1690  */
1691 BOOL WINAPI ImmIsIME(HKL hKL)
1692 {
1693   TRACE("(%p): semi-stub\n", hKL);
1694   /*
1695    * FIXME: Dead key locales will return TRUE here when they should not
1696    * There is probably a more proper way to check this.
1697    */
1698   return (root_context != NULL);
1699 }
1700
1701 /***********************************************************************
1702  *              ImmIsUIMessageA (IMM32.@)
1703  */
1704 BOOL WINAPI ImmIsUIMessageA(
1705   HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
1706 {
1707     BOOL rc = FALSE;
1708
1709     TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam);
1710     if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1711         (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP) ||
1712         (msg == WM_MSIME_SERVICE) ||
1713         (msg == WM_MSIME_RECONVERTOPTIONS) ||
1714         (msg == WM_MSIME_MOUSE) ||
1715         (msg == WM_MSIME_RECONVERTREQUEST) ||
1716         (msg == WM_MSIME_RECONVERT) ||
1717         (msg == WM_MSIME_QUERYPOSITION) ||
1718         (msg == WM_MSIME_DOCUMENTFEED))
1719
1720     {
1721         if (!hwndDefault)
1722             ImmGetDefaultIMEWnd(NULL);
1723
1724         if (hWndIME == NULL)
1725             PostMessageA(hwndDefault, msg, wParam, lParam);
1726
1727         rc = TRUE;
1728     }
1729     return rc;
1730 }
1731
1732 /***********************************************************************
1733  *              ImmIsUIMessageW (IMM32.@)
1734  */
1735 BOOL WINAPI ImmIsUIMessageW(
1736   HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam)
1737 {
1738     BOOL rc = FALSE;
1739     TRACE("(%p, %d, %ld, %ld): stub\n", hWndIME, msg, wParam, lParam);
1740     if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
1741         (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP) ||
1742         (msg == WM_MSIME_SERVICE) ||
1743         (msg == WM_MSIME_RECONVERTOPTIONS) ||
1744         (msg == WM_MSIME_MOUSE) ||
1745         (msg == WM_MSIME_RECONVERTREQUEST) ||
1746         (msg == WM_MSIME_RECONVERT) ||
1747         (msg == WM_MSIME_QUERYPOSITION) ||
1748         (msg == WM_MSIME_DOCUMENTFEED))
1749         rc = TRUE;
1750     return rc;
1751 }
1752
1753 /***********************************************************************
1754  *              ImmNotifyIME (IMM32.@)
1755  */
1756 BOOL WINAPI ImmNotifyIME(
1757   HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
1758 {
1759     BOOL rc = FALSE;
1760
1761     TRACE("(%p, %d, %d, %d)\n",
1762         hIMC, dwAction, dwIndex, dwValue);
1763
1764     if (!root_context)
1765         return rc;
1766
1767     switch(dwAction)
1768     {
1769         case NI_CHANGECANDIDATELIST:
1770             FIXME("%s\n","NI_CHANGECANDIDATELIST");
1771             break;
1772         case NI_CLOSECANDIDATE:
1773             FIXME("%s\n","NI_CLOSECANDIDATE");
1774             break;
1775         case NI_COMPOSITIONSTR:
1776             switch (dwIndex)
1777             {
1778                 case CPS_CANCEL:
1779                     TRACE("%s - %s\n","NI_COMPOSITIONSTR","CPS_CANCEL");
1780                     {
1781                         BOOL send;
1782                         LPCOMPOSITIONSTRING lpCompStr;
1783
1784                         if (pX11DRV_ForceXIMReset)
1785                             pX11DRV_ForceXIMReset(root_context->IMC.hWnd);
1786
1787                         lpCompStr = ImmLockIMCC(root_context->IMC.hCompStr);
1788                         send = (lpCompStr->dwCompStrLen != 0);
1789                         ImmUnlockIMCC(root_context->IMC.hCompStr);
1790
1791                         ImmDestroyIMCC(root_context->IMC.hCompStr);
1792                         root_context->IMC.hCompStr = ImmCreateBlankCompStr();
1793
1794                         if (send)
1795                             ImmInternalPostIMEMessage(root_context, WM_IME_COMPOSITION, 0,
1796                                                   GCS_COMPSTR);
1797                         rc = TRUE;
1798                     }
1799                     break;
1800                 case CPS_COMPLETE:
1801                     TRACE("%s - %s\n","NI_COMPOSITIONSTR","CPS_COMPLETE");
1802                     if (hIMC != (HIMC)FROM_IME && pX11DRV_ForceXIMReset)
1803                         pX11DRV_ForceXIMReset(root_context->IMC.hWnd);
1804                     {
1805                         HIMCC newCompStr;
1806                         DWORD cplen = 0;
1807                         LPWSTR cpstr;
1808                         LPCOMPOSITIONSTRING cs = NULL;
1809                         LPBYTE cdata = NULL;
1810
1811                         /* clear existing result */
1812                         newCompStr = updateResultStr(root_context->IMC.hCompStr, NULL, 0);
1813                         ImmDestroyIMCC(root_context->IMC.hCompStr);
1814                         root_context->IMC.hCompStr = newCompStr;
1815
1816                         if (root_context->IMC.hCompStr)
1817                         {
1818                             cdata = ImmLockIMCC(root_context->IMC.hCompStr);
1819                             cs = (LPCOMPOSITIONSTRING)cdata;
1820                             cplen = cs->dwCompStrLen;
1821                             cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]);
1822                             ImmUnlockIMCC(root_context->IMC.hCompStr);
1823                         }
1824                         if (cplen > 0)
1825                         {
1826                             WCHAR param = cpstr[0];
1827                             newCompStr = updateResultStr(root_context->IMC.hCompStr, cpstr, cplen);
1828                             ImmDestroyIMCC(root_context->IMC.hCompStr);
1829                             root_context->IMC.hCompStr = newCompStr;
1830                             newCompStr = updateCompStr(root_context->IMC.hCompStr, NULL, 0);
1831                             ImmDestroyIMCC(root_context->IMC.hCompStr);
1832                             root_context->IMC.hCompStr = newCompStr;
1833
1834                             root_context->bRead = FALSE;
1835
1836                             ImmInternalPostIMEMessage(root_context, WM_IME_COMPOSITION, 0,
1837                                                   GCS_COMPSTR);
1838
1839                             ImmInternalPostIMEMessage(root_context, WM_IME_COMPOSITION,
1840                                             param,
1841                                             GCS_RESULTSTR|GCS_RESULTCLAUSE);
1842                         }
1843
1844                         ImmInternalPostIMEMessage(root_context, WM_IME_ENDCOMPOSITION, 0, 0);
1845                         root_context->bInComposition = FALSE;
1846                     }
1847                     break;
1848                 case CPS_CONVERT:
1849                     FIXME("%s - %s\n","NI_COMPOSITIONSTR","CPS_CONVERT");
1850                     break;
1851                 case CPS_REVERT:
1852                     FIXME("%s - %s\n","NI_COMPOSITIONSTR","CPS_REVERT");
1853                     break;
1854                 default:
1855                     ERR("%s - %s (%i)\n","NI_COMPOSITIONSTR","UNKNOWN",dwIndex);
1856                     break;
1857             }
1858             break;
1859         case NI_IMEMENUSELECTED:
1860             FIXME("%s\n", "NI_IMEMENUSELECTED");
1861             break;
1862         case NI_OPENCANDIDATE:
1863             FIXME("%s\n", "NI_OPENCANDIDATE");
1864             break;
1865         case NI_SELECTCANDIDATESTR:
1866             FIXME("%s\n", "NI_SELECTCANDIDATESTR");
1867             break;
1868         case NI_SETCANDIDATE_PAGESIZE:
1869             FIXME("%s\n", "NI_SETCANDIDATE_PAGESIZE");
1870             break;
1871         case NI_SETCANDIDATE_PAGESTART:
1872             FIXME("%s\n", "NI_SETCANDIDATE_PAGESTART");
1873             break;
1874         default:
1875             ERR("Unknown\n");
1876     }
1877
1878     return rc;
1879 }
1880
1881 /***********************************************************************
1882  *              ImmRegisterWordA (IMM32.@)
1883  */
1884 BOOL WINAPI ImmRegisterWordA(
1885   HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister)
1886 {
1887   FIXME("(%p, %s, %d, %s): stub\n",
1888     hKL, debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister)
1889   );
1890   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1891   return FALSE;
1892 }
1893
1894 /***********************************************************************
1895  *              ImmRegisterWordW (IMM32.@)
1896  */
1897 BOOL WINAPI ImmRegisterWordW(
1898   HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister)
1899 {
1900   FIXME("(%p, %s, %d, %s): stub\n",
1901     hKL, debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister)
1902   );
1903   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1904   return FALSE;
1905 }
1906
1907 /***********************************************************************
1908  *              ImmReleaseContext (IMM32.@)
1909  */
1910 BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC)
1911 {
1912   static int shown = 0;
1913
1914   if (!shown) {
1915      FIXME("(%p, %p): stub\n", hWnd, hIMC);
1916      shown = 1;
1917   }
1918   return TRUE;
1919 }
1920
1921 /***********************************************************************
1922  *              ImmSetCandidateWindow (IMM32.@)
1923  */
1924 BOOL WINAPI ImmSetCandidateWindow(
1925   HIMC hIMC, LPCANDIDATEFORM lpCandidate)
1926 {
1927   FIXME("(%p, %p): stub\n", hIMC, lpCandidate);
1928   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1929   return FALSE;
1930 }
1931
1932 /***********************************************************************
1933  *              ImmSetCompositionFontA (IMM32.@)
1934  */
1935 BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf)
1936 {
1937     InputContextData *data = (InputContextData*)hIMC;
1938     TRACE("(%p, %p)\n", hIMC, lplf);
1939
1940     if (!data)
1941         return FALSE;
1942
1943     memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA));
1944     MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName,
1945                         LF_FACESIZE);
1946
1947     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
1948
1949     if (data->textfont)
1950     {
1951         DeleteObject(data->textfont);
1952         data->textfont = NULL;
1953     }
1954
1955     data->textfont = CreateFontIndirectW(&data->IMC.lfFont.W);
1956     return TRUE;
1957 }
1958
1959 /***********************************************************************
1960  *              ImmSetCompositionFontW (IMM32.@)
1961  */
1962 BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf)
1963 {
1964     InputContextData *data = (InputContextData*)hIMC;
1965     TRACE("(%p, %p)\n", hIMC, lplf);
1966
1967     if (!data)
1968         return FALSE;
1969
1970     data->IMC.lfFont.W = *lplf;
1971     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0);
1972
1973     if (data->textfont)
1974     {
1975         DeleteObject(data->textfont);
1976         data->textfont = NULL;
1977     }
1978     data->textfont = CreateFontIndirectW(&data->IMC.lfFont.W);
1979     return TRUE;
1980 }
1981
1982 /***********************************************************************
1983  *              ImmSetCompositionStringA (IMM32.@)
1984  */
1985 BOOL WINAPI ImmSetCompositionStringA(
1986   HIMC hIMC, DWORD dwIndex,
1987   LPCVOID lpComp, DWORD dwCompLen,
1988   LPCVOID lpRead, DWORD dwReadLen)
1989 {
1990     DWORD comp_len;
1991     DWORD read_len;
1992     WCHAR *CompBuffer = NULL;
1993     WCHAR *ReadBuffer = NULL;
1994     BOOL rc;
1995
1996     TRACE("(%p, %d, %p, %d, %p, %d): stub\n",
1997             hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
1998
1999     comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0);
2000     if (comp_len)
2001     {
2002         CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR));
2003         MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len);
2004     }
2005
2006     read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0);
2007     if (read_len)
2008     {
2009         ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR));
2010         MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len);
2011     }
2012
2013     rc =  ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len,
2014                                    ReadBuffer, read_len);
2015
2016     HeapFree(GetProcessHeap(), 0, CompBuffer);
2017     HeapFree(GetProcessHeap(), 0, ReadBuffer);
2018
2019     return rc;
2020 }
2021
2022 /***********************************************************************
2023  *              ImmSetCompositionStringW (IMM32.@)
2024  */
2025 BOOL WINAPI ImmSetCompositionStringW(
2026         HIMC hIMC, DWORD dwIndex,
2027         LPCVOID lpComp, DWORD dwCompLen,
2028         LPCVOID lpRead, DWORD dwReadLen)
2029 {
2030      DWORD flags = 0;
2031      WCHAR wParam  = 0;
2032
2033      TRACE("(%p, %d, %p, %d, %p, %d): stub\n",
2034              hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
2035
2036
2037      if (hIMC != (HIMC)FROM_IME)
2038          FIXME("PROBLEM: This only sets the wine level string\n");
2039
2040      /*
2041       * Explanation:
2042       *  this sets the composition string in the imm32.dll level
2043       *  of the composition buffer. we cannot manipulate the xim level
2044       *  buffer, which means that once the xim level buffer changes again
2045       *  any call to this function from the application will be lost
2046       */
2047
2048      if (lpRead && dwReadLen)
2049          FIXME("Reading string unimplemented\n");
2050
2051      /*
2052       * app operating this api to also receive the message from xim
2053       */
2054
2055     if (dwIndex == SCS_SETSTR)
2056     {
2057         HIMCC newCompStr;
2058         if (!root_context->bInComposition)
2059         {
2060             ImmInternalPostIMEMessage(root_context, WM_IME_STARTCOMPOSITION, 0, 0);
2061             root_context->bInComposition = TRUE;
2062         }
2063
2064         flags = GCS_COMPSTR;
2065
2066         if (dwCompLen && lpComp)
2067         {
2068             newCompStr = updateCompStr(root_context->IMC.hCompStr, (LPWSTR)lpComp, dwCompLen / sizeof(WCHAR));
2069             ImmDestroyIMCC(root_context->IMC.hCompStr);
2070             root_context->IMC.hCompStr = newCompStr;
2071
2072              wParam = ((const WCHAR*)lpComp)[0];
2073              flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART;
2074         }
2075         else
2076         {
2077             newCompStr = updateCompStr(root_context->IMC.hCompStr, NULL, 0);
2078             ImmDestroyIMCC(root_context->IMC.hCompStr);
2079             root_context->IMC.hCompStr = newCompStr;
2080         }
2081     }
2082
2083      UpdateDataInDefaultIMEWindow(hwndDefault,FALSE);
2084
2085      ImmInternalPostIMEMessage(root_context, WM_IME_COMPOSITION, wParam, flags);
2086
2087      return TRUE;
2088 }
2089
2090 /***********************************************************************
2091  *              ImmSetCompositionWindow (IMM32.@)
2092  */
2093 BOOL WINAPI ImmSetCompositionWindow(
2094   HIMC hIMC, LPCOMPOSITIONFORM lpCompForm)
2095 {
2096     BOOL reshow = FALSE;
2097     InputContextData *data = (InputContextData*)hIMC;
2098
2099     TRACE("(%p, %p)\n", hIMC, lpCompForm);
2100     TRACE("\t%x, (%i,%i), (%i,%i - %i,%i)\n",lpCompForm->dwStyle,
2101           lpCompForm->ptCurrentPos.x, lpCompForm->ptCurrentPos.y, lpCompForm->rcArea.top,
2102           lpCompForm->rcArea.left, lpCompForm->rcArea.bottom, lpCompForm->rcArea.right);
2103
2104     if (!data)
2105         return FALSE;
2106
2107     data->IMC.cfCompForm = *lpCompForm;
2108
2109     if (IsWindowVisible(hwndDefault))
2110     {
2111         reshow = TRUE;
2112         ShowWindow(hwndDefault,SW_HIDE);
2113     }
2114
2115     /* FIXME: this is a partial stub */
2116
2117     if (reshow)
2118         ShowWindow(hwndDefault,SW_SHOWNOACTIVATE);
2119
2120     ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0);
2121     return TRUE;
2122 }
2123
2124 /***********************************************************************
2125  *              ImmSetConversionStatus (IMM32.@)
2126  */
2127 BOOL WINAPI ImmSetConversionStatus(
2128   HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence)
2129 {
2130   static int shown = 0;
2131
2132   if (!shown) {
2133       FIXME("(%p, %d, %d): stub\n",
2134           hIMC, fdwConversion, fdwSentence
2135       );
2136       shown = 1;
2137   }
2138   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2139   return FALSE;
2140 }
2141
2142 /***********************************************************************
2143  *              ImmSetOpenStatus (IMM32.@)
2144  */
2145 BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen)
2146 {
2147     InputContextData *data = (InputContextData*)hIMC;
2148
2149     TRACE("%p %d\n", hIMC, fOpen);
2150
2151     if (hIMC == (HIMC)FROM_IME)
2152     {
2153         ImmInternalSetOpenStatus(fOpen);
2154         ImmInternalSendIMENotify(root_context, IMN_SETOPENSTATUS, 0);
2155         return TRUE;
2156     }
2157
2158     if (!data)
2159         return FALSE;
2160
2161     if (fOpen != data->bInternalState)
2162     {
2163         if (fOpen == FALSE && pX11DRV_ForceXIMReset)
2164             pX11DRV_ForceXIMReset(data->IMC.hWnd);
2165
2166         if (fOpen == FALSE)
2167             ImmInternalPostIMEMessage(data, WM_IME_ENDCOMPOSITION,0,0);
2168         else
2169             ImmInternalPostIMEMessage(data, WM_IME_STARTCOMPOSITION,0,0);
2170
2171         ImmInternalSetOpenStatus(fOpen);
2172         ImmInternalSetOpenStatus(!fOpen);
2173
2174         if (data->IMC.fOpen == FALSE)
2175             ImmInternalPostIMEMessage(data, WM_IME_ENDCOMPOSITION,0,0);
2176         else
2177             ImmInternalPostIMEMessage(data, WM_IME_STARTCOMPOSITION,0,0);
2178
2179         return FALSE;
2180     }
2181     return TRUE;
2182 }
2183
2184 /***********************************************************************
2185  *              ImmSetStatusWindowPos (IMM32.@)
2186  */
2187 BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos)
2188 {
2189   FIXME("(%p, %p): stub\n", hIMC, lpptPos);
2190   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2191   return FALSE;
2192 }
2193
2194 /***********************************************************************
2195  *              ImmSimulateHotKey (IMM32.@)
2196  */
2197 BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID)
2198 {
2199   FIXME("(%p, %d): stub\n", hWnd, dwHotKeyID);
2200   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2201   return FALSE;
2202 }
2203
2204 /***********************************************************************
2205  *              ImmUnregisterWordA (IMM32.@)
2206  */
2207 BOOL WINAPI ImmUnregisterWordA(
2208   HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister)
2209 {
2210   FIXME("(%p, %s, %d, %s): stub\n",
2211     hKL, debugstr_a(lpszReading), dwStyle, debugstr_a(lpszUnregister)
2212   );
2213   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2214   return FALSE;
2215 }
2216
2217 /***********************************************************************
2218  *              ImmUnregisterWordW (IMM32.@)
2219  */
2220 BOOL WINAPI ImmUnregisterWordW(
2221   HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister)
2222 {
2223   FIXME("(%p, %s, %d, %s): stub\n",
2224     hKL, debugstr_w(lpszReading), dwStyle, debugstr_w(lpszUnregister)
2225   );
2226   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2227   return FALSE;
2228 }
2229
2230 /***********************************************************************
2231  *              ImmGetImeMenuItemsA (IMM32.@)
2232  */
2233 DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2234    LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu,
2235     DWORD dwSize)
2236 {
2237     InputContextData *data = (InputContextData*)hIMC;
2238     TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
2239         lpImeParentMenu, lpImeMenu, dwSize);
2240     if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2241     {
2242         if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2243             return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2244                                 (IMEMENUITEMINFOW*)lpImeParentMenu,
2245                                 (IMEMENUITEMINFOW*)lpImeMenu, dwSize);
2246         else
2247         {
2248             IMEMENUITEMINFOW lpImeParentMenuW;
2249             IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL;
2250             DWORD rc;
2251
2252             if (lpImeParentMenu)
2253                 parent = &lpImeParentMenuW;
2254             if (lpImeMenu)
2255             {
2256                 int count = dwSize / sizeof(LPIMEMENUITEMINFOA);
2257                 dwSize = count * sizeof(IMEMENUITEMINFOW);
2258                 lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize);
2259             }
2260             else
2261                 lpImeMenuW = NULL;
2262
2263             rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2264                                 parent, lpImeMenuW, dwSize);
2265
2266             if (lpImeParentMenu)
2267             {
2268                 memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA));
2269                 lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem;
2270                 WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString,
2271                     -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE,
2272                     NULL, NULL);
2273             }
2274             if (lpImeMenu && rc)
2275             {
2276                 int i;
2277                 for (i = 0; i < rc; i++)
2278                 {
2279                     memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA));
2280                     lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem;
2281                     WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString,
2282                         -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE,
2283                         NULL, NULL);
2284                 }
2285             }
2286             HeapFree(GetProcessHeap(),0,lpImeMenuW);
2287             return rc;
2288         }
2289     }
2290     else
2291         return 0;
2292 }
2293
2294 /***********************************************************************
2295 *               ImmGetImeMenuItemsW (IMM32.@)
2296 */
2297 DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType,
2298    LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
2299    DWORD dwSize)
2300 {
2301     InputContextData *data = (InputContextData*)hIMC;
2302     TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType,
2303         lpImeParentMenu, lpImeMenu, dwSize);
2304     if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems)
2305     {
2306         if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu))
2307             return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2308                                 lpImeParentMenu, lpImeMenu, dwSize);
2309         else
2310         {
2311             IMEMENUITEMINFOA lpImeParentMenuA;
2312             IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL;
2313             DWORD rc;
2314
2315             if (lpImeParentMenu)
2316                 parent = &lpImeParentMenuA;
2317             if (lpImeMenu)
2318             {
2319                 int count = dwSize / sizeof(LPIMEMENUITEMINFOW);
2320                 dwSize = count * sizeof(IMEMENUITEMINFOA);
2321                 lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize);
2322             }
2323             else
2324                 lpImeMenuA = NULL;
2325
2326             rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType,
2327                                 (IMEMENUITEMINFOW*)parent,
2328                                 (IMEMENUITEMINFOW*)lpImeMenuA, dwSize);
2329
2330             if (lpImeParentMenu)
2331             {
2332                 memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA));
2333                 lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem;
2334                 MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString,
2335                     -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE);
2336             }
2337             if (lpImeMenu && rc)
2338             {
2339                 int i;
2340                 for (i = 0; i < rc; i++)
2341                 {
2342                     memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA));
2343                     lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem;
2344                     MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString,
2345                         -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE);
2346                 }
2347             }
2348             HeapFree(GetProcessHeap(),0,lpImeMenuA);
2349             return rc;
2350         }
2351     }
2352     else
2353         return 0;
2354 }
2355
2356 /***********************************************************************
2357 *               ImmLockIMC(IMM32.@)
2358 */
2359 LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC)
2360 {
2361     InputContextData *data = (InputContextData*)hIMC;
2362
2363     if (!data)
2364         return NULL;
2365     data->dwLock++;
2366     return &data->IMC;
2367 }
2368
2369 /***********************************************************************
2370 *               ImmUnlockIMC(IMM32.@)
2371 */
2372 BOOL WINAPI ImmUnlockIMC(HIMC hIMC)
2373 {
2374     InputContextData *data = (InputContextData*)hIMC;
2375     data->dwLock--;
2376     return (data->dwLock!=0);
2377 }
2378
2379 /***********************************************************************
2380 *               ImmGetIMCLockCount(IMM32.@)
2381 */
2382 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
2383 {
2384     InputContextData *data = (InputContextData*)hIMC;
2385     return data->dwLock;
2386 }
2387
2388 /***********************************************************************
2389 *               ImmCreateIMCC(IMM32.@)
2390 */
2391 HIMCC  WINAPI ImmCreateIMCC(DWORD size)
2392 {
2393     IMCCInternal *internal;
2394     int real_size = size + sizeof(IMCCInternal);
2395
2396     internal = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, real_size);
2397     if (internal == NULL)
2398         return NULL;
2399
2400     internal->dwSize = size;
2401     return  (HIMCC)internal;
2402 }
2403
2404 /***********************************************************************
2405 *       ImmDestroyIMCC(IMM32.@)
2406 */
2407 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
2408 {
2409     HeapFree(GetProcessHeap(),0,block);
2410     return NULL;
2411 }
2412
2413 /***********************************************************************
2414 *               ImmLockIMCC(IMM32.@)
2415 */
2416 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
2417 {
2418     IMCCInternal *internal;
2419     internal = (IMCCInternal*) imcc;
2420
2421     internal->dwLock ++;
2422     return internal + 1;
2423 }
2424
2425 /***********************************************************************
2426 *               ImmUnlockIMCC(IMM32.@)
2427 */
2428 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
2429 {
2430     IMCCInternal *internal;
2431     internal = (IMCCInternal*) imcc;
2432
2433     internal->dwLock --;
2434     return (internal->dwLock!=0);
2435 }
2436
2437 /***********************************************************************
2438 *               ImmGetIMCCLockCount(IMM32.@)
2439 */
2440 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
2441 {
2442     IMCCInternal *internal;
2443     internal = (IMCCInternal*) imcc;
2444
2445     return internal->dwLock;
2446 }
2447
2448 /***********************************************************************
2449 *               ImmReSizeIMCC(IMM32.@)
2450 */
2451 HIMCC  WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
2452 {
2453     IMCCInternal *internal,*newone;
2454     int real_size = size + sizeof(IMCCInternal);
2455
2456     internal = (IMCCInternal*) imcc;
2457
2458     newone = HeapReAlloc(GetProcessHeap(), 0, internal, real_size);
2459     newone->dwSize = size;
2460
2461     return newone;
2462 }
2463
2464 /***********************************************************************
2465 *               ImmGetIMCCSize(IMM32.@)
2466 */
2467 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
2468 {
2469     IMCCInternal *internal;
2470     internal = (IMCCInternal*) imcc;
2471
2472     return internal->dwSize;
2473 }
2474
2475 /***********************************************************************
2476 *               ImmGenerateMessage(IMM32.@)
2477 */
2478 BOOL WINAPI ImmGenerateMessage(HIMC hIMC)
2479 {
2480     InputContextData *data = (InputContextData*)hIMC;
2481
2482     TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf);
2483     if (data->IMC.dwNumMsgBuf > 0)
2484     {
2485         LPTRANSMSG lpTransMsg;
2486         INT i;
2487
2488         lpTransMsg = (LPTRANSMSG)ImmLockIMCC(data->IMC.hMsgBuf);
2489         for (i = 0; i < data->IMC.dwNumMsgBuf; i++)
2490             ImmInternalPostIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam);
2491
2492         ImmUnlockIMCC(data->IMC.hMsgBuf);
2493
2494         data->IMC.dwNumMsgBuf = 0;
2495     }
2496
2497     return TRUE;
2498 }
2499
2500 /*****
2501  * Internal functions to help with IME window management
2502  */
2503 static void PaintDefaultIMEWnd(HWND hwnd)
2504 {
2505     PAINTSTRUCT ps;
2506     RECT rect;
2507     HDC hdc = BeginPaint(hwnd,&ps);
2508     LPCOMPOSITIONSTRING compstr;
2509     LPBYTE compdata = NULL;
2510     HMONITOR monitor;
2511     MONITORINFO mon_info;
2512     INT offX=0, offY=0;
2513
2514     GetClientRect(hwnd,&rect);
2515     FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1));
2516
2517     compdata = ImmLockIMCC(root_context->IMC.hCompStr);
2518     compstr = (LPCOMPOSITIONSTRING)compdata;
2519
2520     if (compstr->dwCompStrLen && compstr->dwCompStrOffset)
2521     {
2522         SIZE size;
2523         POINT pt;
2524         HFONT oldfont = NULL;
2525         LPWSTR CompString;
2526
2527         CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset);
2528         if (root_context->textfont)
2529             oldfont = SelectObject(hdc,root_context->textfont);
2530
2531
2532         GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size);
2533         pt.x = size.cx;
2534         pt.y = size.cy;
2535         LPtoDP(hdc,&pt,1);
2536
2537         /*
2538          * How this works based on tests on windows:
2539          * CFS_POINT: then we start our window at the point and grow it as large
2540          *    as it needs to be for the string.
2541          * CFS_RECT:  we still use the ptCurrentPos as a starting point and our
2542          *    window is only as large as we need for the string, but we do not
2543          *    grow such that our window exceeds the given rect.  Wrapping if
2544          *    needed and possible.   If our ptCurrentPos is outside of our rect
2545          *    then no window is displayed.
2546          * CFS_FORCE_POSITION: appears to behave just like CFS_POINT
2547          *    maybe becase the default MSIME does not do any IME adjusting.
2548          */
2549         if (root_context->IMC.cfCompForm.dwStyle != CFS_DEFAULT)
2550         {
2551             POINT cpt = root_context->IMC.cfCompForm.ptCurrentPos;
2552             ClientToScreen(root_context->IMC.hWnd,&cpt);
2553             rect.left = cpt.x;
2554             rect.top = cpt.y;
2555             rect.right = rect.left + pt.x;
2556             rect.bottom = rect.top + pt.y;
2557             monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY);
2558         }
2559         else /* CFS_DEFAULT */
2560         {
2561             /* Windows places the default IME window in the bottom left */
2562             HWND target = root_context->IMC.hWnd;
2563             if (!target) target = GetFocus();
2564
2565             GetWindowRect(target,&rect);
2566             rect.top = rect.bottom;
2567             rect.right = rect.left + pt.x + 20;
2568             rect.bottom = rect.top + pt.y + 20;
2569             offX=offY=10;
2570             monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY);
2571         }
2572
2573         if (root_context->IMC.cfCompForm.dwStyle == CFS_RECT)
2574         {
2575             RECT client;
2576             client =root_context->IMC.cfCompForm.rcArea;
2577             MapWindowPoints( root_context->IMC.hWnd, 0, (POINT *)&client, 2 );
2578             IntersectRect(&rect,&rect,&client);
2579             /* TODO:  Wrap the input if needed */
2580         }
2581
2582         if (root_context->IMC.cfCompForm.dwStyle == CFS_DEFAULT)
2583         {
2584             /* make sure we are on the desktop */
2585             mon_info.cbSize = sizeof(mon_info);
2586             GetMonitorInfoW(monitor, &mon_info);
2587
2588             if (rect.bottom > mon_info.rcWork.bottom)
2589             {
2590                 int shift = rect.bottom - mon_info.rcWork.bottom;
2591                 rect.top -= shift;
2592                 rect.bottom -= shift;
2593             }
2594             if (rect.left < 0)
2595             {
2596                 rect.right -= rect.left;
2597                 rect.left = 0;
2598             }
2599             if (rect.right > mon_info.rcWork.right)
2600             {
2601                 int shift = rect.right - mon_info.rcWork.right;
2602                 rect.left -= shift;
2603                 rect.right -= shift;
2604             }
2605         }
2606
2607         SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE);
2608
2609         TextOutW(hdc, offX,offY, CompString, compstr->dwCompStrLen);
2610
2611         if (oldfont)
2612             SelectObject(hdc,oldfont);
2613     }
2614
2615     ImmUnlockIMCC(root_context->IMC.hCompStr);
2616
2617     EndPaint(hwnd,&ps);
2618 }
2619
2620 static void UpdateDataInDefaultIMEWindow(HWND hwnd, BOOL showable)
2621 {
2622     LPCOMPOSITIONSTRING compstr;
2623
2624     if (root_context->IMC.hCompStr)
2625         compstr = ImmLockIMCC(root_context->IMC.hCompStr);
2626     else
2627         compstr = NULL;
2628
2629     if (compstr == NULL || compstr->dwCompStrLen == 0)
2630         ShowWindow(hwndDefault,SW_HIDE);
2631     else if (showable)
2632         ShowWindow(hwndDefault,SW_SHOWNOACTIVATE);
2633
2634     RedrawWindow(hwnd,NULL,NULL,RDW_ERASENOW|RDW_INVALIDATE);
2635
2636     if (compstr != NULL)
2637         ImmUnlockIMCC(root_context->IMC.hCompStr);
2638 }
2639
2640 /*
2641  * The window proc for the default IME window
2642  */
2643 static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
2644                                           LPARAM lParam)
2645 {
2646     LRESULT rc = 0;
2647
2648     TRACE("Incoming Message 0x%x  (0x%08x, 0x%08x)\n", msg, (UINT)wParam,
2649            (UINT)lParam);
2650
2651     switch(msg)
2652     {
2653         case WM_PAINT:
2654             PaintDefaultIMEWnd(hwnd);
2655             return FALSE;
2656
2657         case WM_NCCREATE:
2658             return TRUE;
2659
2660         case WM_CREATE:
2661             SetWindowTextA(hwnd,"Wine Ime Active");
2662             return TRUE;
2663
2664         case WM_SETFOCUS:
2665             if (wParam)
2666                 SetFocus((HWND)wParam);
2667             else
2668                 FIXME("Received focus, should never have focus\n");
2669             break;
2670         case WM_IME_COMPOSITION:
2671             TRACE("IME message %s, 0x%x, 0x%x (%i)\n",
2672                     "WM_IME_COMPOSITION", (UINT)wParam, (UINT)lParam,
2673                      root_context->bRead);
2674             if (lParam & GCS_RESULTSTR)
2675                     IMM_PostResult(root_context);
2676             else
2677                  UpdateDataInDefaultIMEWindow(hwnd,TRUE);
2678             break;
2679         case WM_IME_STARTCOMPOSITION:
2680             TRACE("IME message %s, 0x%x, 0x%x\n",
2681                     "WM_IME_STARTCOMPOSITION", (UINT)wParam, (UINT)lParam);
2682             root_context->IMC.hWnd = GetFocus();
2683             ShowWindow(hwndDefault,SW_SHOWNOACTIVATE);
2684             break;
2685         case WM_IME_ENDCOMPOSITION:
2686             TRACE("IME message %s, 0x%x, 0x%x\n",
2687                     "WM_IME_ENDCOMPOSITION", (UINT)wParam, (UINT)lParam);
2688             ShowWindow(hwndDefault,SW_HIDE);
2689             break;
2690         case WM_IME_SELECT:
2691             TRACE("IME message %s, 0x%x, 0x%x\n","WM_IME_SELECT",
2692                 (UINT)wParam, (UINT)lParam);
2693             break;
2694         case WM_IME_CONTROL:
2695             TRACE("IME message %s, 0x%x, 0x%x\n","WM_IME_CONTROL",
2696                 (UINT)wParam, (UINT)lParam);
2697             rc = 1;
2698             break;
2699         case WM_IME_NOTIFY:
2700             TRACE("!! IME NOTIFY\n");
2701             break;
2702        default:
2703             TRACE("Non-standard message 0x%x\n",msg);
2704     }
2705     /* check the MSIME messages */
2706     if (msg == WM_MSIME_SERVICE)
2707     {
2708             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_SERVICE",
2709                 (UINT)wParam, (UINT)lParam);
2710             rc = FALSE;
2711     }
2712     else if (msg == WM_MSIME_RECONVERTOPTIONS)
2713     {
2714             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_RECONVERTOPTIONS",
2715                 (UINT)wParam, (UINT)lParam);
2716     }
2717     else if (msg == WM_MSIME_MOUSE)
2718     {
2719             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_MOUSE",
2720                 (UINT)wParam, (UINT)lParam);
2721     }
2722     else if (msg == WM_MSIME_RECONVERTREQUEST)
2723     {
2724             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_RECONVERTREQUEST",
2725                 (UINT)wParam, (UINT)lParam);
2726     }
2727     else if (msg == WM_MSIME_RECONVERT)
2728     {
2729             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_RECONVERT",
2730                 (UINT)wParam, (UINT)lParam);
2731     }
2732     else if (msg == WM_MSIME_QUERYPOSITION)
2733     {
2734             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_QUERYPOSITION",
2735                 (UINT)wParam, (UINT)lParam);
2736     }
2737     else if (msg == WM_MSIME_DOCUMENTFEED)
2738     {
2739             TRACE("IME message %s, 0x%x, 0x%x\n","WM_MSIME_DOCUMENTFEED",
2740                 (UINT)wParam, (UINT)lParam);
2741     }
2742     /* DefWndProc if not an IME message */
2743     else if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) ||
2744                       (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP)))
2745         rc = DefWindowProcW(hwnd,msg,wParam,lParam);
2746
2747     return rc;
2748 }