[v3 PATCH 1/2] ole32: Implement chained IInitializeSpy support.
Nikolay Sivov
nsivov at codeweavers.com
Thu Jan 24 22:07:52 CST 2019
Signed-off-by: Nikolay Sivov <nsivov at 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);
}
--
2.20.1
More information about the wine-devel
mailing list