Reactos
at master 144 lines 4.5 kB view raw
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 11WINE_DEFAULT_DEBUG_CHANNEL(shell); 12 13 14static CLIPFORMAT g_DataObjectAttributes = 0; 15static const DWORD dwDefaultAttributeMask = SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_STORAGE | SFGAO_CANRENAME | 16 SFGAO_CANDELETE | SFGAO_READONLY | SFGAO_STREAM | SFGAO_FOLDER; 17 18struct DataObjectAttributes 19{ 20 DWORD dwMask; 21 DWORD dwAttributes; 22 UINT cItems; 23}; 24 25static_assert(sizeof(DataObjectAttributes) == 0xc, "Unexpected struct size!"); 26 27 28static 29HRESULT _BindToObject(PCUIDLIST_ABSOLUTE pidl, CComPtr<IShellFolder>& spFolder) 30{ 31 return SHBindToObject(NULL, pidl, IID_PPV_ARG(IShellFolder, &spFolder)); 32} 33 34EXTERN_C 35HRESULT 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 HRESULT hr2; 81 hr2 = DataObject_SetData(pDataObject, g_DataObjectAttributes, &data, sizeof(data)); 82 FAILED_UNEXPECTEDLY(hr2); // Report cache failure but don't fail the function 83 } 84 } 85 } 86 87 // Only give the user what they asked for, not everything else we have! 88 dwAttributes = data.dwAttributes & dwAttributeMask; 89 cItems = data.cItems; 90 } 91 92 if (pdwAttributes) 93 *pdwAttributes = dwAttributes; 94 95 if (pcItems) 96 *pcItems = cItems; 97 98 return hr; 99} 100 101HRESULT DataObject_GetHIDACount(IDataObject *pdo) 102{ 103 if (!pdo) 104 return E_INVALIDARG; 105 CDataObjectHIDA cida(pdo); 106 HRESULT hr = cida.hr(); 107 return SUCCEEDED(hr) ? cida->cidl : hr; 108} 109 110PIDLIST_ABSOLUTE SHELL_CIDA_ILCloneFull(_In_ const CIDA *pCIDA, _In_ UINT Index) 111{ 112 if (Index < pCIDA->cidl) 113 return ILCombine(HIDA_GetPIDLFolder(pCIDA), HIDA_GetPIDLItem(pCIDA, Index)); 114 return NULL; 115} 116 117PIDLIST_ABSOLUTE SHELL_DataObject_ILCloneFullItem(_In_ IDataObject *pDO, _In_ UINT Index) 118{ 119 if (!pDO) 120 return NULL; 121 CDataObjectHIDA cida(pDO); 122 return SUCCEEDED(cida.hr()) ? SHELL_CIDA_ILCloneFull(cida, Index) : NULL; 123} 124 125HRESULT SHELL_CloneDataObject(_In_ IDataObject *pDO, _Out_ IDataObject **ppDO) 126{ 127 *ppDO = NULL; 128 CDataObjectHIDA cida(pDO); 129 HRESULT hr = cida.hr(); 130 if (SUCCEEDED(hr)) 131 { 132 CCidaChildArrayHelper items(cida); 133 if (FAILED(hr = items.hr())) 134 return hr; 135 hr = SHCreateFileDataObject(HIDA_GetPIDLFolder(cida), cida->cidl, items.GetItems(), NULL, ppDO); 136 if (SUCCEEDED(hr)) 137 { 138 POINT pt; 139 if (SUCCEEDED(DataObject_GetOffset(pDO, &pt))) 140 DataObject_SetOffset(*ppDO, &pt); 141 } 142 } 143 return hr; 144}