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