Something went wrong. Try again.
Reactos
Something went wrong. Try again.
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334/* * PROJECT: ReactOS api tests * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Test for SHGetAttributesFromDataObject * COPYRIGHT: Copyright 2021 Mark Jansen <mark.jansen@reactos.org> */
#include "shelltest.h"#include <ndk/rtlfuncs.h>#include <stdio.h>#include <shellutils.h>#include <shlwapi.h>
static CLIPFORMAT g_DataObjectAttributes = 0;static const DWORD dwDefaultAttributeMask = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_STORAGE | SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_READONLY | SFGAO_STREAM | SFGAO_FOLDER;static_assert(dwDefaultAttributeMask == 0x2044003B, "Unexpected default attribute mask");static const DWORD dwDefaultAttributeMask_WS03 = dwDefaultAttributeMask | SFGAO_FILESYSTEM | SFGAO_CAPABILITYMASK;static_assert(dwDefaultAttributeMask_WS03 == 0x6044017F, "Unexpected default attribute mask for WS03, Vista");
struct TmpFile{ WCHAR Buffer[MAX_PATH] = {};
void Create(LPCWSTR Folder) { GetTempFileNameW(Folder, L"SHG", 0, Buffer); }
~TmpFile() { if (Buffer[0]) { SetFileAttributesW(Buffer, FILE_ATTRIBUTE_NORMAL); DeleteFileW(Buffer); } }};
CComPtr<IShellFolder> _BindToObject(PCUIDLIST_ABSOLUTE pidl){ CComPtr<IShellFolder> spDesktop, spResult; HRESULT hr = SHGetDesktopFolder(&spDesktop); if (FAILED_UNEXPECTEDLY(hr)) return spResult;
if (FAILED_UNEXPECTEDLY(spDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &spResult)))) { spResult.Release(); } return spResult;}
static void ok_attributes_(IDataObject* pDataObject, HRESULT expect_hr, DWORD expect_mask, DWORD expect_attr, UINT expect_items){ FORMATETC fmt = { g_DataObjectAttributes, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM medium = {};
HRESULT hr = pDataObject->GetData(&fmt, &medium); winetest_ok(hr == expect_hr, "Unexpected result from GetData, got 0x%lx, expected 0x%lx\n", hr, expect_hr);
if (hr == expect_hr && expect_hr == S_OK) { LPVOID blob = GlobalLock(medium.hGlobal); winetest_ok(blob != nullptr, "Failed to lock hGlobal\n"); if (blob) { SIZE_T size = GlobalSize(medium.hGlobal); winetest_ok(size == 0xc, "Unexpected size, got %lu, expected 12\n", size); if (size == 0xc) { PDWORD data = (PDWORD)blob; winetest_ok(data[0] == expect_mask, "Unexpected mask, got 0x%lx, expected 0x%lx\n", data[0], expect_mask); winetest_ok(data[1] == expect_attr, "Unexpected attr, got 0x%lx, expected 0x%lx\n", data[1], expect_attr); winetest_ok(data[2] == expect_items, "Unexpected item count, got %lu, expected %u\n", data[2], expect_items); } GlobalUnlock(medium.hGlobal); } }
if (SUCCEEDED(hr)) ReleaseStgMedium(&medium);}
#define ok_attributes (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : ok_attributes_#define ok_hr_ret(x, y) ok_hr(x, y); if (x != y) return
static void test_SpecialCases(){ DWORD dwAttributeMask = 0, dwAttributes = 123; UINT cItems = 123;
HRESULT hr = SHGetAttributesFromDataObject(nullptr, dwAttributeMask, &dwAttributes, &cItems); ok_hr(hr, S_OK); ok_int(dwAttributes, 0); ok_int(cItems, 0);
cItems = 123; hr = SHGetAttributesFromDataObject(nullptr, dwAttributeMask, nullptr, &cItems); ok_hr(hr, S_OK); ok_int(cItems, 0);
dwAttributes = 123; hr = SHGetAttributesFromDataObject(nullptr, dwAttributeMask, &dwAttributes, nullptr); ok_hr(hr, S_OK); ok_int(dwAttributes, 0);}
static void test_AttributesRegistration(){ WCHAR Buffer[MAX_PATH] = {};
GetModuleFileNameW(NULL, Buffer, _countof(Buffer)); CComHeapPtr<ITEMIDLIST_ABSOLUTE> spPath(ILCreateFromPathW(Buffer));
ok(spPath != nullptr, "Unable to create pidl from %S\n", Buffer); if (spPath == nullptr) return;
SFGAOF attributes = dwDefaultAttributeMask; HRESULT hr; { CComPtr<IShellFolder> spFolder; PCUITEMID_CHILD child; hr = SHBindToParent(spPath, IID_PPV_ARG(IShellFolder, &spFolder), &child); ok_hr_ret(hr, S_OK);
hr = spFolder->GetAttributesOf(1, &child, &attributes); ok_hr_ret(hr, S_OK);
if (GetNTVersion() <= _WIN32_WINNT_VISTA) attributes &= dwDefaultAttributeMask_WS03; else attributes &= dwDefaultAttributeMask; }
CComHeapPtr<ITEMIDLIST> parent(ILClone(spPath)); PCIDLIST_RELATIVE child = ILFindLastID(spPath); ILRemoveLastID(parent);
CComPtr<IDataObject> spDataObject; hr = CIDLData_CreateFromIDArray(parent, 1, &child, &spDataObject); ok_hr_ret(hr, S_OK);
/* Not registered yet */ ok_attributes(spDataObject, (GetNTVersion() >= _WIN32_WINNT_VISTA) ? DV_E_FORMATETC : E_INVALIDARG, 0, 0, 0);
/* Ask for attributes, without specifying any */ DWORD dwAttributeMask = 0, dwAttributes = 0; UINT cItems = 0; hr = SHGetAttributesFromDataObject(spDataObject, dwAttributeMask, &dwAttributes, &cItems); ok_hr(hr, S_OK);
/* Now there are attributes registered */ ok_attributes(spDataObject, S_OK, dwDefaultAttributeMask, attributes, 1);
// Now add an additional mask value (our exe should have a propsheet!) dwAttributeMask = SFGAO_HASPROPSHEET; dwAttributes = 0; cItems = 0; hr = SHGetAttributesFromDataObject(spDataObject, dwAttributeMask, &dwAttributes, &cItems); ok_hr(hr, S_OK);
// Observe that this is now also cached ok_attributes(spDataObject, S_OK, dwDefaultAttributeMask | SFGAO_HASPROPSHEET, attributes | SFGAO_HASPROPSHEET, 1);}
static void test_MultipleFiles(){ TmpFile TmpFile1, TmpFile2, TmpFile3;
CComHeapPtr<ITEMIDLIST> pidl_tmpfolder; CComHeapPtr<ITEMIDLIST> pidl1, pidl2, pidl3;
ITEMIDLIST* items[3] = {}; SFGAOF attributes_first = dwDefaultAttributeMask; SFGAOF attributes2 = dwDefaultAttributeMask; SFGAOF attributes3 = dwDefaultAttributeMask; SFGAOF attributes_last = dwDefaultAttributeMask;
HRESULT hr; { WCHAR TempFolder[MAX_PATH] = {}; GetTempPathW(_countof(TempFolder), TempFolder);
// Create temp files TmpFile1.Create(TempFolder); TmpFile2.Create(TempFolder); TmpFile3.Create(TempFolder);
// Last file is read-only SetFileAttributesW(TmpFile3.Buffer, FILE_ATTRIBUTE_READONLY);
hr = SHParseDisplayName(TempFolder, NULL, &pidl_tmpfolder, NULL, NULL); ok_hr_ret(hr, S_OK);
CComPtr<IShellFolder> spFolder = _BindToObject(pidl_tmpfolder); ok(!!spFolder, "Unable to bind to tmp folder\n"); if (!spFolder) return;
hr = spFolder->ParseDisplayName(NULL, 0, PathFindFileNameW(TmpFile1.Buffer), NULL, &pidl1, NULL); ok_hr_ret(hr, S_OK);
hr = spFolder->ParseDisplayName(NULL, 0, PathFindFileNameW(TmpFile2.Buffer), NULL, &pidl2, NULL); ok_hr_ret(hr, S_OK);
hr = spFolder->ParseDisplayName(NULL, 0, PathFindFileNameW(TmpFile3.Buffer), NULL, &pidl3, NULL); ok_hr_ret(hr, S_OK);
items[0] = pidl1; items[1] = pidl2; items[2] = pidl3;
// Query file attributes hr = spFolder->GetAttributesOf(1, items, &attributes_first); ok_hr(hr, S_OK);
hr = spFolder->GetAttributesOf(2, items, &attributes2); ok_hr(hr, S_OK);
hr = spFolder->GetAttributesOf(3, items, &attributes3); ok_hr(hr, S_OK);
hr = spFolder->GetAttributesOf(1, items + 2, &attributes_last); ok_hr(hr, S_OK);
// Ignore any non-default attributes if (GetNTVersion() <= _WIN32_WINNT_VISTA) { attributes_first &= dwDefaultAttributeMask_WS03; attributes2 &= dwDefaultAttributeMask_WS03; attributes3 &= dwDefaultAttributeMask_WS03; attributes_last &= dwDefaultAttributeMask_WS03; } else { attributes_first &= dwDefaultAttributeMask; attributes2 &= dwDefaultAttributeMask; attributes3 &= dwDefaultAttributeMask; attributes_last &= dwDefaultAttributeMask; } }
// Only 'single' files have the stream attribute set ok(attributes_first & SFGAO_STREAM, "Expected SFGAO_STREAM on attributes_first (0x%lx)\n", attributes_first); ok(!(attributes2 & SFGAO_STREAM), "Expected no SFGAO_STREAM on attributes2 (0x%lx)\n", attributes2); ok(!(attributes3 & SFGAO_STREAM), "Expected no SFGAO_STREAM on attributes3 (0x%lx)\n", attributes3); ok(attributes_last & SFGAO_STREAM, "Expected SFGAO_STREAM on attributes_last (0x%lx)\n", attributes_last);
// Only attributes common on all are returned, so only the last has the readonly bit set! ok(!(attributes_first & SFGAO_READONLY), "Expected no SFGAO_READONLY on attributes_first (0x%lx)\n", attributes_first); ok(!(attributes2 & SFGAO_READONLY), "Expected no SFGAO_READONLY on attributes2 (0x%lx)\n", attributes2); ok(!(attributes3 & SFGAO_READONLY), "Expected no SFGAO_READONLY on attributes3 (0x%lx)\n", attributes3); ok(attributes_last & SFGAO_READONLY, "Expected SFGAO_READONLY on attributes_last (0x%lx)\n", attributes_last);
// The actual tests { // Just the first file CComPtr<IDataObject> spDataObject; hr = CIDLData_CreateFromIDArray(pidl_tmpfolder, 1, items, &spDataObject); ok_hr_ret(hr, S_OK);
DWORD dwAttributeMask = 0, dwAttributes = 123; UINT cItems = 123; hr = SHGetAttributesFromDataObject(spDataObject, dwAttributeMask, &dwAttributes, &cItems); ok_hr(hr, S_OK); ok_attributes(spDataObject, S_OK, dwDefaultAttributeMask, attributes_first, 1); }
{ // First 2 files CComPtr<IDataObject> spDataObject; hr = CIDLData_CreateFromIDArray(pidl_tmpfolder, 2, items, &spDataObject); ok_hr_ret(hr, S_OK);
DWORD dwAttributeMask = 0, dwAttributes = 123; UINT cItems = 123; hr = SHGetAttributesFromDataObject(spDataObject, dwAttributeMask, &dwAttributes, &cItems); ok_hr(hr, S_OK); ok_attributes(spDataObject, S_OK, dwDefaultAttributeMask, attributes2, 2); }
{ // All 3 files CComPtr<IDataObject> spDataObject; hr = CIDLData_CreateFromIDArray(pidl_tmpfolder, 3, items, &spDataObject); ok_hr_ret(hr, S_OK);
DWORD dwAttributeMask = 0, dwAttributes = 123; UINT cItems = 123; hr = SHGetAttributesFromDataObject(spDataObject, dwAttributeMask, &dwAttributes, &cItems); ok_hr(hr, S_OK); ok_attributes(spDataObject, S_OK, dwDefaultAttributeMask, attributes3, 3); }
{ // Only the last file CComPtr<IDataObject> spDataObject; hr = CIDLData_CreateFromIDArray(pidl_tmpfolder, 1, items + 2, &spDataObject); ok_hr_ret(hr, S_OK);
DWORD dwAttributeMask = 0, dwAttributes = 123; UINT cItems = 123; hr = SHGetAttributesFromDataObject(spDataObject, dwAttributeMask, &dwAttributes, &cItems); ok_hr(hr, S_OK); ok_attributes(spDataObject, S_OK, dwDefaultAttributeMask, attributes_last, 1); }}
START_TEST(SHGetAttributesFromDataObject){ HRESULT hr;
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); ok_hr(hr, S_OK); if (!SUCCEEDED(hr)) return;
g_DataObjectAttributes = (CLIPFORMAT)RegisterClipboardFormatW(L"DataObjectAttributes"); ok(g_DataObjectAttributes != 0, "Unable to register DataObjectAttributes\n");
test_SpecialCases(); test_AttributesRegistration(); test_MultipleFiles();
CoUninitialize();}