https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c45a6e15bf7c8a4144fde7...
commit c45a6e15bf7c8a4144fde71a1a92624d1ad269be Author: James Tabor james.tabor@reactos.org AuthorDate: Thu Dec 7 21:14:21 2017 -0600
[User32|IMM32] Fix a recursion crash in IMM. See CORE-14041.
Required a sync port from wine. This is a hack fix with Win32SS until proper IMM support is added to Win32SS. --- dll/win32/imm32/imm.c | 541 ++++++++++++++++++++++------------ dll/win32/imm32/imm32.spec | 6 + media/doc/README.WINE | 2 +- sdk/include/psdk/winbase.h | 1 + win32ss/user/ntuser/simplecall.c | 4 + win32ss/user/user32/include/user32p.h | 1 + win32ss/user/user32/misc/imm.c | 56 +++- win32ss/user/user32/misc/logon.c | 3 + win32ss/user/user32/windows/defwnd.c | 142 ++++----- 9 files changed, 469 insertions(+), 287 deletions(-)
diff --git a/dll/win32/imm32/imm.c b/dll/win32/imm32/imm.c index f3c76d22b8..0c98c58298 100644 --- a/dll/win32/imm32/imm.c +++ b/dll/win32/imm32/imm.c @@ -39,6 +39,9 @@
WINE_DEFAULT_DEBUG_CHANNEL(imm);
+#define IMM_INIT_MAGIC 0x19650412 +BOOL WINAPI User32InitializeImmEntryTable(DWORD); + #define MAKE_FUNCPTR(f) typeof(f) * p##f typedef struct _tagImmHkl{ struct list entry; @@ -73,9 +76,11 @@ typedef struct tagInputContextData { DWORD dwLock; INPUTCONTEXT IMC; + DWORD threadID;
ImmHkl *immKbd; UINT lastVK; + BOOL threadDefault; DWORD magic; } InputContextData;
@@ -88,21 +93,16 @@ typedef struct _tagTRANSMSG { } TRANSMSG, *LPTRANSMSG;
typedef struct _tagIMMThreadData { + struct list entry; + DWORD threadID; HIMC defaultContext; HWND hwndDefault; + BOOL disableIME; + DWORD windowRefs; } 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 struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
static const WCHAR szwWineIMCProperty[] = {'W','i','n','e','I','m','m','H','I','M','C','P','r','o','p','e','r','t','y',0};
@@ -111,14 +111,23 @@ static const WCHAR szLayoutTextW[] = {'L','a','y','o','u','t',' ','T','e','x','t 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};
static const WCHAR szwIME[] = {'I','M','E',0}; +static const WCHAR szwDefaultIME[] = {'D','e','f','a','u','l','t',' ','I','M','E',0};
-static LRESULT WINAPI DefIME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, - LPARAM lParam); +static CRITICAL_SECTION threaddata_cs; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &threaddata_cs, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") } +}; +static CRITICAL_SECTION threaddata_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; +static BOOL disable_ime;
#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 InputContextData* get_imc_data(HIMC hIMC);
static inline WCHAR *strdupAtoW( const char *str ) { @@ -222,29 +231,66 @@ static DWORD convert_candidatelist_AtoW( return ret; }
-static IMMThreadData* IMM_GetThreadData(void) +static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread) { - IMMThreadData* data = TlsGetValue(tlsIndex); - if (!data) + IMMThreadData *data; + DWORD process; + + if (hwnd) { - data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(IMMThreadData)); - TlsSetValue(tlsIndex,data); - TRACE("Thread Data Created\n"); + if (!(thread = GetWindowThreadProcessId(hwnd, &process))) return NULL; + if (process != GetCurrentProcessId()) return NULL; } + else if (thread) + { + HANDLE h = OpenThread(THREAD_QUERY_INFORMATION, FALSE, thread); + if (!h) return NULL; + process = GetProcessIdOfThread(h); + CloseHandle(h); + if (process != GetCurrentProcessId()) return NULL; + } + else + thread = GetCurrentThreadId(); + + EnterCriticalSection(&threaddata_cs); + LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry) + if (data->threadID == thread) return data; + + data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data)); + data->threadID = thread; + list_add_head(&ImmThreadDataList,&data->entry); + TRACE("Thread Data Created (%x)\n",thread); return data; }
+static BOOL IMM_IsDefaultContext(HIMC imc) +{ + InputContextData *data = get_imc_data(imc); + + if (!data) + return FALSE; + + return data->threadDefault; +} + static void IMM_FreeThreadData(void) { - IMMThreadData* data = TlsGetValue(tlsIndex); - if (data) + IMMThreadData *data; + + EnterCriticalSection(&threaddata_cs); + LIST_FOR_EACH_ENTRY(data, &ImmThreadDataList, IMMThreadData, entry) { - IMM_DestroyContext(data->defaultContext); - DestroyWindow(data->hwndDefault); - HeapFree(GetProcessHeap(),0,data); - TRACE("Thread Data Destroyed\n"); + if (data->threadID == GetCurrentThreadId()) + { + list_remove(&data->entry); + LeaveCriticalSection(&threaddata_cs); + IMM_DestroyContext(data->defaultContext); + HeapFree(GetProcessHeap(),0,data); + TRACE("Thread Data Destroyed\n"); + return; + } } + LeaveCriticalSection(&threaddata_cs); }
static HMODULE load_graphics_driver(void) @@ -349,6 +395,12 @@ static ImmHkl *IMM_GetImmHkl(HKL hkl) } #undef LOAD_FUNCPTR
+HWND WINAPI __wine_get_ui_window(HKL hkl) +{ + ImmHkl *immHkl = IMM_GetImmHkl(hkl); + return immHkl->UIWnd; +} + static void IMM_FreeAllImmHkl(void) { ImmHkl *ptr,*cursor2; @@ -367,43 +419,16 @@ static void IMM_FreeAllImmHkl(void) } }
-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"); -} - -static void IMM_RegisterIMEClass(void) -{ - WNDCLASSW wndClass; - - ZeroMemory(&wndClass, sizeof(WNDCLASSW)); - - wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = (WNDPROC) DefIME_WindowProc; - wndClass.cbWndExtra = 2 * sizeof(LONG_PTR); - wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW); - wndClass.lpszClassName = szwIME; - - RegisterClassW(&wndClass); -} - 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) + if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC)) + { return FALSE; - IMM_RegisterIMEClass(); + } break; case DLL_THREAD_ATTACH: break; @@ -414,8 +439,6 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved) if (lpReserved) break; IMM_FreeThreadData(); IMM_FreeAllImmHkl(); - TlsFree(tlsIndex); - UnregisterClassW(szwIME, NULL); break; } return TRUE; @@ -431,6 +454,16 @@ static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM w PostMessageW(target, msg, wParam, lParam); }
+/* for sending messages as the IME */ +static void ImmInternalSendIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HWND target = GetFocus(); + if (!target) + SendMessageW(data->IMC.hWnd,msg,wParam,lParam); + else + SendMessageW(target, msg, wParam, lParam); +} + static LRESULT ImmInternalSendIMENotify(InputContextData *data, WPARAM notify, LPARAM lParam) { HWND target; @@ -471,6 +504,63 @@ static InputContextData* get_imc_data(HIMC hIMC) return data; }
+static HIMC get_default_context( HWND hwnd ) +{ + HIMC ret; + IMMThreadData* thread_data = IMM_GetThreadData( hwnd, 0 ); + + if (!thread_data) return 0; + + if (thread_data->defaultContext) + { + ret = thread_data->defaultContext; + LeaveCriticalSection(&threaddata_cs); + return ret; + } + + /* can't create a default context in another thread */ + if (thread_data->threadID != GetCurrentThreadId()) + { + LeaveCriticalSection(&threaddata_cs); + return 0; + } + + LeaveCriticalSection(&threaddata_cs); + + ret = ImmCreateContext(); + if (!ret) return 0; + ((InputContextData*)ret)->threadDefault = TRUE; + + /* thread_data is in the current thread so we can assume it's still valid */ + EnterCriticalSection(&threaddata_cs); + + if (thread_data->defaultContext) /* someone beat us */ + { + IMM_DestroyContext( ret ); + ret = thread_data->defaultContext; + } + else thread_data->defaultContext = ret; + + LeaveCriticalSection(&threaddata_cs); + return ret; +} + +static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC) +{ + InputContextData *data; + + if (hWnd) + { + DWORD thread = GetWindowThreadProcessId(hWnd, NULL); + if (thread != GetCurrentThreadId()) return TRUE; + } + data = get_imc_data(hIMC); + if (data && data->threadID != GetCurrentThreadId()) + return TRUE; + + return FALSE; +} + /*********************************************************************** * ImmAssociateContext (IMM32.@) */ @@ -484,25 +574,26 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC) if(hIMC && !data) return NULL;
- if (!IMM_GetThreadData()->defaultContext) - IMM_GetThreadData()->defaultContext = ImmCreateContext(); - /* * If already associated just return */ if (hIMC && data->IMC.hWnd == hWnd) return hIMC;
+ if (hIMC && IMM_IsCrossThreadAccess(hWnd, hIMC)) + return NULL; + if (hWnd) { + HIMC defaultContext = get_default_context( hWnd ); old = RemovePropW(hWnd,szwWineIMCProperty);
if (old == NULL) - old = IMM_GetThreadData()->defaultContext; + old = defaultContext; else if (old == (HIMC)-1) old = NULL;
- if (hIMC != IMM_GetThreadData()->defaultContext) + if (hIMC != defaultContext) { if (hIMC == NULL) /* Meaning disable imm for that window*/ SetPropW(hWnd,szwWineIMCProperty,(HANDLE)-1); @@ -521,23 +612,9 @@ HIMC WINAPI ImmAssociateContext(HWND hWnd, HIMC hIMC) 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); - } - + 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); - } + SendMessageW(data->IMC.hWnd, WM_IME_SETCONTEXT, TRUE, ISC_SHOWUIALL);
return old; } @@ -560,10 +637,8 @@ 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; + if (!hWnd) + return FALSE;
switch (dwFlags) { @@ -571,8 +646,12 @@ BOOL WINAPI ImmAssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags) ImmAssociateContext(hWnd,hIMC); return TRUE; case IACE_DEFAULT: - ImmAssociateContext(hWnd,IMM_GetThreadData()->defaultContext); + { + HIMC defaultContext = get_default_context( hWnd ); + if (!defaultContext) return FALSE; + ImmAssociateContext(hWnd,defaultContext); return TRUE; + } case IACE_IGNORENOCONTEXT: if (GetPropW(hWnd,szwWineIMCProperty)) ImmAssociateContext(hWnd,hIMC); @@ -707,7 +786,8 @@ HIMC WINAPI ImmCreateContext(void) IMM_DestroyContext(new_context); return 0; } - SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)GetKeyboardLayout(0)); + new_context->threadID = GetCurrentThreadId(); + SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->immKbd);
new_context->immKbd->uSelected++; TRACE("Created context %p\n",new_context); @@ -727,7 +807,7 @@ static BOOL IMM_DestroyContext(HIMC hIMC)
data->immKbd->uSelected --; data->immKbd->pImeSelect(hIMC, FALSE); - SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)GetKeyboardLayout(0)); + SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd);
ImmDestroyIMCC(data->IMC.hCompStr); ImmDestroyIMCC(data->IMC.hCandInfo); @@ -746,7 +826,7 @@ static BOOL IMM_DestroyContext(HIMC hIMC) */ BOOL WINAPI ImmDestroyContext(HIMC hIMC) { - if (hIMC != IMM_GetThreadData()->defaultContext) + if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC)) return IMM_DestroyContext(hIMC); else return FALSE; @@ -757,7 +837,14 @@ BOOL WINAPI ImmDestroyContext(HIMC hIMC) */ BOOL WINAPI ImmDisableIME(DWORD idThread) { - FIXME("(%d): stub\n", idThread); + if (idThread == (DWORD)-1) + disable_ime = TRUE; + else { + IMMThreadData *thread_data = IMM_GetThreadData(NULL, idThread); + if (!thread_data) return FALSE; + thread_data->disableIME = TRUE; + LeaveCriticalSection(&threaddata_cs); + } return TRUE; }
@@ -1420,20 +1507,19 @@ HIMC WINAPI ImmGetContext(HWND hWnd) SetLastError(ERROR_INVALID_WINDOW_HANDLE); return NULL; } - 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; + rc = get_default_context( hWnd );
if (rc) { InputContextData *data = rc; data->IMC.hWnd = hWnd; } + TRACE("returning %p\n", rc);
return rc; @@ -1536,16 +1622,111 @@ BOOL WINAPI ImmGetConversionStatus( return TRUE; }
+static BOOL needs_ime_window(HWND hwnd) +{ + WCHAR classW[8]; + + if (GetClassNameW(hwnd, classW, sizeof(classW)/sizeof(classW[0])) && + !strcmpW(classW, szwIME)) + return FALSE; + if (GetClassLongPtrW(hwnd, GCL_STYLE) & CS_IME) return FALSE; + + return TRUE; +} + +/*********************************************************************** + * __wine_register_window (IMM32.@) + */ +BOOL WINAPI __wine_register_window(HWND hwnd) +{ + HWND new = NULL; + IMMThreadData *thread_data; + TRACE("(%p)\n", hwnd); + + if (!needs_ime_window(hwnd)) + return FALSE; + + thread_data = IMM_GetThreadData(hwnd, 0); + if (!thread_data) + return FALSE; + + if (thread_data->disableIME || disable_ime) + { + TRACE("IME for this thread is disabled\n"); + LeaveCriticalSection(&threaddata_cs); + return FALSE; + } + thread_data->windowRefs++; + TRACE("windowRefs=%u, hwndDefault=%p\n", + thread_data->windowRefs, thread_data->hwndDefault); + + /* Create default IME window */ + if (thread_data->windowRefs == 1) + { + /* Do not create the window inside of a critical section */ + LeaveCriticalSection(&threaddata_cs); + new = CreateWindowExW( 0, szwIME, szwDefaultIME, + WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS, + 0, 0, 1, 1, 0, 0, 0, 0); + /* thread_data is in the current thread so we can assume it's still valid */ + EnterCriticalSection(&threaddata_cs); + /* See if anyone beat us */ + if (thread_data->hwndDefault == NULL) + { + thread_data->hwndDefault = new; + new = NULL; + TRACE("Default is %p\n", thread_data->hwndDefault); + } + } + + LeaveCriticalSection(&threaddata_cs); + + /* Clean up an unused new window outside of the critical section */ + if (new != NULL) + DestroyWindow(new); + return TRUE; +} + +/*********************************************************************** + * __wine_unregister_window (IMM32.@) + */ +void WINAPI __wine_unregister_window(HWND hwnd) +{ + HWND to_destroy = 0; + IMMThreadData *thread_data; + TRACE("(%p)\n", hwnd); + + thread_data = IMM_GetThreadData(hwnd, 0); + if (!thread_data) return; + + thread_data->windowRefs--; + TRACE("windowRefs=%u, hwndDefault=%p\n", + thread_data->windowRefs, thread_data->hwndDefault); + + /* Destroy default IME window */ + if (thread_data->windowRefs == 0 && thread_data->hwndDefault) + { + to_destroy = thread_data->hwndDefault; + thread_data->hwndDefault = NULL; + } + LeaveCriticalSection(&threaddata_cs); + + if (to_destroy) DestroyWindow( to_destroy ); +} + /*********************************************************************** * ImmGetDefaultIMEWnd (IMM32.@) */ HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) { - if (IMM_GetThreadData()->hwndDefault == NULL) - IMM_GetThreadData()->hwndDefault = CreateWindowExW( WS_EX_TOOLWINDOW, - szwIME, NULL, WS_POPUP, 0, 0, 1, 1, 0, 0, 0, 0); - TRACE("Default is %p\n",IMM_GetThreadData()->hwndDefault); - return IMM_GetThreadData()->hwndDefault; + HWND ret; + IMMThreadData* thread_data = IMM_GetThreadData(hWnd, 0); + if (!thread_data) + return NULL; + ret = thread_data->hwndDefault; + LeaveCriticalSection(&threaddata_cs); + TRACE("Default is %p\n",ret); + return ret; }
/*********************************************************************** @@ -1947,28 +2128,20 @@ BOOL WINAPI ImmIsIME(HKL hKL) 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)) + (msg == 0x287 /* FIXME: WM_IME_SYSTEM */)) { if (hWndIME) SendMessageA(hWndIME, msg, wParam, lParam);
- rc = TRUE; + return TRUE; } - return rc; + return FALSE; }
/*********************************************************************** @@ -1977,28 +2150,20 @@ BOOL WINAPI ImmIsUIMessageA( 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)) + (msg == 0x287 /* FIXME: WM_IME_SYSTEM */)) { if (hWndIME) SendMessageW(hWndIME, msg, wParam, lParam);
- rc = TRUE; + return TRUE; } - return rc; + return FALSE; }
/*********************************************************************** @@ -2108,13 +2273,11 @@ LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam) InputContextData *data = get_imc_data(hIMC);
TRACE("%p %ld %ld\n", hIMC, wParam, wParam); - if (!data) - SetLastError(ERROR_INVALID_HANDLE);
- if (data && IsWindow(data->IMC.hWnd)) - return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); + if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
- return 0; + SetLastError(ERROR_INVALID_HANDLE); + return 0; }
/*********************************************************************** @@ -2126,13 +2289,10 @@ LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam)
TRACE("%p %ld %ld\n", hIMC, wParam, wParam);
- if (!data) - SetLastError(ERROR_INVALID_HANDLE); - - if (data && IsWindow(data->IMC.hWnd)) - return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); + if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam);
- return 0; + SetLastError(ERROR_INVALID_HANDLE); + return 0; }
/*********************************************************************** @@ -2148,11 +2308,13 @@ BOOL WINAPI ImmSetCandidateWindow( 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 (IMM_IsCrossThreadAccess(NULL, hIMC)) + return FALSE; + + TRACE("\t%x, %x, %s, %s\n", + lpCandidate->dwIndex, lpCandidate->dwStyle, + wine_dbgstr_point(&lpCandidate->ptCurrentPos), + wine_dbgstr_rect(&lpCandidate->rcArea));
if ( lpCandidate->dwIndex >= (sizeof(data->IMC.cfCandForm) / sizeof(CANDIDATEFORM)) ) return FALSE; @@ -2178,6 +2340,9 @@ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) return FALSE; }
+ if (IMM_IsCrossThreadAccess(NULL, hIMC)) + return FALSE; + memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA)); MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName, LF_FACESIZE); @@ -2201,6 +2366,9 @@ BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) return FALSE; }
+ if (IMM_IsCrossThreadAccess(NULL, hIMC)) + return FALSE; + data->IMC.lfFont.W = *lplf; ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT); ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0); @@ -2332,9 +2500,10 @@ BOOL WINAPI ImmSetCompositionWindow( InputContextData *data = get_imc_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 (lpCompForm) + TRACE("\t%x, %s, %s\n", lpCompForm->dwStyle, + wine_dbgstr_point(&lpCompForm->ptCurrentPos), + wine_dbgstr_rect(&lpCompForm->rcArea));
if (!data) { @@ -2342,6 +2511,9 @@ BOOL WINAPI ImmSetCompositionWindow( return FALSE; }
+ if (IMM_IsCrossThreadAccess(NULL, hIMC)) + return FALSE; + data->IMC.cfCompForm = *lpCompForm;
if (IsWindowVisible(data->immKbd->UIWnd)) @@ -2376,6 +2548,9 @@ BOOL WINAPI ImmSetConversionStatus( return FALSE; }
+ if (IMM_IsCrossThreadAccess(NULL, hIMC)) + return FALSE; + if ( fdwConversion != data->IMC.fdwConversion ) { oldConversion = data->IMC.fdwConversion; @@ -2409,6 +2584,9 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) return FALSE; }
+ if (IMM_IsCrossThreadAccess(NULL, hIMC)) + return FALSE; + if (data->immKbd->UIWnd == NULL) { /* create the ime window */ @@ -2445,7 +2623,10 @@ BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) return FALSE; }
- TRACE("\t(%i,%i)\n", lpptPos->x, lpptPos->y); + if (IMM_IsCrossThreadAccess(NULL, hIMC)) + return FALSE; + + TRACE("\t%s\n", wine_dbgstr_point(lpptPos));
data->IMC.ptStatusWndPos = *lpptPos; ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS); @@ -2805,15 +2986,23 @@ BOOL WINAPI ImmGenerateMessage(HIMC hIMC) 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); + HIMCC hMsgBuf; + DWORD i, dwNumMsgBuf;
- ImmUnlockIMCC(data->IMC.hMsgBuf); + /* We are going to detach our hMsgBuff so that if processing messages + generates new messages they go into a new buffer */ + hMsgBuf = data->IMC.hMsgBuf; + dwNumMsgBuf = data->IMC.dwNumMsgBuf;
+ data->IMC.hMsgBuf = ImmCreateIMCC(0); data->IMC.dwNumMsgBuf = 0; + + lpTransMsg = ImmLockIMCC(hMsgBuf); + for (i = 0; i < dwNumMsgBuf; i++) + ImmInternalSendIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam); + + ImmUnlockIMCC(hMsgBuf); + ImmDestroyIMCC(hMsgBuf); }
return TRUE; @@ -2900,6 +3089,22 @@ BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD else return FALSE;
+ /* Make sure we are inputting to the correct keyboard */ + if (data->immKbd->hkl != hKL) + { + ImmHkl *new_hkl = IMM_GetImmHkl(hKL); + if (new_hkl) + { + data->immKbd->pImeSelect(imc, FALSE); + data->immKbd->uSelected--; + data->immKbd = new_hkl; + data->immKbd->pImeSelect(imc, TRUE); + data->immKbd->uSelected++; + } + else + return FALSE; + } + if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey) return FALSE;
@@ -2942,53 +3147,3 @@ BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL hkl) FIXME("%x, %p, %p, %p: stub\n", hotkey, modifiers, key, hkl); return FALSE; } - - -/* - * Window Proc for the Default IME window class - */ -static LRESULT WINAPI DefIME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, - LPARAM lParam) -{ - switch (uMsg) - { - case WM_CREATE: - case WM_NCCREATE: - return TRUE; - case WM_IME_STARTCOMPOSITION: - case WM_IME_ENDCOMPOSITION: - case WM_IME_COMPOSITION: - case WM_IME_SETCONTEXT: - case WM_IME_NOTIFY: - case WM_IME_CONTROL: - case WM_IME_COMPOSITIONFULL: - case WM_IME_SELECT: - case WM_IME_CHAR: - case WM_IME_REQUEST: - case WM_IME_KEYDOWN: - case WM_IME_KEYUP: - { - ImmHkl *immHkl = IMM_GetImmHkl(GetKeyboardLayout(0)); - if (immHkl->UIWnd) - return SendMessageW(immHkl->UIWnd,uMsg,wParam,lParam); - else - return FALSE; - } - default: - if ((uMsg == WM_MSIME_RECONVERTOPTIONS) || - (uMsg == WM_MSIME_SERVICE) || - (uMsg == WM_MSIME_MOUSE) || - (uMsg == WM_MSIME_RECONVERTREQUEST) || - (uMsg == WM_MSIME_RECONVERT) || - (uMsg == WM_MSIME_QUERYPOSITION) || - (uMsg == WM_MSIME_DOCUMENTFEED)) - { - ImmHkl *immHkl = IMM_GetImmHkl(GetKeyboardLayout(0)); - if (immHkl->UIWnd) - return SendMessageW(immHkl->UIWnd,uMsg,wParam,lParam); - else - return FALSE; - } - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } -} diff --git a/dll/win32/imm32/imm32.spec b/dll/win32/imm32/imm32.spec index 37c46ab345..2be5d92b11 100644 --- a/dll/win32/imm32/imm32.spec +++ b/dll/win32/imm32/imm32.spec @@ -110,3 +110,9 @@ @ stub ImmWINNLSEnableIME @ stub ImmWINNLSGetEnableStatus @ stub ImmWINNLSGetIMEHotkey + +################################################################ +# Wine internal extensions +@ stdcall __wine_get_ui_window(ptr) +@ stdcall __wine_register_window(long) +@ stdcall __wine_unregister_window(long) diff --git a/media/doc/README.WINE b/media/doc/README.WINE index 8dcdd23aa5..3910789a16 100644 --- a/media/doc/README.WINE +++ b/media/doc/README.WINE @@ -77,7 +77,7 @@ reactos/dll/win32/iccvid # Synced to WineStaging-2.9 reactos/dll/win32/ieframe # Synced to WineStaging-2.9 reactos/dll/win32/imaadp32.acm # Synced to WineStaging-2.16 reactos/dll/win32/imagehlp # Synced to WineStaging-2.9 -reactos/dll/win32/imm32 # Synced to Wine-1.7.27 +reactos/dll/win32/imm32 # Synced to Wine-2.22 reactos/dll/win32/inetcomm # Synced to WineStaging-2.16 reactos/dll/win32/inetmib1 # Synced to WineStaging-2.9 reactos/dll/win32/initpki # Synced to WineStaging-2.9 diff --git a/sdk/include/psdk/winbase.h b/sdk/include/psdk/winbase.h index ec3615aa3e..e8c14cfddc 100644 --- a/sdk/include/psdk/winbase.h +++ b/sdk/include/psdk/winbase.h @@ -2266,6 +2266,7 @@ HANDLE WINAPI GetProcessHeap(VOID); DWORD WINAPI GetProcessHeaps(DWORD,PHANDLE); #if (_WIN32_WINNT >= 0x0502) DWORD WINAPI GetProcessId(HANDLE); +DWORD WINAPI GetProcessIdOfThread(HANDLE); #endif #if (_WIN32_WINNT >= 0x0500) BOOL WINAPI GetProcessIoCounters(_In_ HANDLE, _Out_ PIO_COUNTERS); diff --git a/win32ss/user/ntuser/simplecall.c b/win32ss/user/ntuser/simplecall.c index a32ed43b1c..4be533a8fb 100644 --- a/win32ss/user/ntuser/simplecall.c +++ b/win32ss/user/ntuser/simplecall.c @@ -113,6 +113,10 @@ NtUserCallNoParam(DWORD Routine) case NOPARAM_ROUTINE_ISCONSOLEMODE: RETURN( ScreenDeviceContext == NULL );
+ case NOPARAM_ROUTINE_UPDATEPERUSERIMMENABLING: + gpsi->dwSRVIFlags |= SRVINFO_IMM32; // Always set. + RETURN(1); // Always return TRUE. + default: ERR("Calling invalid routine number 0x%x in NtUserCallNoParam\n", Routine); EngSetLastError(ERROR_INVALID_PARAMETER); diff --git a/win32ss/user/user32/include/user32p.h b/win32ss/user/user32/include/user32p.h index cdf9378b2b..9bfaeecf83 100644 --- a/win32ss/user/user32/include/user32p.h +++ b/win32ss/user/user32/include/user32p.h @@ -134,5 +134,6 @@ VOID DeleteFrameBrushes(VOID); BOOL WINAPI GdiValidateHandle(HGDIOBJ); HANDLE FASTCALL UserGetProp(HWND hWnd, ATOM Atom, BOOLEAN SystemProp); BOOL WINAPI InitializeImmEntryTable(VOID); +BOOL WINAPI UpdatePerUserImmEnabling(VOID);
/* EOF */ diff --git a/win32ss/user/user32/misc/imm.c b/win32ss/user/user32/misc/imm.c index a89dafe271..9c26bcf199 100644 --- a/win32ss/user/user32/misc/imm.c +++ b/win32ss/user/user32/misc/imm.c @@ -25,19 +25,6 @@ HINSTANCE ghImm32 = NULL; BOOL bImmInitializing = FALSE; BOOL ImmApiTableZero = TRUE;
-HRESULT WINAPI GetImmFileName(PWSTR lpBuffer, UINT uSize) -{ - UINT length; - STRSAFE_LPWSTR Safe = lpBuffer; - - length = GetSystemDirectoryW(lpBuffer, uSize); - if ( length && length < uSize ) - { - StringCchCatW(Safe, uSize, L"\"); - return StringCchCatW(Safe, uSize, L"IMM32.DLL"); - } - return StringCchCopyW(Safe, uSize, L"IMM32.DLL"); -}
/* * This function should not be implemented, it is used, @@ -59,6 +46,20 @@ BOOL WINAPI IMM_ImmNotifyIME(HIMC himc, DWORD dword1, DWORD dword2, DWORD dword3 BOOL WINAPI IMM_ImmRegisterClient(PVOID ptr, HINSTANCE hMod) { return 0; } UINT WINAPI IMM_ImmProcessKey(HWND hwnd, HKL hkl, UINT Vk, LPARAM lParam, DWORD HotKey) { return 0; }
+HRESULT WINAPI GetImmFileName(PWSTR lpBuffer, UINT uSize) +{ + UINT length; + STRSAFE_LPWSTR Safe = lpBuffer; + + length = GetSystemDirectoryW(lpBuffer, uSize); + if ( length && length < uSize ) + { + StringCchCatW(Safe, uSize, L"\"); + return StringCchCatW(Safe, uSize, L"imm32.dll"); + } + return StringCchCopyW(Safe, uSize, L"imm32.dll"); +} + /* * @unimplemented */ @@ -189,7 +190,7 @@ BOOL WINAPI InitializeImmEntryTable(VOID)
BOOL WINAPI User32InitializeImmEntryTable(DWORD magic) { - TRACE("(%x)\n", magic); + TRACE("Imm (%x)\n", magic);
if (magic != IMM_INIT_MAGIC) return FALSE; @@ -205,9 +206,7 @@ BOOL WINAPI User32InitializeImmEntryTable(DWORD magic) if (ghImm32 == NULL && !bImmInitializing) { WCHAR ImmFile[MAX_PATH]; - ERR("IMM32 not installed!\n"); GetImmFileName(ImmFile, sizeof(ImmFile)); - ERR("File %ws\n",ImmFile); ghImm32 = LoadLibraryW(ImmFile); if (ghImm32 == NULL) { @@ -285,6 +284,30 @@ LRESULT WINAPI ImeWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) return ImeWndProc_common(hwnd, msg, wParam, lParam, TRUE); }
+BOOL +WINAPI +UpdatePerUserImmEnabling(VOID) +{ + BOOL Ret = NtUserCallNoParam(NOPARAM_ROUTINE_UPDATEPERUSERIMMENABLING); + if ( Ret ) + { + if ( gpsi->dwSRVIFlags & SRVINFO_IMM32 ) + { + HMODULE imm32 = GetModuleHandleW(L"imm32.dll"); + if ( !imm32 ) + { + imm32 = LoadLibraryW(L"imm32.dll"); + if (!imm32) + { + ERR("UPUIE: Imm32 not installed!\n"); + Ret = FALSE; + } + } + } + } + return Ret; +} + static const WCHAR imeW[] = {'I','M','E',0};
BOOL @@ -311,6 +334,7 @@ RegisterIMEClass(VOID) if (atom) { RegisterDefaultClasses |= ICLASS_TO_MASK(ICLS_IME); + TRACE("Register IME Class!\n"); return TRUE; } ERR("Failed to register IME Class!\n"); diff --git a/win32ss/user/user32/misc/logon.c b/win32ss/user/user32/misc/logon.c index abc6ee3d1d..3df5a953f0 100644 --- a/win32ss/user/user32/misc/logon.c +++ b/win32ss/user/user32/misc/logon.c @@ -107,5 +107,8 @@ WINAPI UpdatePerUserSystemParameters(DWORD dwReserved, BOOL bEnable) { + // Update Imm support and load Imm32.dll. + UpdatePerUserImmEnabling(); + return NtUserUpdatePerUserSystemParameters(dwReserved, bEnable); } diff --git a/win32ss/user/user32/windows/defwnd.c b/win32ss/user/user32/windows/defwnd.c index 27dcc574c5..9239775029 100644 --- a/win32ss/user/user32/windows/defwnd.c +++ b/win32ss/user/user32/windows/defwnd.c @@ -797,75 +797,6 @@ GoSS: }
-/* - * helpers for calling IMM32 (from Wine 10/22/2008) - * - * WM_IME_* messages are generated only by IMM32, - * so I assume imm32 is already LoadLibrary-ed. - */ -static HWND -DefWndImmGetDefaultIMEWnd(HWND hwnd) -{ - HINSTANCE hInstIMM = GetModuleHandleW(L"imm32\0"); - HWND (WINAPI *pFunc)(HWND); - HWND hwndRet = 0; - - if (!hInstIMM) - { - ERR("cannot get IMM32 handle\n"); - return 0; - } - - pFunc = (void*) GetProcAddress(hInstIMM, "ImmGetDefaultIMEWnd"); - if (pFunc != NULL) - hwndRet = (*pFunc)(hwnd); - - return hwndRet; -} - - -static BOOL -DefWndImmIsUIMessageA(HWND hwndIME, UINT msg, WPARAM wParam, LPARAM lParam) -{ - HINSTANCE hInstIMM = GetModuleHandleW(L"imm32\0"); - BOOL (WINAPI *pFunc)(HWND,UINT,WPARAM,LPARAM); - BOOL fRet = FALSE; - - if (!hInstIMM) - { - ERR("cannot get IMM32 handle\n"); - return FALSE; - } - - pFunc = (void*) GetProcAddress(hInstIMM, "ImmIsUIMessageA"); - if (pFunc != NULL) - fRet = (*pFunc)(hwndIME, msg, wParam, lParam); - - return fRet; -} - - -static BOOL -DefWndImmIsUIMessageW(HWND hwndIME, UINT msg, WPARAM wParam, LPARAM lParam) -{ - HINSTANCE hInstIMM = GetModuleHandleW(L"imm32\0"); - BOOL (WINAPI *pFunc)(HWND,UINT,WPARAM,LPARAM); - BOOL fRet = FALSE; - - if (!hInstIMM) - { - ERR("cannot get IMM32 handle\n"); - return FALSE; - } - - pFunc = (void*) GetProcAddress(hInstIMM, "ImmIsUIMessageW"); - if (pFunc != NULL) - fRet = (*pFunc)(hwndIME, msg, wParam, lParam); - - return fRet; -} - - LRESULT WINAPI RealDefWindowProcA(HWND hWnd, UINT Msg, @@ -1003,8 +934,44 @@ RealDefWindowProcA(HWND hWnd, break; }
- case WM_IME_STARTCOMPOSITION: case WM_IME_COMPOSITION: + if (lParam & GCS_RESULTSTR) + { + LONG size, i; + unsigned char lead = 0; + char *buf = NULL; + HIMC himc = ImmGetContext( hWnd ); + + if (himc) + { + if ((size = ImmGetCompositionStringA( himc, GCS_RESULTSTR, NULL, 0 ))) + { + if (!(buf = HeapAlloc( GetProcessHeap(), 0, size ))) size = 0; + else size = ImmGetCompositionStringA( himc, GCS_RESULTSTR, buf, size ); + } + ImmReleaseContext( hWnd, himc ); + + for (i = 0; i < size; i++) + { + unsigned char c = buf[i]; + if (!lead) + { + if (IsDBCSLeadByte( c )) + lead = c; + else + SendMessageA( hWnd, WM_IME_CHAR, c, 1 ); + } + else + { + SendMessageA( hWnd, WM_IME_CHAR, MAKEWORD(c, lead), 1 ); + lead = 0; + } + } + HeapFree( GetProcessHeap(), 0, buf ); + } + } + /* fall through */ + case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: case WM_IME_SELECT: case WM_IME_NOTIFY: @@ -1012,7 +979,7 @@ RealDefWindowProcA(HWND hWnd, { HWND hwndIME;
- hwndIME = DefWndImmGetDefaultIMEWnd(hWnd); + hwndIME = ImmGetDefaultIMEWnd(hWnd); if (hwndIME) Result = SendMessageA(hwndIME, Msg, wParam, lParam); break; @@ -1022,9 +989,9 @@ RealDefWindowProcA(HWND hWnd, { HWND hwndIME;
- hwndIME = DefWndImmGetDefaultIMEWnd(hWnd); + hwndIME = ImmGetDefaultIMEWnd(hWnd); if (hwndIME) - Result = DefWndImmIsUIMessageA(hwndIME, Msg, wParam, lParam); + Result = ImmIsUIMessageA(hwndIME, Msg, wParam, lParam); break; }
@@ -1165,8 +1132,29 @@ RealDefWindowProcW(HWND hWnd, break; }
- case WM_IME_STARTCOMPOSITION: case WM_IME_COMPOSITION: + if (lParam & GCS_RESULTSTR) + { + LONG size, i; + WCHAR *buf = NULL; + HIMC himc = ImmGetContext( hWnd ); + + if (himc) + { + if ((size = ImmGetCompositionStringW( himc, GCS_RESULTSTR, NULL, 0 ))) + { + if (!(buf = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) size = 0; + else size = ImmGetCompositionStringW( himc, GCS_RESULTSTR, buf, size * sizeof(WCHAR) ); + } + ImmReleaseContext( hWnd, himc ); + + for (i = 0; i < size / sizeof(WCHAR); i++) + SendMessageW( hWnd, WM_IME_CHAR, buf[i], 1 ); + HeapFree( GetProcessHeap(), 0, buf ); + } + } + /* fall through */ + case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: case WM_IME_SELECT: case WM_IME_NOTIFY: @@ -1174,7 +1162,7 @@ RealDefWindowProcW(HWND hWnd, { HWND hwndIME;
- hwndIME = DefWndImmGetDefaultIMEWnd(hWnd); + hwndIME = ImmGetDefaultIMEWnd(hWnd); if (hwndIME) Result = SendMessageW(hwndIME, Msg, wParam, lParam); break; @@ -1184,9 +1172,9 @@ RealDefWindowProcW(HWND hWnd, { HWND hwndIME;
- hwndIME = DefWndImmGetDefaultIMEWnd(hWnd); + hwndIME = ImmGetDefaultIMEWnd(hWnd); if (hwndIME) - Result = DefWndImmIsUIMessageW(hwndIME, Msg, wParam, lParam); + Result = ImmIsUIMessageW(hwndIME, Msg, wParam, lParam); break; }