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 #ifndef FILE_ATTRIBUTE_VIRTUAL
11 #define FILE_ATTRIBUTE_VIRTUAL 0x10000
12 #endif
13 
14 DEFINE_GUID(CLSID_ZipFolderContextMenu,    0xb8cdcb65, 0xb1bf, 0x4b42, 0x94, 0x28, 0x1d, 0xfd, 0xb7, 0xee, 0x92, 0xaf);
15 
16 
17 static bool g_bOldZipfldr;
18 const char test_file_1_contents[] = "Some generic text in the root file.\r\nMore text on a new line.";
19 const char test_file_2_contents[] = "Some generic text in the file in folder_1.\r\nMore text on a new line.";
20 
21 static BOOL write_raw_file(const WCHAR* FileName, const void* Data, DWORD Size)
22 {
23     BOOL Success;
24     DWORD dwWritten;
25     HANDLE Handle = CreateFileW(FileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
26 
27     if (Handle == INVALID_HANDLE_VALUE)
28     {
29         skip("Failed to create temp file %ls, error %lu\n", FileName, GetLastError());
30         return FALSE;
31     }
32     Success = WriteFile(Handle, Data, Size, &dwWritten, NULL);
33     ok(Success == TRUE, "WriteFile failed with %lu\n", GetLastError());
34     ok(dwWritten == Size, "WriteFile wrote %lu bytes instead of %lu\n", dwWritten, Size);
35     CloseHandle(Handle);
36     return Success && (dwWritten == Size);
37 }
38 
39 BOOL extract_resource(WCHAR* Filename, LPCWSTR ResourceName, WCHAR* ParentFolder)
40 {
41     WCHAR workdir[MAX_PATH];
42     UINT TickMask = 0xffff;
43     if (!ParentFolder)
44     {
45         GetTempPathW(_countof(workdir), workdir);
46         ParentFolder = workdir;
47     }
48     else
49     {
50         // Fixed filename
51         TickMask = 0;
52     }
53     StringCchPrintfW(Filename, MAX_PATH, L"%sTMP%u.zip", ParentFolder, GetTickCount() & TickMask);
54 
55     HMODULE hMod = GetModuleHandleW(NULL);
56     HRSRC hRsrc = FindResourceW(hMod, ResourceName, MAKEINTRESOURCEW(RT_RCDATA));
57     ok(!!hRsrc, "Unable to find %s\n", wine_dbgstr_w(ResourceName));
58     if (!hRsrc)
59         return FALSE;
60 
61     HGLOBAL hGlobal = LoadResource(hMod, hRsrc);
62     DWORD Size = SizeofResource(hMod, hRsrc);
63     LPVOID pData = LockResource(hGlobal);
64 
65     ok(Size && !!pData, "Unable to load %s\n", wine_dbgstr_w(ResourceName));
66     if (!Size || !pData)
67         return FALSE;
68 
69     BOOL Written = write_raw_file(Filename, pData, Size);
70     UnlockResource(pData);
71     return Written;
72 }
73 
74 bool InitializeShellFolder_(const char* file, int line, const WCHAR* Filename, CComPtr<IShellFolder>& spFolder)
75 {
76     CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidl;
77     HRESULT hr;
78     ok_hr_(file, line, (hr = SHParseDisplayName(Filename, NULL, &pidl, 0, NULL)), S_OK);
79     if (!SUCCEEDED(hr))
80         return false;
81 
82     CComPtr<IShellFolder> spParent;
83     PCUIDLIST_RELATIVE pidlLast;
84     ok_hr_(file, line, (hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &spParent), &pidlLast)), S_OK);
85     if (!SUCCEEDED(hr))
86         return false;
87 
88     ok_hr_(file, line, (hr = spParent->BindToObject(pidlLast, 0, IID_PPV_ARG(IShellFolder, &spFolder))), S_OK);
89 
90     return SUCCEEDED(hr);
91 }
92 
93 #define GetFirstDataObject(spFolder, grfFlags, spData)      GetFirstDataObject_(__FILE__, __LINE__, spFolder, grfFlags, spData)
94 static bool GetFirstDataObject_(const char* file, int line, IShellFolder* spFolder, SHCONTF grfFlags, CComPtr<IDataObject>& spData)
95 {
96     CComPtr<IEnumIDList> spEnum;
97     HRESULT hr;
98     ok_hr_(file, line, (hr = spFolder->EnumObjects(NULL, grfFlags, &spEnum)), S_OK);
99     if (!SUCCEEDED(hr))
100         return false;
101 
102     CComHeapPtr<ITEMID_CHILD> child;
103     ULONG celtFetched = 0;
104     ok_hr_(file, line, (hr = spEnum->Next(1, &child, &celtFetched)), S_OK);
105     ok_int_(file, line, celtFetched, 1);
106     if (!SUCCEEDED(hr))
107         return false;
108 
109     // This call fails without the extension being '.zip'
110     ok_hr_(file, line, (hr = spFolder->GetUIObjectOf(NULL, 1, &child, IID_IDataObject, NULL, reinterpret_cast<LPVOID*>(&spData))), S_OK);
111     return SUCCEEDED(hr);
112 }
113 
114 bool IsFormatAdvertised_(const char* file, int line, IDataObject* pDataObj, CLIPFORMAT cfFormat, TYMED tymed)
115 {
116     CComPtr<IEnumFORMATETC> pEnumFmt;
117     HRESULT hr = pDataObj->EnumFormatEtc(DATADIR_GET, &pEnumFmt);
118 
119     ok_hex_(file, line, hr, S_OK);
120     if (!SUCCEEDED(hr))
121         return false;
122 
123     FORMATETC fmt;
124     while (S_OK == (hr = pEnumFmt->Next(1, &fmt, NULL)))
125     {
126         if (fmt.cfFormat == cfFormat)
127         {
128             ok_hex_(file, line, fmt.lindex, -1);
129             if (tymed)
130                 ok_hex_(file, line, fmt.tymed, tymed);
131             return true;
132         }
133     }
134     ok_hex_(file, line, hr, S_FALSE);
135     return false;
136 }
137 
138 #if 0
139 #define DumpDataObjectFormats(pDataObj) DumpDataObjectFormats_(__FILE__, __LINE__, pDataObj)
140 static inline void DumpDataObjectFormats_(const char* file, int line, IDataObject* pDataObj)
141 {
142     CComPtr<IEnumFORMATETC> pEnumFmt;
143     HRESULT hr = pDataObj->EnumFormatEtc(DATADIR_GET, &pEnumFmt);
144 
145     if (FAILED_UNEXPECTEDLY(hr))
146         return;
147 
148     FORMATETC fmt;
149     while (S_OK == pEnumFmt->Next(1, &fmt, NULL))
150     {
151         char szBuf[512];
152         GetClipboardFormatNameA(fmt.cfFormat, szBuf, sizeof(szBuf));
153         trace_(file, line)("Format: %s\n", szBuf);
154         trace_(file, line)(" Tymed: %u\n", fmt.tymed);
155         if (fmt.tymed & TYMED_HGLOBAL)
156         {
157             trace_(file, line)(" TYMED_HGLOBAL supported\n");
158         }
159     }
160 }
161 #endif
162 
163 static void test_FileDescriptor(FILEGROUPDESCRIPTORW* Descriptor)
164 {
165     ok_int(Descriptor->cItems, 1u);
166     if (Descriptor->cItems > 0)
167     {
168         FILETIME LocalFileTime, FileTime;
169         WORD Mask = g_bOldZipfldr ? 0xffe0 : (0xffff);   // bits 0-4 are the seconds
170         DosDateTimeToFileTime(0x5024, (0xa5f2 & Mask), &LocalFileTime);
171         LocalFileTimeToFileTime(&LocalFileTime, &FileTime);
172 
173         FILEDESCRIPTORW* FileDescriptor = Descriptor->fgd;
174         ok_hex(FileDescriptor->dwFlags, FD_ATTRIBUTES | FD_WRITESTIME | FD_FILESIZE | FD_PROGRESSUI);
175         ok_hex(FileDescriptor->dwFileAttributes, FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_VIRTUAL);
176         ok_hex(FileDescriptor->ftLastWriteTime.dwHighDateTime, FileTime.dwHighDateTime);
177         ok_hex(FileDescriptor->ftLastWriteTime.dwLowDateTime, FileTime.dwLowDateTime);
178         ok_hex(FileDescriptor->nFileSizeHigh, 0);
179         ok_hex(FileDescriptor->nFileSizeLow, strlen(test_file_1_contents));
180         ok_wstr(FileDescriptor->cFileName, L"test_file_for_zip.txt");
181     }
182 }
183 
184 static void test_FileDescriptor_Folder(FILEGROUPDESCRIPTORW* Descriptor)
185 {
186     ok_int(Descriptor->cItems, 2u);
187     if (Descriptor->cItems > 0)
188     {
189         FILETIME LocalFileTime, FileTime;
190         WORD Mask = g_bOldZipfldr ? 0xffe0 : (0xffff);   // bits 0-4 are the seconds
191         DosDateTimeToFileTime(0x5024, (0xa5fc & Mask), &LocalFileTime);
192         LocalFileTimeToFileTime(&LocalFileTime, &FileTime);
193 
194         FILEDESCRIPTORW* FileDescriptor = Descriptor->fgd;
195         ok_hex(FileDescriptor->dwFlags, FD_ATTRIBUTES | FD_WRITESTIME | FD_FILESIZE | FD_PROGRESSUI);
196         ok(FileDescriptor->dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY ||
197            FileDescriptor->dwFileAttributes == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_VIRTUAL), "Got attr: 0x%lx\n", FileDescriptor->dwFileAttributes);
198         //ok_hex(FileDescriptor->dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY);
199         ok_hex(FileDescriptor->ftLastWriteTime.dwHighDateTime, FileTime.dwHighDateTime);
200         ok_hex(FileDescriptor->ftLastWriteTime.dwLowDateTime, FileTime.dwLowDateTime);
201         ok_hex(FileDescriptor->nFileSizeHigh, 0);
202         ok_hex(FileDescriptor->nFileSizeLow, 0);
203         ok_wstr(FileDescriptor->cFileName, L"folder_1");
204 
205         if (Descriptor->cItems > 1)
206         {
207             DosDateTimeToFileTime(0x5024, (0xa60d & Mask), &LocalFileTime);
208             LocalFileTimeToFileTime(&LocalFileTime, &FileTime);
209 
210             FileDescriptor = Descriptor->fgd + 1;
211             ok_hex(FileDescriptor->dwFlags, FD_ATTRIBUTES | FD_WRITESTIME | FD_FILESIZE | FD_PROGRESSUI);
212             ok_hex(FileDescriptor->dwFileAttributes, FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_VIRTUAL);
213             ok_hex(FileDescriptor->ftLastWriteTime.dwHighDateTime, FileTime.dwHighDateTime);
214             ok_hex(FileDescriptor->ftLastWriteTime.dwLowDateTime, FileTime.dwLowDateTime);
215             ok_hex(FileDescriptor->nFileSizeHigh, 0);
216             ok_hex(FileDescriptor->nFileSizeLow, strlen(test_file_2_contents));
217             ok_wstr(FileDescriptor->cFileName, L"folder_1\\test_file_for_zip.txt");
218         }
219     }
220 }
221 
222 static GUID GUID_NULL_;
223 static void test_FileContents1(IStream* Stream)
224 {
225     STATSTG statstg = {0};
226     HRESULT hr = Stream->Stat(&statstg, STATFLAG_DEFAULT);
227     ok_hex(hr, g_bOldZipfldr ? E_NOTIMPL : S_OK);
228     if (SUCCEEDED(hr))
229     {
230         FILETIME LocalFileTime, FileTime;
231         WORD Mask = g_bOldZipfldr ? 0xffe0 : (0xffff);   // bits 0-4 are the seconds
232         DosDateTimeToFileTime(0x5024, (0xa5f2 & Mask), &LocalFileTime);
233         LocalFileTimeToFileTime(&LocalFileTime, &FileTime);
234 
235         ok_wstr(statstg.pwcsName, L"test_file_for_zip.txt");
236         ok_hex(statstg.type, STGTY_STREAM);
237         ok_int(statstg.cbSize.LowPart, strlen(test_file_1_contents));
238         ok_hex(statstg.cbSize.HighPart, 0);
239         ok_hex(statstg.mtime.dwHighDateTime, FileTime.dwHighDateTime);
240         ok_hex(statstg.mtime.dwLowDateTime, FileTime.dwLowDateTime);
241         ok_hex(statstg.ctime.dwHighDateTime, FileTime.dwHighDateTime);
242         ok_hex(statstg.ctime.dwLowDateTime, FileTime.dwLowDateTime);
243         ok_hex(statstg.atime.dwHighDateTime, FileTime.dwHighDateTime);
244         ok_hex(statstg.atime.dwLowDateTime, FileTime.dwLowDateTime);
245         ok_hex(statstg.grfMode, STGM_SHARE_DENY_WRITE);
246         ok_hex(statstg.grfLocksSupported, 0);
247         ok(!memcmp(&statstg.clsid, &GUID_NULL_, sizeof(GUID_NULL_)), "Expected GUID_NULL, got %s\n", wine_dbgstr_guid(&statstg.clsid));
248         ok_hex(statstg.grfStateBits, 0);
249         CoTaskMemFree(statstg.pwcsName);
250     }
251 
252     LARGE_INTEGER Offset = { {0} };
253     ULARGE_INTEGER NewPosition = { {0} };
254     hr = Stream->Seek(Offset, STREAM_SEEK_CUR, &NewPosition);
255     ok_hex(hr, g_bOldZipfldr ? E_NOTIMPL : S_OK);
256     ok_int(NewPosition.HighPart, 0);
257     ok_int(NewPosition.LowPart, 0);
258 
259     char buf[100] = { 0 };
260     ULONG cbRead;
261     hr = Stream->Read(buf, sizeof(buf)-1, &cbRead);
262     ok_hex(hr, S_FALSE);
263     ok_int(cbRead, strlen(test_file_1_contents));
264     ok_str(buf, test_file_1_contents);
265 
266     hr = Stream->Seek(Offset, STREAM_SEEK_CUR, &NewPosition);
267     ok_hex(hr, g_bOldZipfldr ? E_NOTIMPL : S_OK);
268     ok_int(NewPosition.HighPart, 0);
269     if (SUCCEEDED(hr))
270         ok_int(NewPosition.LowPart, strlen(test_file_1_contents));
271 
272     ULONG cbWritten;
273     hr = Stream->Write("DUMMY", 5, &cbWritten);
274     if (!g_bOldZipfldr)
275     {
276         ok_hex(hr, STG_E_ACCESSDENIED);
277     }
278     else
279     {
280         // Write succeeds, but is not reflected in the file on disk
281         ok_hex(hr, S_OK);
282     }
283 
284     // Can increase the size...
285     NewPosition.LowPart = statstg.cbSize.LowPart + 1;
286     hr = Stream->SetSize(NewPosition);
287     ok_hex(hr, g_bOldZipfldr ? E_NOTIMPL : S_OK);
288 
289     // But is not reflected in the Stat result
290     hr = Stream->Stat(&statstg, STATFLAG_DEFAULT);
291     ok_hex(hr, g_bOldZipfldr ? E_NOTIMPL : S_OK);
292     if (SUCCEEDED(hr))
293     {
294         ok_int(statstg.cbSize.LowPart, strlen(test_file_1_contents));
295         CoTaskMemFree(statstg.pwcsName);
296     }
297 
298     // Old zipfldr does not support seek, so we can not read it again
299     if (!g_bOldZipfldr)
300     {
301         Offset.QuadPart = 0;
302         hr = Stream->Seek(Offset, STREAM_SEEK_SET, &NewPosition);
303         ok_hex(hr, S_OK);
304 
305         memset(buf, 0, sizeof(buf));
306         hr = Stream->Read(buf, sizeof(buf)-1, &cbRead);
307         ok_hex(hr, S_FALSE);
308         ok_int(cbRead, strlen(test_file_1_contents));
309     }
310 }
311 
312 
313 static void test_FileContents2(IStream* Stream)
314 {
315     STATSTG statstg = {0};
316     HRESULT hr = Stream->Stat(&statstg, STATFLAG_DEFAULT);
317     ok_hex(hr, g_bOldZipfldr ? E_NOTIMPL : S_OK);
318     if (SUCCEEDED(hr))
319     {
320         FILETIME LocalFileTime, FileTime;
321         WORD Mask = g_bOldZipfldr ? 0xffe0 : (0xffff);   // bits 0-4 are the seconds
322         DosDateTimeToFileTime(0x5024, (0xa60d & Mask), &LocalFileTime);
323         LocalFileTimeToFileTime(&LocalFileTime, &FileTime);
324 
325         ok_wstr(statstg.pwcsName, L"test_file_for_zip.txt");
326         ok_hex(statstg.type, STGTY_STREAM);
327         ok_int(statstg.cbSize.LowPart, strlen(test_file_2_contents));
328         ok_hex(statstg.cbSize.HighPart, 0);
329         ok_hex(statstg.mtime.dwHighDateTime, FileTime.dwHighDateTime);
330         ok_hex(statstg.mtime.dwLowDateTime, FileTime.dwLowDateTime);
331         ok_hex(statstg.ctime.dwHighDateTime, FileTime.dwHighDateTime);
332         ok_hex(statstg.ctime.dwLowDateTime, FileTime.dwLowDateTime);
333         ok_hex(statstg.atime.dwHighDateTime, FileTime.dwHighDateTime);
334         ok_hex(statstg.atime.dwLowDateTime, FileTime.dwLowDateTime);
335         ok_hex(statstg.grfMode, STGM_SHARE_DENY_WRITE);
336         ok_hex(statstg.grfLocksSupported, 0);
337         ok(!memcmp(&statstg.clsid, &GUID_NULL_, sizeof(GUID_NULL_)), "Expected GUID_NULL, got %s\n", wine_dbgstr_guid(&statstg.clsid));
338         ok_hex(statstg.grfStateBits, 0);
339         CoTaskMemFree(statstg.pwcsName);
340     }
341 
342     LARGE_INTEGER Offset = { {0} };
343     ULARGE_INTEGER NewPosition = { {0} };
344     hr = Stream->Seek(Offset, STREAM_SEEK_CUR, &NewPosition);
345     ok_hex(hr, g_bOldZipfldr ? E_NOTIMPL : S_OK);
346     ok_int(NewPosition.HighPart, 0);
347     ok_int(NewPosition.LowPart, 0);
348 
349     char buf[100] = { 0 };
350     ULONG cbRead;
351     hr = Stream->Read(buf, sizeof(buf)-1, &cbRead);
352     ok_hex(hr, S_FALSE);
353     ok_int(cbRead, strlen(test_file_2_contents));
354     ok_str(buf, test_file_2_contents);
355 
356     hr = Stream->Seek(Offset, STREAM_SEEK_CUR, &NewPosition);
357     ok_hex(hr, g_bOldZipfldr ? E_NOTIMPL : S_OK);
358     ok_int(NewPosition.HighPart, 0);
359     if (SUCCEEDED(hr))
360         ok_int(NewPosition.LowPart, strlen(test_file_2_contents));
361 
362     ULONG cbWritten;
363     hr = Stream->Write("DUMMY", 5, &cbWritten);
364     if (!g_bOldZipfldr)
365     {
366         ok_hex(hr, STG_E_ACCESSDENIED);
367     }
368     else
369     {
370         // Write succeeds, but is not reflected in the file on disk
371         ok_hex(hr, S_OK);
372     }
373 
374     // Can increase the size...
375     NewPosition.LowPart = statstg.cbSize.LowPart + 1;
376     hr = Stream->SetSize(NewPosition);
377     ok_hex(hr, g_bOldZipfldr ? E_NOTIMPL : S_OK);
378 
379     // But is not reflected in the Stat result
380     hr = Stream->Stat(&statstg, STATFLAG_DEFAULT);
381     ok_hex(hr, g_bOldZipfldr ? E_NOTIMPL : S_OK);
382     if (SUCCEEDED(hr))
383     {
384         ok_int(statstg.cbSize.LowPart, strlen(test_file_2_contents));
385         CoTaskMemFree(statstg.pwcsName);
386     }
387 
388     // Old zipfldr does not support seek, so we can not read it again
389     if (!g_bOldZipfldr)
390     {
391         Offset.QuadPart = 0;
392         hr = Stream->Seek(Offset, STREAM_SEEK_SET, &NewPosition);
393         ok_hex(hr, S_OK);
394 
395         memset(buf, 0, sizeof(buf));
396         hr = Stream->Read(buf, sizeof(buf)-1, &cbRead);
397         ok_hex(hr, S_FALSE);
398         ok_int(cbRead, strlen(test_file_2_contents));
399         ok_str(buf, test_file_2_contents);
400     }
401 }
402 
403 
404 
405 static CLIPFORMAT cfHIDA = RegisterClipboardFormatA(CFSTR_SHELLIDLISTA);
406 static CLIPFORMAT cfFileDescriptor = RegisterClipboardFormatW(CFSTR_FILEDESCRIPTORW);
407 static CLIPFORMAT cfFileContents = RegisterClipboardFormatW(CFSTR_FILECONTENTSW);
408 
409 static void test_DataObject_FirstFile(IShellFolder* pFolder)
410 {
411     CComPtr<IDataObject> spDataObj;
412     if (!GetFirstDataObject(pFolder, SHCONTF_NONFOLDERS, spDataObj))
413         return;
414 
415     if (!IsFormatAdvertised(spDataObj, cfHIDA, TYMED_HGLOBAL))
416     {
417         trace("Pre-Vista zipfldr\n");
418         // No seconds in filetimes, less functional IStream* implementation
419         g_bOldZipfldr = true;
420     }
421 
422     ok(!IsFormatAdvertised(spDataObj, CF_HDROP, TYMED_NULL), "Expected CF_HDROP to be absent\n");
423     ok(IsFormatAdvertised(spDataObj, cfFileDescriptor, TYMED_HGLOBAL), "Expected FileDescriptorW to be supported\n");
424     ok(IsFormatAdvertised(spDataObj, cfFileContents, TYMED_ISTREAM), "Expected FileContents to be supported\n");
425 
426     STGMEDIUM medium = {0};
427     FORMATETC etc = { cfFileDescriptor, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
428     HRESULT hr = spDataObj->GetData(&etc, &medium);
429     ok_hex(hr, S_OK);
430     if (!SUCCEEDED(hr))
431         return;
432 
433     ok_hex(medium.tymed, TYMED_HGLOBAL);
434     PVOID pData = GlobalLock(medium.hGlobal);
435     test_FileDescriptor(static_cast<FILEGROUPDESCRIPTORW*>(pData));
436     GlobalUnlock(medium.hGlobal);
437     ReleaseStgMedium(&medium);
438 
439     // Invalid index
440     etc.cfFormat = cfFileContents;
441     etc.ptd = NULL;
442     etc.dwAspect = DVASPECT_CONTENT;
443     etc.lindex = -1;
444     etc.tymed = TYMED_ISTREAM;
445     memset(&medium, 0xcc, sizeof(medium));
446     hr = spDataObj->GetData(&etc, &medium);
447     ok_hex(hr, E_INVALIDARG);
448     ok_hex(medium.tymed, TYMED_NULL);
449     ok_ptr(medium.hGlobal, NULL);
450     ok_ptr(medium.pUnkForRelease, NULL);
451     if (SUCCEEDED(hr))
452         ReleaseStgMedium(&medium);
453 
454     // Correct index
455     etc.cfFormat = cfFileContents;
456     etc.ptd = NULL;
457     etc.dwAspect = DVASPECT_CONTENT;
458     etc.lindex = 0;
459     etc.tymed = TYMED_ISTREAM;
460     memset(&medium, 0xcc, sizeof(medium));
461     // During this call a temp file is created: %TMP%\Temp%u_%s\test_file_for_zip.txt
462     // Or for the 2k3 version:                  %TMP%\Temporary Directory %u for %s\test_file_for_zip.txt
463     hr = spDataObj->GetData(&etc, &medium);
464     ok_hex(hr, S_OK);
465     ok_hex(medium.tymed, TYMED_ISTREAM);
466     if (SUCCEEDED(hr))
467     {
468         test_FileContents1(medium.pstm);
469         ReleaseStgMedium(&medium);
470     }
471 
472     //if (winetest_get_failures())
473     //    DumpDataObjectFormats(spDataObj);
474 }
475 
476 static void test_DataObject_FirstFolder(IShellFolder* pFolder)
477 {
478     CComPtr<IDataObject> spDataObj;
479     if (!GetFirstDataObject(pFolder, SHCONTF_FOLDERS, spDataObj))
480         return;
481 
482     ok(!IsFormatAdvertised(spDataObj, CF_HDROP, TYMED_NULL), "Expected CF_HDROP to be absent\n");
483     ok(IsFormatAdvertised(spDataObj, cfFileDescriptor, TYMED_HGLOBAL), "Expected FileDescriptorW to be supported\n");
484     ok(IsFormatAdvertised(spDataObj, cfFileContents, TYMED_ISTREAM), "Expected FileContents to be supported\n");
485     // 7+
486     ok(!!IsFormatAdvertised(spDataObj, cfHIDA, TYMED_HGLOBAL) != g_bOldZipfldr, "Expected HIDA to be %s\n", g_bOldZipfldr ? "absent" : "supported");
487 
488     STGMEDIUM medium = {0};
489     FORMATETC etc = { cfFileDescriptor, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
490     HRESULT hr = spDataObj->GetData(&etc, &medium);
491     ok_hex(hr, S_OK);
492     if (!SUCCEEDED(hr))
493         return;
494 
495     ok_hex(medium.tymed, TYMED_HGLOBAL);
496     PVOID pData = GlobalLock(medium.hGlobal);
497     test_FileDescriptor_Folder(static_cast<FILEGROUPDESCRIPTORW*>(pData));
498     GlobalUnlock(medium.hGlobal);
499     ReleaseStgMedium(&medium);
500 
501     // Invalid index
502     etc.cfFormat = cfFileContents;
503     etc.ptd = NULL;
504     etc.dwAspect = DVASPECT_CONTENT;
505     etc.lindex = -1;
506     etc.tymed = TYMED_ISTREAM;
507     memset(&medium, 0xcc, sizeof(medium));
508     hr = spDataObj->GetData(&etc, &medium);
509     ok_hex(hr, E_INVALIDARG);
510     ok_hex(medium.tymed, TYMED_NULL);
511     ok_ptr(medium.hGlobal, NULL);
512     ok_ptr(medium.pUnkForRelease, NULL);
513     if (SUCCEEDED(hr))
514         ReleaseStgMedium(&medium);
515 
516     // Not a file (first index is the folder)
517     etc.cfFormat = cfFileContents;
518     etc.ptd = NULL;
519     etc.dwAspect = DVASPECT_CONTENT;
520     etc.lindex = 0;
521     etc.tymed = TYMED_ISTREAM;
522     memset(&medium, 0xcc, sizeof(medium));
523     hr = spDataObj->GetData(&etc, &medium);
524     ok_hex(hr, E_FAIL);
525     ok_hex(medium.tymed, TYMED_NULL);
526     ok_ptr(medium.hGlobal, NULL);
527     ok_ptr(medium.pUnkForRelease, NULL);
528     if (SUCCEEDED(hr))
529         ReleaseStgMedium(&medium);
530 
531     // The file (content of the folder)
532     etc.cfFormat = cfFileContents;
533     etc.ptd = NULL;
534     etc.dwAspect = DVASPECT_CONTENT;
535     etc.lindex = 1;
536     etc.tymed = TYMED_ISTREAM;
537     memset(&medium, 0xcc, sizeof(medium));
538     // During this call a temp file is created: %TMP%\Temp%u_%s\folder1\test_file_for_zip.txt
539     // Or for the 2k3 version:                  %TMP%\Temporary Directory %u for %s\folder1\test_file_for_zip.txt
540     hr = spDataObj->GetData(&etc, &medium);
541     ok_hex(hr, S_OK);
542     ok_hex(medium.tymed, TYMED_ISTREAM);
543     if (SUCCEEDED(hr))
544     {
545         test_FileContents2(medium.pstm);
546         ReleaseStgMedium(&medium);
547     }
548 
549     //if (winetest_get_failures())
550     //    DumpDataObjectFormats(spDataObj);
551 }
552 
553 
554 static void test_DataObject(const WCHAR* Filename)
555 {
556     CComPtr<IShellFolder> spFolder;
557     if (!InitializeShellFolder(Filename, spFolder))
558         return;
559 
560     test_DataObject_FirstFile(spFolder);
561     test_DataObject_FirstFolder(spFolder);
562 }
563 
564 
565 START_TEST(IDataObject)
566 {
567     skip("Code in zipfldr not implemented yet\n");
568     return;
569 
570     HRESULT hr = CoInitialize(NULL);
571 
572     ok_hr(hr, S_OK);
573     if (!SUCCEEDED(hr))
574         return;
575 
576     WCHAR ZipTestFile[MAX_PATH];
577     if (!extract_resource(ZipTestFile, MAKEINTRESOURCEW(IDR_ZIP_TEST_FILE), NULL))
578         return;
579     test_DataObject(ZipTestFile);
580     DeleteFileW(ZipTestFile);
581     CoUninitialize();
582 }
583