[PATCH] imm32: Automatically initialize COM on window activation.
Nikolay Sivov
nsivov at codeweavers.com
Tue Jan 29 01:23:01 CST 2019
Signed-off-by: Nikolay Sivov <nsivov at 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
{
--
2.20.1
More information about the wine-devel
mailing list