Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457/* * PROJECT: ReactOS api tests * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Test for SHCreateDataObject * COPYRIGHT: Copyright 2019 Mark Jansen <mark.jansen@reactos.org> */
#include "shelltest.h"#include <ndk/rtlfuncs.h>#include <stdio.h>#include <shellutils.h>#include <shlwapi.h>
static DWORD g_WinVersion;
typedef HRESULT (WINAPI *tSHCreateDataObject)(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, IDataObject *pdtInner, REFIID riid, void **ppv);static tSHCreateDataObject pSHCreateDataObject;
static void TestAdviseAndCanonical(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUIDLIST_RELATIVE_ARRAY apidl){ CComPtr<IDataObject> spDataObj; HRESULT hr = pSHCreateDataObject(pidlFolder, cidl, apidl, NULL, IID_PPV_ARG(IDataObject, &spDataObj));
ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
hr = spDataObj->DAdvise(NULL, 0, NULL, NULL); ok_hex(hr, OLE_E_ADVISENOTSUPPORTED);
hr = spDataObj->DUnadvise(0); ok_hex(hr, OLE_E_ADVISENOTSUPPORTED);
hr = spDataObj->EnumDAdvise(NULL); ok_hex(hr, OLE_E_ADVISENOTSUPPORTED);
FORMATETC in = {1, (DVTARGETDEVICE*)2, 3, 4, 5}; FORMATETC out = {6, (DVTARGETDEVICE*)7, 8, 9, 10};
hr = spDataObj->GetCanonicalFormatEtc(&in, &out); ok_hex(hr, DATA_S_SAMEFORMATETC);
if (g_WinVersion < _WIN32_WINNT_VISTA) { ok_int(out.cfFormat, 6); ok_ptr(out.ptd, (void*)7); ok_int(out.dwAspect, 8); ok_int(out.lindex, 9); ok_int(out.tymed, 10); trace("out unmodified\n"); } else { ok_int(out.cfFormat, in.cfFormat); ok_ptr(out.ptd, NULL); ok_int(out.dwAspect, (int)in.dwAspect); ok_int(out.lindex, in.lindex); ok_int(out.tymed, (int)in.tymed); trace("in copied to out\n"); }}
#define ok_wstri(x, y) \ ok(_wcsicmp(x, y) == 0, "Wrong string. Expected '%S', got '%S'\n", y, x)
static void TestHIDA(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR ExpectPath1, LPCWSTR ExpectPath2){ LPIDA pida = (LPIDA)pData;
ok_int(pida->cidl, 2); if (pida->cidl != 2) return;
WCHAR FolderPath[MAX_PATH], Item1[MAX_PATH], Item2[MAX_PATH]; BOOL bRet = SHGetPathFromIDListW(HIDA_GetPIDLFolder(pida), FolderPath); ok_int(bRet, TRUE); if (!bRet) return; ok_wstri(FolderPath, ExpectRoot);
CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl1(ILCombine(HIDA_GetPIDLFolder(pida), HIDA_GetPIDLItem(pida, 0))); CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl2(ILCombine(HIDA_GetPIDLFolder(pida), HIDA_GetPIDLItem(pida, 1)));
bRet = SHGetPathFromIDListW(pidl1, Item1); ok_int(bRet, TRUE); if (!bRet) return; ok_wstri(Item1, ExpectPath1);
bRet = SHGetPathFromIDListW(pidl2, Item2); ok_int(bRet, TRUE); if (!bRet) return; ok_wstri(Item2, ExpectPath2);}
static void TestHDROP(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR ExpectPath1, LPCWSTR ExpectPath2){ DROPFILES* pDropFiles = (DROPFILES*)pData; ok_int(pDropFiles->fWide, TRUE);
LPCWSTR Expected[2] = { ExpectPath1, ExpectPath2 };
SIZE_T offset = pDropFiles->pFiles; UINT Count = 0; for (;;Count++) { LPCWSTR ptr = (LPCWSTR)(((BYTE*)pDropFiles) + offset); if (!*ptr) break;
if (Count < _countof(Expected)) ok_wstri(Expected[Count], ptr);
offset += (wcslen(ptr) + 1) * sizeof(WCHAR); } ok_int(Count, 2);}
static void TestFilenameA(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR ExpectPath1, LPCWSTR ExpectPath2){ LPCSTR FirstFile = (LPCSTR)pData; LPWSTR FirstFileW;
HRESULT hr = SHStrDupA(FirstFile, &FirstFileW); ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
ok_wstri(ExpectPath1, FirstFileW); CoTaskMemFree(FirstFileW);}
static void TestFilenameW(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR ExpectPath1, LPCWSTR ExpectPath2){ LPCWSTR FirstFile = (LPCWSTR)pData; ok_wstri(ExpectPath1, FirstFile);}
static void TestDefaultFormat(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUIDLIST_RELATIVE_ARRAY apidl){ CComPtr<IDataObject> spDataObj; HRESULT hr = pSHCreateDataObject(pidlFolder, cidl, apidl, NULL, IID_PPV_ARG(IDataObject, &spDataObj));
ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
CComPtr<IEnumFORMATETC> pEnumFmt; hr = spDataObj->EnumFormatEtc(DATADIR_GET, &pEnumFmt);
ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
UINT Expected[4] = { RegisterClipboardFormatA(CFSTR_SHELLIDLISTA), CF_HDROP, RegisterClipboardFormatA(CFSTR_FILENAMEA), RegisterClipboardFormatA("FileNameW"), };
UINT Count = 0; FORMATETC fmt; while (S_OK == (hr=pEnumFmt->Next(1, &fmt, NULL))) { char szGot[512], szExpected[512]; GetClipboardFormatNameA(fmt.cfFormat, szGot, sizeof(szGot)); ok(Count < _countof(Expected), "%u\n", Count); if (Count < _countof(Expected)) { GetClipboardFormatNameA(Expected[Count], szExpected, sizeof(szExpected)); ok(fmt.cfFormat == Expected[Count], "Got 0x%x(%s), expected 0x%x(%s) for %u\n", fmt.cfFormat, szGot, Expected[Count], szExpected, Count); }
ok(fmt.ptd == NULL, "Got 0x%p, expected 0x%p for [%u].ptd\n", fmt.ptd, (void*)NULL, Count); ok(fmt.dwAspect == DVASPECT_CONTENT, "Got 0x%lu, expected 0x%d for [%u].dwAspect\n", fmt.dwAspect, DVASPECT_CONTENT, Count); ok(fmt.lindex == -1, "Got 0x%lx, expected 0x%x for [%u].lindex\n", fmt.lindex, -1, Count); ok(fmt.tymed == TYMED_HGLOBAL, "Got 0x%lu, expected 0x%d for [%u].tymed\n", fmt.tymed, TYMED_HGLOBAL, Count);
Count++; } trace("Got %u formats\n", Count); ULONG ExpectedCount = (g_WinVersion < _WIN32_WINNT_WIN8) ? 1 : 4; ok_int(Count, (int)ExpectedCount); ok_hex(hr, S_FALSE);
typedef void (*TestFunction)(PVOID pData, SIZE_T Size, LPCWSTR ExpectRoot, LPCWSTR ExpectPath1, LPCWSTR ExpectPath2); TestFunction TestFormats[] = { TestHIDA, TestHDROP, TestFilenameA, TestFilenameW, };
WCHAR ExpectRoot[MAX_PATH], ExpectItem1[MAX_PATH], ExpectItem2[MAX_PATH];
hr = SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, 0, ExpectRoot); ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
hr = SHGetFolderPathW(NULL, CSIDL_SYSTEM, NULL, 0, ExpectItem1); ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
hr = SHGetFolderPathW(NULL, CSIDL_RESOURCES, NULL, 0, ExpectItem2); ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
/* The formats are not synthesized on request */ for (Count = 0; Count < _countof(Expected); ++Count) { STGMEDIUM medium = {0}; FORMATETC etc = { (CLIPFORMAT)Expected[Count], NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; char szExpected[512];
GetClipboardFormatNameA(etc.cfFormat, szExpected, sizeof(szExpected)); hr = spDataObj->GetData(&etc, &medium); HRESULT hr2 = spDataObj->QueryGetData(&etc); ok_hex(hr2, SUCCEEDED(hr) ? S_OK : S_FALSE);
if (Count < ExpectedCount) { ok(hr == S_OK, "0x%x (0x%x(%s))\n", (unsigned int)hr, Expected[Count], szExpected); ok(medium.tymed == TYMED_HGLOBAL, "0x%lx (0x%x(%s))\n", medium.tymed, Expected[Count], szExpected); if (hr == S_OK && medium.tymed == TYMED_HGLOBAL) { PVOID pData = GlobalLock(medium.hGlobal); SIZE_T Size = GlobalSize(medium.hGlobal); TestFormats[Count](pData, Size, ExpectRoot, ExpectItem1, ExpectItem2); GlobalUnlock(medium.hGlobal); } } else { if (g_WinVersion < _WIN32_WINNT_VISTA) ok(hr == E_INVALIDARG, "0x%x (0x%x(%s))\n", (unsigned int)hr, Expected[Count], szExpected); else ok(hr == DV_E_FORMATETC, "0x%x (0x%x(%s))\n", (unsigned int)hr, Expected[Count], szExpected); }
if (SUCCEEDED(hr)) ReleaseStgMedium(&medium); }
CLIPFORMAT Format = RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECTW); FORMATETC formatetc = { Format, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM medium;
hr = spDataObj->GetData(&formatetc, &medium); if (g_WinVersion < _WIN32_WINNT_VISTA) ok_hex(hr, E_INVALIDARG); else ok_hex(hr, DV_E_FORMATETC);}
static void TestSetAndGetExtraFormat(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUIDLIST_RELATIVE_ARRAY apidl){ CComPtr<IDataObject> spDataObj; HRESULT hr = pSHCreateDataObject(pidlFolder, cidl, apidl, NULL, IID_PPV_ARG(IDataObject, &spDataObj));
ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
STGMEDIUM medium = {0}; medium.tymed = TYMED_HGLOBAL; medium.hGlobal = GlobalAlloc(GHND, sizeof(DWORD)); ok(medium.hGlobal != NULL, "Download more ram\n"); PDWORD data = (PDWORD)GlobalLock(medium.hGlobal); *data = 12345; GlobalUnlock(medium.hGlobal);
UINT flags = GlobalFlags(medium.hGlobal); SIZE_T size = GlobalSize(medium.hGlobal); ok_hex(flags, 0); ok_size_t(size, sizeof(DWORD));
FORMATETC etc = { (CLIPFORMAT)RegisterClipboardFormatA(CFSTR_INDRAGLOOPA), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; FORMATETC etc2 = etc;
/* Not supported! */ hr = spDataObj->SetData(&etc, &medium, FALSE); if (g_WinVersion < _WIN32_WINNT_WIN8) ok_hex(hr, E_INVALIDARG); else ok_hex(hr, E_NOTIMPL);
/* Object takes ownership! */ hr = spDataObj->SetData(&etc, &medium, TRUE); ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
/* Does not touch the hGlobal! */ flags = GlobalFlags(medium.hGlobal); size = GlobalSize(medium.hGlobal); ok_hex(flags, 0); ok_size_t(size, sizeof(DWORD));
STGMEDIUM medium2 = {0};
/* No conversion */ etc2.dwAspect = DVASPECT_DOCPRINT; hr = spDataObj->GetData(&etc2, &medium2); HRESULT hr2 = spDataObj->QueryGetData(&etc2); ok_hex(hr2, SUCCEEDED(hr) ? S_OK : S_FALSE); if (g_WinVersion < _WIN32_WINNT_VISTA) ok_hex(hr, E_INVALIDARG); else ok_hex(hr, DV_E_FORMATETC);
etc2.dwAspect = DVASPECT_CONTENT; etc2.tymed = TYMED_NULL; hr = spDataObj->GetData(&etc2, &medium2); hr2 = spDataObj->QueryGetData(&etc2); ok_hex(hr2, SUCCEEDED(hr) ? S_OK : S_FALSE); if (g_WinVersion < _WIN32_WINNT_VISTA) ok_hex(hr, E_INVALIDARG); else ok_hex(hr, DV_E_FORMATETC); etc2.tymed = TYMED_HGLOBAL;
ok_ptr(medium2.pUnkForRelease, NULL); hr = spDataObj->GetData(&etc2, &medium2); hr2 = spDataObj->QueryGetData(&etc2); ok_hex(hr2, SUCCEEDED(hr) ? S_OK : S_FALSE); ok_hex(hr, S_OK); if (hr == S_OK) { ok_hex(medium2.tymed, TYMED_HGLOBAL); if (g_WinVersion < _WIN32_WINNT_VISTA) { /* The IDataObject is set as pUnkForRelease */ ok(medium2.pUnkForRelease == (IUnknown*)spDataObj, "Expected the data object (0x%p), got 0x%p\n", (IUnknown*)spDataObj, medium2.pUnkForRelease); ok(medium.hGlobal == medium2.hGlobal, "Pointers are not the same!, got 0x%p and 0x%p\n", medium.hGlobal, medium2.hGlobal); } else { ok_ptr(medium2.pUnkForRelease, NULL); ok(medium.hGlobal != medium2.hGlobal, "Pointers are the same!\n"); }
flags = GlobalFlags(medium2.hGlobal); size = GlobalSize(medium2.hGlobal); ok_hex(flags, 0); ok_size_t(size, sizeof(DWORD));
data = (PDWORD)GlobalLock(medium2.hGlobal); if (data) ok_int(*data, 12345); else ok(0, "GlobalLock: %lu\n", GetLastError()); GlobalUnlock(medium2.hGlobal);
HGLOBAL backup = medium2.hGlobal; ReleaseStgMedium(&medium2);
flags = GlobalFlags(backup); size = GlobalSize(backup); if (g_WinVersion < _WIN32_WINNT_VISTA) { /* Same object! just the pUnkForRelease was set, so original hGlobal is still valid */ ok_hex(flags, 0); ok_size_t(size, sizeof(DWORD)); } else { ok_hex(flags, GMEM_INVALID_HANDLE); ok_size_t(size, 0); }
/* Original is still intact (but no longer ours!) */ flags = GlobalFlags(medium.hGlobal); size = GlobalSize(medium.hGlobal); ok_hex(flags, 0); ok_size_t(size, sizeof(DWORD)); }
HGLOBAL backup = medium.hGlobal; spDataObj.Release();
/* Now our hGlobal is deleted */ flags = GlobalFlags(backup); size = GlobalSize(backup); ok_hex(flags, GMEM_INVALID_HANDLE); ok_size_t(size, 0);}
START_TEST(SHCreateDataObject){ HRESULT hr;
pSHCreateDataObject = (tSHCreateDataObject)GetProcAddress(GetModuleHandleA("shell32.dll"), "SHCreateDataObject"); if (!pSHCreateDataObject) { skip("shell32!SHCreateDataObject not exported\n"); return; }
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
RTL_OSVERSIONINFOEXW rtlinfo = {0};
rtlinfo.dwOSVersionInfoSize = sizeof(rtlinfo); RtlGetVersion((PRTL_OSVERSIONINFOW)&rtlinfo); g_WinVersion = (rtlinfo.dwMajorVersion << 8) | rtlinfo.dwMinorVersion;
CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlWindows; CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlSystem32; CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlResources;
hr = SHGetFolderLocation(NULL, CSIDL_WINDOWS, NULL, 0, &pidlWindows); ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
hr = SHGetFolderLocation(NULL, CSIDL_SYSTEM, NULL, 0, &pidlSystem32); ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
hr = SHGetFolderLocation(NULL, CSIDL_RESOURCES, NULL, 0, &pidlResources); ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
CComPtr<IShellFolder> shellFolder; PCUITEMID_CHILD child1; hr = SHBindToParent(pidlSystem32, IID_PPV_ARG(IShellFolder, &shellFolder), &child1); ok_hex(hr, S_OK); if (!SUCCEEDED(hr)) return;
PCUITEMID_CHILD child2 = ILFindLastID(pidlResources);
UINT cidl = 2; PCUIDLIST_RELATIVE apidl[2] = { child1, child2 };
TestAdviseAndCanonical(pidlWindows, cidl, apidl); TestDefaultFormat(pidlWindows, cidl, apidl); TestSetAndGetExtraFormat(pidlWindows, cidl, apidl);}