1 /*
2  * PROJECT:     ReactOS api tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Tests for SHLWAPI IShellFolder helpers
5  * COPYRIGHT:   Copyright 2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  */
7 
8 #include <apitest.h>
9 #include <shlobj.h>
10 #include <shlwapi.h>
11 #include <versionhelpers.h>
12 
13 #define SHLWAPI_ISHELLFOLDER_HELPERS
14 #include <shlwapi_undoc.h>
15 
16 static INT s_nStep = 0;
17 
18 class CTestShellFolder : public IShellFolder
19 {
20 public:
21     CTestShellFolder() { }
22     virtual ~CTestShellFolder() { }
23 
24     static void *operator new(size_t size)
25     {
26         return LocalAlloc(LPTR, size);
27     }
28     static void operator delete(void *ptr)
29     {
30         LocalFree(ptr);
31     }
32     static void operator delete(void *ptr, size_t size)
33     {
34         LocalFree(ptr);
35     }
36 
37     // IUnknown methods
38     STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject) override
39     {
40         ok_int(s_nStep, 11);
41         ok_int(IsEqualGUID(riid, IID_IShellFolder2), TRUE);
42         ++s_nStep;
43         return E_NOINTERFACE;
44     }
45     STDMETHOD_(ULONG, AddRef)() override
46     {
47         ok_int(TRUE, FALSE);
48         return 1;
49     }
50     STDMETHOD_(ULONG, Release)() override
51     {
52         ok_int(TRUE, FALSE);
53         return 1;
54     }
55 
56     // IShellFolder methods
57     STDMETHOD(ParseDisplayName)(
58         HWND hwndOwner,
59         LPBC pbc,
60         LPOLESTR lpszDisplayName,
61         ULONG *pchEaten,
62         PIDLIST_RELATIVE *ppidl,
63         ULONG *pdwAttributes) override
64     {
65         ok_ptr(*ppidl, NULL);
66         ok_long(*pdwAttributes, 0);
67         ++s_nStep;
68         return 0xDEADFACE;
69     }
70     STDMETHOD(EnumObjects)(
71         HWND hwndOwner,
72         DWORD dwFlags,
73         LPENUMIDLIST *ppEnumIDList) override
74     {
75         ok_int(TRUE, FALSE);
76         return E_NOTIMPL;
77     }
78     STDMETHOD(BindToObject)(
79         PCUIDLIST_RELATIVE pidl,
80         LPBC pbcReserved,
81         REFIID riid,
82         LPVOID *ppvOut) override
83     {
84         ok_int(TRUE, FALSE);
85         return E_NOTIMPL;
86     }
87     STDMETHOD(BindToStorage)(
88         PCUIDLIST_RELATIVE pidl,
89         LPBC pbcReserved,
90         REFIID riid,
91         LPVOID *ppvOut) override
92     {
93         ok_int(TRUE, FALSE);
94         return E_NOTIMPL;
95     }
96     STDMETHOD(CompareIDs)(
97         LPARAM lParam,
98         PCUIDLIST_RELATIVE pidl1,
99         PCUIDLIST_RELATIVE pidl2) override
100     {
101         switch (s_nStep)
102         {
103             case 11:
104                 // It shouldn't come here
105                 ok_int(TRUE, FALSE);
106                 break;
107             case 12:
108                 ok_long((LONG)lParam, 0x00001234);
109                 break;
110             case 13:
111                 ok_long((LONG)lParam, 0x00005678);
112                 break;
113             default:
114                 skip("\n");
115                 break;
116         }
117         ++s_nStep;
118         return 0xFEEDF00D;
119     }
120     STDMETHOD(CreateViewObject)(
121         HWND hwndOwner,
122         REFIID riid,
123         LPVOID *ppvOut) override
124     {
125         ok_int(TRUE, FALSE);
126         return E_NOTIMPL;
127     }
128     STDMETHOD(GetAttributesOf)(
129         UINT cidl,
130         PCUITEMID_CHILD_ARRAY apidl,
131         DWORD *rgfInOut) override
132     {
133         ok_int(TRUE, FALSE);
134         return E_NOTIMPL;
135     }
136     STDMETHOD(GetUIObjectOf)(
137         HWND hwndOwner,
138         UINT cidl,
139         PCUITEMID_CHILD_ARRAY apidl,
140         REFIID riid,
141         UINT * prgfInOut,
142         LPVOID * ppvOut) override
143     {
144         ok_int(TRUE, FALSE);
145         return E_NOTIMPL;
146     }
147     STDMETHOD(GetDisplayNameOf)(
148         PCUITEMID_CHILD pidl,
149         DWORD dwFlags,
150         LPSTRRET strRet) override
151     {
152         switch (s_nStep)
153         {
154             case 0:
155                 ok_long(dwFlags, SHGDN_FORPARSING | SHGDN_FORADDRESSBAR | SHGDN_FOREDITING |
156                                  SHGDN_INFOLDER);
157                 break;
158             case 1:
159                 ok_long(dwFlags, SHGDN_FORPARSING | SHGDN_FORADDRESSBAR | SHGDN_INFOLDER);
160                 break;
161             case 2:
162                 ok_long(dwFlags, SHGDN_FORPARSING | SHGDN_INFOLDER);
163                 break;
164             case 3:
165                 ok_long(dwFlags, SHGDN_FORPARSING);
166                 break;
167             case 4:
168                 ok_long(dwFlags, SHGDN_FORADDRESSBAR | SHGDN_FOREDITING | SHGDN_INFOLDER);
169                 break;
170             case 5:
171                 ok_long(dwFlags, SHGDN_FORADDRESSBAR | SHGDN_INFOLDER);
172                 break;
173             case 6:
174                 ok_long(dwFlags, SHGDN_INFOLDER);
175                 break;
176             case 7:
177                 ok_long(dwFlags, SHGDN_FORPARSING | SHGDN_INFOLDER);
178                 break;
179             case 8:
180                 ok_long(dwFlags, SHGDN_INFOLDER);
181                 break;
182             case 9:
183                 ok_long(dwFlags, SHGDN_NORMAL);
184                 break;
185             default:
186                 skip("\n");
187                 break;
188         }
189         ++s_nStep;
190         return E_FAIL;
191     }
192     STDMETHOD(SetNameOf)(
193         HWND hwndOwner,
194         PCUITEMID_CHILD pidl,
195         LPCOLESTR lpName,
196         DWORD dwFlags,
197         PITEMID_CHILD *pPidlOut) override
198     {
199         ok_int(TRUE, FALSE);
200         return E_NOTIMPL;
201     }
202 };
203 
204 static void Test_GetDisplayNameOf(void)
205 {
206     CTestShellFolder *psf = new CTestShellFolder();
207     HRESULT hr;
208 
209     hr = IShellFolder_GetDisplayNameOf(
210         psf,
211         NULL,
212         SHGDN_FOREDITING | SHGDN_FORADDRESSBAR | SHGDN_FORPARSING | SHGDN_INFOLDER,
213         NULL,
214         0);
215     ok_long(hr, E_FAIL);
216     ok_int(s_nStep, 4);
217 
218     hr = IShellFolder_GetDisplayNameOf(
219         psf,
220         NULL,
221         SHGDN_FOREDITING | SHGDN_FORADDRESSBAR | SHGDN_INFOLDER,
222         NULL,
223         0);
224     ok_long(hr, E_FAIL);
225     ok_int(s_nStep, 10);
226 
227     if (s_nStep != 10)
228         skip("s_nStep value is wrong\n");
229 
230     delete psf;
231 }
232 
233 static void Test_ParseDisplayName(void)
234 {
235     CTestShellFolder *psf = new CTestShellFolder();
236     HRESULT hr;
237 
238     s_nStep = 10;
239     LPITEMIDLIST pidl = (LPITEMIDLIST)UlongToPtr(0xDEADDEAD);
240     hr = IShellFolder_ParseDisplayName(
241         psf,
242         NULL,
243         NULL,
244         NULL,
245         NULL,
246         &pidl,
247         NULL);
248     ok_long(hr, 0xDEADFACE);
249     ok_int(s_nStep, 11);
250 
251     delete psf;
252 }
253 
254 typedef HRESULT (WINAPI *FN_IShellFolder_CompareIDs)(
255     _In_ IShellFolder *psf,
256     _In_ LPARAM lParam,
257     _In_ PCUIDLIST_RELATIVE pidl1,
258     _In_ PCUIDLIST_RELATIVE pidl2);
259 
260 static void Test_CompareIDs(void)
261 {
262     FN_IShellFolder_CompareIDs fnIShellFolder_CompareIDs;
263     fnIShellFolder_CompareIDs =
264         (FN_IShellFolder_CompareIDs)
265             GetProcAddress(GetModuleHandleA("shlwapi"), MAKEINTRESOURCEA(551));
266 
267     if (IsWindowsVistaOrGreater())
268     {
269         skip("Vista+\n");
270         ok(fnIShellFolder_CompareIDs == NULL, "Vista+ has no IShellFolder_CompareIDs\n");
271         return;
272     }
273 
274     CTestShellFolder *psf = new CTestShellFolder();
275     HRESULT hr;
276 
277     s_nStep = 11;
278     hr = fnIShellFolder_CompareIDs(
279         psf,
280         0xFFFF1234,
281         NULL,
282         NULL);
283     ok_long(hr, 0xFEEDF00D);
284     ok_int(s_nStep, 13);
285 
286     s_nStep = 13;
287     hr = fnIShellFolder_CompareIDs(
288         psf,
289         0x00005678,
290         NULL,
291         NULL);
292     ok_long(hr, 0xFEEDF00D);
293     ok_int(s_nStep, 14);
294 
295     delete psf;
296 }
297 
298 START_TEST(IShellFolderHelpers)
299 {
300     HRESULT hrCoInit = ::CoInitialize(NULL);
301 
302     Test_GetDisplayNameOf();
303     Test_ParseDisplayName();
304     Test_CompareIDs();
305 
306     if (SUCCEEDED(hrCoInit))
307         ::CoUninitialize();
308 }
309