1 /*
2  * PROJECT:     ReactOS api tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Test for ACListISF objects
5  * COPYRIGHT:   Copyright 2016 Mark Jansen <mark.jansen@reactos.org>
6  *              Copyright 2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
7  */
8 
9 #define _UNICODE
10 #define UNICODE
11 #include <apitest.h>
12 #include <shlobj.h>
13 #include <atlbase.h>
14 #include <tchar.h>      //
15 #include <atlcom.h>     // These 3 includes only exist here to make gcc happy about (unused) templates..
16 #include <atlwin.h>     //
17 
18 // Yes, gcc at it again, let's validate everything found inside unused templates!
19 ULONG DbgPrint(PCH Format,...);
20 
21 #include <stdio.h>
22 #include <shellutils.h>
23 #include <shlwapi.h>
24 #include <strsafe.h>
25 
26 static bool g_ShowHidden;
27 static DWORD g_WinVersion;
28 #define WINVER_VISTA   0x0600
29 
30 
31 #define ok_hr(status, expected)     ok_hex(status, expected)
32 
33 // We do not want our results to originate from the helper functions, so have them originate from the calls to them
34 #define test_at_end                 (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_at_end_imp
35 #define test_ExpectDrives           (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_ExpectDrives_imp
36 #define test_ExpectFolders          (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : test_ExpectFolders_imp
37 #define winetest_ok_hr(expression, expected) \
38     do { \
39         int _value = (expression); \
40         winetest_ok(_value == (expected), "Wrong value for '%s', expected: " #expected " (0x%x), got: 0x%x\n", \
41            #expression, (int)(expected), _value); \
42     } while (0)
43 
test_at_end_imp(CComPtr<IEnumString> & EnumStr)44 static void test_at_end_imp(CComPtr<IEnumString>& EnumStr)
45 {
46     CComHeapPtr<OLECHAR> Result;
47     ULONG Fetched = 12345;
48     HRESULT hr = EnumStr->Next(1, &Result, &Fetched);
49     winetest_ok(hr == S_FALSE, "Expected hr to be S_FALSE, was 0x%lx\n", hr);
50     winetest_ok(Fetched == 0u, "Expected Fetched to be 0, was: %lu\n", Fetched);
51     if (Fetched == 1u)
52         winetest_ok(0, "Expected there not to be a result, got: %s\n", wine_dbgstr_w(Result));
53 }
54 
GetDisplayname(CComPtr<IShellFolder> & spDrives,CComHeapPtr<ITEMIDLIST> & pidl,CComHeapPtr<WCHAR> & DisplayName)55 static bool GetDisplayname(CComPtr<IShellFolder>& spDrives, CComHeapPtr<ITEMIDLIST>& pidl, CComHeapPtr<WCHAR>& DisplayName)
56 {
57     STRRET StrRet;
58     HRESULT hr;
59     winetest_ok_hr(hr = spDrives->GetDisplayNameOf(pidl, SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR, &StrRet), S_OK);
60     if (!SUCCEEDED(hr))
61         return false;
62 
63     winetest_ok_hr(hr = StrRetToStrW(&StrRet, NULL, &DisplayName), S_OK);
64     if (!SUCCEEDED(hr))
65         return false;
66     return true;
67 }
68 
69 enum ExpectOptions
70 {
71     None = 0,
72     IgnoreRoot = 1,
73     CheckLast = 2,
74     IgnoreHidden = 4,
75     IgnoreFiles = 8,
76 };
77 
78 // wtf c++
operator |(const ExpectOptions & left,const ExpectOptions & right)79 ExpectOptions operator | (const ExpectOptions& left, const ExpectOptions& right)
80 {
81     return static_cast<ExpectOptions>(static_cast<int>(left) | static_cast<int>(right));
82 }
83 
84 
85 static void
test_ExpectFolders_imp(CComPtr<IEnumString> & EnumStr,LPITEMIDLIST pidlTarget,const WCHAR * Root,ExpectOptions options)86 test_ExpectFolders_imp(CComPtr<IEnumString>& EnumStr, LPITEMIDLIST pidlTarget, const WCHAR* Root, ExpectOptions options)
87 {
88     CComPtr<IShellFolder> spDesktop;
89     HRESULT hr = SHGetDesktopFolder(&spDesktop);
90 
91     CComPtr<IShellFolder> spTarget;
92     if (pidlTarget)
93     {
94         winetest_ok_hr(hr = spDesktop->BindToObject(pidlTarget, NULL, IID_PPV_ARG(IShellFolder, &spTarget)), S_OK);
95         if (!SUCCEEDED(hr))
96             return;
97     }
98     else
99     {
100         spTarget = spDesktop;
101     }
102 
103     SHCONTF EnumFlags = SHCONTF_FOLDERS | SHCONTF_INIT_ON_FIRST_NEXT;
104     if (g_ShowHidden && !(options & IgnoreHidden))
105         EnumFlags |= SHCONTF_INCLUDEHIDDEN;
106     if (!(options & IgnoreFiles))
107         EnumFlags |= SHCONTF_NONFOLDERS;
108 
109     CComPtr<IEnumIDList> spEnumIDList;
110     winetest_ok_hr(hr = spTarget->EnumObjects(NULL, EnumFlags, &spEnumIDList), S_OK);
111     if (!SUCCEEDED(hr))
112         return;
113 
114     WCHAR Buffer[512];
115     CComHeapPtr<ITEMIDLIST> pidl;
116     INT Count = 0;
117     while (spEnumIDList->Next(1, &pidl, NULL) == S_OK)
118     {
119         CComHeapPtr<WCHAR> DisplayName;
120         if (!GetDisplayname(spTarget, pidl, DisplayName))
121             break;
122 
123         CComHeapPtr<OLECHAR> Result;
124         ULONG Fetched;
125         hr = EnumStr->Next(1, &Result, &Fetched);
126         winetest_ok_hr(hr, S_OK);
127 
128         if (hr != S_OK)
129             break;
130 
131         StringCchPrintfW(Buffer, _ARRAYSIZE(Buffer), L"%s%s", (options & IgnoreRoot) ? L"" : Root, (WCHAR*)DisplayName);
132 
133         winetest_ok(!wcscmp(Buffer, Result), "Expected %s, got %s\n", wine_dbgstr_w(Buffer), wine_dbgstr_w(Result));
134 
135         pidl.Free();
136         Count++;
137     }
138     if (options & CheckLast)
139     {
140         test_at_end_imp(EnumStr);
141     }
142 }
143 
144 static void
test_ExpectDrives_imp(CComPtr<IEnumString> & EnumStr,CComHeapPtr<ITEMIDLIST> & pidlTarget)145 test_ExpectDrives_imp(CComPtr<IEnumString>& EnumStr, CComHeapPtr<ITEMIDLIST>& pidlTarget)
146 {
147     test_ExpectFolders_imp(EnumStr, pidlTarget, NULL, IgnoreRoot | CheckLast);
148 }
149 
150 static void
test_ACListISF_NONE()151 test_ACListISF_NONE()
152 {
153     CComPtr<IEnumString> EnumStr;
154     HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr));
155     ok_hr(hr, S_OK);
156     if (!SUCCEEDED(hr))
157     {
158         skip("CoCreateInstance failed\n");
159         return;
160     }
161 
162     CComPtr<IACList2> ACList;
163     ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK);
164     if (!SUCCEEDED(hr))
165     {
166         skip("QueryInterface failed\n");
167         return;
168     }
169 
170     ok_hr(hr = ACList->SetOptions(ACLO_NONE), S_OK);
171     test_at_end(EnumStr);
172 
173 
174     WCHAR Buffer[MAX_PATH];
175     GetSystemWindowsDirectoryW(Buffer, _ARRAYSIZE(Buffer));
176     Buffer[3] = '\0';
177 
178     CComHeapPtr<ITEMIDLIST> pidlDiskRoot;
179     ok_hr(hr = SHParseDisplayName(Buffer, NULL, &pidlDiskRoot, NULL, NULL), S_OK);
180     if (!SUCCEEDED(hr))
181     {
182         skip("SHParseDisplayName failed\n");
183         return;
184     }
185 
186     ok_hr(hr = ACList->Expand(Buffer), S_OK);
187     test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, CheckLast | IgnoreHidden);
188 
189     ok_hr(hr = EnumStr->Reset(), S_OK);
190     ok_hr(hr = ACList->Expand(Buffer), S_OK);
191     ok_hr(hr = ACList->SetOptions(ACLO_NONE), S_OK);
192     test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, CheckLast);
193 }
194 
195 static void
test_ACListISF_CURRENTDIR()196 test_ACListISF_CURRENTDIR()
197 {
198     CComPtr<IEnumString> EnumStr;
199     HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr));
200     ok_hr(hr, S_OK);
201     if (!SUCCEEDED(hr))
202     {
203         skip("CoCreateInstance failed\n");
204         return;
205     }
206 
207     CComPtr<IACList2> ACList;
208     ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK);
209     if (!SUCCEEDED(hr))
210     {
211         skip("QueryInterface failed\n");
212         return;
213     }
214 
215     CComPtr<ICurrentWorkingDirectory> CurrentWorkingDir;
216     ok_hr(hr = EnumStr->QueryInterface(IID_ICurrentWorkingDirectory, (void**)&CurrentWorkingDir), S_OK);
217     if (!SUCCEEDED(hr))
218     {
219         skip("QueryInterface failed\n");
220         return;
221     }
222 
223     ok_hr(hr = ACList->SetOptions(ACLO_CURRENTDIR), S_OK);
224     test_at_end(EnumStr);
225 
226 
227     WCHAR Buffer[MAX_PATH] = { 1, 1, 1, 1, 1, 0 }, Buffer2[MAX_PATH];
228     if (g_WinVersion < WINVER_VISTA)
229         ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), E_NOTIMPL);
230     else
231         ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), E_UNEXPECTED);
232     ok(!wcscmp(L"\x1\x1\x1\x1\x1", Buffer), "Expected %s, got %s\n", wine_dbgstr_w(L"\x1\x1\x1\x1\x1"), wine_dbgstr_w(Buffer));
233 
234     GetSystemWindowsDirectoryW(Buffer2, _ARRAYSIZE(Buffer2));
235     // Windows 2k3 does not parse it without the trailing '\\'
236     Buffer2[3] = '\0';
237     CComHeapPtr<ITEMIDLIST> pidlDiskRoot;
238     ok_hr(hr = SHParseDisplayName(Buffer2, NULL, &pidlDiskRoot, NULL, NULL), S_OK);
239     if (!SUCCEEDED(hr))
240         return;
241 
242     ok_hr(hr = CurrentWorkingDir->SetDirectory(Buffer2), S_OK);
243     test_at_end(EnumStr);
244 
245     Buffer[0] = '\0';
246     if (g_WinVersion < WINVER_VISTA)
247     {
248         ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), E_NOTIMPL);
249     }
250     else
251     {
252         ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), S_OK);
253         ok(!wcscmp(Buffer2, Buffer), "Expected %s, got %s\n", wine_dbgstr_w(Buffer2), wine_dbgstr_w(Buffer));
254     }
255 
256     Buffer2[2] = '\0';
257     ok_hr(hr = CurrentWorkingDir->SetDirectory(Buffer2), S_OK);
258     test_at_end(EnumStr);
259 
260     Buffer[0] = '\0';
261     Buffer2[2] = '\\';
262     if (g_WinVersion < WINVER_VISTA)
263     {
264         ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), E_NOTIMPL);
265     }
266     else
267     {
268         ok_hr(hr = CurrentWorkingDir->GetDirectory(Buffer, _ARRAYSIZE(Buffer)), S_OK);
269         ok(!wcscmp(Buffer2, Buffer), "Expected %s, got %s\n", wine_dbgstr_w(Buffer2), wine_dbgstr_w(Buffer));
270     }
271 
272     ok_hr(hr = ACList->Expand(Buffer2), S_OK);
273     // The first set of results are absolute paths, without hidden files?!
274     test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer2, IgnoreHidden);
275     test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer2, IgnoreHidden | IgnoreRoot | CheckLast);
276 
277     WCHAR szDir[MAX_PATH], szPath[MAX_PATH];
278     Buffer2[2] = 0;
279     StringCbCopyW(szDir, sizeof(szDir), Buffer2);
280 
281     StringCbCopyW(szPath, sizeof(szPath), szDir);
282     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-1");
283     CreateDirectoryW(szPath, NULL);
284 
285     StringCbCopyW(szPath, sizeof(szPath), szDir);
286     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-1\\TEST1");
287     CreateDirectoryW(szPath, NULL);
288 
289     StringCbCopyW(szPath, sizeof(szPath), szDir);
290     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-1\\TEST2");
291     CreateDirectoryW(szPath, NULL);
292 
293     StringCbCopyW(szPath, sizeof(szPath), szDir);
294     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-2");
295     CreateDirectoryW(szPath, NULL);
296 
297     StringCbCopyW(szPath, sizeof(szPath), szDir);
298     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-2\\tes1");
299     CreateDirectoryW(szPath, NULL);
300 
301     StringCbCopyW(szPath, sizeof(szPath), szDir);
302     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-2\\tes2");
303     CreateDirectoryW(szPath, NULL);
304 
305     ULONG cGot;
306     LPWSTR psz = NULL;
307     EnumStr->Reset();
308 
309     StringCbCopyW(szPath, sizeof(szPath), szDir);
310     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-1\\");
311     ok_hr(hr = ACList->Expand(szPath), S_OK);
312 
313     hr = EnumStr->Next(1, &psz, &cGot);
314     ok_hr(hr, S_OK);
315     StringCbCopyW(szPath, sizeof(szPath), szDir);
316     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-1\\TEST1");
317     ok_wstr(szPath, psz);
318     CoTaskMemFree(psz);
319 
320     hr = EnumStr->Next(1, &psz, &cGot);
321     ok_hr(hr, S_OK);
322     StringCbCopyW(szPath, sizeof(szPath), szDir);
323     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-1\\TEST2");
324     ok_wstr(szPath, psz);
325     CoTaskMemFree(psz);
326 
327     StringCbCopyW(szPath, sizeof(szPath), szDir);
328     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-2\\");
329     ok_hr(hr = CurrentWorkingDir->SetDirectory(szPath), S_OK);
330 
331     hr = EnumStr->Next(1, &psz, &cGot);
332     ok_hr(hr, S_OK);
333     ok_wstr(psz, L"tes1");
334     CoTaskMemFree(psz);
335 
336     hr = EnumStr->Next(1, &psz, &cGot);
337     ok_hr(hr, S_OK);
338     ok_wstr(psz, L"tes2");
339     CoTaskMemFree(psz);
340 
341     StringCbCopyW(szPath, sizeof(szPath), szDir);
342     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-2");
343     ok_hr(hr = CurrentWorkingDir->SetDirectory(szPath), S_OK);
344 
345     EnumStr->Reset();
346 
347     hr = EnumStr->Next(1, &psz, &cGot);
348     ok_hr(hr, S_OK);
349     ok_wstr(psz, L"tes1");
350     CoTaskMemFree(psz);
351 
352     hr = EnumStr->Next(1, &psz, &cGot);
353     ok_hr(hr, S_OK);
354     ok_wstr(psz, L"tes2");
355     CoTaskMemFree(psz);
356 
357     StringCbCopyW(szPath, sizeof(szPath), szDir);
358     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-1\\TEST1");
359     RemoveDirectoryW(szPath);
360 
361     StringCbCopyW(szPath, sizeof(szPath), szDir);
362     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-1\\TEST2");
363     RemoveDirectoryW(szPath);
364 
365     StringCbCopyW(szPath, sizeof(szPath), szDir);
366     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-1");
367     RemoveDirectoryW(szPath);
368 
369     StringCbCopyW(szPath, sizeof(szPath), szDir);
370     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-2\\tes1");
371     RemoveDirectoryW(szPath);
372 
373     StringCbCopyW(szPath, sizeof(szPath), szDir);
374     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-2\\tes2");
375     RemoveDirectoryW(szPath);
376 
377     StringCbCopyW(szPath, sizeof(szPath), szDir);
378     StringCbCatW(szPath, sizeof(szPath), L"\\BROWSEUI-2");
379     RemoveDirectoryW(szPath);
380 }
381 
382 static void
test_ACListISF_CURRENTDIR2()383 test_ACListISF_CURRENTDIR2()
384 {
385     CComPtr<IEnumString> EnumStr;
386     HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr));
387     ok_hr(hr, S_OK);
388     if (!SUCCEEDED(hr))
389     {
390         skip("CoCreateInstance failed\n");
391         return;
392     }
393 
394     CComPtr<IACList2> ACList;
395     ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK);
396     if (!SUCCEEDED(hr))
397     {
398         skip("QueryInterface failed\n");
399         return;
400     }
401 
402     CComPtr<ICurrentWorkingDirectory> CurrentWorkingDir;
403     ok_hr(hr = EnumStr->QueryInterface(IID_ICurrentWorkingDirectory, (void**)&CurrentWorkingDir), S_OK);
404     if (!SUCCEEDED(hr))
405     {
406         skip("QueryInterface failed\n");
407         return;
408     }
409 
410     ok_hr(hr = ACList->SetOptions(ACLO_CURRENTDIR), S_OK);
411     test_at_end(EnumStr);
412 
413     CreateDirectoryW(L"C:\\BROWSEUI-1", NULL);
414     CreateDirectoryW(L"C:\\BROWSEUI-1\\TEST1", NULL);
415     CreateDirectoryW(L"C:\\BROWSEUI-1\\TEST2", NULL);
416     CreateDirectoryW(L"C:\\BROWSEUI-1\\TEST1\\TEST3", NULL);
417     CreateDirectoryW(L"C:\\BROWSEUI-2", NULL);
418     CreateDirectoryW(L"C:\\BROWSEUI-2\\TEST1", NULL);
419     CreateDirectoryW(L"C:\\BROWSEUI-2\\TEST2", NULL);
420     CreateDirectoryW(L"C:\\BROWSEUI-2\\TEST1\\TEST4", NULL);
421 
422     ok_hr(hr = CurrentWorkingDir->SetDirectory(L"C:\\BROWSEUI-1\\TEST1"), S_OK);
423     test_at_end(EnumStr);
424 
425     ok_hr(hr = ACList->Expand(L"C:\\BROWSEUI-2\\TEST1\\"), S_OK);
426 
427     LPWSTR psz;
428     ULONG cGot;
429 
430     hr = EnumStr->Next(1, &psz, &cGot);
431     ok_hr(hr, S_OK);
432     ok_wstr(psz, L"C:\\BROWSEUI-2\\TEST1\\TEST4");
433     CoTaskMemFree(psz);
434 
435     hr = EnumStr->Next(1, &psz, &cGot);
436     ok_hr(hr, S_OK);
437     ok_wstr(psz, L"TEST3");
438     CoTaskMemFree(psz);
439 
440     test_at_end(EnumStr);
441 
442     ok_hr(hr = ACList->Expand(L"C:\\BROWSEUI-1\\TEST1\\"), S_OK);
443 
444     hr = EnumStr->Next(1, &psz, &cGot);
445     ok_hr(hr, S_OK);
446     ok_wstr(psz, L"C:\\BROWSEUI-1\\TEST1\\TEST3");
447     CoTaskMemFree(psz);
448 
449     hr = EnumStr->Next(1, &psz, &cGot);
450     ok_hr(hr, S_OK);
451     ok_wstr(psz, L"TEST3");
452     CoTaskMemFree(psz);
453 
454     test_at_end(EnumStr);
455 
456     ok_hr(hr = CurrentWorkingDir->SetDirectory(L"C:\\BROWSEUI-2\\TEST1"), S_OK);
457     test_at_end(EnumStr);
458 
459     ok_hr(hr = ACList->Expand(L"..\\TEST1\\"), S_OK);
460 
461     hr = EnumStr->Next(1, &psz, &cGot);
462     ok_hr(hr, S_OK);
463     ok_wstr(psz, L"..\\TEST1\\TEST4");
464     CoTaskMemFree(psz);
465 
466     hr = EnumStr->Next(1, &psz, &cGot);
467     ok_hr(hr, S_OK);
468     ok_wstr(psz, L"TEST4");
469     CoTaskMemFree(psz);
470 
471     test_at_end(EnumStr);
472 
473     ok_hr(hr = ACList->Expand(L"\\BROWSEUI-2\\TEST1\\"), S_OK);
474 
475     hr = EnumStr->Next(1, &psz, &cGot);
476     ok_hr(hr, S_OK);
477     ok_wstr(psz, L"\\BROWSEUI-2\\TEST1\\TEST4");
478     CoTaskMemFree(psz);
479 
480     hr = EnumStr->Next(1, &psz, &cGot);
481     ok_hr(hr, S_OK);
482     ok_wstr(psz, L"TEST4");
483     CoTaskMemFree(psz);
484 
485     test_at_end(EnumStr);
486 
487     RemoveDirectoryW(L"C:\\BROWSEUI-1\\TEST1\\TEST3");
488     RemoveDirectoryW(L"C:\\BROWSEUI-1\\TEST1");
489     RemoveDirectoryW(L"C:\\BROWSEUI-1\\TEST2");
490     RemoveDirectoryW(L"C:\\BROWSEUI-1");
491     RemoveDirectoryW(L"C:\\BROWSEUI-2\\TEST1\\TEST4");
492     RemoveDirectoryW(L"C:\\BROWSEUI-2\\TEST1");
493     RemoveDirectoryW(L"C:\\BROWSEUI-2\\TEST2");
494     RemoveDirectoryW(L"C:\\BROWSEUI-2");
495 }
496 
497 static void
test_ACListISF_MYCOMPUTER()498 test_ACListISF_MYCOMPUTER()
499 {
500     CComPtr<IACList2> ACList;
501     HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IACList2, &ACList));
502     ok_hr(hr, S_OK);
503     if (!SUCCEEDED(hr))
504     {
505         skip("CoCreateInstance failed\n");
506         return;
507     }
508 
509     // Check the default
510     DWORD CurrentOption = 0xdeadbeef;
511     ok_hr(ACList->GetOptions(&CurrentOption), S_OK);
512     ok(CurrentOption == (ACLO_CURRENTDIR|ACLO_MYCOMPUTER), "Expected the default to be %x, was %lx\n",
513         (ACLO_CURRENTDIR|ACLO_MYCOMPUTER), CurrentOption);
514 
515 
516     CComPtr<IEnumString> EnumStr;
517     ok_hr(hr = ACList->QueryInterface(IID_IEnumString, (void**)&EnumStr), S_OK);
518     if (!SUCCEEDED(hr))
519     {
520         skip("QueryInterface failed\n");
521         return;
522     }
523 
524     CComPtr<IPersistFolder> PersistFolder;
525     ok_hr(hr = EnumStr->QueryInterface(IID_IPersistFolder, (void**)&PersistFolder), S_OK);
526     if (!SUCCEEDED(hr))
527     {
528         skip("QueryInterface failed\n");
529         return;
530     }
531 
532     CComHeapPtr<ITEMIDLIST> pidlMyComputer;
533     ok_hr(hr = SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlMyComputer), S_OK);
534     if (!SUCCEEDED(hr))
535     {
536         skip("SHGetSpecialFolderLocation failed\n");
537         return;
538     }
539 
540     hr = EnumStr->Reset();
541     if (g_WinVersion < WINVER_VISTA)
542         ok_hr(hr, S_FALSE);
543     else
544         ok_hr(hr, S_OK);
545     test_ExpectDrives(EnumStr, pidlMyComputer);
546 
547     ok_hr(hr = ACList->SetOptions(ACLO_MYCOMPUTER), S_OK);
548     ok_hr(EnumStr->Reset(), S_OK);
549     test_ExpectDrives(EnumStr, pidlMyComputer);
550 
551     WCHAR Buffer[MAX_PATH];
552     GetSystemWindowsDirectoryW(Buffer, _ARRAYSIZE(Buffer));
553     // Windows 2k3 does not parse it without the trailing '\\'
554     Buffer[3] = '\0';
555     CComHeapPtr<ITEMIDLIST> pidlDiskRoot;
556     ok_hr(hr = SHParseDisplayName(Buffer, NULL, &pidlDiskRoot, NULL, NULL), S_OK);
557     if (!SUCCEEDED(hr))
558         return;
559     Buffer[2] = '\0';
560 
561     ok_hr(hr = ACList->Expand(Buffer), S_OK);
562     test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, None);
563     test_ExpectDrives(EnumStr, pidlMyComputer);
564 
565     ok_hr(hr = ACList->Expand(Buffer), S_OK);
566     ok_hr(EnumStr->Reset(), S_OK);
567     // Pre vista does not remove the expanded data from the enumeration, it changes it to relative paths???
568     if (g_WinVersion < WINVER_VISTA)
569         test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, IgnoreRoot);
570     test_ExpectDrives(EnumStr, pidlMyComputer);
571 
572     ok_hr(EnumStr->Reset(), S_OK);
573     ok_hr(hr = ACList->Expand(Buffer), S_OK);
574     test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, None);
575     test_ExpectDrives(EnumStr, pidlMyComputer);
576 }
577 
578 static void
test_ACListISF_DESKTOP()579 test_ACListISF_DESKTOP()
580 {
581     CComPtr<IEnumString> EnumStr;
582     HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr));
583     ok_hr(hr, S_OK);
584     if (!SUCCEEDED(hr))
585     {
586         skip("CoCreateInstance failed\n");
587         return;
588     }
589 
590     CComPtr<IACList2> ACList;
591     ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK);
592     if (!SUCCEEDED(hr))
593     {
594         skip("QueryInterface failed\n");
595         return;
596     }
597 
598     ok_hr(hr = ACList->SetOptions(ACLO_DESKTOP), S_OK);
599     test_ExpectFolders(EnumStr, NULL, NULL, IgnoreRoot | CheckLast | IgnoreHidden);
600 }
601 
602 static void
test_ACListISF_FAVORITES()603 test_ACListISF_FAVORITES()
604 {
605     CComPtr<IEnumString> EnumStr;
606     HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr));
607     ok_hr(hr, S_OK);
608     if (!SUCCEEDED(hr))
609     {
610         skip("CoCreateInstance failed\n");
611         return;
612     }
613 
614     CComPtr<IACList2> ACList;
615     ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK);
616     if (!SUCCEEDED(hr))
617     {
618         skip("QueryInterface failed\n");
619         return;
620     }
621 
622     CComHeapPtr<ITEMIDLIST> pidlFavorites;
623     ok_hr(hr = SHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidlFavorites), S_OK);
624     if (!SUCCEEDED(hr))
625     {
626         skip("SHGetSpecialFolderLocation failed\n");
627         return;
628     }
629 
630     ok_hr(hr = ACList->SetOptions(ACLO_FAVORITES), S_OK);
631     test_ExpectFolders(EnumStr, pidlFavorites, NULL, IgnoreRoot | CheckLast | IgnoreHidden);
632 }
633 
634 static void
test_ACListISF_FILESYSONLY()635 test_ACListISF_FILESYSONLY()
636 {
637     CComPtr<IEnumString> EnumStr;
638     HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr));
639     ok_hr(hr, S_OK);
640     if (!SUCCEEDED(hr))
641     {
642         skip("CoCreateInstance failed\n");
643         return;
644     }
645 
646     CComPtr<IACList2> ACList;
647     ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK);
648     if (!SUCCEEDED(hr))
649     {
650         skip("QueryInterface failed\n");
651         return;
652     }
653 
654     WCHAR Buffer[MAX_PATH];
655     GetSystemWindowsDirectoryW(Buffer, _ARRAYSIZE(Buffer));
656     // Windows 2k3 does not parse it without the trailing '\\'
657     Buffer[3] = '\0';
658     CComHeapPtr<ITEMIDLIST> pidlDiskRoot;
659     ok_hr(hr = SHParseDisplayName(Buffer, NULL, &pidlDiskRoot, NULL, NULL), S_OK);
660     if (!SUCCEEDED(hr))
661     {
662         skip("SHParseDisplayName failed\n");
663         return;
664     }
665 
666     ok_hr(hr = ACList->SetOptions(ACLO_FILESYSONLY), S_OK);
667     test_at_end(EnumStr);
668 
669     ok_hr(hr = ACList->Expand(Buffer), S_OK);
670     test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, CheckLast | IgnoreHidden);
671 }
672 
673 static void
test_ACListISF_FILESYSDIRS()674 test_ACListISF_FILESYSDIRS()
675 {
676     CComPtr<IEnumString> EnumStr;
677     HRESULT hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_ALL, IID_PPV_ARG(IEnumString, &EnumStr));
678     ok_hr(hr, S_OK);
679     if (!SUCCEEDED(hr))
680     {
681         skip("CoCreateInstance failed\n");
682         return;
683     }
684 
685     CComPtr<IACList2> ACList;
686     ok_hr(hr = EnumStr->QueryInterface(IID_IACList2, (void**)&ACList), S_OK);
687     if (!SUCCEEDED(hr))
688     {
689         skip("QueryInterface failed\n");
690         return;
691     }
692 
693     WCHAR Buffer[MAX_PATH];
694     GetSystemWindowsDirectoryW(Buffer, _ARRAYSIZE(Buffer));
695     // Windows 2k3 does not parse it without the trailing '\\'
696     Buffer[3] = '\0';
697     CComHeapPtr<ITEMIDLIST> pidlDiskRoot;
698     ok_hr(hr = SHParseDisplayName(Buffer, NULL, &pidlDiskRoot, NULL, NULL), S_OK);
699     if (!SUCCEEDED(hr))
700         return;
701 
702     ok_hr(hr = ACList->SetOptions(ACLO_FILESYSDIRS), S_OK);
703     test_at_end(EnumStr);
704 
705     ok_hr(hr = ACList->Expand(Buffer), S_OK);
706     test_ExpectFolders(EnumStr, pidlDiskRoot, Buffer, CheckLast | IgnoreFiles | IgnoreHidden);
707 }
708 
GetEnvStatus()709 static void GetEnvStatus()
710 {
711     RTL_OSVERSIONINFOEXW rtlinfo = {0};
712     void (__stdcall* pRtlGetVersion)(RTL_OSVERSIONINFOEXW*);
713     pRtlGetVersion = (void (__stdcall*)(RTL_OSVERSIONINFOEXW*))GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");
714 
715     rtlinfo.dwOSVersionInfoSize = sizeof(rtlinfo);
716     pRtlGetVersion(&rtlinfo);
717     g_WinVersion = (rtlinfo.dwMajorVersion << 8) | rtlinfo.dwMinorVersion;
718 
719     SHELLFLAGSTATE sfs = {0};
720     SHGetSettings(&sfs, SSF_SHOWALLOBJECTS);
721     g_ShowHidden = !!sfs.fShowAllObjects;
722     trace("Show hidden folders: %s\n", g_ShowHidden ? "yes" : "no");
723 }
724 
START_TEST(ACListISF)725 START_TEST(ACListISF)
726 {
727     GetEnvStatus();
728     CCoInit init;
729     ok_hr(init.hr, S_OK);
730     if (!SUCCEEDED(init.hr))
731     {
732         skip("CoInitialize failed\n");
733         return;
734     }
735 
736     test_ACListISF_NONE();
737     test_ACListISF_CURRENTDIR();
738     test_ACListISF_CURRENTDIR2();
739     test_ACListISF_MYCOMPUTER();
740     test_ACListISF_DESKTOP();
741     test_ACListISF_FAVORITES();
742     test_ACListISF_FILESYSONLY();
743     test_ACListISF_FILESYSDIRS();
744 }
745