Jacek Caban : imm32: Use a separated struct for COM initialization spy.
Alexandre Julliard
julliard at winehq.org
Mon Jul 11 15:51:39 CDT 2022
Module: wine
Branch: master
Commit: d7d9344003edf5599a5190ada049461a2acca808
URL: https://gitlab.winehq.org/wine/wine/-/commit/d7d9344003edf5599a5190ada049461a2acca808
Author: Jacek Caban <jacek at codeweavers.com>
Date: Fri Jul 8 13:54:34 2022 +0200
imm32: Use a separated struct for COM initialization spy.
---
dlls/imm32/imm.c | 149 ++++++++++++++++++++++++++++++++-----------------------
1 file changed, 86 insertions(+), 63 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c
index be4ff25a3f9..d290e580a23 100644
--- a/dlls/imm32/imm.c
+++ b/dlls/imm32/imm.c
@@ -107,8 +107,13 @@ typedef struct _tagIMMThreadData {
HWND hwndDefault;
BOOL disableIME;
DWORD windowRefs;
+} IMMThreadData;
+
+struct coinit_spy
+{
IInitializeSpy IInitializeSpy_iface;
- ULARGE_INTEGER spy_cookie;
+ LONG ref;
+ ULARGE_INTEGER cookie;
enum
{
IMM_APT_INIT = 0x1,
@@ -116,7 +121,9 @@ typedef struct _tagIMMThreadData {
IMM_APT_CAN_FREE = 0x4,
IMM_APT_BROKEN = 0x8
} apt_flags;
-} IMMThreadData;
+};
+
+static LONG spy_tls = TLS_OUT_OF_INDEXES;
static struct list ImmHklList = LIST_INIT(ImmHklList);
static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
@@ -249,62 +256,38 @@ static DWORD convert_candidatelist_AtoW(
return ret;
}
-static void imm_coinit_thread(IMMThreadData *thread_data)
+static void imm_couninit_thread(BOOL cleanup)
{
- HRESULT hr;
-
- TRACE("implicit COM initialization\n");
-
- if (thread_data->threadID != GetCurrentThreadId())
- return;
-
- if (thread_data->apt_flags & (IMM_APT_INIT | IMM_APT_BROKEN))
- return;
- thread_data->apt_flags |= IMM_APT_INIT;
+ struct coinit_spy *spy;
- if(!thread_data->spy_cookie.QuadPart)
- {
- hr = CoRegisterInitializeSpy(&thread_data->IInitializeSpy_iface,
- &thread_data->spy_cookie);
- if (FAILED(hr))
- return;
- }
-
- hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
- if (SUCCEEDED(hr))
- thread_data->apt_flags |= IMM_APT_CREATED;
-}
-
-static void imm_couninit_thread(IMMThreadData *thread_data, BOOL cleanup)
-{
TRACE("implicit COM deinitialization\n");
- if (thread_data->apt_flags & IMM_APT_BROKEN)
+ if (!(spy = TlsGetValue(spy_tls)) || (spy->apt_flags & IMM_APT_BROKEN))
return;
- if (cleanup && thread_data->spy_cookie.QuadPart)
+ if (cleanup && spy->cookie.QuadPart)
{
- CoRevokeInitializeSpy(thread_data->spy_cookie);
- thread_data->spy_cookie.QuadPart = 0;
+ CoRevokeInitializeSpy(spy->cookie);
+ spy->cookie.QuadPart = 0;
}
- if (!(thread_data->apt_flags & IMM_APT_INIT))
+ if (!(spy->apt_flags & IMM_APT_INIT))
return;
- thread_data->apt_flags &= ~IMM_APT_INIT;
+ spy->apt_flags &= ~IMM_APT_INIT;
- if (thread_data->apt_flags & IMM_APT_CREATED)
+ if (spy->apt_flags & IMM_APT_CREATED)
{
- thread_data->apt_flags &= ~IMM_APT_CREATED;
- if (thread_data->apt_flags & IMM_APT_CAN_FREE)
+ spy->apt_flags &= ~IMM_APT_CREATED;
+ if (spy->apt_flags & IMM_APT_CAN_FREE)
CoUninitialize();
}
if (cleanup)
- thread_data->apt_flags = 0;
+ spy->apt_flags = 0;
}
-static inline IMMThreadData *impl_from_IInitializeSpy(IInitializeSpy *iface)
+static inline struct coinit_spy *impl_from_IInitializeSpy(IInitializeSpy *iface)
{
- return CONTAINING_RECORD(iface, IMMThreadData, IInitializeSpy_iface);
+ return CONTAINING_RECORD(iface, struct coinit_spy, IInitializeSpy_iface);
}
static HRESULT WINAPI InitializeSpy_QueryInterface(IInitializeSpy *iface, REFIID riid, void **obj)
@@ -323,24 +306,28 @@ static HRESULT WINAPI InitializeSpy_QueryInterface(IInitializeSpy *iface, REFIID
static ULONG WINAPI InitializeSpy_AddRef(IInitializeSpy *iface)
{
- return 2;
+ struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
+ return InterlockedIncrement(&spy->ref);
}
static ULONG WINAPI InitializeSpy_Release(IInitializeSpy *iface)
{
- return 1;
+ struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
+ LONG ref = InterlockedDecrement(&spy->ref);
+ if (!ref) HeapFree(GetProcessHeap(), 0, spy);
+ return ref;
}
static HRESULT WINAPI InitializeSpy_PreInitialize(IInitializeSpy *iface,
DWORD coinit, DWORD refs)
{
- IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
+ struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
- if ((thread_data->apt_flags & IMM_APT_CREATED) &&
+ if ((spy->apt_flags & IMM_APT_CREATED) &&
!(coinit & COINIT_APARTMENTTHREADED) && refs == 1)
{
- imm_couninit_thread(thread_data, TRUE);
- thread_data->apt_flags |= IMM_APT_BROKEN;
+ imm_couninit_thread(TRUE);
+ spy->apt_flags |= IMM_APT_BROKEN;
}
return S_OK;
}
@@ -348,12 +335,12 @@ static HRESULT WINAPI InitializeSpy_PreInitialize(IInitializeSpy *iface,
static HRESULT WINAPI InitializeSpy_PostInitialize(IInitializeSpy *iface,
HRESULT hr, DWORD coinit, DWORD refs)
{
- IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
+ struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
- if ((thread_data->apt_flags & IMM_APT_CREATED) && hr == S_FALSE && refs == 2)
+ if ((spy->apt_flags & IMM_APT_CREATED) && hr == S_FALSE && refs == 2)
hr = S_OK;
if (SUCCEEDED(hr))
- thread_data->apt_flags |= IMM_APT_CAN_FREE;
+ spy->apt_flags |= IMM_APT_CAN_FREE;
return hr;
}
@@ -364,12 +351,14 @@ static HRESULT WINAPI InitializeSpy_PreUninitialize(IInitializeSpy *iface, DWORD
static HRESULT WINAPI InitializeSpy_PostUninitialize(IInitializeSpy *iface, DWORD refs)
{
- IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
+ struct coinit_spy *spy = impl_from_IInitializeSpy(iface);
+
+ TRACE("%lu %p\n", refs, ImmGetDefaultIMEWnd(0));
- if (refs == 1 && !thread_data->windowRefs)
- imm_couninit_thread(thread_data, FALSE);
+ if (refs == 1 && !ImmGetDefaultIMEWnd(0))
+ imm_couninit_thread(FALSE);
else if (!refs)
- thread_data->apt_flags &= ~IMM_APT_CAN_FREE;
+ spy->apt_flags &= ~IMM_APT_CAN_FREE;
return S_OK;
}
@@ -384,6 +373,45 @@ static const IInitializeSpyVtbl InitializeSpyVtbl =
InitializeSpy_PostUninitialize,
};
+static void imm_coinit_thread(void)
+{
+ struct coinit_spy *spy;
+ HRESULT hr;
+
+ TRACE("implicit COM initialization\n");
+
+ if (spy_tls == TLS_OUT_OF_INDEXES)
+ {
+ DWORD tls = TlsAlloc();
+ if (tls == TLS_OUT_OF_INDEXES) return;
+ if (InterlockedCompareExchange(&spy_tls, tls, TLS_OUT_OF_INDEXES)) TlsFree(tls);
+ }
+ if (!(spy = TlsGetValue(spy_tls)))
+ {
+ if (!(spy = HeapAlloc(GetProcessHeap(), 0, sizeof(*spy)))) return;
+ spy->IInitializeSpy_iface.lpVtbl = &InitializeSpyVtbl;
+ spy->ref = 1;
+ spy->cookie.QuadPart = 0;
+ spy->apt_flags = 0;
+ TlsSetValue(spy_tls, spy);
+ }
+
+ if (spy->apt_flags & (IMM_APT_INIT | IMM_APT_BROKEN))
+ return;
+ spy->apt_flags |= IMM_APT_INIT;
+
+ if(!spy->cookie.QuadPart)
+ {
+ hr = CoRegisterInitializeSpy(&spy->IInitializeSpy_iface, &spy->cookie);
+ if (FAILED(hr))
+ return;
+ }
+
+ hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+ if (SUCCEEDED(hr))
+ spy->apt_flags |= IMM_APT_CREATED;
+}
+
static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread)
{
IMMThreadData *data;
@@ -410,7 +438,6 @@ 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 (%lx)\n",thread);
@@ -429,6 +456,7 @@ static BOOL IMM_IsDefaultContext(HIMC imc)
static void IMM_FreeThreadData(void)
{
+ struct coinit_spy *spy;
IMMThreadData *data;
EnterCriticalSection(&threaddata_cs);
@@ -439,13 +467,14 @@ static void IMM_FreeThreadData(void)
list_remove(&data->entry);
LeaveCriticalSection(&threaddata_cs);
IMM_DestroyContext(data->defaultContext);
- imm_couninit_thread(data, TRUE);
HeapFree(GetProcessHeap(),0,data);
TRACE("Thread Data Destroyed\n");
return;
}
}
LeaveCriticalSection(&threaddata_cs);
+
+ if ((spy = TlsGetValue(spy_tls))) IInitializeSpy_Release(&spy->IInitializeSpy_iface);
}
static HMODULE load_graphics_driver(void)
@@ -704,19 +733,13 @@ static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC)
BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate)
{
InputContextData *data = get_imc_data(himc);
- IMMThreadData *thread_data;
TRACE("(%p, %p, %x)\n", hwnd, himc, activate);
if (himc && !data && activate)
return FALSE;
- thread_data = IMM_GetThreadData(hwnd, 0);
- if (thread_data)
- {
- imm_coinit_thread(thread_data);
- LeaveCriticalSection(&threaddata_cs);
- }
+ imm_coinit_thread();
if (data)
{
@@ -1002,10 +1025,10 @@ static HWND imm_detach_default_window(IMMThreadData *thread_data)
{
HWND to_destroy;
- imm_couninit_thread(thread_data, TRUE);
to_destroy = thread_data->hwndDefault;
thread_data->hwndDefault = NULL;
thread_data->windowRefs = 0;
+ imm_couninit_thread(TRUE);
return to_destroy;
}
More information about the wine-cvs
mailing list