4 * Copyright 2006 Kevin Koltzau
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define NONAMELESSUNION
32 #include "wine/test.h"
34 #define InitFormatEtc(fe, cf, med) \
37 (fe).dwAspect=DVASPECT_CONTENT;\
43 static inline char *dump_fmtetc(FORMATETC *fmt)
47 snprintf(buf, sizeof(buf), "cf %04x ptd %p aspect %x lindex %d tymed %x",
48 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed);
52 typedef struct DataObjectImpl {
53 IDataObject IDataObject_iface;
64 typedef struct EnumFormatImpl {
65 IEnumFORMATETC IEnumFORMATETC_iface;
74 static BOOL expect_DataObjectImpl_QueryGetData = TRUE;
75 static ULONG DataObjectImpl_GetData_calls = 0;
76 static ULONG DataObjectImpl_GetDataHere_calls = 0;
77 static ULONG DataObjectImpl_EnumFormatEtc_calls = 0;
79 static UINT cf_stream, cf_storage, cf_global, cf_another, cf_onemore;
81 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc);
83 static inline DataObjectImpl *impl_from_IDataObject(IDataObject *iface)
85 return CONTAINING_RECORD(iface, DataObjectImpl, IDataObject_iface);
88 static inline EnumFormatImpl *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface)
90 return CONTAINING_RECORD(iface, EnumFormatImpl, IEnumFORMATETC_iface);
93 static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj)
95 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
97 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumFORMATETC)) {
98 IEnumFORMATETC_AddRef(iface);
103 return E_NOINTERFACE;
106 static ULONG WINAPI EnumFormatImpl_AddRef(IEnumFORMATETC *iface)
108 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
109 LONG ref = InterlockedIncrement(&This->ref);
113 static ULONG WINAPI EnumFormatImpl_Release(IEnumFORMATETC *iface)
115 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
116 ULONG ref = InterlockedDecrement(&This->ref);
119 HeapFree(GetProcessHeap(), 0, This->fmtetc);
120 HeapFree(GetProcessHeap(), 0, This);
126 static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
127 FORMATETC *rgelt, ULONG *pceltFetched)
129 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
132 trace("next: count %d cur %d\n", celt, This->cur);
137 count = min(celt, This->fmtetc_cnt - This->cur);
138 for(i = 0; i < count; i++, This->cur++, rgelt++)
140 *rgelt = This->fmtetc[This->cur];
143 DWORD size = This->fmtetc[This->cur].ptd->tdSize;
144 rgelt->ptd = CoTaskMemAlloc(size);
145 memcpy(rgelt->ptd, This->fmtetc[This->cur].ptd, size);
149 *pceltFetched = count;
150 return count == celt ? S_OK : S_FALSE;
153 static HRESULT WINAPI EnumFormatImpl_Skip(IEnumFORMATETC *iface, ULONG celt)
155 ok(0, "unexpected call\n");
159 static HRESULT WINAPI EnumFormatImpl_Reset(IEnumFORMATETC *iface)
161 EnumFormatImpl *This = impl_from_IEnumFORMATETC(iface);
167 static HRESULT WINAPI EnumFormatImpl_Clone(IEnumFORMATETC *iface, IEnumFORMATETC **ppenum)
169 ok(0, "unexpected call\n");
173 static const IEnumFORMATETCVtbl VT_EnumFormatImpl = {
174 EnumFormatImpl_QueryInterface,
175 EnumFormatImpl_AddRef,
176 EnumFormatImpl_Release,
179 EnumFormatImpl_Reset,
183 static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT fmtetc_cnt, IEnumFORMATETC **lplpformatetc)
187 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumFormatImpl));
188 ret->IEnumFORMATETC_iface.lpVtbl = &VT_EnumFormatImpl;
191 ret->fmtetc_cnt = fmtetc_cnt;
192 ret->fmtetc = HeapAlloc(GetProcessHeap(), 0, fmtetc_cnt*sizeof(FORMATETC));
193 memcpy(ret->fmtetc, fmtetc, fmtetc_cnt*sizeof(FORMATETC));
194 *lplpformatetc = (LPENUMFORMATETC)ret;
198 static HRESULT WINAPI DataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, LPVOID *ppvObj)
200 DataObjectImpl *This = impl_from_IDataObject(iface);
202 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDataObject)) {
203 IDataObject_AddRef(iface);
208 return E_NOINTERFACE;
211 static ULONG WINAPI DataObjectImpl_AddRef(IDataObject* iface)
213 DataObjectImpl *This = impl_from_IDataObject(iface);
214 ULONG ref = InterlockedIncrement(&This->ref);
218 static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
220 DataObjectImpl *This = impl_from_IDataObject(iface);
221 ULONG ref = InterlockedDecrement(&This->ref);
226 if(This->text) GlobalFree(This->text);
227 for(i = 0; i < This->fmtetc_cnt; i++)
228 HeapFree(GetProcessHeap(), 0, This->fmtetc[i].ptd);
229 HeapFree(GetProcessHeap(), 0, This->fmtetc);
230 if(This->stm) IStream_Release(This->stm);
231 if(This->stg) IStorage_Release(This->stg);
232 HeapFree(GetProcessHeap(), 0, This);
238 static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
240 DataObjectImpl *This = impl_from_IDataObject(iface);
242 BOOL foundFormat = FALSE;
244 trace("getdata: %s\n", dump_fmtetc(pformatetc));
246 DataObjectImpl_GetData_calls++;
248 if(pformatetc->lindex != -1)
249 return DV_E_FORMATETC;
251 for(i = 0; i < This->fmtetc_cnt; i++)
253 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat)
256 if(This->fmtetc[i].tymed & pformatetc->tymed)
258 pmedium->pUnkForRelease = (LPUNKNOWN)iface;
259 IUnknown_AddRef(pmedium->pUnkForRelease);
261 if(pformatetc->cfFormat == CF_TEXT || pformatetc->cfFormat == cf_global)
263 pmedium->tymed = TYMED_HGLOBAL;
264 U(*pmedium).hGlobal = This->text;
266 else if(pformatetc->cfFormat == cf_stream)
268 pmedium->tymed = TYMED_ISTREAM;
269 IStream_AddRef(This->stm);
270 U(*pmedium).pstm = This->stm;
272 else if(pformatetc->cfFormat == cf_storage || pformatetc->cfFormat == cf_another)
274 pmedium->tymed = TYMED_ISTORAGE;
275 IStorage_AddRef(This->stg);
276 U(*pmedium).pstg = This->stg;
283 return foundFormat ? DV_E_TYMED : DV_E_FORMATETC;
286 static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
288 trace("getdatahere: %s\n", dump_fmtetc(pformatetc));
289 DataObjectImpl_GetDataHere_calls++;
294 static HRESULT WINAPI DataObjectImpl_QueryGetData(IDataObject* iface, FORMATETC *pformatetc)
296 DataObjectImpl *This = impl_from_IDataObject(iface);
298 BOOL foundFormat = FALSE;
300 trace("querygetdata: %s\n", dump_fmtetc(pformatetc));
301 if (!expect_DataObjectImpl_QueryGetData)
302 ok(0, "unexpected call to DataObjectImpl_QueryGetData\n");
304 if(pformatetc->lindex != -1)
307 for(i=0; i<This->fmtetc_cnt; i++) {
308 if(This->fmtetc[i].cfFormat == pformatetc->cfFormat) {
310 if(This->fmtetc[i].tymed == pformatetc->tymed)
314 return foundFormat?DV_E_FORMATETC:DV_E_TYMED;
317 static HRESULT WINAPI DataObjectImpl_GetCanonicalFormatEtc(IDataObject* iface, FORMATETC *pformatectIn,
318 FORMATETC *pformatetcOut)
320 ok(0, "unexpected call\n");
324 static HRESULT WINAPI DataObjectImpl_SetData(IDataObject* iface, FORMATETC *pformatetc,
325 STGMEDIUM *pmedium, BOOL fRelease)
327 ok(0, "unexpected call\n");
331 static HRESULT WINAPI DataObjectImpl_EnumFormatEtc(IDataObject* iface, DWORD dwDirection,
332 IEnumFORMATETC **ppenumFormatEtc)
334 DataObjectImpl *This = impl_from_IDataObject(iface);
336 DataObjectImpl_EnumFormatEtc_calls++;
338 if(dwDirection != DATADIR_GET) {
339 ok(0, "unexpected direction %d\n", dwDirection);
342 return EnumFormatImpl_Create(This->fmtetc, This->fmtetc_cnt, ppenumFormatEtc);
345 static HRESULT WINAPI DataObjectImpl_DAdvise(IDataObject* iface, FORMATETC *pformatetc, DWORD advf,
346 IAdviseSink *pAdvSink, DWORD *pdwConnection)
348 ok(0, "unexpected call\n");
352 static HRESULT WINAPI DataObjectImpl_DUnadvise(IDataObject* iface, DWORD dwConnection)
354 ok(0, "unexpected call\n");
358 static HRESULT WINAPI DataObjectImpl_EnumDAdvise(IDataObject* iface, IEnumSTATDATA **ppenumAdvise)
360 ok(0, "unexpected call\n");
364 static const IDataObjectVtbl VT_DataObjectImpl =
366 DataObjectImpl_QueryInterface,
367 DataObjectImpl_AddRef,
368 DataObjectImpl_Release,
369 DataObjectImpl_GetData,
370 DataObjectImpl_GetDataHere,
371 DataObjectImpl_QueryGetData,
372 DataObjectImpl_GetCanonicalFormatEtc,
373 DataObjectImpl_SetData,
374 DataObjectImpl_EnumFormatEtc,
375 DataObjectImpl_DAdvise,
376 DataObjectImpl_DUnadvise,
377 DataObjectImpl_EnumDAdvise
380 static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj)
384 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
385 obj->IDataObject_iface.lpVtbl = &VT_DataObjectImpl;
387 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1);
388 strcpy(GlobalLock(obj->text), text);
389 GlobalUnlock(obj->text);
394 obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC));
395 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
397 *lplpdataobj = (LPDATAOBJECT)obj;
401 static const char *cmpl_stm_data = "complex stream";
402 static const char *cmpl_text_data = "complex text";
403 static const WCHAR device_name[] = {'m','y','d','e','v',0};
405 static HRESULT DataObjectImpl_CreateComplex(LPDATAOBJECT *lplpdataobj)
411 obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
412 obj->IDataObject_iface.lpVtbl = &VT_DataObjectImpl;
414 obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(cmpl_text_data) + 1);
415 strcpy(GlobalLock(obj->text), cmpl_text_data);
416 GlobalUnlock(obj->text);
417 CreateStreamOnHGlobal(NULL, TRUE, &obj->stm);
418 IStream_Write(obj->stm, cmpl_stm_data, strlen(cmpl_stm_data), NULL);
420 CreateILockBytesOnHGlobal(NULL, TRUE, &lbs);
421 StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &obj->stg);
422 ILockBytes_Release(lbs);
425 /* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
426 obj->fmtetc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, obj->fmtetc_cnt*sizeof(FORMATETC));
427 InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
428 InitFormatEtc(obj->fmtetc[1], cf_stream, TYMED_ISTREAM);
429 InitFormatEtc(obj->fmtetc[2], cf_storage, TYMED_ISTORAGE);
430 InitFormatEtc(obj->fmtetc[3], cf_another, TYMED_ISTORAGE|TYMED_ISTREAM|TYMED_HGLOBAL);
431 memset(&dm, 0, sizeof(dm));
432 dm.dmSize = sizeof(dm);
433 dm.dmDriverExtra = 0;
434 lstrcpyW(dm.dmDeviceName, device_name);
435 obj->fmtetc[3].ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra);
436 obj->fmtetc[3].ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra;
437 obj->fmtetc[3].ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
438 obj->fmtetc[3].ptd->tdDeviceNameOffset = 0;
439 obj->fmtetc[3].ptd->tdPortNameOffset = 0;
440 obj->fmtetc[3].ptd->tdExtDevmodeOffset = obj->fmtetc[3].ptd->tdDriverNameOffset + sizeof(device_name);
441 lstrcpyW((WCHAR*)obj->fmtetc[3].ptd->tdData, device_name);
442 memcpy(obj->fmtetc[3].ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra);
444 InitFormatEtc(obj->fmtetc[4], cf_global, TYMED_HGLOBAL);
445 InitFormatEtc(obj->fmtetc[5], cf_another, TYMED_HGLOBAL);
446 InitFormatEtc(obj->fmtetc[6], cf_another, 0xfffff);
447 InitFormatEtc(obj->fmtetc[7], cf_another, 0xfffff);
448 obj->fmtetc[7].dwAspect = DVASPECT_ICON;
450 *lplpdataobj = (LPDATAOBJECT)obj;
454 static void test_get_clipboard(void)
457 IDataObject *data_obj;
461 hr = OleGetClipboard(NULL);
462 ok(hr == E_INVALIDARG, "OleGetClipboard(NULL) should return E_INVALIDARG instead of 0x%08x\n", hr);
464 hr = OleGetClipboard(&data_obj);
465 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
467 /* test IDataObject_QueryGetData */
469 /* clipboard's IDataObject_QueryGetData shouldn't defer to our IDataObject_QueryGetData */
470 expect_DataObjectImpl_QueryGetData = FALSE;
472 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
473 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
474 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
476 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
477 fmtetc.dwAspect = 0xdeadbeef;
478 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
479 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
481 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
482 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
483 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
484 ok(hr == DV_E_FORMATETC, "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
486 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
488 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
489 ok(hr == DV_E_FORMATETC || broken(hr == S_OK),
490 "IDataObject_QueryGetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
492 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
493 fmtetc.cfFormat = CF_RIFF;
494 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
495 ok(hr == DV_E_CLIPFORMAT, "IDataObject_QueryGetData should have failed with DV_E_CLIPFORMAT instead of 0x%08x\n", hr);
497 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
498 fmtetc.tymed = TYMED_FILE;
499 hr = IDataObject_QueryGetData(data_obj, &fmtetc);
500 ok(hr == S_OK, "IDataObject_QueryGetData failed with error 0x%08x\n", hr);
502 expect_DataObjectImpl_QueryGetData = TRUE;
504 /* test IDataObject_GetData */
506 DataObjectImpl_GetData_calls = 0;
508 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
509 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
510 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
511 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
513 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
514 fmtetc.dwAspect = 0xdeadbeef;
515 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
516 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
517 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
519 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
520 fmtetc.dwAspect = DVASPECT_THUMBNAIL;
521 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
522 ok(hr == S_OK, "IDataObject_GetData failed with error 0x%08x\n", hr);
523 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
525 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
527 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
528 ok(hr == DV_E_FORMATETC || broken(hr == S_OK), "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
531 /* undo the unexpected success */
532 DataObjectImpl_GetData_calls--;
533 ReleaseStgMedium(&stgmedium);
536 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
537 fmtetc.cfFormat = CF_RIFF;
538 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
539 ok(hr == DV_E_FORMATETC, "IDataObject_GetData should have failed with DV_E_FORMATETC instead of 0x%08x\n", hr);
540 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
542 InitFormatEtc(fmtetc, CF_TEXT, TYMED_HGLOBAL);
543 fmtetc.tymed = TYMED_FILE;
544 hr = IDataObject_GetData(data_obj, &fmtetc, &stgmedium);
545 ok(hr == DV_E_TYMED, "IDataObject_GetData should have failed with DV_E_TYMED instead of 0x%08x\n", hr);
546 if(SUCCEEDED(hr)) ReleaseStgMedium(&stgmedium);
548 ok(DataObjectImpl_GetData_calls == 6, "DataObjectImpl_GetData should have been called 6 times instead of %d times\n", DataObjectImpl_GetData_calls);
550 IDataObject_Release(data_obj);
553 static void test_enum_fmtetc(IDataObject *src)
557 IEnumFORMATETC *enum_fmt, *src_enum;
558 FORMATETC fmt, src_fmt;
561 hr = OleGetClipboard(&data);
562 ok(hr == S_OK, "OleGetClipboard failed with error 0x%08x\n", hr);
564 hr = IDataObject_EnumFormatEtc(data, DATADIR_SET, &enum_fmt);
565 ok(hr == E_NOTIMPL ||
566 broken(hr == E_INVALIDARG), /* win98 (not win98SE) */
569 DataObjectImpl_EnumFormatEtc_calls = 0;
570 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
571 ok(hr == S_OK, "got %08x\n", hr);
572 ok(DataObjectImpl_EnumFormatEtc_calls == 0, "EnumFormatEtc was called\n");
574 if(src) IDataObject_EnumFormatEtc(src, DATADIR_GET, &src_enum);
576 while((hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL)) == S_OK)
578 ok(src != NULL, "shouldn't be here\n");
579 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
580 ok(hr == S_OK, "%d: got %08x\n", count, hr);
581 trace("%d: %s\n", count, dump_fmtetc(&fmt));
582 ok(fmt.cfFormat == src_fmt.cfFormat, "%d: %04x %04x\n", count, fmt.cfFormat, src_fmt.cfFormat);
583 ok(fmt.dwAspect == src_fmt.dwAspect, "%d: %08x %08x\n", count, fmt.dwAspect, src_fmt.dwAspect);
584 ok(fmt.lindex == src_fmt.lindex, "%d: %08x %08x\n", count, fmt.lindex, src_fmt.lindex);
585 ok(fmt.tymed == src_fmt.tymed, "%d: %08x %08x\n", count, fmt.tymed, src_fmt.tymed);
588 ok(src_fmt.ptd != NULL, "%d: expected non-NULL\n", count);
589 CoTaskMemFree(fmt.ptd);
590 CoTaskMemFree(src_fmt.ptd);
595 ok(hr == S_FALSE, "%d: got %08x\n", count, hr);
599 hr = IEnumFORMATETC_Next(src_enum, 1, &src_fmt, NULL);
601 broken(hr == S_OK && count == 5), /* win9x and winme don't enumerate duplicated cf's */
602 "%d: got %08x\n", count, hr);
603 IEnumFORMATETC_Release(src_enum);
606 hr = IEnumFORMATETC_Reset(enum_fmt);
607 ok(hr == S_OK, "got %08x\n", hr);
609 if(src) /* Exercise the enumerator a bit */
611 IEnumFORMATETC *clone;
614 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
615 ok(hr == S_OK, "got %08x\n", hr);
616 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
617 ok(hr == S_OK, "got %08x\n", hr);
618 hr = IEnumFORMATETC_Next(enum_fmt, 1, &third_fmt, NULL);
619 ok(hr == S_OK, "got %08x\n", hr);
621 hr = IEnumFORMATETC_Reset(enum_fmt);
622 ok(hr == S_OK, "got %08x\n", hr);
623 hr = IEnumFORMATETC_Skip(enum_fmt, 2);
624 ok(hr == S_OK, "got %08x\n", hr);
626 hr = IEnumFORMATETC_Clone(enum_fmt, &clone);
627 ok(hr == S_OK, "got %08x\n", hr);
628 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
629 ok(hr == S_OK, "got %08x\n", hr);
630 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n");
631 hr = IEnumFORMATETC_Next(clone, 1, &fmt, NULL);
632 ok(hr == S_OK, "got %08x\n", hr);
633 ok(fmt.cfFormat == third_fmt.cfFormat, "formats don't match\n");
634 IEnumFORMATETC_Release(clone);
637 IEnumFORMATETC_Release(enum_fmt);
638 IDataObject_Release(data);
641 static void test_no_cf_dataobject(void)
643 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
644 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
648 h = GetClipboardData(cf_dataobject);
649 ok(!h, "got %p\n", h);
650 h = GetClipboardData(cf_ole_priv_data);
651 ok(!h, "got %p\n", h);
656 static void test_cf_dataobject(IDataObject *data)
659 UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
660 UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
661 BOOL found_dataobject = FALSE, found_priv_data = FALSE;
666 cf = EnumClipboardFormats(cf);
667 if(cf == cf_dataobject)
669 HGLOBAL h = GetClipboardData(cf);
670 HWND *ptr = GlobalLock(h);
671 DWORD size = GlobalSize(h);
672 HWND clip_owner = GetClipboardOwner();
674 found_dataobject = TRUE;
675 ok(size >= sizeof(*ptr), "size %d\n", size);
677 ok(*ptr == clip_owner, "hwnd %p clip_owner %p\n", *ptr, clip_owner);
678 else /* ole clipboard flushed */
679 ok(*ptr == NULL, "hwnd %p\n", *ptr);
682 else if(cf == cf_ole_priv_data)
684 found_priv_data = TRUE;
687 HGLOBAL h = GetClipboardData(cf);
688 DWORD *ptr = GlobalLock(h);
689 DWORD size = GlobalSize(h);
692 win_skip("Ole Private Data in win9x format\n");
696 IEnumFORMATETC *enum_fmt;
702 BOOL first_use_of_cf;
712 struct formatetcetc fmts[1];
713 } *priv = (struct priv_data*)ptr;
714 CLIPFORMAT cfs_seen[10];
716 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
717 ok(hr == S_OK, "got %08x\n", hr);
718 fmt_ptr = priv->fmts;
720 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
723 BOOL seen_cf = FALSE;
725 ok(fmt_ptr->fmt.cfFormat == fmt.cfFormat,
726 "got %08x expected %08x\n", fmt_ptr->fmt.cfFormat, fmt.cfFormat);
727 ok(fmt_ptr->fmt.dwAspect == fmt.dwAspect, "got %08x expected %08x\n",
728 fmt_ptr->fmt.dwAspect, fmt.dwAspect);
729 ok(fmt_ptr->fmt.lindex == fmt.lindex, "got %08x expected %08x\n",
730 fmt_ptr->fmt.lindex, fmt.lindex);
731 ok(fmt_ptr->fmt.tymed == fmt.tymed, "got %08x expected %08x\n",
732 fmt_ptr->fmt.tymed, fmt.tymed);
733 for(i = 0; i < count; i++)
734 if(fmt_ptr->fmt.cfFormat == cfs_seen[i])
739 cfs_seen[count] = fmt.cfFormat;
740 ok(fmt_ptr->first_use_of_cf == seen_cf ? FALSE : TRUE, "got %08x expected %08x\n",
741 fmt_ptr->first_use_of_cf, !seen_cf);
742 ok(fmt_ptr->res[0] == 0, "got %08x\n", fmt_ptr->res[1]);
743 ok(fmt_ptr->res[1] == 0, "got %08x\n", fmt_ptr->res[2]);
746 DVTARGETDEVICE *target;
748 ok(fmt_ptr->fmt.ptd != NULL, "target device offset zero\n");
749 target = (DVTARGETDEVICE*)((char*)priv + (DWORD_PTR)fmt_ptr->fmt.ptd);
750 ok(!memcmp(target, fmt.ptd, fmt.ptd->tdSize), "target devices differ\n");
751 CoTaskMemFree(fmt.ptd);
756 ok(priv->res1 == 0, "got %08x\n", priv->res1);
757 ok(priv->res2 == 1, "got %08x\n", priv->res2);
758 ok(priv->count == count, "got %08x expected %08x\n", priv->count, count);
759 ok(priv->res3[0] == 0, "got %08x\n", priv->res3[0]);
761 /* win64 sets the lsb */
762 if(sizeof(fmt_ptr->fmt.ptd) == 8)
763 todo_wine ok(priv->res3[1] == 1, "got %08x\n", priv->res3[1]);
765 ok(priv->res3[1] == 0, "got %08x\n", priv->res3[1]);
768 IEnumFORMATETC_Release(enum_fmt);
772 else if(cf == cf_stream)
778 DataObjectImpl_GetDataHere_calls = 0;
779 h = GetClipboardData(cf);
780 ok(DataObjectImpl_GetDataHere_calls == 1, "got %d\n", DataObjectImpl_GetDataHere_calls);
782 size = GlobalSize(h);
783 ok(size == strlen(cmpl_stm_data) ||
784 broken(size > strlen(cmpl_stm_data)), /* win9x, winme */
785 "expected %d got %d\n", lstrlenA(cmpl_stm_data), size);
786 ok(!memcmp(ptr, cmpl_stm_data, strlen(cmpl_stm_data)), "mismatch\n");
789 else if(cf == cf_global)
795 DataObjectImpl_GetDataHere_calls = 0;
796 h = GetClipboardData(cf);
797 ok(DataObjectImpl_GetDataHere_calls == 0, "got %d\n", DataObjectImpl_GetDataHere_calls);
799 size = GlobalSize(h);
800 ok(size == strlen(cmpl_text_data) + 1 ||
801 broken(size > strlen(cmpl_text_data) + 1), /* win9x, winme */
802 "expected %d got %d\n", lstrlenA(cmpl_text_data) + 1, size);
803 ok(!memcmp(ptr, cmpl_text_data, strlen(cmpl_text_data) + 1), "mismatch\n");
808 ok(found_dataobject, "didn't find cf_dataobject\n");
809 ok(found_priv_data, "didn't find cf_ole_priv_data\n");
812 static void test_set_clipboard(void)
816 LPDATAOBJECT data1, data2, data_cmpl;
819 cf_stream = RegisterClipboardFormatA("stream format");
820 cf_storage = RegisterClipboardFormatA("storage format");
821 cf_global = RegisterClipboardFormatA("global format");
822 cf_another = RegisterClipboardFormatA("another format");
823 cf_onemore = RegisterClipboardFormatA("one more format");
825 hr = DataObjectImpl_CreateText("data1", &data1);
826 ok(SUCCEEDED(hr), "Failed to create data1 object: 0x%08x\n", hr);
829 hr = DataObjectImpl_CreateText("data2", &data2);
830 ok(SUCCEEDED(hr), "Failed to create data2 object: 0x%08x\n", hr);
833 hr = DataObjectImpl_CreateComplex(&data_cmpl);
834 ok(SUCCEEDED(hr), "Failed to create complex data object: 0x%08x\n", hr);
838 hr = OleSetClipboard(data1);
839 ok(hr == CO_E_NOTINITIALIZED, "OleSetClipboard should have failed with CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
842 hr = OleSetClipboard(data1);
843 ok(hr == CO_E_NOTINITIALIZED ||
844 hr == CLIPBRD_E_CANT_SET, /* win9x */
845 "OleSetClipboard should have failed with "
846 "CO_E_NOTINITIALIZED or CLIPBRD_E_CANT_SET instead of 0x%08x\n", hr);
849 hr = OleInitialize(NULL);
850 ok(hr == S_OK, "OleInitialize failed with error 0x%08x\n", hr);
852 hr = OleSetClipboard(data1);
853 ok(hr == S_OK, "failed to set clipboard to data1, hr = 0x%08x\n", hr);
855 test_cf_dataobject(data1);
857 hr = OleIsCurrentClipboard(data1);
858 ok(hr == S_OK, "expected current clipboard to be data1, hr = 0x%08x\n", hr);
859 hr = OleIsCurrentClipboard(data2);
860 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
861 hr = OleIsCurrentClipboard(NULL);
862 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
864 test_get_clipboard();
866 hr = OleSetClipboard(data2);
867 ok(hr == S_OK, "failed to set clipboard to data2, hr = 0x%08x\n", hr);
868 hr = OleIsCurrentClipboard(data1);
869 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
870 hr = OleIsCurrentClipboard(data2);
871 ok(hr == S_OK, "expected current clipboard to be data2, hr = 0x%08x\n", hr);
872 hr = OleIsCurrentClipboard(NULL);
873 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
875 /* put a format directly onto the clipboard to show
876 OleFlushClipboard doesn't empty the clipboard */
877 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
879 h = SetClipboardData(cf_onemore, hblob);
880 ok(h == hblob, "got %p\n", h);
881 h = GetClipboardData(cf_onemore);
883 broken(h != NULL), /* win9x */
887 hr = OleFlushClipboard();
888 ok(hr == S_OK, "failed to flush clipboard, hr = 0x%08x\n", hr);
889 hr = OleIsCurrentClipboard(data1);
890 ok(hr == S_FALSE, "did not expect current clipboard to be data1, hr = 0x%08x\n", hr);
891 hr = OleIsCurrentClipboard(data2);
892 ok(hr == S_FALSE, "did not expect current clipboard to be data2, hr = 0x%08x\n", hr);
893 hr = OleIsCurrentClipboard(NULL);
894 ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
896 /* format should survive the flush */
898 h = GetClipboardData(cf_onemore);
900 broken(h != NULL), /* win9x */
904 test_cf_dataobject(NULL);
906 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
909 h = GetClipboardData(cf_onemore);
910 ok(h == NULL, "got %p\n", h);
913 trace("setting complex\n");
914 hr = OleSetClipboard(data_cmpl);
915 ok(hr == S_OK, "failed to set clipboard to complex data, hr = 0x%08x\n", hr);
916 test_cf_dataobject(data_cmpl);
917 test_enum_fmtetc(data_cmpl);
919 ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
921 test_no_cf_dataobject();
922 test_enum_fmtetc(NULL);
924 ref = IDataObject_Release(data1);
925 ok(ref == 0, "expected data1 ref=0, got %d\n", ref);
926 ref = IDataObject_Release(data2);
927 ok(ref == 0, "expected data2 ref=0, got %d\n", ref);
928 ref = IDataObject_Release(data_cmpl);
929 ok(ref == 0, "expected data_cmpl ref=0, got %d\n", ref);
934 static inline ULONG count_refs(IDataObject *d)
936 IDataObject_AddRef(d);
937 return IDataObject_Release(d);
940 static void test_consumer_refs(void)
943 IDataObject *src, *src2, *get1, *get2, *get3;
944 ULONG refs, old_refs;
948 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
952 /* First show that each clipboard state results in
953 a different data object */
955 hr = DataObjectImpl_CreateText("data1", &src);
956 ok(hr == S_OK, "got %08x\n", hr);
957 hr = DataObjectImpl_CreateText("data2", &src2);
958 ok(hr == S_OK, "got %08x\n", hr);
960 hr = OleSetClipboard(src);
961 ok(hr == S_OK, "got %08x\n", hr);
963 hr = OleGetClipboard(&get1);
964 ok(hr == S_OK, "got %08x\n", hr);
966 hr = OleGetClipboard(&get2);
967 ok(hr == S_OK, "got %08x\n", hr);
970 broken(get1 != get2), /* win9x, winme & nt4 */
971 "data objects differ\n");
972 refs = IDataObject_Release(get2);
973 ok(refs == (get1 == get2 ? 1 : 0), "got %d\n", refs);
977 DataObjectImpl_GetData_calls = 0;
978 hr = IDataObject_GetData(get1, &fmt, &med);
979 ok(hr == S_OK, "got %08x\n", hr);
980 ok(DataObjectImpl_GetData_calls == 0, "GetData called\n");
981 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
983 hr = OleGetClipboard(&get2);
984 ok(hr == S_OK, "got %08x\n", hr);
986 ok(get1 != get2, "data objects match\n");
988 OleSetClipboard(NULL);
990 hr = OleGetClipboard(&get3);
991 ok(hr == S_OK, "got %08x\n", hr);
993 ok(get1 != get3, "data objects match\n");
994 ok(get2 != get3, "data objects match\n");
996 IDataObject_Release(get3);
997 IDataObject_Release(get2);
998 IDataObject_Release(get1);
1000 /* Now call GetData before the flush and show that this
1001 takes a ref on our src data obj. */
1003 hr = OleSetClipboard(src);
1004 ok(hr == S_OK, "got %08x\n", hr);
1006 old_refs = count_refs(src);
1008 hr = OleGetClipboard(&get1);
1009 ok(hr == S_OK, "got %08x\n", hr);
1011 refs = count_refs(src);
1012 ok(refs == old_refs, "%d %d\n", refs, old_refs);
1014 DataObjectImpl_GetData_calls = 0;
1015 hr = IDataObject_GetData(get1, &fmt, &med);
1016 ok(hr == S_OK, "got %08x\n", hr);
1017 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1018 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1019 refs = count_refs(src);
1020 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
1022 OleFlushClipboard();
1024 DataObjectImpl_GetData_calls = 0;
1025 hr = IDataObject_GetData(get1, &fmt, &med);
1026 ok(hr == S_OK, "got %08x\n", hr);
1027 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1028 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1030 refs = count_refs(src);
1031 ok(refs == 2, "%d\n", refs);
1033 IDataObject_Release(get1);
1035 refs = count_refs(src);
1036 ok(refs == 1, "%d\n", refs);
1038 /* Now set a second src object before the call to GetData
1039 and show that GetData calls that second src. */
1041 hr = OleSetClipboard(src);
1042 ok(hr == S_OK, "got %08x\n", hr);
1044 old_refs = count_refs(src);
1046 hr = OleGetClipboard(&get1);
1047 ok(hr == S_OK, "got %08x\n", hr);
1049 refs = count_refs(src);
1050 ok(refs == old_refs, "%d %d\n", refs, old_refs);
1052 hr = OleSetClipboard(src2);
1053 ok(hr == S_OK, "got %08x\n", hr);
1055 old_refs = count_refs(src2);
1057 DataObjectImpl_GetData_calls = 0;
1058 hr = IDataObject_GetData(get1, &fmt, &med);
1059 ok(hr == S_OK, "got %08x\n", hr);
1060 ok(DataObjectImpl_GetData_calls == 1, "GetData not called\n");
1061 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1063 refs = count_refs(src);
1064 ok(refs == 1, "%d\n", refs);
1065 refs = count_refs(src2);
1066 ok(refs == old_refs + 1, "%d %d\n", refs, old_refs);
1068 OleSetClipboard(NULL);
1070 refs = count_refs(src2);
1071 ok(refs == 2, "%d\n", refs);
1073 IDataObject_Release(get1);
1075 IDataObject_Release(src2);
1076 IDataObject_Release(src);
1081 static void test_flushed_getdata(void)
1084 IDataObject *src, *get;
1090 OleInitialize(NULL);
1092 hr = DataObjectImpl_CreateComplex(&src);
1093 ok(hr == S_OK, "got %08x\n", hr);
1095 hr = OleSetClipboard(src);
1096 ok(hr == S_OK, "got %08x\n", hr);
1098 hr = OleFlushClipboard();
1099 ok(hr == S_OK, "got %08x\n", hr);
1101 hr = OleGetClipboard(&get);
1102 ok(hr == S_OK, "got %08x\n", hr);
1104 /* global format -> global & stream */
1106 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1107 hr = IDataObject_GetData(get, &fmt, &med);
1108 ok(hr == S_OK, "got %08x\n", hr);
1109 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1110 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1112 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTREAM);
1113 hr = IDataObject_GetData(get, &fmt, &med);
1114 ok(hr == S_OK, "got %08x\n", hr);
1115 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1116 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1118 InitFormatEtc(fmt, CF_TEXT, TYMED_ISTORAGE);
1119 hr = IDataObject_GetData(get, &fmt, &med);
1120 ok(hr == E_FAIL, "got %08x\n", hr);
1121 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1123 InitFormatEtc(fmt, CF_TEXT, 0xffff);
1124 hr = IDataObject_GetData(get, &fmt, &med);
1125 ok(hr == S_OK, "got %08x\n", hr);
1126 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1127 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1129 /* stream format -> global & stream */
1131 InitFormatEtc(fmt, cf_stream, TYMED_ISTREAM);
1132 hr = IDataObject_GetData(get, &fmt, &med);
1133 ok(hr == S_OK, "got %08x\n", hr);
1134 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1135 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1137 InitFormatEtc(fmt, cf_stream, TYMED_ISTORAGE);
1138 hr = IDataObject_GetData(get, &fmt, &med);
1139 ok(hr == E_FAIL, "got %08x\n", hr);
1140 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1142 InitFormatEtc(fmt, cf_stream, TYMED_HGLOBAL);
1143 hr = IDataObject_GetData(get, &fmt, &med);
1144 ok(hr == S_OK, "got %08x\n", hr);
1145 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1146 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1148 InitFormatEtc(fmt, cf_stream, 0xffff);
1149 hr = IDataObject_GetData(get, &fmt, &med);
1150 ok(hr == S_OK, "got %08x\n", hr);
1151 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1152 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1154 /* storage format -> global, stream & storage */
1156 InitFormatEtc(fmt, cf_storage, TYMED_ISTORAGE);
1157 hr = IDataObject_GetData(get, &fmt, &med);
1158 ok(hr == S_OK, "got %08x\n", hr);
1159 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1161 hr = IStorage_Stat(med.u.pstg, &stat, STATFLAG_NONAME);
1162 ok(hr == S_OK, "got %08x\n", hr);
1163 ok(stat.grfMode == (STGM_SHARE_EXCLUSIVE | STGM_READWRITE), "got %08x\n", stat.grfMode);
1164 ReleaseStgMedium(&med);
1167 InitFormatEtc(fmt, cf_storage, TYMED_ISTREAM);
1168 hr = IDataObject_GetData(get, &fmt, &med);
1169 ok(hr == S_OK, "got %08x\n", hr);
1170 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1171 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1173 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL);
1174 hr = IDataObject_GetData(get, &fmt, &med);
1175 ok(hr == S_OK, "got %08x\n", hr);
1176 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1177 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1179 InitFormatEtc(fmt, cf_storage, TYMED_HGLOBAL | TYMED_ISTREAM);
1180 hr = IDataObject_GetData(get, &fmt, &med);
1181 ok(hr == S_OK, "got %08x\n", hr);
1182 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1183 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1185 InitFormatEtc(fmt, cf_storage, 0xffff);
1186 hr = IDataObject_GetData(get, &fmt, &med);
1187 ok(hr == S_OK, "got %08x\n", hr);
1188 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1189 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1191 /* complex format with target device */
1193 InitFormatEtc(fmt, cf_another, 0xffff);
1194 hr = IDataObject_GetData(get, &fmt, &med);
1195 ok(hr == DV_E_FORMATETC ||
1196 broken(hr == S_OK), /* win9x, winme & nt4 */
1198 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1200 InitFormatEtc(fmt, cf_another, 0xffff);
1201 memset(&dm, 0, sizeof(dm));
1202 dm.dmSize = sizeof(dm);
1203 dm.dmDriverExtra = 0;
1204 lstrcpyW(dm.dmDeviceName, device_name);
1205 fmt.ptd = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra);
1206 fmt.ptd->tdSize = FIELD_OFFSET(DVTARGETDEVICE, tdData) + sizeof(device_name) + dm.dmSize + dm.dmDriverExtra;
1207 fmt.ptd->tdDriverNameOffset = FIELD_OFFSET(DVTARGETDEVICE, tdData);
1208 fmt.ptd->tdDeviceNameOffset = 0;
1209 fmt.ptd->tdPortNameOffset = 0;
1210 fmt.ptd->tdExtDevmodeOffset = fmt.ptd->tdDriverNameOffset + sizeof(device_name);
1211 lstrcpyW((WCHAR*)fmt.ptd->tdData, device_name);
1212 memcpy(fmt.ptd->tdData + sizeof(device_name), &dm, dm.dmSize + dm.dmDriverExtra);
1214 hr = IDataObject_GetData(get, &fmt, &med);
1215 ok(hr == S_OK, "got %08x\n", hr);
1216 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1217 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1219 HeapFree(GetProcessHeap(), 0, fmt.ptd);
1222 IDataObject_Release(get);
1223 IDataObject_Release(src);
1227 static HGLOBAL create_text(void)
1229 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 5);
1230 char *p = GlobalLock(h);
1236 static HENHMETAFILE create_emf(void)
1238 const RECT rect = {0, 0, 100, 100};
1239 HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
1240 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
1241 return CloseEnhMetaFile(hdc);
1244 static void test_nonole_clipboard(void)
1249 IEnumFORMATETC *enum_fmt;
1251 HGLOBAL h, hblob, htext;
1256 r = OpenClipboard(NULL);
1257 ok(r, "gle %d\n", GetLastError());
1258 r = EmptyClipboard();
1259 ok(r, "gle %d\n", GetLastError());
1260 r = CloseClipboard();
1261 ok(r, "gle %d\n", GetLastError());
1263 OleInitialize(NULL);
1265 /* empty clipboard */
1266 hr = OleGetClipboard(&get);
1267 ok(hr == S_OK, "got %08x\n", hr);
1268 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1269 ok(hr == S_OK, "got %08x\n", hr);
1271 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1272 ok(hr == S_FALSE, "got %08x\n", hr);
1273 IEnumFORMATETC_Release(enum_fmt);
1275 IDataObject_Release(get);
1277 /* set a user defined clipboard type */
1279 htext = create_text();
1280 hblob = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, 10);
1283 r = OpenClipboard(NULL);
1284 ok(r, "gle %d\n", GetLastError());
1285 h = SetClipboardData(CF_TEXT, htext);
1286 ok(h == htext, "got %p\n", h);
1287 h = SetClipboardData(cf_onemore, hblob);
1288 ok(h == hblob, "got %p\n", h);
1289 h = SetClipboardData(CF_ENHMETAFILE, emf);
1290 ok(h == emf, "got %p\n", h);
1291 r = CloseClipboard();
1292 ok(r, "gle %d\n", GetLastError());
1294 hr = OleGetClipboard(&get);
1295 ok(hr == S_OK, "got %08x\n", hr);
1296 hr = IDataObject_EnumFormatEtc(get, DATADIR_GET, &enum_fmt);
1297 ok(hr == S_OK, "got %08x\n", hr);
1299 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1300 ok(hr == S_OK, "got %08x\n", hr);
1301 ok(fmt.cfFormat == CF_TEXT, "cf %04x\n", fmt.cfFormat);
1302 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1303 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1304 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1305 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1307 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1308 ok(hr == S_OK, "got %08x\n", hr);
1309 ok(fmt.cfFormat == cf_onemore, "cf %04x\n", fmt.cfFormat);
1310 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1311 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1312 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1313 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1315 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1316 ok(hr == S_OK, "got %08x\n", hr);
1317 ok(fmt.cfFormat == CF_ENHMETAFILE, "cf %04x\n", fmt.cfFormat);
1318 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1319 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1320 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1321 ok(fmt.tymed == TYMED_ENHMF, "tymed %x\n", fmt.tymed);
1323 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1324 ok(hr == S_OK, "got %08x\n", hr); /* User32 adds some synthesised formats */
1326 todo_wine ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
1327 if(fmt.cfFormat == CF_LOCALE)
1329 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1330 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1331 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1332 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1334 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1335 ok(hr == S_OK, "got %08x\n", hr);
1338 ok(fmt.cfFormat == CF_OEMTEXT, "cf %04x\n", fmt.cfFormat);
1339 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1340 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1341 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1342 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1344 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1345 ok(hr == S_OK, "got %08x\n", hr);
1346 ok(fmt.cfFormat == CF_UNICODETEXT ||
1347 broken(fmt.cfFormat == CF_METAFILEPICT), /* win9x and winme don't have CF_UNICODETEXT */
1348 "cf %04x\n", fmt.cfFormat);
1349 if(fmt.cfFormat == CF_UNICODETEXT)
1351 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1352 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1353 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1354 ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
1356 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1357 ok(hr == S_OK, "got %08x\n", hr);
1359 ok(fmt.cfFormat == CF_METAFILEPICT, "cf %04x\n", fmt.cfFormat);
1360 ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
1361 ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
1362 ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
1363 ok(fmt.tymed == TYMED_MFPICT, "tymed %x\n", fmt.tymed);
1365 hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
1366 ok(hr == S_FALSE, "got %08x\n", hr);
1367 IEnumFORMATETC_Release(enum_fmt);
1369 InitFormatEtc(fmt, CF_ENHMETAFILE, TYMED_ENHMF);
1370 hr = IDataObject_GetData(get, &fmt, &med);
1371 ok(hr == S_OK, "got %08x\n", hr);
1372 obj_type = GetObjectType(U(med).hEnhMetaFile);
1373 ok(obj_type == OBJ_ENHMETAFILE, "got %d\n", obj_type);
1374 if(SUCCEEDED(hr)) ReleaseStgMedium(&med);
1376 IDataObject_Release(get);
1378 r = OpenClipboard(NULL);
1379 ok(r, "gle %d\n", GetLastError());
1380 r = EmptyClipboard();
1381 ok(r, "gle %d\n", GetLastError());
1382 r = CloseClipboard();
1383 ok(r, "gle %d\n", GetLastError());
1388 static void test_getdatahere(void)
1391 IDataObject *src, *get;
1395 OleInitialize(NULL);
1397 hr = DataObjectImpl_CreateComplex(&src);
1398 ok(hr == S_OK, "got %08x\n", hr);
1400 hr = OleSetClipboard(src);
1401 ok(hr == S_OK, "got %08x\n", hr);
1403 hr = OleGetClipboard(&get);
1404 ok(hr == S_OK, "got %08x\n", hr);
1406 /* global format -> global & stream */
1408 DataObjectImpl_GetData_calls = 0;
1409 DataObjectImpl_GetDataHere_calls = 0;
1411 InitFormatEtc(fmt, CF_TEXT, TYMED_HGLOBAL);
1413 med.pUnkForRelease = NULL;
1414 med.tymed = TYMED_HGLOBAL;
1415 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1416 hr = IDataObject_GetDataHere(get, &fmt, &med);
1417 ok(hr == S_OK, "got %08x\n", hr);
1418 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1419 ReleaseStgMedium(&med);
1420 ok(DataObjectImpl_GetDataHere_calls == 1, "called %d\n", DataObjectImpl_GetDataHere_calls);
1421 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1423 InitFormatEtc(fmt, CF_TEXT, 0);
1425 med.pUnkForRelease = NULL;
1426 med.tymed = TYMED_HGLOBAL;
1427 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1428 hr = IDataObject_GetDataHere(get, &fmt, &med);
1429 ok(hr == S_OK, "got %08x\n", hr);
1430 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1431 ReleaseStgMedium(&med);
1432 ok(DataObjectImpl_GetDataHere_calls == 2, "called %d\n", DataObjectImpl_GetDataHere_calls);
1433 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1435 med.pUnkForRelease = NULL;
1436 med.tymed = TYMED_HGLOBAL;
1437 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 1);
1438 hr = IDataObject_GetDataHere(get, &fmt, &med);
1439 ok(hr == E_FAIL, "got %08x\n", hr);
1440 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1441 ReleaseStgMedium(&med);
1442 ok(DataObjectImpl_GetDataHere_calls == 3, "called %d\n", DataObjectImpl_GetDataHere_calls);
1443 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1445 med.pUnkForRelease = NULL;
1446 med.tymed = TYMED_ISTREAM;
1447 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1448 hr = IDataObject_GetDataHere(get, &fmt, &med);
1449 ok(hr == S_OK, "got %08x\n", hr);
1450 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1451 ReleaseStgMedium(&med);
1452 ok(DataObjectImpl_GetDataHere_calls == 4, "called %d\n", DataObjectImpl_GetDataHere_calls);
1453 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1455 med.pUnkForRelease = NULL;
1456 med.tymed = TYMED_ISTORAGE;
1457 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1458 hr = IDataObject_GetDataHere(get, &fmt, &med);
1459 ok(hr == E_FAIL, "got %08x\n", hr);
1460 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1461 ReleaseStgMedium(&med);
1462 ok(DataObjectImpl_GetDataHere_calls == 5, "called %d\n", DataObjectImpl_GetDataHere_calls);
1463 ok(DataObjectImpl_GetData_calls == 1, "called %d\n", DataObjectImpl_GetData_calls);
1465 InitFormatEtc(fmt, cf_stream, 0);
1467 med.pUnkForRelease = NULL;
1468 med.tymed = TYMED_HGLOBAL;
1469 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 100);
1470 hr = IDataObject_GetDataHere(get, &fmt, &med);
1471 ok(hr == S_OK, "got %08x\n", hr);
1472 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1473 ReleaseStgMedium(&med);
1474 ok(DataObjectImpl_GetDataHere_calls == 7, "called %d\n", DataObjectImpl_GetDataHere_calls);
1475 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1477 med.pUnkForRelease = NULL;
1478 med.tymed = TYMED_ISTREAM;
1479 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1480 hr = IDataObject_GetDataHere(get, &fmt, &med);
1481 ok(hr == S_OK, "got %08x\n", hr);
1482 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1483 ReleaseStgMedium(&med);
1484 ok(DataObjectImpl_GetDataHere_calls == 8, "called %d\n", DataObjectImpl_GetDataHere_calls);
1485 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1487 med.pUnkForRelease = NULL;
1488 med.tymed = TYMED_ISTORAGE;
1489 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1490 hr = IDataObject_GetDataHere(get, &fmt, &med);
1491 ok(hr == E_FAIL, "got %08x\n", hr);
1492 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1493 ReleaseStgMedium(&med);
1494 ok(DataObjectImpl_GetDataHere_calls == 9, "called %d\n", DataObjectImpl_GetDataHere_calls);
1495 ok(DataObjectImpl_GetData_calls == 2, "called %d\n", DataObjectImpl_GetData_calls);
1497 InitFormatEtc(fmt, cf_storage, 0);
1499 med.pUnkForRelease = NULL;
1500 med.tymed = TYMED_HGLOBAL;
1501 U(med).hGlobal = GlobalAlloc(GMEM_MOVEABLE, 3000);
1502 hr = IDataObject_GetDataHere(get, &fmt, &med);
1503 ok(hr == S_OK, "got %08x\n", hr);
1504 ok(med.tymed == TYMED_HGLOBAL, "got %x\n", med.tymed);
1505 ReleaseStgMedium(&med);
1506 ok(DataObjectImpl_GetDataHere_calls == 11, "called %d\n", DataObjectImpl_GetDataHere_calls);
1507 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1509 med.pUnkForRelease = NULL;
1510 med.tymed = TYMED_ISTREAM;
1511 CreateStreamOnHGlobal(NULL, TRUE, &U(med).pstm);
1512 hr = IDataObject_GetDataHere(get, &fmt, &med);
1513 ok(hr == S_OK, "got %08x\n", hr);
1514 ok(med.tymed == TYMED_ISTREAM, "got %x\n", med.tymed);
1515 ReleaseStgMedium(&med);
1516 ok(DataObjectImpl_GetDataHere_calls == 12, "called %d\n", DataObjectImpl_GetDataHere_calls);
1517 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1519 med.pUnkForRelease = NULL;
1520 med.tymed = TYMED_ISTORAGE;
1521 StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &U(med).pstg);
1522 hr = IDataObject_GetDataHere(get, &fmt, &med);
1523 ok(hr == S_OK, "got %08x\n", hr);
1524 ok(med.tymed == TYMED_ISTORAGE, "got %x\n", med.tymed);
1525 ReleaseStgMedium(&med);
1526 ok(DataObjectImpl_GetDataHere_calls == 13, "called %d\n", DataObjectImpl_GetDataHere_calls);
1527 ok(DataObjectImpl_GetData_calls == 3, "called %d\n", DataObjectImpl_GetData_calls);
1530 IDataObject_Release(get);
1531 IDataObject_Release(src);
1537 START_TEST(clipboard)
1539 test_set_clipboard();
1540 test_consumer_refs();
1541 test_flushed_getdata();
1542 test_nonole_clipboard();