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 zipfldr
5  * COPYRIGHT:   Copyright 2020 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 static bool g_bOldZipfldr = false;
11 
ok_displayname_(const char * file,int line,IShellFolder * pFolder,PCUITEMID_CHILD pidl,SHGDNF Flags,LPCWSTR Name)12 void ok_displayname_(const char* file, int line, IShellFolder* pFolder, PCUITEMID_CHILD pidl, SHGDNF Flags, LPCWSTR Name)
13 {
14     STRRET NameRet;
15     HRESULT hr;
16 
17     hr = pFolder->GetDisplayNameOf(pidl, Flags, &NameRet);
18     ok_hr_(file, line, hr, S_OK);
19     if (!SUCCEEDED(hr))
20         return;
21 
22     WCHAR DisplayName[MAX_PATH];
23     hr = StrRetToBufW(&NameRet, pidl, DisplayName, RTL_NUMBER_OF(DisplayName));
24     ok_hr_(file, line, hr, S_OK);
25     if (!SUCCEEDED(hr))
26         return;
27 
28     ok_wstr_(file, line, DisplayName, Name);
29 }
30 
31 struct ZipFiles
32 {
33     LPCWSTR Name;
34     SFGAOF Attributes;
35 };
36 
37 static CLIPFORMAT cfHIDA = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
38 static CLIPFORMAT cfFileDescriptor = RegisterClipboardFormatW(CFSTR_FILEDESCRIPTORW);
39 
test_EnumObjects_Files(const WCHAR * Filename,IShellFolder * pFolder)40 static void test_EnumObjects_Files(const WCHAR* Filename, IShellFolder* pFolder)
41 {
42     CComPtr<IEnumIDList> spEnum;
43     HRESULT hr = pFolder->EnumObjects(NULL, SHCONTF_NONFOLDERS, &spEnum);
44     ok_hr(hr, S_OK);
45     if (!SUCCEEDED(hr))
46         return;
47 
48     SFGAOF BaseAttributes = SFGAO_STREAM | SFGAO_HASPROPSHEET | SFGAO_CANDELETE | SFGAO_CANCOPY | SFGAO_CANMOVE;
49     ZipFiles ExpectedFiles[] = {
50         { L"cccc.txt", BaseAttributes },
51         { L"bbbb.txt", BaseAttributes },
52     };
53 
54     ULONG totalFetched = 0;
55     do
56     {
57         CComHeapPtr<ITEMID_CHILD> child;
58         ULONG celtFetched = 0;
59         hr = spEnum->Next(1, &child, &celtFetched);
60         if (hr != S_OK)
61             break;
62         ok_int(celtFetched, 1);
63         if (celtFetched != 1)
64             break;
65 
66         LPCWSTR ExpectedName = totalFetched < RTL_NUMBER_OF(ExpectedFiles) ? ExpectedFiles[totalFetched].Name : L"<TOO MANY FILES>";
67         SFGAOF ExpectedAttributes = totalFetched < RTL_NUMBER_OF(ExpectedFiles) ? ExpectedFiles[totalFetched].Attributes : 0xdeaddead;
68 
69         totalFetched++;
70 
71 
72         CComPtr<IDataObject> spDataObj;
73         hr = pFolder->GetUIObjectOf(NULL, 1, &child, IID_IDataObject, NULL, reinterpret_cast<LPVOID*>(&spDataObj));
74         ok_hr(hr, S_OK);
75 
76         if (!g_bOldZipfldr && !IsFormatAdvertised(spDataObj, cfHIDA, TYMED_HGLOBAL))
77         {
78             trace("Pre-Vista zipfldr\n");
79             // No seconds in filetimes, less functional IStream* implementation
80             g_bOldZipfldr = true;
81         }
82 
83         ok_displayname(pFolder, child, SHGDN_NORMAL, ExpectedName);
84         if (g_bOldZipfldr)
85         {
86             ok_displayname(pFolder, child, SHGDN_FORPARSING, ExpectedName);
87         }
88         else
89         {
90             WCHAR Buffer[MAX_PATH];
91             StringCchPrintfW(Buffer, _countof(Buffer), L"%s\\%s", Filename, ExpectedName);
92             ok_displayname(pFolder, child, SHGDN_FORPARSING, Buffer);
93         }
94         ok_displayname(pFolder, child, SHGDN_FORPARSING | SHGDN_INFOLDER, ExpectedName);
95         ok_displayname(pFolder, child, SHGDN_FOREDITING , ExpectedName);
96         ok_displayname(pFolder, child, SHGDN_FOREDITING | SHGDN_INFOLDER, ExpectedName);
97         ok_displayname(pFolder, child, SHGDN_FORADDRESSBAR , ExpectedName);
98         ok_displayname(pFolder, child, SHGDN_FORADDRESSBAR | SHGDN_INFOLDER, ExpectedName);
99 
100         SFGAOF Attributes = 0;
101         hr = pFolder->GetAttributesOf(1, &child, &Attributes);
102         ok_hr(hr, S_OK);
103         ok_hex(Attributes, ExpectedAttributes);
104 
105         STGMEDIUM medium = {0};
106         FORMATETC etc = { cfFileDescriptor, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
107         HRESULT hr = spDataObj->GetData(&etc, &medium);
108         ok_hex(hr, S_OK);
109         if (!SUCCEEDED(hr))
110             continue;
111 
112         ok_hex(medium.tymed, TYMED_HGLOBAL);
113         PVOID pData = GlobalLock(medium.hGlobal);
114         FILEGROUPDESCRIPTORW* Descriptor = static_cast<FILEGROUPDESCRIPTORW*>(pData);
115         ok_hex(Descriptor->cItems, 1);
116         if (Descriptor->cItems == 1)
117             ok_wstr(Descriptor->fgd[0].cFileName, ExpectedName);
118         GlobalUnlock(medium.hGlobal);
119         ReleaseStgMedium(&medium);
120     } while (true);
121 
122     ok_int(totalFetched, RTL_NUMBER_OF(ExpectedFiles));
123     ok_hr(hr, S_FALSE);
124 }
125 
test_EnumObjects_Folders(const WCHAR * Filename,IShellFolder * pFolder)126 static void test_EnumObjects_Folders(const WCHAR* Filename, IShellFolder* pFolder)
127 {
128     CComPtr<IEnumIDList> spEnum;
129     HRESULT hr = pFolder->EnumObjects(NULL, SHCONTF_FOLDERS, &spEnum);
130     ok_hr(hr, S_OK);
131     if (!SUCCEEDED(hr))
132         return;
133 
134     SFGAOF BaseAttributes = SFGAO_FOLDER | SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANDELETE | SFGAO_CANCOPY | SFGAO_CANMOVE;
135     ZipFiles ExpectedFolders[] = {
136         { L"aaaa", BaseAttributes | (g_bOldZipfldr ? 0 : SFGAO_STORAGE) },
137         { L"cccc", BaseAttributes | (g_bOldZipfldr ? 0 : SFGAO_STORAGE) },
138     };
139 
140     LPCWSTR ExpectedExtraFiles[2][4] =
141     {
142         {
143             L"aaaa\\a_aaaa",
144             L"aaaa\\a_cccc",
145             L"aaaa\\a_bbbb.txt",
146             L"aaaa\\a_cccc.txt",
147         },
148         {
149             L"cccc\\c_cccc",
150             L"cccc\\c_bbbb.txt",
151             L"cccc\\c_cccc.txt",
152             L"cccc\\c_aaaa",
153         },
154     };
155 
156     ULONG totalFetched = 0;
157     do
158     {
159         CComHeapPtr<ITEMID_CHILD> child;
160         ULONG celtFetched = 0;
161         hr = spEnum->Next(1, &child, &celtFetched);
162         if (hr != S_OK)
163             break;
164         ok_int(celtFetched, 1);
165         if (celtFetched != 1)
166             break;
167 
168         LPCWSTR ExpectedName = totalFetched < RTL_NUMBER_OF(ExpectedFolders) ? ExpectedFolders[totalFetched].Name : L"<TOO MANY FILES>";
169         SFGAOF ExpectedAttributes = totalFetched < RTL_NUMBER_OF(ExpectedFolders) ? ExpectedFolders[totalFetched].Attributes : 0xdeaddead;
170         LPCWSTR* ExtraFiles = totalFetched < RTL_NUMBER_OF(ExpectedExtraFiles) ? ExpectedExtraFiles[totalFetched] : ExpectedExtraFiles[0];
171 
172         totalFetched++;
173 
174         ok_displayname(pFolder, child, SHGDN_NORMAL, ExpectedName);
175         if (g_bOldZipfldr)
176         {
177             ok_displayname(pFolder, child, SHGDN_FORPARSING, ExpectedName);
178         }
179         else
180         {
181             WCHAR Buffer[MAX_PATH];
182             StringCchPrintfW(Buffer, _countof(Buffer), L"%s\\%s", Filename, ExpectedName);
183             ok_displayname(pFolder, child, SHGDN_FORPARSING, Buffer);
184         }
185         ok_displayname(pFolder, child, SHGDN_FORPARSING | SHGDN_INFOLDER, ExpectedName);
186         ok_displayname(pFolder, child, SHGDN_FOREDITING , ExpectedName);
187         ok_displayname(pFolder, child, SHGDN_FOREDITING | SHGDN_INFOLDER, ExpectedName);
188 
189         SFGAOF Attributes = 0;
190         hr = pFolder->GetAttributesOf(1, &child, &Attributes);
191         ok_hr(hr, S_OK);
192         ok_hex(Attributes, ExpectedAttributes);
193 
194         CComPtr<IDataObject> spData;
195         hr = pFolder->GetUIObjectOf(NULL, 1, &child, IID_IDataObject, NULL, reinterpret_cast<LPVOID*>(&spData));
196         ok_hr(hr, S_OK);
197 
198         STGMEDIUM medium = {0};
199         FORMATETC etc = { cfFileDescriptor, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
200         HRESULT hr = spData->GetData(&etc, &medium);
201         ok_hex(hr, S_OK);
202         if (!SUCCEEDED(hr))
203             continue;
204 
205         ok_hex(medium.tymed, TYMED_HGLOBAL);
206         PVOID pData = GlobalLock(medium.hGlobal);
207         FILEGROUPDESCRIPTORW* Descriptor = static_cast<FILEGROUPDESCRIPTORW*>(pData);
208         ok_hex(Descriptor->cItems, 5);
209         if (Descriptor->cItems == 5)
210         {
211             ok_wstr(Descriptor->fgd[0].cFileName, ExpectedName);
212             ok_wstr(Descriptor->fgd[1].cFileName, ExtraFiles[0]);
213             ok_wstr(Descriptor->fgd[2].cFileName, ExtraFiles[1]);
214             ok_wstr(Descriptor->fgd[3].cFileName, ExtraFiles[2]);
215             ok_wstr(Descriptor->fgd[4].cFileName, ExtraFiles[3]);
216         }
217         GlobalUnlock(medium.hGlobal);
218         ReleaseStgMedium(&medium);
219     } while (true);
220 
221     ok_int(totalFetched, RTL_NUMBER_OF(ExpectedFolders));
222     ok_hr(hr, S_FALSE);
223 }
224 
test_EnumObjects(const WCHAR * Filename)225 static void test_EnumObjects(const WCHAR* Filename)
226 {
227     CComPtr<IShellFolder> spFolder;
228     if (!InitializeShellFolder(Filename, spFolder))
229         return;
230 
231     // Let's ask the shell how it wants to display the full path to our zip file
232     WCHAR ZipFilename[MAX_PATH] = L"<Failed to query zip path>";
233     {
234         CComPtr<IPersistFolder2> spPersistFolder;
235         HRESULT hr = spFolder->QueryInterface(IID_PPV_ARG(IPersistFolder2, &spPersistFolder));
236         ok_hr(hr, S_OK);
237         if (SUCCEEDED(hr))
238         {
239             CComHeapPtr<ITEMIDLIST_ABSOLUTE> zipPidl;
240             hr = spPersistFolder->GetCurFolder(&zipPidl);
241             ok_hr(hr, S_OK);
242             if (SUCCEEDED(hr))
243             {
244                 BOOL bHasPath = SHGetPathFromIDListW(zipPidl, ZipFilename);
245                 ok_int(bHasPath, TRUE);
246             }
247         }
248     }
249 
250 
251     test_EnumObjects_Files(ZipFilename, spFolder);
252     test_EnumObjects_Folders(ZipFilename, spFolder);
253 }
254 
START_TEST(EnumObjects)255 START_TEST(EnumObjects)
256 {
257     skip("Code in zipfldr not implemented yet\n");
258     return;
259 
260     HRESULT hr = CoInitialize(NULL);
261 
262     ok_hr(hr, S_OK);
263     if (!SUCCEEDED(hr))
264         return;
265 
266     WCHAR ZipTestFile[MAX_PATH];
267     if (!extract_resource(ZipTestFile, MAKEINTRESOURCEW(IDR_ZIP_TEST_ENUM), NULL))
268         return;
269     test_EnumObjects(ZipTestFile);
270     DeleteFileW(ZipTestFile);
271     CoUninitialize();
272 }
273