Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/ole32/compobj.c | 108 +++++++++++++++++++++++++++-------- dlls/ole32/compobj_private.h | 17 +++++- dlls/ole32/tests/compobj.c | 15 ++--- 3 files changed, 102 insertions(+), 38 deletions(-)
diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 66b1683d98..f48e78ba38 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; } @@ -1783,6 +1793,9 @@ DWORD WINAPI CoBuildVersion(void) HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie) { struct oletls *info = COM_CurrentInfo(); + struct init_spy *entry, *cur; + unsigned int id = 0; + struct list *before; HRESULT hr;
TRACE("(%p, %p)\n", spy, cookie); @@ -1794,19 +1807,38 @@ 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; + before = &info->spies; + + LIST_FOR_EACH_ENTRY(cur, &info->spies, struct init_spy, entry) { - cookie->QuadPart = (DWORD_PTR)spy; - return S_OK; + if (id != cur->id) + { + before = &cur->entry; + break; + } + + id++; } - return hr; + + entry->id = id; + list_add_before(before, &entry->entry); + + cookie->HighPart = GetCurrentThreadId(); + cookie->LowPart = entry->id; + + return S_OK; }
/****************************************************************************** @@ -1827,14 +1859,26 @@ 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; + LIST_FOR_EACH_ENTRY(spy, &info->spies, struct init_spy, entry) + { + if (cookie.LowPart == spy->id) + { + 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 +1973,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 +2000,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 +2034,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 +2042,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 +2079,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); }