xref: /reactos/dll/win32/shell32/shldataobject.cpp (revision aebaa14e)
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
_BindToObject(PCUIDLIST_ABSOLUTE pidl,CComPtr<IShellFolder> & spFolder)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
SHGetAttributesFromDataObject(IDataObject * pDataObject,DWORD dwAttributeMask,DWORD * pdwAttributes,UINT * pcItems)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                     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 
SHELL_CIDA_ILCloneFull(_In_ const CIDA * pCIDA,_In_ UINT Index)101 PIDLIST_ABSOLUTE SHELL_CIDA_ILCloneFull(_In_ const CIDA *pCIDA, _In_ UINT Index)
102 {
103     if (Index < pCIDA->cidl)
104         return ILCombine(HIDA_GetPIDLFolder(pCIDA), HIDA_GetPIDLItem(pCIDA, Index));
105     return NULL;
106 }
107 
SHELL_DataObject_ILCloneFullItem(_In_ IDataObject * pDO,_In_ UINT Index)108 PIDLIST_ABSOLUTE SHELL_DataObject_ILCloneFullItem(_In_ IDataObject *pDO, _In_ UINT Index)
109 {
110     if (!pDO)
111         return NULL;
112     CDataObjectHIDA cida(pDO);
113     return SUCCEEDED(cida.hr()) ? SHELL_CIDA_ILCloneFull(cida, Index) : NULL;
114 }
115 
SHELL_CloneDataObject(_In_ IDataObject * pDO,_Out_ IDataObject ** ppDO)116 HRESULT SHELL_CloneDataObject(_In_ IDataObject *pDO, _Out_ IDataObject **ppDO)
117 {
118     *ppDO = NULL;
119     CDataObjectHIDA cida(pDO);
120     HRESULT hr = cida.hr();
121     if (SUCCEEDED(hr))
122     {
123         PCUITEMID_CHILD items = HIDA_GetPIDLItem(cida, 0);
124         hr = SHCreateFileDataObject(HIDA_GetPIDLFolder(cida), cida->cidl, &items, NULL, ppDO);
125         if (SUCCEEDED(hr))
126         {
127             POINT pt;
128             if (SUCCEEDED(DataObject_GetOffset(pDO, &pt)))
129                 DataObject_SetOffset(*ppDO, &pt);
130         }
131     }
132     return hr;
133 }
134