Signed-off-by: Nikolay Sivov nsivov@codeweavers.com ---
v3: fixes the call order, last registered instance is called first, not in id order v2: simplified after review
dlls/ole32/compobj.c | 111 +++++++++++++++++++++++++++-------- dlls/ole32/compobj_private.h | 17 +++++- dlls/ole32/tests/compobj.c | 15 ++--- 3 files changed, 105 insertions(+), 38 deletions(-)
diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 66b1683d98..a28ff79924 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -1738,11 +1738,21 @@ static void COM_TlsDestroy(void) struct oletls *info = NtCurrentTeb()->ReservedForOle; if (info) { + struct init_spy *cursor, *cursor2; + if (info->apt) apartment_release(info->apt); if (info->errorinfo) IErrorInfo_Release(info->errorinfo); if (info->state) IUnknown_Release(info->state); - if (info->spy) IInitializeSpy_Release(info->spy); + + LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &info->spies, struct init_spy, entry) + { + list_remove(&cursor->entry); + IInitializeSpy_Release(cursor->spy); + heap_free(cursor); + } + if (info->context_token) IObjContext_Release(info->context_token); + HeapFree(GetProcessHeap(), 0, info); NtCurrentTeb()->ReservedForOle = NULL; } @@ -1764,6 +1774,19 @@ DWORD WINAPI CoBuildVersion(void) return (rmm<<16)+rup; }
+static struct init_spy *get_spy_entry(struct oletls *info, unsigned int id) +{ + struct init_spy *spy; + + LIST_FOR_EACH_ENTRY(spy, &info->spies, struct init_spy, entry) + { + if (id == spy->id) + return spy; + } + + return NULL; +} + /****************************************************************************** * CoRegisterInitializeSpy [OLE32.@] * @@ -1783,6 +1806,8 @@ DWORD WINAPI CoBuildVersion(void) HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie) { struct oletls *info = COM_CurrentInfo(); + struct init_spy *entry; + unsigned int id; HRESULT hr;
TRACE("(%p, %p)\n", spy, cookie); @@ -1794,19 +1819,32 @@ HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cook return E_INVALIDARG; }
- if (info->spy) + hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **)&spy); + if (FAILED(hr)) + return hr; + + entry = heap_alloc(sizeof(*entry)); + if (!entry) { - FIXME("Already registered?\n"); - return E_UNEXPECTED; + IInitializeSpy_Release(spy); + return E_OUTOFMEMORY; }
- hr = IInitializeSpy_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy); - if (SUCCEEDED(hr)) + entry->spy = spy; + + id = 0; + while (get_spy_entry(info, id) != NULL) { - cookie->QuadPart = (DWORD_PTR)spy; - return S_OK; + id++; } - return hr; + + entry->id = id; + list_add_head(&info->spies, &entry->entry); + + cookie->HighPart = GetCurrentThreadId(); + cookie->LowPart = entry->id; + + return S_OK; }
/****************************************************************************** @@ -1827,14 +1865,23 @@ HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cook HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie) { struct oletls *info = COM_CurrentInfo(); + struct init_spy *spy; + TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));
- if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy) + if (!info || cookie.HighPart != GetCurrentThreadId()) return E_INVALIDARG;
- IInitializeSpy_Release(info->spy); - info->spy = NULL; - return S_OK; + if ((spy = get_spy_entry(info, cookie.LowPart))) + { + IInitializeSpy_Release(spy->spy); + list_remove(&spy->entry); + heap_free(spy); + + return S_OK; + } + + return E_INVALIDARG; }
HRESULT enter_apartment( struct oletls *info, DWORD model ) @@ -1929,6 +1976,7 @@ HRESULT WINAPI CoInitialize(LPVOID lpReserved) HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit) { struct oletls *info = COM_CurrentInfo(); + struct init_spy *cursor; HRESULT hr;
TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit); @@ -1955,13 +2003,17 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoIni RunningObjectTableImpl_Initialize(); }
- if (info->spy) - IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits); + LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry) + { + IInitializeSpy_PreInitialize(cursor->spy, dwCoInit, info->inits); + }
hr = enter_apartment( info, dwCoInit );
- if (info->spy) - IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits); + LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry) + { + hr = IInitializeSpy_PostInitialize(cursor->spy, hr, dwCoInit, info->inits); + }
return hr; } @@ -1985,6 +2037,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoInitializeEx(LPVOID lpReserved, DWORD dwCoIni void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void) { struct oletls * info = COM_CurrentInfo(); + struct init_spy *cursor; LONG lCOMRefCnt;
TRACE("()\n"); @@ -1992,17 +2045,22 @@ void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void) /* will only happen on OOM */ if (!info) return;
- if (info->spy) - IInitializeSpy_PreUninitialize(info->spy, info->inits); + LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry) + { + IInitializeSpy_PreUninitialize(cursor->spy, info->inits); + }
/* sanity check */ if (!info->inits) { - ERR("Mismatched CoUninitialize\n"); + ERR("Mismatched CoUninitialize\n");
- if (info->spy) - IInitializeSpy_PostUninitialize(info->spy, info->inits); - return; + LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry) + { + IInitializeSpy_PostUninitialize(cursor->spy, info->inits); + } + + return; }
leave_apartment( info ); @@ -2024,8 +2082,11 @@ void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void) ERR( "CoUninitialize() - not CoInitialized.\n" ); InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */ } - if (info->spy) - IInitializeSpy_PostUninitialize(info->spy, info->inits); + + LIST_FOR_EACH_ENTRY(cursor, &info->spies, struct init_spy, entry) + { + IInitializeSpy_PostUninitialize(cursor->spy, info->inits); + } }
/****************************************************************************** diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 1e564a3de1..8bf3d6fc81 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -153,6 +153,13 @@ struct apartment BOOL main; /* is this a main-threaded-apartment? (RO) */ };
+struct init_spy +{ + struct list entry; + IInitializeSpy *spy; + unsigned int id; +}; + /* this is what is stored in TEB->ReservedForOle */ struct oletls { @@ -160,7 +167,7 @@ struct oletls IErrorInfo *errorinfo; /* see errorinfo.c */ IUnknown *state; /* see CoSetState */ DWORD apt_mask; /* apartment mask (+0Ch on x86) */ - IInitializeSpy *spy; /* The "SPY" from CoInitializeSpy */ + void *unknown0; DWORD inits; /* number of times CoInitializeEx called */ DWORD ole_inits; /* number of times OleInitialize called */ GUID causality_id; /* unique identifier for each COM call */ @@ -171,6 +178,7 @@ struct oletls IUnknown *call_state; /* current call context (+3Ch on x86) */ DWORD unknown2[46]; IUnknown *cancel_object; /* cancel object set by CoSetCancelObject (+F8h on x86) */ + struct list spies; /* Spies installed with CoRegisterInitializeSpy */ };
@@ -262,7 +270,12 @@ APARTMENT *apartment_get_current_or_mta(void) DECLSPEC_HIDDEN; static inline struct oletls *COM_CurrentInfo(void) { if (!NtCurrentTeb()->ReservedForOle) - NtCurrentTeb()->ReservedForOle = heap_alloc_zero(sizeof(struct oletls)); + { + struct oletls *oletls = heap_alloc_zero(sizeof(*oletls)); + if (oletls) + list_init(&oletls->spies); + NtCurrentTeb()->ReservedForOle = oletls; + }
return NtCurrentTeb()->ReservedForOle; } diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index d3b4dc70e4..4c51ee67a0 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -3363,32 +3363,28 @@ static void test_IInitializeSpy(void) cookie.LowPart = 1; hr = CoRegisterInitializeSpy(&testinitialize, &cookie); ok(hr == S_OK, "got 0x%08x\n", hr); -todo_wine { ok(cookie.HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", cookie.HighPart, GetCurrentThreadId()); ok(cookie.LowPart == 0, "got wrong low part 0x%x\n", cookie.LowPart); -} + /* register same instance one more time */ cookie1.HighPart = 0; cookie1.LowPart = 0; hr = CoRegisterInitializeSpy(&testinitialize, &cookie1); -todo_wine { ok(hr == S_OK, "got 0x%08x\n", hr); ok(cookie1.HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", cookie1.HighPart, GetCurrentThreadId()); ok(cookie1.LowPart == 1, "got wrong low part 0x%x\n", cookie1.LowPart); -} + cookie2.HighPart = 0; cookie2.LowPart = 0; hr = CoRegisterInitializeSpy(&testinitialize, &cookie2); -todo_wine { ok(hr == S_OK, "got 0x%08x\n", hr); ok(cookie2.HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", cookie2.HighPart, GetCurrentThreadId()); ok(cookie2.LowPart == 2, "got wrong low part 0x%x\n", cookie2.LowPart); -} + hr = CoRevokeInitializeSpy(cookie1); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
hr = CoRevokeInitializeSpy(cookie1); @@ -3397,21 +3393,18 @@ todo_wine cookie1.HighPart = 0; cookie1.LowPart = 0; hr = CoRegisterInitializeSpy(&testinitialize, &cookie1); -todo_wine { ok(hr == S_OK, "got 0x%08x\n", hr); ok(cookie1.HighPart == GetCurrentThreadId(), "got high part 0x%08x, expected 0x%08x\n", cookie1.HighPart, GetCurrentThreadId()); ok(cookie1.LowPart == 1, "got wrong low part 0x%x\n", cookie1.LowPart); -} + hr = CoRevokeInitializeSpy(cookie); ok(hr == S_OK, "got 0x%08x\n", hr);
hr = CoRevokeInitializeSpy(cookie1); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
hr = CoRevokeInitializeSpy(cookie2); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/ole32/tests/compobj.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 4c51ee67a0..b4dd83e63d 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -3308,14 +3308,14 @@ static ULONG WINAPI testinitialize_Release(IInitializeSpy *iface)
static HRESULT WINAPI testinitialize_PreInitialize(IInitializeSpy *iface, DWORD coinit, DWORD aptrefs) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + ok(coinit == (COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE), "Unexpected init flags %#x.\n", coinit); + return S_OK; }
static HRESULT WINAPI testinitialize_PostInitialize(IInitializeSpy *iface, HRESULT hr, DWORD coinit, DWORD aptrefs) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + ok(coinit == (COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE), "Unexpected init flags %#x.\n", coinit); + return hr; }
static HRESULT WINAPI testinitialize_PreUninitialize(IInitializeSpy *iface, DWORD aptrefs) @@ -3398,6 +3398,9 @@ static void test_IInitializeSpy(void) GetCurrentThreadId()); ok(cookie1.LowPart == 1, "got wrong low part 0x%x\n", cookie1.LowPart);
+ hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + ok(hr == S_OK, "Failed to initialize COM, hr %#x.\n", hr); + hr = CoRevokeInitializeSpy(cookie); ok(hr == S_OK, "got 0x%08x\n", hr);
@@ -3406,6 +3409,8 @@ static void test_IInitializeSpy(void)
hr = CoRevokeInitializeSpy(cookie2); ok(hr == S_OK, "got 0x%08x\n", hr); + + CoUninitialize(); }
static HRESULT g_persistfile_qi_ret;
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=46617
Your paranoid android.
=== debian9 (64 bit WoW report) ===
ole32: clipboard.c:1049: Test failed: OleIsCurrentClipboard returned 0 clipboard.c:1117: Test failed: 1 WM_DRAWCLIPBOARD received
Signed-off-by: Huw Davies huw@codeweavers.com