2 * Unit test of the IShellFolder functions.
4 * Copyright 2004 Vitaliy Margolen
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.
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.
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
40 #include "wine/test.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);
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);
75 static WCHAR *make_wstr(const char *str)
80 if(!str || strlen(str) == 0)
83 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
87 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
91 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
95 static int strcmp_wa(LPCWSTR strw, const char *stra)
98 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
99 return lstrcmpA(stra, buf);
102 static void init_function_pointers(void)
108 hmod = GetModuleHandleA("shell32.dll");
110 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
111 MAKEFUNC(SHBindToParent);
112 MAKEFUNC(SHCreateItemFromIDList);
113 MAKEFUNC(SHCreateItemFromParsingName);
114 MAKEFUNC(SHCreateShellItem);
115 MAKEFUNC(SHCreateShellItemArray);
116 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
117 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
118 MAKEFUNC(SHGetFolderPathA);
119 MAKEFUNC(SHGetFolderPathAndSubDirA);
120 MAKEFUNC(SHGetPathFromIDListW);
121 MAKEFUNC(SHGetSpecialFolderPathA);
122 MAKEFUNC(SHGetSpecialFolderPathW);
123 MAKEFUNC(SHGetSpecialFolderLocation);
124 MAKEFUNC(SHParseDisplayName);
125 MAKEFUNC(SHGetNameFromIDList);
126 MAKEFUNC(SHGetItemFromDataObject);
127 MAKEFUNC(SHGetIDListFromObject);
128 MAKEFUNC(SHGetItemFromObject);
131 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
132 MAKEFUNC_ORD(ILFindLastID, 16);
133 MAKEFUNC_ORD(ILIsEqual, 21);
134 MAKEFUNC_ORD(ILCombine, 25);
135 MAKEFUNC_ORD(ILFree, 155);
136 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
139 /* test named exports */
140 ptr = GetProcAddress(hmod, "ILFree");
141 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
144 #define TESTNAMED(f) \
145 ptr = (void*)GetProcAddress(hmod, #f); \
146 ok(ptr != 0, "expected named export for " #f "\n");
148 TESTNAMED(ILAppendID);
150 TESTNAMED(ILCloneFirst);
151 TESTNAMED(ILCombine);
152 TESTNAMED(ILCreateFromPath);
153 TESTNAMED(ILCreateFromPathA);
154 TESTNAMED(ILCreateFromPathW);
155 TESTNAMED(ILFindChild);
156 TESTNAMED(ILFindLastID);
157 TESTNAMED(ILGetNext);
158 TESTNAMED(ILGetSize);
159 TESTNAMED(ILIsEqual);
160 TESTNAMED(ILIsParent);
161 TESTNAMED(ILRemoveLastID);
162 TESTNAMED(ILSaveToStream);
166 hmod = GetModuleHandleA("shlwapi.dll");
167 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
169 hmod = GetModuleHandleA("kernel32.dll");
170 pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
171 pGetSystemWow64DirectoryW = (void*)GetProcAddress(hmod, "GetSystemWow64DirectoryW");
173 hr = SHGetMalloc(&ppM);
174 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
177 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
178 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
182 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
188 if (lpszPath[-1] != '\\')
197 static void test_ParseDisplayName(void)
200 IShellFolder *IDesktopFolder;
201 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
202 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
203 static const char *cInetTestA = "http:\\yyy";
204 static const char *cInetTest2A = "xx:yyy";
206 WCHAR cTestDirW [MAX_PATH] = {0};
210 hr = SHGetDesktopFolder(&IDesktopFolder);
211 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
212 if(hr != S_OK) return;
214 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
215 if (pSHCreateShellItem)
217 /* null name and pidl */
218 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
219 NULL, NULL, NULL, NULL, NULL, 0);
220 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
223 newPIDL = (ITEMIDLIST*)0xdeadbeef;
224 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
225 NULL, NULL, NULL, NULL, &newPIDL, 0);
226 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
227 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
230 win_skip("Tests would crash on W2K and below\n");
232 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
233 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
234 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
235 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
236 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
239 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
240 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
241 IMalloc_Free(ppM, newPIDL);
244 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
245 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
246 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
247 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
248 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
251 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
252 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
253 IMalloc_Free(ppM, newPIDL);
256 res = GetFileAttributesA(cNonExistDir1A);
257 if(res != INVALID_FILE_ATTRIBUTES)
259 skip("Test directory unexpectedly exists\n");
263 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
264 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
265 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
266 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
267 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
269 res = GetFileAttributesA(cNonExistDir2A);
270 if(res != INVALID_FILE_ATTRIBUTES)
272 skip("Test directory unexpectedly exists\n");
276 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
277 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
278 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
279 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
280 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
282 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
283 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
284 * out it doesn't. The magic seems to happen in the file dialogs, then. */
285 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
287 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
291 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
292 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
293 if (!bRes) goto finished;
295 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
296 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
297 if (hr != S_OK) goto finished;
299 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
300 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
301 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
302 pILFindLastID(newPIDL)->mkid.abID[0]);
303 IMalloc_Free(ppM, newPIDL);
306 IShellFolder_Release(IDesktopFolder);
309 /* creates a file with the specified name for tests */
310 static void CreateTestFile(const CHAR *name)
315 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
316 if (file != INVALID_HANDLE_VALUE)
318 WriteFile(file, name, strlen(name), &written, NULL);
319 WriteFile(file, "\n", strlen("\n"), &written, NULL);
325 /* initializes the tests */
326 static void CreateFilesFolders(void)
328 CreateDirectoryA(".\\testdir", NULL);
329 CreateDirectoryA(".\\testdir\\test.txt", NULL);
330 CreateTestFile (".\\testdir\\test1.txt ");
331 CreateTestFile (".\\testdir\\test2.txt ");
332 CreateTestFile (".\\testdir\\test3.txt ");
333 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
334 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
337 /* cleans after tests */
338 static void Cleanup(void)
340 DeleteFileA(".\\testdir\\test1.txt");
341 DeleteFileA(".\\testdir\\test2.txt");
342 DeleteFileA(".\\testdir\\test3.txt");
343 RemoveDirectoryA(".\\testdir\\test.txt");
344 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
345 RemoveDirectoryA(".\\testdir\\testdir2");
346 RemoveDirectoryA(".\\testdir");
351 static void test_EnumObjects(IShellFolder *iFolder)
353 IEnumIDList *iEnumList;
354 LPITEMIDLIST newPIDL, idlArr[10];
359 static const WORD iResults [5][5] =
368 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
369 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
370 static const ULONG attrs[5] =
372 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
373 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
374 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
375 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
376 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
379 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
380 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
382 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
383 * the filesystem shellfolders return S_OK even if less than 'celt' items are
384 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
385 * only ever returns a single entry per call. */
386 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
388 ok (i == 5, "i: %d\n", i);
390 hr = IEnumIDList_Release(iEnumList);
391 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
393 /* Sort them first in case of wrong order from system */
394 for (i=0;i<5;i++) for (j=0;j<5;j++)
395 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
398 idlArr[i] = idlArr[j];
402 for (i=0;i<5;i++) for (j=0;j<5;j++)
404 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
405 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
409 for (i = 0; i < 5; i++)
412 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
413 /* Native returns all flags no matter what we ask for */
414 flags = SFGAO_CANCOPY;
415 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
416 flags &= SFGAO_testfor;
417 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
418 ok(flags == (attrs[i]) ||
419 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
420 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
421 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
423 flags = SFGAO_testfor;
424 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
425 flags &= SFGAO_testfor;
426 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
427 ok(flags == attrs[i] ||
428 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
429 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
433 IMalloc_Free(ppM, idlArr[i]);
436 static void test_BindToObject(void)
440 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
441 SHITEMID emptyitem = { 0, { 0 } };
442 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
443 WCHAR wszSystemDir[MAX_PATH];
444 char szSystemDir[MAX_PATH];
446 WCHAR path[MAX_PATH];
447 CHAR pathA[MAX_PATH];
449 WCHAR wszMyComputer[] = {
450 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
451 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
452 static const CHAR filename_html[] = "winetest.html";
453 static const CHAR filename_txt[] = "winetest.txt";
454 static const CHAR filename_foo[] = "winetest.foo";
456 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
457 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
459 hr = SHGetDesktopFolder(&psfDesktop);
460 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
461 if (hr != S_OK) return;
463 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
464 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
466 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
467 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
469 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
470 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
472 IShellFolder_Release(psfDesktop);
476 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
477 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
478 IShellFolder_Release(psfDesktop);
479 IMalloc_Free(ppM, pidlMyComputer);
480 if (hr != S_OK) return;
482 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
483 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
487 /* this call segfaults on 98SE */
488 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
489 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
492 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
493 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
494 if (cChars == 0 || cChars >= MAX_PATH) {
495 IShellFolder_Release(psfMyComputer);
498 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
500 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
501 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
503 IShellFolder_Release(psfMyComputer);
507 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
508 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
509 IShellFolder_Release(psfMyComputer);
510 IMalloc_Free(ppM, pidlSystemDir);
511 if (hr != S_OK) return;
513 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
514 ok (hr == E_INVALIDARG,
515 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
519 /* this call segfaults on 98SE */
520 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
521 ok (hr == E_INVALIDARG,
522 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
525 IShellFolder_Release(psfSystemDir);
527 GetCurrentDirectoryA(MAX_PATH, buf);
530 skip("Failed to get current directory, skipping tests.\n");
534 SHGetDesktopFolder(&psfDesktop);
536 /* Attempt BindToObject on files. */
539 lstrcpyA(pathA, buf);
540 lstrcatA(pathA, "\\");
541 lstrcatA(pathA, filename_html);
542 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
543 if(hfile != INVALID_HANDLE_VALUE)
546 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
547 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
548 ok(hr == S_OK, "Got 0x%08x\n", hr);
551 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
553 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
558 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
560 broken(hr == E_NOINTERFACE), /* Win9x, NT4, W2K */
565 hr = IPersist_GetClassID(pp, &id);
566 ok(hr == S_OK, "Got 0x%08x\n", hr);
567 ok(IsEqualIID(&id, &CLSID_ShellDocObjView), "Unexpected classid\n");
568 IPersist_Release(pp);
571 IShellFolder_Release(psfChild);
578 win_skip("Failed to create .html testfile.\n");
581 lstrcpyA(pathA, buf);
582 lstrcatA(pathA, "\\");
583 lstrcatA(pathA, filename_txt);
584 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
585 if(hfile != INVALID_HANDLE_VALUE)
588 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
589 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
590 ok(hr == S_OK, "Got 0x%08x\n", hr);
593 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
594 ok(hr == E_FAIL || /* Vista+ */
595 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
596 broken(hr == S_OK), /* Win9x, NT4, W2K */
598 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
604 win_skip("Failed to create .txt testfile.\n");
607 lstrcpyA(pathA, buf);
608 lstrcatA(pathA, "\\");
609 lstrcatA(pathA, filename_foo);
610 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
611 if(hfile != INVALID_HANDLE_VALUE)
614 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
615 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
616 ok(hr == S_OK, "Got 0x%08x\n", hr);
619 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
620 ok(hr == E_FAIL || /* Vista+ */
621 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
622 broken(hr == S_OK), /* Win9x, NT4, W2K */
624 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
630 win_skip("Failed to create .foo testfile.\n");
632 /* And on the desktop */
633 if(pSHGetSpecialFolderPathA)
635 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
636 lstrcatA(pathA, "\\");
637 lstrcatA(pathA, filename_html);
638 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
639 if(hfile != INVALID_HANDLE_VALUE)
642 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
643 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
644 ok(hr == S_OK, "Got 0x%08x\n", hr);
647 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
649 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
651 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
654 if(!DeleteFileA(pathA))
655 trace("Failed to delete: %d\n", GetLastError());
659 win_skip("Failed to create .html testfile.\n");
661 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
662 lstrcatA(pathA, "\\");
663 lstrcatA(pathA, filename_foo);
664 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
665 if(hfile != INVALID_HANDLE_VALUE)
668 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
669 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
670 ok(hr == S_OK, "Got 0x%08x\n", hr);
673 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
674 ok(hr == E_FAIL || /* Vista+ */
675 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
676 broken(hr == S_OK), /* Win9x, NT4, W2K */
678 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
684 win_skip("Failed to create .foo testfile.\n");
687 IShellFolder_Release(psfDesktop);
690 static void test_GetDisplayName(void)
695 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
696 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
699 LPSHELLFOLDER psfDesktop, psfPersonal;
701 SHITEMID emptyitem = { 0, { 0 } };
702 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
703 LPCITEMIDLIST pidlLast;
704 static const CHAR szFileName[] = "winetest.foo";
705 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
706 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
708 /* I'm trying to figure if there is a functional difference between calling
709 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
710 * binding to the shellfolder. One thing I thought of was that perhaps
711 * SHGetPathFromIDListW would be able to get the path to a file, which does
712 * not exist anymore, while the other method wouldn't. It turns out there's
713 * no functional difference in this respect.
716 if(!pSHGetSpecialFolderPathA) {
717 win_skip("SHGetSpecialFolderPathA is not available\n");
721 /* First creating a directory in MyDocuments and a file in this directory. */
722 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
723 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
726 /* Use ANSI file functions so this works on Windows 9x */
727 lstrcatA(szTestDir, "\\winetest");
728 CreateDirectoryA(szTestDir, NULL);
729 attr=GetFileAttributesA(szTestDir);
730 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
732 ok(0, "unable to create the '%s' directory\n", szTestDir);
736 lstrcpyA(szTestFile, szTestDir);
737 lstrcatA(szTestFile, "\\");
738 lstrcatA(szTestFile, szFileName);
739 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
740 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
741 if (hTestFile == INVALID_HANDLE_VALUE) return;
742 CloseHandle(hTestFile);
744 /* Getting an itemidlist for the file. */
745 hr = SHGetDesktopFolder(&psfDesktop);
746 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
747 if (hr != S_OK) return;
749 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
751 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
752 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
754 IShellFolder_Release(psfDesktop);
758 pidlLast = pILFindLastID(pidlTestFile);
759 ok(pidlLast->mkid.cb >=76 ||
760 broken(pidlLast->mkid.cb == 28) || /* W2K */
761 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
762 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
763 if (pidlLast->mkid.cb >= 28) {
764 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
765 "Filename should be stored as ansi-string at this position!\n");
767 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
768 if (pidlLast->mkid.cb >= 76) {
769 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
770 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
771 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
772 "Filename should be stored as wchar-string at this position!\n");
775 /* It seems as if we cannot bind to regular files on windows, but only directories.
777 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
778 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
779 hr == E_NOTIMPL || /* Vista */
780 broken(hr == S_OK), /* Win9x, W2K */
783 IShellFolder_Release(psfFile);
786 if (!pSHBindToParent)
788 win_skip("SHBindToParent is missing\n");
789 DeleteFileA(szTestFile);
790 RemoveDirectoryA(szTestDir);
794 /* Some tests for IShellFolder::SetNameOf */
795 if (pSHGetFolderPathAndSubDirA)
797 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
798 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
800 /* It's ok to use this fixed path. Call will fail anyway. */
801 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
802 LPITEMIDLIST pidlNew;
804 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
805 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
806 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
809 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
810 "pidl returned from SetNameOf should be simple!\n");
812 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
813 * is implemented on top of SHFileOperation in WinXP. */
814 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
815 SHGDN_FORPARSING, NULL);
816 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
818 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
819 * SHGDN flags specify an absolute path. */
820 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
821 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
826 IShellFolder_Release(psfPersonal);
830 win_skip("Avoid needs of interaction on Win2k\n");
832 /* Deleting the file and the directory */
833 DeleteFileA(szTestFile);
834 RemoveDirectoryA(szTestDir);
836 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
837 if (pSHGetPathFromIDListW)
839 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
840 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
841 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
844 /* SHBindToParent fails, if called with a NULL PIDL. */
845 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
846 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
848 /* But it succeeds with an empty PIDL. */
849 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
850 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
851 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
853 IShellFolder_Release(psfPersonal);
855 /* Binding to the folder and querying the display name of the file also works. */
856 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
857 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
859 IShellFolder_Release(psfDesktop);
863 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
864 * pidlTestFile (In accordance with MSDN). */
865 ok (pILFindLastID(pidlTestFile) == pidlLast,
866 "SHBindToParent doesn't return the last id of the pidl param!\n");
868 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
869 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
871 IShellFolder_Release(psfDesktop);
872 IShellFolder_Release(psfPersonal);
878 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
879 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
880 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
883 ILFree(pidlTestFile);
884 IShellFolder_Release(psfDesktop);
885 IShellFolder_Release(psfPersonal);
888 static void test_CallForAttributes(void)
894 LPSHELLFOLDER psfDesktop;
895 LPITEMIDLIST pidlMyDocuments;
896 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
897 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
898 static const WCHAR wszCallForAttributes[] = {
899 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
900 static const WCHAR wszMyDocumentsKey[] = {
901 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
902 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
903 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
904 WCHAR wszMyDocuments[] = {
905 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
906 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
908 /* For the root of a namespace extension, the attributes are not queried by binding
909 * to the object and calling GetAttributesOf. Instead, the attributes are read from
910 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
912 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
913 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
914 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
915 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
917 hr = SHGetDesktopFolder(&psfDesktop);
918 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
919 if (hr != S_OK) return;
921 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
922 &pidlMyDocuments, NULL);
924 broken(hr == E_INVALIDARG), /* Win95, NT4 */
925 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
927 IShellFolder_Release(psfDesktop);
931 dwAttributes = 0xffffffff;
932 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
933 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
934 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
936 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
937 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
938 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
939 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
941 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
942 * key. So the test will return at this point, if run on wine.
944 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
945 ok (lResult == ERROR_SUCCESS ||
946 lResult == ERROR_ACCESS_DENIED,
947 "RegOpenKeyEx failed! result: %08x\n", lResult);
948 if (lResult != ERROR_SUCCESS) {
949 if (lResult == ERROR_ACCESS_DENIED)
950 skip("Not enough rights to open the registry key\n");
951 IMalloc_Free(ppM, pidlMyDocuments);
952 IShellFolder_Release(psfDesktop);
956 /* Query MyDocuments' Attributes value, to be able to restore it later. */
957 dwSize = sizeof(DWORD);
958 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
959 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
960 if (lResult != ERROR_SUCCESS) {
962 IMalloc_Free(ppM, pidlMyDocuments);
963 IShellFolder_Release(psfDesktop);
967 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
968 dwSize = sizeof(DWORD);
969 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
970 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
971 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
972 if (lResult != ERROR_SUCCESS) {
974 IMalloc_Free(ppM, pidlMyDocuments);
975 IShellFolder_Release(psfDesktop);
979 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
980 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
981 * SFGAO_FILESYSTEM attributes. */
982 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
983 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
984 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
985 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
986 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
988 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
989 * GetAttributesOf. It seems that once there is a single attribute queried, for which
990 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
991 * the flags in Attributes are ignored.
993 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
994 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
995 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
996 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
998 ok (dwAttributes == SFGAO_FILESYSTEM,
999 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
1002 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
1003 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
1004 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1005 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
1007 IMalloc_Free(ppM, pidlMyDocuments);
1008 IShellFolder_Release(psfDesktop);
1011 static void test_GetAttributesOf(void)
1014 LPSHELLFOLDER psfDesktop, psfMyComputer;
1015 SHITEMID emptyitem = { 0, { 0 } };
1016 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1017 LPITEMIDLIST pidlMyComputer;
1019 static const DWORD desktopFlags[] = {
1021 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
1022 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1024 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
1025 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1026 /* WinMe, Win9x, WinNT*/
1027 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
1028 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1030 static const DWORD myComputerFlags[] = {
1032 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
1033 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1035 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
1036 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1037 /* WinMe, Win9x, WinNT */
1038 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1039 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1040 /* Win95, WinNT when queried directly */
1041 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1042 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1044 WCHAR wszMyComputer[] = {
1045 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1046 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1047 char cCurrDirA [MAX_PATH] = {0};
1048 WCHAR cCurrDirW [MAX_PATH];
1049 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
1050 IShellFolder *IDesktopFolder, *testIShellFolder;
1051 ITEMIDLIST *newPIDL;
1053 BOOL foundFlagsMatch;
1055 hr = SHGetDesktopFolder(&psfDesktop);
1056 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1057 if (hr != S_OK) return;
1059 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
1060 dwFlags = 0xffffffff;
1061 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
1062 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
1063 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1064 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1066 if (desktopFlags[i] == dwFlags)
1067 foundFlagsMatch = TRUE;
1069 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1071 /* .. or with no itemidlist at all. */
1072 dwFlags = 0xffffffff;
1073 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
1074 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1075 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1076 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1078 if (desktopFlags[i] == dwFlags)
1079 foundFlagsMatch = TRUE;
1081 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1083 /* Testing the attributes of the MyComputer shellfolder */
1084 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1085 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1087 IShellFolder_Release(psfDesktop);
1091 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
1092 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
1094 dwFlags = 0xffffffff;
1095 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
1096 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
1097 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1098 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1100 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
1101 foundFlagsMatch = TRUE;
1104 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1106 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
1107 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
1108 IShellFolder_Release(psfDesktop);
1109 IMalloc_Free(ppM, pidlMyComputer);
1110 if (hr != S_OK) return;
1112 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
1114 ok (hr == E_INVALIDARG ||
1115 broken(hr == S_OK), /* W2K and earlier */
1116 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
1118 dwFlags = 0xffffffff;
1119 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
1120 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1121 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1122 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1124 if (myComputerFlags[i] == dwFlags)
1125 foundFlagsMatch = TRUE;
1128 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1130 IShellFolder_Release(psfMyComputer);
1132 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1133 len = lstrlenA(cCurrDirA);
1136 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1139 if (len > 3 && cCurrDirA[len-1] == '\\')
1140 cCurrDirA[len-1] = 0;
1142 /* create test directory */
1143 CreateFilesFolders();
1145 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1147 hr = SHGetDesktopFolder(&IDesktopFolder);
1148 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1150 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1151 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1153 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1154 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1156 IMalloc_Free(ppM, newPIDL);
1158 /* get relative PIDL */
1159 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1160 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1162 /* test the shell attributes of the test directory using the relative PIDL */
1163 dwFlags = SFGAO_FOLDER;
1164 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1165 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1166 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1169 IMalloc_Free(ppM, newPIDL);
1171 /* append testdirectory name to path */
1172 if (cCurrDirA[len-1] == '\\')
1173 cCurrDirA[len-1] = 0;
1174 lstrcatA(cCurrDirA, "\\testdir");
1175 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1177 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1178 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1180 /* test the shell attributes of the test directory using the absolute PIDL */
1181 dwFlags = SFGAO_FOLDER;
1182 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1183 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1184 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1187 IMalloc_Free(ppM, newPIDL);
1189 IShellFolder_Release(testIShellFolder);
1193 IShellFolder_Release(IDesktopFolder);
1196 static void test_SHGetPathFromIDList(void)
1198 SHITEMID emptyitem = { 0, { 0 } };
1199 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1200 LPITEMIDLIST pidlMyComputer;
1201 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1204 LPSHELLFOLDER psfDesktop;
1205 WCHAR wszMyComputer[] = {
1206 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1207 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1208 WCHAR wszFileName[MAX_PATH];
1209 LPITEMIDLIST pidlTestFile;
1212 static WCHAR wszTestFile[] = {
1213 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1214 LPITEMIDLIST pidlPrograms;
1216 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1218 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1222 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1225 result = pSHGetPathFromIDListW(NULL, wszPath);
1226 ok(!result, "Expected failure\n");
1227 ok(!wszPath[0], "Expected empty string\n");
1229 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1230 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1231 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1232 if (!result) return;
1234 /* Check if we are on Win9x */
1235 SetLastError(0xdeadbeef);
1236 lstrcmpiW(wszDesktop, wszDesktop);
1237 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1239 win_skip("Most W-calls are not implemented\n");
1243 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1244 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1245 if (!result) return;
1246 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1248 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1249 hr = SHGetDesktopFolder(&psfDesktop);
1250 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1251 if (hr != S_OK) return;
1253 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1254 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1256 IShellFolder_Release(psfDesktop);
1260 SetLastError(0xdeadbeef);
1263 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1264 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1265 ok (GetLastError()==0xdeadbeef ||
1266 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1267 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1268 ok (!wszPath[0], "Expected empty path\n");
1270 IShellFolder_Release(psfDesktop);
1274 IMalloc_Free(ppM, pidlMyComputer);
1276 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1277 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1279 IShellFolder_Release(psfDesktop);
1282 myPathAddBackslashW(wszFileName);
1283 lstrcatW(wszFileName, wszTestFile);
1284 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1285 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1286 if (hTestFile == INVALID_HANDLE_VALUE) {
1287 IShellFolder_Release(psfDesktop);
1290 CloseHandle(hTestFile);
1292 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1293 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1295 IShellFolder_Release(psfDesktop);
1296 DeleteFileW(wszFileName);
1297 IMalloc_Free(ppM, pidlTestFile);
1301 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1302 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1303 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1304 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1305 IShellFolder_Release(psfDesktop);
1306 DeleteFileW(wszFileName);
1308 IMalloc_Free(ppM, pidlTestFile);
1313 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1314 ok(0 == lstrcmpW(wszFileName, wszPath),
1315 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1316 "returned incorrect path for file placed on desktop\n");
1319 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1320 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1321 IMalloc_Free(ppM, pidlTestFile);
1322 if (!result) return;
1323 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1326 /* Test if we can get the path from the start menu "program files" PIDL. */
1327 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1328 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1330 SetLastError(0xdeadbeef);
1331 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1332 IMalloc_Free(ppM, pidlPrograms);
1333 ok(result, "SHGetPathFromIDListW failed\n");
1336 static void test_EnumObjects_and_CompareIDs(void)
1338 ITEMIDLIST *newPIDL;
1339 IShellFolder *IDesktopFolder, *testIShellFolder;
1340 char cCurrDirA [MAX_PATH] = {0};
1341 static const CHAR cTestDirA[] = "\\testdir";
1342 WCHAR cTestDirW[MAX_PATH];
1346 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1347 len = lstrlenA(cCurrDirA);
1350 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1353 if(cCurrDirA[len-1] == '\\')
1354 cCurrDirA[len-1] = 0;
1356 lstrcatA(cCurrDirA, cTestDirA);
1357 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1359 hr = SHGetDesktopFolder(&IDesktopFolder);
1360 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1362 CreateFilesFolders();
1364 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1365 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1367 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1368 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1370 test_EnumObjects(testIShellFolder);
1372 IShellFolder_Release(testIShellFolder);
1376 IMalloc_Free(ppM, newPIDL);
1378 IShellFolder_Release(IDesktopFolder);
1381 /* A simple implementation of an IPropertyBag, which returns fixed values for
1382 * 'Target' and 'Attributes' properties.
1384 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1388 return E_INVALIDARG;
1390 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1393 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1394 return E_NOINTERFACE;
1397 IPropertyBag_AddRef(iface);
1401 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1405 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1409 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1410 VARIANT *pVar, IErrorLog *pErrorLog)
1412 static const WCHAR wszTargetSpecialFolder[] = {
1413 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1414 static const WCHAR wszTarget[] = {
1415 'T','a','r','g','e','t',0 };
1416 static const WCHAR wszAttributes[] = {
1417 'A','t','t','r','i','b','u','t','e','s',0 };
1418 static const WCHAR wszResolveLinkFlags[] = {
1419 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1420 static const WCHAR wszTargetKnownFolder[] = {
1421 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1422 static const WCHAR wszCLSID[] = {
1423 'C','L','S','I','D',0 };
1425 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1426 ok(V_VT(pVar) == VT_I4 ||
1427 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1428 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1429 return E_INVALIDARG;
1432 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1434 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1435 return E_INVALIDARG;
1438 if (!lstrcmpW(pszPropName, wszTarget)) {
1439 WCHAR wszPath[MAX_PATH];
1442 ok(V_VT(pVar) == VT_BSTR ||
1443 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1444 "Wrong variant type for 'Target' property!\n");
1445 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1447 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1448 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1449 if (!result) return E_INVALIDARG;
1451 V_BSTR(pVar) = SysAllocString(wszPath);
1455 if (!lstrcmpW(pszPropName, wszAttributes)) {
1456 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1457 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1458 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1459 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1463 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1464 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1466 return E_INVALIDARG;
1469 if (!lstrcmpW(pszPropName, wszCLSID)) {
1470 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1472 return E_INVALIDARG;
1475 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1476 return E_INVALIDARG;
1479 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1482 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1486 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1487 InitPropertyBag_IPropertyBag_QueryInterface,
1488 InitPropertyBag_IPropertyBag_AddRef,
1489 InitPropertyBag_IPropertyBag_Release,
1490 InitPropertyBag_IPropertyBag_Read,
1491 InitPropertyBag_IPropertyBag_Write
1494 static struct IPropertyBag InitPropertyBag = {
1495 &InitPropertyBag_IPropertyBagVtbl
1498 static void test_FolderShortcut(void) {
1499 IPersistPropertyBag *pPersistPropertyBag;
1500 IShellFolder *pShellFolder, *pDesktopFolder;
1501 IPersistFolder3 *pPersistFolder3;
1504 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1507 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1509 WCHAR wszWineTestFolder[] = {
1510 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1511 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1512 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1513 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1514 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1515 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1516 'N','a','m','e','S','p','a','c','e','\\',
1517 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1518 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1520 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1521 static const GUID CLSID_UnixDosFolder =
1522 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1524 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1525 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1529 if (!pSHGetFolderPathAndSubDirA)
1531 win_skip("FolderShortcut test doesn't work on Win2k\n");
1535 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1536 * via their IPersistPropertyBag interface. And that the target folder
1537 * is taken from the IPropertyBag's 'Target' property.
1539 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1540 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1541 if (hr == REGDB_E_CLASSNOTREG) {
1542 win_skip("CLSID_FolderShortcut is not implemented\n");
1545 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1546 if (hr != S_OK) return;
1548 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1549 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1551 IPersistPropertyBag_Release(pPersistPropertyBag);
1555 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1556 (LPVOID*)&pShellFolder);
1557 IPersistPropertyBag_Release(pPersistPropertyBag);
1558 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1559 if (hr != S_OK) return;
1561 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1562 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1564 IShellFolder_Release(pShellFolder);
1568 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1569 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1570 if (!result) return;
1572 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1573 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1575 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1576 IShellFolder_Release(pShellFolder);
1577 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1578 if (hr != S_OK) return;
1580 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1581 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1582 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1584 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1585 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1586 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1588 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1589 * shell namespace. The target folder, read from the property bag above, remains untouched.
1590 * The following tests show this: The itemidlist for some imaginary shellfolder object
1591 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1592 * itemidlist, but GetDisplayNameOf still returns the path from above.
1594 hr = SHGetDesktopFolder(&pDesktopFolder);
1595 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1596 if (hr != S_OK) return;
1598 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1599 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1600 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1601 RegCloseKey(hShellExtKey);
1602 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1603 &pidlWineTestFolder, NULL);
1604 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1605 IShellFolder_Release(pDesktopFolder);
1606 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1607 if (hr != S_OK) return;
1609 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1610 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1612 IPersistFolder3_Release(pPersistFolder3);
1613 pILFree(pidlWineTestFolder);
1617 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1618 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1619 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1620 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1621 pILFree(pidlCurrentFolder);
1622 pILFree(pidlWineTestFolder);
1624 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1625 IPersistFolder3_Release(pPersistFolder3);
1626 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1627 if (hr != S_OK) return;
1629 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1630 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1632 IShellFolder_Release(pShellFolder);
1636 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1637 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1639 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1640 * but ShellFSFolders. */
1641 myPathAddBackslashW(wszDesktopPath);
1642 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1643 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1644 IShellFolder_Release(pShellFolder);
1648 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1649 &pidlSubFolder, NULL);
1650 RemoveDirectoryW(wszDesktopPath);
1651 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1653 IShellFolder_Release(pShellFolder);
1657 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1658 (LPVOID*)&pPersistFolder3);
1659 IShellFolder_Release(pShellFolder);
1660 pILFree(pidlSubFolder);
1661 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1665 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1666 * a little bit and also allow CLSID_UnixDosFolder. */
1667 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1668 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1669 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1670 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1672 IPersistFolder3_Release(pPersistFolder3);
1675 #include "pshpack1.h"
1676 struct FileStructA {
1680 WORD uFileDate; /* In our current implementation this is */
1681 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1686 struct FileStructW {
1687 WORD cbLen; /* Length of this element. */
1688 BYTE abFooBar1[6]; /* Beyond any recognition. */
1689 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1690 WORD uTime; /* (this is currently speculation) */
1691 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1692 WORD uTime2; /* (this is currently speculation) */
1693 BYTE abFooBar2[4]; /* Beyond any recognition. */
1694 WCHAR wszName[1]; /* The long filename in unicode. */
1695 /* Just for documentation: Right after the unicode string: */
1696 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1697 * SHITEMID->cb == uOffset + cbLen */
1699 #include "poppack.h"
1701 static void test_ITEMIDLIST_format(void) {
1702 WCHAR wszPersonal[MAX_PATH];
1703 LPSHELLFOLDER psfDesktop, psfPersonal;
1704 LPITEMIDLIST pidlPersonal, pidlFile;
1708 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1709 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1712 if (!pSHGetSpecialFolderPathW) return;
1714 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1715 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1716 if (!bResult) return;
1718 SetLastError(0xdeadbeef);
1719 bResult = SetCurrentDirectoryW(wszPersonal);
1720 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1721 win_skip("Most W-calls are not implemented\n");
1724 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1725 if (!bResult) return;
1727 hr = SHGetDesktopFolder(&psfDesktop);
1728 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1729 if (hr != S_OK) return;
1731 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1732 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1734 IShellFolder_Release(psfDesktop);
1738 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1739 (LPVOID*)&psfPersonal);
1740 IShellFolder_Release(psfDesktop);
1741 pILFree(pidlPersonal);
1742 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1743 if (hr != S_OK) return;
1745 for (i=0; i<3; i++) {
1746 CHAR szFile[MAX_PATH];
1747 struct FileStructA *pFileStructA;
1750 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1752 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1753 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1754 if (hFile == INVALID_HANDLE_VALUE) {
1755 IShellFolder_Release(psfPersonal);
1760 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1761 DeleteFileW(wszFile[i]);
1762 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1764 IShellFolder_Release(psfPersonal);
1768 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1769 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1770 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1771 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1773 if (i < 2) /* First two file names are already in valid 8.3 format */
1774 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1776 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1777 * can't implement this correctly, since unix filesystems don't support
1778 * this nasty short/long filename stuff. So we'll probably stay with our
1779 * current habbit of storing the long filename here, which seems to work
1782 ok(pidlFile->mkid.abID[18] == '~' ||
1783 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1784 "Should be derived 8.3 name!\n");
1786 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1787 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1788 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1789 "Alignment byte, where there shouldn't be!\n");
1791 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1792 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1793 "There should be an alignment byte, but isn't!\n");
1795 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1796 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1797 ok ((cbOffset >= sizeof(struct FileStructA) &&
1798 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1799 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1800 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1801 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1803 if (cbOffset >= sizeof(struct FileStructA) &&
1804 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1806 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1808 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1809 "FileStructW's offset and length should add up to the PIDL's length!\n");
1811 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1812 /* Since we just created the file, time of creation,
1813 * time of last access and time of last write access just be the same.
1814 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1815 * after the first run. I do remember something with NTFS keeping the creation time
1816 * if a file is deleted and then created again within a couple of seconds or so.
1817 * Might be the reason. */
1818 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1819 pFileStructA->uFileTime == pFileStructW->uTime,
1820 "Last write time should match creation time!\n");
1822 /* On FAT filesystems the last access time is midnight
1823 local time, so the values of uDate2 and uTime2 will
1824 depend on the local timezone. If the times are exactly
1825 equal then the dates should be identical for both FAT
1826 and NTFS as no timezone is more than 1 day away from UTC.
1828 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1830 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1831 "Last write date and time should match last access date and time!\n");
1835 /* Filesystem may be FAT. Check date within 1 day
1836 and seconds are zero. */
1837 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1838 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1839 "Last access time on FAT filesystems should have zero seconds.\n");
1840 /* TODO: Perform check for date being within one day.*/
1843 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1844 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1845 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1846 "The filename should be stored in unicode at this position!\n");
1853 IShellFolder_Release(psfPersonal);
1856 static void test_SHGetFolderPathA(void)
1858 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1860 char path[MAX_PATH];
1861 char path_x86[MAX_PATH];
1862 char path_key[MAX_PATH];
1866 if (!pSHGetFolderPathA)
1868 win_skip("SHGetFolderPathA not present\n");
1871 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1873 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1874 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1875 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1878 win_skip( "Program Files (x86) not supported\n" );
1881 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1884 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1885 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1886 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1890 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1892 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1894 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1896 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1898 DWORD type, count = sizeof(path_x86);
1899 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1901 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1902 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1904 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1908 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1909 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1910 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1913 win_skip( "Common Files (x86) not supported\n" );
1916 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1919 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1920 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1921 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1925 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1927 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1929 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1931 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1933 DWORD type, count = sizeof(path_x86);
1934 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1936 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1937 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1939 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1943 static void test_SHGetFolderPathAndSubDirA(void)
1949 static char wine[] = "wine";
1950 static char winetemp[] = "wine\\temp";
1951 static char appdata[MAX_PATH];
1952 static char testpath[MAX_PATH];
1953 static char toolongpath[MAX_PATH+1];
1955 if(!pSHGetFolderPathAndSubDirA)
1957 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1961 if(!pSHGetFolderPathA) {
1962 win_skip("SHGetFolderPathA not present!\n");
1965 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1967 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1971 sprintf(testpath, "%s\\%s", appdata, winetemp);
1972 delret = RemoveDirectoryA(testpath);
1973 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1974 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1978 sprintf(testpath, "%s\\%s", appdata, wine);
1979 delret = RemoveDirectoryA(testpath);
1980 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1981 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1985 /* test invalid second parameter */
1986 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1987 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1989 /* test fourth parameter */
1990 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1992 case S_OK: /* winvista */
1993 ok(!strncmp(appdata, testpath, strlen(appdata)),
1994 "expected %s to start with %s\n", testpath, appdata);
1995 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1996 "expected %s to end with %s\n", testpath, winetemp);
1998 case E_INVALIDARG: /* winxp, win2k3 */
2001 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
2004 /* test fifth parameter */
2006 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
2007 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2008 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2011 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
2012 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2013 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2016 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
2017 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2018 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2020 for(i=0; i< MAX_PATH; i++)
2021 toolongpath[i] = '0' + i % 10;
2022 toolongpath[MAX_PATH] = '\0';
2023 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2024 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2025 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2028 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2029 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2031 /* test a not existing path */
2033 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2034 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2035 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2037 /* create a directory inside a not existing directory */
2039 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2040 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2041 ok(!strncmp(appdata, testpath, strlen(appdata)),
2042 "expected %s to start with %s\n", testpath, appdata);
2043 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2044 "expected %s to end with %s\n", testpath, winetemp);
2045 dwret = GetFileAttributes(testpath);
2046 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2049 sprintf(testpath, "%s\\%s", appdata, winetemp);
2050 RemoveDirectoryA(testpath);
2051 sprintf(testpath, "%s\\%s", appdata, wine);
2052 RemoveDirectoryA(testpath);
2055 static void test_LocalizedNames(void)
2057 static char cCurrDirA[MAX_PATH];
2058 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2059 IShellFolder *IDesktopFolder, *testIShellFolder;
2060 ITEMIDLIST *newPIDL;
2063 static char resourcefile[MAX_PATH];
2069 static const char desktopini_contents1[] =
2070 "[.ShellClassInfo]\r\n"
2071 "LocalizedResourceName=@";
2072 static const char desktopini_contents2[] =
2074 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2075 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2077 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2078 CreateDirectoryA(".\\testfolder", NULL);
2080 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2082 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2084 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2085 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2086 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2087 ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2088 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2089 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
2090 ok(ret, "WriteFile failed %i\n", GetLastError());
2093 /* get IShellFolder for parent */
2094 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2095 len = lstrlenA(cCurrDirA);
2098 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2101 if(cCurrDirA[len-1] == '\\')
2102 cCurrDirA[len-1] = 0;
2104 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2106 hr = SHGetDesktopFolder(&IDesktopFolder);
2107 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2109 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2110 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2112 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2113 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2115 IMalloc_Free(ppM, newPIDL);
2117 /* windows reads the display name from the resource */
2118 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2119 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2121 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2122 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2124 if (hr == S_OK && pStrRetToBufW)
2126 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2127 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2129 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2130 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2131 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2134 /* editing name is also read from the resource */
2135 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2136 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2138 if (hr == S_OK && pStrRetToBufW)
2140 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2141 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2143 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2144 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2145 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2148 /* parsing name is unchanged */
2149 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2150 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2152 if (hr == S_OK && pStrRetToBufW)
2154 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2155 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2156 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2159 IShellFolder_Release(IDesktopFolder);
2160 IShellFolder_Release(testIShellFolder);
2162 IMalloc_Free(ppM, newPIDL);
2165 DeleteFileA(".\\testfolder\\desktop.ini");
2166 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2167 RemoveDirectoryA(".\\testfolder");
2170 static void test_SHCreateShellItem(void)
2172 IShellItem *shellitem, *shellitem2;
2173 IPersistIDList *persistidl;
2174 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2176 char curdirA[MAX_PATH];
2177 WCHAR curdirW[MAX_PATH];
2178 WCHAR fnbufW[MAX_PATH];
2179 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2180 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2182 GetCurrentDirectoryA(MAX_PATH, curdirA);
2184 if (!pSHCreateShellItem)
2186 win_skip("SHCreateShellItem isn't available\n");
2190 if (!lstrlenA(curdirA))
2192 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2196 if(pSHGetSpecialFolderLocation)
2198 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2199 ok(ret == S_OK, "Got 0x%08x\n", ret);
2203 win_skip("pSHGetSpecialFolderLocation missing.\n");
2204 pidl_desktop = NULL;
2207 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2209 ret = SHGetDesktopFolder(&desktopfolder);
2210 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2212 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2213 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2215 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)¤tfolder);
2216 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2218 CreateTestFile(".\\testfile");
2220 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2221 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2223 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2225 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2226 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2228 if (0) /* crashes on Windows XP */
2230 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2231 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2232 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2233 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2236 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2237 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2240 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2241 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2244 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2245 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2248 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2251 IPersistIDList_Release(persistidl);
2253 IShellItem_Release(shellitem);
2256 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2257 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2260 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2261 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2264 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2265 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2268 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2271 IPersistIDList_Release(persistidl);
2274 ret = IShellItem_GetParent(shellitem, &shellitem2);
2275 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2278 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2279 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2282 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2283 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2286 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2289 IPersistIDList_Release(persistidl);
2291 IShellItem_Release(shellitem2);
2294 IShellItem_Release(shellitem);
2297 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2298 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2301 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2302 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2305 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2306 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2309 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2312 IPersistIDList_Release(persistidl);
2314 IShellItem_Release(shellitem);
2317 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2318 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2319 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2322 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2323 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2326 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2327 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2330 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2333 IPersistIDList_Release(persistidl);
2335 IShellItem_Release(shellitem);
2338 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2339 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2342 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2343 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2346 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2347 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2350 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2353 IPersistIDList_Release(persistidl);
2356 IShellItem_Release(shellitem);
2359 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2360 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2363 ret = IShellItem_GetParent(shellitem, &shellitem2);
2364 ok(FAILED(ret), "Got 0x%08x\n", ret);
2365 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2366 IShellItem_Release(shellitem);
2369 /* SHCreateItemFromParsingName */
2370 if(pSHCreateItemFromParsingName)
2374 /* Crashes under windows 7 */
2375 pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2378 shellitem = (void*)0xdeadbeef;
2379 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2380 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2381 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2383 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2384 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2385 "SHCreateItemFromParsingName returned %x\n", ret);
2386 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2388 lstrcpyW(fnbufW, curdirW);
2389 myPathAddBackslashW(fnbufW);
2390 lstrcatW(fnbufW, testfileW);
2392 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2393 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2397 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2398 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2401 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2402 CoTaskMemFree(tmp_fname);
2404 IShellItem_Release(shellitem);
2408 win_skip("No SHCreateItemFromParsingName\n");
2411 /* SHCreateItemFromIDList */
2412 if(pSHCreateItemFromIDList)
2416 /* Crashes under win7 */
2417 pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2420 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2421 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2423 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2424 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2427 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2428 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2431 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2432 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2435 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2438 IPersistIDList_Release(persistidl);
2440 IShellItem_Release(shellitem);
2443 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2444 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2447 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2448 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2451 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2452 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2455 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2458 IPersistIDList_Release(persistidl);
2460 IShellItem_Release(shellitem);
2464 win_skip("No SHCreateItemFromIDList\n");
2466 DeleteFileA(".\\testfile");
2467 pILFree(pidl_abstestfile);
2468 pILFree(pidl_testfile);
2469 pILFree(pidl_desktop);
2471 IShellFolder_Release(currentfolder);
2472 IShellFolder_Release(desktopfolder);
2475 static void test_SHGetNameFromIDList(void)
2477 IShellItem *shellitem;
2482 static const DWORD flags[] = {
2483 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2484 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2485 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2486 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2488 if(!pSHGetNameFromIDList)
2490 win_skip("SHGetNameFromIDList missing.\n");
2494 /* These should be available on any platform that passed the above test. */
2495 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2496 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2497 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2498 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2502 /* Crashes under win7 */
2503 pSHGetNameFromIDList(NULL, 0, NULL);
2506 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2507 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2509 /* Test the desktop */
2510 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2511 ok(hres == S_OK, "Got 0x%08x\n", hres);
2512 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2513 ok(hres == S_OK, "Got 0x%08x\n", hres);
2516 WCHAR *nameSI, *nameSH;
2517 WCHAR buf[MAX_PATH];
2518 HRESULT hrSI, hrSH, hrSF;
2523 SHGetDesktopFolder(&psf);
2524 for(i = 0; flags[i] != -1234; i++)
2526 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2527 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2528 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2529 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2530 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2531 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2533 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2534 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2538 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2540 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2542 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2544 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2545 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2547 IShellFolder_Release(psf);
2549 if(pSHGetPathFromIDListW){
2550 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2551 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2552 res = pSHGetPathFromIDListW(pidl, buf);
2553 ok(res == TRUE, "Got %d\n", res);
2554 if(SUCCEEDED(hrSI) && res)
2555 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2556 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2558 win_skip("pSHGetPathFromIDListW not available\n");
2560 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2561 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2562 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2564 IShellItem_Release(shellitem);
2568 /* Test the control panel */
2569 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2570 ok(hres == S_OK, "Got 0x%08x\n", hres);
2571 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2572 ok(hres == S_OK, "Got 0x%08x\n", hres);
2575 WCHAR *nameSI, *nameSH;
2576 WCHAR buf[MAX_PATH];
2577 HRESULT hrSI, hrSH, hrSF;
2582 SHGetDesktopFolder(&psf);
2583 for(i = 0; flags[i] != -1234; i++)
2585 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2586 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2587 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2588 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2589 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2590 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2592 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2593 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2597 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2599 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2601 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2603 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2604 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2606 IShellFolder_Release(psf);
2608 if(pSHGetPathFromIDListW){
2609 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2610 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2611 res = pSHGetPathFromIDListW(pidl, buf);
2612 ok(res == FALSE, "Got %d\n", res);
2613 if(SUCCEEDED(hrSI) && res)
2614 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2615 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2617 win_skip("pSHGetPathFromIDListW not available\n");
2619 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2620 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2621 "Got 0x%08x\n", hres);
2622 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2624 IShellItem_Release(shellitem);
2629 static void test_SHGetItemFromDataObject(void)
2631 IShellFolder *psfdesktop;
2636 if(!pSHGetItemFromDataObject)
2638 win_skip("No SHGetItemFromDataObject.\n");
2644 /* Crashes under win7 */
2645 pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2648 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2649 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2651 SHGetDesktopFolder(&psfdesktop);
2653 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2654 ok(hres == S_OK, "got 0x%08x\n", hres);
2661 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2662 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2663 ok(hres == S_OK, "got 0x%08x\n", hres);
2666 LPITEMIDLIST apidl[5];
2669 for(count = 0; count < 5; count++)
2670 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2675 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2676 &IID_IDataObject, NULL, (void**)&pdo);
2677 ok(hres == S_OK, "got 0x%08x\n", hres);
2680 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2681 ok(hres == S_OK, "got 0x%08x\n", hres);
2682 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2683 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2684 ok(hres == S_OK, "got 0x%08x\n", hres);
2685 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2686 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2687 ok(hres == S_OK, "got 0x%08x\n", hres);
2688 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2689 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2690 ok(hres == S_OK, "got 0x%08x\n", hres);
2691 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2692 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2693 ok(hres == S_OK, "got 0x%08x\n", hres);
2694 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2696 IDataObject_Release(pdo);
2700 skip("No file(s) found - skipping single-file test.\n");
2704 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2705 &IID_IDataObject, NULL, (void**)&pdo);
2706 ok(hres == S_OK, "got 0x%08x\n", hres);
2709 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2710 ok(hres == S_OK, "got 0x%08x\n", hres);
2711 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2712 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2713 ok(hres == S_OK, "got 0x%08x\n", hres);
2714 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2715 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2716 ok(hres == S_OK, "got 0x%08x\n", hres);
2717 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2718 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2719 ok(hres == S_OK, "got 0x%08x\n", hres);
2720 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2721 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2722 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2723 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2724 IDataObject_Release(pdo);
2728 skip("zero or one file found - skipping multi-file test.\n");
2730 for(i = 0; i < count; i++)
2733 IEnumIDList_Release(peidl);
2736 IShellView_Release(psv);
2739 IShellFolder_Release(psfdesktop);
2742 static void test_ShellItemCompare(void)
2744 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2745 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2746 IShellFolder *psf_desktop, *psf_current;
2747 LPITEMIDLIST pidl_cwd;
2748 WCHAR curdirW[MAX_PATH];
2751 static const WCHAR filesW[][9] = {
2752 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2753 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2754 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2758 if(!pSHCreateShellItem)
2760 win_skip("SHCreateShellItem missing.\n");
2764 GetCurrentDirectoryW(MAX_PATH, curdirW);
2765 if(!lstrlenW(curdirW))
2767 skip("Failed to get current directory, skipping.\n");
2771 CreateDirectoryA(".\\a", NULL);
2772 CreateDirectoryA(".\\b", NULL);
2773 CreateDirectoryA(".\\c", NULL);
2774 CreateTestFile(".\\a\\a");
2775 CreateTestFile(".\\a\\b");
2776 CreateTestFile(".\\a\\c");
2777 CreateTestFile(".\\b\\a");
2778 CreateTestFile(".\\b\\b");
2779 CreateTestFile(".\\b\\c");
2780 CreateTestFile(".\\c\\a");
2781 CreateTestFile(".\\c\\b");
2782 CreateTestFile(".\\c\\c");
2784 SHGetDesktopFolder(&psf_desktop);
2785 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2786 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2787 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2788 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2789 IShellFolder_Release(psf_desktop);
2792 /* Generate ShellItems for the files */
2793 memset(&psi, 0, sizeof(psi));
2795 for(i = 0; i < 9; i++)
2797 LPITEMIDLIST pidl_testfile = NULL;
2799 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2800 NULL, &pidl_testfile, NULL);
2801 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2804 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2805 ok(hr == S_OK, "Got 0x%08x\n", hr);
2806 pILFree(pidl_testfile);
2808 if(FAILED(hr)) failed = TRUE;
2812 skip("Failed to create all shellitems.\n");
2816 /* Generate ShellItems for the folders */
2817 hr = IShellItem_GetParent(psi[0], &psi_a);
2818 ok(hr == S_OK, "Got 0x%08x\n", hr);
2819 if(FAILED(hr)) failed = TRUE;
2820 hr = IShellItem_GetParent(psi[3], &psi_b);
2821 ok(hr == S_OK, "Got 0x%08x\n", hr);
2822 if(FAILED(hr)) failed = TRUE;
2823 hr = IShellItem_GetParent(psi[6], &psi_c);
2824 ok(hr == S_OK, "Got 0x%08x\n", hr);
2825 if(FAILED(hr)) failed = TRUE;
2829 skip("Failed to create shellitems.\n");
2835 /* Crashes on native (win7, winxp) */
2836 IShellItem_Compare(psi_a, NULL, 0, NULL);
2837 IShellItem_Compare(psi_a, psi_b, 0, NULL);
2838 IShellItem_Compare(psi_a, NULL, 0, &order);
2842 for(i = 0; i < 9; i++)
2844 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2845 ok(hr == S_OK, "Got 0x%08x\n", hr);
2846 ok(order == 0, "Got order %d\n", order);
2847 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2848 ok(hr == S_OK, "Got 0x%08x\n", hr);
2849 ok(order == 0, "Got order %d\n", order);
2850 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2851 ok(hr == S_OK, "Got 0x%08x\n", hr);
2852 ok(order == 0, "Got order %d\n", order);
2856 /* a\b:a\a , a\b:a\c, a\b:a\b */
2857 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2858 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2859 ok(order == 1, "Got order %d\n", order);
2860 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2861 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2862 ok(order == -1, "Got order %d\n", order);
2863 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2864 ok(hr == S_OK, "Got 0x%08x\n", hr);
2865 ok(order == 0, "Got order %d\n", order);
2867 /* b\b:a\b, b\b:c\b, b\b:c\b */
2868 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2869 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2870 ok(order == 1, "Got order %d\n", order);
2871 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2872 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2873 ok(order == -1, "Got order %d\n", order);
2874 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2875 ok(hr == S_OK, "Got 0x%08x\n", hr);
2876 ok(order == 0, "Got order %d\n", order);
2878 /* b:a\a, b:a\c, b:a\b */
2879 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2880 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2881 todo_wine ok(order == 1, "Got order %d\n", order);
2882 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2883 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2884 todo_wine ok(order == 1, "Got order %d\n", order);
2885 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2886 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2887 todo_wine ok(order == 1, "Got order %d\n", order);
2889 /* b:c\a, b:c\c, b:c\b */
2890 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2891 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2892 ok(order == -1, "Got order %d\n", order);
2893 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2894 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2895 ok(order == -1, "Got order %d\n", order);
2896 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2897 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2898 ok(order == -1, "Got order %d\n", order);
2900 /* a\b:a\a , a\b:a\c, a\b:a\b */
2901 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2902 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2903 ok(order == 1, "Got order %d\n", order);
2904 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2905 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2906 ok(order == -1, "Got order %d\n", order);
2907 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2908 ok(hr == S_OK, "Got 0x%08x\n", hr);
2909 ok(order == 0, "Got order %d\n", order);
2911 /* b\b:a\b, b\b:c\b, b\b:c\b */
2912 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2913 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2914 ok(order == 1, "Got order %d\n", order);
2915 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2916 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2917 ok(order == -1, "Got order %d\n", order);
2918 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2919 ok(hr == S_OK, "Got 0x%08x\n", hr);
2920 ok(order == 0, "Got order %d\n", order);
2922 /* b:a\a, b:a\c, b:a\b */
2923 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2924 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2925 todo_wine ok(order == 1, "Got order %d\n", order);
2926 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2927 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2928 todo_wine ok(order == 1, "Got order %d\n", order);
2929 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2930 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2931 todo_wine ok(order == 1, "Got order %d\n", order);
2933 /* b:c\a, b:c\c, b:c\b */
2934 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2935 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2936 ok(order == -1, "Got order %d\n", order);
2937 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2938 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2939 ok(order == -1, "Got order %d\n", order);
2940 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2941 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2942 ok(order == -1, "Got order %d\n", order);
2945 IShellFolder_Release(psf_current);
2947 DeleteFileA(".\\a\\a");
2948 DeleteFileA(".\\a\\b");
2949 DeleteFileA(".\\a\\c");
2950 DeleteFileA(".\\b\\a");
2951 DeleteFileA(".\\b\\b");
2952 DeleteFileA(".\\b\\c");
2953 DeleteFileA(".\\c\\a");
2954 DeleteFileA(".\\c\\b");
2955 DeleteFileA(".\\c\\c");
2956 RemoveDirectoryA(".\\a");
2957 RemoveDirectoryA(".\\b");
2958 RemoveDirectoryA(".\\c");
2960 if(psi_a) IShellItem_Release(psi_a);
2961 if(psi_b) IShellItem_Release(psi_b);
2962 if(psi_c) IShellItem_Release(psi_c);
2964 for(i = 0; i < 9; i++)
2965 if(psi[i]) IShellItem_Release(psi[i]);
2968 /**************************************************************/
2969 /* IUnknown implementation for counting QueryInterface calls. */
2971 IUnknown IUnknown_iface;
2979 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
2981 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
2984 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2986 IUnknownImpl *This = impl_from_IUnknown(iunk);
2988 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2990 if(IsEqualIID(This->ifaces[i].id, riid))
2992 This->ifaces[i].count++;
2999 return E_NOINTERFACE;
3002 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
3007 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3012 static const IUnknownVtbl vt_IUnknown = {
3013 unk_fnQueryInterface,
3018 static void test_SHGetIDListFromObject(void)
3020 IUnknownImpl *punkimpl;
3021 IShellFolder *psfdesktop;
3023 LPITEMIDLIST pidl, pidl_desktop;
3026 struct if_count ifaces[] =
3027 { {&IID_IPersistIDList, 0},
3028 {&IID_IPersistFolder2, 0},
3029 {&IID_IDataObject, 0},
3030 {&IID_IParentAndItem, 0},
3031 {&IID_IFolderView, 0},
3034 if(!pSHGetIDListFromObject)
3036 win_skip("SHGetIDListFromObject missing.\n");
3040 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3044 /* Crashes native */
3045 pSHGetIDListFromObject(NULL, NULL);
3046 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3049 hres = pSHGetIDListFromObject(NULL, &pidl);
3050 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3052 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3053 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3054 punkimpl->ifaces = ifaces;
3055 punkimpl->unknown = 0;
3057 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3058 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3059 ok(ifaces[0].count, "interface not requested.\n");
3060 ok(ifaces[1].count, "interface not requested.\n");
3061 ok(ifaces[2].count, "interface not requested.\n");
3063 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3064 "interface not requested.\n");
3065 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3066 "interface not requested.\n");
3068 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3069 HeapFree(GetProcessHeap(), 0, punkimpl);
3071 pidl_desktop = NULL;
3072 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3073 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3075 SHGetDesktopFolder(&psfdesktop);
3077 /* Test IShellItem */
3078 if(pSHCreateShellItem)
3080 IShellItem *shellitem;
3081 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3082 ok(hres == S_OK, "got 0x%08x\n", hres);
3085 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3086 ok(hres == S_OK, "got 0x%08x\n", hres);
3089 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3092 IShellItem_Release(shellitem);
3096 skip("no SHCreateShellItem.\n");
3098 /* Test IShellFolder */
3099 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3100 ok(hres == S_OK, "got 0x%08x\n", hres);
3103 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3107 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3108 ok(hres == S_OK, "got 0x%08x\n", hres);
3115 /* Test IFolderView */
3116 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3117 ok(hres == S_OK, "got 0x%08x\n", hres);
3120 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3124 /* Test IDataObject */
3125 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3126 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3127 ok(hres == S_OK, "got 0x%08x\n", hres);
3130 LPITEMIDLIST apidl[5];
3132 for(count = 0; count < 5; count++)
3133 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3138 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3139 &IID_IDataObject, NULL, (void**)&pdo);
3140 ok(hres == S_OK, "got 0x%08x\n", hres);
3143 pidl = (void*)0xDEADBEEF;
3144 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3145 ok(hres == S_OK, "got 0x%08x\n", hres);
3146 ok(pidl != NULL, "pidl is NULL.\n");
3147 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3150 IDataObject_Release(pdo);
3154 skip("No files found - skipping single-file test.\n");
3158 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3159 &IID_IDataObject, NULL, (void**)&pdo);
3160 ok(hres == S_OK, "got 0x%08x\n", hres);
3163 pidl = (void*)0xDEADBEEF;
3164 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3165 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3166 "got 0x%08x\n", hres);
3167 ok(pidl == NULL, "pidl is not NULL.\n");
3169 IDataObject_Release(pdo);
3173 skip("zero or one file found - skipping multi-file test.\n");
3175 for(i = 0; i < count; i++)
3178 IEnumIDList_Release(peidl);
3181 IShellView_Release(psv);
3184 IShellFolder_Release(psfdesktop);
3185 pILFree(pidl_desktop);
3188 static void test_SHGetItemFromObject(void)
3190 IUnknownImpl *punkimpl;
3191 IShellFolder *psfdesktop;
3196 struct if_count ifaces[] =
3197 { {&IID_IPersistIDList, 0},
3198 {&IID_IPersistFolder2, 0},
3199 {&IID_IDataObject, 0},
3200 {&IID_IParentAndItem, 0},
3201 {&IID_IFolderView, 0},
3204 if(!pSHGetItemFromObject)
3206 skip("No SHGetItemFromObject.\n");
3210 SHGetDesktopFolder(&psfdesktop);
3214 /* Crashes with Windows 7 */
3215 pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3216 pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3217 pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3220 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3221 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3223 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3224 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3225 punkimpl->ifaces = ifaces;
3226 punkimpl->unknown = 0;
3228 /* The same as SHGetIDListFromObject */
3229 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3230 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3231 ok(ifaces[0].count, "interface not requested.\n");
3232 ok(ifaces[1].count, "interface not requested.\n");
3233 ok(ifaces[2].count, "interface not requested.\n");
3235 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3236 "interface not requested.\n");
3237 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3238 "interface not requested.\n");
3240 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3241 HeapFree(GetProcessHeap(), 0, punkimpl);
3243 /* Test IShellItem */
3244 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3245 ok(hres == S_OK, "Got 0x%08x\n", hres);
3249 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3250 ok(hres == S_OK, "Got 0x%08x\n", hres);
3254 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3255 IShellItem_Release(psi2);
3257 IShellItem_Release(psi);
3260 IShellFolder_Release(psfdesktop);
3263 static void test_SHCreateShellItemArray(void)
3265 IShellFolder *pdesktopsf, *psf;
3266 IShellItemArray *psia;
3269 WCHAR cTestDirW[MAX_PATH];
3270 LPITEMIDLIST pidl_testdir, pidl;
3271 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3273 if(!pSHCreateShellItemArray) {
3274 skip("No pSHCreateShellItemArray!\n");
3278 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3282 /* Crashes under native */
3283 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3284 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3285 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3286 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3289 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3290 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3292 SHGetDesktopFolder(&pdesktopsf);
3293 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3294 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3296 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3297 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3299 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3300 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3301 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3304 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3305 myPathAddBackslashW(cTestDirW);
3306 lstrcatW(cTestDirW, testdirW);
3308 CreateFilesFolders();
3310 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3311 ok(hr == S_OK, "got 0x%08x\n", hr);
3314 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3316 ok(hr == S_OK, "Got 0x%08x\n", hr);
3318 IShellFolder_Release(pdesktopsf);
3322 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3323 pILFree(pidl_testdir);
3328 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3329 ok(hr == S_OK, "Got %08x\n", hr);
3332 LPITEMIDLIST apidl[5];
3333 UINT done, numitems, i;
3335 for(done = 0; done < 5; done++)
3336 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3338 ok(done == 5, "Got %d pidls\n", done);
3339 IEnumIDList_Release(peidl);
3341 /* Create a ShellItemArray */
3342 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3343 ok(hr == S_OK, "Got 0x%08x\n", hr);
3350 /* Crashes in Windows 7 */
3351 IShellItemArray_GetCount(psia, NULL);
3354 IShellItemArray_GetCount(psia, &numitems);
3355 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3357 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3358 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3360 /* Compare all the items */
3361 for(i = 0; i < numitems; i++)
3363 LPITEMIDLIST pidl_abs;
3364 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3366 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3367 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3370 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3371 ok(hr == S_OK, "Got 0x%08x\n", hr);
3374 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3377 IShellItem_Release(psi);
3381 for(i = 0; i < done; i++)
3383 IShellItemArray_Release(psia);
3387 /* SHCreateShellItemArrayFromShellItem */
3388 if(pSHCreateShellItemArrayFromShellItem)
3394 /* Crashes under Windows 7 */
3395 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3396 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3397 pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3400 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3401 ok(hr == S_OK, "Got 0x%08x\n", hr);
3404 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3405 ok(hr == S_OK, "Got 0x%08x\n", hr);
3410 hr = IShellItemArray_GetCount(psia, &count);
3411 ok(hr == S_OK, "Got 0x%08x\n", hr);
3412 ok(count == 1, "Got count %d\n", count);
3413 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3414 ok(hr == S_OK, "Got 0x%08x\n", hr);
3416 ok(psi != psi2, "ShellItems are of the same instance.\n");
3419 LPITEMIDLIST pidl1, pidl2;
3420 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3421 ok(hr == S_OK, "Got 0x%08x\n", hr);
3422 ok(pidl1 != NULL, "pidl1 was null.\n");
3423 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3424 ok(hr == S_OK, "Got 0x%08x\n", hr);
3425 ok(pidl2 != NULL, "pidl2 was null.\n");
3426 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3429 IShellItem_Release(psi2);
3431 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3432 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3433 IShellItemArray_Release(psia);
3435 IShellItem_Release(psi);
3439 skip("No SHCreateShellItemArrayFromShellItem.\n");
3441 if(pSHCreateShellItemArrayFromDataObject)
3447 /* Crashes under Windows 7 */
3448 pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3450 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3451 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3453 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3454 ok(hr == S_OK, "got 0x%08x\n", hr);
3461 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3462 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3463 ok(hr == S_OK, "got 0x%08x\n", hr);
3466 LPITEMIDLIST apidl[5];
3469 for(count = 0; count < 5; count++)
3470 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3472 ok(count == 5, "Got %d\n", count);
3476 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3477 &IID_IDataObject, NULL, (void**)&pdo);
3478 ok(hr == S_OK, "Got 0x%08x\n", hr);
3481 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3483 ok(hr == S_OK, "Got 0x%08x\n", hr);
3487 hr = IShellItemArray_GetCount(psia, &count_sia);
3488 ok(hr == S_OK, "Got 0x%08x\n", hr);
3489 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3490 for(i = 0; i < count_sia; i++)
3492 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3494 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3495 ok(hr == S_OK, "Got 0x%08x\n", hr);
3499 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3500 ok(hr == S_OK, "Got 0x%08x\n", hr);
3501 ok(pidl != NULL, "pidl as NULL.\n");
3502 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3504 IShellItem_Release(psi);
3509 IShellItemArray_Release(psia);
3512 IDataObject_Release(pdo);
3514 for(i = 0; i < count; i++)
3518 skip("No files found - skipping test.\n");
3520 IEnumIDList_Release(peidl);
3522 IShellView_Release(psv);
3526 skip("No SHCreateShellItemArrayFromDataObject.\n");
3528 IShellFolder_Release(psf);
3529 pILFree(pidl_testdir);
3533 static void test_ShellItemBindToHandler(void)
3536 LPITEMIDLIST pidl_desktop;
3539 if(!pSHCreateShellItem)
3541 skip("SHCreateShellItem missing.\n");
3545 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3546 ok(hr == S_OK, "Got 0x%08x\n", hr);
3549 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3550 ok(hr == S_OK, "Got 0x%08x\n", hr);
3554 IPersistFolder2 *ppf2;
3559 /* Crashes under Windows 7 */
3560 IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3561 IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3563 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3564 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3567 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3568 ok(hr == S_OK, "Got 0x%08x\n", hr);
3569 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3570 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3571 ok(hr == S_OK, "Got 0x%08x\n", hr);
3574 LPITEMIDLIST pidl_tmp;
3575 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3576 ok(hr == S_OK, "Got 0x%08x\n", hr);
3579 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3582 IPersistFolder2_Release(ppf2);
3585 /* BHID_SFUIObject */
3586 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3587 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3588 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3589 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3590 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3591 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3593 /* BHID_DataObject */
3594 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3595 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3596 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3600 /* BHID_SFViewObject */
3601 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3602 ok(hr == S_OK, "Got 0x%08x\n", hr);
3603 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3604 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3605 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3606 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3609 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3610 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3611 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3612 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3613 ok(hr == S_OK, "Got 0x%08x\n", hr);
3614 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3617 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3618 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3619 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3620 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3621 ok(hr == S_OK, "Got 0x%08x\n", hr);
3622 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3624 /* BHID_StorageEnum */
3625 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3626 ok(hr == S_OK, "Got 0x%08x\n", hr);
3627 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3630 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3631 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3632 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3634 /* BHID_EnumItems */
3635 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3636 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3637 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3640 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3641 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3642 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3644 /* BHID_LinkTargetItem */
3645 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3646 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3647 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3648 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3649 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3650 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3652 /* BHID_PropertyStore */
3653 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3654 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3655 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3656 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3657 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3658 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3660 /* BHID_ThumbnailHandler */
3661 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3662 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3663 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3665 /* BHID_AssociationArray */
3666 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3667 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3668 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3670 /* BHID_EnumAssocHandlers */
3671 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3672 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3673 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3676 IShellItem_Release(psi);
3679 skip("Failed to create ShellItem.\n");
3681 pILFree(pidl_desktop);
3684 static void test_ShellItemGetAttributes(void)
3687 LPITEMIDLIST pidl_desktop;
3691 if(!pSHCreateShellItem)
3693 skip("SHCreateShellItem missing.\n");
3697 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3698 ok(hr == S_OK, "Got 0x%08x\n", hr);
3701 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3702 ok(hr == S_OK, "Got 0x%08x\n", hr);
3703 pILFree(pidl_desktop);
3707 skip("Skipping tests.\n");
3713 /* Crashes on native (Win 7) */
3714 IShellItem_GetAttributes(psi, 0, NULL);
3717 /* Test GetAttributes on the desktop folder. */
3719 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
3720 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
3721 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
3723 IShellItem_Release(psi);
3726 static void test_SHParseDisplayName(void)
3728 LPITEMIDLIST pidl1, pidl2;
3729 IShellFolder *desktop;
3730 WCHAR dirW[MAX_PATH];
3735 if (!pSHParseDisplayName)
3737 win_skip("SHParseDisplayName isn't available\n");
3743 /* crashes on native */
3744 pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3746 pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3749 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3750 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3751 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3752 hr == E_INVALIDARG, "failed %08x\n", hr);
3753 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3757 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3758 ok(hr == S_OK, "failed %08x\n", hr);
3759 hr = SHGetDesktopFolder(&desktop);
3760 ok(hr == S_OK, "failed %08x\n", hr);
3761 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3762 ok(hr == S_OK, "failed %08x\n", hr);
3763 ret = pILIsEqual(pidl1, pidl2);
3764 ok(ret == TRUE, "expected equal idls\n");
3769 GetWindowsDirectoryW( dirW, MAX_PATH );
3771 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3772 ok(hr == S_OK, "failed %08x\n", hr);
3773 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3774 ok(hr == S_OK, "failed %08x\n", hr);
3776 ret = pILIsEqual(pidl1, pidl2);
3777 ok(ret == TRUE, "expected equal idls\n");
3781 /* system32 is not redirected to syswow64 on WOW64 */
3782 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
3783 if (is_wow64 && pGetSystemWow64DirectoryW)
3786 ok(GetSystemDirectoryW(dirW, MAX_PATH) > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
3787 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3788 ok(hr == S_OK, "failed %08x\n", hr);
3790 ok(pGetSystemWow64DirectoryW(dirW, MAX_PATH) > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
3791 hr = pSHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
3792 ok(hr == S_OK, "failed %08x\n", hr);
3793 ret = pILIsEqual(pidl1, pidl2);
3794 ok(ret == FALSE, "expected different idls\n");
3799 IShellFolder_Release(desktop);
3802 static void test_desktop_IPersist(void)
3804 IShellFolder *desktop;
3806 IPersistFolder2 *ppf2;
3810 hr = SHGetDesktopFolder(&desktop);
3811 ok(hr == S_OK, "failed %08x\n", hr);
3813 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3814 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3820 /* crashes on native */
3821 IPersist_GetClassID(persist, NULL);
3823 memset(&clsid, 0, sizeof(clsid));
3824 hr = IPersist_GetClassID(persist, &clsid);
3825 ok(hr == S_OK, "failed %08x\n", hr);
3826 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3827 IPersist_Release(persist);
3830 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3831 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3834 IPersistFolder *ppf;
3836 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3837 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3839 IPersistFolder_Release(ppf);
3842 hr = IPersistFolder2_Initialize(ppf2, NULL);
3843 ok(hr == S_OK, "got %08x\n", hr);
3847 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3848 ok(hr == S_OK, "got %08x\n", hr);
3849 ok(pidl != NULL, "pidl was NULL.\n");
3850 if(SUCCEEDED(hr)) pILFree(pidl);
3852 IPersistFolder2_Release(ppf2);
3855 IShellFolder_Release(desktop);
3858 static void test_GetUIObject(void)
3860 IShellFolder *psf_desktop;
3864 WCHAR path[MAX_PATH];
3865 const WCHAR filename[] =
3866 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3868 if(!pSHBindToParent)
3870 win_skip("SHBindToParent missing.\n");
3874 GetCurrentDirectoryW(MAX_PATH, path);
3877 skip("GetCurrentDirectoryW returned an empty string.\n");
3880 lstrcatW(path, filename);
3881 SHGetDesktopFolder(&psf_desktop);
3883 CreateFilesFolders();
3885 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3886 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3890 LPCITEMIDLIST pidl_child;
3891 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3892 ok(hr == S_OK, "Got 0x%08x\n", hr);
3895 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3896 &IID_IContextMenu, NULL, (void**)&pcm);
3897 ok(hr == S_OK, "Got 0x%08x\n", hr);
3900 HMENU hmenu = CreatePopupMenu();
3901 INT max_id, max_id_check;
3903 const int id_upper_limit = 32767;
3904 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3905 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3906 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3907 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3908 count = GetMenuItemCount(hmenu);
3909 ok(count, "Got %d\n", count);
3912 for(i = 0; i < count; i++)
3916 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3917 mii.cbSize = sizeof(MENUITEMINFOA);
3918 mii.fMask = MIIM_ID | MIIM_FTYPE;
3921 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3922 ok(res, "Failed (last error: %d).\n", GetLastError());
3924 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3925 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3926 if(!(mii.fType & MFT_SEPARATOR))
3927 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3929 ok((max_id_check == max_id) ||
3930 (max_id_check == max_id-1 /* Win 7 */),
3931 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3933 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3935 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3937 CMINVOKECOMMANDINFO cmi;
3938 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3939 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3941 /* Attempt to execute a nonexistent command */
3942 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3943 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3944 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3946 cmi.lpVerb = "foobar_wine_test";
3947 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3948 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3949 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3950 "Got 0x%08x\n", hr);
3955 IContextMenu_Release(pcm);
3957 IShellFolder_Release(psf);
3959 if(pILFree) pILFree(pidl);
3962 IShellFolder_Release(psf_desktop);
3966 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3967 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3969 LPCITEMIDLIST child;
3970 IShellFolder *parent;
3974 if(!pSHBindToParent){
3975 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3977 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3979 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3985 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3989 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3990 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3994 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3995 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3997 IShellFolder_Release(parent);
4001 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
4002 "Got unexpected string type: %d\n", filename.uType);
4003 if(filename.uType == STRRET_WSTR){
4004 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
4005 "didn't get expected path (%s), instead: %s\n",
4006 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
4007 SHFree(U(filename).pOleStr);
4008 }else if(filename.uType == STRRET_CSTR){
4009 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
4010 "didn't get expected path (%s), instead: %s\n",
4011 wine_dbgstr_w(path), U(filename).cStr);
4014 IShellFolder_Release(parent);
4016 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4019 static void test_SHSimpleIDListFromPath(void)
4021 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4022 const CHAR adirA[] = "C:\\sidlfpdir";
4023 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4025 LPITEMIDLIST pidl = NULL;
4027 if(!pSHSimpleIDListFromPathAW){
4028 win_skip("SHSimpleIDListFromPathAW not available\n");
4032 br = CreateDirectoryA(adirA, NULL);
4033 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4036 pidl = pSHSimpleIDListFromPathAW(adirW);
4038 pidl = pSHSimpleIDListFromPathAW(adirA);
4039 verify_pidl(pidl, adirW);
4042 br = RemoveDirectoryA(adirA);
4043 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4046 pidl = pSHSimpleIDListFromPathAW(adirW);
4048 pidl = pSHSimpleIDListFromPathAW(adirA);
4049 verify_pidl(pidl, adirW);
4053 /* IFileSystemBindData impl */
4054 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4055 REFIID riid, void **ppv)
4057 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4058 IsEqualIID(riid, &IID_IUnknown)){
4062 return E_NOINTERFACE;
4065 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4070 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4075 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4076 const WIN32_FIND_DATAW *pfd)
4078 ok(0, "SetFindData called\n");
4082 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4083 WIN32_FIND_DATAW *pfd)
4085 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4089 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4090 WIN32_FIND_DATAW *pfd)
4092 memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4096 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4097 WIN32_FIND_DATAW *pfd)
4099 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4100 *pfd->cFileName = 'a';
4101 *pfd->cAlternateFileName = 'a';
4105 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4106 WIN32_FIND_DATAW *pfd)
4108 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4109 HANDLE handle = FindFirstFileW(adirW, pfd);
4114 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4115 WIN32_FIND_DATAW *pfd)
4120 static IFileSystemBindDataVtbl fsbdVtbl = {
4121 fsbd_QueryInterface,
4128 static IFileSystemBindData fsbd = { &fsbdVtbl };
4130 static void test_ParseDisplayNamePBC(void)
4132 WCHAR wFileSystemBindData[] =
4133 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4134 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4135 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4136 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4137 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4144 /* Check if we support WCHAR functions */
4145 SetLastError(0xdeadbeef);
4146 lstrcmpiW(adirW, adirW);
4147 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4148 win_skip("Most W-calls are not implemented\n");
4152 hres = SHGetDesktopFolder(&psf);
4153 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4155 win_skip("Failed to get IShellFolder, can't run tests\n");
4159 /* fails on unknown dir with no IBindCtx */
4160 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4161 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4162 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4163 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4164 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4165 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4166 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4167 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4168 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4170 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4171 hres = CreateBindCtx(0, &pbc);
4172 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4174 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4175 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4176 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4177 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4178 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4179 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4180 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4181 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4182 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4184 /* unknown dir with IBindCtx with IFileSystemBindData */
4185 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4186 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4188 /* return E_FAIL from GetFindData */
4189 pidl = (ITEMIDLIST*)0xdeadbeef;
4190 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4191 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4192 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4193 "ParseDisplayName failed: 0x%08x\n", hres);
4194 if(SUCCEEDED(hres)){
4195 verify_pidl(pidl, adirW);
4199 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4200 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4201 "ParseDisplayName failed: 0x%08x\n", hres);
4202 if(SUCCEEDED(hres)){
4203 verify_pidl(pidl, afileW);
4207 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4208 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4209 "ParseDisplayName failed: 0x%08x\n", hres);
4210 if(SUCCEEDED(hres)){
4211 verify_pidl(pidl, afile2W);
4215 /* set FIND_DATA struct to NULLs */
4216 pidl = (ITEMIDLIST*)0xdeadbeef;
4217 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4218 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4219 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4220 "ParseDisplayName failed: 0x%08x\n", hres);
4221 if(SUCCEEDED(hres)){
4222 verify_pidl(pidl, adirW);
4226 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4227 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4228 "ParseDisplayName failed: 0x%08x\n", hres);
4229 if(SUCCEEDED(hres)){
4230 verify_pidl(pidl, afileW);
4234 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4235 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4236 "ParseDisplayName failed: 0x%08x\n", hres);
4237 if(SUCCEEDED(hres)){
4238 verify_pidl(pidl, afile2W);
4242 /* set FIND_DATA struct to junk */
4243 pidl = (ITEMIDLIST*)0xdeadbeef;
4244 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4245 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4246 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4247 "ParseDisplayName failed: 0x%08x\n", hres);
4248 if(SUCCEEDED(hres)){
4249 verify_pidl(pidl, adirW);
4253 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4254 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4255 "ParseDisplayName failed: 0x%08x\n", hres);
4256 if(SUCCEEDED(hres)){
4257 verify_pidl(pidl, afileW);
4261 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4262 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4263 "ParseDisplayName failed: 0x%08x\n", hres);
4264 if(SUCCEEDED(hres)){
4265 verify_pidl(pidl, afile2W);
4269 /* set FIND_DATA struct to invalid data */
4270 pidl = (ITEMIDLIST*)0xdeadbeef;
4271 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4272 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4273 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4274 "ParseDisplayName failed: 0x%08x\n", hres);
4275 if(SUCCEEDED(hres)){
4276 verify_pidl(pidl, adirW);
4280 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4281 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4282 "ParseDisplayName failed: 0x%08x\n", hres);
4283 if(SUCCEEDED(hres)){
4284 verify_pidl(pidl, afileW);
4288 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4289 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4290 "ParseDisplayName failed: 0x%08x\n", hres);
4291 if(SUCCEEDED(hres)){
4292 verify_pidl(pidl, afile2W);
4296 /* set FIND_DATA struct to valid data */
4297 pidl = (ITEMIDLIST*)0xdeadbeef;
4298 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4299 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4300 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4301 "ParseDisplayName failed: 0x%08x\n", hres);
4302 if(SUCCEEDED(hres)){
4303 verify_pidl(pidl, adirW);
4307 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4308 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4309 "ParseDisplayName failed: 0x%08x\n", hres);
4310 if(SUCCEEDED(hres)){
4311 verify_pidl(pidl, afileW);
4315 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4316 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4317 "ParseDisplayName failed: 0x%08x\n", hres);
4318 if(SUCCEEDED(hres)){
4319 verify_pidl(pidl, afile2W);
4323 IBindCtx_Release(pbc);
4324 IShellFolder_Release(psf);
4327 static const CHAR testwindow_class[] = "testwindow";
4328 #define WM_USER_NOTIFY (WM_APP+1)
4330 struct ChNotifyTest {
4332 const UINT notify_count;
4333 UINT missing_events;
4335 const char path_1[256];
4336 const char path_2[256];
4337 } chnotify_tests[] = {
4338 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4339 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4340 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4343 struct ChNotifyTest *exp_data;
4345 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4347 UINT signal = (UINT)lparam;
4350 case WM_USER_NOTIFY:
4351 if(exp_data->missing_events > 0){
4352 WCHAR *path1, *path2;
4353 LPCITEMIDLIST *pidls = (LPCITEMIDLIST*)wparam;
4355 ok(exp_data->signal == signal,
4356 "%s: expected notification type %x, got: %x\n",
4357 exp_data->id, exp_data->signal, signal);
4359 trace("verifying pidls for: %s\n", exp_data->id);
4360 path1 = make_wstr(exp_data->path_1);
4361 path2 = make_wstr(exp_data->path_2);
4362 verify_pidl(pidls[0], path1);
4363 verify_pidl(pidls[1], path2);
4364 HeapFree(GetProcessHeap(), 0, path1);
4365 HeapFree(GetProcessHeap(), 0, path2);
4367 exp_data->missing_events--;
4369 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4372 return DefWindowProc(hwnd, msg, wparam, lparam);
4375 static void register_testwindow_class(void)
4380 ZeroMemory(&cls, sizeof(cls));
4381 cls.cbSize = sizeof(cls);
4383 cls.lpfnWndProc = testwindow_wndproc;
4384 cls.hInstance = GetModuleHandleA(NULL);
4385 cls.lpszClassName = testwindow_class;
4388 ret = RegisterClassExA(&cls);
4389 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4392 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4393 * have to poll repeatedly for the message to appear */
4394 static void do_events(void)
4397 while (exp_data->missing_events && (c++ < 10)){
4399 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4400 TranslateMessage(&msg);
4401 DispatchMessageA(&msg);
4403 if(exp_data->missing_events)
4406 trace("%s: took %d tries\n", exp_data->id, c);
4409 static void test_SHChangeNotify(void)
4414 BOOL br, has_unicode;
4415 SHChangeNotifyEntry entries[1];
4416 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4417 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4419 CreateDirectoryW(NULL, NULL);
4420 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4422 register_testwindow_class();
4424 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4425 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4426 NULL, NULL, GetModuleHandleA(NULL), 0);
4427 ok(wnd != NULL, "Failed to make a window\n");
4429 br = CreateDirectoryA(root_dirA, NULL);
4430 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4432 entries[0].pidl = NULL;
4434 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4436 hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4437 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4438 entries[0].fRecursive = TRUE;
4440 notifyID = SHChangeNotifyRegister(wnd, SHCNRF_ShellLevel,
4441 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4442 ok(notifyID != 0, "Failed to register a window for change notifications\n");
4444 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
4445 exp_data = chnotify_tests + i;
4447 exp_data->missing_events = exp_data->notify_count;
4448 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4449 strlen(exp_data->path_1) > 0 ? exp_data->path_1 : NULL,
4450 strlen(exp_data->path_2) > 0 ? exp_data->path_2 : NULL);
4452 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4455 WCHAR *path1, *path2;
4457 path1 = make_wstr(exp_data->path_1);
4458 path2 = make_wstr(exp_data->path_2);
4460 exp_data->missing_events = exp_data->notify_count;
4461 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
4463 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4465 HeapFree(GetProcessHeap(), 0, path1);
4466 HeapFree(GetProcessHeap(), 0, path2);
4470 SHChangeNotifyDeregister(notifyID);
4473 ILFree((LPITEMIDLIST)entries[0].pidl);
4474 br = RemoveDirectoryA(root_dirA);
4475 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4478 START_TEST(shlfolder)
4480 init_function_pointers();
4481 /* if OleInitialize doesn't get called, ParseDisplayName returns
4482 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4483 OleInitialize(NULL);
4485 test_ParseDisplayName();
4486 test_SHParseDisplayName();
4487 test_BindToObject();
4488 test_EnumObjects_and_CompareIDs();
4489 test_GetDisplayName();
4490 test_GetAttributesOf();
4491 test_SHGetPathFromIDList();
4492 test_CallForAttributes();
4493 test_FolderShortcut();
4494 test_ITEMIDLIST_format();
4495 test_SHGetFolderPathA();
4496 test_SHGetFolderPathAndSubDirA();
4497 test_LocalizedNames();
4498 test_SHCreateShellItem();
4499 test_SHCreateShellItemArray();
4500 test_desktop_IPersist();
4502 test_SHSimpleIDListFromPath();
4503 test_ParseDisplayNamePBC();
4504 test_SHGetNameFromIDList();
4505 test_SHGetItemFromDataObject();
4506 test_SHGetIDListFromObject();
4507 test_SHGetItemFromObject();
4508 test_ShellItemCompare();
4509 test_SHChangeNotify();
4510 test_ShellItemBindToHandler();
4511 test_ShellItemGetAttributes();