xref: /reactos/dll/win32/shell32/shldataobject.cpp (revision 0c2cdcae)
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