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

This commit is contained in:
Huw Davies 2009-04-16 12:17:00 +01:00 committed by Alexandre Julliard
parent d2156f3894
commit fca4ed5596
2 changed files with 81 additions and 16 deletions

View File

@ -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;
}

View File

@ -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();