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