Signed-off-by: Nikolay Sivov nsivov@codeweavers.com ---
Some applications depend on this and expect COM to be initialized. Examples:
- Path Of Exile inability to create WIC objects (was fixed in game itself); - missing sound in games after failing to create xaudio objects https://github.com/ValveSoftware/Proton/issues/1855 https://github.com/ValveSoftware/Proton/issues/937
dlls/imm32/Makefile.in | 2 +- dlls/imm32/imm.c | 129 ++++++++++++++++++++++++++++++++++++- dlls/imm32/imm32.spec | 1 + dlls/user32/focus.c | 2 + dlls/user32/misc.c | 2 + dlls/user32/user_private.h | 1 + 6 files changed, 135 insertions(+), 2 deletions(-)
diff --git a/dlls/imm32/Makefile.in b/dlls/imm32/Makefile.in index b190888659..ad10fc2fa4 100644 --- a/dlls/imm32/Makefile.in +++ b/dlls/imm32/Makefile.in @@ -1,6 +1,6 @@ MODULE = imm32.dll IMPORTLIB = imm32 -IMPORTS = user32 gdi32 advapi32 +IMPORTS = user32 gdi32 advapi32 ole32
C_SRCS = \ imm.c diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 28eb00f355..129f7e8cb5 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#define COBJMACROS + #include <stdarg.h> #include <stdio.h>
@@ -32,6 +34,8 @@ #include "ddk/imm.h" #include "winnls.h" #include "winreg.h" +#include "initguid.h" +#include "objbase.h" #include "wine/list.h" #include "wine/unicode.h"
@@ -95,8 +99,16 @@ typedef struct _tagIMMThreadData { HWND hwndDefault; BOOL disableIME; DWORD windowRefs; + IInitializeSpy IInitializeSpy_iface; + ULARGE_INTEGER spy_cookie; + BOOL apt_initialized; } IMMThreadData;
+static inline IMMThreadData *impl_from_IInitializeSpy(IInitializeSpy *iface) +{ + return CONTAINING_RECORD(iface, IMMThreadData, IInitializeSpy_iface); +} + static struct list ImmHklList = LIST_INIT(ImmHklList); static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
@@ -227,6 +239,88 @@ static DWORD convert_candidatelist_AtoW( return ret; }
+static HRESULT WINAPI initializespy_QueryInterface(IInitializeSpy *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(&IID_IInitializeSpy, riid) || + IsEqualIID(&IID_IUnknown, riid)) + { + *obj = iface; + IInitializeSpy_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI initializespy_AddRef(IInitializeSpy *iface) +{ + return 2; +} + +static ULONG WINAPI initializespy_Release(IInitializeSpy *iface) +{ + return 1; +} + +static void imm_couninit_thread(IMMThreadData *thread_data) +{ + if (!thread_data->apt_initialized) + return; + + thread_data->apt_initialized = FALSE; + CoUninitialize(); +} + +static HRESULT WINAPI initializespy_PreInitialize(IInitializeSpy *iface, DWORD coinit, DWORD refs) +{ + IMMThreadData *thread_data = impl_from_IInitializeSpy(iface); + + /* Application requested initialization of different apartment type. */ + if (!(coinit & COINIT_APARTMENTTHREADED)) + imm_couninit_thread(thread_data); + + return S_OK; +} + +static HRESULT WINAPI initializespy_PostInitialize(IInitializeSpy *iface, HRESULT hr, DWORD coinit, DWORD refs) +{ + IMMThreadData *thread_data = impl_from_IInitializeSpy(iface); + + /* Explicit initialization call should return S_OK first time. */ + if (thread_data->apt_initialized && hr == S_FALSE && refs == 2) + hr = S_OK; + + return hr; +} + +static HRESULT WINAPI initializespy_PreUninitialize(IInitializeSpy *iface, DWORD refs) +{ + IMMThreadData *thread_data = impl_from_IInitializeSpy(iface); + + /* Account for explicit uninitialization calls. */ + if (thread_data->apt_initialized && refs == 1) + thread_data->apt_initialized = FALSE; + + return S_OK; +} + +static HRESULT WINAPI initializespy_PostUninitialize(IInitializeSpy *iface, DWORD refs) +{ + return S_OK; +} + +static const IInitializeSpyVtbl initializespyvtbl = +{ + initializespy_QueryInterface, + initializespy_AddRef, + initializespy_Release, + initializespy_PreInitialize, + initializespy_PostInitialize, + initializespy_PreUninitialize, + initializespy_PostUninitialize, +}; + static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread) { IMMThreadData *data; @@ -253,6 +347,7 @@ static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread) if (data->threadID == thread) return data;
data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data)); + data->IInitializeSpy_iface.lpVtbl = &initializespyvtbl; data->threadID = thread; list_add_head(&ImmThreadDataList,&data->entry); TRACE("Thread Data Created (%x)\n",thread); @@ -281,6 +376,7 @@ static void IMM_FreeThreadData(void) list_remove(&data->entry); LeaveCriticalSection(&threaddata_cs); IMM_DestroyContext(data->defaultContext); + imm_couninit_thread(data); HeapFree(GetProcessHeap(),0,data); TRACE("Thread Data Destroyed\n"); return; @@ -1627,6 +1723,32 @@ static BOOL needs_ime_window(HWND hwnd) return TRUE; }
+void WINAPI __wine_activate_window(HWND hwnd) +{ + IMMThreadData *thread_data; + + TRACE("(%p)\n", hwnd); + + if (!needs_ime_window(hwnd)) + return; + + thread_data = IMM_GetThreadData(hwnd, 0); + if (!thread_data) + return; + + if (thread_data->disableIME || disable_ime) + { + TRACE("IME for this thread is disabled\n"); + LeaveCriticalSection(&threaddata_cs); + return; + } + + if (!thread_data->apt_initialized) + thread_data->apt_initialized = SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); + + LeaveCriticalSection(&threaddata_cs); +} + /*********************************************************************** * __wine_register_window (IMM32.@) */ @@ -1656,6 +1778,8 @@ BOOL WINAPI __wine_register_window(HWND hwnd) /* Create default IME window */ if (thread_data->windowRefs == 1) { + CoRegisterInitializeSpy(&thread_data->IInitializeSpy_iface, &thread_data->spy_cookie); + /* Do not create the window inside of a critical section */ LeaveCriticalSection(&threaddata_cs); new = CreateWindowExW( 0, szwIME, szwDefaultIME, @@ -1697,8 +1821,11 @@ void WINAPI __wine_unregister_window(HWND hwnd) thread_data->windowRefs, thread_data->hwndDefault);
/* Destroy default IME window */ - if (thread_data->windowRefs == 0 && thread_data->hwndDefault) + if (thread_data->windowRefs == 0) { + CoRevokeInitializeSpy(thread_data->spy_cookie); + thread_data->spy_cookie.QuadPart = 0; + imm_couninit_thread(thread_data); to_destroy = thread_data->hwndDefault; thread_data->hwndDefault = NULL; } diff --git a/dlls/imm32/imm32.spec b/dlls/imm32/imm32.spec index 4197bb81e2..d9cdc794e9 100644 --- a/dlls/imm32/imm32.spec +++ b/dlls/imm32/imm32.spec @@ -117,3 +117,4 @@ @ stdcall __wine_get_ui_window(ptr) @ stdcall __wine_register_window(long) @ stdcall __wine_unregister_window(long) +@ stdcall __wine_activate_window(long) diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index f1c883167e..50b3323ae9 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -156,6 +156,8 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) (LPARAM)previous ); if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow()) PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd ); + + imm_activate_window( hwnd ); }
/* now change focus if necessary */ diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c index d28cd9fd05..cfaa1b94db 100644 --- a/dlls/user32/misc.c +++ b/dlls/user32/misc.c @@ -43,6 +43,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); static HWND (WINAPI *imm_get_ui_window)(HKL); BOOL (WINAPI *imm_register_window)(HWND) = NULL; void (WINAPI *imm_unregister_window)(HWND) = NULL; +void (WINAPI *imm_activate_window)(HWND) = NULL;
/* MSIME messages */ static UINT WM_MSIME_SERVICE; @@ -480,6 +481,7 @@ BOOL WINAPI User32InitializeImmEntryTable(DWORD magic) imm_get_ui_window = (void*)GetProcAddress(imm32, "__wine_get_ui_window"); imm_register_window = (void*)GetProcAddress(imm32, "__wine_register_window"); imm_unregister_window = (void*)GetProcAddress(imm32, "__wine_unregister_window"); + imm_activate_window = (void*)GetProcAddress(imm32, "__wine_activate_window"); if (!imm_get_ui_window) FIXME("native imm32.dll not supported\n"); return TRUE; diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 514cf6753f..b86831d7d9 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -197,6 +197,7 @@ C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) extern INT global_key_state_counter DECLSPEC_HIDDEN; extern BOOL (WINAPI *imm_register_window)(HWND) DECLSPEC_HIDDEN; extern void (WINAPI *imm_unregister_window)(HWND) DECLSPEC_HIDDEN; +extern void (WINAPI *imm_activate_window)(HWND) DECLSPEC_HIDDEN;
struct user_key_state_info {