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 return SHBindToObject(NULL, pidl, IID_PPV_ARG(IShellFolder, &spFolder)); 32 } 33 34 EXTERN_C 35 HRESULT WINAPI SHGetAttributesFromDataObject(IDataObject* pDataObject, DWORD dwAttributeMask, DWORD* pdwAttributes, UINT* pcItems) 36 { 37 DWORD dwAttributes = 0; 38 DWORD cItems = 0; 39 HRESULT hr = S_OK; 40 41 TRACE("(%p, 0x%x, %p, %p)\n", pDataObject, dwAttributeMask, pdwAttributes, pcItems); 42 43 if (!g_DataObjectAttributes) 44 g_DataObjectAttributes = (CLIPFORMAT)RegisterClipboardFormatW(L"DataObjectAttributes"); 45 46 if (pDataObject) 47 { 48 DataObjectAttributes data = {}; 49 if (FAILED(DataObject_GetData(pDataObject, g_DataObjectAttributes, &data, sizeof(data)))) 50 { 51 TRACE("No attributes yet, creating new\n"); 52 memset(&data, 0, sizeof(data)); 53 } 54 55 DWORD dwQueryAttributes = dwAttributeMask | dwDefaultAttributeMask; 56 57 if ((data.dwMask & dwQueryAttributes) != dwQueryAttributes) 58 { 59 CDataObjectHIDA hida(pDataObject); 60 CComPtr<IShellFolder> spFolder; 61 62 if (!FAILED_UNEXPECTEDLY(hr = hida.hr()) && 63 !FAILED_UNEXPECTEDLY(hr = _BindToObject(HIDA_GetPIDLFolder(hida), spFolder))) 64 { 65 CSimpleArray<PCUIDLIST_RELATIVE> apidl; 66 for (UINT n = 0; n < hida->cidl; ++n) 67 { 68 apidl.Add(HIDA_GetPIDLItem(hida, n)); 69 } 70 71 SFGAOF rgfInOut = dwQueryAttributes; 72 hr = spFolder->GetAttributesOf(apidl.GetSize(), apidl.GetData(), &rgfInOut); 73 if (!FAILED_UNEXPECTEDLY(hr)) 74 { 75 data.dwMask = dwQueryAttributes; 76 // Only store what we asked for 77 data.dwAttributes = rgfInOut & dwQueryAttributes; 78 data.cItems = apidl.GetSize(); 79 80 hr = DataObject_SetData(pDataObject, g_DataObjectAttributes, &data, sizeof(data)); 81 FAILED_UNEXPECTEDLY(hr); 82 } 83 } 84 } 85 86 // Only give the user what they asked for, not everything else we have! 87 dwAttributes = data.dwAttributes & dwAttributeMask; 88 cItems = data.cItems; 89 } 90 91 if (pdwAttributes) 92 *pdwAttributes = dwAttributes; 93 94 if (pcItems) 95 *pcItems = cItems; 96 97 return hr; 98 } 99 100 PIDLIST_ABSOLUTE SHELL_CIDA_ILCloneFull(_In_ const CIDA *pCIDA, _In_ UINT Index) 101 { 102 if (Index < pCIDA->cidl) 103 return ILCombine(HIDA_GetPIDLFolder(pCIDA), HIDA_GetPIDLItem(pCIDA, Index)); 104 return NULL; 105 } 106 107 PIDLIST_ABSOLUTE SHELL_DataObject_ILCloneFullItem(_In_ IDataObject *pDO, _In_ UINT Index) 108 { 109 CDataObjectHIDA cida(pDO); 110 return SUCCEEDED(cida.hr()) ? SHELL_CIDA_ILCloneFull(cida, Index) : NULL; 111 } 112