|  | /* | 
|  | * IMM32 library | 
|  | * | 
|  | * Copyright 1998 Patrik Stridvall | 
|  | * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "wingdi.h" | 
|  | #include "winuser.h" | 
|  | #include "winerror.h" | 
|  | #include "wine/debug.h" | 
|  | #include "imm.h" | 
|  | #include "ddk/imm.h" | 
|  | #include "winnls.h" | 
|  | #include "winreg.h" | 
|  | #include "wine/list.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(imm); | 
|  |  | 
|  | typedef struct tagIMCCInternal | 
|  | { | 
|  | DWORD dwLock; | 
|  | DWORD dwSize; | 
|  | } IMCCInternal; | 
|  |  | 
|  | #define MAKE_FUNCPTR(f) typeof(f) * p##f | 
|  | typedef struct _tagImmHkl{ | 
|  | struct list entry; | 
|  | HKL         hkl; | 
|  | HMODULE     hIME; | 
|  | IMEINFO     imeInfo; | 
|  | WCHAR       imeClassName[17]; /* 16 character max */ | 
|  | ULONG       uSelected; | 
|  |  | 
|  | /* Function Pointers */ | 
|  | MAKE_FUNCPTR(ImeInquire); | 
|  | MAKE_FUNCPTR(ImeConfigure); | 
|  | MAKE_FUNCPTR(ImeDestroy); | 
|  | MAKE_FUNCPTR(ImeEscape); | 
|  | MAKE_FUNCPTR(ImeSelect); | 
|  | MAKE_FUNCPTR(ImeSetActiveContext); | 
|  | MAKE_FUNCPTR(ImeToAsciiEx); | 
|  | MAKE_FUNCPTR(NotifyIME); | 
|  | MAKE_FUNCPTR(ImeRegisterWord); | 
|  | MAKE_FUNCPTR(ImeUnregisterWord); | 
|  | MAKE_FUNCPTR(ImeEnumRegisterWord); | 
|  | MAKE_FUNCPTR(ImeSetCompositionString); | 
|  | MAKE_FUNCPTR(ImeConversionList); | 
|  | MAKE_FUNCPTR(ImeProcessKey); | 
|  | MAKE_FUNCPTR(ImeGetRegisterWordStyle); | 
|  | MAKE_FUNCPTR(ImeGetImeMenuItems); | 
|  | } ImmHkl; | 
|  | #undef MAKE_FUNCPTR | 
|  |  | 
|  | typedef struct tagInputContextData | 
|  | { | 
|  | DWORD           dwLock; | 
|  | INPUTCONTEXT    IMC; | 
|  |  | 
|  | ImmHkl          *immKbd; | 
|  | HWND            imeWnd; | 
|  | UINT            lastVK; | 
|  | } InputContextData; | 
|  |  | 
|  | typedef struct _tagTRANSMSG { | 
|  | UINT message; | 
|  | WPARAM wParam; | 
|  | LPARAM lParam; | 
|  | } TRANSMSG, *LPTRANSMSG; | 
|  |  | 
|  | typedef struct _tagIMMThreadData { | 
|  | HIMC defaultContext; | 
|  | HWND hwndDefault; | 
|  | } IMMThreadData; | 
|  |  | 
|  | static DWORD tlsIndex = 0; | 
|  | static struct list ImmHklList = LIST_INIT(ImmHklList); | 
|  |  | 
|  | /* MSIME messages */ | 
|  | static UINT WM_MSIME_SERVICE; | 
|  | static UINT WM_MSIME_RECONVERTOPTIONS; | 
|  | static UINT WM_MSIME_MOUSE; | 
|  | static UINT WM_MSIME_RECONVERTREQUEST; | 
|  | static UINT WM_MSIME_RECONVERT; | 
|  | static UINT WM_MSIME_QUERYPOSITION; | 
|  | static UINT WM_MSIME_DOCUMENTFEED; | 
|  |  | 
|  | static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0}; | 
|  |  | 
|  | static const WCHAR szImeFileW[] = {'I','m','e',' ','F','i','l','e',0}; | 
|  | static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t',0}; | 
|  | static const WCHAR szImeRegFmt[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s','\\','%','0','8','l','x',0}; | 
|  |  | 
|  |  | 
|  | #define is_himc_ime_unicode(p)  (p->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE) | 
|  | #define is_kbd_ime_unicode(p)  (p->imeInfo.fdwProperty & IME_PROP_UNICODE) | 
|  |  | 
|  | static BOOL IMM_DestroyContext(HIMC hIMC); | 
|  |  | 
|  | static inline WCHAR *strdupAtoW( const char *str ) | 
|  | { | 
|  | WCHAR *ret = NULL; | 
|  | if (str) | 
|  | { | 
|  | DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); | 
|  | if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) | 
|  | MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static inline CHAR *strdupWtoA( const WCHAR *str ) | 
|  | { | 
|  | CHAR *ret = NULL; | 
|  | if (str) | 
|  | { | 
|  | DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); | 
|  | if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) | 
|  | WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static DWORD convert_candidatelist_WtoA( | 
|  | LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen) | 
|  | { | 
|  | DWORD ret, i, len; | 
|  |  | 
|  | ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] ); | 
|  | if ( lpDst && dwBufLen > 0 ) | 
|  | { | 
|  | *lpDst = *lpSrc; | 
|  | lpDst->dwOffset[0] = ret; | 
|  | } | 
|  |  | 
|  | for ( i = 0; i < lpSrc->dwCount; i++) | 
|  | { | 
|  | LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i]; | 
|  |  | 
|  | if ( lpDst && dwBufLen > 0 ) | 
|  | { | 
|  | LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i]; | 
|  |  | 
|  | len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, | 
|  | (LPSTR)dest, dwBufLen, NULL, NULL); | 
|  |  | 
|  | if ( i + 1 < lpSrc->dwCount ) | 
|  | lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(char); | 
|  | dwBufLen -= len * sizeof(char); | 
|  | } | 
|  | else | 
|  | len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, NULL, 0, NULL, NULL); | 
|  |  | 
|  | ret += len * sizeof(char); | 
|  | } | 
|  |  | 
|  | if ( lpDst ) | 
|  | lpDst->dwSize = ret; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static DWORD convert_candidatelist_AtoW( | 
|  | LPCANDIDATELIST lpSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen) | 
|  | { | 
|  | DWORD ret, i, len; | 
|  |  | 
|  | ret = FIELD_OFFSET( CANDIDATELIST, dwOffset[lpSrc->dwCount] ); | 
|  | if ( lpDst && dwBufLen > 0 ) | 
|  | { | 
|  | *lpDst = *lpSrc; | 
|  | lpDst->dwOffset[0] = ret; | 
|  | } | 
|  |  | 
|  | for ( i = 0; i < lpSrc->dwCount; i++) | 
|  | { | 
|  | LPBYTE src = (LPBYTE)lpSrc + lpSrc->dwOffset[i]; | 
|  |  | 
|  | if ( lpDst && dwBufLen > 0 ) | 
|  | { | 
|  | LPBYTE dest = (LPBYTE)lpDst + lpDst->dwOffset[i]; | 
|  |  | 
|  | len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, | 
|  | (LPWSTR)dest, dwBufLen); | 
|  |  | 
|  | if ( i + 1 < lpSrc->dwCount ) | 
|  | lpDst->dwOffset[i+1] = lpDst->dwOffset[i] + len * sizeof(WCHAR); | 
|  | dwBufLen -= len * sizeof(WCHAR); | 
|  | } | 
|  | else | 
|  | len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, NULL, 0); | 
|  |  | 
|  | ret += len * sizeof(WCHAR); | 
|  | } | 
|  |  | 
|  | if ( lpDst ) | 
|  | lpDst->dwSize = ret; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static IMMThreadData* IMM_GetThreadData(void) | 
|  | { | 
|  | IMMThreadData* data = TlsGetValue(tlsIndex); | 
|  | if (!data) | 
|  | { | 
|  | data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, | 
|  | sizeof(IMMThreadData)); | 
|  | TlsSetValue(tlsIndex,data); | 
|  | TRACE("Thread Data Created\n"); | 
|  | } | 
|  | return data; | 
|  | } | 
|  |  | 
|  | static void IMM_FreeThreadData(void) | 
|  | { | 
|  | IMMThreadData* data = TlsGetValue(tlsIndex); | 
|  | if (data) | 
|  | { | 
|  | IMM_DestroyContext(data->defaultContext); | 
|  | DestroyWindow(data->hwndDefault); | 
|  | HeapFree(GetProcessHeap(),0,data); | 
|  | TRACE("Thread Data Destroyed\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static HMODULE LoadDefaultWineIME(void) | 
|  | { | 
|  | char buffer[MAX_PATH], libname[32], *name, *next; | 
|  | HMODULE module = 0; | 
|  | HKEY hkey; | 
|  |  | 
|  | TRACE("Attempting to fall back to wine default IME\n"); | 
|  |  | 
|  | strcpy( buffer, "x11" );  /* default value */ | 
|  | /* @@ Wine registry key: HKCU\Software\Wine\Drivers */ | 
|  | if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Drivers", &hkey )) | 
|  | { | 
|  | DWORD type, count = sizeof(buffer); | 
|  | RegQueryValueExA( hkey, "Ime", 0, &type, (LPBYTE) buffer, &count ); | 
|  | RegCloseKey( hkey ); | 
|  | } | 
|  |  | 
|  | name = buffer; | 
|  | while (name) | 
|  | { | 
|  | next = strchr( name, ',' ); | 
|  | if (next) *next++ = 0; | 
|  |  | 
|  | snprintf( libname, sizeof(libname), "wine%s.drv", name ); | 
|  | if ((module = LoadLibraryA( libname )) != 0) break; | 
|  | name = next; | 
|  | } | 
|  |  | 
|  | return module; | 
|  | } | 
|  |  | 
|  | /* ImmHkl loading and freeing */ | 
|  | #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);} | 
|  | static ImmHkl *IMM_GetImmHkl(HKL hkl) | 
|  | { | 
|  | ImmHkl *ptr; | 
|  | WCHAR filename[MAX_PATH]; | 
|  |  | 
|  | TRACE("Seeking ime for keyboard %p\n",hkl); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry) | 
|  | { | 
|  | if (ptr->hkl == hkl) | 
|  | return ptr; | 
|  | } | 
|  | /* not found... create it */ | 
|  |  | 
|  | ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl)); | 
|  |  | 
|  | ptr->hkl = hkl; | 
|  | if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename); | 
|  | if (!ptr->hIME) | 
|  | ptr->hIME = LoadDefaultWineIME(); | 
|  | if (ptr->hIME) | 
|  | { | 
|  | LOAD_FUNCPTR(ImeInquire); | 
|  | if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL)) | 
|  | { | 
|  | FreeLibrary(ptr->hIME); | 
|  | ptr->hIME = NULL; | 
|  | } | 
|  | else | 
|  | { | 
|  | LOAD_FUNCPTR(ImeDestroy); | 
|  | LOAD_FUNCPTR(ImeSelect); | 
|  | if (!ptr->pImeSelect || !ptr->pImeDestroy) | 
|  | { | 
|  | FreeLibrary(ptr->hIME); | 
|  | ptr->hIME = NULL; | 
|  | } | 
|  | else | 
|  | { | 
|  | LOAD_FUNCPTR(ImeConfigure); | 
|  | LOAD_FUNCPTR(ImeEscape); | 
|  | LOAD_FUNCPTR(ImeSetActiveContext); | 
|  | LOAD_FUNCPTR(ImeToAsciiEx); | 
|  | LOAD_FUNCPTR(NotifyIME); | 
|  | LOAD_FUNCPTR(ImeRegisterWord); | 
|  | LOAD_FUNCPTR(ImeUnregisterWord); | 
|  | LOAD_FUNCPTR(ImeEnumRegisterWord); | 
|  | LOAD_FUNCPTR(ImeSetCompositionString); | 
|  | LOAD_FUNCPTR(ImeConversionList); | 
|  | LOAD_FUNCPTR(ImeProcessKey); | 
|  | LOAD_FUNCPTR(ImeGetRegisterWordStyle); | 
|  | LOAD_FUNCPTR(ImeGetImeMenuItems); | 
|  | /* make sure our classname is WCHAR */ | 
|  | if (!is_kbd_ime_unicode(ptr)) | 
|  | { | 
|  | WCHAR bufW[17]; | 
|  | MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName, | 
|  | -1, bufW, 17); | 
|  | lstrcpyW(ptr->imeClassName, bufW); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | list_add_head(&ImmHklList,&ptr->entry); | 
|  |  | 
|  | return ptr; | 
|  | } | 
|  | #undef LOAD_FUNCPTR | 
|  |  | 
|  | static void IMM_FreeAllImmHkl(void) | 
|  | { | 
|  | ImmHkl *ptr,*cursor2; | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &ImmHklList, ImmHkl, entry) | 
|  | { | 
|  | list_remove(&ptr->entry); | 
|  | if (ptr->hIME) | 
|  | { | 
|  | ptr->pImeDestroy(1); | 
|  | FreeLibrary(ptr->hIME); | 
|  | } | 
|  | HeapFree(GetProcessHeap(),0,ptr); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void IMM_RegisterMessages(void) | 
|  | { | 
|  | WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService"); | 
|  | WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions"); | 
|  | WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation"); | 
|  | WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest"); | 
|  | WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert"); | 
|  | WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition"); | 
|  | WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed"); | 
|  | } | 
|  |  | 
|  | BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved) | 
|  | { | 
|  | TRACE("%p, %x, %p\n",hInstDLL,fdwReason,lpReserved); | 
|  | switch (fdwReason) | 
|  | { | 
|  | case DLL_PROCESS_ATTACH: | 
|  | IMM_RegisterMessages(); | 
|  | tlsIndex = TlsAlloc(); | 
|  | if (tlsIndex == TLS_OUT_OF_INDEXES) | 
|  | return FALSE; | 
|  | break; | 
|  | case DLL_THREAD_ATTACH: | 
|  | break; | 
|  | case DLL_THREAD_DETACH: | 
|  | IMM_FreeThreadData(); | 
|  | break; | 
|  | case DLL_PROCESS_DETACH: | 
|  | IMM_FreeThreadData(); | 
|  | IMM_FreeAllImmHkl(); | 
|  | TlsFree(tlsIndex); | 
|  | break; | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /* for posting messages as the IME */ | 
|  | static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | HWND target = GetFocus(); | 
|  | if (!target) | 
|  | PostMessageW(data->IMC.hWnd,msg,wParam,lParam); | 
|  | else | 
|  | PostMessageW(target, msg, wParam, lParam); | 
|  | } | 
|  |  | 
|  | static LRESULT ImmInternalSendIMENotify(InputContextData *data, WPARAM notify, LPARAM lParam) | 
|  | { | 
|  | HWND target; | 
|  |  | 
|  | target = data->IMC.hWnd; | 
|  | if (!target) target = GetFocus(); | 
|  |  | 
|  | if (target) | 
|  | return SendMessageW(target, WM_IME_NOTIFY, notify, lParam); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static HIMCC ImmCreateBlankCompStr(void) | 
|  | { | 
|  | HIMCC rc; | 
|  | LPCOMPOSITIONSTRING ptr; | 
|  | rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING)); | 
|  | ptr = ImmLockIMCC(rc); | 
|  | memset(ptr,0,sizeof(COMPOSITIONSTRING)); | 
|  | ptr->dwSize = sizeof(COMPOSITIONSTRING); | 
|  | ImmUnlockIMCC(rc); | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmAssociateContext (IMM32.@) | 
|  | */ | 
|  | HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC) | 
|  | { | 
|  | HIMC old = NULL; | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("(%p, %p):\n", hWnd, hIMC); | 
|  |  | 
|  | if (!IMM_GetThreadData()->defaultContext) | 
|  | IMM_GetThreadData()->defaultContext = ImmCreateContext(); | 
|  |  | 
|  | /* | 
|  | * If already associated just return | 
|  | */ | 
|  | if (hIMC && data->IMC.hWnd == hWnd) | 
|  | return hIMC; | 
|  |  | 
|  | if (hWnd) | 
|  | { | 
|  | old = RemovePropW(hWnd,szwWineIMCProperty); | 
|  |  | 
|  | if (old == NULL) | 
|  | old = IMM_GetThreadData()->defaultContext; | 
|  | else if (old == (HIMC)-1) | 
|  | old = NULL; | 
|  |  | 
|  | if (hIMC != IMM_GetThreadData()->defaultContext) | 
|  | { | 
|  | if (hIMC == NULL) /* Meaning disable imm for that window*/ | 
|  | SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1); | 
|  | else | 
|  | SetPropW(hWnd,szwWineIMCProperty,hIMC); | 
|  | } | 
|  |  | 
|  | if (old) | 
|  | { | 
|  | InputContextData *old_data = old; | 
|  | if (old_data->IMC.hWnd == hWnd) | 
|  | old_data->IMC.hWnd = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!hIMC) | 
|  | return old; | 
|  |  | 
|  | if (IsWindow(data->IMC.hWnd)) | 
|  | { | 
|  | /* | 
|  | * Post a message that your context is switching | 
|  | */ | 
|  | SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, FALSE, ISC_SHOWUIALL); | 
|  | } | 
|  |  | 
|  | data->IMC.hWnd = hWnd; | 
|  |  | 
|  | if (IsWindow(data->IMC.hWnd)) | 
|  | { | 
|  | /* | 
|  | * Post a message that your context is switching | 
|  | */ | 
|  | SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL); | 
|  | } | 
|  |  | 
|  | return old; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Helper function for ImmAssociateContextEx | 
|  | */ | 
|  | static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam) | 
|  | { | 
|  | HIMC hImc = (HIMC)lParam; | 
|  | ImmAssociateContext(hwnd,hImc); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              ImmAssociateContextEx (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags) | 
|  | { | 
|  | TRACE("(%p, %p, 0x%x):\n", hWnd, hIMC, dwFlags); | 
|  |  | 
|  | if (!IMM_GetThreadData()->defaultContext) | 
|  | IMM_GetThreadData()->defaultContext = ImmCreateContext(); | 
|  |  | 
|  | if (!hWnd) return FALSE; | 
|  |  | 
|  | switch (dwFlags) | 
|  | { | 
|  | case 0: | 
|  | ImmAssociateContext(hWnd,hIMC); | 
|  | return TRUE; | 
|  | case IACE_DEFAULT: | 
|  | ImmAssociateContext(hWnd,IMM_GetThreadData()->defaultContext); | 
|  | return TRUE; | 
|  | case IACE_IGNORENOCONTEXT: | 
|  | if (GetPropW(hWnd,szwWineIMCProperty)) | 
|  | ImmAssociateContext(hWnd,hIMC); | 
|  | return TRUE; | 
|  | case IACE_CHILDREN: | 
|  | EnumChildWindows(hWnd,_ImmAssociateContextExEnumProc,(LPARAM)hIMC); | 
|  | return TRUE; | 
|  | default: | 
|  | FIXME("Unknown dwFlags 0x%x\n",dwFlags); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmConfigureIMEA (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmConfigureIMEA( | 
|  | HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  |  | 
|  | TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData); | 
|  |  | 
|  | if (dwMode == IME_CONFIG_REGISTERWORD && !lpData) | 
|  | return FALSE; | 
|  |  | 
|  | if (immHkl->hIME && immHkl->pImeConfigure) | 
|  | { | 
|  | if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData); | 
|  | else | 
|  | { | 
|  | REGISTERWORDW rww; | 
|  | REGISTERWORDA *rwa = lpData; | 
|  | BOOL rc; | 
|  |  | 
|  | rww.lpReading = strdupAtoW(rwa->lpReading); | 
|  | rww.lpWord = strdupAtoW(rwa->lpWord); | 
|  | rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww); | 
|  | HeapFree(GetProcessHeap(),0,rww.lpReading); | 
|  | HeapFree(GetProcessHeap(),0,rww.lpWord); | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmConfigureIMEW (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmConfigureIMEW( | 
|  | HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  |  | 
|  | TRACE("(%p, %p, %d, %p):\n", hKL, hWnd, dwMode, lpData); | 
|  |  | 
|  | if (dwMode == IME_CONFIG_REGISTERWORD && !lpData) | 
|  | return FALSE; | 
|  |  | 
|  | if (immHkl->hIME && immHkl->pImeConfigure) | 
|  | { | 
|  | if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData); | 
|  | else | 
|  | { | 
|  | REGISTERWORDW *rww = lpData; | 
|  | REGISTERWORDA rwa; | 
|  | BOOL rc; | 
|  |  | 
|  | rwa.lpReading = strdupWtoA(rww->lpReading); | 
|  | rwa.lpWord = strdupWtoA(rww->lpWord); | 
|  | rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa); | 
|  | HeapFree(GetProcessHeap(),0,rwa.lpReading); | 
|  | HeapFree(GetProcessHeap(),0,rwa.lpWord); | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmCreateContext (IMM32.@) | 
|  | */ | 
|  | HIMC WINAPI ImmCreateContext(void) | 
|  | { | 
|  | InputContextData *new_context; | 
|  | LPGUIDELINE gl; | 
|  | LPCANDIDATEINFO ci; | 
|  |  | 
|  | new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData)); | 
|  |  | 
|  | /* Load the IME */ | 
|  | new_context->immKbd = IMM_GetImmHkl(GetKeyboardLayout(0)); | 
|  |  | 
|  | if (!new_context->immKbd->hIME) | 
|  | { | 
|  | TRACE("IME dll could not be loaded\n"); | 
|  | HeapFree(GetProcessHeap(),0,new_context); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* the HIMCCs are never NULL */ | 
|  | new_context->IMC.hCompStr = ImmCreateBlankCompStr(); | 
|  | new_context->IMC.hMsgBuf = ImmCreateIMCC(0); | 
|  | new_context->IMC.hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO)); | 
|  | ci = ImmLockIMCC(new_context->IMC.hCandInfo); | 
|  | memset(ci,0,sizeof(CANDIDATEINFO)); | 
|  | ci->dwSize = sizeof(CANDIDATEINFO); | 
|  | ImmUnlockIMCC(new_context->IMC.hCandInfo); | 
|  | new_context->IMC.hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE)); | 
|  | gl = ImmLockIMCC(new_context->IMC.hGuideLine); | 
|  | memset(gl,0,sizeof(GUIDELINE)); | 
|  | gl->dwSize = sizeof(GUIDELINE); | 
|  | ImmUnlockIMCC(new_context->IMC.hGuideLine); | 
|  |  | 
|  | /* Initialize the IME Private */ | 
|  | new_context->IMC.hPrivate = ImmCreateIMCC(new_context->immKbd->imeInfo.dwPrivateDataSize); | 
|  |  | 
|  | if (!new_context->immKbd->pImeSelect(new_context, TRUE)) | 
|  | { | 
|  | TRACE("Selection of IME failed\n"); | 
|  | IMM_DestroyContext(new_context); | 
|  | return 0; | 
|  | } | 
|  | SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)GetKeyboardLayout(0)); | 
|  |  | 
|  | new_context->immKbd->uSelected++; | 
|  | TRACE("Created context %p\n",new_context); | 
|  |  | 
|  | return new_context; | 
|  | } | 
|  |  | 
|  | static BOOL IMM_DestroyContext(HIMC hIMC) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("Destroying %p\n",hIMC); | 
|  |  | 
|  | if (hIMC) | 
|  | { | 
|  | data->immKbd->uSelected --; | 
|  | data->immKbd->pImeSelect(hIMC, FALSE); | 
|  | SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)GetKeyboardLayout(0)); | 
|  |  | 
|  | if (IMM_GetThreadData()->hwndDefault == data->imeWnd) | 
|  | IMM_GetThreadData()->hwndDefault = NULL; | 
|  | DestroyWindow(data->imeWnd); | 
|  |  | 
|  | ImmDestroyIMCC(data->IMC.hCompStr); | 
|  | ImmDestroyIMCC(data->IMC.hCandInfo); | 
|  | ImmDestroyIMCC(data->IMC.hGuideLine); | 
|  | ImmDestroyIMCC(data->IMC.hPrivate); | 
|  | ImmDestroyIMCC(data->IMC.hMsgBuf); | 
|  |  | 
|  | HeapFree(GetProcessHeap(),0,data); | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmDestroyContext (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmDestroyContext(HIMC hIMC) | 
|  | { | 
|  | if (hIMC != IMM_GetThreadData()->defaultContext) | 
|  | return IMM_DestroyContext(hIMC); | 
|  | else | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmDisableIME (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmDisableIME(DWORD idThread) | 
|  | { | 
|  | FIXME("(%d): stub\n", idThread); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmEnumRegisterWordA (IMM32.@) | 
|  | */ | 
|  | UINT WINAPI ImmEnumRegisterWordA( | 
|  | HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc, | 
|  | LPCSTR lpszReading, DWORD dwStyle, | 
|  | LPCSTR lpszRegister, LPVOID lpData) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  | TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc, | 
|  | debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister), lpData); | 
|  | if (immHkl->hIME && immHkl->pImeEnumRegisterWord) | 
|  | { | 
|  | if (!is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc, | 
|  | (LPCWSTR)lpszReading, dwStyle, (LPCWSTR)lpszRegister, lpData); | 
|  | else | 
|  | { | 
|  | LPWSTR lpszwReading = strdupAtoW(lpszReading); | 
|  | LPWSTR lpszwRegister = strdupAtoW(lpszRegister); | 
|  | BOOL rc; | 
|  |  | 
|  | rc = immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc, | 
|  | lpszwReading, dwStyle, lpszwRegister, | 
|  | lpData); | 
|  |  | 
|  | HeapFree(GetProcessHeap(),0,lpszwReading); | 
|  | HeapFree(GetProcessHeap(),0,lpszwRegister); | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmEnumRegisterWordW (IMM32.@) | 
|  | */ | 
|  | UINT WINAPI ImmEnumRegisterWordW( | 
|  | HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc, | 
|  | LPCWSTR lpszReading, DWORD dwStyle, | 
|  | LPCWSTR lpszRegister, LPVOID lpData) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  | TRACE("(%p, %p, %s, %d, %s, %p):\n", hKL, lpfnEnumProc, | 
|  | debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), lpData); | 
|  | if (immHkl->hIME && immHkl->pImeEnumRegisterWord) | 
|  | { | 
|  | if (is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle, | 
|  | lpszRegister, lpData); | 
|  | else | 
|  | { | 
|  | LPSTR lpszaReading = strdupWtoA(lpszReading); | 
|  | LPSTR lpszaRegister = strdupWtoA(lpszRegister); | 
|  | BOOL rc; | 
|  |  | 
|  | rc = immHkl->pImeEnumRegisterWord(lpfnEnumProc, (LPCWSTR)lpszaReading, | 
|  | dwStyle, (LPCWSTR)lpszaRegister, lpData); | 
|  |  | 
|  | HeapFree(GetProcessHeap(),0,lpszaReading); | 
|  | HeapFree(GetProcessHeap(),0,lpszaRegister); | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static inline BOOL EscapeRequiresWA(UINT uEscape) | 
|  | { | 
|  | if (uEscape == IME_ESC_GET_EUDC_DICTIONARY || | 
|  | uEscape == IME_ESC_SET_EUDC_DICTIONARY || | 
|  | uEscape == IME_ESC_IME_NAME || | 
|  | uEscape == IME_ESC_GETHELPFILENAME) | 
|  | return TRUE; | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmEscapeA (IMM32.@) | 
|  | */ | 
|  | LRESULT WINAPI ImmEscapeA( | 
|  | HKL hKL, HIMC hIMC, | 
|  | UINT uEscape, LPVOID lpData) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  | TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData); | 
|  |  | 
|  | if (immHkl->hIME && immHkl->pImeEscape) | 
|  | { | 
|  | if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeEscape(hIMC,uEscape,lpData); | 
|  | else | 
|  | { | 
|  | WCHAR buffer[81]; /* largest required buffer should be 80 */ | 
|  | LRESULT rc; | 
|  | if (uEscape == IME_ESC_SET_EUDC_DICTIONARY) | 
|  | { | 
|  | MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81); | 
|  | rc = immHkl->pImeEscape(hIMC,uEscape,buffer); | 
|  | } | 
|  | else | 
|  | { | 
|  | rc = immHkl->pImeEscape(hIMC,uEscape,buffer); | 
|  | WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL); | 
|  | } | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmEscapeW (IMM32.@) | 
|  | */ | 
|  | LRESULT WINAPI ImmEscapeW( | 
|  | HKL hKL, HIMC hIMC, | 
|  | UINT uEscape, LPVOID lpData) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  | TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData); | 
|  |  | 
|  | if (immHkl->hIME && immHkl->pImeEscape) | 
|  | { | 
|  | if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeEscape(hIMC,uEscape,lpData); | 
|  | else | 
|  | { | 
|  | CHAR buffer[81]; /* largest required buffer should be 80 */ | 
|  | LRESULT rc; | 
|  | if (uEscape == IME_ESC_SET_EUDC_DICTIONARY) | 
|  | { | 
|  | WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL); | 
|  | rc = immHkl->pImeEscape(hIMC,uEscape,buffer); | 
|  | } | 
|  | else | 
|  | { | 
|  | rc = immHkl->pImeEscape(hIMC,uEscape,buffer); | 
|  | MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80); | 
|  | } | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetCandidateListA (IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetCandidateListA( | 
|  | HIMC hIMC, DWORD dwIndex, | 
|  | LPCANDIDATELIST lpCandList, DWORD dwBufLen) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  | LPCANDIDATEINFO candinfo; | 
|  | LPCANDIDATELIST candlist; | 
|  | DWORD ret = 0; | 
|  |  | 
|  | TRACE("%p, %d, %p, %d\n", hIMC, dwIndex, lpCandList, dwBufLen); | 
|  |  | 
|  | if (!data || !data->IMC.hCandInfo) | 
|  | return 0; | 
|  |  | 
|  | candinfo = ImmLockIMCC(data->IMC.hCandInfo); | 
|  | if ( dwIndex >= candinfo->dwCount || | 
|  | dwIndex >= (sizeof(candinfo->dwOffset) / sizeof(DWORD)) ) | 
|  | goto done; | 
|  |  | 
|  | candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]); | 
|  | if ( !candlist->dwSize || !candlist->dwCount ) | 
|  | goto done; | 
|  |  | 
|  | if ( !is_himc_ime_unicode(data) ) | 
|  | { | 
|  | ret = candlist->dwSize; | 
|  | if ( lpCandList && dwBufLen >= ret ) | 
|  | memcpy(lpCandList, candlist, ret); | 
|  | } | 
|  | else | 
|  | ret = convert_candidatelist_WtoA( candlist, lpCandList, dwBufLen); | 
|  |  | 
|  | done: | 
|  | ImmUnlockIMCC(data->IMC.hCandInfo); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetCandidateListCountA (IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetCandidateListCountA( | 
|  | HIMC hIMC, LPDWORD lpdwListCount) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  | LPCANDIDATEINFO candinfo; | 
|  | DWORD ret, count; | 
|  |  | 
|  | TRACE("%p, %p\n", hIMC, lpdwListCount); | 
|  |  | 
|  | if (!data || !lpdwListCount || !data->IMC.hCandInfo) | 
|  | return 0; | 
|  |  | 
|  | candinfo = ImmLockIMCC(data->IMC.hCandInfo); | 
|  |  | 
|  | *lpdwListCount = count = candinfo->dwCount; | 
|  |  | 
|  | if ( !is_himc_ime_unicode(data) ) | 
|  | ret = candinfo->dwSize; | 
|  | else | 
|  | { | 
|  | ret = sizeof(CANDIDATEINFO); | 
|  | while ( count-- ) | 
|  | ret += ImmGetCandidateListA(hIMC, count, NULL, 0); | 
|  | } | 
|  |  | 
|  | ImmUnlockIMCC(data->IMC.hCandInfo); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetCandidateListCountW (IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetCandidateListCountW( | 
|  | HIMC hIMC, LPDWORD lpdwListCount) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  | LPCANDIDATEINFO candinfo; | 
|  | DWORD ret, count; | 
|  |  | 
|  | TRACE("%p, %p\n", hIMC, lpdwListCount); | 
|  |  | 
|  | if (!data || !lpdwListCount || !data->IMC.hCandInfo) | 
|  | return 0; | 
|  |  | 
|  | candinfo = ImmLockIMCC(data->IMC.hCandInfo); | 
|  |  | 
|  | *lpdwListCount = count = candinfo->dwCount; | 
|  |  | 
|  | if ( is_himc_ime_unicode(data) ) | 
|  | ret = candinfo->dwSize; | 
|  | else | 
|  | { | 
|  | ret = sizeof(CANDIDATEINFO); | 
|  | while ( count-- ) | 
|  | ret += ImmGetCandidateListW(hIMC, count, NULL, 0); | 
|  | } | 
|  |  | 
|  | ImmUnlockIMCC(data->IMC.hCandInfo); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetCandidateListW (IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetCandidateListW( | 
|  | HIMC hIMC, DWORD dwIndex, | 
|  | LPCANDIDATELIST lpCandList, DWORD dwBufLen) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  | LPCANDIDATEINFO candinfo; | 
|  | LPCANDIDATELIST candlist; | 
|  | DWORD ret = 0; | 
|  |  | 
|  | TRACE("%p, %d, %p, %d\n", hIMC, dwIndex, lpCandList, dwBufLen); | 
|  |  | 
|  | if (!data || !data->IMC.hCandInfo) | 
|  | return 0; | 
|  |  | 
|  | candinfo = ImmLockIMCC(data->IMC.hCandInfo); | 
|  | if ( dwIndex >= candinfo->dwCount || | 
|  | dwIndex >= (sizeof(candinfo->dwOffset) / sizeof(DWORD)) ) | 
|  | goto done; | 
|  |  | 
|  | candlist = (LPCANDIDATELIST)((LPBYTE)candinfo + candinfo->dwOffset[dwIndex]); | 
|  | if ( !candlist->dwSize || !candlist->dwCount ) | 
|  | goto done; | 
|  |  | 
|  | if ( is_himc_ime_unicode(data) ) | 
|  | { | 
|  | ret = candlist->dwSize; | 
|  | if ( lpCandList && dwBufLen >= ret ) | 
|  | memcpy(lpCandList, candlist, ret); | 
|  | } | 
|  | else | 
|  | ret = convert_candidatelist_AtoW( candlist, lpCandList, dwBufLen); | 
|  |  | 
|  | done: | 
|  | ImmUnlockIMCC(data->IMC.hCandInfo); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetCandidateWindow (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmGetCandidateWindow( | 
|  | HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("%p, %d, %p\n", hIMC, dwIndex, lpCandidate); | 
|  |  | 
|  | if (!data || !lpCandidate) | 
|  | return FALSE; | 
|  |  | 
|  | if ( dwIndex >= (sizeof(data->IMC.cfCandForm) / sizeof(CANDIDATEFORM)) ) | 
|  | return FALSE; | 
|  |  | 
|  | *lpCandidate = data->IMC.cfCandForm[dwIndex]; | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetCompositionFontA (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) | 
|  | { | 
|  | LOGFONTW lfW; | 
|  | BOOL rc; | 
|  |  | 
|  | TRACE("(%p, %p):\n", hIMC, lplf); | 
|  |  | 
|  | rc = ImmGetCompositionFontW(hIMC,&lfW); | 
|  | if (!rc || !lplf) | 
|  | return FALSE; | 
|  |  | 
|  | memcpy(lplf,&lfW,sizeof(LOGFONTA)); | 
|  | WideCharToMultiByte(CP_ACP, 0, lfW.lfFaceName, -1, lplf->lfFaceName, | 
|  | LF_FACESIZE, NULL, NULL); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetCompositionFontW (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("(%p, %p):\n", hIMC, lplf); | 
|  |  | 
|  | if (!data || !lplf) | 
|  | return FALSE; | 
|  |  | 
|  | *lplf = data->IMC.lfFont.W; | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Helpers for the GetCompositionString functions */ | 
|  |  | 
|  | static INT CopyCompStringIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE target, INT tlen, | 
|  | BOOL unicode ) | 
|  | { | 
|  | INT rc; | 
|  |  | 
|  | if (is_himc_ime_unicode(data) && !unicode) | 
|  | rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)source, slen, (LPSTR)target, tlen, NULL, NULL); | 
|  | else if (!is_himc_ime_unicode(data) && unicode) | 
|  | rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)source, slen, (LPWSTR)target, tlen) * sizeof(WCHAR); | 
|  | else | 
|  | { | 
|  | int dlen = (unicode)?sizeof(WCHAR):sizeof(CHAR); | 
|  | memcpy( target, source, min(slen,tlen)*dlen); | 
|  | rc = slen*dlen; | 
|  | } | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | static INT CopyCompAttrIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource, INT sslen, | 
|  | LPBYTE target, INT tlen, BOOL unicode ) | 
|  | { | 
|  | INT rc; | 
|  |  | 
|  | if (is_himc_ime_unicode(data) && !unicode) | 
|  | { | 
|  | rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, sslen, NULL, 0, NULL, NULL); | 
|  | if (tlen) | 
|  | { | 
|  | const BYTE *src = source; | 
|  | LPBYTE dst = target; | 
|  | int i, j = 0, k = 0; | 
|  |  | 
|  | if (rc < tlen) | 
|  | tlen = rc; | 
|  | for (i = 0; i < sslen; ++i) | 
|  | { | 
|  | int len; | 
|  |  | 
|  | len = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)ssource + i, 1, | 
|  | NULL, 0, NULL, NULL); | 
|  | for (; len > 0; --len) | 
|  | { | 
|  | dst[j++] = src[k]; | 
|  |  | 
|  | if (j >= tlen) | 
|  | goto end; | 
|  | } | 
|  | ++k; | 
|  | } | 
|  | end: | 
|  | rc = j; | 
|  | } | 
|  | } | 
|  | else if (!is_himc_ime_unicode(data) && unicode) | 
|  | { | 
|  | rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, sslen, NULL, 0); | 
|  | if (tlen) | 
|  | { | 
|  | const BYTE *src = source; | 
|  | LPBYTE dst = target; | 
|  | int i, j = 0; | 
|  |  | 
|  | if (rc < tlen) | 
|  | tlen = rc; | 
|  | for (i = 0; i < sslen; ++i) | 
|  | { | 
|  | if (IsDBCSLeadByte(((LPSTR)ssource)[i])) | 
|  | continue; | 
|  |  | 
|  | dst[j++] = src[i]; | 
|  |  | 
|  | if (j >= tlen) | 
|  | break; | 
|  | } | 
|  | rc = j; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | memcpy( target, source, min(slen,tlen)); | 
|  | rc = slen; | 
|  | } | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource, | 
|  | LPBYTE target, INT tlen, BOOL unicode ) | 
|  | { | 
|  | INT rc; | 
|  |  | 
|  | if (is_himc_ime_unicode(data) && !unicode) | 
|  | { | 
|  | if (tlen) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | if (slen < tlen) | 
|  | tlen = slen; | 
|  | tlen /= sizeof (DWORD); | 
|  | for (i = 0; i < tlen; ++i) | 
|  | { | 
|  | ((DWORD *)target)[i] = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, | 
|  | ((DWORD *)source)[i], | 
|  | NULL, 0, | 
|  | NULL, NULL); | 
|  | } | 
|  | rc = sizeof (DWORD) * i; | 
|  | } | 
|  | else | 
|  | rc = slen; | 
|  | } | 
|  | else if (!is_himc_ime_unicode(data) && unicode) | 
|  | { | 
|  | if (tlen) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | if (slen < tlen) | 
|  | tlen = slen; | 
|  | tlen /= sizeof (DWORD); | 
|  | for (i = 0; i < tlen; ++i) | 
|  | { | 
|  | ((DWORD *)target)[i] = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, | 
|  | ((DWORD *)source)[i], | 
|  | NULL, 0); | 
|  | } | 
|  | rc = sizeof (DWORD) * i; | 
|  | } | 
|  | else | 
|  | rc = slen; | 
|  | } | 
|  | else | 
|  | { | 
|  | memcpy( target, source, min(slen,tlen)); | 
|  | rc = slen; | 
|  | } | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode) | 
|  | { | 
|  | int rc; | 
|  |  | 
|  | if (is_himc_ime_unicode(data) && !unicode) | 
|  | { | 
|  | rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL); | 
|  | } | 
|  | else if (!is_himc_ime_unicode(data) && unicode) | 
|  | { | 
|  | rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0); | 
|  | } | 
|  | else | 
|  | rc = offset; | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, | 
|  | DWORD dwBufLen, BOOL unicode) | 
|  | { | 
|  | LONG rc = 0; | 
|  | InputContextData *data = hIMC; | 
|  | LPCOMPOSITIONSTRING compstr; | 
|  | LPBYTE compdata; | 
|  |  | 
|  | TRACE("(%p, 0x%x, %p, %d)\n", hIMC, dwIndex, lpBuf, dwBufLen); | 
|  |  | 
|  | if (!data) | 
|  | return FALSE; | 
|  |  | 
|  | if (!data->IMC.hCompStr) | 
|  | return FALSE; | 
|  |  | 
|  | compdata = ImmLockIMCC(data->IMC.hCompStr); | 
|  | compstr = (LPCOMPOSITIONSTRING)compdata; | 
|  |  | 
|  | switch (dwIndex) | 
|  | { | 
|  | case GCS_RESULTSTR: | 
|  | TRACE("GCS_RESULTSTR\n"); | 
|  | rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode); | 
|  | break; | 
|  | case GCS_COMPSTR: | 
|  | TRACE("GCS_COMPSTR\n"); | 
|  | rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode); | 
|  | break; | 
|  | case GCS_COMPATTR: | 
|  | TRACE("GCS_COMPATTR\n"); | 
|  | rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen, | 
|  | compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, | 
|  | lpBuf, dwBufLen, unicode); | 
|  | break; | 
|  | case GCS_COMPCLAUSE: | 
|  | TRACE("GCS_COMPCLAUSE\n"); | 
|  | rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen, | 
|  | compdata + compstr->dwCompStrOffset, | 
|  | lpBuf, dwBufLen, unicode); | 
|  | break; | 
|  | case GCS_RESULTCLAUSE: | 
|  | TRACE("GCS_RESULTCLAUSE\n"); | 
|  | rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen, | 
|  | compdata + compstr->dwResultStrOffset, | 
|  | lpBuf, dwBufLen, unicode); | 
|  | break; | 
|  | case GCS_RESULTREADSTR: | 
|  | TRACE("GCS_RESULTREADSTR\n"); | 
|  | rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode); | 
|  | break; | 
|  | case GCS_RESULTREADCLAUSE: | 
|  | TRACE("GCS_RESULTREADCLAUSE\n"); | 
|  | rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen, | 
|  | compdata + compstr->dwResultStrOffset, | 
|  | lpBuf, dwBufLen, unicode); | 
|  | break; | 
|  | case GCS_COMPREADSTR: | 
|  | TRACE("GCS_COMPREADSTR\n"); | 
|  | rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode); | 
|  | break; | 
|  | case GCS_COMPREADATTR: | 
|  | TRACE("GCS_COMPREADATTR\n"); | 
|  | rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen, | 
|  | compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, | 
|  | lpBuf, dwBufLen, unicode); | 
|  | break; | 
|  | case GCS_COMPREADCLAUSE: | 
|  | TRACE("GCS_COMPREADCLAUSE\n"); | 
|  | rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen, | 
|  | compdata + compstr->dwCompStrOffset, | 
|  | lpBuf, dwBufLen, unicode); | 
|  | break; | 
|  | case GCS_CURSORPOS: | 
|  | TRACE("GCS_CURSORPOS\n"); | 
|  | rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode); | 
|  | break; | 
|  | case GCS_DELTASTART: | 
|  | TRACE("GCS_DELTASTART\n"); | 
|  | rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode); | 
|  | break; | 
|  | default: | 
|  | FIXME("Unhandled index 0x%x\n",dwIndex); | 
|  | break; | 
|  | } | 
|  |  | 
|  | ImmUnlockIMCC(data->IMC.hCompStr); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetCompositionStringA (IMM32.@) | 
|  | */ | 
|  | LONG WINAPI ImmGetCompositionStringA( | 
|  | HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen) | 
|  | { | 
|  | return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, FALSE); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetCompositionStringW (IMM32.@) | 
|  | */ | 
|  | LONG WINAPI ImmGetCompositionStringW( | 
|  | HIMC hIMC, DWORD dwIndex, | 
|  | LPVOID lpBuf, DWORD dwBufLen) | 
|  | { | 
|  | return ImmGetCompositionStringT(hIMC, dwIndex, lpBuf, dwBufLen, TRUE); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetCompositionWindow (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("(%p, %p)\n", hIMC, lpCompForm); | 
|  |  | 
|  | if (!data) | 
|  | return FALSE; | 
|  |  | 
|  | *lpCompForm = data->IMC.cfCompForm; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetContext (IMM32.@) | 
|  | * | 
|  | */ | 
|  | HIMC WINAPI ImmGetContext(HWND hWnd) | 
|  | { | 
|  | HIMC rc = NULL; | 
|  |  | 
|  | TRACE("%p\n", hWnd); | 
|  | if (!IMM_GetThreadData()->defaultContext) | 
|  | IMM_GetThreadData()->defaultContext = ImmCreateContext(); | 
|  |  | 
|  | rc = GetPropW(hWnd,szwWineIMCProperty); | 
|  | if (rc == (HIMC)-1) | 
|  | rc = NULL; | 
|  | else if (rc == NULL) | 
|  | rc = IMM_GetThreadData()->defaultContext; | 
|  |  | 
|  | if (rc) | 
|  | { | 
|  | InputContextData *data = rc; | 
|  | data->IMC.hWnd = hWnd; | 
|  | } | 
|  | TRACE("returning %p\n", rc); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetConversionListA (IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetConversionListA( | 
|  | HKL hKL, HIMC hIMC, | 
|  | LPCSTR pSrc, LPCANDIDATELIST lpDst, | 
|  | DWORD dwBufLen, UINT uFlag) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  | TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_a(pSrc), lpDst, | 
|  | dwBufLen, uFlag); | 
|  | if (immHkl->hIME && immHkl->pImeConversionList) | 
|  | { | 
|  | if (!is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeConversionList(hIMC,(LPCWSTR)pSrc,lpDst,dwBufLen,uFlag); | 
|  | else | 
|  | { | 
|  | LPCANDIDATELIST lpwDst; | 
|  | DWORD ret = 0, len; | 
|  | LPWSTR pwSrc = strdupAtoW(pSrc); | 
|  |  | 
|  | len = immHkl->pImeConversionList(hIMC, pwSrc, NULL, 0, uFlag); | 
|  | lpwDst = HeapAlloc(GetProcessHeap(), 0, len); | 
|  | if ( lpwDst ) | 
|  | { | 
|  | immHkl->pImeConversionList(hIMC, pwSrc, lpwDst, len, uFlag); | 
|  | ret = convert_candidatelist_WtoA( lpwDst, lpDst, dwBufLen); | 
|  | HeapFree(GetProcessHeap(), 0, lpwDst); | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, pwSrc); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  | } | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetConversionListW (IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetConversionListW( | 
|  | HKL hKL, HIMC hIMC, | 
|  | LPCWSTR pSrc, LPCANDIDATELIST lpDst, | 
|  | DWORD dwBufLen, UINT uFlag) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  | TRACE("(%p, %p, %s, %p, %d, %d):\n", hKL, hIMC, debugstr_w(pSrc), lpDst, | 
|  | dwBufLen, uFlag); | 
|  | if (immHkl->hIME && immHkl->pImeConversionList) | 
|  | { | 
|  | if (is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeConversionList(hIMC,pSrc,lpDst,dwBufLen,uFlag); | 
|  | else | 
|  | { | 
|  | LPCANDIDATELIST lpaDst; | 
|  | DWORD ret = 0, len; | 
|  | LPSTR paSrc = strdupWtoA(pSrc); | 
|  |  | 
|  | len = immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, NULL, 0, uFlag); | 
|  | lpaDst = HeapAlloc(GetProcessHeap(), 0, len); | 
|  | if ( lpaDst ) | 
|  | { | 
|  | immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, lpaDst, len, uFlag); | 
|  | ret = convert_candidatelist_AtoW( lpaDst, lpDst, dwBufLen); | 
|  | HeapFree(GetProcessHeap(), 0, lpaDst); | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, paSrc); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  | } | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetConversionStatus (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmGetConversionStatus( | 
|  | HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence); | 
|  |  | 
|  | if (!data) | 
|  | return FALSE; | 
|  |  | 
|  | if (lpfdwConversion) | 
|  | *lpfdwConversion = data->IMC.fdwConversion; | 
|  | if (lpfdwSentence) | 
|  | *lpfdwSentence = data->IMC.fdwSentence; | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetDefaultIMEWnd (IMM32.@) | 
|  | */ | 
|  | HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) | 
|  | { | 
|  | TRACE("Default is %p\n",IMM_GetThreadData()->hwndDefault); | 
|  | return IMM_GetThreadData()->hwndDefault; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetDescriptionA (IMM32.@) | 
|  | */ | 
|  | UINT WINAPI ImmGetDescriptionA( | 
|  | HKL hKL, LPSTR lpszDescription, UINT uBufLen) | 
|  | { | 
|  | WCHAR *buf; | 
|  | DWORD len; | 
|  |  | 
|  | TRACE("%p %p %d\n", hKL, lpszDescription, uBufLen); | 
|  |  | 
|  | /* find out how many characters in the unicode buffer */ | 
|  | len = ImmGetDescriptionW( hKL, NULL, 0 ); | 
|  |  | 
|  | /* allocate a buffer of that size */ | 
|  | buf = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR) ); | 
|  | if( !buf ) | 
|  | return 0; | 
|  |  | 
|  | /* fetch the unicode buffer */ | 
|  | len = ImmGetDescriptionW( hKL, buf, len + 1 ); | 
|  |  | 
|  | /* convert it back to ASCII */ | 
|  | len = WideCharToMultiByte( CP_ACP, 0, buf, len + 1, | 
|  | lpszDescription, uBufLen, NULL, NULL ); | 
|  |  | 
|  | HeapFree( GetProcessHeap(), 0, buf ); | 
|  |  | 
|  | return len; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetDescriptionW (IMM32.@) | 
|  | */ | 
|  | UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen) | 
|  | { | 
|  | static const WCHAR name[] = { 'W','i','n','e',' ','X','I','M',0 }; | 
|  |  | 
|  | FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen); | 
|  |  | 
|  | if (!uBufLen) return lstrlenW( name ); | 
|  | lstrcpynW( lpszDescription, name, uBufLen ); | 
|  | return lstrlenW( lpszDescription ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetGuideLineA (IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetGuideLineA( | 
|  | HIMC hIMC, DWORD dwIndex, LPSTR lpBuf, DWORD dwBufLen) | 
|  | { | 
|  | FIXME("(%p, %d, %s, %d): stub\n", | 
|  | hIMC, dwIndex, debugstr_a(lpBuf), dwBufLen | 
|  | ); | 
|  | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetGuideLineW (IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBufLen) | 
|  | { | 
|  | FIXME("(%p, %d, %s, %d): stub\n", | 
|  | hIMC, dwIndex, debugstr_w(lpBuf), dwBufLen | 
|  | ); | 
|  | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetIMEFileNameA (IMM32.@) | 
|  | */ | 
|  | UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen) | 
|  | { | 
|  | LPWSTR bufW = NULL; | 
|  | UINT wBufLen = uBufLen; | 
|  | UINT rc; | 
|  |  | 
|  | if (uBufLen && lpszFileName) | 
|  | bufW = HeapAlloc(GetProcessHeap(),0,uBufLen * sizeof(WCHAR)); | 
|  | else /* We need this to get the number of byte required */ | 
|  | { | 
|  | bufW = HeapAlloc(GetProcessHeap(),0,MAX_PATH * sizeof(WCHAR)); | 
|  | wBufLen = MAX_PATH; | 
|  | } | 
|  |  | 
|  | rc = ImmGetIMEFileNameW(hKL,bufW,wBufLen); | 
|  |  | 
|  | if (rc > 0) | 
|  | { | 
|  | if (uBufLen && lpszFileName) | 
|  | rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, lpszFileName, | 
|  | uBufLen, NULL, NULL); | 
|  | else /* get the length */ | 
|  | rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, | 
|  | NULL); | 
|  | } | 
|  |  | 
|  | HeapFree(GetProcessHeap(),0,bufW); | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetIMEFileNameW (IMM32.@) | 
|  | */ | 
|  | UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen) | 
|  | { | 
|  | HKEY hkey; | 
|  | DWORD length; | 
|  | DWORD rc; | 
|  | WCHAR regKey[sizeof(szImeRegFmt)/sizeof(WCHAR)+8]; | 
|  |  | 
|  | wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hKL ); | 
|  | rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey); | 
|  | if (rc != ERROR_SUCCESS) | 
|  | { | 
|  | SetLastError(rc); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | length = 0; | 
|  | rc = RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, NULL, &length); | 
|  |  | 
|  | if (rc != ERROR_SUCCESS) | 
|  | { | 
|  | RegCloseKey(hkey); | 
|  | SetLastError(rc); | 
|  | return 0; | 
|  | } | 
|  | if (length > uBufLen * sizeof(WCHAR) || !lpszFileName) | 
|  | { | 
|  | RegCloseKey(hkey); | 
|  | if (lpszFileName) | 
|  | { | 
|  | SetLastError(ERROR_INSUFFICIENT_BUFFER); | 
|  | return 0; | 
|  | } | 
|  | else | 
|  | return length / sizeof(WCHAR); | 
|  | } | 
|  |  | 
|  | RegGetValueW(hkey, NULL, szImeFileW, RRF_RT_REG_SZ, NULL, lpszFileName, &length); | 
|  |  | 
|  | RegCloseKey(hkey); | 
|  |  | 
|  | return length / sizeof(WCHAR); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetOpenStatus (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmGetOpenStatus(HIMC hIMC) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  | static int i; | 
|  |  | 
|  | if (!data) | 
|  | return FALSE; | 
|  |  | 
|  | TRACE("(%p): semi-stub\n", hIMC); | 
|  |  | 
|  | if (!i++) | 
|  | FIXME("(%p): semi-stub\n", hIMC); | 
|  |  | 
|  | return data->IMC.fOpen; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetProperty (IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex) | 
|  | { | 
|  | DWORD rc = 0; | 
|  | ImmHkl *kbd; | 
|  |  | 
|  | TRACE("(%p, %d)\n", hKL, fdwIndex); | 
|  | kbd = IMM_GetImmHkl(hKL); | 
|  |  | 
|  | if (kbd && kbd->hIME) | 
|  | { | 
|  | switch (fdwIndex) | 
|  | { | 
|  | case IGP_PROPERTY: rc = kbd->imeInfo.fdwProperty; break; | 
|  | case IGP_CONVERSION: rc = kbd->imeInfo.fdwConversionCaps; break; | 
|  | case IGP_SENTENCE: rc = kbd->imeInfo.fdwSentenceCaps; break; | 
|  | case IGP_SETCOMPSTR: rc = kbd->imeInfo.fdwSCSCaps; break; | 
|  | case IGP_SELECT: rc = kbd->imeInfo.fdwSelectCaps; break; | 
|  | case IGP_GETIMEVERSION: rc = IMEVER_0400; break; | 
|  | case IGP_UI: rc = 0; break; | 
|  | default: rc = 0; | 
|  | } | 
|  | } | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetRegisterWordStyleA (IMM32.@) | 
|  | */ | 
|  | UINT WINAPI ImmGetRegisterWordStyleA( | 
|  | HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  | TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf); | 
|  | if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle) | 
|  | { | 
|  | if (!is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)lpStyleBuf); | 
|  | else | 
|  | { | 
|  | STYLEBUFW sbw; | 
|  | UINT rc; | 
|  |  | 
|  | rc = immHkl->pImeGetRegisterWordStyle(nItem,&sbw); | 
|  | WideCharToMultiByte(CP_ACP, 0, sbw.szDescription, -1, | 
|  | lpStyleBuf->szDescription, 32, NULL, NULL); | 
|  | lpStyleBuf->dwStyle = sbw.dwStyle; | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetRegisterWordStyleW (IMM32.@) | 
|  | */ | 
|  | UINT WINAPI ImmGetRegisterWordStyleW( | 
|  | HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  | TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf); | 
|  | if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle) | 
|  | { | 
|  | if (is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeGetRegisterWordStyle(nItem,lpStyleBuf); | 
|  | else | 
|  | { | 
|  | STYLEBUFA sba; | 
|  | UINT rc; | 
|  |  | 
|  | rc = immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)&sba); | 
|  | MultiByteToWideChar(CP_ACP, 0, sba.szDescription, -1, | 
|  | lpStyleBuf->szDescription, 32); | 
|  | lpStyleBuf->dwStyle = sba.dwStyle; | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetStatusWindowPos (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("(%p, %p)\n", hIMC, lpptPos); | 
|  |  | 
|  | if (!data || !lpptPos) | 
|  | return FALSE; | 
|  |  | 
|  | *lpptPos = data->IMC.ptStatusWndPos; | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetVirtualKey (IMM32.@) | 
|  | */ | 
|  | UINT WINAPI ImmGetVirtualKey(HWND hWnd) | 
|  | { | 
|  | OSVERSIONINFOA version; | 
|  | InputContextData *data = ImmGetContext( hWnd ); | 
|  | TRACE("%p\n", hWnd); | 
|  |  | 
|  | if ( data ) | 
|  | return data->lastVK; | 
|  |  | 
|  | version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); | 
|  | GetVersionExA( &version ); | 
|  | switch(version.dwPlatformId) | 
|  | { | 
|  | case VER_PLATFORM_WIN32_WINDOWS: | 
|  | return VK_PROCESSKEY; | 
|  | case VER_PLATFORM_WIN32_NT: | 
|  | return 0; | 
|  | default: | 
|  | FIXME("%d not supported\n",version.dwPlatformId); | 
|  | return VK_PROCESSKEY; | 
|  | } | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmInstallIMEA (IMM32.@) | 
|  | */ | 
|  | HKL WINAPI ImmInstallIMEA( | 
|  | LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText) | 
|  | { | 
|  | LPWSTR lpszwIMEFileName; | 
|  | LPWSTR lpszwLayoutText; | 
|  | HKL hkl; | 
|  |  | 
|  | TRACE ("(%s, %s)\n", debugstr_a(lpszIMEFileName), | 
|  | debugstr_a(lpszLayoutText)); | 
|  |  | 
|  | lpszwIMEFileName = strdupAtoW(lpszIMEFileName); | 
|  | lpszwLayoutText = strdupAtoW(lpszLayoutText); | 
|  |  | 
|  | hkl = ImmInstallIMEW(lpszwIMEFileName, lpszwLayoutText); | 
|  |  | 
|  | HeapFree(GetProcessHeap(),0,lpszwIMEFileName); | 
|  | HeapFree(GetProcessHeap(),0,lpszwLayoutText); | 
|  | return hkl; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmInstallIMEW (IMM32.@) | 
|  | */ | 
|  | HKL WINAPI ImmInstallIMEW( | 
|  | LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText) | 
|  | { | 
|  | INT lcid = GetUserDefaultLCID(); | 
|  | INT count; | 
|  | HKL hkl; | 
|  | DWORD rc; | 
|  | HKEY hkey; | 
|  | WCHAR regKey[sizeof(szImeRegFmt)/sizeof(WCHAR)+8]; | 
|  |  | 
|  | TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName), | 
|  | debugstr_w(lpszLayoutText)); | 
|  |  | 
|  | /* Start with 2.  e001 will be blank and so default to the wine internal IME */ | 
|  | count = 2; | 
|  |  | 
|  | while (count < 0xfff) | 
|  | { | 
|  | DWORD disposition = 0; | 
|  |  | 
|  | hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count ); | 
|  | wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl); | 
|  |  | 
|  | rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition); | 
|  | if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY) | 
|  | break; | 
|  | else if (rc == ERROR_SUCCESS) | 
|  | RegCloseKey(hkey); | 
|  |  | 
|  | count++; | 
|  | } | 
|  |  | 
|  | if (count == 0xfff) | 
|  | { | 
|  | WARN("Unable to find slot to install IME\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (rc == ERROR_SUCCESS) | 
|  | { | 
|  | rc = RegSetValueExW(hkey, szImeFileW, 0, REG_SZ, (const BYTE*)lpszIMEFileName, | 
|  | (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR)); | 
|  | if (rc == ERROR_SUCCESS) | 
|  | rc = RegSetValueExW(hkey, szLayoutTextW, 0, REG_SZ, (const BYTE*)lpszLayoutText, | 
|  | (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR)); | 
|  | RegCloseKey(hkey); | 
|  | return hkl; | 
|  | } | 
|  | else | 
|  | { | 
|  | WARN("Unable to set IME registry values\n"); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmIsIME (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmIsIME(HKL hKL) | 
|  | { | 
|  | ImmHkl *ptr; | 
|  | TRACE("(%p):\n", hKL); | 
|  | ptr = IMM_GetImmHkl(hKL); | 
|  | return (ptr && ptr->hIME); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmIsUIMessageA (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmIsUIMessageA( | 
|  | HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | BOOL rc = FALSE; | 
|  |  | 
|  | TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam); | 
|  | if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) || | 
|  | (msg == WM_IME_SETCONTEXT) || | 
|  | (msg == WM_IME_NOTIFY) || | 
|  | (msg == WM_IME_COMPOSITIONFULL) || | 
|  | (msg == WM_IME_SELECT) || | 
|  | (msg == 0x287 /* FIXME: WM_IME_SYSTEM */) || | 
|  | (msg == WM_MSIME_RECONVERTOPTIONS) || | 
|  | (msg == WM_MSIME_MOUSE) || | 
|  | (msg == WM_MSIME_RECONVERTREQUEST) || | 
|  | (msg == WM_MSIME_RECONVERT) || | 
|  | (msg == WM_MSIME_QUERYPOSITION) || | 
|  | (msg == WM_MSIME_DOCUMENTFEED)) | 
|  | { | 
|  | if (hWndIME) | 
|  | SendMessageA(hWndIME, msg, wParam, lParam); | 
|  |  | 
|  | rc = TRUE; | 
|  | } | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmIsUIMessageW (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmIsUIMessageW( | 
|  | HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | BOOL rc = FALSE; | 
|  |  | 
|  | TRACE("(%p, %x, %ld, %ld)\n", hWndIME, msg, wParam, lParam); | 
|  | if ((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) || | 
|  | (msg == WM_IME_SETCONTEXT) || | 
|  | (msg == WM_IME_NOTIFY) || | 
|  | (msg == WM_IME_COMPOSITIONFULL) || | 
|  | (msg == WM_IME_SELECT) || | 
|  | (msg == 0x287 /* FIXME: WM_IME_SYSTEM */) || | 
|  | (msg == WM_MSIME_RECONVERTOPTIONS) || | 
|  | (msg == WM_MSIME_MOUSE) || | 
|  | (msg == WM_MSIME_RECONVERTREQUEST) || | 
|  | (msg == WM_MSIME_RECONVERT) || | 
|  | (msg == WM_MSIME_QUERYPOSITION) || | 
|  | (msg == WM_MSIME_DOCUMENTFEED)) | 
|  | { | 
|  | if (hWndIME) | 
|  | SendMessageW(hWndIME, msg, wParam, lParam); | 
|  |  | 
|  | rc = TRUE; | 
|  | } | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmNotifyIME (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmNotifyIME( | 
|  | HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("(%p, %d, %d, %d)\n", | 
|  | hIMC, dwAction, dwIndex, dwValue); | 
|  |  | 
|  | if (!data || ! data->immKbd->pNotifyIME) | 
|  | return FALSE; | 
|  |  | 
|  | return data->immKbd->pNotifyIME(hIMC,dwAction,dwIndex,dwValue); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmRegisterWordA (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmRegisterWordA( | 
|  | HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  | TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle, | 
|  | debugstr_a(lpszRegister)); | 
|  | if (immHkl->hIME && immHkl->pImeRegisterWord) | 
|  | { | 
|  | if (!is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeRegisterWord((LPCWSTR)lpszReading,dwStyle, | 
|  | (LPCWSTR)lpszRegister); | 
|  | else | 
|  | { | 
|  | LPWSTR lpszwReading = strdupAtoW(lpszReading); | 
|  | LPWSTR lpszwRegister = strdupAtoW(lpszRegister); | 
|  | BOOL rc; | 
|  |  | 
|  | rc = immHkl->pImeRegisterWord(lpszwReading,dwStyle,lpszwRegister); | 
|  | HeapFree(GetProcessHeap(),0,lpszwReading); | 
|  | HeapFree(GetProcessHeap(),0,lpszwRegister); | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmRegisterWordW (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmRegisterWordW( | 
|  | HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  | TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle, | 
|  | debugstr_w(lpszRegister)); | 
|  | if (immHkl->hIME && immHkl->pImeRegisterWord) | 
|  | { | 
|  | if (is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeRegisterWord(lpszReading,dwStyle,lpszRegister); | 
|  | else | 
|  | { | 
|  | LPSTR lpszaReading = strdupWtoA(lpszReading); | 
|  | LPSTR lpszaRegister = strdupWtoA(lpszRegister); | 
|  | BOOL rc; | 
|  |  | 
|  | rc = immHkl->pImeRegisterWord((LPCWSTR)lpszaReading,dwStyle, | 
|  | (LPCWSTR)lpszaRegister); | 
|  | HeapFree(GetProcessHeap(),0,lpszaReading); | 
|  | HeapFree(GetProcessHeap(),0,lpszaRegister); | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmReleaseContext (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC) | 
|  | { | 
|  | static int shown = 0; | 
|  |  | 
|  | if (!shown) { | 
|  | FIXME("(%p, %p): stub\n", hWnd, hIMC); | 
|  | shown = 1; | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              ImmRequestMessageA(IMM32.@) | 
|  | */ | 
|  | LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("%p %ld %ld\n", hIMC, wParam, wParam); | 
|  |  | 
|  | if (data && IsWindow(data->IMC.hWnd)) | 
|  | return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              ImmRequestMessageW(IMM32.@) | 
|  | */ | 
|  | LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("%p %ld %ld\n", hIMC, wParam, wParam); | 
|  |  | 
|  | if (data && IsWindow(data->IMC.hWnd)) | 
|  | return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmSetCandidateWindow (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmSetCandidateWindow( | 
|  | HIMC hIMC, LPCANDIDATEFORM lpCandidate) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("(%p, %p)\n", hIMC, lpCandidate); | 
|  |  | 
|  | if (!data || !lpCandidate) | 
|  | return FALSE; | 
|  |  | 
|  | TRACE("\t%x, %x, (%i,%i), (%i,%i - %i,%i)\n", | 
|  | lpCandidate->dwIndex, lpCandidate->dwStyle, | 
|  | lpCandidate->ptCurrentPos.x, lpCandidate->ptCurrentPos.y, | 
|  | lpCandidate->rcArea.top, lpCandidate->rcArea.left, | 
|  | lpCandidate->rcArea.bottom, lpCandidate->rcArea.right); | 
|  |  | 
|  | if ( lpCandidate->dwIndex >= (sizeof(data->IMC.cfCandForm) / sizeof(CANDIDATEFORM)) ) | 
|  | return FALSE; | 
|  |  | 
|  | data->IMC.cfCandForm[lpCandidate->dwIndex] = *lpCandidate; | 
|  | ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS); | 
|  | ImmInternalSendIMENotify(data, IMN_SETCANDIDATEPOS, 1 << lpCandidate->dwIndex); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmSetCompositionFontA (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  | TRACE("(%p, %p)\n", hIMC, lplf); | 
|  |  | 
|  | if (!data || !lplf) | 
|  | return FALSE; | 
|  |  | 
|  | memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA)); | 
|  | MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName, | 
|  | LF_FACESIZE); | 
|  | ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT); | 
|  | ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmSetCompositionFontW (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  | TRACE("(%p, %p)\n", hIMC, lplf); | 
|  |  | 
|  | if (!data || !lplf) | 
|  | return FALSE; | 
|  |  | 
|  | data->IMC.lfFont.W = *lplf; | 
|  | ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT); | 
|  | ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmSetCompositionStringA (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmSetCompositionStringA( | 
|  | HIMC hIMC, DWORD dwIndex, | 
|  | LPCVOID lpComp, DWORD dwCompLen, | 
|  | LPCVOID lpRead, DWORD dwReadLen) | 
|  | { | 
|  | DWORD comp_len; | 
|  | DWORD read_len; | 
|  | WCHAR *CompBuffer = NULL; | 
|  | WCHAR *ReadBuffer = NULL; | 
|  | BOOL rc; | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("(%p, %d, %p, %d, %p, %d):\n", | 
|  | hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); | 
|  |  | 
|  | if (!data) | 
|  | return FALSE; | 
|  |  | 
|  | if (!(dwIndex == SCS_SETSTR || | 
|  | dwIndex == SCS_CHANGEATTR || | 
|  | dwIndex == SCS_CHANGECLAUSE || | 
|  | dwIndex == SCS_SETRECONVERTSTRING || | 
|  | dwIndex == SCS_QUERYRECONVERTSTRING)) | 
|  | return FALSE; | 
|  |  | 
|  | if (!is_himc_ime_unicode(data)) | 
|  | return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp, | 
|  | dwCompLen, lpRead, dwReadLen); | 
|  |  | 
|  | comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0); | 
|  | if (comp_len) | 
|  | { | 
|  | CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR)); | 
|  | MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len); | 
|  | } | 
|  |  | 
|  | read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0); | 
|  | if (read_len) | 
|  | { | 
|  | ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR)); | 
|  | MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len); | 
|  | } | 
|  |  | 
|  | rc =  ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len, | 
|  | ReadBuffer, read_len); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, CompBuffer); | 
|  | HeapFree(GetProcessHeap(), 0, ReadBuffer); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmSetCompositionStringW (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmSetCompositionStringW( | 
|  | HIMC hIMC, DWORD dwIndex, | 
|  | LPCVOID lpComp, DWORD dwCompLen, | 
|  | LPCVOID lpRead, DWORD dwReadLen) | 
|  | { | 
|  | DWORD comp_len; | 
|  | DWORD read_len; | 
|  | CHAR *CompBuffer = NULL; | 
|  | CHAR *ReadBuffer = NULL; | 
|  | BOOL rc; | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("(%p, %d, %p, %d, %p, %d):\n", | 
|  | hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); | 
|  |  | 
|  | if (!data) | 
|  | return FALSE; | 
|  |  | 
|  | if (!(dwIndex == SCS_SETSTR || | 
|  | dwIndex == SCS_CHANGEATTR || | 
|  | dwIndex == SCS_CHANGECLAUSE || | 
|  | dwIndex == SCS_SETRECONVERTSTRING || | 
|  | dwIndex == SCS_QUERYRECONVERTSTRING)) | 
|  | return FALSE; | 
|  |  | 
|  | if (is_himc_ime_unicode(data)) | 
|  | return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp, | 
|  | dwCompLen, lpRead, dwReadLen); | 
|  |  | 
|  | comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL, | 
|  | NULL); | 
|  | if (comp_len) | 
|  | { | 
|  | CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len); | 
|  | WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len, | 
|  | NULL, NULL); | 
|  | } | 
|  |  | 
|  | read_len = WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, NULL, 0, NULL, | 
|  | NULL); | 
|  | if (read_len) | 
|  | { | 
|  | ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len); | 
|  | WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len, | 
|  | NULL, NULL); | 
|  | } | 
|  |  | 
|  | rc =  ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len, | 
|  | ReadBuffer, read_len); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, CompBuffer); | 
|  | HeapFree(GetProcessHeap(), 0, ReadBuffer); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmSetCompositionWindow (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmSetCompositionWindow( | 
|  | HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) | 
|  | { | 
|  | BOOL reshow = FALSE; | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("(%p, %p)\n", hIMC, lpCompForm); | 
|  | TRACE("\t%x, (%i,%i), (%i,%i - %i,%i)\n",lpCompForm->dwStyle, | 
|  | lpCompForm->ptCurrentPos.x, lpCompForm->ptCurrentPos.y, lpCompForm->rcArea.top, | 
|  | lpCompForm->rcArea.left, lpCompForm->rcArea.bottom, lpCompForm->rcArea.right); | 
|  |  | 
|  | if (!data) | 
|  | return FALSE; | 
|  |  | 
|  | data->IMC.cfCompForm = *lpCompForm; | 
|  |  | 
|  | if (IsWindowVisible(IMM_GetThreadData()->hwndDefault)) | 
|  | { | 
|  | reshow = TRUE; | 
|  | ShowWindow(IMM_GetThreadData()->hwndDefault,SW_HIDE); | 
|  | } | 
|  |  | 
|  | /* FIXME: this is a partial stub */ | 
|  |  | 
|  | if (reshow) | 
|  | ShowWindow(IMM_GetThreadData()->hwndDefault,SW_SHOWNOACTIVATE); | 
|  |  | 
|  | ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmSetConversionStatus (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmSetConversionStatus( | 
|  | HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence) | 
|  | { | 
|  | DWORD oldConversion, oldSentence; | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("%p %d %d\n", hIMC, fdwConversion, fdwSentence); | 
|  |  | 
|  | if (!data) | 
|  | return FALSE; | 
|  |  | 
|  | if ( fdwConversion != data->IMC.fdwConversion ) | 
|  | { | 
|  | oldConversion = data->IMC.fdwConversion; | 
|  | data->IMC.fdwConversion = fdwConversion; | 
|  | ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE); | 
|  | ImmInternalSendIMENotify(data, IMN_SETCONVERSIONMODE, 0); | 
|  | } | 
|  | if ( fdwSentence != data->IMC.fdwSentence ) | 
|  | { | 
|  | oldSentence = data->IMC.fdwSentence; | 
|  | data->IMC.fdwSentence = fdwSentence; | 
|  | ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE); | 
|  | ImmInternalSendIMENotify(data, IMN_SETSENTENCEMODE, 0); | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmSetOpenStatus (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("%p %d\n", hIMC, fOpen); | 
|  |  | 
|  | if (!data) | 
|  | return FALSE; | 
|  |  | 
|  | if (data->imeWnd == NULL) | 
|  | { | 
|  | /* create the ime window */ | 
|  | data->imeWnd = CreateWindowExW( WS_EX_TOOLWINDOW, | 
|  | data->immKbd->imeClassName, NULL, WS_POPUP, 0, 0, 1, 1, 0, | 
|  | 0, data->immKbd->hIME, 0); | 
|  | SetWindowLongPtrW(data->imeWnd, IMMGWL_IMC, (LONG_PTR)data); | 
|  | IMM_GetThreadData()->hwndDefault = data->imeWnd; | 
|  | } | 
|  |  | 
|  | if (!fOpen != !data->IMC.fOpen) | 
|  | { | 
|  | data->IMC.fOpen = fOpen; | 
|  | ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS); | 
|  | ImmInternalSendIMENotify(data, IMN_SETOPENSTATUS, 0); | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmSetStatusWindowPos (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("(%p, %p)\n", hIMC, lpptPos); | 
|  |  | 
|  | if (!data || !lpptPos) | 
|  | return FALSE; | 
|  |  | 
|  | TRACE("\t(%i,%i)\n", lpptPos->x, lpptPos->y); | 
|  |  | 
|  | data->IMC.ptStatusWndPos = *lpptPos; | 
|  | ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS); | 
|  | ImmInternalSendIMENotify(data, IMN_SETSTATUSWINDOWPOS, 0); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              ImmCreateSoftKeyboard(IMM32.@) | 
|  | */ | 
|  | HWND WINAPI ImmCreateSoftKeyboard(UINT uType, UINT hOwner, int x, int y) | 
|  | { | 
|  | FIXME("(%d, %d, %d, %d): stub\n", uType, hOwner, x, y); | 
|  | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              ImmDestroySoftKeyboard(IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmDestroySoftKeyboard(HWND hSoftWnd) | 
|  | { | 
|  | FIXME("(%p): stub\n", hSoftWnd); | 
|  | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              ImmShowSoftKeyboard(IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmShowSoftKeyboard(HWND hSoftWnd, int nCmdShow) | 
|  | { | 
|  | FIXME("(%p, %d): stub\n", hSoftWnd, nCmdShow); | 
|  | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmSimulateHotKey (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID) | 
|  | { | 
|  | FIXME("(%p, %d): stub\n", hWnd, dwHotKeyID); | 
|  | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmUnregisterWordA (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmUnregisterWordA( | 
|  | HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  | TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_a(lpszReading), dwStyle, | 
|  | debugstr_a(lpszUnregister)); | 
|  | if (immHkl->hIME && immHkl->pImeUnregisterWord) | 
|  | { | 
|  | if (!is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeUnregisterWord((LPCWSTR)lpszReading,dwStyle, | 
|  | (LPCWSTR)lpszUnregister); | 
|  | else | 
|  | { | 
|  | LPWSTR lpszwReading = strdupAtoW(lpszReading); | 
|  | LPWSTR lpszwUnregister = strdupAtoW(lpszUnregister); | 
|  | BOOL rc; | 
|  |  | 
|  | rc = immHkl->pImeUnregisterWord(lpszwReading,dwStyle,lpszwUnregister); | 
|  | HeapFree(GetProcessHeap(),0,lpszwReading); | 
|  | HeapFree(GetProcessHeap(),0,lpszwUnregister); | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmUnregisterWordW (IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmUnregisterWordW( | 
|  | HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister) | 
|  | { | 
|  | ImmHkl *immHkl = IMM_GetImmHkl(hKL); | 
|  | TRACE("(%p, %s, %d, %s):\n", hKL, debugstr_w(lpszReading), dwStyle, | 
|  | debugstr_w(lpszUnregister)); | 
|  | if (immHkl->hIME && immHkl->pImeUnregisterWord) | 
|  | { | 
|  | if (is_kbd_ime_unicode(immHkl)) | 
|  | return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister); | 
|  | else | 
|  | { | 
|  | LPSTR lpszaReading = strdupWtoA(lpszReading); | 
|  | LPSTR lpszaUnregister = strdupWtoA(lpszUnregister); | 
|  | BOOL rc; | 
|  |  | 
|  | rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle, | 
|  | (LPCWSTR)lpszaUnregister); | 
|  | HeapFree(GetProcessHeap(),0,lpszaReading); | 
|  | HeapFree(GetProcessHeap(),0,lpszaUnregister); | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetImeMenuItemsA (IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType, | 
|  | LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu, | 
|  | DWORD dwSize) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  | TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType, | 
|  | lpImeParentMenu, lpImeMenu, dwSize); | 
|  | if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems) | 
|  | { | 
|  | if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu)) | 
|  | return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, | 
|  | (IMEMENUITEMINFOW*)lpImeParentMenu, | 
|  | (IMEMENUITEMINFOW*)lpImeMenu, dwSize); | 
|  | else | 
|  | { | 
|  | IMEMENUITEMINFOW lpImeParentMenuW; | 
|  | IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL; | 
|  | DWORD rc; | 
|  |  | 
|  | if (lpImeParentMenu) | 
|  | parent = &lpImeParentMenuW; | 
|  | if (lpImeMenu) | 
|  | { | 
|  | int count = dwSize / sizeof(LPIMEMENUITEMINFOA); | 
|  | dwSize = count * sizeof(IMEMENUITEMINFOW); | 
|  | lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize); | 
|  | } | 
|  | else | 
|  | lpImeMenuW = NULL; | 
|  |  | 
|  | rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, | 
|  | parent, lpImeMenuW, dwSize); | 
|  |  | 
|  | if (lpImeParentMenu) | 
|  | { | 
|  | memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA)); | 
|  | lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem; | 
|  | WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString, | 
|  | -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE, | 
|  | NULL, NULL); | 
|  | } | 
|  | if (lpImeMenu && rc) | 
|  | { | 
|  | unsigned int i; | 
|  | for (i = 0; i < rc; i++) | 
|  | { | 
|  | memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA)); | 
|  | lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem; | 
|  | WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString, | 
|  | -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE, | 
|  | NULL, NULL); | 
|  | } | 
|  | } | 
|  | HeapFree(GetProcessHeap(),0,lpImeMenuW); | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetImeMenuItemsW (IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType, | 
|  | LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu, | 
|  | DWORD dwSize) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  | TRACE("(%p, %i, %i, %p, %p, %i):\n", hIMC, dwFlags, dwType, | 
|  | lpImeParentMenu, lpImeMenu, dwSize); | 
|  | if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems) | 
|  | { | 
|  | if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu)) | 
|  | return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, | 
|  | lpImeParentMenu, lpImeMenu, dwSize); | 
|  | else | 
|  | { | 
|  | IMEMENUITEMINFOA lpImeParentMenuA; | 
|  | IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL; | 
|  | DWORD rc; | 
|  |  | 
|  | if (lpImeParentMenu) | 
|  | parent = &lpImeParentMenuA; | 
|  | if (lpImeMenu) | 
|  | { | 
|  | int count = dwSize / sizeof(LPIMEMENUITEMINFOW); | 
|  | dwSize = count * sizeof(IMEMENUITEMINFOA); | 
|  | lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize); | 
|  | } | 
|  | else | 
|  | lpImeMenuA = NULL; | 
|  |  | 
|  | rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, | 
|  | (IMEMENUITEMINFOW*)parent, | 
|  | (IMEMENUITEMINFOW*)lpImeMenuA, dwSize); | 
|  |  | 
|  | if (lpImeParentMenu) | 
|  | { | 
|  | memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA)); | 
|  | lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem; | 
|  | MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString, | 
|  | -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE); | 
|  | } | 
|  | if (lpImeMenu && rc) | 
|  | { | 
|  | unsigned int i; | 
|  | for (i = 0; i < rc; i++) | 
|  | { | 
|  | memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA)); | 
|  | lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem; | 
|  | MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString, | 
|  | -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE); | 
|  | } | 
|  | } | 
|  | HeapFree(GetProcessHeap(),0,lpImeMenuA); | 
|  | return rc; | 
|  | } | 
|  | } | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmLockIMC(IMM32.@) | 
|  | */ | 
|  | LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | if (!data) | 
|  | return NULL; | 
|  | data->dwLock++; | 
|  | return &data->IMC; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmUnlockIMC(IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmUnlockIMC(HIMC hIMC) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  | data->dwLock--; | 
|  | return (data->dwLock!=0); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetIMCLockCount(IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  | return data->dwLock; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmCreateIMCC(IMM32.@) | 
|  | */ | 
|  | HIMCC  WINAPI ImmCreateIMCC(DWORD size) | 
|  | { | 
|  | IMCCInternal *internal; | 
|  | int real_size = size + sizeof(IMCCInternal); | 
|  |  | 
|  | internal = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, real_size); | 
|  | if (internal == NULL) | 
|  | return NULL; | 
|  |  | 
|  | internal->dwSize = size; | 
|  | return  internal; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       ImmDestroyIMCC(IMM32.@) | 
|  | */ | 
|  | HIMCC WINAPI ImmDestroyIMCC(HIMCC block) | 
|  | { | 
|  | HeapFree(GetProcessHeap(),0,block); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmLockIMCC(IMM32.@) | 
|  | */ | 
|  | LPVOID WINAPI ImmLockIMCC(HIMCC imcc) | 
|  | { | 
|  | IMCCInternal *internal; | 
|  | internal = imcc; | 
|  |  | 
|  | internal->dwLock ++; | 
|  | return internal + 1; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmUnlockIMCC(IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmUnlockIMCC(HIMCC imcc) | 
|  | { | 
|  | IMCCInternal *internal; | 
|  | internal = imcc; | 
|  |  | 
|  | internal->dwLock --; | 
|  | return (internal->dwLock!=0); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetIMCCLockCount(IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc) | 
|  | { | 
|  | IMCCInternal *internal; | 
|  | internal = imcc; | 
|  |  | 
|  | return internal->dwLock; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmReSizeIMCC(IMM32.@) | 
|  | */ | 
|  | HIMCC  WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size) | 
|  | { | 
|  | IMCCInternal *internal,*newone; | 
|  | int real_size = size + sizeof(IMCCInternal); | 
|  |  | 
|  | internal = imcc; | 
|  |  | 
|  | newone = HeapReAlloc(GetProcessHeap(), 0, internal, real_size); | 
|  | newone->dwSize = size; | 
|  |  | 
|  | return newone; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGetIMCCSize(IMM32.@) | 
|  | */ | 
|  | DWORD WINAPI ImmGetIMCCSize(HIMCC imcc) | 
|  | { | 
|  | IMCCInternal *internal; | 
|  | internal = imcc; | 
|  |  | 
|  | return internal->dwSize; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmGenerateMessage(IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmGenerateMessage(HIMC hIMC) | 
|  | { | 
|  | InputContextData *data = hIMC; | 
|  |  | 
|  | TRACE("%i messages queued\n",data->IMC.dwNumMsgBuf); | 
|  | if (data->IMC.dwNumMsgBuf > 0) | 
|  | { | 
|  | LPTRANSMSG lpTransMsg; | 
|  | DWORD i; | 
|  |  | 
|  | lpTransMsg = ImmLockIMCC(data->IMC.hMsgBuf); | 
|  | for (i = 0; i < data->IMC.dwNumMsgBuf; i++) | 
|  | ImmInternalPostIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam); | 
|  |  | 
|  | ImmUnlockIMCC(data->IMC.hMsgBuf); | 
|  |  | 
|  | data->IMC.dwNumMsgBuf = 0; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       ImmTranslateMessage(IMM32.@) | 
|  | *       ( Undocumented, call internally and from user32.dll ) | 
|  | */ | 
|  | BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData) | 
|  | { | 
|  | InputContextData *data; | 
|  | HIMC imc = ImmGetContext(hwnd); | 
|  | BYTE state[256]; | 
|  | UINT scancode; | 
|  | LPVOID list = 0; | 
|  | UINT msg_count; | 
|  | UINT uVirtKey; | 
|  | static const DWORD list_count = 10; | 
|  |  | 
|  | TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData); | 
|  |  | 
|  | if (imc) | 
|  | data = imc; | 
|  | else | 
|  | return FALSE; | 
|  |  | 
|  | if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx) | 
|  | return FALSE; | 
|  |  | 
|  | GetKeyboardState(state); | 
|  | scancode = lKeyData >> 0x10 & 0xff; | 
|  |  | 
|  | list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD)); | 
|  | ((DWORD*)list)[0] = list_count; | 
|  |  | 
|  | if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST) | 
|  | { | 
|  | WCHAR chr; | 
|  |  | 
|  | if (!is_himc_ime_unicode(data)) | 
|  | ToAscii(data->lastVK, scancode, state, &chr, 0); | 
|  | else | 
|  | ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0)); | 
|  | uVirtKey = MAKELONG(data->lastVK,chr); | 
|  | } | 
|  | else | 
|  | uVirtKey = data->lastVK; | 
|  |  | 
|  | msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc); | 
|  | TRACE("%i messages generated\n",msg_count); | 
|  | if (msg_count && msg_count <= list_count) | 
|  | { | 
|  | UINT i; | 
|  | LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD)); | 
|  |  | 
|  | for (i = 0; i < msg_count; i++) | 
|  | ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam); | 
|  | } | 
|  | else if (msg_count > list_count) | 
|  | ImmGenerateMessage(imc); | 
|  |  | 
|  | HeapFree(GetProcessHeap(),0,list); | 
|  |  | 
|  | data->lastVK = VK_PROCESSKEY; | 
|  |  | 
|  | return (msg_count > 0); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmProcessKey(IMM32.@) | 
|  | *       ( Undocumented, called from user32.dll ) | 
|  | */ | 
|  | BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown) | 
|  | { | 
|  | InputContextData *data; | 
|  | HIMC imc = ImmGetContext(hwnd); | 
|  | BYTE state[256]; | 
|  |  | 
|  | TRACE("%p %p %x %x %x\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown); | 
|  |  | 
|  | if (imc) | 
|  | data = imc; | 
|  | else | 
|  | return FALSE; | 
|  |  | 
|  | if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey) | 
|  | return FALSE; | 
|  |  | 
|  | GetKeyboardState(state); | 
|  | if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state)) | 
|  | { | 
|  | data->lastVK = vKey; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | data->lastVK = VK_PROCESSKEY; | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ImmDisableTextFrameService(IMM32.@) | 
|  | */ | 
|  | BOOL WINAPI ImmDisableTextFrameService(DWORD idThread) | 
|  | { | 
|  | FIXME("Stub\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              ImmEnumInputContext(IMM32.@) | 
|  | */ | 
|  |  | 
|  | BOOL WINAPI ImmEnumInputContext(DWORD idThread, IMCENUMPROC lpfn, LPARAM lParam) | 
|  | { | 
|  | FIXME("Stub\n"); | 
|  | return FALSE; | 
|  | } |