ret->fmtetc_cnt = fmtetc_cnt;
ret->fmtetc = HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt*sizeof(FORMATETC));
memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC));
- *lplpformatetc = (LPENUMFORMATETC)ret;
+ *lplpformatetc = &ret->IEnumFORMATETC_iface;
return S_OK;
}
DataObjectImpl_GetData_calls++;
+ ok(pmedium->tymed == 0, "pmedium->tymed = %u\n", pmedium->tymed);
+ ok(U(*pmedium).hGlobal == NULL, "pmedium->hGlobal = %p\n", U(*pmedium).hGlobal);
+ ok(pmedium->pUnkForRelease == NULL, "pmedium->pUnkForRelease = %p\n", pmedium->pUnkForRelease);
+
if(pformatetc->lindex != -1)
return DV_E_FORMATETC;
obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC));
InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
- *lplpdataobj = (LPDATAOBJECT)obj;
+ *lplpdataobj = &obj->IDataObject_iface;
return S_OK;
}
InitFormatEtc(obj->fmtetc[7], cf_another, 0xfffff);
obj->fmtetc[7].dwAspect = DVASPECT_ICON;
- *lplpdataobj = (LPDATAOBJECT)obj;
+ *lplpdataobj = &obj->IDataObject_iface;
return S_OK;
}
+static void test_get_clipboard_uninitialized(void)
+{
+ HRESULT hr;
+ IDataObject *pDObj;
+
+ pDObj = (IDataObject *)0xdeadbeef;
+ hr = OleGetClipboard(&pDObj);
+ todo_wine ok(hr == S_OK, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr, S_OK);
+ if (pDObj && pDObj != (IDataObject *)0xdeadbeef) IDataObject_Release(pDObj);
+}
+
static void test_get_clipboard(void)
{
HRESULT hr;
if(src)
{
hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
- ok(hr == S_FALSE ||
- broken(hr == S_OK && count == 5), /* win9x and winme don't enumerate duplicated cf's */
- "%d: got %08x\n", count, hr);
+ ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
IEnumFORMATETC_Release(src_enum);
}
ok(DataObjectImpl_GetDataHere_calls == 1, "got %d\n", DataObjectImpl_GetDataHere_calls);
ptr = GlobalLock(h);
size = GlobalSize(h);
- ok(size == strlen(cmpl_stm_data) ||
- broken(size > strlen(cmpl_stm_data)), /* win9x, winme */
+ ok(size == strlen(cmpl_stm_data),
"expected %d got %d\n", lstrlenA(cmpl_stm_data), size);
ok(!memcmp(ptr, cmpl_stm_data, strlen(cmpl_stm_data)), "mismatch\n");
GlobalUnlock(h);
ok(DataObjectImpl_GetDataHere_calls == 0, "got %d\n", DataObjectImpl_GetDataHere_calls);
ptr = GlobalLock(h);
size = GlobalSize(h);
- ok(size == strlen(cmpl_text_data) + 1 ||
- broken(size > strlen(cmpl_text_data) + 1), /* win9x, winme */
+ ok(size == strlen(cmpl_text_data) + 1,
"expected %d got %d\n", lstrlenA(cmpl_text_data) + 1, size);
ok(!memcmp(ptr, cmpl_text_data, strlen(cmpl_text_data) + 1), "mismatch\n");
GlobalUnlock(h);
ULONG ref;
LPDATAOBJECT data1, data2, data_cmpl;
HGLOBAL hblob, h;
+ void *ptr;
cf_stream = RegisterClipboardFormatA("stream format");
cf_storage = RegisterClipboardFormatA("storage format");
CoInitialize(NULL);
hr = OleSetClipboard(data1);
- ok(hr == CO_E_NOTINITIALIZED ||
- hr == CLIPBRD_E_CANT_SET, /* win9x */
- "OleSetClipboard should have failed with "
- "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr);
+ ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard failed with 0x%08x\n", hr);
CoUninitialize();
hr = OleInitialize(NULL);
/* put a format directly onto the clipboard to show
OleFlushClipboard doesn't empty the clipboard */
hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
- OpenClipboard(NULL);
+ ptr = GlobalLock( hblob );
+ ok( ptr && ptr != hblob, "got fixed block %p / %p\n", ptr, hblob );
+ GlobalUnlock( hblob );
+ ok( OpenClipboard(NULL), "OpenClipboard failed\n" );
h = SetClipboardData(cf_onemore, hblob);
ok(h == hblob, "got %p\n", h);
h = GetClipboardData(cf_onemore);
- ok(h == hblob ||
- broken(h != NULL), /* win9x */
- "got %p\n", h);
- CloseClipboard();
+ ok(h == hblob, "got %p / %p\n", h, hblob);
+ ptr = GlobalLock( h );
+ ok( ptr && ptr != h, "got fixed block %p / %p\n", ptr, h );
+ GlobalUnlock( hblob );
+ ok( CloseClipboard(), "CloseClipboard failed\n" );
hr = OleFlushClipboard();
ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
/* format should survive the flush */
- OpenClipboard(NULL);
+ ok( OpenClipboard(NULL), "OpenClipboard failed\n" );
h = GetClipboardData(cf_onemore);
- ok(h == hblob ||
- broken(h != NULL), /* win9x */
- "got %p\n", h);
- CloseClipboard();
+ ok(h == hblob, "got %p\n", h);
+ ptr = GlobalLock( h );
+ ok( ptr && ptr != h, "got fixed block %p / %p\n", ptr, h );
+ GlobalUnlock( hblob );
+ ok( CloseClipboard(), "CloseClipboard failed\n" );
test_cf_dataobject(NULL);
OleUninitialize();
}
+static LPDATAOBJECT clip_data;
+static HWND next_wnd;
+static UINT wm_drawclipboard;
+
+static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ LRESULT ret;
+
+ switch (msg)
+ {
+ case WM_DRAWCLIPBOARD:
+ wm_drawclipboard++;
+ if (clip_data)
+ {
+ /* if this is the WM_DRAWCLIPBOARD of a previous change, the data isn't current yet */
+ /* this demonstrates an issue in Qt where it will free the data while it's being set */
+ HRESULT hr = OleIsCurrentClipboard( clip_data );
+ ok( hr == (wm_drawclipboard > 1) ? S_OK : S_FALSE,
+ "OleIsCurrentClipboard returned %x\n", hr );
+ }
+ break;
+ case WM_CHANGECBCHAIN:
+ if (next_wnd == (HWND)wp) next_wnd = (HWND)lp;
+ else if (next_wnd) SendMessageA( next_wnd, msg, wp, lp );
+ break;
+ case WM_USER:
+ ret = wm_drawclipboard;
+ wm_drawclipboard = 0;
+ return ret;
+ }
+
+ return DefWindowProcA(hwnd, msg, wp, lp);
+}
+
+static DWORD CALLBACK set_clipboard_thread(void *arg)
+{
+ OpenClipboard( GetDesktopWindow() );
+ EmptyClipboard();
+ SetClipboardData( CF_WAVE, 0 );
+ CloseClipboard();
+ return 0;
+}
+
+/* test that WM_DRAWCLIPBOARD can be delivered for a previous change during OleSetClipboard */
+static void test_set_clipboard_DRAWCLIPBOARD(void)
+{
+ LPDATAOBJECT data;
+ HRESULT hr;
+ WNDCLASSA cls;
+ HWND viewer;
+ int ret;
+ HANDLE thread;
+
+ hr = DataObjectImpl_CreateText("data", &data);
+ ok(hr == S_OK, "Failed to create data object: 0x%08x\n", hr);
+
+ memset(&cls, 0, sizeof(cls));
+ cls.lpfnWndProc = clipboard_wnd_proc;
+ cls.hInstance = GetModuleHandleA(NULL);
+ cls.lpszClassName = "clipboard_test";
+ RegisterClassA(&cls);
+
+ viewer = CreateWindowA("clipboard_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0);
+ ok(viewer != NULL, "CreateWindow failed: %d\n", GetLastError());
+ next_wnd = SetClipboardViewer( viewer );
+
+ ret = SendMessageA( viewer, WM_USER, 0, 0 );
+ ok( ret == 1, "%u WM_DRAWCLIPBOARD received\n", ret );
+
+ hr = OleInitialize(NULL);
+ ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
+
+ ret = SendMessageA( viewer, WM_USER, 0, 0 );
+ ok( !ret, "%u WM_DRAWCLIPBOARD received\n", ret );
+
+ thread = CreateThread(NULL, 0, set_clipboard_thread, NULL, 0, NULL);
+ ok(thread != NULL, "CreateThread failed (%d)\n", GetLastError());
+ ret = WaitForSingleObject(thread, 5000);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret);
+
+ clip_data = data;
+ hr = OleSetClipboard(data);
+ ok(hr == S_OK, "failed to set clipboard to data, hr = 0x%08x\n", hr);
+
+ ret = SendMessageA( viewer, WM_USER, 0, 0 );
+ ok( ret == 2, "%u WM_DRAWCLIPBOARD received\n", ret );
+
+ clip_data = NULL;
+ hr = OleFlushClipboard();
+ ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
+ ret = IDataObject_Release(data);
+ ok(ret == 0, "got %d\n", ret);
+
+ OleUninitialize();
+ ChangeClipboardChain( viewer, next_wnd );
+ DestroyWindow( viewer );
+}
+
static inline ULONG count_refs(IDataObject *d)
{
IDataObject_AddRef(d);
hr = OleGetClipboard(&get2);
ok(hr == S_OK, "got %08x\n", hr);
- ok(get1 == get2 ||
- broken(get1 != get2), /* win9x, winme & nt4 */
- "data objects differ\n");
+ ok(get1 == get2, "data objects differ\n");
refs = IDataObject_Release(get2);
ok(refs == (get1 == get2 ? 1 : 0), "got %d\n", refs);
IDataObject_Release(get1);
IDataObject_Release(src2);
- IDataObject_Release(src);
+
+ /* Show that OleUninitialize() doesn't release the
+ dataobject's ref, and thus the object is leaked. */
+ old_refs = count_refs(src);
+ ok(old_refs == 1, "%d\n", old_refs);
+
+ OleSetClipboard(src);
+ refs = count_refs(src);
+ ok(refs > old_refs, "%d %d\n", refs, old_refs);
OleUninitialize();
+ refs = count_refs(src);
+ ok(refs == 2, "%d\n", refs);
+
+ IDataObject_Release(src);
}
static void test_flushed_getdata(void)
hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
ok(hr == S_OK, "got %08x\n", hr); /* User32 adds some synthesised formats */
- todo_wine ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
- if(fmt.cfFormat == CF_LOCALE)
- {
- ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
- ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
- ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
- ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
+ ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
+ ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
+ ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
+ ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
+ todo_wine ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
- hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
- ok(hr == S_OK, "got %08x\n", hr);
- }
+ hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
+ ok(hr == S_OK, "got %08x\n", hr);
ok(fmt.cfFormat == CF_OEMTEXT, "cf %04x\n", fmt.cfFormat);
ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
ok(hr == S_OK, "got %08x\n", hr);
- ok(fmt.cfFormat == CF_UNICODETEXT ||
- broken(fmt.cfFormat == CF_METAFILEPICT), /* win9x and winme don't have CF_UNICODETEXT */
- "cf %04x\n", fmt.cfFormat);
- if(fmt.cfFormat == CF_UNICODETEXT)
- {
- ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
- ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
- ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
- ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
+ ok(fmt.cfFormat == CF_UNICODETEXT, "cf %04x\n", fmt.cfFormat);
+ ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
+ ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
+ ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
+ ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
- hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
- ok(hr == S_OK, "got %08x\n", hr);
- }
+ hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
+ ok(hr == S_OK, "got %08x\n", hr);
ok(fmt.cfFormat == CF_METAFILEPICT, "cf %04x\n", fmt.cfFormat);
ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
}
+static DWORD CALLBACK test_data_obj(void *arg)
+{
+ IDataObject *data_obj = arg;
+
+ IDataObject_Release(data_obj);
+ return 0;
+}
+
+static void test_multithreaded_clipboard(void)
+{
+ IDataObject *data_obj;
+ HANDLE thread;
+ HRESULT hr;
+ DWORD ret;
+
+ OleInitialize(NULL);
+
+ hr = OleGetClipboard(&data_obj);
+ ok(hr == S_OK, "OleGetClipboard returned %x\n", hr);
+
+ thread = CreateThread(NULL, 0, test_data_obj, data_obj, 0, NULL);
+ ok(thread != NULL, "CreateThread failed (%d)\n", GetLastError());
+ ret = WaitForSingleObject(thread, 5000);
+ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret);
+
+ hr = OleGetClipboard(&data_obj);
+ ok(hr == S_OK, "OleGetClipboard returned %x\n", hr);
+ IDataObject_Release(data_obj);
+
+ OleUninitialize();
+}
+
+static void test_get_clipboard_locked(void)
+{
+ HRESULT hr;
+ IDataObject *pDObj;
+
+ OleInitialize(NULL);
+
+ pDObj = (IDataObject *)0xdeadbeef;
+ /* lock clipboard */
+ OpenClipboard(NULL);
+ hr = OleGetClipboard(&pDObj);
+ todo_wine ok(hr == CLIPBRD_E_CANT_OPEN, "OleGetClipboard() got 0x%08x instead of 0x%08x\n", hr, CLIPBRD_E_CANT_OPEN);
+ todo_wine ok(pDObj == NULL, "OleGetClipboard() got 0x%p instead of NULL\n",pDObj);
+ if (pDObj) IDataObject_Release(pDObj);
+ CloseClipboard();
+
+ OleUninitialize();
+}
+
START_TEST(clipboard)
{
+ test_get_clipboard_uninitialized();
test_set_clipboard();
+ test_set_clipboard_DRAWCLIPBOARD();
test_consumer_refs();
test_flushed_getdata();
test_nonole_clipboard();
test_getdatahere();
+ test_multithreaded_clipboard();
+ test_get_clipboard_locked();
}