1 /* 2 * PROJECT: shell32 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: SHGetAttributesFromDataObject implementation 5 * COPYRIGHT: Copyright 2021 Mark Jansen <mark.jansen@reactos.org> 6 */ 7 8 9 #include "precomp.h" 10 11 WINE_DEFAULT_DEBUG_CHANNEL(shell); 12 13 14 static CLIPFORMAT g_DataObjectAttributes = 0; 15 static const DWORD dwDefaultAttributeMask = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_STORAGE | SFGAO_CANRENAME | 16 SFGAO_CANDELETE | SFGAO_READONLY | SFGAO_STREAM | SFGAO_FOLDER; 17 18 struct DataObjectAttributes 19 { 20 DWORD dwMask; 21 DWORD dwAttributes; 22 UINT cItems; 23 }; 24 25 static_assert(sizeof(DataObjectAttributes) == 0xc, "Unexpected struct size!"); 26 27 28 static 29 HRESULT _BindToObject(PCUIDLIST_ABSOLUTE pidl, CComPtr<IShellFolder>& spFolder) 30 { 31 CComPtr<IShellFolder> spDesktop; 32 HRESULT hr = SHGetDesktopFolder(&spDesktop); 33 if (FAILED(hr)) 34 return hr; 35 36 return spDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &spFolder)); 37 } 38 39 EXTERN_C 40 HRESULT WINAPI SHGetAttributesFromDataObject(IDataObject* pDataObject, DWORD dwAttributeMask, DWORD* pdwAttributes, UINT* pcItems) 41 { 42 DWORD dwAttributes = 0; 43 DWORD cItems = 0; 44 HRESULT hr = S_OK; 45 46 TRACE("(%p, 0x%x, %p, %p)\n", pDataObject, dwAttributeMask, pdwAttributes, pcItems); 47 48 if (!g_DataObjectAttributes) 49 g_DataObjectAttributes = (CLIPFORMAT)RegisterClipboardFormatW(L"DataObjectAttributes"); 50 51 if (pDataObject) 52 { 53 DataObjectAttributes data = {}; 54 if (FAILED(DataObject_GetData(pDataObject, g_DataObjectAttributes, &data, sizeof(data)))) 55 { 56 TRACE("No attributes yet, creating new\n"); 57 memset(&data, 0, sizeof(data)); 58 } 59 60 DWORD dwQueryAttributes = dwAttributeMask | dwDefaultAttributeMask; 61 62 if ((data.dwMask & dwQueryAttributes) != dwQueryAttributes) 63 { 64 CDataObjectHIDA hida(pDataObject); 65 CComPtr<IShellFolder> spFolder; 66 67 if (!FAILED_UNEXPECTEDLY(hr = hida.hr()) && 68 !FAILED_UNEXPECTEDLY(hr = _BindToObject(HIDA_GetPIDLFolder(hida), spFolder))) 69 { 70 CSimpleArray<PCUIDLIST_RELATIVE> apidl; 71 for (UINT n = 0; n < hida->cidl; ++n) 72 { 73 apidl.Add(HIDA_GetPIDLItem(hida, n)); 74 } 75 76 SFGAOF rgfInOut = dwQueryAttributes; 77 hr = spFolder->GetAttributesOf(apidl.GetSize(), apidl.GetData(), &rgfInOut); 78 if (!FAILED_UNEXPECTEDLY(hr)) 79 { 80 data.dwMask = dwQueryAttributes; 81 // Only store what we asked for 82 data.dwAttributes = rgfInOut & dwQueryAttributes; 83 data.cItems = apidl.GetSize(); 84 85 hr = DataObject_SetData(pDataObject, g_DataObjectAttributes, &data, sizeof(data)); 86 FAILED_UNEXPECTEDLY(hr); 87 } 88 } 89 } 90 91 // Only give the user what they asked for, not everything else we have! 92 dwAttributes = data.dwAttributes & dwAttributeMask; 93 cItems = data.cItems; 94 } 95 96 if (pdwAttributes) 97 *pdwAttributes = dwAttributes; 98 99 if (pcItems) 100 *pcItems = cItems; 101 102 return hr; 103 } 104