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