Huw Davies : ole32: After a call to GetData the consumer should hold a ref on the source data object .

Alexandre Julliard julliard at winehq.org
Thu Apr 16 14:34:51 CDT 2009


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

Author: Huw Davies <huw at codeweavers.com>
Date:   Thu Apr 16 12:17:00 2009 +0100

ole32: After a call to GetData the consumer should hold a ref on the source data object.

---

 dlls/ole32/clipboard.c       |   36 ++++++++++++++----------
 dlls/ole32/tests/clipboard.c |   61 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 81 insertions(+), 16 deletions(-)

diff --git a/dlls/ole32/clipboard.c b/dlls/ole32/clipboard.c
index b7527e9..c1ef5d3 100644
--- a/dlls/ole32/clipboard.c
+++ b/dlls/ole32/clipboard.c
@@ -134,6 +134,8 @@ typedef struct snapshot
     LONG ref;
 
     DWORD seq_no;                   /* Clipboard sequence number corresponding to this snapshot */
+
+    IDataObject *data;              /* If we unmarshal a remote data object we hold a ref here */
 } snapshot;
 
 /****************************************************************************
@@ -830,6 +832,8 @@ static ULONG WINAPI snapshot_Release(IDataObject *iface)
         ole_clipbrd *clipbrd;
         HRESULT hr = get_ole_clipbrd(&clipbrd);
 
+        if(This->data) IDataObject_Release(This->data);
+
         if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
             clipbrd->latest_snapshot = NULL;
         HeapFree(GetProcessHeap(), 0, This);
@@ -907,25 +911,26 @@ static HRESULT WINAPI snapshot_GetData(IDataObject *iface,
                                        FORMATETC *pformatetcIn,
                                        STGMEDIUM *pmedium)
 {
-  HANDLE h, hData = 0;
-  HRESULT hr;
-  IDataObject *data;
+    snapshot *This = impl_from_IDataObject(iface);
+    HANDLE h, hData = 0;
+    HRESULT hr;
 
-  TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium);
+    TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium);
 
-  if ( !pformatetcIn || !pmedium )
-    return E_INVALIDARG;
+    if ( !pformatetcIn || !pmedium ) return E_INVALIDARG;
 
-  if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
+    if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
+
+    if(!This->data)
+        hr = get_current_dataobject(&This->data);
+
+    if(This->data)
+    {
+        hr = IDataObject_GetData(This->data, pformatetcIn, pmedium);
+        CloseClipboard();
+        return hr;
+    }
 
-  hr = get_current_dataobject(&data);
-  if ( hr == S_OK )
-  {
-    hr = IDataObject_GetData(data, pformatetcIn, pmedium);
-    IDataObject_Release(data);
-    CloseClipboard();
-    return hr;
-  }
 
   /*
    * Otherwise, get the data from the windows clipboard using GetClipboardData
@@ -1130,6 +1135,7 @@ static snapshot *snapshot_construct(DWORD seq_no)
     This->lpVtbl = &snapshot_vtable;
     This->ref = 0;
     This->seq_no = seq_no;
+    This->data = NULL;
 
     return This;
 }
diff --git a/dlls/ole32/tests/clipboard.c b/dlls/ole32/tests/clipboard.c
index eef57bd..c77ec95 100644
--- a/dlls/ole32/tests/clipboard.c
+++ b/dlls/ole32/tests/clipboard.c
@@ -862,14 +862,27 @@ static void test_set_clipboard(void)
     OleUninitialize();
 }
 
+static inline ULONG count_refs(IDataObject *d)
+{
+    IDataObject_AddRef(d);
+    return IDataObject_Release(d);
+}
+
 static void test_consumer_refs(void)
 {
     HRESULT hr;
     IDataObject *src, *get1, *get2, *get3;
-    LONG refs;
+    ULONG refs, old_refs;
+    FORMATETC fmt;
+    STGMEDIUM med;
+
+    InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
 
     OleInitialize(NULL);
 
+    /* First show that each clipboard state results in
+       a different data object */
+
     hr = DataObjectImpl_CreateText("data1", &src);
     ok(hr == S_OK, "got %08x\n", hr);
 
@@ -888,6 +901,12 @@ static void test_consumer_refs(void)
 
     OleFlushClipboard();
 
+    DataObjectImpl_GetData_calls = 0;
+    hr = IDataObject_GetData(get1, &fmt, &med);
+    ok(hr == S_OK, "got %08x\n", hr);
+    ok(DataObjectImpl_GetData_calls == 0, "GetData called\n");
+    ReleaseStgMedium(&med);
+
     hr = OleGetClipboard(&get2);
     ok(hr == S_OK, "got %08x\n", hr);
 
@@ -904,6 +923,46 @@ static void test_consumer_refs(void)
     IDataObject_Release(get3);
     IDataObject_Release(get2);
     IDataObject_Release(get1);
+
+    /* Now call GetData before the flush and show that this
+       takes a ref on our src data obj. */
+
+    hr = OleSetClipboard(src);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    old_refs = count_refs(src);
+    trace("old_refs %d\n", old_refs);
+
+    hr = OleGetClipboard(&get1);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    refs = count_refs(src);
+    ok(refs == old_refs, "%d %d\n", refs, old_refs);
+
+    DataObjectImpl_GetData_calls = 0;
+    hr = IDataObject_GetData(get1, &fmt, &med);
+    ok(hr == S_OK, "got %08x\n", hr);
+    ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
+    ReleaseStgMedium(&med);
+    refs = count_refs(src);
+    ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
+
+    OleFlushClipboard();
+
+    DataObjectImpl_GetData_calls = 0;
+    hr = IDataObject_GetData(get1, &fmt, &med);
+    ok(hr == S_OK, "got %08x\n", hr);
+    ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
+    ReleaseStgMedium(&med);
+
+    refs = count_refs(src);
+    ok(refs == 2, "%d\n", refs);
+
+    IDataObject_Release(get1);
+
+    refs = count_refs(src);
+    ok(refs == 1, "%d\n", refs);
+
     IDataObject_Release(src);
 
     OleUninitialize();




More information about the wine-cvs mailing list