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