mirror of
https://github.com/reactos/wine.git
synced 2024-11-25 12:49:45 +00:00
ole32/tests: Tests for the 'Ole Private Data' clipboard format.
This commit is contained in:
parent
3383db6107
commit
b75caee2ab
@ -45,6 +45,8 @@ typedef struct DataObjectImpl {
|
||||
UINT fmtetc_cnt;
|
||||
|
||||
HANDLE text;
|
||||
IStream *stm;
|
||||
IStorage *stg;
|
||||
} DataObjectImpl;
|
||||
|
||||
typedef struct EnumFormatImpl {
|
||||
@ -60,6 +62,8 @@ typedef struct EnumFormatImpl {
|
||||
static BOOL expect_DataObjectImpl_QueryGetData = TRUE;
|
||||
static ULONG DataObjectImpl_GetData_calls = 0;
|
||||
|
||||
static UINT cf_stream, cf_storage, cf_another, cf_onemore;
|
||||
|
||||
static HRESULT EnumFormatImpl_Create(FORMATETC *fmtetc, UINT size, LPENUMFORMATETC *lplpformatetc);
|
||||
|
||||
static HRESULT WINAPI EnumFormatImpl_QueryInterface(IEnumFORMATETC *iface, REFIID riid, LPVOID *ppvObj)
|
||||
@ -99,15 +103,21 @@ static HRESULT WINAPI EnumFormatImpl_Next(IEnumFORMATETC *iface, ULONG celt,
|
||||
FORMATETC *rgelt, ULONG *pceltFetched)
|
||||
{
|
||||
EnumFormatImpl *This = (EnumFormatImpl*)iface;
|
||||
ULONG count = 0;
|
||||
ULONG count, i;
|
||||
|
||||
if(!rgelt)
|
||||
return E_INVALIDARG;
|
||||
|
||||
count = min(celt, This->fmtetc_cnt - This->cur);
|
||||
if(count > 0) {
|
||||
memcpy(rgelt, This->fmtetc+This->cur, count*sizeof(FORMATETC));
|
||||
This->cur += count;
|
||||
for(i = 0; i < count; i++, This->cur++, rgelt++)
|
||||
{
|
||||
*rgelt = This->fmtetc[This->cur];
|
||||
if(rgelt->ptd)
|
||||
{
|
||||
DWORD size = This->fmtetc[This->cur].ptd->tdSize;
|
||||
rgelt->ptd = CoTaskMemAlloc(size);
|
||||
memcpy(rgelt->ptd, This->fmtetc[This->cur].ptd, size);
|
||||
}
|
||||
}
|
||||
if(pceltFetched)
|
||||
*pceltFetched = count;
|
||||
@ -184,9 +194,15 @@ static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
|
||||
DataObjectImpl *This = (DataObjectImpl*)iface;
|
||||
ULONG ref = InterlockedDecrement(&This->ref);
|
||||
|
||||
if(!ref) {
|
||||
if(!ref)
|
||||
{
|
||||
int i;
|
||||
if(This->text) GlobalFree(This->text);
|
||||
if(This->fmtetc) GlobalFree(This->fmtetc);
|
||||
for(i = 0; i < This->fmtetc_cnt; i++)
|
||||
HeapFree(GetProcessHeap(), 0, This->fmtetc[i].ptd);
|
||||
HeapFree(GetProcessHeap(), 0, This->fmtetc);
|
||||
if(This->stm) IStream_Release(This->stm);
|
||||
if(This->stg) IStorage_Release(This->stg);
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
}
|
||||
|
||||
@ -196,25 +212,37 @@ static ULONG WINAPI DataObjectImpl_Release(IDataObject* iface)
|
||||
static HRESULT WINAPI DataObjectImpl_GetData(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
|
||||
{
|
||||
DataObjectImpl *This = (DataObjectImpl*)iface;
|
||||
UINT i;
|
||||
BOOL foundFormat = FALSE;
|
||||
|
||||
DataObjectImpl_GetData_calls++;
|
||||
|
||||
if(pformatetc->lindex != -1)
|
||||
return DV_E_FORMATETC;
|
||||
|
||||
if(!(pformatetc->tymed & TYMED_HGLOBAL))
|
||||
return DV_E_TYMED;
|
||||
|
||||
if(This->text && pformatetc->cfFormat == CF_TEXT)
|
||||
U(*pmedium).hGlobal = This->text;
|
||||
else
|
||||
return DV_E_FORMATETC;
|
||||
|
||||
pmedium->tymed = TYMED_HGLOBAL;
|
||||
for(i = 0; i < This->fmtetc_cnt; i++)
|
||||
{
|
||||
if(This->fmtetc[i].cfFormat == pformatetc->cfFormat)
|
||||
{
|
||||
foundFormat = TRUE;
|
||||
if(This->fmtetc[i].tymed & pformatetc->tymed)
|
||||
{
|
||||
pmedium->pUnkForRelease = (LPUNKNOWN)iface;
|
||||
IUnknown_AddRef(pmedium->pUnkForRelease);
|
||||
|
||||
if(pformatetc->cfFormat == CF_TEXT)
|
||||
U(*pmedium).hGlobal = This->text;
|
||||
else if(pformatetc->cfFormat == cf_stream)
|
||||
U(*pmedium).pstm = This->stm;
|
||||
else if(pformatetc->cfFormat == cf_storage)
|
||||
U(*pmedium).pstg = This->stg;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return foundFormat ? DV_E_TYMED : DV_E_FORMATETC;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI DataObjectImpl_GetDataHere(IDataObject* iface, FORMATETC *pformatetc, STGMEDIUM *pmedium)
|
||||
{
|
||||
@ -315,6 +343,8 @@ static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj)
|
||||
obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1);
|
||||
strcpy(GlobalLock(obj->text), text);
|
||||
GlobalUnlock(obj->text);
|
||||
obj->stm = NULL;
|
||||
obj->stg = NULL;
|
||||
|
||||
obj->fmtetc_cnt = 1;
|
||||
obj->fmtetc = HeapAlloc(GetProcessHeap(), 0, obj->fmtetc_cnt*sizeof(FORMATETC));
|
||||
@ -324,6 +354,55 @@ static HRESULT DataObjectImpl_CreateText(LPCSTR text, LPDATAOBJECT *lplpdataobj)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT DataObjectImpl_CreateComplex(LPDATAOBJECT *lplpdataobj)
|
||||
{
|
||||
DataObjectImpl *obj;
|
||||
const char *stm_data = "complex stream";
|
||||
const char *text_data = "complex text";
|
||||
ILockBytes *lbs;
|
||||
static const WCHAR devname[] = {'m','y','d','e','v',0};
|
||||
DEVMODEW dm;
|
||||
|
||||
obj = HeapAlloc(GetProcessHeap(), 0, sizeof(DataObjectImpl));
|
||||
obj->lpVtbl = &VT_DataObjectImpl;
|
||||
obj->ref = 1;
|
||||
obj->text = GlobalAlloc(GMEM_MOVEABLE, strlen(text_data) + 1);
|
||||
strcpy(GlobalLock(obj->text), text_data);
|
||||
GlobalUnlock(obj->text);
|
||||
CreateStreamOnHGlobal(NULL, TRUE, &obj->stm);
|
||||
IStream_Write(obj->stm, stm_data, strlen(stm_data), NULL);
|
||||
|
||||
CreateILockBytesOnHGlobal(NULL, TRUE, &lbs);
|
||||
StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &obj->stg);
|
||||
ILockBytes_Release(lbs);
|
||||
|
||||
obj->fmtetc_cnt = 5;
|
||||
/* zeroing here since FORMATETC has a hole in it, and it's confusing to have this uninitialised. */
|
||||
obj->fmtetc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, obj->fmtetc_cnt*sizeof(FORMATETC));
|
||||
InitFormatEtc(obj->fmtetc[0], CF_TEXT, TYMED_HGLOBAL);
|
||||
InitFormatEtc(obj->fmtetc[1], cf_stream, TYMED_ISTREAM);
|
||||
InitFormatEtc(obj->fmtetc[2], cf_storage, TYMED_ISTORAGE);
|
||||
InitFormatEtc(obj->fmtetc[3], cf_another, TYMED_ISTORAGE|TYMED_ISTREAM|TYMED_HGLOBAL);
|
||||
memset(&dm, 0, sizeof(dm));
|
||||
dm.dmSize = sizeof(dm);
|
||||
dm.dmDriverExtra = 0;
|
||||
lstrcpyW(dm.dmDeviceName, devname);
|
||||
obj->fmtetc[3].ptd = HeapAlloc(GetProcessHeap(), 0, sizeof(DVTARGETDEVICE) + sizeof(devname) + dm.dmSize + dm.dmDriverExtra);
|
||||
obj->fmtetc[3].ptd->tdSize = sizeof(DVTARGETDEVICE) + sizeof(devname) + dm.dmSize + dm.dmDriverExtra;
|
||||
obj->fmtetc[3].ptd->tdDriverNameOffset = sizeof(DVTARGETDEVICE);
|
||||
obj->fmtetc[3].ptd->tdDeviceNameOffset = 0;
|
||||
obj->fmtetc[3].ptd->tdPortNameOffset = 0;
|
||||
obj->fmtetc[3].ptd->tdExtDevmodeOffset = sizeof(DVTARGETDEVICE) + sizeof(devname);
|
||||
lstrcpyW((WCHAR*)obj->fmtetc[3].ptd->tdData, devname);
|
||||
memcpy(obj->fmtetc[3].ptd->tdData + sizeof(devname), &dm, dm.dmSize + dm.dmDriverExtra);
|
||||
|
||||
InitFormatEtc(obj->fmtetc[4], cf_stream, 0xfffff);
|
||||
obj->fmtetc[4].dwAspect = DVASPECT_ICON;
|
||||
|
||||
*lplpdataobj = (LPDATAOBJECT)obj;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void test_get_clipboard(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
@ -423,11 +502,12 @@ static void test_get_clipboard(void)
|
||||
IDataObject_Release(data_obj);
|
||||
}
|
||||
|
||||
static void test_cf_dataobject(BOOL dataobject_active)
|
||||
static void test_cf_dataobject(IDataObject *data)
|
||||
{
|
||||
UINT cf = 0;
|
||||
UINT cf_dataobject = RegisterClipboardFormatA("DataObject");
|
||||
BOOL found_dataobject = FALSE;
|
||||
UINT cf_ole_priv_data = RegisterClipboardFormatA("Ole Private Data");
|
||||
BOOL found_dataobject = FALSE, found_priv_data = FALSE;
|
||||
|
||||
OpenClipboard(NULL);
|
||||
do
|
||||
@ -442,28 +522,125 @@ static void test_cf_dataobject(BOOL dataobject_active)
|
||||
|
||||
found_dataobject = TRUE;
|
||||
ok(size >= sizeof(*ptr), "size %d\n", size);
|
||||
if(dataobject_active)
|
||||
if(data)
|
||||
ok(*ptr == clip_owner, "hwnd %p clip_owner %p\n", *ptr, clip_owner);
|
||||
else /* ole clipboard flushed */
|
||||
ok(*ptr == NULL, "hwnd %p\n", *ptr);
|
||||
GlobalUnlock(h);
|
||||
}
|
||||
else if(cf == cf_ole_priv_data)
|
||||
{
|
||||
found_priv_data = TRUE;
|
||||
if(data)
|
||||
{
|
||||
HGLOBAL h = GetClipboardData(cf);
|
||||
DWORD *ptr = GlobalLock(h);
|
||||
DWORD size = GlobalSize(h);
|
||||
|
||||
if(size != ptr[1])
|
||||
win_skip("Ole Private Data in win9x format\n");
|
||||
else
|
||||
{
|
||||
HRESULT hr;
|
||||
IEnumFORMATETC *enum_fmt;
|
||||
DWORD count = 0;
|
||||
FORMATETC fmt;
|
||||
struct formatetcetc
|
||||
{
|
||||
FORMATETC fmt;
|
||||
BOOL first_use_of_cf;
|
||||
DWORD res[2];
|
||||
} *fmt_ptr;
|
||||
struct priv_data
|
||||
{
|
||||
DWORD res1;
|
||||
DWORD size;
|
||||
DWORD res2;
|
||||
DWORD count;
|
||||
DWORD res3[2];
|
||||
struct formatetcetc fmts[1];
|
||||
} *priv = (struct priv_data*)ptr;
|
||||
CLIPFORMAT cfs_seen[10];
|
||||
|
||||
hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
|
||||
ok(hr == S_OK, "got %08x\n", hr);
|
||||
fmt_ptr = priv->fmts;
|
||||
|
||||
while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
|
||||
{
|
||||
int i;
|
||||
BOOL seen_cf = FALSE;
|
||||
|
||||
ok(fmt_ptr->fmt.cfFormat == fmt.cfFormat,
|
||||
"got %08x expected %08x\n", fmt_ptr->fmt.cfFormat, fmt.cfFormat);
|
||||
ok(fmt_ptr->fmt.dwAspect == fmt.dwAspect, "got %08x expected %08x\n",
|
||||
fmt_ptr->fmt.dwAspect, fmt.dwAspect);
|
||||
ok(fmt_ptr->fmt.lindex == fmt.lindex, "got %08x expected %08x\n",
|
||||
fmt_ptr->fmt.lindex, fmt.lindex);
|
||||
ok(fmt_ptr->fmt.tymed == fmt.tymed, "got %08x expected %08x\n",
|
||||
fmt_ptr->fmt.tymed, fmt.tymed);
|
||||
for(i = 0; i < count; i++)
|
||||
if(fmt_ptr->fmt.cfFormat == cfs_seen[i])
|
||||
{
|
||||
seen_cf = TRUE;
|
||||
break;
|
||||
}
|
||||
cfs_seen[count] = fmt.cfFormat;
|
||||
ok(fmt_ptr->first_use_of_cf == seen_cf ? FALSE : TRUE, "got %08x expected %08x\n",
|
||||
fmt_ptr->first_use_of_cf, !seen_cf);
|
||||
ok(fmt_ptr->res[0] == 0, "got %08x\n", fmt_ptr->res[1]);
|
||||
ok(fmt_ptr->res[1] == 0, "got %08x\n", fmt_ptr->res[2]);
|
||||
if(fmt.ptd)
|
||||
{
|
||||
DVTARGETDEVICE *target;
|
||||
|
||||
ok(fmt_ptr->fmt.ptd != NULL, "target device offset zero\n");
|
||||
target = (DVTARGETDEVICE*)((char*)priv + (DWORD)fmt_ptr->fmt.ptd);
|
||||
ok(!memcmp(target, fmt.ptd, fmt.ptd->tdSize), "target devices differ\n");
|
||||
CoTaskMemFree(fmt.ptd);
|
||||
}
|
||||
fmt_ptr++;
|
||||
count++;
|
||||
}
|
||||
ok(priv->res1 == 0, "got %08x\n", priv->res1);
|
||||
ok(priv->res2 == 1, "got %08x\n", priv->res2);
|
||||
ok(priv->count == count, "got %08x expected %08x\n", priv->count, count);
|
||||
ok(priv->res3[0] == 0, "got %08x\n", priv->res3[0]);
|
||||
ok(priv->res3[1] == 0, "got %08x\n", priv->res3[1]);
|
||||
|
||||
GlobalUnlock(h);
|
||||
IEnumFORMATETC_Release(enum_fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(cf);
|
||||
CloseClipboard();
|
||||
ok(found_dataobject, "didn't find cf_dataobject\n");
|
||||
todo_wine
|
||||
ok(found_priv_data, "didn't find cf_ole_priv_data\n");
|
||||
}
|
||||
|
||||
static void test_set_clipboard(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
ULONG ref;
|
||||
LPDATAOBJECT data1, data2;
|
||||
LPDATAOBJECT data1, data2, data_cmpl;
|
||||
|
||||
cf_stream = RegisterClipboardFormatA("stream format");
|
||||
cf_storage = RegisterClipboardFormatA("storage format");
|
||||
cf_another = RegisterClipboardFormatA("another format");
|
||||
cf_onemore = RegisterClipboardFormatA("one more format");
|
||||
|
||||
hr = DataObjectImpl_CreateText("data1", &data1);
|
||||
ok(SUCCEEDED(hr), "Failed to create data1 object: 0x%08x\n", hr);
|
||||
if(FAILED(hr))
|
||||
return;
|
||||
hr = DataObjectImpl_CreateText("data2", &data2);
|
||||
ok(SUCCEEDED(hr), "Failed to create data2 object: 0x%08x\n", hr);
|
||||
if(FAILED(hr))
|
||||
return;
|
||||
hr = DataObjectImpl_CreateComplex(&data_cmpl);
|
||||
ok(SUCCEEDED(hr), "Failed to create complex data object: 0x%08x\n", hr);
|
||||
if(FAILED(hr))
|
||||
return;
|
||||
|
||||
@ -484,7 +661,7 @@ static void test_set_clipboard(void)
|
||||
hr = OleSetClipboard(data1);
|
||||
ok(hr == S_OK, "failed to set clipboard to data1, hr = 0x%08x\n", hr);
|
||||
|
||||
test_cf_dataobject(TRUE);
|
||||
test_cf_dataobject(data1);
|
||||
|
||||
hr = OleIsCurrentClipboard(data1);
|
||||
ok(hr == S_OK, "expected current clipboard to be data1, hr = 0x%08x\n", hr);
|
||||
@ -513,7 +690,13 @@ static void test_set_clipboard(void)
|
||||
hr = OleIsCurrentClipboard(NULL);
|
||||
ok(hr == S_FALSE, "expect S_FALSE, hr = 0x%08x\n", hr);
|
||||
|
||||
test_cf_dataobject(FALSE);
|
||||
test_cf_dataobject(NULL);
|
||||
|
||||
ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
|
||||
|
||||
hr = OleSetClipboard(data_cmpl);
|
||||
ok(hr == S_OK, "failed to set clipboard to complex data, hr = 0x%08x\n", hr);
|
||||
test_cf_dataobject(data_cmpl);
|
||||
|
||||
ok(OleSetClipboard(NULL) == S_OK, "failed to clear clipboard, hr = 0x%08x\n", hr);
|
||||
|
||||
@ -521,6 +704,8 @@ static void test_set_clipboard(void)
|
||||
ok(ref == 0, "expected data1 ref=0, got %d\n", ref);
|
||||
ref = IDataObject_Release(data2);
|
||||
ok(ref == 0, "expected data2 ref=0, got %d\n", ref);
|
||||
ref = IDataObject_Release(data_cmpl);
|
||||
ok(ref == 0, "expected data_cmpl ref=0, got %d\n", ref);
|
||||
|
||||
OleUninitialize();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user