[SHELL32_WINETEST] Add a PCH.
[reactos.git] / modules / rostests / winetests / shell32 / shlfolder.c
1 /*
2 * Unit test of the IShellFolder functions.
3 *
4 * Copyright 2004 Vitaliy Margolen
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22
23 #include <initguid.h>
24 DEFINE_GUID(IID_IParentAndItem, 0xB3A4B685, 0xB685, 0x4805, 0x99,0xD9, 0x5D,0xEA,0xD2,0x87,0x32,0x36);
25 DEFINE_GUID(CLSID_ShellDocObjView, 0xe7e4bc40, 0xe76a, 0x11ce, 0xa9,0xbb, 0x00,0xaa,0x00,0x4a,0xe8,0x37);
26
27 static IMalloc *ppM;
28
29 static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
30 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
31 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
32 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
33 static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
34 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
35 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
36 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
37 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
38 static void (WINAPI *pILFree)(LPITEMIDLIST);
39 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
40 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
41 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
42 static HRESULT (WINAPI *pSHCreateItemFromRelativeName)(IShellItem*,PCWSTR,IBindCtx*,REFIID,void**);
43 static HRESULT (WINAPI *pSHCreateItemInKnownFolder)(REFKNOWNFOLDERID,DWORD,PCWSTR,REFIID,void **);
44 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
45 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
46 static HRESULT (WINAPI *pSHCreateShellItemArrayFromIDLists)(UINT, PCIDLIST_ABSOLUTE*, IShellItemArray**);
47 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
48 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
49 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
50 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
51 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
52 static HRESULT (WINAPI *pSHGetKnownFolderPath)(REFKNOWNFOLDERID,DWORD,HANDLE,PWSTR*);
53 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
54 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
55 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
56 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
57 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
58 static UINT (WINAPI *pGetSystemWow64DirectoryW)(LPWSTR, UINT);
59 static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
60 static HRESULT (WINAPI *pSHILCreateFromPath)(LPCWSTR, LPITEMIDLIST *,DWORD*);
61 static BOOL (WINAPI *pSHGetPathFromIDListEx)(PCIDLIST_ABSOLUTE,WCHAR*,DWORD,GPFIDL_FLAGS);
62
63 static WCHAR *make_wstr(const char *str)
64 {
65 WCHAR *ret;
66 int len;
67
68 if (!str || !str[0])
69 return NULL;
70
71 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
72 if(!len || len < 0)
73 return NULL;
74
75 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
76 if(!ret)
77 return NULL;
78
79 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
80 return ret;
81 }
82
83 static int strcmp_wa(LPCWSTR strw, const char *stra)
84 {
85 CHAR buf[512];
86 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
87 return lstrcmpA(stra, buf);
88 }
89
90 static void init_function_pointers(void)
91 {
92 HMODULE hmod;
93 HRESULT hr;
94 void *ptr;
95
96 hmod = GetModuleHandleA("shell32.dll");
97
98 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
99 MAKEFUNC(SHBindToParent);
100 MAKEFUNC(SHCreateItemFromIDList);
101 MAKEFUNC(SHCreateItemFromParsingName);
102 MAKEFUNC(SHCreateItemFromRelativeName);
103 MAKEFUNC(SHCreateItemInKnownFolder);
104 MAKEFUNC(SHCreateShellItem);
105 MAKEFUNC(SHCreateShellItemArray);
106 MAKEFUNC(SHCreateShellItemArrayFromIDLists);
107 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
108 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
109 MAKEFUNC(SHGetFolderPathA);
110 MAKEFUNC(SHGetFolderPathAndSubDirA);
111 MAKEFUNC(SHGetPathFromIDListW);
112 MAKEFUNC(SHGetSpecialFolderPathA);
113 MAKEFUNC(SHGetSpecialFolderPathW);
114 MAKEFUNC(SHGetSpecialFolderLocation);
115 MAKEFUNC(SHParseDisplayName);
116 MAKEFUNC(SHGetKnownFolderPath);
117 MAKEFUNC(SHGetNameFromIDList);
118 MAKEFUNC(SHGetItemFromDataObject);
119 MAKEFUNC(SHGetIDListFromObject);
120 MAKEFUNC(SHGetItemFromObject);
121 MAKEFUNC(SHCreateDefaultContextMenu);
122 MAKEFUNC(SHGetPathFromIDListEx);
123 #undef MAKEFUNC
124
125 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
126 MAKEFUNC_ORD(ILFindLastID, 16);
127 MAKEFUNC_ORD(ILIsEqual, 21);
128 MAKEFUNC_ORD(ILCombine, 25);
129 MAKEFUNC_ORD(SHILCreateFromPath, 28);
130 MAKEFUNC_ORD(ILFree, 155);
131 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
132 #undef MAKEFUNC_ORD
133
134 /* test named exports */
135 ptr = GetProcAddress(hmod, "ILFree");
136 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
137 if (ptr)
138 {
139 #define TESTNAMED(f) \
140 ptr = (void*)GetProcAddress(hmod, #f); \
141 ok(ptr != 0, "expected named export for " #f "\n");
142
143 TESTNAMED(ILAppendID);
144 TESTNAMED(ILClone);
145 TESTNAMED(ILCloneFirst);
146 TESTNAMED(ILCombine);
147 TESTNAMED(ILCreateFromPath);
148 TESTNAMED(ILCreateFromPathA);
149 TESTNAMED(ILCreateFromPathW);
150 TESTNAMED(ILFindChild);
151 TESTNAMED(ILFindLastID);
152 TESTNAMED(ILGetNext);
153 TESTNAMED(ILGetSize);
154 TESTNAMED(ILIsEqual);
155 TESTNAMED(ILIsParent);
156 TESTNAMED(ILRemoveLastID);
157 TESTNAMED(ILSaveToStream);
158 #undef TESTNAMED
159 }
160
161 hmod = GetModuleHandleA("shlwapi.dll");
162 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
163
164 hmod = GetModuleHandleA("kernel32.dll");
165 pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
166 pGetSystemWow64DirectoryW = (void*)GetProcAddress(hmod, "GetSystemWow64DirectoryW");
167
168 hr = SHGetMalloc(&ppM);
169 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
170 }
171
172 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
173 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
174 {
175 size_t iLen;
176
177 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
178 return NULL;
179
180 if (iLen)
181 {
182 lpszPath += iLen;
183 if (lpszPath[-1] != '\\')
184 {
185 *lpszPath++ = '\\';
186 *lpszPath = '\0';
187 }
188 }
189 return lpszPath;
190 }
191
192 static void test_ParseDisplayName(void)
193 {
194 HRESULT hr;
195 IShellFolder *IDesktopFolder;
196 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
197 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
198 static const char *cInetTestA = "http:\\yyy";
199 static const char *cInetTest2A = "xx:yyy";
200 DWORD res;
201 WCHAR cTestDirW [MAX_PATH] = {0};
202 ITEMIDLIST *newPIDL;
203 BOOL bRes;
204
205 hr = SHGetDesktopFolder(&IDesktopFolder);
206 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
207 if(hr != S_OK) return;
208
209 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
210 if (pSHCreateShellItem)
211 {
212 if (0)
213 {
214 /* null name and pidl, also crashes on Windows 8 */
215 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL,
216 NULL, NULL, NULL, 0);
217 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
218 }
219
220 /* null name */
221 newPIDL = (ITEMIDLIST*)0xdeadbeef;
222 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
223 NULL, NULL, NULL, NULL, &newPIDL, 0);
224 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
225 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
226 }
227 else
228 win_skip("Tests would crash on W2K and below\n");
229
230 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
231 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
232 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
233 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
234 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
235 if (hr == S_OK)
236 {
237 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
238 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
239 IMalloc_Free(ppM, newPIDL);
240 }
241
242 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
243 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
244 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
245 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
246 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
247 if (hr == S_OK)
248 {
249 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
250 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
251 IMalloc_Free(ppM, newPIDL);
252 }
253
254 res = GetFileAttributesA(cNonExistDir1A);
255 if(res != INVALID_FILE_ATTRIBUTES)
256 {
257 skip("Test directory unexpectedly exists\n");
258 goto finished;
259 }
260
261 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
262 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
263 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
264 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
265 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
266
267 res = GetFileAttributesA(cNonExistDir2A);
268 if(res != INVALID_FILE_ATTRIBUTES)
269 {
270 skip("Test directory unexpectedly exists\n");
271 goto finished;
272 }
273
274 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
275 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
276 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
277 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
278 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
279
280 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
281 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
282 * out it doesn't. The magic seems to happen in the file dialogs, then. */
283 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
284 {
285 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
286 goto finished;
287 }
288
289 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
290 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
291 if (!bRes) goto finished;
292
293 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
294 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
295 if (hr != S_OK) goto finished;
296
297 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
298 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
299 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
300 pILFindLastID(newPIDL)->mkid.abID[0]);
301 IMalloc_Free(ppM, newPIDL);
302
303 finished:
304 IShellFolder_Release(IDesktopFolder);
305 }
306
307 /* creates a file with the specified name for tests */
308 static void CreateTestFile(const CHAR *name)
309 {
310 HANDLE file;
311 DWORD written;
312
313 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
314 if (file != INVALID_HANDLE_VALUE)
315 {
316 WriteFile(file, name, strlen(name), &written, NULL);
317 WriteFile(file, "\n", strlen("\n"), &written, NULL);
318 CloseHandle(file);
319 }
320 }
321
322
323 /* initializes the tests */
324 static void CreateFilesFolders(void)
325 {
326 CreateDirectoryA(".\\testdir", NULL);
327 CreateDirectoryA(".\\testdir\\test.txt", NULL);
328 CreateTestFile (".\\testdir\\test1.txt ");
329 CreateTestFile (".\\testdir\\test2.txt ");
330 CreateTestFile (".\\testdir\\test3.txt ");
331 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
332 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
333 }
334
335 /* cleans after tests */
336 static void Cleanup(void)
337 {
338 DeleteFileA(".\\testdir\\test1.txt");
339 DeleteFileA(".\\testdir\\test2.txt");
340 DeleteFileA(".\\testdir\\test3.txt");
341 RemoveDirectoryA(".\\testdir\\test.txt");
342 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
343 RemoveDirectoryA(".\\testdir\\testdir2");
344 RemoveDirectoryA(".\\testdir");
345 }
346
347
348 /* perform test */
349 static void test_EnumObjects(IShellFolder *iFolder)
350 {
351 IEnumIDList *iEnumList;
352 LPITEMIDLIST newPIDL, idlArr[10];
353 ULONG NumPIDLs;
354 int i=0, j;
355 HRESULT hr;
356
357 static const WORD iResults [5][5] =
358 {
359 { 0,-1,-1,-1,-1},
360 { 1, 0,-1,-1,-1},
361 { 1, 1, 0,-1,-1},
362 { 1, 1, 1, 0,-1},
363 { 1, 1, 1, 1, 0}
364 };
365
366 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
367 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
368 static const ULONG attrs[5] =
369 {
370 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
371 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
372 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
373 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
374 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
375 };
376 static const ULONG full_attrs[5] =
377 {
378 SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
379 SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
380 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
381 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
382 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
383 };
384
385 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
386 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
387
388 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
389 * the filesystem shellfolders return S_OK even if less than 'celt' items are
390 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
391 * only ever returns a single entry per call. */
392 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
393 i += NumPIDLs;
394 ok (i == 5, "i: %d\n", i);
395
396 hr = IEnumIDList_Release(iEnumList);
397 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
398
399 /* Sort them first in case of wrong order from system */
400 for (i=0;i<5;i++) for (j=0;j<5;j++)
401 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
402 {
403 newPIDL = idlArr[i];
404 idlArr[i] = idlArr[j];
405 idlArr[j] = newPIDL;
406 }
407
408 for (i=0;i<5;i++) for (j=0;j<5;j++)
409 {
410 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
411 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
412 }
413
414
415 for (i = 0; i < 5; i++)
416 {
417 SFGAOF flags;
418 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
419 /* Native returns all flags no matter what we ask for */
420 flags = SFGAO_CANCOPY;
421 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
422 flags &= SFGAO_testfor;
423 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
424 ok(flags == (attrs[i]) ||
425 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
426 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
427 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
428
429 flags = SFGAO_testfor;
430 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
431 flags &= SFGAO_testfor;
432 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
433 ok(flags == attrs[i] ||
434 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
435 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
436
437 flags = ~0u;
438 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
439 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
440 ok((flags & ~(SFGAO_HASSUBFOLDER|SFGAO_COMPRESSED)) == full_attrs[i], "%d: got %08x expected %08x\n", i, flags, full_attrs[i]);
441 }
442
443 for (i=0;i<5;i++)
444 IMalloc_Free(ppM, idlArr[i]);
445 }
446
447 static void test_BindToObject(void)
448 {
449 HRESULT hr;
450 UINT cChars;
451 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
452 SHITEMID emptyitem = { 0, { 0 } };
453 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
454 WCHAR wszSystemDir[MAX_PATH];
455 char szSystemDir[MAX_PATH];
456 char buf[MAX_PATH];
457 WCHAR path[MAX_PATH];
458 CHAR pathA[MAX_PATH];
459 HANDLE hfile;
460 WCHAR wszMyComputer[] = {
461 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
462 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
463 static const CHAR filename_html[] = "winetest.html";
464 static const CHAR filename_txt[] = "winetest.txt";
465 static const CHAR filename_foo[] = "winetest.foo";
466
467 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
468 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
469 */
470 hr = SHGetDesktopFolder(&psfDesktop);
471 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
472 if (hr != S_OK) return;
473
474 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
475 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
476
477 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
478 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
479
480 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
481 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
482 if (hr != S_OK) {
483 IShellFolder_Release(psfDesktop);
484 return;
485 }
486
487 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
488 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
489 IShellFolder_Release(psfDesktop);
490 IMalloc_Free(ppM, pidlMyComputer);
491 if (hr != S_OK) return;
492
493 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
494 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
495
496 if (0)
497 {
498 /* this call segfaults on 98SE */
499 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
500 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
501 }
502
503 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
504 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
505 if (cChars == 0 || cChars >= MAX_PATH) {
506 IShellFolder_Release(psfMyComputer);
507 return;
508 }
509 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
510
511 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
512 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
513 if (hr != S_OK) {
514 IShellFolder_Release(psfMyComputer);
515 return;
516 }
517
518 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
519 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
520 IShellFolder_Release(psfMyComputer);
521 IMalloc_Free(ppM, pidlSystemDir);
522 if (hr != S_OK) return;
523
524 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
525 ok (hr == E_INVALIDARG,
526 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
527
528 if (0)
529 {
530 /* this call segfaults on 98SE */
531 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
532 ok (hr == E_INVALIDARG,
533 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
534 }
535
536 IShellFolder_Release(psfSystemDir);
537
538 cChars = GetCurrentDirectoryA(MAX_PATH, buf);
539 if(!cChars)
540 {
541 skip("Failed to get current directory, skipping tests.\n");
542 return;
543 }
544 if(buf[cChars-1] != '\\') lstrcatA(buf, "\\");
545
546 SHGetDesktopFolder(&psfDesktop);
547
548 /* Attempt BindToObject on files. */
549
550 /* .html */
551 lstrcpyA(pathA, buf);
552 lstrcatA(pathA, filename_html);
553 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
554 if(hfile != INVALID_HANDLE_VALUE)
555 {
556 CloseHandle(hfile);
557 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
558 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
559 ok(hr == S_OK, "Got 0x%08x\n", hr);
560 if(SUCCEEDED(hr))
561 {
562 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
563 ok(hr == S_OK ||
564 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
565 "Got 0x%08x\n", hr);
566 if(SUCCEEDED(hr))
567 {
568 IPersist *pp;
569 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
570 ok(hr == S_OK ||
571 broken(hr == E_NOINTERFACE), /* Win9x, NT4, W2K */
572 "Got 0x%08x\n", hr);
573 if(SUCCEEDED(hr))
574 {
575 CLSID id;
576 hr = IPersist_GetClassID(pp, &id);
577 ok(hr == S_OK, "Got 0x%08x\n", hr);
578 /* CLSID_ShellFSFolder on some w2k systems */
579 ok(IsEqualIID(&id, &CLSID_ShellDocObjView) || broken(IsEqualIID(&id, &CLSID_ShellFSFolder)),
580 "Unexpected classid %s\n", wine_dbgstr_guid(&id));
581 IPersist_Release(pp);
582 }
583
584 IShellFolder_Release(psfChild);
585 }
586 pILFree(pidl);
587 }
588 DeleteFileA(pathA);
589 }
590 else
591 win_skip("Failed to create .html testfile.\n");
592
593 /* .txt */
594 lstrcpyA(pathA, buf);
595 lstrcatA(pathA, filename_txt);
596 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
597 if(hfile != INVALID_HANDLE_VALUE)
598 {
599 CloseHandle(hfile);
600 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
601 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
602 ok(hr == S_OK, "Got 0x%08x\n", hr);
603 if(SUCCEEDED(hr))
604 {
605 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
606 ok(hr == E_FAIL || /* Vista+ */
607 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
608 hr == E_INVALIDARG || /* W2K item in top dir */
609 broken(hr == S_OK), /* Win9x, NT4, W2K */
610 "Got 0x%08x\n", hr);
611 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
612 pILFree(pidl);
613 }
614 DeleteFileA(pathA);
615 }
616 else
617 win_skip("Failed to create .txt testfile.\n");
618
619 /* .foo */
620 lstrcpyA(pathA, buf);
621 lstrcatA(pathA, filename_foo);
622 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
623 if(hfile != INVALID_HANDLE_VALUE)
624 {
625 CloseHandle(hfile);
626 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
627 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
628 ok(hr == S_OK, "Got 0x%08x\n", hr);
629 if(SUCCEEDED(hr))
630 {
631 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
632 ok(hr == E_FAIL || /* Vista+ */
633 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
634 hr == E_INVALIDARG || /* W2K item in top dir */
635 broken(hr == S_OK), /* Win9x, NT4, W2K */
636 "Got 0x%08x\n", hr);
637 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
638 pILFree(pidl);
639 }
640 DeleteFileA(pathA);
641 }
642 else
643 win_skip("Failed to create .foo testfile.\n");
644
645 /* And on the desktop */
646 if(pSHGetSpecialFolderPathA)
647 {
648 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
649 lstrcatA(pathA, "\\");
650 lstrcatA(pathA, filename_html);
651 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
652 if(hfile != INVALID_HANDLE_VALUE)
653 {
654 CloseHandle(hfile);
655 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
656 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
657 ok(hr == S_OK, "Got 0x%08x\n", hr);
658 if(SUCCEEDED(hr))
659 {
660 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
661 ok(hr == S_OK ||
662 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
663 "Got 0x%08x\n", hr);
664 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
665 pILFree(pidl);
666 }
667 if(!DeleteFileA(pathA))
668 trace("Failed to delete: %d\n", GetLastError());
669
670 }
671 else
672 win_skip("Failed to create .html testfile.\n");
673
674 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
675 lstrcatA(pathA, "\\");
676 lstrcatA(pathA, filename_foo);
677 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
678 if(hfile != INVALID_HANDLE_VALUE)
679 {
680 CloseHandle(hfile);
681 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
682 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
683 ok(hr == S_OK, "Got 0x%08x\n", hr);
684 if(SUCCEEDED(hr))
685 {
686 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
687 ok(hr == E_FAIL || /* Vista+ */
688 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
689 broken(hr == S_OK), /* Win9x, NT4, W2K */
690 "Got 0x%08x\n", hr);
691 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
692 pILFree(pidl);
693 }
694 DeleteFileA(pathA);
695 }
696 else
697 win_skip("Failed to create .foo testfile.\n");
698 }
699
700 IShellFolder_Release(psfDesktop);
701 }
702
703 static void test_GetDisplayName(void)
704 {
705 BOOL result;
706 HRESULT hr;
707 HANDLE hTestFile;
708 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
709 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
710 DWORD attr;
711 STRRET strret;
712 LPSHELLFOLDER psfDesktop, psfPersonal;
713 IUnknown *psfFile;
714 SHITEMID emptyitem = { 0, { 0 } };
715 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
716 LPCITEMIDLIST pidlLast;
717 static const CHAR szFileName[] = "winetest.foo";
718 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
719 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
720
721 /* I'm trying to figure if there is a functional difference between calling
722 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
723 * binding to the shellfolder. One thing I thought of was that perhaps
724 * SHGetPathFromIDListW would be able to get the path to a file, which does
725 * not exist anymore, while the other method wouldn't. It turns out there's
726 * no functional difference in this respect.
727 */
728
729 if(!pSHGetSpecialFolderPathA) {
730 win_skip("SHGetSpecialFolderPathA is not available\n");
731 return;
732 }
733
734 /* First creating a directory in MyDocuments and a file in this directory. */
735 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
736 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
737 if (!result) return;
738
739 /* Use ANSI file functions so this works on Windows 9x */
740 lstrcatA(szTestDir, "\\winetest");
741 CreateDirectoryA(szTestDir, NULL);
742 attr=GetFileAttributesA(szTestDir);
743 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
744 {
745 ok(0, "unable to create the '%s' directory\n", szTestDir);
746 return;
747 }
748
749 lstrcpyA(szTestFile, szTestDir);
750 lstrcatA(szTestFile, "\\");
751 lstrcatA(szTestFile, szFileName);
752 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
753 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
754 if (hTestFile == INVALID_HANDLE_VALUE) return;
755 CloseHandle(hTestFile);
756
757 /* Getting an itemidlist for the file. */
758 hr = SHGetDesktopFolder(&psfDesktop);
759 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
760 if (hr != S_OK) return;
761
762 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
763
764 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
765 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
766 if (hr != S_OK) {
767 IShellFolder_Release(psfDesktop);
768 return;
769 }
770
771 pidlLast = pILFindLastID(pidlTestFile);
772 ok(pidlLast->mkid.cb >=76 ||
773 broken(pidlLast->mkid.cb == 28) || /* W2K */
774 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
775 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
776 if (pidlLast->mkid.cb >= 28) {
777 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
778 "Filename should be stored as ansi-string at this position!\n");
779 }
780 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
781 if (pidlLast->mkid.cb >= 76) {
782 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
783 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
784 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)) || /* Win7 */
785 (pidlLast->mkid.cb >= 102 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[72], wszFileName)), /* Win8 */
786 "Filename should be stored as wchar-string at this position!\n");
787 }
788
789 /* It seems as if we cannot bind to regular files on windows, but only directories.
790 */
791 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
792 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
793 hr == E_NOTIMPL || /* Vista */
794 broken(hr == S_OK), /* Win9x, W2K */
795 "hr = %08x\n", hr);
796 if (hr == S_OK) {
797 IUnknown_Release(psfFile);
798 }
799
800 if (!pSHBindToParent)
801 {
802 win_skip("SHBindToParent is missing\n");
803 DeleteFileA(szTestFile);
804 RemoveDirectoryA(szTestDir);
805 return;
806 }
807
808 /* Some tests for IShellFolder::SetNameOf */
809 if (pSHGetFolderPathAndSubDirA)
810 {
811 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
812 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
813 if (hr == S_OK) {
814 /* It's ok to use this fixed path. Call will fail anyway. */
815 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
816 LPITEMIDLIST pidlNew;
817
818 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
819 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
820 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
821 if (hr == S_OK)
822 {
823 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
824 "pidl returned from SetNameOf should be simple!\n");
825
826 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
827 * is implemented on top of SHFileOperation in WinXP. */
828 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
829 SHGDN_FORPARSING, NULL);
830 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
831
832 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
833 * SHGDN flags specify an absolute path. */
834 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
835 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
836
837 pILFree(pidlNew);
838 }
839
840 IShellFolder_Release(psfPersonal);
841 }
842 }
843 else
844 win_skip("Avoid needs of interaction on Win2k\n");
845
846 /* Deleting the file and the directory */
847 DeleteFileA(szTestFile);
848 RemoveDirectoryA(szTestDir);
849
850 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
851 if (pSHGetPathFromIDListW)
852 {
853 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
854 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
855 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
856 }
857
858 /* SHBindToParent fails, if called with a NULL PIDL. */
859 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
860 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
861
862 /* But it succeeds with an empty PIDL. */
863 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
864 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
865 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
866 if (hr == S_OK)
867 IShellFolder_Release(psfPersonal);
868
869 /* Binding to the folder and querying the display name of the file also works. */
870 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
871 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
872 if (hr != S_OK) {
873 IShellFolder_Release(psfDesktop);
874 return;
875 }
876
877 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
878 * pidlTestFile (In accordance with MSDN). */
879 ok (pILFindLastID(pidlTestFile) == pidlLast,
880 "SHBindToParent doesn't return the last id of the pidl param!\n");
881
882 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
883 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
884 if (hr != S_OK) {
885 IShellFolder_Release(psfDesktop);
886 IShellFolder_Release(psfPersonal);
887 return;
888 }
889
890 if (pStrRetToBufW)
891 {
892 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
893 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
894 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
895 }
896
897 ILFree(pidlTestFile);
898 IShellFolder_Release(psfDesktop);
899 IShellFolder_Release(psfPersonal);
900 }
901
902 static void test_CallForAttributes(void)
903 {
904 HKEY hKey;
905 LONG lResult;
906 HRESULT hr;
907 DWORD dwSize;
908 LPSHELLFOLDER psfDesktop;
909 LPITEMIDLIST pidlMyDocuments;
910 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
911 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
912 static const WCHAR wszCallForAttributes[] = {
913 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
914 static const WCHAR wszMyDocumentsKey[] = {
915 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
916 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
917 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
918 WCHAR wszMyDocuments[] = {
919 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
920 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
921
922 /* For the root of a namespace extension, the attributes are not queried by binding
923 * to the object and calling GetAttributesOf. Instead, the attributes are read from
924 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
925 *
926 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
927 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
928 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
929 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
930 */
931 hr = SHGetDesktopFolder(&psfDesktop);
932 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
933 if (hr != S_OK) return;
934
935 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
936 &pidlMyDocuments, NULL);
937 ok (hr == S_OK ||
938 broken(hr == E_INVALIDARG), /* Win95, NT4 */
939 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
940 if (hr != S_OK) {
941 IShellFolder_Release(psfDesktop);
942 return;
943 }
944
945 dwAttributes = 0xffffffff;
946 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
947 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
948 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
949
950 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
951 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
952 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
953 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
954
955 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
956 * key. So the test will return at this point, if run on wine.
957 */
958 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
959 ok (lResult == ERROR_SUCCESS ||
960 lResult == ERROR_ACCESS_DENIED,
961 "RegOpenKeyEx failed! result: %08x\n", lResult);
962 if (lResult != ERROR_SUCCESS) {
963 if (lResult == ERROR_ACCESS_DENIED)
964 skip("Not enough rights to open the registry key\n");
965 IMalloc_Free(ppM, pidlMyDocuments);
966 IShellFolder_Release(psfDesktop);
967 return;
968 }
969
970 /* Query MyDocuments' Attributes value, to be able to restore it later. */
971 dwSize = sizeof(DWORD);
972 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
973 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
974 if (lResult != ERROR_SUCCESS) {
975 RegCloseKey(hKey);
976 IMalloc_Free(ppM, pidlMyDocuments);
977 IShellFolder_Release(psfDesktop);
978 return;
979 }
980
981 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
982 dwSize = sizeof(DWORD);
983 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
984 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
985 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
986 if (lResult != ERROR_SUCCESS) {
987 RegCloseKey(hKey);
988 IMalloc_Free(ppM, pidlMyDocuments);
989 IShellFolder_Release(psfDesktop);
990 return;
991 }
992
993 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
994 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
995 * SFGAO_FILESYSTEM attributes. */
996 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
997 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
998 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
999 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1000 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
1001
1002 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
1003 * GetAttributesOf. It seems that once there is a single attribute queried, for which
1004 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
1005 * the flags in Attributes are ignored.
1006 */
1007 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
1008 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
1009 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
1010 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
1011 if (hr == S_OK)
1012 ok (dwAttributes == SFGAO_FILESYSTEM,
1013 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
1014 dwAttributes);
1015
1016 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
1017 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
1018 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1019 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
1020 RegCloseKey(hKey);
1021 IMalloc_Free(ppM, pidlMyDocuments);
1022 IShellFolder_Release(psfDesktop);
1023 }
1024
1025 static void test_GetAttributesOf(void)
1026 {
1027 HRESULT hr;
1028 LPSHELLFOLDER psfDesktop, psfMyComputer;
1029 SHITEMID emptyitem = { 0, { 0 } };
1030 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1031 LPITEMIDLIST pidlMyComputer;
1032 DWORD dwFlags;
1033 static const DWORD desktopFlags[] = {
1034 /* WinXP */
1035 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
1036 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1037 /* Win2k */
1038 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
1039 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1040 /* WinMe, Win9x, WinNT*/
1041 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
1042 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1043 };
1044 static const DWORD myComputerFlags[] = {
1045 /* WinXP */
1046 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
1047 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1048 /* Win2k */
1049 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
1050 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1051 /* WinMe, Win9x, WinNT */
1052 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1053 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1054 /* Win95, WinNT when queried directly */
1055 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1056 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1057 };
1058 WCHAR wszMyComputer[] = {
1059 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1060 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1061 char cCurrDirA [MAX_PATH] = {0};
1062 WCHAR cCurrDirW [MAX_PATH];
1063 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
1064 IShellFolder *IDesktopFolder, *testIShellFolder;
1065 ITEMIDLIST *newPIDL;
1066 int len, i;
1067 BOOL foundFlagsMatch;
1068
1069 hr = SHGetDesktopFolder(&psfDesktop);
1070 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1071 if (hr != S_OK) return;
1072
1073 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
1074 dwFlags = 0xffffffff;
1075 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
1076 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
1077 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1078 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1079 {
1080 if (desktopFlags[i] == dwFlags)
1081 foundFlagsMatch = TRUE;
1082 }
1083 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1084
1085 /* .. or with no itemidlist at all. */
1086 dwFlags = 0xffffffff;
1087 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
1088 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1089 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1090 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1091 {
1092 if (desktopFlags[i] == dwFlags)
1093 foundFlagsMatch = TRUE;
1094 }
1095 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1096
1097 /* Testing the attributes of the MyComputer shellfolder */
1098 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1099 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1100 if (hr != S_OK) {
1101 IShellFolder_Release(psfDesktop);
1102 return;
1103 }
1104
1105 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
1106 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
1107 */
1108 dwFlags = 0xffffffff;
1109 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
1110 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
1111 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1112 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1113 {
1114 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
1115 foundFlagsMatch = TRUE;
1116 }
1117 todo_wine
1118 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1119
1120 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
1121 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
1122 IShellFolder_Release(psfDesktop);
1123 IMalloc_Free(ppM, pidlMyComputer);
1124 if (hr != S_OK) return;
1125
1126 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
1127 todo_wine
1128 ok (hr == E_INVALIDARG ||
1129 broken(hr == S_OK), /* W2K and earlier */
1130 "MyComputer->GetAttributesOf(empty pidl) should fail! hr = %08x\n", hr);
1131
1132 dwFlags = 0xffffffff;
1133 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
1134 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1135 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1136 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1137 {
1138 if (myComputerFlags[i] == dwFlags)
1139 foundFlagsMatch = TRUE;
1140 }
1141 todo_wine
1142 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1143
1144 IShellFolder_Release(psfMyComputer);
1145
1146 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1147 len = lstrlenA(cCurrDirA);
1148
1149 if (len == 0) {
1150 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1151 return;
1152 }
1153 if (len > 3 && cCurrDirA[len-1] == '\\')
1154 cCurrDirA[len-1] = 0;
1155
1156 /* create test directory */
1157 CreateFilesFolders();
1158
1159 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1160
1161 hr = SHGetDesktopFolder(&IDesktopFolder);
1162 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1163
1164 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1165 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1166
1167 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1168 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1169
1170 IMalloc_Free(ppM, newPIDL);
1171
1172 /* get relative PIDL */
1173 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1174 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1175
1176 /* test the shell attributes of the test directory using the relative PIDL */
1177 dwFlags = SFGAO_FOLDER;
1178 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1179 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1180 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1181
1182 /* free memory */
1183 IMalloc_Free(ppM, newPIDL);
1184
1185 /* append testdirectory name to path */
1186 if (cCurrDirA[len-1] == '\\')
1187 cCurrDirA[len-1] = 0;
1188 lstrcatA(cCurrDirA, "\\testdir");
1189 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1190
1191 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1192 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1193
1194 /* test the shell attributes of the test directory using the absolute PIDL */
1195 dwFlags = SFGAO_FOLDER;
1196 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1197 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1198 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1199
1200 /* free memory */
1201 IMalloc_Free(ppM, newPIDL);
1202
1203 IShellFolder_Release(testIShellFolder);
1204
1205 Cleanup();
1206
1207 IShellFolder_Release(IDesktopFolder);
1208 }
1209
1210 static void test_SHGetPathFromIDList(void)
1211 {
1212 SHITEMID emptyitem = { 0, { 0 } };
1213 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1214 LPITEMIDLIST pidlMyComputer;
1215 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1216 BOOL result;
1217 HRESULT hr;
1218 LPSHELLFOLDER psfDesktop;
1219 WCHAR wszMyComputer[] = {
1220 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1221 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1222 WCHAR wszFileName[MAX_PATH];
1223 LPITEMIDLIST pidlTestFile;
1224 HANDLE hTestFile;
1225 STRRET strret;
1226 static WCHAR wszTestFile[] = {
1227 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1228 LPITEMIDLIST pidlPrograms;
1229
1230 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1231 {
1232 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1233 return;
1234 }
1235
1236 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1237 wszPath[0] = 'a';
1238 wszPath[1] = '\0';
1239 result = pSHGetPathFromIDListW(NULL, wszPath);
1240 ok(!result, "Expected failure\n");
1241 ok(!wszPath[0], "Expected empty string\n");
1242
1243 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1244 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1245 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1246 if (!result) return;
1247
1248 /* Check if we are on Win9x */
1249 SetLastError(0xdeadbeef);
1250 lstrcmpiW(wszDesktop, wszDesktop);
1251 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1252 {
1253 win_skip("Most W-calls are not implemented\n");
1254 return;
1255 }
1256
1257 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1258 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1259 if (!result) return;
1260 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1261
1262 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1263 hr = SHGetDesktopFolder(&psfDesktop);
1264 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1265 if (hr != S_OK) return;
1266
1267 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1268 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1269 if (hr != S_OK) {
1270 IShellFolder_Release(psfDesktop);
1271 return;
1272 }
1273
1274 SetLastError(0xdeadbeef);
1275 wszPath[0] = 'a';
1276 wszPath[1] = '\0';
1277 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1278 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1279 ok (GetLastError()==0xdeadbeef ||
1280 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1281 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1282 ok (!wszPath[0], "Expected empty path\n");
1283 if (result) {
1284 IShellFolder_Release(psfDesktop);
1285 return;
1286 }
1287
1288 IMalloc_Free(ppM, pidlMyComputer);
1289
1290 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1291 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1292 if (!result) {
1293 IShellFolder_Release(psfDesktop);
1294 return;
1295 }
1296 myPathAddBackslashW(wszFileName);
1297 lstrcatW(wszFileName, wszTestFile);
1298 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1299 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1300 if (hTestFile == INVALID_HANDLE_VALUE) {
1301 IShellFolder_Release(psfDesktop);
1302 return;
1303 }
1304 CloseHandle(hTestFile);
1305
1306 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1307 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1308 if (hr != S_OK) {
1309 IShellFolder_Release(psfDesktop);
1310 DeleteFileW(wszFileName);
1311 IMalloc_Free(ppM, pidlTestFile);
1312 return;
1313 }
1314
1315 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1316 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1317 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1318 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1319 IShellFolder_Release(psfDesktop);
1320 DeleteFileW(wszFileName);
1321 if (hr != S_OK) {
1322 IMalloc_Free(ppM, pidlTestFile);
1323 return;
1324 }
1325 if (pStrRetToBufW)
1326 {
1327 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1328 ok(0 == lstrcmpW(wszFileName, wszPath),
1329 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1330 "returned incorrect path for file placed on desktop\n");
1331 }
1332
1333 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1334 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1335 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1336
1337 if (pSHGetPathFromIDListEx)
1338 {
1339 result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1340 ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1341 ok(!lstrcmpiW(wszDesktop, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1342 wine_dbgstr_w(wszPath), wine_dbgstr_w(wszDesktop));
1343
1344 result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1345 ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1346 ok(!lstrcmpiW(wszFileName, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1347 wine_dbgstr_w(wszPath), wine_dbgstr_w(wszFileName));
1348
1349 SetLastError(0xdeadbeef);
1350 memset(wszPath, 0x55, sizeof(wszPath));
1351 result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, 5, SFGAO_FILESYSTEM);
1352 ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1353
1354 SetLastError(0xdeadbeef);
1355 memset(wszPath, 0x55, sizeof(wszPath));
1356 result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, 5, SFGAO_FILESYSTEM);
1357 ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1358 }
1359 else
1360 win_skip("SHGetPathFromIDListEx not available\n");
1361
1362 IMalloc_Free(ppM, pidlTestFile);
1363
1364 /* Test if we can get the path from the start menu "program files" PIDL. */
1365 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1366 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1367
1368 SetLastError(0xdeadbeef);
1369 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1370 IMalloc_Free(ppM, pidlPrograms);
1371 ok(result, "SHGetPathFromIDListW failed\n");
1372 }
1373
1374 static void test_EnumObjects_and_CompareIDs(void)
1375 {
1376 ITEMIDLIST *newPIDL;
1377 IShellFolder *IDesktopFolder, *testIShellFolder;
1378 char cCurrDirA [MAX_PATH] = {0};
1379 static const CHAR cTestDirA[] = "\\testdir";
1380 WCHAR cTestDirW[MAX_PATH];
1381 int len;
1382 HRESULT hr;
1383
1384 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1385 len = lstrlenA(cCurrDirA);
1386
1387 if(len == 0) {
1388 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1389 return;
1390 }
1391 if(cCurrDirA[len-1] == '\\')
1392 cCurrDirA[len-1] = 0;
1393
1394 lstrcatA(cCurrDirA, cTestDirA);
1395 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1396
1397 hr = SHGetDesktopFolder(&IDesktopFolder);
1398 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1399
1400 CreateFilesFolders();
1401
1402 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1403 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1404
1405 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1406 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1407
1408 test_EnumObjects(testIShellFolder);
1409
1410 IShellFolder_Release(testIShellFolder);
1411
1412 Cleanup();
1413
1414 IMalloc_Free(ppM, newPIDL);
1415
1416 IShellFolder_Release(IDesktopFolder);
1417 }
1418
1419 /* A simple implementation of an IPropertyBag, which returns fixed values for
1420 * 'Target' and 'Attributes' properties.
1421 */
1422 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1423 void **ppvObject)
1424 {
1425 if (!ppvObject)
1426 return E_INVALIDARG;
1427
1428 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1429 *ppvObject = iface;
1430 } else {
1431 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1432 return E_NOINTERFACE;
1433 }
1434
1435 IPropertyBag_AddRef(iface);
1436 return S_OK;
1437 }
1438
1439 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1440 return 2;
1441 }
1442
1443 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1444 return 1;
1445 }
1446
1447 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1448 VARIANT *pVar, IErrorLog *pErrorLog)
1449 {
1450 static const WCHAR wszTargetSpecialFolder[] = {
1451 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1452 static const WCHAR wszTarget[] = {
1453 'T','a','r','g','e','t',0 };
1454 static const WCHAR wszAttributes[] = {
1455 'A','t','t','r','i','b','u','t','e','s',0 };
1456 static const WCHAR wszResolveLinkFlags[] = {
1457 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1458 static const WCHAR wszTargetKnownFolder[] = {
1459 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1460 static const WCHAR wszCLSID[] = {
1461 'C','L','S','I','D',0 };
1462
1463 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1464 ok(V_VT(pVar) == VT_I4 ||
1465 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1466 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1467 return E_INVALIDARG;
1468 }
1469
1470 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1471 {
1472 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1473 return E_INVALIDARG;
1474 }
1475
1476 if (!lstrcmpW(pszPropName, wszTarget)) {
1477 WCHAR wszPath[MAX_PATH];
1478 BOOL result;
1479
1480 ok(V_VT(pVar) == VT_BSTR ||
1481 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1482 "Wrong variant type for 'Target' property!\n");
1483 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1484
1485 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1486 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1487 if (!result) return E_INVALIDARG;
1488
1489 V_BSTR(pVar) = SysAllocString(wszPath);
1490 return S_OK;
1491 }
1492
1493 if (!lstrcmpW(pszPropName, wszAttributes)) {
1494 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1495 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1496 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1497 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1498 return S_OK;
1499 }
1500
1501 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1502 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1503 /* TODO */
1504 return E_INVALIDARG;
1505 }
1506
1507 if (!lstrcmpW(pszPropName, wszCLSID)) {
1508 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1509 /* TODO */
1510 return E_INVALIDARG;
1511 }
1512
1513 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1514 return E_INVALIDARG;
1515 }
1516
1517 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1518 VARIANT *pVar)
1519 {
1520 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1521 return E_NOTIMPL;
1522 }
1523
1524 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1525 InitPropertyBag_IPropertyBag_QueryInterface,
1526 InitPropertyBag_IPropertyBag_AddRef,
1527 InitPropertyBag_IPropertyBag_Release,
1528 InitPropertyBag_IPropertyBag_Read,
1529 InitPropertyBag_IPropertyBag_Write
1530 };
1531
1532 static struct IPropertyBag InitPropertyBag = {
1533 &InitPropertyBag_IPropertyBagVtbl
1534 };
1535
1536 static void test_FolderShortcut(void) {
1537 IPersistPropertyBag *pPersistPropertyBag;
1538 IShellFolder *pShellFolder, *pDesktopFolder;
1539 IPersistFolder3 *pPersistFolder3;
1540 HRESULT hr;
1541 STRRET strret;
1542 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1543 BOOL result;
1544 CLSID clsid;
1545 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1546 HKEY hShellExtKey;
1547 WCHAR wszWineTestFolder[] = {
1548 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1549 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1550 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1551 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1552 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1553 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1554 'N','a','m','e','S','p','a','c','e','\\',
1555 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1556 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1557
1558 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1559 static const GUID CLSID_UnixDosFolder =
1560 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1561
1562 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1563 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1564 return;
1565 }
1566
1567 if (!pSHGetFolderPathAndSubDirA)
1568 {
1569 win_skip("FolderShortcut test doesn't work on Win2k\n");
1570 return;
1571 }
1572
1573 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1574 * via their IPersistPropertyBag interface. And that the target folder
1575 * is taken from the IPropertyBag's 'Target' property.
1576 */
1577 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1578 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1579 if (hr == REGDB_E_CLASSNOTREG) {
1580 win_skip("CLSID_FolderShortcut is not implemented\n");
1581 return;
1582 }
1583 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1584 if (hr != S_OK) return;
1585
1586 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1587 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1588 if (hr != S_OK) {
1589 IPersistPropertyBag_Release(pPersistPropertyBag);
1590 return;
1591 }
1592
1593 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1594 (LPVOID*)&pShellFolder);
1595 IPersistPropertyBag_Release(pPersistPropertyBag);
1596 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1597 if (hr != S_OK) return;
1598
1599 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1600 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* win10 */,
1601 "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1602 if (hr != S_OK) {
1603 IShellFolder_Release(pShellFolder);
1604 return;
1605 }
1606
1607 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1608 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1609 if (!result) return;
1610
1611 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1612 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1613
1614 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1615 IShellFolder_Release(pShellFolder);
1616 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1617 if (hr != S_OK) return;
1618
1619 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1620 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1621 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1622
1623 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1624 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1625 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1626
1627 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1628 * shell namespace. The target folder, read from the property bag above, remains untouched.
1629 * The following tests show this: The itemidlist for some imaginary shellfolder object
1630 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1631 * itemidlist, but GetDisplayNameOf still returns the path from above.
1632 */
1633 hr = SHGetDesktopFolder(&pDesktopFolder);
1634 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1635 if (hr != S_OK) return;
1636
1637 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1638 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1639 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1640 RegCloseKey(hShellExtKey);
1641 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1642 &pidlWineTestFolder, NULL);
1643 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1644 IShellFolder_Release(pDesktopFolder);
1645 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1646 if (hr != S_OK) return;
1647
1648 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1649 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1650 if (hr != S_OK) {
1651 IPersistFolder3_Release(pPersistFolder3);
1652 pILFree(pidlWineTestFolder);
1653 return;
1654 }
1655
1656 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1657 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1658 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1659 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1660 pILFree(pidlCurrentFolder);
1661 pILFree(pidlWineTestFolder);
1662
1663 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1664 IPersistFolder3_Release(pPersistFolder3);
1665 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1666 if (hr != S_OK) return;
1667
1668 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1669 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1670 if (hr != S_OK) {
1671 IShellFolder_Release(pShellFolder);
1672 return;
1673 }
1674
1675 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1676 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1677
1678 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1679 * but ShellFSFolders. */
1680 myPathAddBackslashW(wszDesktopPath);
1681 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1682 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1683 IShellFolder_Release(pShellFolder);
1684 return;
1685 }
1686
1687 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1688 &pidlSubFolder, NULL);
1689 RemoveDirectoryW(wszDesktopPath);
1690 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1691 if (hr != S_OK) {
1692 IShellFolder_Release(pShellFolder);
1693 return;
1694 }
1695
1696 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1697 (LPVOID*)&pPersistFolder3);
1698 IShellFolder_Release(pShellFolder);
1699 pILFree(pidlSubFolder);
1700 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1701 if (hr != S_OK)
1702 return;
1703
1704 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1705 * a little bit and also allow CLSID_UnixDosFolder. */
1706 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1707 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1708 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1709 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1710
1711 IPersistFolder3_Release(pPersistFolder3);
1712 }
1713
1714 #include "pshpack1.h"
1715 struct FileStructA {
1716 BYTE type;
1717 BYTE dummy;
1718 DWORD dwFileSize;
1719 WORD uFileDate; /* In our current implementation this is */
1720 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1721 WORD uFileAttribs;
1722 CHAR szName[1];
1723 };
1724
1725 struct FileStructW {
1726 WORD cbLen; /* Length of this element. */
1727 BYTE abFooBar1[6]; /* Beyond any recognition. */
1728 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1729 WORD uTime; /* (this is currently speculation) */
1730 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1731 WORD uTime2; /* (this is currently speculation) */
1732 BYTE abFooBar2[4]; /* Beyond any recognition. */
1733 WCHAR wszName[1]; /* The long filename in unicode. */
1734 /* Just for documentation: Right after the unicode string: */
1735 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1736 * SHITEMID->cb == uOffset + cbLen */
1737 };
1738 #include "poppack.h"
1739
1740 static void test_ITEMIDLIST_format(void) {
1741 WCHAR wszPersonal[MAX_PATH];
1742 LPSHELLFOLDER psfDesktop, psfPersonal;
1743 LPITEMIDLIST pidlPersonal, pidlFile;
1744 HANDLE hFile;
1745 HRESULT hr;
1746 BOOL bResult;
1747 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1748 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1749 int i;
1750
1751 if (!pSHGetSpecialFolderPathW) return;
1752
1753 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1754 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1755 if (!bResult) return;
1756
1757 SetLastError(0xdeadbeef);
1758 bResult = SetCurrentDirectoryW(wszPersonal);
1759 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1760 win_skip("Most W-calls are not implemented\n");
1761 return;
1762 }
1763 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1764 if (!bResult) return;
1765
1766 hr = SHGetDesktopFolder(&psfDesktop);
1767 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1768 if (hr != S_OK) return;
1769
1770 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1771 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1772 if (hr != S_OK) {
1773 IShellFolder_Release(psfDesktop);
1774 return;
1775 }
1776
1777 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1778 (LPVOID*)&psfPersonal);
1779 IShellFolder_Release(psfDesktop);
1780 pILFree(pidlPersonal);
1781 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1782 if (hr != S_OK) return;
1783
1784 for (i=0; i<3; i++) {
1785 CHAR szFile[MAX_PATH];
1786 struct FileStructA *pFileStructA;
1787 WORD cbOffset;
1788
1789 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1790
1791 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1792 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1793 if (hFile == INVALID_HANDLE_VALUE) {
1794 IShellFolder_Release(psfPersonal);
1795 return;
1796 }
1797 CloseHandle(hFile);
1798
1799 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1800 DeleteFileW(wszFile[i]);
1801 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1802 if (hr != S_OK) {
1803 IShellFolder_Release(psfPersonal);
1804 return;
1805 }
1806
1807 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1808 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1809 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1810 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1811
1812 if (i < 2) /* First two file names are already in valid 8.3 format */
1813 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1814 else
1815 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1816 * can't implement this correctly, since unix filesystems don't support
1817 * this nasty short/long filename stuff. So we'll probably stay with our
1818 * current habit of storing the long filename here, which seems to work
1819 * just fine. */
1820 todo_wine
1821 ok(pidlFile->mkid.abID[18] == '~' ||
1822 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1823 "Should be derived 8.3 name!\n");
1824
1825 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1826 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1827 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1828 "Alignment byte, where there shouldn't be!\n");
1829
1830 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1831 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1832 "There should be an alignment byte, but isn't!\n");
1833
1834 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1835 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1836 ok ((cbOffset >= sizeof(struct FileStructA) &&
1837 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1838 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1839 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1840 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1841
1842 if (cbOffset >= sizeof(struct FileStructA) &&
1843 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1844 {
1845 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1846 WCHAR *name = pFileStructW->wszName;
1847
1848 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1849 "FileStructW's offset and length should add up to the PIDL's length!\n");
1850
1851 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1852 /* Since we just created the file, time of creation,
1853 * time of last access and time of last write access just be the same.
1854 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1855 * after the first run. I do remember something with NTFS keeping the creation time
1856 * if a file is deleted and then created again within a couple of seconds or so.
1857 * Might be the reason. */
1858 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1859 pFileStructA->uFileTime == pFileStructW->uTime,
1860 "Last write time should match creation time!\n");
1861
1862 /* On FAT filesystems the last access time is midnight
1863 local time, so the values of uDate2 and uTime2 will
1864 depend on the local timezone. If the times are exactly
1865 equal then the dates should be identical for both FAT
1866 and NTFS as no timezone is more than 1 day away from UTC.
1867 */
1868 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1869 {
1870 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1871 "Last write date and time should match last access date and time!\n");
1872 }
1873 else
1874 {
1875 /* Filesystem may be FAT. Check date within 1 day
1876 and seconds are zero. */
1877 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1878 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1879 "Last access time on FAT filesystems should have zero seconds.\n");
1880 /* TODO: Perform check for date being within one day.*/
1881 }
1882
1883 ok (!lstrcmpW(wszFile[i], name) ||
1884 !lstrcmpW(wszFile[i], name + 9) || /* Vista */
1885 !lstrcmpW(wszFile[i], name + 11) || /* Win7 */
1886 !lstrcmpW(wszFile[i], name + 13), /* Win8 */
1887 "The filename should be stored in unicode at this position!\n");
1888 }
1889 }
1890
1891 pILFree(pidlFile);
1892 }
1893
1894 IShellFolder_Release(psfPersonal);
1895 }
1896
1897 static void test_SHGetFolderPathA(void)
1898 {
1899 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1900 BOOL is_wow64;
1901 char path[MAX_PATH];
1902 char path_x86[MAX_PATH];
1903 char path_key[MAX_PATH];
1904 HRESULT hr;
1905 HKEY key;
1906
1907 if (!pSHGetFolderPathA)
1908 {
1909 win_skip("SHGetFolderPathA not present\n");
1910 return;
1911 }
1912 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1913
1914 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1915 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1916 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1917 if (hr == E_FAIL)
1918 {
1919 win_skip( "Program Files (x86) not supported\n" );
1920 return;
1921 }
1922 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1923 if (is_win64)
1924 {
1925 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1926 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1927 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1928 }
1929 else
1930 {
1931 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1932 if (is_wow64)
1933 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1934 else
1935 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1936 }
1937 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1938 {
1939 DWORD type, count = sizeof(path_x86);
1940 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1941 {
1942 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1943 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1944 }
1945 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1946 RegCloseKey( key );
1947 }
1948
1949 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1950 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1951 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1952 if (hr == E_FAIL)
1953 {
1954 win_skip( "Common Files (x86) not supported\n" );
1955 return;
1956 }
1957 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1958 if (is_win64)
1959 {
1960 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1961 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1962 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1963 }
1964 else
1965 {
1966 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1967 if (is_wow64)
1968 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1969 else
1970 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1971 }
1972 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1973 {
1974 DWORD type, count = sizeof(path_x86);
1975 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1976 {
1977 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1978 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1979 }
1980 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1981 }
1982 }
1983
1984 static void test_SHGetFolderPathAndSubDirA(void)
1985 {
1986 HRESULT ret;
1987 BOOL delret;
1988 DWORD dwret;
1989 int i;
1990 static const char wine[] = "wine";
1991 static const char winetemp[] = "wine\\temp";
1992 static char appdata[MAX_PATH];
1993 static char testpath[MAX_PATH];
1994 static char toolongpath[MAX_PATH+1];
1995
1996 if(!pSHGetFolderPathAndSubDirA)
1997 {
1998 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1999 return;
2000 }
2001
2002 if(!pSHGetFolderPathA) {
2003 win_skip("SHGetFolderPathA not present!\n");
2004 return;
2005 }
2006 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
2007 {
2008 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
2009 return;
2010 }
2011
2012 sprintf(testpath, "%s\\%s", appdata, winetemp);
2013 delret = RemoveDirectoryA(testpath);
2014 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
2015 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
2016 return;
2017 }
2018
2019 sprintf(testpath, "%s\\%s", appdata, wine);
2020 delret = RemoveDirectoryA(testpath);
2021 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
2022 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
2023 return;
2024 }
2025
2026 /* test invalid second parameter */
2027 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
2028 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
2029
2030 /* test fourth parameter */
2031 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
2032 switch(ret) {
2033 case S_OK: /* winvista */
2034 ok(!strncmp(appdata, testpath, strlen(appdata)),
2035 "expected %s to start with %s\n", testpath, appdata);
2036 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2037 "expected %s to end with %s\n", testpath, winetemp);
2038 break;
2039 case E_INVALIDARG: /* winxp, win2k3 */
2040 break;
2041 default:
2042 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
2043 }
2044
2045 /* test fifth parameter */
2046 testpath[0] = '\0';
2047 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
2048 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2049 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2050
2051 testpath[0] = '\0';
2052 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
2053 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2054 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2055
2056 testpath[0] = '\0';
2057 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
2058 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2059 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2060
2061 for(i=0; i< MAX_PATH; i++)
2062 toolongpath[i] = '0' + i % 10;
2063 toolongpath[MAX_PATH] = '\0';
2064 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2065 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2066 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2067
2068 testpath[0] = '\0';
2069 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2070 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2071
2072 /* test a not existing path */
2073 testpath[0] = '\0';
2074 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2075 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2076 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2077
2078 /* create a directory inside a not existing directory */
2079 testpath[0] = '\0';
2080 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2081 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2082 ok(!strncmp(appdata, testpath, strlen(appdata)),
2083 "expected %s to start with %s\n", testpath, appdata);
2084 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2085 "expected %s to end with %s\n", testpath, winetemp);
2086 dwret = GetFileAttributesA(testpath);
2087 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2088
2089 /* cleanup */
2090 sprintf(testpath, "%s\\%s", appdata, winetemp);
2091 RemoveDirectoryA(testpath);
2092 sprintf(testpath, "%s\\%s", appdata, wine);
2093 RemoveDirectoryA(testpath);
2094 }
2095
2096 static void test_LocalizedNames(void)
2097 {
2098 static char cCurrDirA[MAX_PATH];
2099 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2100 IShellFolder *IDesktopFolder, *testIShellFolder;
2101 ITEMIDLIST *newPIDL;
2102 int len;
2103 HRESULT hr;
2104 static char resourcefile[MAX_PATH];
2105 DWORD res;
2106 HANDLE file;
2107 STRRET strret;
2108 BOOL ret;
2109
2110 static const char desktopini_contents1[] =
2111 "[.ShellClassInfo]\r\n"
2112 "LocalizedResourceName=@";
2113 static const char desktopini_contents2[] =
2114 ",-1\r\n";
2115 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2116 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2117
2118 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2119 CreateDirectoryA(".\\testfolder", NULL);
2120
2121 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2122
2123 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2124
2125 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2126 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2127 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2128 ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2129 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2130 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
2131 ok(ret, "WriteFile failed %i\n", GetLastError());
2132 CloseHandle(file);
2133
2134 /* get IShellFolder for parent */
2135 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2136 len = lstrlenA(cCurrDirA);
2137
2138 if (len == 0) {
2139 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2140 goto cleanup;
2141 }
2142 if(cCurrDirA[len-1] == '\\')
2143 cCurrDirA[len-1] = 0;
2144
2145 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2146
2147 hr = SHGetDesktopFolder(&IDesktopFolder);
2148 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2149
2150 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2151 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2152
2153 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2154 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2155
2156 IMalloc_Free(ppM, newPIDL);
2157
2158 /* windows reads the display name from the resource */
2159 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2160 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2161
2162 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2163 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2164
2165 if (hr == S_OK && pStrRetToBufW)
2166 {
2167 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2168 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2169 todo_wine
2170 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2171 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2172 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2173 }
2174
2175 /* editing name is also read from the resource */
2176 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2177 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2178
2179 if (hr == S_OK && pStrRetToBufW)
2180 {
2181 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2182 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2183 todo_wine
2184 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2185 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2186 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2187 }
2188
2189 /* parsing name is unchanged */
2190 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2191 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2192
2193 if (hr == S_OK && pStrRetToBufW)
2194 {
2195 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2196 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2197 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2198 }
2199
2200 IShellFolder_Release(IDesktopFolder);
2201 IShellFolder_Release(testIShellFolder);
2202
2203 IMalloc_Free(ppM, newPIDL);
2204
2205 cleanup:
2206 DeleteFileA(".\\testfolder\\desktop.ini");
2207 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2208 RemoveDirectoryA(".\\testfolder");
2209 }
2210
2211 static void test_SHCreateShellItem(void)
2212 {
2213 IShellItem *shellitem, *shellitem2;
2214 IPersistIDList *persistidl;
2215 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2216 HRESULT ret;
2217 char curdirA[MAX_PATH];
2218 WCHAR curdirW[MAX_PATH];
2219 WCHAR fnbufW[MAX_PATH];
2220 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2221 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2222
2223 GetCurrentDirectoryA(MAX_PATH, curdirA);
2224
2225 if (!pSHCreateShellItem)
2226 {
2227 win_skip("SHCreateShellItem isn't available\n");
2228 return;
2229 }
2230
2231 if (!curdirA[0])
2232 {
2233 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2234 return;
2235 }
2236
2237 if(pSHGetSpecialFolderLocation)
2238 {
2239 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2240 ok(ret == S_OK, "Got 0x%08x\n", ret);
2241 }
2242 else
2243 {
2244 win_skip("pSHGetSpecialFolderLocation missing.\n");
2245 pidl_desktop = NULL;
2246 }
2247
2248 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2249
2250 ret = SHGetDesktopFolder(&desktopfolder);
2251 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2252
2253 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2254 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2255
2256 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2257 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2258
2259 CreateTestFile(".\\testfile");
2260
2261 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2262 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2263
2264 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2265
2266 shellitem = (void*)0xdeadbeef;
2267 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2268 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2269 ok(shellitem == 0, "Got %p\n", shellitem);
2270
2271 if (0) /* crashes on Windows XP */
2272 {
2273 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2274 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2275 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2276 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2277 }
2278
2279 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2280 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2281 if (SUCCEEDED(ret))
2282 {
2283 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2284 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2285 if (SUCCEEDED(ret))
2286 {
2287 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2288 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2289 if (SUCCEEDED(ret))
2290 {
2291 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2292 pILFree(pidl_test);
2293 }
2294 IPersistIDList_Release(persistidl);
2295 }
2296 IShellItem_Release(shellitem);
2297 }
2298
2299 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2300 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2301 if (SUCCEEDED(ret))
2302 {
2303 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2304 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2305 if (SUCCEEDED(ret))
2306 {
2307 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2308 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2309 if (SUCCEEDED(ret))
2310 {
2311 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2312 pILFree(pidl_test);
2313 }
2314 IPersistIDList_Release(persistidl);
2315 }
2316
2317 ret = IShellItem_GetParent(shellitem, &shellitem2);
2318 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2319 if (SUCCEEDED(ret))
2320 {
2321 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2322 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2323 if (SUCCEEDED(ret))
2324 {
2325 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2326 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2327 if (SUCCEEDED(ret))
2328 {
2329 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2330 pILFree(pidl_test);
2331 }
2332 IPersistIDList_Release(persistidl);
2333 }
2334 IShellItem_Release(shellitem2);
2335 }
2336
2337 IShellItem_Release(shellitem);
2338 }
2339
2340 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2341 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2342 if (SUCCEEDED(ret))
2343 {
2344 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2345 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2346 if (SUCCEEDED(ret))
2347 {
2348 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2349 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2350 if (SUCCEEDED(ret))
2351 {
2352 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2353 pILFree(pidl_test);
2354 }
2355 IPersistIDList_Release(persistidl);
2356 }
2357 IShellItem_Release(shellitem);
2358 }
2359
2360 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2361 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2362 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2363 if (SUCCEEDED(ret))
2364 {
2365 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2366 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2367 if (SUCCEEDED(ret))
2368 {
2369 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2370 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2371 if (SUCCEEDED(ret))
2372 {
2373 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2374 pILFree(pidl_test);
2375 }
2376 IPersistIDList_Release(persistidl);
2377 }
2378 IShellItem_Release(shellitem);
2379 }
2380
2381 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2382 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2383 if (SUCCEEDED(ret))
2384 {
2385 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2386 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2387 if (SUCCEEDED(ret))
2388 {
2389 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2390 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2391 if (SUCCEEDED(ret))
2392 {
2393 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2394 pILFree(pidl_test);
2395 }
2396 IPersistIDList_Release(persistidl);
2397 }
2398
2399 IShellItem_Release(shellitem);
2400 }
2401
2402 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2403 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2404 if (SUCCEEDED(ret))
2405 {
2406 ret = IShellItem_GetParent(shellitem, &shellitem2);
2407 ok(FAILED(ret), "Got 0x%08x\n", ret);
2408 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2409 IShellItem_Release(shellitem);
2410 }
2411
2412 /* SHCreateItemFromParsingName */
2413 if(pSHCreateItemFromParsingName)
2414 {
2415 if(0)
2416 {
2417 /* Crashes under windows 7 */
2418 pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2419 }
2420
2421 shellitem = (void*)0xdeadbeef;
2422 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2423 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2424 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2425
2426 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2427 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2428 "SHCreateItemFromParsingName returned %x\n", ret);
2429 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2430
2431 lstrcpyW(fnbufW, curdirW);
2432 myPathAddBackslashW(fnbufW);
2433 lstrcatW(fnbufW, testfileW);
2434
2435 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2436 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2437 if(SUCCEEDED(ret))
2438 {
2439 LPWSTR tmp_fname;
2440 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2441 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2442 if(SUCCEEDED(ret))
2443 {
2444 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2445 CoTaskMemFree(tmp_fname);
2446 }
2447 IShellItem_Release(shellitem);
2448 }
2449 }
2450 else
2451 win_skip("No SHCreateItemFromParsingName\n");
2452
2453
2454 /* SHCreateItemFromIDList */
2455 if(pSHCreateItemFromIDList)
2456 {
2457 if(0)
2458 {
2459 /* Crashes under win7 */
2460 pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2461 }
2462
2463 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2464 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2465
2466 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2467 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2468 if (SUCCEEDED(ret))
2469 {
2470 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2471 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2472 if (SUCCEEDED(ret))
2473 {
2474 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2475 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2476 if (SUCCEEDED(ret))
2477 {
2478 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2479 pILFree(pidl_test);
2480 }
2481 IPersistIDList_Release(persistidl);
2482 }
2483 IShellItem_Release(shellitem);
2484 }
2485
2486 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2487 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2488 if (SUCCEEDED(ret))
2489 {
2490 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2491 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2492 if (SUCCEEDED(ret))
2493 {
2494 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2495 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2496 if (SUCCEEDED(ret))
2497 {
2498 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2499 pILFree(pidl_test);
2500 }
2501 IPersistIDList_Release(persistidl);
2502 }
2503 IShellItem_Release(shellitem);
2504 }
2505 }
2506 else
2507 win_skip("No SHCreateItemFromIDList\n");
2508
2509 /* SHCreateItemFromRelativeName */
2510 if(pSHCreateItemFromRelativeName && pSHGetKnownFolderPath)
2511 {
2512 IShellItem *shellitem_desktop = NULL;
2513 WCHAR *desktop_path, *displayname;
2514 WCHAR testfile_path[MAX_PATH] = {0};
2515 HANDLE file;
2516 LPITEMIDLIST pidl_desktop_testfile = NULL;
2517 int order;
2518
2519 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem_desktop);
2520 ok(ret == S_OK, "SHCreateShellItem failed: 0x%08x.\n", ret);
2521
2522 shellitem = (void*)0xdeadbeef;
2523 ret = pSHCreateItemFromRelativeName(shellitem_desktop, NULL, NULL, &IID_IShellItem,
2524 (void**)&shellitem);
2525 ok(ret == E_INVALIDARG, "Expected 0x%08x but SHCreateItemFromRelativeName return: 0x%08x.\n",
2526 E_INVALIDARG, ret);
2527 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2528
2529 /* Test with a non-existent file */
2530 shellitem = (void*)0xdeadbeef;
2531 ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2532 (void**)&shellitem);
2533 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2534 "Expected 0x%08x but SHCreateItemFromRelativeName return: 0x%08x.\n",
2535 HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), ret);
2536 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2537
2538 /* Create a file for testing in desktop folder */
2539 pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &desktop_path);
2540 lstrcatW(testfile_path, desktop_path);
2541 myPathAddBackslashW(testfile_path);
2542 lstrcatW(testfile_path, testfileW);
2543 file = CreateFileW(testfile_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
2544 ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: 0x%08x.\n", GetLastError());
2545 CloseHandle(file);
2546
2547 shellitem = (void*)0xdeadbeef;
2548 ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2549 (void**)&shellitem);
2550 ok(ret == S_OK, "SHCreateItemFromRelativeName failed: 0x%08x.\n", ret);
2551 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2552 if(SUCCEEDED(ret))
2553 {
2554 ret = IShellItem_GetDisplayName(shellitem, 0, &displayname);
2555 ok(ret == S_OK, "IShellItem_GetDisplayName failed: 0x%08x.\n", ret);
2556 ok(!lstrcmpW(displayname, testfileW), "got wrong display name: %s.\n", wine_dbgstr_w(displayname));
2557 CoTaskMemFree(displayname);
2558
2559 shellitem2 = (void*)0xdeadbeef;
2560 ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2561 (void**)&shellitem2);
2562 ok(ret == S_OK, "SHCreateItemFromRelativeName failed: 0x%08x.\n", ret);
2563 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2564 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2565 ok(!order, "order got wrong value: %d.\n", order);
2566 IShellItem_Release(shellitem2);
2567
2568 shellitem2 = (void*)0xdeadbeef;
2569 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, testfileW, NULL,
2570 &pidl_desktop_testfile, NULL);
2571 ok(ret == S_OK, "ParseDisplayName failed 0x%08x.\n", ret);
2572 ret = pSHCreateItemFromIDList(pidl_desktop_testfile, &IID_IShellItem, (void**)&shellitem2);
2573 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2574 ok(ret == S_OK, "IShellItem_Compare fail: 0x%08x.\n", ret);
2575 ok(!order, "order got wrong value: %d.\n", order);
2576 pILFree(pidl_desktop_testfile);
2577 IShellItem_Release(shellitem2);
2578
2579 IShellItem_Release(shellitem);
2580 }
2581
2582 DeleteFileW(testfile_path);
2583 CoTaskMemFree(desktop_path);
2584 IShellItem_Release(shellitem_desktop);
2585 }
2586 else
2587 win_skip("No SHCreateItemFromRelativeName or SHGetKnownFolderPath\n");
2588
2589 /* SHCreateItemInKnownFolder */
2590 if(pSHCreateItemInKnownFolder && pSHGetKnownFolderPath)
2591 {
2592 WCHAR *desktop_path;
2593 WCHAR testfile_path[MAX_PATH] = {0};
2594 HANDLE file;
2595 WCHAR *displayname = NULL;
2596 int order;
2597 LPITEMIDLIST pidl_desktop_testfile = NULL;
2598
2599 shellitem = (void*)0xdeadbeef;
2600 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, NULL, &IID_IShellItem,
2601 (void**)&shellitem);
2602 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2603 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2604 if(SUCCEEDED(ret))
2605 {
2606 shellitem2 = (void*)0xdeadbeef;
2607 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem2);
2608 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2609 if(SUCCEEDED(ret))
2610 {
2611 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2612 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2613 ok(!order, "order got wrong value: %d.\n", order);
2614 IShellItem_Release(shellitem2);
2615 }
2616 IShellItem_Release(shellitem);
2617 }
2618
2619 /* Test with a non-existent file */
2620 shellitem = (void*)0xdeadbeef;
2621 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2622 (void**)&shellitem);
2623 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2624 "Expected 0x%08x but SHCreateItemInKnownFolder return: 0x%08x.\n",
2625 HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), ret);
2626 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2627
2628 pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &desktop_path);
2629 lstrcatW(testfile_path, desktop_path);
2630 myPathAddBackslashW(testfile_path);
2631 lstrcatW(testfile_path, testfileW);
2632 file = CreateFileW(testfile_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
2633 ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: 0x%08x.\n", GetLastError());
2634 CloseHandle(file);
2635
2636 shellitem = (void*)0xdeadbeef;
2637 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2638 (void**)&shellitem);
2639 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2640 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2641 if(SUCCEEDED(ret))
2642 {
2643 ret = IShellItem_GetDisplayName(shellitem, 0, &displayname);
2644 ok(ret == S_OK, "IShellItem_GetDisplayName failed: 0x%08x.\n", ret);
2645 ok(!lstrcmpW(displayname, testfileW), "got wrong display name: %s.\n",
2646 wine_dbgstr_w(displayname));
2647 CoTaskMemFree(displayname);
2648
2649 shellitem2 = (void*)0xdeadbeef;
2650 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2651 (void**)&shellitem2);
2652 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2653 ok(shellitem2 != NULL, "shellitem was %p.\n", shellitem);
2654 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2655 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2656 ok(!order, "order got wrong value: %d.\n", order);
2657 IShellItem_Release(shellitem2);
2658
2659 shellitem2 = (void*)0xdeadbeef;
2660 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, testfileW, NULL,
2661 &pidl_desktop_testfile, NULL);
2662 ok(SUCCEEDED(ret), "ParseDisplayName returned %x.\n", ret);
2663 ret = pSHCreateItemFromIDList(pidl_desktop_testfile, &IID_IShellItem, (void**)&shellitem2);
2664 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2665 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2666 ok(!order, "order got wrong value: %d.\n", order);
2667 pILFree(pidl_desktop_testfile);
2668 IShellItem_Release(shellitem2);
2669
2670 IShellItem_Release(shellitem);
2671 }
2672
2673 shellitem = (void*)0xdeadbeef;
2674 ret = pSHCreateItemInKnownFolder(&FOLDERID_Documents, 0, NULL, &IID_IShellItem,
2675 (void**)&shellitem);
2676 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2677 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2678 if(SUCCEEDED(ret))
2679 {
2680 shellitem2 = (void*)0xdeadbeef;
2681 ret = pSHCreateItemInKnownFolder(&FOLDERID_Documents, 0, NULL, &IID_IShellItem,
2682 (void**)&shellitem2);
2683 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2684 ok(shellitem2 != NULL, "shellitem was %p.\n", shellitem);
2685 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2686 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2687 ok(!order, "order got wrong value: %d.\n", order);
2688 IShellItem_Release(shellitem2);
2689
2690 IShellItem_Release(shellitem);
2691 }
2692 DeleteFileW(testfile_path);
2693 CoTaskMemFree(desktop_path);
2694 }
2695 else
2696 win_skip("No SHCreateItemInKnownFolder or SHGetKnownFolderPath\n");
2697
2698 DeleteFileA(".\\testfile");
2699 pILFree(pidl_abstestfile);
2700 pILFree(pidl_testfile);
2701 pILFree(pidl_desktop);
2702 pILFree(pidl_cwd);
2703 IShellFolder_Release(currentfolder);
2704 IShellFolder_Release(desktopfolder);
2705 }
2706
2707 static void test_SHGetNameFromIDList(void)
2708 {
2709 IShellItem *shellitem;
2710 LPITEMIDLIST pidl;
2711 LPWSTR name_string;
2712 HRESULT hres;
2713 UINT i;
2714 static const DWORD flags[] = {
2715 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2716 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2717 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2718 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2719
2720 if(!pSHGetNameFromIDList)
2721 {
2722 win_skip("SHGetNameFromIDList missing.\n");
2723 return;
2724 }
2725
2726 /* These should be available on any platform that passed the above test. */
2727 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2728 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2729 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2730 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2731
2732 if(0)
2733 {
2734 /* Crashes under win7 */
2735 pSHGetNameFromIDList(NULL, 0, NULL);
2736 }
2737
2738 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2739 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2740
2741 /* Test the desktop */
2742 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2743 ok(hres == S_OK, "Got 0x%08x\n", hres);
2744 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2745 ok(hres == S_OK, "Got 0x%08x\n", hres);
2746 if(SUCCEEDED(hres))
2747 {
2748 WCHAR *nameSI, *nameSH;
2749 WCHAR buf[MAX_PATH];
2750 HRESULT hrSI, hrSH, hrSF;
2751 STRRET strret;
2752 IShellFolder *psf;
2753 BOOL res;
2754
2755 SHGetDesktopFolder(&psf);
2756 for(i = 0; flags[i] != -1234; i++)
2757 {
2758 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2759 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2760 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2761 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2762 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2763 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2764
2765 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2766 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2767
2768 if(SUCCEEDED(hrSF))
2769 {
2770 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2771 if(SUCCEEDED(hrSI))
2772 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2773 if(SUCCEEDED(hrSF))
2774 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2775 }
2776 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2777 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2778 }
2779 IShellFolder_Release(psf);
2780
2781 if(pSHGetPathFromIDListW){
2782 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2783 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2784 res = pSHGetPathFromIDListW(pidl, buf);
2785 ok(res == TRUE, "Got %d\n", res);
2786 if(SUCCEEDED(hrSI) && res)
2787 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2788 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2789 }else
2790 win_skip("pSHGetPathFromIDListW not available\n");
2791
2792 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2793 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2794 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2795
2796 IShellItem_Release(shellitem);
2797 }
2798 pILFree(pidl);
2799
2800 /* Test the control panel */
2801 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2802 ok(hres == S_OK, "Got 0x%08x\n", hres);
2803 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2804 ok(hres == S_OK, "Got 0x%08x\n", hres);
2805 if(SUCCEEDED(hres))
2806 {
2807 WCHAR *nameSI, *nameSH;
2808 WCHAR buf[MAX_PATH];
2809 HRESULT hrSI, hrSH, hrSF;
2810 STRRET strret;
2811 IShellFolder *psf;
2812 BOOL res;
2813
2814 SHGetDesktopFolder(&psf);
2815 for(i = 0; flags[i] != -1234; i++)
2816 {
2817 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2818 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2819 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2820 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2821 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2822 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2823
2824 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2825 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2826
2827 if(SUCCEEDED(hrSF))
2828 {
2829 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2830 if(SUCCEEDED(hrSI))
2831 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2832 if(SUCCEEDED(hrSF))
2833 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2834 }
2835 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2836 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2837 }
2838 IShellFolder_Release(psf);
2839
2840 if(pSHGetPathFromIDListW){
2841 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2842 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2843 res = pSHGetPathFromIDListW(pidl, buf);
2844 ok(res == FALSE, "Got %d\n", res);
2845 if(SUCCEEDED(hrSI) && res)
2846 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2847 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2848 }else
2849 win_skip("pSHGetPathFromIDListW not available\n");
2850
2851 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2852 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2853 "Got 0x%08x\n", hres);
2854 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2855
2856 IShellItem_Release(shellitem);
2857 }
2858 pILFree(pidl);
2859 }
2860
2861 static void test_SHGetItemFromDataObject(void)
2862 {
2863 IShellFolder *psfdesktop;
2864 IShellItem *psi;
2865 IShellView *psv;
2866 HRESULT hres;
2867
2868 if(!pSHGetItemFromDataObject)
2869 {
2870 win_skip("No SHGetItemFromDataObject.\n");
2871 return;
2872 }
2873
2874 if(0)
2875 {
2876 /* Crashes under win7 */
2877 pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2878 }
2879
2880 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2881 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2882
2883 SHGetDesktopFolder(&psfdesktop);
2884
2885 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2886 ok(hres == S_OK, "got 0x%08x\n", hres);
2887 if(SUCCEEDED(hres))
2888 {
2889 IEnumIDList *peidl;
2890 IDataObject *pdo;
2891 SHCONTF enum_flags;
2892
2893 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2894 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2895 ok(hres == S_OK, "got 0x%08x\n", hres);
2896 if(SUCCEEDED(hres))
2897 {
2898 LPITEMIDLIST apidl[5];
2899 UINT count = 0, i;
2900
2901 for(count = 0; count < 5; count++)
2902 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2903 break;
2904
2905 if(count)
2906 {
2907 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2908 &IID_IDataObject, NULL, (void**)&pdo);
2909 ok(hres == S_OK, "got 0x%08x\n", hres);
2910 if(SUCCEEDED(hres))
2911 {
2912 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2913 ok(hres == S_OK, "got 0x%08x\n", hres);
2914 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2915 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2916 ok(hres == S_OK, "got 0x%08x\n", hres);
2917 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2918 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2919 ok(hres == S_OK, "got 0x%08x\n", hres);
2920 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2921 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2922 ok(hres == S_OK, "got 0x%08x\n", hres);
2923 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2924 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2925 ok(hres == S_OK, "got 0x%08x\n", hres);
2926 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2927
2928 IDataObject_Release(pdo);
2929 }
2930 }
2931 else
2932 skip("No file(s) found - skipping single-file test.\n");
2933
2934 if(count > 1)
2935 {
2936 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2937 &IID_IDataObject, NULL, (void**)&pdo);
2938 ok(hres == S_OK, "got 0x%08x\n", hres);
2939 if(SUCCEEDED(hres))
2940 {
2941 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2942 ok(hres == S_OK, "got 0x%08x\n", hres);
2943 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2944 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2945 ok(hres == S_OK, "got 0x%08x\n", hres);
2946 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2947 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2948 ok(hres == S_OK, "got 0x%08x\n", hres);
2949 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2950 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2951 ok(hres == S_OK, "got 0x%08x\n", hres);
2952 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2953 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2954 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2955 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2956 IDataObject_Release(pdo);
2957 }
2958 }
2959 else
2960 skip("zero or one file found - skipping multi-file test.\n");
2961
2962 for(i = 0; i < count; i++)
2963 pILFree(apidl[i]);
2964
2965 IEnumIDList_Release(peidl);
2966 }
2967
2968 IShellView_Release(psv);
2969 }
2970
2971 IShellFolder_Release(psfdesktop);
2972 }
2973
2974 static void test_ShellItemCompare(void)
2975 {
2976 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2977 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2978 IShellFolder *psf_desktop, *psf_current;
2979 LPITEMIDLIST pidl_cwd;
2980 WCHAR curdirW[MAX_PATH];
2981 BOOL failed;
2982 HRESULT hr;
2983 static const WCHAR filesW[][9] = {
2984 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2985 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2986 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2987 int order;
2988 UINT i;
2989
2990 if(!pSHCreateShellItem)
2991 {
2992 win_skip("SHCreateShellItem missing.\n");
2993 return;
2994 }
2995
2996 GetCurrentDirectoryW(MAX_PATH, curdirW);
2997 if (!curdirW[0])
2998 {
2999 skip("Failed to get current directory, skipping.\n");
3000 return;
3001 }
3002
3003 CreateDirectoryA(".\\a", NULL);
3004 CreateDirectoryA(".\\b", NULL);
3005 CreateDirectoryA(".\\c", NULL);
3006 CreateTestFile(".\\a\\a");
3007 CreateTestFile(".\\a\\b");
3008 CreateTestFile(".\\a\\c");
3009 CreateTestFile(".\\b\\a");
3010 CreateTestFile(".\\b\\b");
3011 CreateTestFile(".\\b\\c");
3012 CreateTestFile(".\\c\\a");
3013 CreateTestFile(".\\c\\b");
3014 CreateTestFile(".\\c\\c");
3015
3016 SHGetDesktopFolder(&psf_desktop);
3017 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
3018 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
3019 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
3020 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
3021 IShellFolder_Release(psf_desktop);
3022 ILFree(pidl_cwd);
3023
3024 /* Generate ShellItems for the files */
3025 memset(&psi, 0, sizeof(psi));
3026 failed = FALSE;
3027 for(i = 0; i < 9; i++)
3028 {
3029 LPITEMIDLIST pidl_testfile = NULL;
3030
3031 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
3032 NULL, &pidl_testfile, NULL);
3033 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
3034 if(SUCCEEDED(hr))
3035 {
3036 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
3037 ok(hr == S_OK, "Got 0x%08x\n", hr);
3038 pILFree(pidl_testfile);
3039 }
3040 if(FAILED(hr)) failed = TRUE;
3041 }
3042 if(failed)
3043 {
3044 skip("Failed to create all shellitems.\n");
3045 goto cleanup;
3046 }
3047
3048 /* Generate ShellItems for the folders */
3049 hr = IShellItem_GetParent(psi[0], &psi_a);
3050 ok(hr == S_OK, "Got 0x%08x\n", hr);
3051 if(FAILED(hr)) failed = TRUE;
3052 hr = IShellItem_GetParent(psi[3], &psi_b);
3053 ok(hr == S_OK, "Got 0x%08x\n", hr);
3054 if(FAILED(hr)) failed = TRUE;
3055 hr = IShellItem_GetParent(psi[6], &psi_c);
3056 ok(hr == S_OK, "Got 0x%08x\n", hr);
3057 if(FAILED(hr)) failed = TRUE;
3058
3059 if(failed)
3060 {
3061 skip("Failed to create shellitems.\n");
3062 goto cleanup;
3063 }
3064
3065 if(0)
3066 {
3067 /* Crashes on native (win7, winxp) */
3068 IShellItem_Compare(psi_a, NULL, 0, NULL);
3069 IShellItem_Compare(psi_a, psi_b, 0, NULL);
3070 IShellItem_Compare(psi_a, NULL, 0, &order);
3071 }
3072
3073 /* Basics */
3074 for(i = 0; i < 9; i++)
3075 {
3076 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
3077 ok(hr == S_OK, "Got 0x%08x\n", hr);
3078 ok(order == 0, "Got order %d\n", order);
3079 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
3080 ok(hr == S_OK, "Got 0x%08x\n", hr);
3081 ok(order == 0, "Got order %d\n", order);
3082 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
3083 ok(hr == S_OK, "Got 0x%08x\n", hr);
3084 ok(order == 0, "Got order %d\n", order);
3085 }
3086
3087 /* Order */
3088 /* a\b:a\a , a\b:a\c, a\b:a\b */
3089 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
3090 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3091 ok(order == 1, "Got order %d\n", order);
3092 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
3093 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3094 ok(order == -1, "Got order %d\n", order);
3095 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
3096 ok(hr == S_OK, "Got 0x%08x\n", hr);
3097 ok(order == 0, "Got order %d\n", order);
3098
3099 /* b\b:a\b, b\b:c\b, b\b:c\b */
3100 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
3101 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3102 ok(order == 1, "Got order %d\n", order);
3103 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
3104 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3105 ok(order == -1, "Got order %d\n", order);
3106 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
3107 ok(hr == S_OK, "Got 0x%08x\n", hr);
3108 ok(order == 0, "Got order %d\n", order);
3109
3110 /* b:a\a, b:a\c, b:a\b */
3111 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
3112 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3113 todo_wine ok(order == 1, "Got order %d\n", order);
3114 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
3115 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3116 todo_wine ok(order == 1, "Got order %d\n", order);
3117 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
3118 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3119 todo_wine ok(order == 1, "Got order %d\n", order);
3120
3121 /* b:c\a, b:c\c, b:c\b */
3122 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
3123 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3124 ok(order == -1, "Got order %d\n", order);
3125 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
3126 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3127 ok(order == -1, "Got order %d\n", order);
3128 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
3129 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3130 ok(order == -1, "Got order %d\n", order);
3131
3132 /* a\b:a\a , a\b:a\c, a\b:a\b */
3133 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
3134 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3135 ok(order == 1, "Got order %d\n", order);
3136 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
3137 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3138 ok(order == -1, "Got order %d\n", order);
3139 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
3140 ok(hr == S_OK, "Got 0x%08x\n", hr);
3141 ok(order == 0, "Got order %d\n", order);
3142
3143 /* b\b:a\b, b\b:c\b, b\b:c\b */
3144 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
3145 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3146 ok(order == 1, "Got order %d\n", order);
3147 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
3148 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3149 ok(order == -1, "Got order %d\n", order);
3150 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
3151 ok(hr == S_OK, "Got 0x%08x\n", hr);
3152 ok(order == 0, "Got order %d\n", order);
3153
3154 /* b:a\a, b:a\c, b:a\b */
3155 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
3156 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3157 todo_wine ok(order == 1, "Got order %d\n", order);
3158 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
3159 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3160 todo_wine ok(order == 1, "Got order %d\n", order);
3161 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
3162 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3163 todo_wine ok(order == 1, "Got order %d\n", order);
3164
3165 /* b:c\a, b:c\c, b:c\b */
3166 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
3167 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3168 ok(order == -1, "Got order %d\n", order);
3169 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
3170 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3171 ok(order == -1, "Got order %d\n", order);
3172 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
3173 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3174 ok(order == -1, "Got order %d\n", order);
3175
3176 cleanup:
3177 IShellFolder_Release(psf_current);
3178
3179 DeleteFileA(".\\a\\a");
3180 DeleteFileA(".\\a\\b");
3181 DeleteFileA(".\\a\\c");
3182 DeleteFileA(".\\b\\a");
3183 DeleteFileA(".\\b\\b");
3184 DeleteFileA(".\\b\\c");
3185 DeleteFileA(".\\c\\a");
3186 DeleteFileA(".\\c\\b");
3187 DeleteFileA(".\\c\\c");
3188 RemoveDirectoryA(".\\a");
3189 RemoveDirectoryA(".\\b");
3190 RemoveDirectoryA(".\\c");
3191
3192 if(psi_a) IShellItem_Release(psi_a);
3193 if(psi_b) IShellItem_Release(psi_b);
3194 if(psi_c) IShellItem_Release(psi_c);
3195
3196 for(i = 0; i < 9; i++)
3197 if(psi[i]) IShellItem_Release(psi[i]);
3198 }
3199
3200 /**************************************************************/
3201 /* IUnknown implementation for counting QueryInterface calls. */
3202 typedef struct {
3203 IUnknown IUnknown_iface;
3204 struct if_count {
3205 REFIID id;
3206 LONG count;
3207 } *ifaces;
3208 LONG unknown;
3209 } IUnknownImpl;
3210
3211 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
3212 {
3213 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
3214 }
3215
3216 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
3217 {
3218 IUnknownImpl *This = impl_from_IUnknown(iunk);
3219 UINT i;
3220 BOOL found = FALSE;
3221 for(i = 0; This->ifaces[i].id != NULL; i++)
3222 {
3223 if(IsEqualIID(This->ifaces[i].id, riid))
3224 {
3225 This->ifaces[i].count++;
3226 found = TRUE;
3227 break;
3228 }
3229 }
3230 if(!found)
3231 This->unknown++;
3232 return E_NOINTERFACE;
3233 }
3234
3235 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
3236 {
3237 return 2;
3238 }
3239
3240 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3241 {
3242 return 1;
3243 }
3244
3245 static const IUnknownVtbl vt_IUnknown = {
3246 unk_fnQueryInterface,
3247 unk_fnAddRef,
3248 unk_fnRelease
3249 };
3250
3251 static void test_SHGetIDListFromObject(void)
3252 {
3253 IUnknownImpl *punkimpl;
3254 IShellFolder *psfdesktop;
3255 IShellView *psv;
3256 LPITEMIDLIST pidl, pidl_desktop;
3257 HRESULT hres;
3258 UINT i;
3259 struct if_count ifaces[] =
3260 { {&IID_IPersistIDList, 0},
3261 {&IID_IPersistFolder2, 0},
3262 {&IID_IDataObject, 0},
3263 {&IID_IParentAndItem, 0},
3264 {&IID_IFolderView, 0},
3265 {NULL, 0} };
3266
3267 if(!pSHGetIDListFromObject)
3268 {
3269 win_skip("SHGetIDListFromObject missing.\n");
3270 return;
3271 }
3272
3273 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3274
3275 if(0)
3276 {
3277 /* Crashes native */
3278 pSHGetIDListFromObject(NULL, NULL);
3279 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3280 }
3281
3282 hres = pSHGetIDListFromObject(NULL, &pidl);
3283 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3284
3285 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3286 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3287 punkimpl->ifaces = ifaces;
3288 punkimpl->unknown = 0;
3289
3290 hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3291 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3292 ok(ifaces[0].count, "interface not requested.\n");
3293 ok(ifaces[1].count, "interface not requested.\n");
3294 ok(ifaces[2].count, "interface not requested.\n");
3295 todo_wine
3296 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3297 "interface not requested.\n");
3298 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3299 "interface not requested.\n");
3300
3301 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3302 HeapFree(GetProcessHeap(), 0, punkimpl);
3303
3304 pidl_desktop = NULL;
3305 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3306 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3307
3308 SHGetDesktopFolder(&psfdesktop);
3309
3310 /* Test IShellItem */
3311 if(pSHCreateShellItem)
3312 {
3313 IShellItem *shellitem;
3314 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3315 ok(hres == S_OK, "got 0x%08x\n", hres);
3316 if(SUCCEEDED(hres))
3317 {
3318 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3319 ok(hres == S_OK, "got 0x%08x\n", hres);
3320 if(SUCCEEDED(hres))
3321 {
3322 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3323 pILFree(pidl);
3324 }
3325 IShellItem_Release(shellitem);
3326 }
3327 }
3328 else
3329 skip("no SHCreateShellItem.\n");
3330
3331 /* Test IShellFolder */
3332 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3333 ok(hres == S_OK, "got 0x%08x\n", hres);
3334 if(SUCCEEDED(hres))
3335 {
3336 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3337 pILFree(pidl);
3338 }
3339
3340 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3341 ok(hres == S_OK, "got 0x%08x\n", hres);
3342 if(SUCCEEDED(hres))
3343 {
3344 IEnumIDList *peidl;
3345 IDataObject *pdo;
3346 SHCONTF enum_flags;
3347
3348 /* Test IFolderView */
3349 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3350 ok(hres == S_OK, "got 0x%08x\n", hres);
3351 if(SUCCEEDED(hres))
3352 {
3353 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3354 pILFree(pidl);
3355 }
3356
3357 /* Test IDataObject */
3358 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3359 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3360 ok(hres == S_OK, "got 0x%08x\n", hres);
3361 if(SUCCEEDED(hres))
3362 {
3363 LPITEMIDLIST apidl[5];
3364 UINT count = 0;
3365 for(count = 0; count < 5; count++)
3366 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3367 break;
3368
3369 if(count)
3370 {
3371 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3372 &IID_IDataObject, NULL, (void**)&pdo);
3373 ok(hres == S_OK, "got 0x%08x\n", hres);
3374 if(SUCCEEDED(hres))
3375 {
3376 pidl = (void*)0xDEADBEEF;
3377 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3378 ok(hres == S_OK, "got 0x%08x\n", hres);
3379 ok(pidl != NULL, "pidl is NULL.\n");
3380 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3381 pILFree(pidl);
3382
3383 IDataObject_Release(pdo);
3384 }
3385 }
3386 else
3387 skip("No files found - skipping single-file test.\n");
3388
3389 if(count > 1)
3390 {
3391 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3392 &IID_IDataObject, NULL, (void**)&pdo);
3393 ok(hres == S_OK, "got 0x%08x\n", hres);
3394 if(SUCCEEDED(hres))
3395 {
3396 pidl = (void*)0xDEADBEEF;
3397 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3398 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3399 "got 0x%08x\n", hres);
3400 ok(pidl == NULL, "pidl is not NULL.\n");
3401
3402 IDataObject_Release(pdo);
3403 }
3404 }
3405 else
3406 skip("zero or one file found - skipping multi-file test.\n");
3407
3408 for(i = 0; i < count; i++)
3409 pILFree(apidl[i]);
3410
3411 IEnumIDList_Release(peidl);
3412 }
3413
3414 IShellView_Release(psv);
3415 }
3416
3417 IShellFolder_Release(psfdesktop);
3418 pILFree(pidl_desktop);
3419 }
3420
3421 static void test_SHGetItemFromObject(void)
3422 {
3423 IUnknownImpl *punkimpl;
3424 IShellFolder *psfdesktop;
3425 LPITEMIDLIST pidl;
3426 IShellItem *psi;
3427 IUnknown *punk;
3428 HRESULT hres;
3429 struct if_count ifaces[] =
3430 { {&IID_IPersistIDList, 0},
3431 {&IID_IPersistFolder2, 0},
3432 {&IID_IDataObject, 0},
3433 {&IID_IParentAndItem, 0},
3434 {&IID_IFolderView, 0},
3435 {NULL, 0} };
3436
3437 if(!pSHGetItemFromObject)
3438 {
3439 skip("No SHGetItemFromObject.\n");
3440 return;
3441 }
3442
3443 SHGetDesktopFolder(&psfdesktop);
3444
3445 if(0)
3446 {
3447 /* Crashes with Windows 7 */
3448 pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3449 pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3450 pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3451 }
3452
3453 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3454 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3455
3456 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3457 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3458 punkimpl->ifaces = ifaces;
3459 punkimpl->unknown = 0;
3460
3461 /* The same as SHGetIDListFromObject */
3462 hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3463 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3464 ok(ifaces[0].count, "interface not requested.\n");
3465 ok(ifaces[1].count, "interface not requested.\n");
3466 ok(ifaces[2].count, "interface not requested.\n");
3467 todo_wine
3468 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3469 "interface not requested.\n");
3470 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3471 "interface not requested.\n");
3472
3473 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3474 HeapFree(GetProcessHeap(), 0, punkimpl);
3475
3476 /* Test IShellItem */
3477 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3478 ok(hres == S_OK, "Got 0x%08x\n", hres);
3479 if(SUCCEEDED(hres))
3480 {
3481 IShellItem *psi2;
3482 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3483 ok(hres == S_OK, "Got 0x%08x\n", hres);
3484 if(SUCCEEDED(hres))
3485 {
3486 todo_wine
3487 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3488 IShellItem_Release(psi2);
3489 }
3490 IShellItem_Release(psi);
3491 }
3492
3493 IShellFolder_Release(psfdesktop);
3494 }
3495
3496 static void test_SHCreateShellItemArray(void)
3497 {
3498 IShellFolder *pdesktopsf, *psf;
3499 IShellItemArray *psia;
3500 IEnumIDList *peidl;
3501 HRESULT hr;
3502 WCHAR cTestDirW[MAX_PATH];
3503 LPITEMIDLIST pidl_testdir, pidl;
3504 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3505
3506 if(!pSHCreateShellItemArray) {
3507 skip("No pSHCreateShellItemArray!\n");
3508 return;
3509 }
3510
3511 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3512
3513 if(0)
3514 {
3515 /* Crashes under native */
3516 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3517 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3518 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3519 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3520 }
3521
3522 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3523 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3524
3525 SHGetDesktopFolder(&pdesktopsf);
3526 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3527 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3528
3529 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3530 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3531
3532 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3533 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3534 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3535 pILFree(pidl);
3536
3537 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3538 myPathAddBackslashW(cTestDirW);
3539 lstrcatW(cTestDirW, testdirW);
3540
3541 CreateFilesFolders();
3542
3543 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3544 ok(hr == S_OK, "got 0x%08x\n", hr);
3545 if(SUCCEEDED(hr))
3546 {
3547 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3548 (void**)&psf);
3549 ok(hr == S_OK, "Got 0x%08x\n", hr);
3550 }
3551 IShellFolder_Release(pdesktopsf);
3552
3553 if(FAILED(hr))
3554 {
3555 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3556 pILFree(pidl_testdir);
3557 Cleanup();
3558 return;
3559 }
3560
3561 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3562 ok(hr == S_OK, "Got %08x\n", hr);
3563 if(SUCCEEDED(hr))
3564 {
3565 LPITEMIDLIST apidl[5];
3566 UINT done, numitems, i;
3567
3568 for(done = 0; done < 5; done++)
3569 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3570 break;
3571 ok(done == 5, "Got %d pidls\n", done);
3572 IEnumIDList_Release(peidl);
3573
3574 /* Create a ShellItemArray */
3575 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3576 ok(hr == S_OK, "Got 0x%08x\n", hr);
3577 if(SUCCEEDED(hr))
3578 {
3579 IShellItem *psi;
3580
3581 if(0)
3582 {
3583 /* Crashes in Windows 7 */
3584 IShellItemArray_GetCount(psia, NULL);
3585 }
3586
3587 IShellItemArray_GetCount(psia, &numitems);
3588 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3589
3590 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3591 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3592
3593 /* Compare all the items */
3594 for(i = 0; i < numitems; i++)
3595 {
3596 LPITEMIDLIST pidl_abs;
3597 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3598
3599 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3600 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3601 if(SUCCEEDED(hr))
3602 {
3603 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3604 ok(hr == S_OK, "Got 0x%08x\n", hr);
3605 if(SUCCEEDED(hr))
3606 {
3607 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3608 pILFree(pidl);
3609 }
3610 IShellItem_Release(psi);
3611 }
3612 pILFree(pidl_abs);
3613 }
3614 for(i = 0; i < done; i++)
3615 pILFree(apidl[i]);
3616 IShellItemArray_Release(psia);
3617 }
3618 }
3619
3620 /* SHCreateShellItemArrayFromShellItem */
3621 if(pSHCreateShellItemArrayFromShellItem)
3622 {
3623 IShellItem *psi;
3624
3625 if(0)
3626 {
3627 /* Crashes under Windows 7 */
3628 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3629 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3630 pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3631 }
3632
3633 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3634 ok(hr == S_OK, "Got 0x%08x\n", hr);
3635 if(SUCCEEDED(hr))
3636 {
3637 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3638 ok(hr == S_OK, "Got 0x%08x\n", hr);
3639 if(SUCCEEDED(hr))
3640 {
3641 IShellItem *psi2;
3642 UINT count;
3643 hr = IShellItemArray_GetCount(psia, &count);
3644 ok(hr == S_OK, "Got 0x%08x\n", hr);
3645 ok(count == 1, "Got count %d\n", count);
3646 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3647 ok(hr == S_OK, "Got 0x%08x\n", hr);
3648 todo_wine
3649 ok(psi != psi2, "ShellItems are of the same instance.\n");
3650 if(SUCCEEDED(hr))
3651 {
3652 LPITEMIDLIST pidl1, pidl2;
3653 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3654 ok(hr == S_OK, "Got 0x%08x\n", hr);
3655 ok(pidl1 != NULL, "pidl1 was null.\n");
3656 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3657 ok(hr == S_OK, "Got 0x%08x\n", hr);
3658 ok(pidl2 != NULL, "pidl2 was null.\n");
3659 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3660 pILFree(pidl1);
3661 pILFree(pidl2);
3662 IShellItem_Release(psi2);
3663 }
3664 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3665 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3666 IShellItemArray_Release(psia);
3667 }
3668 IShellItem_Release(psi);
3669 }
3670 }
3671 else
3672 skip("No SHCreateShellItemArrayFromShellItem.\n");
3673
3674 if(pSHCreateShellItemArrayFromDataObject)
3675 {
3676 IShellView *psv;
3677
3678 if(0)
3679 {
3680 /* Crashes under Windows 7 */
3681 pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3682 }
3683 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3684 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3685
3686 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3687 ok(hr == S_OK, "got 0x%08x\n", hr);
3688 if(SUCCEEDED(hr))
3689 {
3690 IEnumIDList *peidl;
3691 IDataObject *pdo;
3692 SHCONTF enum_flags;
3693
3694 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3695 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3696 ok(hr == S_OK, "got 0x%08x\n", hr);
3697 if(SUCCEEDED(hr))
3698 {
3699 LPITEMIDLIST apidl[5];
3700 UINT count, i;
3701
3702 for(count = 0; count < 5; count++)
3703 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3704 break;
3705 ok(count == 5, "Got %d\n", count);
3706
3707 if(count)
3708 {
3709 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3710 &IID_IDataObject, NULL, (void**)&pdo);
3711 ok(hr == S_OK, "Got 0x%08x\n", hr);
3712 if(SUCCEEDED(hr))
3713 {
3714 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3715 (void**)&psia);
3716 ok(hr == S_OK, "Got 0x%08x\n", hr);
3717 if(SUCCEEDED(hr))
3718 {
3719 UINT count_sia, i;
3720 hr = IShellItemArray_GetCount(psia, &count_sia);
3721 ok(hr == S_OK, "Got 0x%08x\n", hr);
3722 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3723 for(i = 0; i < count_sia; i++)
3724 {
3725 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3726 IShellItem *psi;
3727 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3728 ok(hr == S_OK, "Got 0x%08x\n", hr);
3729 if(SUCCEEDED(hr))
3730 {
3731 LPITEMIDLIST pidl;
3732 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3733 ok(hr == S_OK, "Got 0x%08x\n", hr);
3734 ok(pidl != NULL, "pidl as NULL.\n");
3735 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3736 pILFree(pidl);
3737 IShellItem_Release(psi);
3738 }
3739 pILFree(pidl_abs);
3740 }
3741
3742 IShellItemArray_Release(psia);
3743 }
3744
3745 IDataObject_Release(pdo);
3746 }
3747 for(i = 0; i < count; i++)
3748 pILFree(apidl[i]);
3749 }
3750 else
3751 skip("No files found - skipping test.\n");
3752
3753 IEnumIDList_Release(peidl);
3754 }
3755 IShellView_Release(psv);
3756 }
3757 }
3758 else
3759 skip("No SHCreateShellItemArrayFromDataObject.\n");
3760
3761 if(pSHCreateShellItemArrayFromIDLists)
3762 {
3763 WCHAR test1W[] = {'t','e','s','t','1','.','t','x','t',0};
3764 WCHAR test1pathW[MAX_PATH];
3765 LPITEMIDLIST pidltest1;
3766 LPCITEMIDLIST pidl_array[2];
3767
3768 if(0)
3769 {
3770 /* Crashes */
3771 hr = pSHCreateShellItemArrayFromIDLists(0, NULL, NULL);
3772 }
3773
3774 psia = (void*)0xdeadbeef;
3775 hr = pSHCreateShellItemArrayFromIDLists(0, NULL, &psia);
3776 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3777 ok(psia == NULL, "Got %p\n", psia);
3778
3779 psia = (void*)0xdeadbeef;
3780 hr = pSHCreateShellItemArrayFromIDLists(0, pidl_array, &psia);
3781 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3782 ok(psia == NULL, "Got %p\n", psia);
3783
3784 psia = (void*)0xdeadbeef;
3785 pidl_array[0] = NULL;
3786 hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3787 todo_wine ok(hr == E_OUTOFMEMORY, "Got 0x%08x\n", hr);
3788 ok(psia == NULL, "Got %p\n", psia);
3789
3790 psia = (void*)0xdeadbeef;
3791 pidl_array[0] = pidl_testdir;
3792 pidl_array[1] = NULL;
3793 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3794 todo_wine ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Vista */, "Got 0x%08x\n", hr);
3795 todo_wine ok(psia != NULL || broken(psia == NULL) /* Vista */, "Got %p\n", psia);
3796 if(SUCCEEDED(hr))
3797 {
3798 IShellItem *psi;
3799 UINT count = 0;
3800
3801 hr = IShellItemArray_GetCount(psia, &count);
3802 ok(hr == S_OK, "Got 0x%08x\n", hr);
3803 ok(count == 2, "Got %d\n", count);
3804
3805 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3806 ok(hr == S_OK, "Got 0x%08x\n", hr);
3807 if(SUCCEEDED(hr))
3808 {
3809 LPWSTR path;
3810 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3811 ok(hr == S_OK, "Got 0x%08x\n", hr);
3812 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3813 if(SUCCEEDED(hr))
3814 CoTaskMemFree(path);
3815
3816 IShellItem_Release(psi);
3817 }
3818
3819 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3820 ok(hr == S_OK, "Got 0x%08x\n", hr);
3821 if(SUCCEEDED(hr))
3822 {
3823 LPWSTR path;
3824 WCHAR desktoppath[MAX_PATH];
3825 BOOL result;
3826
3827 result = pSHGetSpecialFolderPathW(NULL, desktoppath, CSIDL_DESKTOPDIRECTORY, FALSE);
3828 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
3829
3830 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3831 ok(hr == S_OK, "Got 0x%08x\n", hr);
3832 ok(!lstrcmpW(path, desktoppath), "Got %s\n", wine_dbgstr_w(path));
3833 if(SUCCEEDED(hr))
3834 CoTaskMemFree(path);
3835
3836 IShellItem_Release(psi);
3837 }
3838
3839
3840 IShellItemArray_Release(psia);
3841 }
3842
3843
3844 /* Single pidl */
3845 psia = (void*)0xdeadbeef;
3846 pidl_array[0] = pidl_testdir;
3847 hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3848 ok(hr == S_OK, "Got 0x%08x\n", hr);
3849 if(SUCCEEDED(hr))
3850 {
3851 IShellItem *psi;
3852 UINT count = 0;
3853
3854 hr = IShellItemArray_GetCount(psia, &count);
3855 ok(hr == S_OK, "Got 0x%08x\n", hr);
3856 ok(count == 1, "Got %d\n", count);
3857
3858 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3859 ok(hr == S_OK, "Got 0x%08x\n", hr);
3860 if(SUCCEEDED(hr))
3861 {
3862 LPWSTR path;
3863 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3864 ok(hr == S_OK, "Got 0x%08x\n", hr);
3865 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3866 if(SUCCEEDED(hr))
3867 CoTaskMemFree(path);
3868
3869 IShellItem_Release(psi);
3870 }
3871
3872 IShellItemArray_Release(psia);
3873 }
3874
3875
3876 lstrcpyW(test1pathW, cTestDirW);
3877 myPathAddBackslashW(test1pathW);
3878 lstrcatW(test1pathW, test1W);
3879
3880 SHGetDesktopFolder(&pdesktopsf);
3881
3882 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, test1pathW, NULL, &pidltest1, NULL);
3883 ok(hr == S_OK, "Got 0x%08x\n", hr);
3884 if(SUCCEEDED(hr))
3885 {
3886 psia = (void*)0xdeadbeef;
3887 pidl_array[0] = pidl_testdir;
3888 pidl_array[1] = pidltest1;
3889 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3890 ok(hr == S_OK, "Got 0x%08x\n", hr);
3891 if(SUCCEEDED(hr))
3892 {
3893 IShellItem *psi;
3894 UINT count = 0;
3895
3896 hr = IShellItemArray_GetCount(psia, &count);
3897 ok(hr == S_OK, "Got 0x%08x\n", hr);
3898 ok(count == 2, "Got %d\n", count);
3899
3900 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3901 ok(hr == S_OK, "Got 0x%08x\n", hr);
3902 if(SUCCEEDED(hr))
3903 {
3904 LPWSTR path;
3905 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3906 ok(hr == S_OK, "Got 0x%08x\n", hr);
3907 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3908 if(SUCCEEDED(hr))
3909 CoTaskMemFree(path);
3910
3911 IShellItem_Release(psi);
3912 }
3913
3914 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3915 ok(hr == S_OK, "Got 0x%08x\n", hr);
3916 if(SUCCEEDED(hr))
3917 {
3918 LPWSTR path;
3919 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3920 ok(hr == S_OK, "Got 0x%08x\n", hr);
3921 ok(!lstrcmpW(path, test1pathW), "Got %s\n", wine_dbgstr_w(path));
3922 if(SUCCEEDED(hr))
3923 CoTaskMemFree(path);
3924
3925 IShellItem_Release(psi);
3926 }
3927
3928
3929 IShellItemArray_Release(psia);
3930 }
3931
3932 pILFree(pidltest1);
3933 }
3934
3935 IShellFolder_Release(pdesktopsf);
3936 }
3937 else
3938 skip("No SHCreateShellItemArrayFromIDLists.\n");
3939
3940 IShellFolder_Release(psf);
3941 pILFree(pidl_testdir);
3942 Cleanup();
3943 }
3944
3945 static void test_ShellItemArrayEnumItems(void)
3946 {
3947 IShellFolder *pdesktopsf, *psf;
3948 IEnumIDList *peidl;
3949 WCHAR cTestDirW[MAX_PATH];
3950 HRESULT hr;
3951 LPITEMIDLIST pidl_testdir;
3952 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3953
3954 if(!pSHCreateShellItemArray)
3955 {
3956 win_skip("No SHCreateShellItemArray, skipping test...\n");
3957 return;
3958 }
3959
3960 CreateFilesFolders();
3961
3962 SHGetDesktopFolder(&pdesktopsf);
3963
3964 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3965 myPathAddBackslashW(cTestDirW);
3966 lstrcatW(cTestDirW, testdirW);
3967
3968 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3969 ok(hr == S_OK, "got 0x%08x\n", hr);
3970 if(SUCCEEDED(hr))
3971 {
3972 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3973 (void**)&psf);
3974 ok(hr == S_OK, "Got 0x%08x\n", hr);
3975 pILFree(pidl_testdir);
3976 }
3977 IShellFolder_Release(pdesktopsf);
3978 if (FAILED(hr)) return;
3979
3980 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3981 ok(hr == S_OK, "Got %08x\n", hr);
3982 if(SUCCEEDED(hr))
3983 {
3984 IShellItemArray *psia;
3985 LPITEMIDLIST apidl[5];
3986 UINT done, numitems, i;
3987
3988 for(done = 0; done < 5; done++)
3989 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3990 break;
3991 ok(done == 5, "Got %d pidls\n", done);
3992 IEnumIDList_Release(peidl);
3993
3994 /* Create a ShellItemArray */
3995 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3996 ok(hr == S_OK, "Got 0x%08x\n", hr);
3997 if(SUCCEEDED(hr))
3998 {
3999 IEnumShellItems *iesi;
4000 IShellItem *my_array[10];
4001 ULONG fetched;
4002
4003 IShellItemArray_GetCount(psia, &numitems);
4004 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
4005
4006 iesi = NULL;
4007 hr = IShellItemArray_EnumItems(psia, &iesi);
4008 ok(hr == S_OK, "Got 0x%08x\n", hr);
4009 ok(iesi != NULL, "Got NULL\n");
4010 if(SUCCEEDED(hr))
4011 {
4012 IEnumShellItems *iesi2;
4013
4014 /* This should fail according to the documentation and Win7+ */
4015 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
4016 hr = IEnumShellItems_Next(iesi, 2, my_array, NULL);
4017 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4018 for(i = 0; i < 2; i++)
4019 {
4020 ok(my_array[i] == (void*)0xdeadbeef ||
4021 broken(my_array[i] != (void*)0xdeadbeef && my_array[i] != NULL), /* Vista */
4022 "Got %p (%d)\n", my_array[i], i);
4023
4024 if(my_array[i] != (void*)0xdeadbeef)
4025 IShellItem_Release(my_array[i]);
4026 }
4027 ok(my_array[2] == (void*)0xdeadbeef, "Got %p\n", my_array[2]);
4028
4029 IEnumShellItems_Reset(iesi);
4030 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
4031 hr = IEnumShellItems_Next(iesi, 1, my_array, NULL);
4032 ok(hr == S_OK, "Got 0x%08x\n", hr);
4033 ok(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef, "Got %p\n", my_array[0]);
4034 if(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef)
4035 IShellItem_Release(my_array[0]);
4036 ok(my_array[1] == (void*)0xdeadbeef, "Got %p\n", my_array[1]);
4037
4038 IEnumShellItems_Reset(iesi);
4039 fetched = 0;
4040 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
4041 hr = IEnumShellItems_Next(iesi, numitems, my_array, &fetched);
4042 ok(hr == S_OK, "Got 0x%08x\n", hr);
4043 ok(fetched == numitems, "Got %d\n", fetched);
4044 for(i = 0;i < numitems; i++)
4045 {
4046 ok(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef,
4047 "Got %p at %d\n", my_array[i], i);
4048
4049 if(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef)
4050 IShellItem_Release(my_array[i]);
4051 }
4052 ok(my_array[i] == (void*)0xdeadbeef, "Got %p\n", my_array[i]);
4053
4054 /* Compare all the items */
4055 IEnumShellItems_Reset(iesi);
4056 for(i = 0; i < numitems; i++)
4057 {
4058 IShellItem *psi;
4059 int order;
4060
4061 hr = IShellItemArray_GetItemAt(psia, i, &psi);
4062 ok(hr == S_OK, "Got 0x%08x\n", hr);
4063 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
4064 ok(hr == S_OK, "Got 0x%08x\n", hr);
4065 ok(fetched == 1, "Got %d\n", fetched);
4066
4067 hr = IShellItem_Compare(psi, my_array[0], 0, &order);
4068 ok(hr == S_OK, "Got 0x%08x\n", hr);
4069 ok(order == 0, "Got %d\n", order);
4070
4071 IShellItem_Release(psi);
4072 IShellItem_Release(my_array[0]);
4073 }
4074
4075 my_array[0] = (void*)0xdeadbeef;
4076 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
4077 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
4078 ok(fetched == 0, "Got %d\n", fetched);
4079 ok(my_array[0] == (void*)0xdeadbeef, "Got %p\n", my_array[0]);
4080
4081 /* Cloning not implemented anywhere */
4082 iesi2 = (void*)0xdeadbeef;
4083 hr = IEnumShellItems_Clone(iesi, &iesi2);
4084 ok(hr == E_NOTIMPL, "Got 0x%08x\n", hr);
4085 ok(iesi2 == NULL || broken(iesi2 == (void*)0xdeadbeef) /* Vista */, "Got %p\n", iesi2);
4086
4087 IEnumShellItems_Release(iesi);
4088 }
4089
4090 IShellItemArray_Release(psia);
4091 }
4092
4093 for(i = 0; i < done; i++)
4094 pILFree(apidl[i]);
4095 }
4096 }
4097
4098
4099 static void test_ShellItemBindToHandler(void)
4100 {
4101 IShellItem *psi;
4102 LPITEMIDLIST pidl_desktop;
4103 HRESULT hr;
4104
4105 if(!pSHCreateShellItem)
4106 {
4107 skip("SHCreateShellItem missing.\n");
4108 return;
4109 }
4110
4111 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
4112 ok(hr == S_OK, "Got 0x%08x\n", hr);
4113 if(SUCCEEDED(hr))
4114 {
4115 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
4116 ok(hr == S_OK, "Got 0x%08x\n", hr);
4117 }
4118 if(SUCCEEDED(hr))
4119 {
4120 IPersistFolder2 *ppf2;
4121 IUnknown *punk;
4122
4123 if(0)
4124 {
4125 /* Crashes under Windows 7 */
4126 IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
4127 IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
4128 }
4129 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
4130 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
4131
4132 /* BHID_SFObject */
4133 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
4134 ok(hr == S_OK, "Got 0x%08x\n", hr);
4135 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4136 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
4137 ok(hr == S_OK, "Got 0x%08x\n", hr);
4138 if(SUCCEEDED(hr))
4139 {
4140 LPITEMIDLIST pidl_tmp;
4141 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
4142 ok(hr == S_OK, "Got 0x%08x\n", hr);
4143 if(SUCCEEDED(hr))
4144 {
4145 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
4146 pILFree(pidl_tmp);
4147 }
4148 IPersistFolder2_Release(ppf2);
4149 }
4150
4151 /* BHID_SFUIObject */
4152 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
4153 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
4154 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4155 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
4156 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
4157 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4158
4159 /* BHID_DataObject */
4160 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
4161 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4162 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4163
4164 todo_wine
4165 {
4166 /* BHID_SFViewObject */
4167 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
4168 ok(hr == S_OK, "Got 0x%08x\n", hr);
4169 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4170 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
4171 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
4172 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4173
4174 /* BHID_Storage */
4175 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
4176 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
4177 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4178 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
4179 ok(hr == S_OK, "Got 0x%08x\n", hr);
4180 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4181
4182 /* BHID_Stream */
4183 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
4184 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
4185 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4186 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
4187 ok(hr == S_OK, "Got 0x%08x\n", hr);
4188 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4189
4190 /* BHID_StorageEnum */
4191 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
4192 ok(hr == S_OK, "Got 0x%08x\n", hr);
4193 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4194
4195 /* BHID_Transfer
4196 ITransferSource and ITransferDestination are accessible starting from Vista, IUnknown is
4197 supported starting from Win8. */
4198 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferSource, (void**)&punk);
4199 ok(hr == S_OK || broken(FAILED(hr)) /* pre-Vista */, "Got 0x%08x\n", hr);
4200 if(SUCCEEDED(hr))
4201 {
4202 IUnknown_Release(punk);
4203
4204 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferDestination, (void**)&punk);
4205 ok(hr == S_OK, "Got 0x%08x\n", hr);
4206 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4207
4208 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
4209 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Win8 */, "Got 0x%08x\n", hr);
4210 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4211 }
4212
4213 /* BHID_EnumItems */
4214 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
4215 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4216 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4217
4218 /* BHID_Filter */
4219 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
4220 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4221 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4222
4223 /* BHID_LinkTargetItem */
4224 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
4225 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
4226 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4227 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
4228 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
4229 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4230
4231 /* BHID_PropertyStore */
4232 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
4233 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4234 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4235 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
4236 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4237 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4238
4239 /* BHID_ThumbnailHandler */
4240 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
4241 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4242 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4243
4244 /* BHID_AssociationArray */
4245 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
4246 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4247 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4248
4249 /* BHID_EnumAssocHandlers */
4250 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
4251 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4252 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4253 }
4254
4255 IShellItem_Release(psi);
4256 }
4257 else
4258 skip("Failed to create ShellItem.\n");
4259
4260 pILFree(pidl_desktop);
4261 }
4262
4263 static void test_ShellItemGetAttributes(void)
4264 {
4265 IShellItem *psi, *psi_folder1, *psi_file1;
4266 IShellFolder *pdesktopsf;
4267 LPITEMIDLIST pidl_desktop, pidl;
4268 SFGAOF sfgao;
4269 HRESULT hr;
4270 WCHAR curdirW[MAX_PATH];
4271 WCHAR buf[MAX_PATH];
4272 static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4273 static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4274
4275 if(!pSHCreateShellItem)
4276 {
4277 skip("SHCreateShellItem missing.\n");
4278 return;
4279 }
4280
4281 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
4282 ok(hr == S_OK, "Got 0x%08x\n", hr);
4283 if(SUCCEEDED(hr))
4284 {
4285 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
4286 ok(hr == S_OK, "Got 0x%08x\n", hr);
4287 pILFree(pidl_desktop);
4288 }
4289 if(FAILED(hr))
4290 {
4291 skip("Skipping tests.\n");
4292 return;
4293 }
4294
4295 if(0)
4296 {
4297 /* Crashes on native (Win 7) */
4298 IShellItem_GetAttributes(psi, 0, NULL);
4299 }
4300
4301 /* Test GetAttributes on the desktop folder. */
4302 sfgao = 0xdeadbeef;
4303 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
4304 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
4305 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
4306
4307 IShellItem_Release(psi);
4308
4309 CreateFilesFolders();
4310
4311 SHGetDesktopFolder(&pdesktopsf);
4312
4313 GetCurrentDirectoryW(MAX_PATH, curdirW);
4314 myPathAddBackslashW(curdirW);
4315
4316 lstrcpyW(buf, curdirW);
4317 lstrcatW(buf, testdir1W);
4318 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4319 ok(hr == S_OK, "got 0x%08x\n", hr);
4320 hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_folder1);
4321 ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4322 pILFree(pidl);
4323
4324 lstrcpyW(buf, curdirW);
4325 lstrcatW(buf, testfile1W);
4326 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4327 ok(hr == S_OK, "got 0x%08x\n", hr);
4328 hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_file1);
4329 ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4330 pILFree(pidl);
4331
4332 IShellFolder_Release(pdesktopsf);
4333
4334 sfgao = 0xdeadbeef;
4335 hr = IShellItem_GetAttributes(psi_folder1, 0, &sfgao);
4336 ok(hr == S_OK, "Got 0x%08x\n", hr);
4337 ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4338
4339 sfgao = 0xdeadbeef;
4340 hr = IShellItem_GetAttributes(psi_folder1, SFGAO_FOLDER, &sfgao);
4341 ok(hr == S_OK, "Got 0x%08x\n", hr);
4342 ok(sfgao == SFGAO_FOLDER, "Got 0x%08x\n", sfgao);
4343
4344 sfgao = 0xdeadbeef;
4345 hr = IShellItem_GetAttributes(psi_file1, SFGAO_FOLDER, &sfgao);
4346 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
4347 ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4348
4349 IShellItem_Release(psi_folder1);
4350 IShellItem_Release(psi_file1);
4351
4352 Cleanup();
4353 }
4354
4355 static void test_ShellItemArrayGetAttributes(void)
4356 {
4357 IShellItemArray *psia_files, *psia_folders1, *psia_folders2, *psia_all;
4358 IShellFolder *pdesktopsf;
4359 LPCITEMIDLIST pidl_array[5];
4360 SFGAOF attr;
4361 HRESULT hr;
4362 WCHAR curdirW[MAX_PATH];
4363 WCHAR buf[MAX_PATH];
4364 UINT i;
4365 static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4366 static const WCHAR testdir2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','2',0};
4367 static const WCHAR testdir3W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','3',0};
4368 static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4369 static const WCHAR testfile2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','2','.','t','x','t',0};
4370 static const WCHAR *testfilesW[5] = { testdir1W, testdir2W, testdir3W, testfile1W, testfile2W };
4371
4372 if(!pSHCreateShellItemArrayFromShellItem)
4373 {
4374 win_skip("No SHCreateShellItemArrayFromShellItem, skipping test...\n");
4375 return;
4376 }
4377
4378 CreateFilesFolders();
4379 CreateDirectoryA(".\\testdir\\testdir3", NULL);
4380
4381 SHGetDesktopFolder(&pdesktopsf);
4382
4383 GetCurrentDirectoryW(MAX_PATH, curdirW);
4384 myPathAddBackslashW(curdirW);
4385
4386 for(i = 0; i < 5; i++)
4387 {
4388 lstrcpyW(buf, curdirW);
4389 lstrcatW(buf, testfilesW[i]);
4390 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, (LPITEMIDLIST*)&pidl_array[i], NULL);
4391 ok(hr == S_OK, "got 0x%08x\n", hr);
4392 }
4393 IShellFolder_Release(pdesktopsf);
4394
4395 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia_folders1);
4396 ok(hr == S_OK, "got 0x%08x\n", hr);
4397 hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[1], &psia_folders2);
4398 ok(hr == S_OK, "got 0x%08x\n", hr);
4399 hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[3], &psia_files);
4400 ok(hr == S_OK, "got 0x%08x\n", hr);
4401 hr = pSHCreateShellItemArrayFromIDLists(4, &pidl_array[1], &psia_all); /* All except the first */
4402 ok(hr == S_OK, "got 0x%08x\n", hr);
4403
4404 for(i = 0; i < 5; i++)
4405 pILFree((LPITEMIDLIST)pidl_array[i]);
4406
4407 /* [testfolder/, testfolder/testfolder2] seems to break in Vista */
4408 attr = 0xdeadbeef;
4409 hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4410 ok(hr == S_OK || broken(hr == E_UNEXPECTED) /* Vista */, "Got 0x%08x\n", hr);
4411 ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4412 attr = 0xdeadbeef;
4413 hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4414 ok(hr == S_OK || broken(hr == E_UNEXPECTED) /* Vista */, "Got 0x%08x\n", hr);
4415 ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4416
4417 /* [testfolder/testfolder2, testfolder/testfolder3] works */
4418 attr = 0xdeadbeef;
4419 hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4420 ok(hr == S_OK, "Got 0x%08x\n", hr);
4421 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4422 attr = 0xdeadbeef;
4423 hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4424 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4425 ok(attr == 0, "Got 0x%08x\n", attr);
4426 attr = 0xdeadbeef;
4427 hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4428 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4429 ok(attr == 0, "Got 0x%08x\n", attr);
4430 attr = 0xdeadbeef;
4431 hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4432 ok(hr == S_OK, "Got 0x%08x\n", hr);
4433 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4434 attr = 0xdeadbeef;
4435 hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4436 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4437 ok(attr == 0, "Got 0x%08x\n", attr);
4438 attr = 0xdeadbeef;
4439 hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4440 ok(hr == S_OK, "Got 0x%08x\n", hr);
4441 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4442
4443 IShellItemArray_Release(psia_folders1);
4444 IShellItemArray_Release(psia_folders2);
4445 IShellItemArray_Release(psia_files);
4446 IShellItemArray_Release(psia_all);
4447
4448 RemoveDirectoryA(".\\testdir\\testdir3");
4449 Cleanup();
4450 }
4451
4452 static WCHAR *get_empty_cddrive(void)
4453 {
4454 static WCHAR cdrom_drive[] = {'A',':','\\',0};
4455 DWORD drives = GetLogicalDrives();
4456
4457 cdrom_drive[0] = 'A';
4458 while (drives)
4459 {
4460 if ((drives & 1) &&
4461 GetDriveTypeW(cdrom_drive) == DRIVE_CDROM &&
4462 GetFileAttributesW(cdrom_drive) == INVALID_FILE_ATTRIBUTES)
4463 {
4464 return cdrom_drive;
4465 }
4466
4467 drives = drives >> 1;
4468 cdrom_drive[0]++;
4469 }
4470 return NULL;
4471 }
4472
4473 static void test_SHParseDisplayName(void)
4474 {
4475 LPITEMIDLIST pidl1, pidl2;
4476 IShellFolder *desktop;
4477 WCHAR dirW[MAX_PATH];
4478 WCHAR nameW[10];
4479 WCHAR *cdrom;
4480 HRESULT hr;
4481 BOOL ret, is_wow64;
4482
4483 if (!pSHParseDisplayName)
4484 {
4485 win_skip("SHParseDisplayName isn't available\n");
4486 return;
4487 }
4488
4489 if (0)
4490 {
4491 /* crashes on native */
4492 pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
4493 nameW[0] = 0;
4494 pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
4495 }
4496
4497 pidl1 = (LPITEMIDLIST)0xdeadbeef;
4498 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
4499 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
4500 hr == E_INVALIDARG, "failed %08x\n", hr);
4501 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
4502
4503 /* dummy name */
4504 nameW[0] = 0;
4505 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
4506 ok(hr == S_OK, "failed %08x\n", hr);
4507 hr = SHGetDesktopFolder(&desktop);
4508 ok(hr == S_OK, "failed %08x\n", hr);
4509 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
4510 ok(hr == S_OK, "failed %08x\n", hr);
4511 ret = pILIsEqual(pidl1, pidl2);
4512 ok(ret == TRUE, "expected equal idls\n");
4513 pILFree(pidl1);
4514 pILFree(pidl2);
4515
4516 /* with path */
4517 GetWindowsDirectoryW( dirW, MAX_PATH );
4518
4519 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4520 ok(hr == S_OK, "failed %08x\n", hr);
4521 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
4522 ok(hr == S_OK, "failed %08x\n", hr);
4523
4524 ret = pILIsEqual(pidl1, pidl2);
4525 ok(ret == TRUE, "expected equal idls\n");
4526 pILFree(pidl1);
4527 pILFree(pidl2);
4528
4529 /* system32 is not redirected to syswow64 on WOW64 */
4530 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
4531 if (is_wow64 && pGetSystemWow64DirectoryW)
4532 {
4533 UINT len;
4534 *dirW = 0;
4535 len = GetSystemDirectoryW(dirW, MAX_PATH);
4536 ok(len > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
4537 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4538 ok(hr == S_OK, "failed %08x\n", hr);
4539 *dirW = 0;
4540 len = pGetSystemWow64DirectoryW(dirW, MAX_PATH);
4541 ok(len > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
4542 hr = pSHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
4543 ok(hr == S_OK, "failed %08x\n", hr);
4544 ret = pILIsEqual(pidl1, pidl2);
4545 ok(ret == FALSE, "expected different idls\n");
4546 pILFree(pidl1);
4547 pILFree(pidl2);
4548 }
4549
4550 IShellFolder_Release(desktop);
4551
4552 cdrom = get_empty_cddrive();
4553 if (!cdrom)
4554 skip("No empty cdrom drive found, skipping test\n");
4555 else
4556 {
4557 hr = pSHParseDisplayName(cdrom, NULL, &pidl1, 0, NULL);
4558 ok(hr == S_OK, "failed %08x\n", hr);
4559 if (SUCCEEDED(hr)) pILFree(pidl1);
4560 }
4561 }
4562
4563 static void test_desktop_IPersist(void)
4564 {
4565 IShellFolder *desktop;
4566 IPersist *persist;
4567 IPersistFolder2 *ppf2;
4568 CLSID clsid;
4569 HRESULT hr;
4570
4571 hr = SHGetDesktopFolder(&desktop);
4572 ok(hr == S_OK, "failed %08x\n", hr);
4573
4574 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
4575 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
4576
4577 if (hr == S_OK)
4578 {
4579 if (0)
4580 {
4581 /* crashes on native */
4582 IPersist_GetClassID(persist, NULL);
4583 }
4584 memset(&clsid, 0, sizeof(clsid));
4585 hr = IPersist_GetClassID(persist, &clsid);
4586 ok(hr == S_OK, "failed %08x\n", hr);
4587 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
4588 IPersist_Release(persist);
4589 }
4590
4591 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
4592 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
4593 if(SUCCEEDED(hr))
4594 {
4595 IPersistFolder *ppf;
4596 LPITEMIDLIST pidl;
4597 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
4598 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
4599 if(SUCCEEDED(hr))
4600 IPersistFolder_Release(ppf);
4601
4602 todo_wine {
4603 hr = IPersistFolder2_Initialize(ppf2, NULL);
4604 ok(hr == S_OK, "got %08x\n", hr);
4605 }
4606
4607 pidl = NULL;
4608 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
4609 ok(hr == S_OK, "got %08x\n", hr);
4610 ok(pidl != NULL, "pidl was NULL.\n");
4611 if(SUCCEEDED(hr)) pILFree(pidl);
4612
4613 IPersistFolder2_Release(ppf2);
4614 }
4615
4616 IShellFolder_Release(desktop);
4617 }
4618
4619 static void test_GetUIObject(void)
4620 {
4621 IShellFolder *psf_desktop;
4622 IContextMenu *pcm;
4623 LPITEMIDLIST pidl;
4624 HRESULT hr;
4625 WCHAR path[MAX_PATH];
4626 const WCHAR filename[] =
4627 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4628
4629 if(!pSHBindToParent)
4630 {
4631 win_skip("SHBindToParent missing.\n");
4632 return;
4633 }
4634
4635 GetCurrentDirectoryW(MAX_PATH, path);
4636 if (!path[0])
4637 {
4638 skip("GetCurrentDirectoryW returned an empty string.\n");
4639 return;
4640 }
4641 lstrcatW(path, filename);
4642 SHGetDesktopFolder(&psf_desktop);
4643
4644 CreateFilesFolders();
4645
4646 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
4647 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
4648 if(SUCCEEDED(hr))
4649 {
4650 IShellFolder *psf;
4651 LPCITEMIDLIST pidl_child;
4652 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
4653 ok(hr == S_OK, "Got 0x%08x\n", hr);
4654 if(SUCCEEDED(hr))
4655 {
4656 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, &pidl_child, &IID_IContextMenu, NULL,
4657 (void**)&pcm);
4658 ok(hr == S_OK, "Got 0x%08x\n", hr);
4659 if(SUCCEEDED(hr))
4660 {
4661 const int baseItem = 0x40;
4662 HMENU hmenu = CreatePopupMenu();
4663 INT max_id, max_id_check;
4664 UINT count, i;
4665 const int id_upper_limit = 32767;
4666 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, baseItem, id_upper_limit, CMF_NORMAL);
4667 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
4668 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
4669 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
4670 count = GetMenuItemCount(hmenu);
4671 ok(count, "Got %d\n", count);
4672
4673 max_id_check = 0;
4674 for(i = 0; i < count; i++)
4675 {
4676 MENUITEMINFOA mii;
4677 INT res;
4678 char buf[255], buf2[255];
4679 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
4680 mii.cbSize = sizeof(MENUITEMINFOA);
4681 mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
4682 mii.dwTypeData = buf2;
4683 mii.cch = sizeof(buf2);
4684
4685 SetLastError(0);
4686 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
4687 ok(res, "Failed (last error: %d).\n", GetLastError());
4688
4689 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
4690 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
4691 if(!(mii.fType & MFT_SEPARATOR))
4692 {
4693 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
4694 hr = IContextMenu_GetCommandString(pcm, mii.wID - baseItem, GCS_VERBA, 0, buf, sizeof(buf));
4695 ok(SUCCEEDED(hr) || hr == E_NOTIMPL, "for id 0x%x got 0x%08x (menustr: %s)\n", mii.wID - baseItem, hr, mii.dwTypeData);
4696 if (SUCCEEDED(hr))
4697 trace("for id 0x%x got string %s (menu string: %s)\n", mii.wID - baseItem, buf, mii.dwTypeData);
4698 else if (hr == E_NOTIMPL)
4699 trace("for id 0x%x got E_NOTIMPL (menu string: %s)\n", mii.wID - baseItem, mii.dwTypeData);
4700 }
4701 }
4702 max_id_check -= baseItem;
4703 ok((max_id_check == max_id) ||
4704 (max_id_check == max_id-1) || /* Win 7 */
4705 (max_id_check == max_id-2), /* Win 8 */
4706 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
4707
4708 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
4709
4710 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
4711 {
4712 CMINVOKECOMMANDINFO cmi;
4713 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
4714 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
4715
4716 /* Attempt to execute a nonexistent command */
4717 cmi.lpVerb = MAKEINTRESOURCEA(9999);
4718 hr = IContextMenu_InvokeCommand(pcm, &cmi);
4719 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
4720
4721 cmi.lpVerb = "foobar_wine_test";
4722 hr = IContextMenu_InvokeCommand(pcm, &cmi);
4723 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
4724 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
4725 "Got 0x%08x\n", hr);
4726 }
4727 #undef is_win2k
4728
4729 DestroyMenu(hmenu);
4730 IContextMenu_Release(pcm);
4731 }
4732 IShellFolder_Release(psf);
4733 }
4734 if(pILFree) pILFree(pidl);
4735 }
4736
4737 IShellFolder_Release(psf_desktop);
4738 Cleanup();
4739 }
4740
4741 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
4742 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
4743 {
4744 LPCITEMIDLIST child;
4745 IShellFolder *parent;
4746 STRRET filename;
4747 HRESULT hr;
4748
4749 if(!pSHBindToParent){
4750 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
4751 if(path)
4752 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
4753 else
4754 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4755 return;
4756 }
4757
4758 if(path){
4759 if(!pidl){
4760 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
4761 return;
4762 }
4763
4764 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
4765 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
4766 if(FAILED(hr))
4767 return;
4768
4769 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
4770 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
4771 if(FAILED(hr)){
4772 IShellFolder_Release(parent);
4773 return;
4774 }
4775
4776 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
4777 "Got unexpected string type: %d\n", filename.uType);
4778 if(filename.uType == STRRET_WSTR){
4779 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
4780 "didn't get expected path (%s), instead: %s\n",
4781 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
4782 SHFree(U(filename).pOleStr);
4783 }else if(filename.uType == STRRET_CSTR){
4784 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
4785 "didn't get expected path (%s), instead: %s\n",
4786 wine_dbgstr_w(path), U(filename).cStr);
4787 }
4788
4789 IShellFolder_Release(parent);
4790 }else
4791 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4792 }
4793
4794 static void test_SHSimpleIDListFromPath(void)
4795 {
4796 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4797 const CHAR adirA[] = "C:\\sidlfpdir";
4798 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4799
4800 LPITEMIDLIST pidl = NULL;
4801
4802 if(!pSHSimpleIDListFromPathAW){
4803 win_skip("SHSimpleIDListFromPathAW not available\n");
4804 return;
4805 }
4806
4807 br = CreateDirectoryA(adirA, NULL);
4808 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4809
4810 if(is_unicode)
4811 pidl = pSHSimpleIDListFromPathAW(adirW);
4812 else
4813 pidl = pSHSimpleIDListFromPathAW(adirA);
4814 verify_pidl(pidl, adirW);
4815 pILFree(pidl);
4816
4817 br = RemoveDirectoryA(adirA);
4818 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4819
4820 if(is_unicode)
4821 pidl = pSHSimpleIDListFromPathAW(adirW);
4822 else
4823 pidl = pSHSimpleIDListFromPathAW(adirA);
4824 verify_pidl(pidl, adirW);
4825 pILFree(pidl);
4826 }
4827
4828 /* IFileSystemBindData impl */
4829 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4830 REFIID riid, void **ppv)
4831 {
4832 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4833 IsEqualIID(riid, &IID_IUnknown)){
4834 *ppv = fsbd;
4835 return S_OK;
4836 }
4837 return E_NOINTERFACE;
4838 }
4839
4840 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4841 {
4842 return 2;
4843 }
4844
4845 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4846 {
4847 return 1;
4848 }
4849
4850 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4851 const WIN32_FIND_DATAW *pfd)
4852 {
4853 ok(0, "SetFindData called\n");
4854 return E_NOTIMPL;
4855 }
4856
4857 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4858 WIN32_FIND_DATAW *pfd)
4859 {
4860 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4861 return S_OK;
4862 }
4863
4864 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4865 WIN32_FIND_DATAW *pfd)
4866 {
4867 memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4868 return S_OK;
4869 }
4870
4871 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4872 WIN32_FIND_DATAW *pfd)
4873 {
4874 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4875 *pfd->cFileName = 'a';
4876 *pfd->cAlternateFileName = 'a';
4877 return S_OK;
4878 }
4879
4880 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4881 WIN32_FIND_DATAW *pfd)
4882 {
4883 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4884 HANDLE handle = FindFirstFileW(adirW, pfd);
4885 FindClose(handle);
4886 return S_OK;
4887 }
4888
4889 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4890 WIN32_FIND_DATAW *pfd)
4891 {
4892 return E_FAIL;
4893 }
4894
4895 static IFileSystemBindDataVtbl fsbdVtbl = {
4896 fsbd_QueryInterface,
4897 fsbd_AddRef,
4898 fsbd_Release,
4899 fsbd_SetFindData,
4900 NULL
4901 };
4902
4903 static IFileSystemBindData fsbd = { &fsbdVtbl };
4904
4905 static void test_ParseDisplayNamePBC(void)
4906 {
4907 WCHAR wFileSystemBindData[] =
4908 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4909 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4910 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4911 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4912 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4913
4914 IShellFolder *psf;
4915 IBindCtx *pbc;
4916 HRESULT hres;
4917 ITEMIDLIST *pidl;
4918
4919 /* Check if we support WCHAR functions */
4920 SetLastError(0xdeadbeef);
4921 lstrcmpiW(adirW, adirW);
4922 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4923 win_skip("Most W-calls are not implemented\n");
4924 return;
4925 }
4926
4927 hres = SHGetDesktopFolder(&psf);
4928 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4929 if(FAILED(hres)){
4930 win_skip("Failed to get IShellFolder, can't run tests\n");
4931 return;
4932 }
4933
4934 /* fails on unknown dir with no IBindCtx */
4935 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4936 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4937 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4938 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4939 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4940 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4941 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4942 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4943 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4944
4945 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4946 hres = CreateBindCtx(0, &pbc);
4947 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4948
4949 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4950 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4951 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4952 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4953 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4954 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4955 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4956 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4957 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4958
4959 /* unknown dir with IBindCtx with IFileSystemBindData */
4960 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4961 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4962
4963 /* return E_FAIL from GetFindData */
4964 pidl = (ITEMIDLIST*)0xdeadbeef;
4965 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4966 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4967 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4968 "ParseDisplayName failed: 0x%08x\n", hres);
4969 if(SUCCEEDED(hres)){
4970 verify_pidl(pidl, adirW);
4971 ILFree(pidl);
4972 }
4973
4974 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4975 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4976 "ParseDisplayName failed: 0x%08x\n", hres);
4977 if(SUCCEEDED(hres)){
4978 verify_pidl(pidl, afileW);
4979 ILFree(pidl);
4980 }
4981
4982 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4983 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4984 "ParseDisplayName failed: 0x%08x\n", hres);
4985 if(SUCCEEDED(hres)){
4986 verify_pidl(pidl, afile2W);
4987 ILFree(pidl);
4988 }
4989
4990 /* set FIND_DATA struct to NULLs */
4991 pidl = (ITEMIDLIST*)0xdeadbeef;
4992 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4993 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4994 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4995 "ParseDisplayName failed: 0x%08x\n", hres);
4996 if(SUCCEEDED(hres)){
4997 verify_pidl(pidl, adirW);
4998 ILFree(pidl);
4999 }
5000
5001 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
5002 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5003 "ParseDisplayName failed: 0x%08x\n", hres);
5004 if(SUCCEEDED(hres)){
5005 verify_pidl(pidl, afileW);
5006 ILFree(pidl);
5007 }
5008
5009 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
5010 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5011 "ParseDisplayName failed: 0x%08x\n", hres);
5012 if(SUCCEEDED(hres)){
5013 verify_pidl(pidl, afile2W);
5014 ILFree(pidl);
5015 }
5016
5017 /* set FIND_DATA struct to junk */
5018 pidl = (ITEMIDLIST*)0xdeadbeef;
5019 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
5020 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
5021 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5022 "ParseDisplayName failed: 0x%08x\n", hres);
5023 if(SUCCEEDED(hres)){
5024 verify_pidl(pidl, adirW);
5025 ILFree(pidl);
5026 }
5027
5028 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
5029 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5030 "ParseDisplayName failed: 0x%08x\n", hres);
5031 if(SUCCEEDED(hres)){
5032 verify_pidl(pidl, afileW);
5033 ILFree(pidl);
5034 }
5035
5036 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
5037 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5038 "ParseDisplayName failed: 0x%08x\n", hres);
5039 if(SUCCEEDED(hres)){
5040 verify_pidl(pidl, afile2W);
5041 ILFree(pidl);
5042 }
5043
5044 /* set FIND_DATA struct to invalid data */
5045 pidl = (ITEMIDLIST*)0xdeadbeef;
5046 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
5047 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
5048 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5049 "ParseDisplayName failed: 0x%08x\n", hres);
5050 if(SUCCEEDED(hres)){
5051 verify_pidl(pidl, adirW);
5052 ILFree(pidl);
5053 }
5054
5055 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
5056 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5057 "ParseDisplayName failed: 0x%08x\n", hres);
5058 if(SUCCEEDED(hres)){
5059 verify_pidl(pidl, afileW);
5060 ILFree(pidl);
5061 }
5062
5063 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
5064 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5065 "ParseDisplayName failed: 0x%08x\n", hres);
5066 if(SUCCEEDED(hres)){
5067 verify_pidl(pidl, afile2W);
5068 ILFree(pidl);
5069 }
5070
5071 /* set FIND_DATA struct to valid data */
5072 pidl = (ITEMIDLIST*)0xdeadbeef;
5073 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
5074 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
5075 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5076 "ParseDisplayName failed: 0x%08x\n", hres);
5077 if(SUCCEEDED(hres)){
5078 verify_pidl(pidl, adirW);
5079 ILFree(pidl);
5080 }
5081
5082 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
5083 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5084 "ParseDisplayName failed: 0x%08x\n", hres);
5085 if(SUCCEEDED(hres)){
5086 verify_pidl(pidl, afileW);
5087 ILFree(pidl);
5088 }
5089
5090 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
5091 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5092 "ParseDisplayName failed: 0x%08x\n", hres);
5093 if(SUCCEEDED(hres)){
5094 verify_pidl(pidl, afile2W);
5095 ILFree(pidl);
5096 }
5097
5098 IBindCtx_Release(pbc);
5099 IShellFolder_Release(psf);
5100 }
5101
5102 static const CHAR testwindow_class[] = "testwindow";
5103 #define WM_USER_NOTIFY (WM_APP+1)
5104
5105 struct ChNotifyTest {
5106 const char id[256];
5107 const UINT notify_count;
5108 UINT missing_events;
5109 UINT signal;
5110 const char path_1[256];
5111 const char path_2[256];
5112 } chnotify_tests[] = {
5113 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
5114 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
5115 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
5116 };
5117
5118 struct ChNotifyTest *exp_data;
5119 BOOL test_new_delivery_flag;
5120
5121 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5122 {
5123 LONG signal = (LONG)lparam;
5124
5125 switch(msg){
5126 case WM_USER_NOTIFY:
5127 if(exp_data->missing_events > 0) {
5128 WCHAR *path1, *path2;
5129 LPITEMIDLIST *pidls = (LPITEMIDLIST*)wparam;
5130 HANDLE hLock = NULL;
5131
5132 if(test_new_delivery_flag) {
5133 hLock = SHChangeNotification_Lock((HANDLE)wparam, lparam, &pidls, &signal);
5134 ok(hLock != NULL, "SHChangeNotification_Lock returned NULL\n");
5135 }
5136
5137 ok(exp_data->signal == signal,
5138 "%s: expected notification type %x, got: %x\n",
5139 exp_data->id, exp_data->signal, signal);
5140
5141 trace("verifying pidls for: %s\n", exp_data->id);
5142 path1 = make_wstr(exp_data->path_1);
5143 path2 = make_wstr(exp_data->path_2);
5144 verify_pidl(pidls[0], path1);
5145 verify_pidl(pidls[1], path2);
5146 HeapFree(GetProcessHeap(), 0, path1);
5147 HeapFree(GetProcessHeap(), 0, path2);
5148
5149 exp_data->missing_events--;
5150
5151 if(test_new_delivery_flag)
5152 SHChangeNotification_Unlock(hLock);
5153 }else
5154 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
5155 return 0;
5156 }
5157 return DefWindowProcA(hwnd, msg, wparam, lparam);
5158 }
5159
5160 static void register_testwindow_class(void)
5161 {
5162 WNDCLASSEXA cls;
5163 ATOM ret;
5164
5165 ZeroMemory(&cls, sizeof(cls));
5166 cls.cbSize = sizeof(cls);
5167 cls.style = 0;
5168 cls.lpfnWndProc = testwindow_wndproc;
5169 cls.hInstance = GetModuleHandleA(NULL);
5170 cls.lpszClassName = testwindow_class;
5171
5172 SetLastError(0);
5173 ret = RegisterClassExA(&cls);
5174 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
5175 }
5176
5177 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
5178 * have to poll repeatedly for the message to appear */
5179 static void do_events(void)
5180 {
5181 int c = 0;
5182 while (exp_data->missing_events && (c++ < 10)){
5183 MSG msg;
5184 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
5185 TranslateMessage(&msg);
5186 DispatchMessageA(&msg);
5187 }
5188 if(exp_data->missing_events)
5189 Sleep(500);
5190 }
5191 trace("%s: took %d tries\n", exp_data->id, c);
5192 }
5193
5194 static void test_SHChangeNotify(BOOL test_new_delivery)
5195 {
5196 HWND wnd;
5197 ULONG notifyID, i;
5198 HRESULT hr;
5199 BOOL br, has_unicode;
5200 SHChangeNotifyEntry entries[1];
5201 const CHAR root_dirA[] = "C:\\shell32_cn_test";
5202 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
5203
5204 trace("SHChangeNotify tests (%x)\n", test_new_delivery);
5205
5206 CreateDirectoryW(NULL, NULL);
5207 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
5208
5209 test_new_delivery_flag = test_new_delivery;
5210 if(!test_new_delivery)
5211 register_testwindow_class();
5212
5213 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
5214 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
5215 NULL, NULL, GetModuleHandleA(NULL), 0);
5216 ok(wnd != NULL, "Failed to make a window\n");
5217
5218 br = CreateDirectoryA(root_dirA, NULL);
5219 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
5220
5221 entries[0].pidl = NULL;
5222 if(has_unicode)
5223 hr = pSHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
5224 else
5225 hr = pSHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
5226 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
5227 entries[0].fRecursive = TRUE;
5228
5229 notifyID = SHChangeNotifyRegister(wnd, !test_new_delivery ? SHCNRF_ShellLevel : SHCNRF_ShellLevel|SHCNRF_NewDelivery,
5230 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
5231 ok(notifyID != 0, "Failed to register a window for change notifications\n");
5232
5233 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
5234 exp_data = chnotify_tests + i;
5235
5236 exp_data->missing_events = exp_data->notify_count;
5237 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
5238 exp_data->path_1[0] ? exp_data->path_1 : NULL,
5239 exp_data->path_2[0] ? exp_data->path_2 : NULL);
5240 do_events();
5241 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
5242
5243 if(has_unicode){
5244 WCHAR *path1, *path2;
5245
5246 path1 = make_wstr(exp_data->path_1);
5247 path2 = make_wstr(exp_data->path_2);
5248
5249 exp_data->missing_events = exp_data->notify_count;
5250 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
5251 do_events();
5252 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
5253
5254 HeapFree(GetProcessHeap(), 0, path1);
5255 HeapFree(GetProcessHeap(), 0, path2);
5256 }
5257 }
5258
5259 SHChangeNotifyDeregister(notifyID);
5260 DestroyWindow(wnd);
5261
5262 ILFree((LPITEMIDLIST)entries[0].pidl);
5263 br = RemoveDirectoryA(root_dirA);
5264 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
5265 }
5266
5267 static void test_SHCreateDefaultContextMenu(void)
5268 {
5269 HKEY keys[16];
5270 WCHAR path[MAX_PATH];
5271 IShellFolder *desktop,*folder;
5272 IPersistFolder2 *persist;
5273 IContextMenu *cmenu;
5274 LONG status;
5275 LPITEMIDLIST pidlFolder, pidl_child, pidl;
5276 DEFCONTEXTMENU cminfo;
5277 HRESULT hr;
5278 UINT i;
5279 const WCHAR filename[] =
5280 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
5281 if(!pSHCreateDefaultContextMenu)
5282 {
5283 win_skip("SHCreateDefaultContextMenu missing.\n");
5284 return;
5285 }
5286
5287 if(!pSHBindToParent)
5288 {
5289 skip("SHBindToParent missing.\n");
5290 return;
5291 }
5292
5293 GetCurrentDirectoryW(MAX_PATH, path);
5294 if (!path[0])
5295 {
5296 skip("GetCurrentDirectoryW returned an empty string.\n");
5297 return;
5298 }
5299 lstrcatW(path, filename);
5300 SHGetDesktopFolder(&desktop);
5301
5302 CreateFilesFolders();
5303
5304 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &pidl, 0);
5305 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
5306 if(SUCCEEDED(hr))
5307 {
5308
5309 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&folder, (LPCITEMIDLIST*)&pidl_child);
5310 ok(hr == S_OK, "Got 0x%08x\n", hr);
5311
5312 IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
5313 IPersistFolder2_GetCurFolder(persist,&pidlFolder);
5314 IPersistFolder2_Release(persist);
5315 if(SUCCEEDED(hr))
5316 {
5317
5318 cminfo.hwnd=NULL;
5319 cminfo.pcmcb=NULL;
5320 cminfo.psf=folder;
5321 cminfo.pidlFolder=NULL;
5322 cminfo.apidl=(LPCITEMIDLIST*)&pidl_child;
5323 cminfo.cidl=1;
5324 cminfo.aKeys=NULL;
5325 cminfo.cKeys=0;
5326 cminfo.punkAssociationInfo=NULL;
5327 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5328 ok(hr==S_OK,"Got 0x%08x\n", hr);
5329 IContextMenu_Release(cmenu);
5330 cminfo.pidlFolder=pidlFolder;
5331 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5332 ok(hr==S_OK,"Got 0x%08x\n", hr);
5333 IContextMenu_Release(cmenu);
5334 status = RegOpenKeyExA(HKEY_CLASSES_ROOT,"*",0,KEY_READ,keys);
5335 if(status==ERROR_SUCCESS){
5336 for(i=1;i<16;i++)
5337 keys[i]=keys[0];
5338 cminfo.aKeys=keys;
5339 cminfo.cKeys=16;
5340 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5341 RegCloseKey(keys[0]);
5342 ok(hr==S_OK,"Got 0x%08x\n", hr);
5343 IContextMenu_Release(cmenu);
5344 }
5345 }
5346 ILFree(pidlFolder);
5347 IShellFolder_Release(folder);
5348 }
5349 IShellFolder_Release(desktop);
5350 ILFree(pidl);
5351 Cleanup();
5352 }
5353
5354 static void test_DataObject(void)
5355 {
5356 IShellFolder *desktop;
5357 IDataObject *data_obj;
5358 HRESULT hres;
5359 IEnumIDList *peidl;
5360 LPITEMIDLIST apidl;
5361 FORMATETC fmt;
5362 DWORD cf_shellidlist;
5363 STGMEDIUM medium;
5364
5365 SHGetDesktopFolder(&desktop);
5366
5367 hres = IShellFolder_EnumObjects(desktop, NULL,
5368 SHCONTF_NONFOLDERS|SHCONTF_FOLDERS|SHCONTF_INCLUDEHIDDEN, &peidl);
5369 ok(hres == S_OK, "got %x\n", hres);
5370
5371 if(IEnumIDList_Next(peidl, 1, &apidl, NULL) != S_OK) {
5372 skip("no files on desktop - skipping GetDataObject tests\n");
5373 IEnumIDList_Release(peidl);
5374 IShellFolder_Release(desktop);
5375 return;
5376 }
5377 IEnumIDList_Release(peidl);
5378
5379 hres = IShellFolder_GetUIObjectOf(desktop, NULL, 1, (LPCITEMIDLIST*)&apidl,
5380 &IID_IDataObject, NULL, (void**)&data_obj);
5381 ok(hres == S_OK, "got %x\n", hres);
5382 pILFree(apidl);
5383 IShellFolder_Release(desktop);
5384
5385 cf_shellidlist = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
5386 fmt.cfFormat = cf_shellidlist;
5387 fmt.ptd = NULL;
5388 fmt.dwAspect = DVASPECT_CONTENT;
5389 fmt.lindex = -1;
5390 fmt.tymed = TYMED_HGLOBAL;
5391 hres = IDataObject_QueryGetData(data_obj, &fmt);
5392 ok(hres == S_OK, "got %x\n", hres);
5393
5394 fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5395 hres = IDataObject_QueryGetData(data_obj, &fmt);
5396 ok(hres == S_OK, "got %x\n", hres);
5397
5398 fmt.tymed = TYMED_ISTREAM;
5399 hres = IDataObject_QueryGetData(data_obj, &fmt);
5400 todo_wine ok(hres == S_FALSE, "got %x\n", hres);
5401
5402 fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5403 hres = IDataObject_GetData(data_obj, &fmt, &medium);
5404 ok(hres == S_OK, "got %x\n", hres);
5405 ok(medium.tymed == TYMED_HGLOBAL, "medium.tymed = %x\n", medium.tymed);
5406 ReleaseStgMedium(&medium);
5407
5408 IDataObject_Release(data_obj);
5409 }
5410
5411 START_TEST(shlfolder)
5412 {
5413 init_function_pointers();
5414 /* if OleInitialize doesn't get called, ParseDisplayName returns
5415 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
5416 OleInitialize(NULL);
5417
5418 test_ParseDisplayName();
5419 test_SHParseDisplayName();
5420 test_BindToObject();
5421 test_EnumObjects_and_CompareIDs();
5422 test_GetDisplayName();
5423 test_GetAttributesOf();
5424 test_SHGetPathFromIDList();
5425 test_CallForAttributes();
5426 test_FolderShortcut();
5427 test_ITEMIDLIST_format();
5428 test_SHGetFolderPathA();
5429 test_SHGetFolderPathAndSubDirA();
5430 test_LocalizedNames();
5431 test_SHCreateShellItem();
5432 test_SHCreateShellItemArray();
5433 test_ShellItemArrayEnumItems();
5434 test_desktop_IPersist();
5435 test_GetUIObject();
5436 test_SHSimpleIDListFromPath();
5437 test_ParseDisplayNamePBC();
5438 test_SHGetNameFromIDList();
5439 test_SHGetItemFromDataObject();
5440 test_SHGetIDListFromObject();
5441 test_SHGetItemFromObject();
5442 test_ShellItemCompare();
5443 test_SHChangeNotify(FALSE);
5444 test_SHChangeNotify(TRUE);
5445 test_ShellItemBindToHandler();
5446 test_ShellItemGetAttributes();
5447 test_ShellItemArrayGetAttributes();
5448 test_SHCreateDefaultContextMenu();
5449 test_DataObject();
5450
5451 OleUninitialize();
5452 }