Nikolay Sivov : ole32: Fix refcounting of IObjContext per-thread instance.

Alexandre Julliard julliard at wine.codeweavers.com
Tue Mar 15 10:12:16 CDT 2016


Module: wine
Branch: master
Commit: cf218bca423a78f9ee45dfbbda784bc285307471
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=cf218bca423a78f9ee45dfbbda784bc285307471

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Mon Mar 14 20:30:54 2016 +0300

ole32: Fix refcounting of IObjContext per-thread instance.

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Huw Davies <huw at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ole32/compobj.c       | 61 ++++++++++++++++++++--------------------------
 dlls/ole32/tests/compobj.c | 46 ++++++++++++++++++++--------------
 2 files changed, 55 insertions(+), 52 deletions(-)

diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c
index b095aeb..857f985 100644
--- a/dlls/ole32/compobj.c
+++ b/dlls/ole32/compobj.c
@@ -4683,10 +4683,15 @@ static ULONG Context_AddRef(Context *This)
 
 static ULONG Context_Release(Context *This)
 {
-    ULONG refs = InterlockedDecrement(&This->refs);
-    if (!refs)
+    /* Context instance is initially created with CoGetContextToken() with refcount set to 0,
+       releasing context while refcount is at 0 destroys it. */
+    if (!This->refs)
+    {
         HeapFree(GetProcessHeap(), 0, This);
-    return refs;
+        return 0;
+    }
+
+    return InterlockedDecrement(&This->refs);
 }
 
 static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
@@ -4924,39 +4929,19 @@ static const IObjContextVtbl Context_Object_Vtbl =
  */
 HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
 {
-    APARTMENT *apt = COM_CurrentApt();
-    Context *context;
+    IObjContext *context;
     HRESULT hr;
 
     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
 
     *ppv = NULL;
-    if (!apt)
-    {
-        if (!(apt = apartment_find_multi_threaded()))
-        {
-            ERR("apartment not initialised\n");
-            return CO_E_NOTINITIALIZED;
-        }
-        apartment_release(apt);
-    }
-
-    context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
-    if (!context)
-        return E_OUTOFMEMORY;
-
-    context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
-    context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
-    context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
-    context->refs = 1;
-
-    hr = IComThreadingInfo_QueryInterface(&context->IComThreadingInfo_iface, riid, ppv);
-    IComThreadingInfo_Release(&context->IComThreadingInfo_iface);
+    hr = CoGetContextToken((ULONG_PTR*)&context);
+    if (FAILED(hr))
+        return hr;
 
-    return hr;
+    return IObjContext_QueryInterface(context, riid, ppv);
 }
 
-
 /***********************************************************************
  *           CoGetContextToken [OLE32.@]
  */
@@ -4985,16 +4970,24 @@ HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
 
     if (!info->context_token)
     {
-        HRESULT hr;
-        IObjContext *ctx;
+        Context *context;
+
+        context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
+        if (!context)
+            return E_OUTOFMEMORY;
+
+        context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
+        context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
+        context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
+        /* Context token does not take a reference, it's always zero until
+           interface is explicitely requested with CoGetObjectContext(). */
+        context->refs = 0;
 
-        hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
-        if (FAILED(hr)) return hr;
-        info->context_token = ctx;
+        info->context_token = &context->IObjContext_iface;
     }
 
     *token = (ULONG_PTR)info->context_token;
-    TRACE("apt->context_token=%p\n", info->context_token);
+    TRACE("context_token=%p\n", info->context_token);
 
     return S_OK;
 }
diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c
index d684e33..1af24b6 100644
--- a/dlls/ole32/tests/compobj.c
+++ b/dlls/ole32/tests/compobj.c
@@ -1774,7 +1774,7 @@ static void test_CoGetObjectContext(void)
 {
     HRESULT hr;
     ULONG refs;
-    IComThreadingInfo *pComThreadingInfo;
+    IComThreadingInfo *pComThreadingInfo, *threadinginfo2;
     IContextCallback *pContextCallback;
     IObjContext *pObjContext;
     APTTYPE apttype;
@@ -1786,7 +1786,7 @@ static void test_CoGetObjectContext(void)
 
     if (!pCoGetObjectContext)
     {
-        skip("CoGetObjectContext not present\n");
+        win_skip("CoGetObjectContext not present\n");
         return;
     }
 
@@ -1812,6 +1812,12 @@ static void test_CoGetObjectContext(void)
     hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&pComThreadingInfo);
     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
 
+    threadinginfo2 = NULL;
+    hr = pCoGetObjectContext(&IID_IComThreadingInfo, (void **)&threadinginfo2);
+    ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
+    ok(pComThreadingInfo == threadinginfo2, "got different instance\n");
+    IComThreadingInfo_Release(threadinginfo2);
+
     hr = IComThreadingInfo_GetCurrentLogicalThreadId(pComThreadingInfo, NULL);
     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
 
@@ -1854,11 +1860,8 @@ static void test_CoGetObjectContext(void)
     hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
     ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
 
-    if (hr == S_OK)
-    {
-        refs = IContextCallback_Release(pContextCallback);
-        ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
-    }
+    refs = IContextCallback_Release(pContextCallback);
+    ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
 
     CoUninitialize();
 
@@ -1881,11 +1884,8 @@ static void test_CoGetObjectContext(void)
     hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback);
     ok_ole_success(hr, "CoGetObjectContext(ContextCallback)");
 
-    if (hr == S_OK)
-    {
-        refs = IContextCallback_Release(pContextCallback);
-        ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
-    }
+    refs = IContextCallback_Release(pContextCallback);
+    ok(refs == 0, "pContextCallback should have 0 refs instead of %d refs\n", refs);
 
     hr = pCoGetObjectContext(&IID_IObjContext, (void **)&pObjContext);
     ok_ole_success(hr, "CoGetObjectContext");
@@ -2007,7 +2007,7 @@ static void test_CoGetContextToken(void)
 {
     HRESULT hr;
     ULONG refs;
-    ULONG_PTR token;
+    ULONG_PTR token, token2;
     IObjContext *ctx;
     struct info info;
     HANDLE thread;
@@ -2042,6 +2042,11 @@ static void test_CoGetContextToken(void)
     hr = pCoGetContextToken(&token);
     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
 
+    token2 = 0;
+    hr = pCoGetContextToken(&token2);
+    ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
+    ok(token == token2, "got different token\n");
+
     SetEvent(info.stop);
     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
 
@@ -2063,18 +2068,23 @@ static void test_CoGetContextToken(void)
     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
     ok(token, "Expected token != 0\n");
 
+    token2 = 0;
+    hr = pCoGetContextToken(&token2);
+    ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
+    ok(token2 == token, "got different token\n");
+
     refs = IUnknown_AddRef((IUnknown *)token);
-    todo_wine ok(refs == 1, "Expected 1, got %u\n", refs);
+    ok(refs == 1, "Expected 1, got %u\n", refs);
 
     hr = pCoGetObjectContext(&IID_IObjContext, (void **)&ctx);
     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
-    todo_wine ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
+    ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
 
     refs = IObjContext_AddRef(ctx);
-    todo_wine ok(refs == 3, "Expected 3, got %u\n", refs);
+    ok(refs == 3, "Expected 3, got %u\n", refs);
 
     refs = IObjContext_Release(ctx);
-    todo_wine ok(refs == 2, "Expected 2, got %u\n", refs);
+    ok(refs == 2, "Expected 2, got %u\n", refs);
 
     refs = IUnknown_Release((IUnknown *)token);
     ok(refs == 1, "Expected 1, got %u\n", refs);
@@ -2084,7 +2094,7 @@ static void test_CoGetContextToken(void)
     hr = pCoGetContextToken(&token);
     ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr);
     ok(token, "Expected token != 0\n");
-    todo_wine ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
+    ok(ctx == (IObjContext *)token, "Expected interface pointers to be the same\n");
 
     refs = IObjContext_AddRef(ctx);
     ok(refs == 2, "Expected 1, got %u\n", refs);




More information about the wine-cvs mailing list