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);
74 static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
76 static WCHAR *make_wstr(const char *str)
81 if(!str || strlen(str) == 0)
84 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
88 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
92 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
96 static int strcmp_wa(LPCWSTR strw, const char *stra)
99 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
100 return lstrcmpA(stra, buf);
103 static void init_function_pointers(void)
109 hmod = GetModuleHandleA("shell32.dll");
111 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
112 MAKEFUNC(SHBindToParent);
113 MAKEFUNC(SHCreateItemFromIDList);
114 MAKEFUNC(SHCreateItemFromParsingName);
115 MAKEFUNC(SHCreateShellItem);
116 MAKEFUNC(SHCreateShellItemArray);
117 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
118 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
119 MAKEFUNC(SHGetFolderPathA);
120 MAKEFUNC(SHGetFolderPathAndSubDirA);
121 MAKEFUNC(SHGetPathFromIDListW);
122 MAKEFUNC(SHGetSpecialFolderPathA);
123 MAKEFUNC(SHGetSpecialFolderPathW);
124 MAKEFUNC(SHGetSpecialFolderLocation);
125 MAKEFUNC(SHParseDisplayName);
126 MAKEFUNC(SHGetNameFromIDList);
127 MAKEFUNC(SHGetItemFromDataObject);
128 MAKEFUNC(SHGetIDListFromObject);
129 MAKEFUNC(SHGetItemFromObject);
130 MAKEFUNC(SHCreateDefaultContextMenu);
133 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
134 MAKEFUNC_ORD(ILFindLastID, 16);
135 MAKEFUNC_ORD(ILIsEqual, 21);
136 MAKEFUNC_ORD(ILCombine, 25);
137 MAKEFUNC_ORD(ILFree, 155);
138 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
141 /* test named exports */
142 ptr = GetProcAddress(hmod, "ILFree");
143 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
146 #define TESTNAMED(f) \
147 ptr = (void*)GetProcAddress(hmod, #f); \
148 ok(ptr != 0, "expected named export for " #f "\n");
150 TESTNAMED(ILAppendID);
152 TESTNAMED(ILCloneFirst);
153 TESTNAMED(ILCombine);
154 TESTNAMED(ILCreateFromPath);
155 TESTNAMED(ILCreateFromPathA);
156 TESTNAMED(ILCreateFromPathW);
157 TESTNAMED(ILFindChild);
158 TESTNAMED(ILFindLastID);
159 TESTNAMED(ILGetNext);
160 TESTNAMED(ILGetSize);
161 TESTNAMED(ILIsEqual);
162 TESTNAMED(ILIsParent);
163 TESTNAMED(ILRemoveLastID);
164 TESTNAMED(ILSaveToStream);
168 hmod = GetModuleHandleA("shlwapi.dll");
169 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
171 hmod = GetModuleHandleA("kernel32.dll");
172 pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
173 pGetSystemWow64DirectoryW = (void*)GetProcAddress(hmod, "GetSystemWow64DirectoryW");
175 hr = SHGetMalloc(&ppM);
176 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
179 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
180 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
184 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
190 if (lpszPath[-1] != '\\')
199 static void test_ParseDisplayName(void)
202 IShellFolder *IDesktopFolder;
203 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
204 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
205 static const char *cInetTestA = "http:\\yyy";
206 static const char *cInetTest2A = "xx:yyy";
208 WCHAR cTestDirW [MAX_PATH] = {0};
212 hr = SHGetDesktopFolder(&IDesktopFolder);
213 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
214 if(hr != S_OK) return;
216 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
217 if (pSHCreateShellItem)
219 /* null name and pidl */
220 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
221 NULL, NULL, NULL, NULL, NULL, 0);
222 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
225 newPIDL = (ITEMIDLIST*)0xdeadbeef;
226 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
227 NULL, NULL, NULL, NULL, &newPIDL, 0);
228 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
229 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
232 win_skip("Tests would crash on W2K and below\n");
234 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
235 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
236 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
237 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
238 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
241 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
242 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
243 IMalloc_Free(ppM, newPIDL);
246 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
247 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
248 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
249 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
250 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
253 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
254 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
255 IMalloc_Free(ppM, newPIDL);
258 res = GetFileAttributesA(cNonExistDir1A);
259 if(res != INVALID_FILE_ATTRIBUTES)
261 skip("Test directory unexpectedly exists\n");
265 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
266 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
267 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
268 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
269 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
271 res = GetFileAttributesA(cNonExistDir2A);
272 if(res != INVALID_FILE_ATTRIBUTES)
274 skip("Test directory unexpectedly exists\n");
278 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
279 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
280 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
281 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
282 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
284 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
285 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
286 * out it doesn't. The magic seems to happen in the file dialogs, then. */
287 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
289 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
293 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
294 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
295 if (!bRes) goto finished;
297 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
298 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
299 if (hr != S_OK) goto finished;
301 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
302 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
303 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
304 pILFindLastID(newPIDL)->mkid.abID[0]);
305 IMalloc_Free(ppM, newPIDL);
308 IShellFolder_Release(IDesktopFolder);
311 /* creates a file with the specified name for tests */
312 static void CreateTestFile(const CHAR *name)
317 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
318 if (file != INVALID_HANDLE_VALUE)
320 WriteFile(file, name, strlen(name), &written, NULL);
321 WriteFile(file, "\n", strlen("\n"), &written, NULL);
327 /* initializes the tests */
328 static void CreateFilesFolders(void)
330 CreateDirectoryA(".\\testdir", NULL);
331 CreateDirectoryA(".\\testdir\\test.txt", NULL);
332 CreateTestFile (".\\testdir\\test1.txt ");
333 CreateTestFile (".\\testdir\\test2.txt ");
334 CreateTestFile (".\\testdir\\test3.txt ");
335 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
336 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
339 /* cleans after tests */
340 static void Cleanup(void)
342 DeleteFileA(".\\testdir\\test1.txt");
343 DeleteFileA(".\\testdir\\test2.txt");
344 DeleteFileA(".\\testdir\\test3.txt");
345 RemoveDirectoryA(".\\testdir\\test.txt");
346 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
347 RemoveDirectoryA(".\\testdir\\testdir2");
348 RemoveDirectoryA(".\\testdir");
353 static void test_EnumObjects(IShellFolder *iFolder)
355 IEnumIDList *iEnumList;
356 LPITEMIDLIST newPIDL, idlArr[10];
361 static const WORD iResults [5][5] =
370 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
371 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
372 static const ULONG attrs[5] =
374 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
375 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
376 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
377 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
378 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
381 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
382 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
384 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
385 * the filesystem shellfolders return S_OK even if less than 'celt' items are
386 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
387 * only ever returns a single entry per call. */
388 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
390 ok (i == 5, "i: %d\n", i);
392 hr = IEnumIDList_Release(iEnumList);
393 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
395 /* Sort them first in case of wrong order from system */
396 for (i=0;i<5;i++) for (j=0;j<5;j++)
397 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
400 idlArr[i] = idlArr[j];
404 for (i=0;i<5;i++) for (j=0;j<5;j++)
406 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
407 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
411 for (i = 0; i < 5; i++)
414 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
415 /* Native returns all flags no matter what we ask for */
416 flags = SFGAO_CANCOPY;
417 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
418 flags &= SFGAO_testfor;
419 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
420 ok(flags == (attrs[i]) ||
421 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
422 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
423 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
425 flags = SFGAO_testfor;
426 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
427 flags &= SFGAO_testfor;
428 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
429 ok(flags == attrs[i] ||
430 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
431 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
435 IMalloc_Free(ppM, idlArr[i]);
438 static void test_BindToObject(void)
442 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
443 SHITEMID emptyitem = { 0, { 0 } };
444 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
445 WCHAR wszSystemDir[MAX_PATH];
446 char szSystemDir[MAX_PATH];
448 WCHAR path[MAX_PATH];
449 CHAR pathA[MAX_PATH];
451 WCHAR wszMyComputer[] = {
452 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
453 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
454 static const CHAR filename_html[] = "winetest.html";
455 static const CHAR filename_txt[] = "winetest.txt";
456 static const CHAR filename_foo[] = "winetest.foo";
458 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
459 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
461 hr = SHGetDesktopFolder(&psfDesktop);
462 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
463 if (hr != S_OK) return;
465 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
466 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
468 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
469 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
471 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
472 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
474 IShellFolder_Release(psfDesktop);
478 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
479 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
480 IShellFolder_Release(psfDesktop);
481 IMalloc_Free(ppM, pidlMyComputer);
482 if (hr != S_OK) return;
484 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
485 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
489 /* this call segfaults on 98SE */
490 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
491 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
494 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
495 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
496 if (cChars == 0 || cChars >= MAX_PATH) {
497 IShellFolder_Release(psfMyComputer);
500 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
502 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
503 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
505 IShellFolder_Release(psfMyComputer);
509 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
510 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
511 IShellFolder_Release(psfMyComputer);
512 IMalloc_Free(ppM, pidlSystemDir);
513 if (hr != S_OK) return;
515 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
516 ok (hr == E_INVALIDARG,
517 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
521 /* this call segfaults on 98SE */
522 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
523 ok (hr == E_INVALIDARG,
524 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
527 IShellFolder_Release(psfSystemDir);
529 GetCurrentDirectoryA(MAX_PATH, buf);
532 skip("Failed to get current directory, skipping tests.\n");
536 SHGetDesktopFolder(&psfDesktop);
538 /* Attempt BindToObject on files. */
541 lstrcpyA(pathA, buf);
542 lstrcatA(pathA, "\\");
543 lstrcatA(pathA, filename_html);
544 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
545 if(hfile != INVALID_HANDLE_VALUE)
548 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
549 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
550 ok(hr == S_OK, "Got 0x%08x\n", hr);
553 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
555 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
560 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
562 broken(hr == E_NOINTERFACE), /* Win9x, NT4, W2K */
567 hr = IPersist_GetClassID(pp, &id);
568 ok(hr == S_OK, "Got 0x%08x\n", hr);
569 ok(IsEqualIID(&id, &CLSID_ShellDocObjView), "Unexpected classid\n");
570 IPersist_Release(pp);
573 IShellFolder_Release(psfChild);
580 win_skip("Failed to create .html testfile.\n");
583 lstrcpyA(pathA, buf);
584 lstrcatA(pathA, "\\");
585 lstrcatA(pathA, filename_txt);
586 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
587 if(hfile != INVALID_HANDLE_VALUE)
590 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
591 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
592 ok(hr == S_OK, "Got 0x%08x\n", hr);
595 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
596 ok(hr == E_FAIL || /* Vista+ */
597 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
598 broken(hr == S_OK), /* Win9x, NT4, W2K */
600 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
606 win_skip("Failed to create .txt testfile.\n");
609 lstrcpyA(pathA, buf);
610 lstrcatA(pathA, "\\");
611 lstrcatA(pathA, filename_foo);
612 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
613 if(hfile != INVALID_HANDLE_VALUE)
616 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
617 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
618 ok(hr == S_OK, "Got 0x%08x\n", hr);
621 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
622 ok(hr == E_FAIL || /* Vista+ */
623 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
624 broken(hr == S_OK), /* Win9x, NT4, W2K */
626 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
632 win_skip("Failed to create .foo testfile.\n");
634 /* And on the desktop */
635 if(pSHGetSpecialFolderPathA)
637 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
638 lstrcatA(pathA, "\\");
639 lstrcatA(pathA, filename_html);
640 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
641 if(hfile != INVALID_HANDLE_VALUE)
644 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
645 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
646 ok(hr == S_OK, "Got 0x%08x\n", hr);
649 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
651 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
653 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
656 if(!DeleteFileA(pathA))
657 trace("Failed to delete: %d\n", GetLastError());
661 win_skip("Failed to create .html testfile.\n");
663 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
664 lstrcatA(pathA, "\\");
665 lstrcatA(pathA, filename_foo);
666 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
667 if(hfile != INVALID_HANDLE_VALUE)
670 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
671 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
672 ok(hr == S_OK, "Got 0x%08x\n", hr);
675 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
676 ok(hr == E_FAIL || /* Vista+ */
677 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
678 broken(hr == S_OK), /* Win9x, NT4, W2K */
680 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
686 win_skip("Failed to create .foo testfile.\n");
689 IShellFolder_Release(psfDesktop);
692 static void test_GetDisplayName(void)
697 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
698 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
701 LPSHELLFOLDER psfDesktop, psfPersonal;
703 SHITEMID emptyitem = { 0, { 0 } };
704 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
705 LPCITEMIDLIST pidlLast;
706 static const CHAR szFileName[] = "winetest.foo";
707 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
708 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
710 /* I'm trying to figure if there is a functional difference between calling
711 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
712 * binding to the shellfolder. One thing I thought of was that perhaps
713 * SHGetPathFromIDListW would be able to get the path to a file, which does
714 * not exist anymore, while the other method wouldn't. It turns out there's
715 * no functional difference in this respect.
718 if(!pSHGetSpecialFolderPathA) {
719 win_skip("SHGetSpecialFolderPathA is not available\n");
723 /* First creating a directory in MyDocuments and a file in this directory. */
724 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
725 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
728 /* Use ANSI file functions so this works on Windows 9x */
729 lstrcatA(szTestDir, "\\winetest");
730 CreateDirectoryA(szTestDir, NULL);
731 attr=GetFileAttributesA(szTestDir);
732 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
734 ok(0, "unable to create the '%s' directory\n", szTestDir);
738 lstrcpyA(szTestFile, szTestDir);
739 lstrcatA(szTestFile, "\\");
740 lstrcatA(szTestFile, szFileName);
741 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
742 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
743 if (hTestFile == INVALID_HANDLE_VALUE) return;
744 CloseHandle(hTestFile);
746 /* Getting an itemidlist for the file. */
747 hr = SHGetDesktopFolder(&psfDesktop);
748 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
749 if (hr != S_OK) return;
751 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
753 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
754 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
756 IShellFolder_Release(psfDesktop);
760 pidlLast = pILFindLastID(pidlTestFile);
761 ok(pidlLast->mkid.cb >=76 ||
762 broken(pidlLast->mkid.cb == 28) || /* W2K */
763 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
764 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
765 if (pidlLast->mkid.cb >= 28) {
766 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
767 "Filename should be stored as ansi-string at this position!\n");
769 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
770 if (pidlLast->mkid.cb >= 76) {
771 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
772 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
773 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
774 "Filename should be stored as wchar-string at this position!\n");
777 /* It seems as if we cannot bind to regular files on windows, but only directories.
779 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
780 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
781 hr == E_NOTIMPL || /* Vista */
782 broken(hr == S_OK), /* Win9x, W2K */
785 IShellFolder_Release(psfFile);
788 if (!pSHBindToParent)
790 win_skip("SHBindToParent is missing\n");
791 DeleteFileA(szTestFile);
792 RemoveDirectoryA(szTestDir);
796 /* Some tests for IShellFolder::SetNameOf */
797 if (pSHGetFolderPathAndSubDirA)
799 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
800 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
802 /* It's ok to use this fixed path. Call will fail anyway. */
803 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
804 LPITEMIDLIST pidlNew;
806 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
807 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
808 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
811 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
812 "pidl returned from SetNameOf should be simple!\n");
814 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
815 * is implemented on top of SHFileOperation in WinXP. */
816 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
817 SHGDN_FORPARSING, NULL);
818 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
820 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
821 * SHGDN flags specify an absolute path. */
822 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
823 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
828 IShellFolder_Release(psfPersonal);
832 win_skip("Avoid needs of interaction on Win2k\n");
834 /* Deleting the file and the directory */
835 DeleteFileA(szTestFile);
836 RemoveDirectoryA(szTestDir);
838 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
839 if (pSHGetPathFromIDListW)
841 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
842 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
843 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
846 /* SHBindToParent fails, if called with a NULL PIDL. */
847 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
848 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
850 /* But it succeeds with an empty PIDL. */
851 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
852 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
853 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
855 IShellFolder_Release(psfPersonal);
857 /* Binding to the folder and querying the display name of the file also works. */
858 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
859 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
861 IShellFolder_Release(psfDesktop);
865 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
866 * pidlTestFile (In accordance with MSDN). */
867 ok (pILFindLastID(pidlTestFile) == pidlLast,
868 "SHBindToParent doesn't return the last id of the pidl param!\n");
870 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
871 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
873 IShellFolder_Release(psfDesktop);
874 IShellFolder_Release(psfPersonal);
880 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
881 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
882 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
885 ILFree(pidlTestFile);
886 IShellFolder_Release(psfDesktop);
887 IShellFolder_Release(psfPersonal);
890 static void test_CallForAttributes(void)
896 LPSHELLFOLDER psfDesktop;
897 LPITEMIDLIST pidlMyDocuments;
898 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
899 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
900 static const WCHAR wszCallForAttributes[] = {
901 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
902 static const WCHAR wszMyDocumentsKey[] = {
903 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
904 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
905 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
906 WCHAR wszMyDocuments[] = {
907 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
908 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
910 /* For the root of a namespace extension, the attributes are not queried by binding
911 * to the object and calling GetAttributesOf. Instead, the attributes are read from
912 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
914 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
915 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
916 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
917 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
919 hr = SHGetDesktopFolder(&psfDesktop);
920 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
921 if (hr != S_OK) return;
923 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
924 &pidlMyDocuments, NULL);
926 broken(hr == E_INVALIDARG), /* Win95, NT4 */
927 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
929 IShellFolder_Release(psfDesktop);
933 dwAttributes = 0xffffffff;
934 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
935 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
936 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
938 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
939 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
940 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
941 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
943 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
944 * key. So the test will return at this point, if run on wine.
946 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
947 ok (lResult == ERROR_SUCCESS ||
948 lResult == ERROR_ACCESS_DENIED,
949 "RegOpenKeyEx failed! result: %08x\n", lResult);
950 if (lResult != ERROR_SUCCESS) {
951 if (lResult == ERROR_ACCESS_DENIED)
952 skip("Not enough rights to open the registry key\n");
953 IMalloc_Free(ppM, pidlMyDocuments);
954 IShellFolder_Release(psfDesktop);
958 /* Query MyDocuments' Attributes value, to be able to restore it later. */
959 dwSize = sizeof(DWORD);
960 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
961 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
962 if (lResult != ERROR_SUCCESS) {
964 IMalloc_Free(ppM, pidlMyDocuments);
965 IShellFolder_Release(psfDesktop);
969 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
970 dwSize = sizeof(DWORD);
971 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
972 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
973 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
974 if (lResult != ERROR_SUCCESS) {
976 IMalloc_Free(ppM, pidlMyDocuments);
977 IShellFolder_Release(psfDesktop);
981 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
982 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
983 * SFGAO_FILESYSTEM attributes. */
984 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
985 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
986 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
987 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
988 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
990 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
991 * GetAttributesOf. It seems that once there is a single attribute queried, for which
992 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
993 * the flags in Attributes are ignored.
995 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
996 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
997 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
998 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
1000 ok (dwAttributes == SFGAO_FILESYSTEM,
1001 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
1004 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
1005 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
1006 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1007 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
1009 IMalloc_Free(ppM, pidlMyDocuments);
1010 IShellFolder_Release(psfDesktop);
1013 static void test_GetAttributesOf(void)
1016 LPSHELLFOLDER psfDesktop, psfMyComputer;
1017 SHITEMID emptyitem = { 0, { 0 } };
1018 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1019 LPITEMIDLIST pidlMyComputer;
1021 static const DWORD desktopFlags[] = {
1023 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
1024 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1026 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
1027 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1028 /* WinMe, Win9x, WinNT*/
1029 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
1030 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1032 static const DWORD myComputerFlags[] = {
1034 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
1035 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1037 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
1038 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1039 /* WinMe, Win9x, WinNT */
1040 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1041 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1042 /* Win95, WinNT when queried directly */
1043 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1044 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1046 WCHAR wszMyComputer[] = {
1047 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1048 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1049 char cCurrDirA [MAX_PATH] = {0};
1050 WCHAR cCurrDirW [MAX_PATH];
1051 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
1052 IShellFolder *IDesktopFolder, *testIShellFolder;
1053 ITEMIDLIST *newPIDL;
1055 BOOL foundFlagsMatch;
1057 hr = SHGetDesktopFolder(&psfDesktop);
1058 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1059 if (hr != S_OK) return;
1061 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
1062 dwFlags = 0xffffffff;
1063 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
1064 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
1065 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1066 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1068 if (desktopFlags[i] == dwFlags)
1069 foundFlagsMatch = TRUE;
1071 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1073 /* .. or with no itemidlist at all. */
1074 dwFlags = 0xffffffff;
1075 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
1076 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1077 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1078 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1080 if (desktopFlags[i] == dwFlags)
1081 foundFlagsMatch = TRUE;
1083 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1085 /* Testing the attributes of the MyComputer shellfolder */
1086 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1087 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1089 IShellFolder_Release(psfDesktop);
1093 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
1094 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
1096 dwFlags = 0xffffffff;
1097 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
1098 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
1099 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1100 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1102 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
1103 foundFlagsMatch = TRUE;
1106 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1108 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
1109 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
1110 IShellFolder_Release(psfDesktop);
1111 IMalloc_Free(ppM, pidlMyComputer);
1112 if (hr != S_OK) return;
1114 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
1116 ok (hr == E_INVALIDARG ||
1117 broken(hr == S_OK), /* W2K and earlier */
1118 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
1120 dwFlags = 0xffffffff;
1121 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
1122 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1123 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1124 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1126 if (myComputerFlags[i] == dwFlags)
1127 foundFlagsMatch = TRUE;
1130 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1132 IShellFolder_Release(psfMyComputer);
1134 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1135 len = lstrlenA(cCurrDirA);
1138 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1141 if (len > 3 && cCurrDirA[len-1] == '\\')
1142 cCurrDirA[len-1] = 0;
1144 /* create test directory */
1145 CreateFilesFolders();
1147 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1149 hr = SHGetDesktopFolder(&IDesktopFolder);
1150 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1152 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1153 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1155 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1156 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1158 IMalloc_Free(ppM, newPIDL);
1160 /* get relative PIDL */
1161 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1162 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1164 /* test the shell attributes of the test directory using the relative PIDL */
1165 dwFlags = SFGAO_FOLDER;
1166 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1167 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1168 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1171 IMalloc_Free(ppM, newPIDL);
1173 /* append testdirectory name to path */
1174 if (cCurrDirA[len-1] == '\\')
1175 cCurrDirA[len-1] = 0;
1176 lstrcatA(cCurrDirA, "\\testdir");
1177 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1179 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1180 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1182 /* test the shell attributes of the test directory using the absolute PIDL */
1183 dwFlags = SFGAO_FOLDER;
1184 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1185 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1186 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1189 IMalloc_Free(ppM, newPIDL);
1191 IShellFolder_Release(testIShellFolder);
1195 IShellFolder_Release(IDesktopFolder);
1198 static void test_SHGetPathFromIDList(void)
1200 SHITEMID emptyitem = { 0, { 0 } };
1201 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1202 LPITEMIDLIST pidlMyComputer;
1203 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1206 LPSHELLFOLDER psfDesktop;
1207 WCHAR wszMyComputer[] = {
1208 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1209 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1210 WCHAR wszFileName[MAX_PATH];
1211 LPITEMIDLIST pidlTestFile;
1214 static WCHAR wszTestFile[] = {
1215 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1216 LPITEMIDLIST pidlPrograms;
1218 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1220 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1224 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1227 result = pSHGetPathFromIDListW(NULL, wszPath);
1228 ok(!result, "Expected failure\n");
1229 ok(!wszPath[0], "Expected empty string\n");
1231 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1232 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1233 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1234 if (!result) return;
1236 /* Check if we are on Win9x */
1237 SetLastError(0xdeadbeef);
1238 lstrcmpiW(wszDesktop, wszDesktop);
1239 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1241 win_skip("Most W-calls are not implemented\n");
1245 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1246 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1247 if (!result) return;
1248 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1250 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1251 hr = SHGetDesktopFolder(&psfDesktop);
1252 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1253 if (hr != S_OK) return;
1255 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1256 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1258 IShellFolder_Release(psfDesktop);
1262 SetLastError(0xdeadbeef);
1265 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1266 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1267 ok (GetLastError()==0xdeadbeef ||
1268 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1269 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1270 ok (!wszPath[0], "Expected empty path\n");
1272 IShellFolder_Release(psfDesktop);
1276 IMalloc_Free(ppM, pidlMyComputer);
1278 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1279 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1281 IShellFolder_Release(psfDesktop);
1284 myPathAddBackslashW(wszFileName);
1285 lstrcatW(wszFileName, wszTestFile);
1286 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1287 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1288 if (hTestFile == INVALID_HANDLE_VALUE) {
1289 IShellFolder_Release(psfDesktop);
1292 CloseHandle(hTestFile);
1294 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1295 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1297 IShellFolder_Release(psfDesktop);
1298 DeleteFileW(wszFileName);
1299 IMalloc_Free(ppM, pidlTestFile);
1303 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1304 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1305 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1306 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1307 IShellFolder_Release(psfDesktop);
1308 DeleteFileW(wszFileName);
1310 IMalloc_Free(ppM, pidlTestFile);
1315 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1316 ok(0 == lstrcmpW(wszFileName, wszPath),
1317 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1318 "returned incorrect path for file placed on desktop\n");
1321 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1322 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1323 IMalloc_Free(ppM, pidlTestFile);
1324 if (!result) return;
1325 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1328 /* Test if we can get the path from the start menu "program files" PIDL. */
1329 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1330 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1332 SetLastError(0xdeadbeef);
1333 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1334 IMalloc_Free(ppM, pidlPrograms);
1335 ok(result, "SHGetPathFromIDListW failed\n");
1338 static void test_EnumObjects_and_CompareIDs(void)
1340 ITEMIDLIST *newPIDL;
1341 IShellFolder *IDesktopFolder, *testIShellFolder;
1342 char cCurrDirA [MAX_PATH] = {0};
1343 static const CHAR cTestDirA[] = "\\testdir";
1344 WCHAR cTestDirW[MAX_PATH];
1348 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1349 len = lstrlenA(cCurrDirA);
1352 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1355 if(cCurrDirA[len-1] == '\\')
1356 cCurrDirA[len-1] = 0;
1358 lstrcatA(cCurrDirA, cTestDirA);
1359 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1361 hr = SHGetDesktopFolder(&IDesktopFolder);
1362 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1364 CreateFilesFolders();
1366 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1367 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1369 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1370 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1372 test_EnumObjects(testIShellFolder);
1374 IShellFolder_Release(testIShellFolder);
1378 IMalloc_Free(ppM, newPIDL);
1380 IShellFolder_Release(IDesktopFolder);
1383 /* A simple implementation of an IPropertyBag, which returns fixed values for
1384 * 'Target' and 'Attributes' properties.
1386 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1390 return E_INVALIDARG;
1392 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1395 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1396 return E_NOINTERFACE;
1399 IPropertyBag_AddRef(iface);
1403 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1407 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1411 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1412 VARIANT *pVar, IErrorLog *pErrorLog)
1414 static const WCHAR wszTargetSpecialFolder[] = {
1415 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1416 static const WCHAR wszTarget[] = {
1417 'T','a','r','g','e','t',0 };
1418 static const WCHAR wszAttributes[] = {
1419 'A','t','t','r','i','b','u','t','e','s',0 };
1420 static const WCHAR wszResolveLinkFlags[] = {
1421 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1422 static const WCHAR wszTargetKnownFolder[] = {
1423 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1424 static const WCHAR wszCLSID[] = {
1425 'C','L','S','I','D',0 };
1427 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1428 ok(V_VT(pVar) == VT_I4 ||
1429 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1430 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1431 return E_INVALIDARG;
1434 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1436 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1437 return E_INVALIDARG;
1440 if (!lstrcmpW(pszPropName, wszTarget)) {
1441 WCHAR wszPath[MAX_PATH];
1444 ok(V_VT(pVar) == VT_BSTR ||
1445 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1446 "Wrong variant type for 'Target' property!\n");
1447 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1449 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1450 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1451 if (!result) return E_INVALIDARG;
1453 V_BSTR(pVar) = SysAllocString(wszPath);
1457 if (!lstrcmpW(pszPropName, wszAttributes)) {
1458 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1459 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1460 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1461 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1465 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1466 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1468 return E_INVALIDARG;
1471 if (!lstrcmpW(pszPropName, wszCLSID)) {
1472 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1474 return E_INVALIDARG;
1477 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1478 return E_INVALIDARG;
1481 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1484 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1488 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1489 InitPropertyBag_IPropertyBag_QueryInterface,
1490 InitPropertyBag_IPropertyBag_AddRef,
1491 InitPropertyBag_IPropertyBag_Release,
1492 InitPropertyBag_IPropertyBag_Read,
1493 InitPropertyBag_IPropertyBag_Write
1496 static struct IPropertyBag InitPropertyBag = {
1497 &InitPropertyBag_IPropertyBagVtbl
1500 static void test_FolderShortcut(void) {
1501 IPersistPropertyBag *pPersistPropertyBag;
1502 IShellFolder *pShellFolder, *pDesktopFolder;
1503 IPersistFolder3 *pPersistFolder3;
1506 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1509 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1511 WCHAR wszWineTestFolder[] = {
1512 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1513 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1514 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1515 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1516 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1517 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1518 'N','a','m','e','S','p','a','c','e','\\',
1519 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1520 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1522 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1523 static const GUID CLSID_UnixDosFolder =
1524 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1526 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1527 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1531 if (!pSHGetFolderPathAndSubDirA)
1533 win_skip("FolderShortcut test doesn't work on Win2k\n");
1537 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1538 * via their IPersistPropertyBag interface. And that the target folder
1539 * is taken from the IPropertyBag's 'Target' property.
1541 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1542 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1543 if (hr == REGDB_E_CLASSNOTREG) {
1544 win_skip("CLSID_FolderShortcut is not implemented\n");
1547 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1548 if (hr != S_OK) return;
1550 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1551 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1553 IPersistPropertyBag_Release(pPersistPropertyBag);
1557 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1558 (LPVOID*)&pShellFolder);
1559 IPersistPropertyBag_Release(pPersistPropertyBag);
1560 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1561 if (hr != S_OK) return;
1563 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1564 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1566 IShellFolder_Release(pShellFolder);
1570 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1571 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1572 if (!result) return;
1574 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1575 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1577 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1578 IShellFolder_Release(pShellFolder);
1579 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1580 if (hr != S_OK) return;
1582 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1583 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1584 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1586 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1587 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1588 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1590 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1591 * shell namespace. The target folder, read from the property bag above, remains untouched.
1592 * The following tests show this: The itemidlist for some imaginary shellfolder object
1593 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1594 * itemidlist, but GetDisplayNameOf still returns the path from above.
1596 hr = SHGetDesktopFolder(&pDesktopFolder);
1597 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1598 if (hr != S_OK) return;
1600 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1601 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1602 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1603 RegCloseKey(hShellExtKey);
1604 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1605 &pidlWineTestFolder, NULL);
1606 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1607 IShellFolder_Release(pDesktopFolder);
1608 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1609 if (hr != S_OK) return;
1611 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1612 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1614 IPersistFolder3_Release(pPersistFolder3);
1615 pILFree(pidlWineTestFolder);
1619 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1620 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1621 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1622 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1623 pILFree(pidlCurrentFolder);
1624 pILFree(pidlWineTestFolder);
1626 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1627 IPersistFolder3_Release(pPersistFolder3);
1628 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1629 if (hr != S_OK) return;
1631 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1632 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1634 IShellFolder_Release(pShellFolder);
1638 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1639 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1641 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1642 * but ShellFSFolders. */
1643 myPathAddBackslashW(wszDesktopPath);
1644 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1645 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1646 IShellFolder_Release(pShellFolder);
1650 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1651 &pidlSubFolder, NULL);
1652 RemoveDirectoryW(wszDesktopPath);
1653 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1655 IShellFolder_Release(pShellFolder);
1659 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1660 (LPVOID*)&pPersistFolder3);
1661 IShellFolder_Release(pShellFolder);
1662 pILFree(pidlSubFolder);
1663 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1667 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1668 * a little bit and also allow CLSID_UnixDosFolder. */
1669 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1670 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1671 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1672 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1674 IPersistFolder3_Release(pPersistFolder3);
1677 #include "pshpack1.h"
1678 struct FileStructA {
1682 WORD uFileDate; /* In our current implementation this is */
1683 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1688 struct FileStructW {
1689 WORD cbLen; /* Length of this element. */
1690 BYTE abFooBar1[6]; /* Beyond any recognition. */
1691 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1692 WORD uTime; /* (this is currently speculation) */
1693 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1694 WORD uTime2; /* (this is currently speculation) */
1695 BYTE abFooBar2[4]; /* Beyond any recognition. */
1696 WCHAR wszName[1]; /* The long filename in unicode. */
1697 /* Just for documentation: Right after the unicode string: */
1698 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1699 * SHITEMID->cb == uOffset + cbLen */
1701 #include "poppack.h"
1703 static void test_ITEMIDLIST_format(void) {
1704 WCHAR wszPersonal[MAX_PATH];
1705 LPSHELLFOLDER psfDesktop, psfPersonal;
1706 LPITEMIDLIST pidlPersonal, pidlFile;
1710 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1711 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1714 if (!pSHGetSpecialFolderPathW) return;
1716 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1717 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1718 if (!bResult) return;
1720 SetLastError(0xdeadbeef);
1721 bResult = SetCurrentDirectoryW(wszPersonal);
1722 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1723 win_skip("Most W-calls are not implemented\n");
1726 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1727 if (!bResult) return;
1729 hr = SHGetDesktopFolder(&psfDesktop);
1730 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1731 if (hr != S_OK) return;
1733 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1734 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1736 IShellFolder_Release(psfDesktop);
1740 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1741 (LPVOID*)&psfPersonal);
1742 IShellFolder_Release(psfDesktop);
1743 pILFree(pidlPersonal);
1744 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1745 if (hr != S_OK) return;
1747 for (i=0; i<3; i++) {
1748 CHAR szFile[MAX_PATH];
1749 struct FileStructA *pFileStructA;
1752 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1754 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1755 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1756 if (hFile == INVALID_HANDLE_VALUE) {
1757 IShellFolder_Release(psfPersonal);
1762 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1763 DeleteFileW(wszFile[i]);
1764 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1766 IShellFolder_Release(psfPersonal);
1770 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1771 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1772 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1773 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1775 if (i < 2) /* First two file names are already in valid 8.3 format */
1776 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1778 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1779 * can't implement this correctly, since unix filesystems don't support
1780 * this nasty short/long filename stuff. So we'll probably stay with our
1781 * current habbit of storing the long filename here, which seems to work
1784 ok(pidlFile->mkid.abID[18] == '~' ||
1785 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1786 "Should be derived 8.3 name!\n");
1788 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1789 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1790 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1791 "Alignment byte, where there shouldn't be!\n");
1793 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1794 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1795 "There should be an alignment byte, but isn't!\n");
1797 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1798 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1799 ok ((cbOffset >= sizeof(struct FileStructA) &&
1800 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1801 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1802 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1803 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1805 if (cbOffset >= sizeof(struct FileStructA) &&
1806 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1808 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1810 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1811 "FileStructW's offset and length should add up to the PIDL's length!\n");
1813 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1814 /* Since we just created the file, time of creation,
1815 * time of last access and time of last write access just be the same.
1816 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1817 * after the first run. I do remember something with NTFS keeping the creation time
1818 * if a file is deleted and then created again within a couple of seconds or so.
1819 * Might be the reason. */
1820 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1821 pFileStructA->uFileTime == pFileStructW->uTime,
1822 "Last write time should match creation time!\n");
1824 /* On FAT filesystems the last access time is midnight
1825 local time, so the values of uDate2 and uTime2 will
1826 depend on the local timezone. If the times are exactly
1827 equal then the dates should be identical for both FAT
1828 and NTFS as no timezone is more than 1 day away from UTC.
1830 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1832 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1833 "Last write date and time should match last access date and time!\n");
1837 /* Filesystem may be FAT. Check date within 1 day
1838 and seconds are zero. */
1839 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1840 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1841 "Last access time on FAT filesystems should have zero seconds.\n");
1842 /* TODO: Perform check for date being within one day.*/
1845 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1846 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1847 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1848 "The filename should be stored in unicode at this position!\n");
1855 IShellFolder_Release(psfPersonal);
1858 static void test_SHGetFolderPathA(void)
1860 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1862 char path[MAX_PATH];
1863 char path_x86[MAX_PATH];
1864 char path_key[MAX_PATH];
1868 if (!pSHGetFolderPathA)
1870 win_skip("SHGetFolderPathA not present\n");
1873 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1875 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1876 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1877 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1880 win_skip( "Program Files (x86) not supported\n" );
1883 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1886 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1887 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1888 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1892 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1894 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1896 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1898 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1900 DWORD type, count = sizeof(path_x86);
1901 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1903 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1904 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1906 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1910 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1911 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1912 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1915 win_skip( "Common Files (x86) not supported\n" );
1918 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1921 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1922 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1923 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1927 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1929 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1931 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1933 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1935 DWORD type, count = sizeof(path_x86);
1936 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1938 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1939 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1941 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1945 static void test_SHGetFolderPathAndSubDirA(void)
1951 static char wine[] = "wine";
1952 static char winetemp[] = "wine\\temp";
1953 static char appdata[MAX_PATH];
1954 static char testpath[MAX_PATH];
1955 static char toolongpath[MAX_PATH+1];
1957 if(!pSHGetFolderPathAndSubDirA)
1959 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1963 if(!pSHGetFolderPathA) {
1964 win_skip("SHGetFolderPathA not present!\n");
1967 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1969 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1973 sprintf(testpath, "%s\\%s", appdata, winetemp);
1974 delret = RemoveDirectoryA(testpath);
1975 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1976 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1980 sprintf(testpath, "%s\\%s", appdata, wine);
1981 delret = RemoveDirectoryA(testpath);
1982 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1983 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1987 /* test invalid second parameter */
1988 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1989 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1991 /* test fourth parameter */
1992 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1994 case S_OK: /* winvista */
1995 ok(!strncmp(appdata, testpath, strlen(appdata)),
1996 "expected %s to start with %s\n", testpath, appdata);
1997 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1998 "expected %s to end with %s\n", testpath, winetemp);
2000 case E_INVALIDARG: /* winxp, win2k3 */
2003 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
2006 /* test fifth parameter */
2008 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
2009 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2010 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2013 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
2014 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2015 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2018 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
2019 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2020 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2022 for(i=0; i< MAX_PATH; i++)
2023 toolongpath[i] = '0' + i % 10;
2024 toolongpath[MAX_PATH] = '\0';
2025 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2026 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2027 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2030 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2031 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2033 /* test a not existing path */
2035 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2036 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2037 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2039 /* create a directory inside a not existing directory */
2041 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2042 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2043 ok(!strncmp(appdata, testpath, strlen(appdata)),
2044 "expected %s to start with %s\n", testpath, appdata);
2045 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2046 "expected %s to end with %s\n", testpath, winetemp);
2047 dwret = GetFileAttributes(testpath);
2048 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2051 sprintf(testpath, "%s\\%s", appdata, winetemp);
2052 RemoveDirectoryA(testpath);
2053 sprintf(testpath, "%s\\%s", appdata, wine);
2054 RemoveDirectoryA(testpath);
2057 static void test_LocalizedNames(void)
2059 static char cCurrDirA[MAX_PATH];
2060 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2061 IShellFolder *IDesktopFolder, *testIShellFolder;
2062 ITEMIDLIST *newPIDL;
2065 static char resourcefile[MAX_PATH];
2071 static const char desktopini_contents1[] =
2072 "[.ShellClassInfo]\r\n"
2073 "LocalizedResourceName=@";
2074 static const char desktopini_contents2[] =
2076 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2077 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2079 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2080 CreateDirectoryA(".\\testfolder", NULL);
2082 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2084 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2086 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2087 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2088 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2089 ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2090 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2091 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
2092 ok(ret, "WriteFile failed %i\n", GetLastError());
2095 /* get IShellFolder for parent */
2096 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2097 len = lstrlenA(cCurrDirA);
2100 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2103 if(cCurrDirA[len-1] == '\\')
2104 cCurrDirA[len-1] = 0;
2106 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2108 hr = SHGetDesktopFolder(&IDesktopFolder);
2109 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2111 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2112 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2114 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2115 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2117 IMalloc_Free(ppM, newPIDL);
2119 /* windows reads the display name from the resource */
2120 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2121 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2123 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2124 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2126 if (hr == S_OK && pStrRetToBufW)
2128 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2129 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2131 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2132 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2133 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2136 /* editing name is also read from the resource */
2137 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2138 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2140 if (hr == S_OK && pStrRetToBufW)
2142 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2143 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2145 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2146 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2147 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2150 /* parsing name is unchanged */
2151 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2152 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2154 if (hr == S_OK && pStrRetToBufW)
2156 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2157 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2158 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2161 IShellFolder_Release(IDesktopFolder);
2162 IShellFolder_Release(testIShellFolder);
2164 IMalloc_Free(ppM, newPIDL);
2167 DeleteFileA(".\\testfolder\\desktop.ini");
2168 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2169 RemoveDirectoryA(".\\testfolder");
2172 static void test_SHCreateShellItem(void)
2174 IShellItem *shellitem, *shellitem2;
2175 IPersistIDList *persistidl;
2176 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2178 char curdirA[MAX_PATH];
2179 WCHAR curdirW[MAX_PATH];
2180 WCHAR fnbufW[MAX_PATH];
2181 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2182 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2184 GetCurrentDirectoryA(MAX_PATH, curdirA);
2186 if (!pSHCreateShellItem)
2188 win_skip("SHCreateShellItem isn't available\n");
2192 if (!lstrlenA(curdirA))
2194 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2198 if(pSHGetSpecialFolderLocation)
2200 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2201 ok(ret == S_OK, "Got 0x%08x\n", ret);
2205 win_skip("pSHGetSpecialFolderLocation missing.\n");
2206 pidl_desktop = NULL;
2209 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2211 ret = SHGetDesktopFolder(&desktopfolder);
2212 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2214 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2215 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2217 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)¤tfolder);
2218 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2220 CreateTestFile(".\\testfile");
2222 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2223 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2225 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2227 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2228 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2230 if (0) /* crashes on Windows XP */
2232 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2233 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2234 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2235 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2238 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2239 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2242 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2243 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2246 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2247 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2250 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2253 IPersistIDList_Release(persistidl);
2255 IShellItem_Release(shellitem);
2258 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2259 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2262 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2263 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2266 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2267 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2270 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2273 IPersistIDList_Release(persistidl);
2276 ret = IShellItem_GetParent(shellitem, &shellitem2);
2277 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2280 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2281 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2284 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2285 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2288 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2291 IPersistIDList_Release(persistidl);
2293 IShellItem_Release(shellitem2);
2296 IShellItem_Release(shellitem);
2299 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2300 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2303 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2304 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2307 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2308 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2311 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2314 IPersistIDList_Release(persistidl);
2316 IShellItem_Release(shellitem);
2319 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2320 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2321 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2324 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2325 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2328 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2329 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2332 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2335 IPersistIDList_Release(persistidl);
2337 IShellItem_Release(shellitem);
2340 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2341 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2344 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2345 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2348 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2349 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2352 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2355 IPersistIDList_Release(persistidl);
2358 IShellItem_Release(shellitem);
2361 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2362 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2365 ret = IShellItem_GetParent(shellitem, &shellitem2);
2366 ok(FAILED(ret), "Got 0x%08x\n", ret);
2367 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2368 IShellItem_Release(shellitem);
2371 /* SHCreateItemFromParsingName */
2372 if(pSHCreateItemFromParsingName)
2376 /* Crashes under windows 7 */
2377 pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2380 shellitem = (void*)0xdeadbeef;
2381 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2382 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2383 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2385 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2386 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2387 "SHCreateItemFromParsingName returned %x\n", ret);
2388 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2390 lstrcpyW(fnbufW, curdirW);
2391 myPathAddBackslashW(fnbufW);
2392 lstrcatW(fnbufW, testfileW);
2394 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2395 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2399 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2400 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2403 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2404 CoTaskMemFree(tmp_fname);
2406 IShellItem_Release(shellitem);
2410 win_skip("No SHCreateItemFromParsingName\n");
2413 /* SHCreateItemFromIDList */
2414 if(pSHCreateItemFromIDList)
2418 /* Crashes under win7 */
2419 pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2422 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2423 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2425 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2426 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2429 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2430 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2433 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2434 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2437 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2440 IPersistIDList_Release(persistidl);
2442 IShellItem_Release(shellitem);
2445 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2446 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2449 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2450 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2453 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2454 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2457 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2460 IPersistIDList_Release(persistidl);
2462 IShellItem_Release(shellitem);
2466 win_skip("No SHCreateItemFromIDList\n");
2468 DeleteFileA(".\\testfile");
2469 pILFree(pidl_abstestfile);
2470 pILFree(pidl_testfile);
2471 pILFree(pidl_desktop);
2473 IShellFolder_Release(currentfolder);
2474 IShellFolder_Release(desktopfolder);
2477 static void test_SHGetNameFromIDList(void)
2479 IShellItem *shellitem;
2484 static const DWORD flags[] = {
2485 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2486 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2487 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2488 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2490 if(!pSHGetNameFromIDList)
2492 win_skip("SHGetNameFromIDList missing.\n");
2496 /* These should be available on any platform that passed the above test. */
2497 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2498 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2499 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2500 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2504 /* Crashes under win7 */
2505 pSHGetNameFromIDList(NULL, 0, NULL);
2508 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2509 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2511 /* Test the desktop */
2512 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2513 ok(hres == S_OK, "Got 0x%08x\n", hres);
2514 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2515 ok(hres == S_OK, "Got 0x%08x\n", hres);
2518 WCHAR *nameSI, *nameSH;
2519 WCHAR buf[MAX_PATH];
2520 HRESULT hrSI, hrSH, hrSF;
2525 SHGetDesktopFolder(&psf);
2526 for(i = 0; flags[i] != -1234; i++)
2528 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2529 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2530 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2531 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2532 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2533 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2535 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2536 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2540 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2542 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2544 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2546 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2547 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2549 IShellFolder_Release(psf);
2551 if(pSHGetPathFromIDListW){
2552 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2553 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2554 res = pSHGetPathFromIDListW(pidl, buf);
2555 ok(res == TRUE, "Got %d\n", res);
2556 if(SUCCEEDED(hrSI) && res)
2557 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2558 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2560 win_skip("pSHGetPathFromIDListW not available\n");
2562 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2563 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2564 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2566 IShellItem_Release(shellitem);
2570 /* Test the control panel */
2571 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2572 ok(hres == S_OK, "Got 0x%08x\n", hres);
2573 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2574 ok(hres == S_OK, "Got 0x%08x\n", hres);
2577 WCHAR *nameSI, *nameSH;
2578 WCHAR buf[MAX_PATH];
2579 HRESULT hrSI, hrSH, hrSF;
2584 SHGetDesktopFolder(&psf);
2585 for(i = 0; flags[i] != -1234; i++)
2587 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2588 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2589 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2590 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2591 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2592 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2594 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2595 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2599 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2601 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2603 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2605 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2606 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2608 IShellFolder_Release(psf);
2610 if(pSHGetPathFromIDListW){
2611 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2612 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2613 res = pSHGetPathFromIDListW(pidl, buf);
2614 ok(res == FALSE, "Got %d\n", res);
2615 if(SUCCEEDED(hrSI) && res)
2616 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2617 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2619 win_skip("pSHGetPathFromIDListW not available\n");
2621 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2622 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2623 "Got 0x%08x\n", hres);
2624 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2626 IShellItem_Release(shellitem);
2631 static void test_SHGetItemFromDataObject(void)
2633 IShellFolder *psfdesktop;
2638 if(!pSHGetItemFromDataObject)
2640 win_skip("No SHGetItemFromDataObject.\n");
2646 /* Crashes under win7 */
2647 pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2650 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2651 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2653 SHGetDesktopFolder(&psfdesktop);
2655 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2656 ok(hres == S_OK, "got 0x%08x\n", hres);
2663 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2664 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2665 ok(hres == S_OK, "got 0x%08x\n", hres);
2668 LPITEMIDLIST apidl[5];
2671 for(count = 0; count < 5; count++)
2672 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2677 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2678 &IID_IDataObject, NULL, (void**)&pdo);
2679 ok(hres == S_OK, "got 0x%08x\n", hres);
2682 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2683 ok(hres == S_OK, "got 0x%08x\n", hres);
2684 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2685 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2686 ok(hres == S_OK, "got 0x%08x\n", hres);
2687 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2688 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2689 ok(hres == S_OK, "got 0x%08x\n", hres);
2690 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2691 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2692 ok(hres == S_OK, "got 0x%08x\n", hres);
2693 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2694 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2695 ok(hres == S_OK, "got 0x%08x\n", hres);
2696 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2698 IDataObject_Release(pdo);
2702 skip("No file(s) found - skipping single-file test.\n");
2706 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2707 &IID_IDataObject, NULL, (void**)&pdo);
2708 ok(hres == S_OK, "got 0x%08x\n", hres);
2711 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2712 ok(hres == S_OK, "got 0x%08x\n", hres);
2713 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2714 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2715 ok(hres == S_OK, "got 0x%08x\n", hres);
2716 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2717 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2718 ok(hres == S_OK, "got 0x%08x\n", hres);
2719 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2720 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2721 ok(hres == S_OK, "got 0x%08x\n", hres);
2722 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2723 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2724 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2725 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2726 IDataObject_Release(pdo);
2730 skip("zero or one file found - skipping multi-file test.\n");
2732 for(i = 0; i < count; i++)
2735 IEnumIDList_Release(peidl);
2738 IShellView_Release(psv);
2741 IShellFolder_Release(psfdesktop);
2744 static void test_ShellItemCompare(void)
2746 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2747 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2748 IShellFolder *psf_desktop, *psf_current;
2749 LPITEMIDLIST pidl_cwd;
2750 WCHAR curdirW[MAX_PATH];
2753 static const WCHAR filesW[][9] = {
2754 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2755 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2756 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2760 if(!pSHCreateShellItem)
2762 win_skip("SHCreateShellItem missing.\n");
2766 GetCurrentDirectoryW(MAX_PATH, curdirW);
2767 if(!lstrlenW(curdirW))
2769 skip("Failed to get current directory, skipping.\n");
2773 CreateDirectoryA(".\\a", NULL);
2774 CreateDirectoryA(".\\b", NULL);
2775 CreateDirectoryA(".\\c", NULL);
2776 CreateTestFile(".\\a\\a");
2777 CreateTestFile(".\\a\\b");
2778 CreateTestFile(".\\a\\c");
2779 CreateTestFile(".\\b\\a");
2780 CreateTestFile(".\\b\\b");
2781 CreateTestFile(".\\b\\c");
2782 CreateTestFile(".\\c\\a");
2783 CreateTestFile(".\\c\\b");
2784 CreateTestFile(".\\c\\c");
2786 SHGetDesktopFolder(&psf_desktop);
2787 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2788 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2789 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2790 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2791 IShellFolder_Release(psf_desktop);
2794 /* Generate ShellItems for the files */
2795 memset(&psi, 0, sizeof(psi));
2797 for(i = 0; i < 9; i++)
2799 LPITEMIDLIST pidl_testfile = NULL;
2801 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2802 NULL, &pidl_testfile, NULL);
2803 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2806 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2807 ok(hr == S_OK, "Got 0x%08x\n", hr);
2808 pILFree(pidl_testfile);
2810 if(FAILED(hr)) failed = TRUE;
2814 skip("Failed to create all shellitems.\n");
2818 /* Generate ShellItems for the folders */
2819 hr = IShellItem_GetParent(psi[0], &psi_a);
2820 ok(hr == S_OK, "Got 0x%08x\n", hr);
2821 if(FAILED(hr)) failed = TRUE;
2822 hr = IShellItem_GetParent(psi[3], &psi_b);
2823 ok(hr == S_OK, "Got 0x%08x\n", hr);
2824 if(FAILED(hr)) failed = TRUE;
2825 hr = IShellItem_GetParent(psi[6], &psi_c);
2826 ok(hr == S_OK, "Got 0x%08x\n", hr);
2827 if(FAILED(hr)) failed = TRUE;
2831 skip("Failed to create shellitems.\n");
2837 /* Crashes on native (win7, winxp) */
2838 IShellItem_Compare(psi_a, NULL, 0, NULL);
2839 IShellItem_Compare(psi_a, psi_b, 0, NULL);
2840 IShellItem_Compare(psi_a, NULL, 0, &order);
2844 for(i = 0; i < 9; i++)
2846 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2847 ok(hr == S_OK, "Got 0x%08x\n", hr);
2848 ok(order == 0, "Got order %d\n", order);
2849 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2850 ok(hr == S_OK, "Got 0x%08x\n", hr);
2851 ok(order == 0, "Got order %d\n", order);
2852 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2853 ok(hr == S_OK, "Got 0x%08x\n", hr);
2854 ok(order == 0, "Got order %d\n", order);
2858 /* a\b:a\a , a\b:a\c, a\b:a\b */
2859 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2860 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2861 ok(order == 1, "Got order %d\n", order);
2862 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2863 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2864 ok(order == -1, "Got order %d\n", order);
2865 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2866 ok(hr == S_OK, "Got 0x%08x\n", hr);
2867 ok(order == 0, "Got order %d\n", order);
2869 /* b\b:a\b, b\b:c\b, b\b:c\b */
2870 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2871 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2872 ok(order == 1, "Got order %d\n", order);
2873 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2874 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2875 ok(order == -1, "Got order %d\n", order);
2876 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2877 ok(hr == S_OK, "Got 0x%08x\n", hr);
2878 ok(order == 0, "Got order %d\n", order);
2880 /* b:a\a, b:a\c, b:a\b */
2881 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2882 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2883 todo_wine ok(order == 1, "Got order %d\n", order);
2884 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2885 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2886 todo_wine ok(order == 1, "Got order %d\n", order);
2887 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2888 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2889 todo_wine ok(order == 1, "Got order %d\n", order);
2891 /* b:c\a, b:c\c, b:c\b */
2892 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2893 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2894 ok(order == -1, "Got order %d\n", order);
2895 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2896 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2897 ok(order == -1, "Got order %d\n", order);
2898 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2899 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2900 ok(order == -1, "Got order %d\n", order);
2902 /* a\b:a\a , a\b:a\c, a\b:a\b */
2903 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2904 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2905 ok(order == 1, "Got order %d\n", order);
2906 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2907 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2908 ok(order == -1, "Got order %d\n", order);
2909 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2910 ok(hr == S_OK, "Got 0x%08x\n", hr);
2911 ok(order == 0, "Got order %d\n", order);
2913 /* b\b:a\b, b\b:c\b, b\b:c\b */
2914 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2915 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2916 ok(order == 1, "Got order %d\n", order);
2917 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2918 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2919 ok(order == -1, "Got order %d\n", order);
2920 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2921 ok(hr == S_OK, "Got 0x%08x\n", hr);
2922 ok(order == 0, "Got order %d\n", order);
2924 /* b:a\a, b:a\c, b:a\b */
2925 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2926 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2927 todo_wine ok(order == 1, "Got order %d\n", order);
2928 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2929 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2930 todo_wine ok(order == 1, "Got order %d\n", order);
2931 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2932 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2933 todo_wine ok(order == 1, "Got order %d\n", order);
2935 /* b:c\a, b:c\c, b:c\b */
2936 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2937 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2938 ok(order == -1, "Got order %d\n", order);
2939 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2940 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2941 ok(order == -1, "Got order %d\n", order);
2942 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2943 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2944 ok(order == -1, "Got order %d\n", order);
2947 IShellFolder_Release(psf_current);
2949 DeleteFileA(".\\a\\a");
2950 DeleteFileA(".\\a\\b");
2951 DeleteFileA(".\\a\\c");
2952 DeleteFileA(".\\b\\a");
2953 DeleteFileA(".\\b\\b");
2954 DeleteFileA(".\\b\\c");
2955 DeleteFileA(".\\c\\a");
2956 DeleteFileA(".\\c\\b");
2957 DeleteFileA(".\\c\\c");
2958 RemoveDirectoryA(".\\a");
2959 RemoveDirectoryA(".\\b");
2960 RemoveDirectoryA(".\\c");
2962 if(psi_a) IShellItem_Release(psi_a);
2963 if(psi_b) IShellItem_Release(psi_b);
2964 if(psi_c) IShellItem_Release(psi_c);
2966 for(i = 0; i < 9; i++)
2967 if(psi[i]) IShellItem_Release(psi[i]);
2970 /**************************************************************/
2971 /* IUnknown implementation for counting QueryInterface calls. */
2973 IUnknown IUnknown_iface;
2981 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
2983 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
2986 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2988 IUnknownImpl *This = impl_from_IUnknown(iunk);
2990 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2992 if(IsEqualIID(This->ifaces[i].id, riid))
2994 This->ifaces[i].count++;
3001 return E_NOINTERFACE;
3004 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
3009 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3014 static const IUnknownVtbl vt_IUnknown = {
3015 unk_fnQueryInterface,
3020 static void test_SHGetIDListFromObject(void)
3022 IUnknownImpl *punkimpl;
3023 IShellFolder *psfdesktop;
3025 LPITEMIDLIST pidl, pidl_desktop;
3028 struct if_count ifaces[] =
3029 { {&IID_IPersistIDList, 0},
3030 {&IID_IPersistFolder2, 0},
3031 {&IID_IDataObject, 0},
3032 {&IID_IParentAndItem, 0},
3033 {&IID_IFolderView, 0},
3036 if(!pSHGetIDListFromObject)
3038 win_skip("SHGetIDListFromObject missing.\n");
3042 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3046 /* Crashes native */
3047 pSHGetIDListFromObject(NULL, NULL);
3048 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3051 hres = pSHGetIDListFromObject(NULL, &pidl);
3052 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3054 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3055 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3056 punkimpl->ifaces = ifaces;
3057 punkimpl->unknown = 0;
3059 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3060 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3061 ok(ifaces[0].count, "interface not requested.\n");
3062 ok(ifaces[1].count, "interface not requested.\n");
3063 ok(ifaces[2].count, "interface not requested.\n");
3065 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3066 "interface not requested.\n");
3067 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3068 "interface not requested.\n");
3070 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3071 HeapFree(GetProcessHeap(), 0, punkimpl);
3073 pidl_desktop = NULL;
3074 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3075 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3077 SHGetDesktopFolder(&psfdesktop);
3079 /* Test IShellItem */
3080 if(pSHCreateShellItem)
3082 IShellItem *shellitem;
3083 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3084 ok(hres == S_OK, "got 0x%08x\n", hres);
3087 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3088 ok(hres == S_OK, "got 0x%08x\n", hres);
3091 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3094 IShellItem_Release(shellitem);
3098 skip("no SHCreateShellItem.\n");
3100 /* Test IShellFolder */
3101 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3102 ok(hres == S_OK, "got 0x%08x\n", hres);
3105 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3109 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3110 ok(hres == S_OK, "got 0x%08x\n", hres);
3117 /* Test IFolderView */
3118 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3119 ok(hres == S_OK, "got 0x%08x\n", hres);
3122 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3126 /* Test IDataObject */
3127 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3128 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3129 ok(hres == S_OK, "got 0x%08x\n", hres);
3132 LPITEMIDLIST apidl[5];
3134 for(count = 0; count < 5; count++)
3135 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3140 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3141 &IID_IDataObject, NULL, (void**)&pdo);
3142 ok(hres == S_OK, "got 0x%08x\n", hres);
3145 pidl = (void*)0xDEADBEEF;
3146 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3147 ok(hres == S_OK, "got 0x%08x\n", hres);
3148 ok(pidl != NULL, "pidl is NULL.\n");
3149 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3152 IDataObject_Release(pdo);
3156 skip("No files found - skipping single-file test.\n");
3160 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3161 &IID_IDataObject, NULL, (void**)&pdo);
3162 ok(hres == S_OK, "got 0x%08x\n", hres);
3165 pidl = (void*)0xDEADBEEF;
3166 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3167 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3168 "got 0x%08x\n", hres);
3169 ok(pidl == NULL, "pidl is not NULL.\n");
3171 IDataObject_Release(pdo);
3175 skip("zero or one file found - skipping multi-file test.\n");
3177 for(i = 0; i < count; i++)
3180 IEnumIDList_Release(peidl);
3183 IShellView_Release(psv);
3186 IShellFolder_Release(psfdesktop);
3187 pILFree(pidl_desktop);
3190 static void test_SHGetItemFromObject(void)
3192 IUnknownImpl *punkimpl;
3193 IShellFolder *psfdesktop;
3198 struct if_count ifaces[] =
3199 { {&IID_IPersistIDList, 0},
3200 {&IID_IPersistFolder2, 0},
3201 {&IID_IDataObject, 0},
3202 {&IID_IParentAndItem, 0},
3203 {&IID_IFolderView, 0},
3206 if(!pSHGetItemFromObject)
3208 skip("No SHGetItemFromObject.\n");
3212 SHGetDesktopFolder(&psfdesktop);
3216 /* Crashes with Windows 7 */
3217 pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3218 pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3219 pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3222 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3223 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3225 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3226 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3227 punkimpl->ifaces = ifaces;
3228 punkimpl->unknown = 0;
3230 /* The same as SHGetIDListFromObject */
3231 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3232 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3233 ok(ifaces[0].count, "interface not requested.\n");
3234 ok(ifaces[1].count, "interface not requested.\n");
3235 ok(ifaces[2].count, "interface not requested.\n");
3237 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3238 "interface not requested.\n");
3239 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3240 "interface not requested.\n");
3242 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3243 HeapFree(GetProcessHeap(), 0, punkimpl);
3245 /* Test IShellItem */
3246 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3247 ok(hres == S_OK, "Got 0x%08x\n", hres);
3251 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3252 ok(hres == S_OK, "Got 0x%08x\n", hres);
3256 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3257 IShellItem_Release(psi2);
3259 IShellItem_Release(psi);
3262 IShellFolder_Release(psfdesktop);
3265 static void test_SHCreateShellItemArray(void)
3267 IShellFolder *pdesktopsf, *psf;
3268 IShellItemArray *psia;
3271 WCHAR cTestDirW[MAX_PATH];
3272 LPITEMIDLIST pidl_testdir, pidl;
3273 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3275 if(!pSHCreateShellItemArray) {
3276 skip("No pSHCreateShellItemArray!\n");
3280 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3284 /* Crashes under native */
3285 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3286 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3287 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3288 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3291 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3292 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3294 SHGetDesktopFolder(&pdesktopsf);
3295 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3296 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3298 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3299 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3301 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3302 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3303 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3306 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3307 myPathAddBackslashW(cTestDirW);
3308 lstrcatW(cTestDirW, testdirW);
3310 CreateFilesFolders();
3312 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3313 ok(hr == S_OK, "got 0x%08x\n", hr);
3316 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3318 ok(hr == S_OK, "Got 0x%08x\n", hr);
3320 IShellFolder_Release(pdesktopsf);
3324 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3325 pILFree(pidl_testdir);
3330 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3331 ok(hr == S_OK, "Got %08x\n", hr);
3334 LPITEMIDLIST apidl[5];
3335 UINT done, numitems, i;
3337 for(done = 0; done < 5; done++)
3338 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3340 ok(done == 5, "Got %d pidls\n", done);
3341 IEnumIDList_Release(peidl);
3343 /* Create a ShellItemArray */
3344 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3345 ok(hr == S_OK, "Got 0x%08x\n", hr);
3352 /* Crashes in Windows 7 */
3353 IShellItemArray_GetCount(psia, NULL);
3356 IShellItemArray_GetCount(psia, &numitems);
3357 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3359 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3360 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3362 /* Compare all the items */
3363 for(i = 0; i < numitems; i++)
3365 LPITEMIDLIST pidl_abs;
3366 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3368 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3369 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3372 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3373 ok(hr == S_OK, "Got 0x%08x\n", hr);
3376 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3379 IShellItem_Release(psi);
3383 for(i = 0; i < done; i++)
3385 IShellItemArray_Release(psia);
3389 /* SHCreateShellItemArrayFromShellItem */
3390 if(pSHCreateShellItemArrayFromShellItem)
3396 /* Crashes under Windows 7 */
3397 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3398 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3399 pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3402 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3403 ok(hr == S_OK, "Got 0x%08x\n", hr);
3406 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3407 ok(hr == S_OK, "Got 0x%08x\n", hr);
3412 hr = IShellItemArray_GetCount(psia, &count);
3413 ok(hr == S_OK, "Got 0x%08x\n", hr);
3414 ok(count == 1, "Got count %d\n", count);
3415 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3416 ok(hr == S_OK, "Got 0x%08x\n", hr);
3418 ok(psi != psi2, "ShellItems are of the same instance.\n");
3421 LPITEMIDLIST pidl1, pidl2;
3422 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3423 ok(hr == S_OK, "Got 0x%08x\n", hr);
3424 ok(pidl1 != NULL, "pidl1 was null.\n");
3425 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3426 ok(hr == S_OK, "Got 0x%08x\n", hr);
3427 ok(pidl2 != NULL, "pidl2 was null.\n");
3428 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3431 IShellItem_Release(psi2);
3433 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3434 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3435 IShellItemArray_Release(psia);
3437 IShellItem_Release(psi);
3441 skip("No SHCreateShellItemArrayFromShellItem.\n");
3443 if(pSHCreateShellItemArrayFromDataObject)
3449 /* Crashes under Windows 7 */
3450 pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3452 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3453 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3455 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3456 ok(hr == S_OK, "got 0x%08x\n", hr);
3463 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3464 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3465 ok(hr == S_OK, "got 0x%08x\n", hr);
3468 LPITEMIDLIST apidl[5];
3471 for(count = 0; count < 5; count++)
3472 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3474 ok(count == 5, "Got %d\n", count);
3478 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3479 &IID_IDataObject, NULL, (void**)&pdo);
3480 ok(hr == S_OK, "Got 0x%08x\n", hr);
3483 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3485 ok(hr == S_OK, "Got 0x%08x\n", hr);
3489 hr = IShellItemArray_GetCount(psia, &count_sia);
3490 ok(hr == S_OK, "Got 0x%08x\n", hr);
3491 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3492 for(i = 0; i < count_sia; i++)
3494 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3496 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3497 ok(hr == S_OK, "Got 0x%08x\n", hr);
3501 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3502 ok(hr == S_OK, "Got 0x%08x\n", hr);
3503 ok(pidl != NULL, "pidl as NULL.\n");
3504 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3506 IShellItem_Release(psi);
3511 IShellItemArray_Release(psia);
3514 IDataObject_Release(pdo);
3516 for(i = 0; i < count; i++)
3520 skip("No files found - skipping test.\n");
3522 IEnumIDList_Release(peidl);
3524 IShellView_Release(psv);
3528 skip("No SHCreateShellItemArrayFromDataObject.\n");
3530 IShellFolder_Release(psf);
3531 pILFree(pidl_testdir);
3535 static void test_ShellItemBindToHandler(void)
3538 LPITEMIDLIST pidl_desktop;
3541 if(!pSHCreateShellItem)
3543 skip("SHCreateShellItem missing.\n");
3547 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3548 ok(hr == S_OK, "Got 0x%08x\n", hr);
3551 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3552 ok(hr == S_OK, "Got 0x%08x\n", hr);
3556 IPersistFolder2 *ppf2;
3561 /* Crashes under Windows 7 */
3562 IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3563 IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3565 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3566 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3569 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3570 ok(hr == S_OK, "Got 0x%08x\n", hr);
3571 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3572 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3573 ok(hr == S_OK, "Got 0x%08x\n", hr);
3576 LPITEMIDLIST pidl_tmp;
3577 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3578 ok(hr == S_OK, "Got 0x%08x\n", hr);
3581 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3584 IPersistFolder2_Release(ppf2);
3587 /* BHID_SFUIObject */
3588 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3589 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3590 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3591 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3592 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3593 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3595 /* BHID_DataObject */
3596 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3597 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3598 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3602 /* BHID_SFViewObject */
3603 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3604 ok(hr == S_OK, "Got 0x%08x\n", hr);
3605 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3606 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3607 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3608 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3611 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3612 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3613 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3614 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3615 ok(hr == S_OK, "Got 0x%08x\n", hr);
3616 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3619 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3620 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3621 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3622 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3623 ok(hr == S_OK, "Got 0x%08x\n", hr);
3624 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3626 /* BHID_StorageEnum */
3627 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3628 ok(hr == S_OK, "Got 0x%08x\n", hr);
3629 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3632 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3633 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3634 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3636 /* BHID_EnumItems */
3637 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3638 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3639 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3642 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3643 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3644 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3646 /* BHID_LinkTargetItem */
3647 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3648 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3649 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3650 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3651 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3652 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3654 /* BHID_PropertyStore */
3655 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3656 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3657 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3658 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3659 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3660 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3662 /* BHID_ThumbnailHandler */
3663 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3664 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3665 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3667 /* BHID_AssociationArray */
3668 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3669 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3670 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3672 /* BHID_EnumAssocHandlers */
3673 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3674 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3675 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3678 IShellItem_Release(psi);
3681 skip("Failed to create ShellItem.\n");
3683 pILFree(pidl_desktop);
3686 static void test_ShellItemGetAttributes(void)
3689 LPITEMIDLIST pidl_desktop;
3693 if(!pSHCreateShellItem)
3695 skip("SHCreateShellItem missing.\n");
3699 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3700 ok(hr == S_OK, "Got 0x%08x\n", hr);
3703 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3704 ok(hr == S_OK, "Got 0x%08x\n", hr);
3705 pILFree(pidl_desktop);
3709 skip("Skipping tests.\n");
3715 /* Crashes on native (Win 7) */
3716 IShellItem_GetAttributes(psi, 0, NULL);
3719 /* Test GetAttributes on the desktop folder. */
3721 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
3722 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
3723 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
3725 IShellItem_Release(psi);
3728 static void test_SHParseDisplayName(void)
3730 LPITEMIDLIST pidl1, pidl2;
3731 IShellFolder *desktop;
3732 WCHAR dirW[MAX_PATH];
3737 if (!pSHParseDisplayName)
3739 win_skip("SHParseDisplayName isn't available\n");
3745 /* crashes on native */
3746 pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3748 pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3751 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3752 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3753 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3754 hr == E_INVALIDARG, "failed %08x\n", hr);
3755 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3759 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3760 ok(hr == S_OK, "failed %08x\n", hr);
3761 hr = SHGetDesktopFolder(&desktop);
3762 ok(hr == S_OK, "failed %08x\n", hr);
3763 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3764 ok(hr == S_OK, "failed %08x\n", hr);
3765 ret = pILIsEqual(pidl1, pidl2);
3766 ok(ret == TRUE, "expected equal idls\n");
3771 GetWindowsDirectoryW( dirW, MAX_PATH );
3773 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3774 ok(hr == S_OK, "failed %08x\n", hr);
3775 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3776 ok(hr == S_OK, "failed %08x\n", hr);
3778 ret = pILIsEqual(pidl1, pidl2);
3779 ok(ret == TRUE, "expected equal idls\n");
3783 /* system32 is not redirected to syswow64 on WOW64 */
3784 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
3785 if (is_wow64 && pGetSystemWow64DirectoryW)
3788 ok(GetSystemDirectoryW(dirW, MAX_PATH) > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
3789 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3790 ok(hr == S_OK, "failed %08x\n", hr);
3792 ok(pGetSystemWow64DirectoryW(dirW, MAX_PATH) > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
3793 hr = pSHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
3794 ok(hr == S_OK, "failed %08x\n", hr);
3795 ret = pILIsEqual(pidl1, pidl2);
3796 ok(ret == FALSE, "expected different idls\n");
3801 IShellFolder_Release(desktop);
3804 static void test_desktop_IPersist(void)
3806 IShellFolder *desktop;
3808 IPersistFolder2 *ppf2;
3812 hr = SHGetDesktopFolder(&desktop);
3813 ok(hr == S_OK, "failed %08x\n", hr);
3815 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3816 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3822 /* crashes on native */
3823 IPersist_GetClassID(persist, NULL);
3825 memset(&clsid, 0, sizeof(clsid));
3826 hr = IPersist_GetClassID(persist, &clsid);
3827 ok(hr == S_OK, "failed %08x\n", hr);
3828 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3829 IPersist_Release(persist);
3832 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3833 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3836 IPersistFolder *ppf;
3838 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3839 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3841 IPersistFolder_Release(ppf);
3844 hr = IPersistFolder2_Initialize(ppf2, NULL);
3845 ok(hr == S_OK, "got %08x\n", hr);
3849 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3850 ok(hr == S_OK, "got %08x\n", hr);
3851 ok(pidl != NULL, "pidl was NULL.\n");
3852 if(SUCCEEDED(hr)) pILFree(pidl);
3854 IPersistFolder2_Release(ppf2);
3857 IShellFolder_Release(desktop);
3860 static void test_GetUIObject(void)
3862 IShellFolder *psf_desktop;
3866 WCHAR path[MAX_PATH];
3867 const WCHAR filename[] =
3868 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3870 if(!pSHBindToParent)
3872 win_skip("SHBindToParent missing.\n");
3876 GetCurrentDirectoryW(MAX_PATH, path);
3879 skip("GetCurrentDirectoryW returned an empty string.\n");
3882 lstrcatW(path, filename);
3883 SHGetDesktopFolder(&psf_desktop);
3885 CreateFilesFolders();
3887 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3888 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3892 LPCITEMIDLIST pidl_child;
3893 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3894 ok(hr == S_OK, "Got 0x%08x\n", hr);
3897 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3898 &IID_IContextMenu, NULL, (void**)&pcm);
3899 ok(hr == S_OK, "Got 0x%08x\n", hr);
3902 HMENU hmenu = CreatePopupMenu();
3903 INT max_id, max_id_check;
3905 const int id_upper_limit = 32767;
3906 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3907 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3908 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3909 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3910 count = GetMenuItemCount(hmenu);
3911 ok(count, "Got %d\n", count);
3914 for(i = 0; i < count; i++)
3918 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3919 mii.cbSize = sizeof(MENUITEMINFOA);
3920 mii.fMask = MIIM_ID | MIIM_FTYPE;
3923 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3924 ok(res, "Failed (last error: %d).\n", GetLastError());
3926 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3927 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3928 if(!(mii.fType & MFT_SEPARATOR))
3929 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3931 ok((max_id_check == max_id) ||
3932 (max_id_check == max_id-1 /* Win 7 */),
3933 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3935 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3937 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3939 CMINVOKECOMMANDINFO cmi;
3940 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3941 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3943 /* Attempt to execute a nonexistent command */
3944 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3945 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3946 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3948 cmi.lpVerb = "foobar_wine_test";
3949 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3950 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3951 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3952 "Got 0x%08x\n", hr);
3957 IContextMenu_Release(pcm);
3959 IShellFolder_Release(psf);
3961 if(pILFree) pILFree(pidl);
3964 IShellFolder_Release(psf_desktop);
3968 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3969 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3971 LPCITEMIDLIST child;
3972 IShellFolder *parent;
3976 if(!pSHBindToParent){
3977 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3979 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3981 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3987 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3991 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3992 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3996 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3997 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3999 IShellFolder_Release(parent);
4003 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
4004 "Got unexpected string type: %d\n", filename.uType);
4005 if(filename.uType == STRRET_WSTR){
4006 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
4007 "didn't get expected path (%s), instead: %s\n",
4008 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
4009 SHFree(U(filename).pOleStr);
4010 }else if(filename.uType == STRRET_CSTR){
4011 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
4012 "didn't get expected path (%s), instead: %s\n",
4013 wine_dbgstr_w(path), U(filename).cStr);
4016 IShellFolder_Release(parent);
4018 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4021 static void test_SHSimpleIDListFromPath(void)
4023 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4024 const CHAR adirA[] = "C:\\sidlfpdir";
4025 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4027 LPITEMIDLIST pidl = NULL;
4029 if(!pSHSimpleIDListFromPathAW){
4030 win_skip("SHSimpleIDListFromPathAW not available\n");
4034 br = CreateDirectoryA(adirA, NULL);
4035 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4038 pidl = pSHSimpleIDListFromPathAW(adirW);
4040 pidl = pSHSimpleIDListFromPathAW(adirA);
4041 verify_pidl(pidl, adirW);
4044 br = RemoveDirectoryA(adirA);
4045 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4048 pidl = pSHSimpleIDListFromPathAW(adirW);
4050 pidl = pSHSimpleIDListFromPathAW(adirA);
4051 verify_pidl(pidl, adirW);
4055 /* IFileSystemBindData impl */
4056 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4057 REFIID riid, void **ppv)
4059 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4060 IsEqualIID(riid, &IID_IUnknown)){
4064 return E_NOINTERFACE;
4067 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4072 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4077 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4078 const WIN32_FIND_DATAW *pfd)
4080 ok(0, "SetFindData called\n");
4084 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4085 WIN32_FIND_DATAW *pfd)
4087 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4091 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4092 WIN32_FIND_DATAW *pfd)
4094 memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4098 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4099 WIN32_FIND_DATAW *pfd)
4101 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4102 *pfd->cFileName = 'a';
4103 *pfd->cAlternateFileName = 'a';
4107 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4108 WIN32_FIND_DATAW *pfd)
4110 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4111 HANDLE handle = FindFirstFileW(adirW, pfd);
4116 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4117 WIN32_FIND_DATAW *pfd)
4122 static IFileSystemBindDataVtbl fsbdVtbl = {
4123 fsbd_QueryInterface,
4130 static IFileSystemBindData fsbd = { &fsbdVtbl };
4132 static void test_ParseDisplayNamePBC(void)
4134 WCHAR wFileSystemBindData[] =
4135 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4136 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4137 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4138 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4139 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4146 /* Check if we support WCHAR functions */
4147 SetLastError(0xdeadbeef);
4148 lstrcmpiW(adirW, adirW);
4149 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4150 win_skip("Most W-calls are not implemented\n");
4154 hres = SHGetDesktopFolder(&psf);
4155 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4157 win_skip("Failed to get IShellFolder, can't run tests\n");
4161 /* fails on unknown dir with no IBindCtx */
4162 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4163 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4164 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4165 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4166 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4167 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4168 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4169 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4170 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4172 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4173 hres = CreateBindCtx(0, &pbc);
4174 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4176 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4177 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4178 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4179 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4180 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4181 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4182 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4183 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4184 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4186 /* unknown dir with IBindCtx with IFileSystemBindData */
4187 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4188 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4190 /* return E_FAIL from GetFindData */
4191 pidl = (ITEMIDLIST*)0xdeadbeef;
4192 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4193 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4194 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4195 "ParseDisplayName failed: 0x%08x\n", hres);
4196 if(SUCCEEDED(hres)){
4197 verify_pidl(pidl, adirW);
4201 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4202 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4203 "ParseDisplayName failed: 0x%08x\n", hres);
4204 if(SUCCEEDED(hres)){
4205 verify_pidl(pidl, afileW);
4209 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4210 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4211 "ParseDisplayName failed: 0x%08x\n", hres);
4212 if(SUCCEEDED(hres)){
4213 verify_pidl(pidl, afile2W);
4217 /* set FIND_DATA struct to NULLs */
4218 pidl = (ITEMIDLIST*)0xdeadbeef;
4219 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4220 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4221 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4222 "ParseDisplayName failed: 0x%08x\n", hres);
4223 if(SUCCEEDED(hres)){
4224 verify_pidl(pidl, adirW);
4228 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4229 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4230 "ParseDisplayName failed: 0x%08x\n", hres);
4231 if(SUCCEEDED(hres)){
4232 verify_pidl(pidl, afileW);
4236 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4237 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4238 "ParseDisplayName failed: 0x%08x\n", hres);
4239 if(SUCCEEDED(hres)){
4240 verify_pidl(pidl, afile2W);
4244 /* set FIND_DATA struct to junk */
4245 pidl = (ITEMIDLIST*)0xdeadbeef;
4246 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4247 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4248 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4249 "ParseDisplayName failed: 0x%08x\n", hres);
4250 if(SUCCEEDED(hres)){
4251 verify_pidl(pidl, adirW);
4255 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4256 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4257 "ParseDisplayName failed: 0x%08x\n", hres);
4258 if(SUCCEEDED(hres)){
4259 verify_pidl(pidl, afileW);
4263 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4264 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4265 "ParseDisplayName failed: 0x%08x\n", hres);
4266 if(SUCCEEDED(hres)){
4267 verify_pidl(pidl, afile2W);
4271 /* set FIND_DATA struct to invalid data */
4272 pidl = (ITEMIDLIST*)0xdeadbeef;
4273 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4274 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4275 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4276 "ParseDisplayName failed: 0x%08x\n", hres);
4277 if(SUCCEEDED(hres)){
4278 verify_pidl(pidl, adirW);
4282 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4283 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4284 "ParseDisplayName failed: 0x%08x\n", hres);
4285 if(SUCCEEDED(hres)){
4286 verify_pidl(pidl, afileW);
4290 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4291 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4292 "ParseDisplayName failed: 0x%08x\n", hres);
4293 if(SUCCEEDED(hres)){
4294 verify_pidl(pidl, afile2W);
4298 /* set FIND_DATA struct to valid data */
4299 pidl = (ITEMIDLIST*)0xdeadbeef;
4300 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4301 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4302 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4303 "ParseDisplayName failed: 0x%08x\n", hres);
4304 if(SUCCEEDED(hres)){
4305 verify_pidl(pidl, adirW);
4309 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4310 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4311 "ParseDisplayName failed: 0x%08x\n", hres);
4312 if(SUCCEEDED(hres)){
4313 verify_pidl(pidl, afileW);
4317 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4318 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4319 "ParseDisplayName failed: 0x%08x\n", hres);
4320 if(SUCCEEDED(hres)){
4321 verify_pidl(pidl, afile2W);
4325 IBindCtx_Release(pbc);
4326 IShellFolder_Release(psf);
4329 static const CHAR testwindow_class[] = "testwindow";
4330 #define WM_USER_NOTIFY (WM_APP+1)
4332 struct ChNotifyTest {
4334 const UINT notify_count;
4335 UINT missing_events;
4337 const char path_1[256];
4338 const char path_2[256];
4339 } chnotify_tests[] = {
4340 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4341 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4342 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4345 struct ChNotifyTest *exp_data;
4347 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4349 UINT signal = (UINT)lparam;
4352 case WM_USER_NOTIFY:
4353 if(exp_data->missing_events > 0){
4354 WCHAR *path1, *path2;
4355 LPCITEMIDLIST *pidls = (LPCITEMIDLIST*)wparam;
4357 ok(exp_data->signal == signal,
4358 "%s: expected notification type %x, got: %x\n",
4359 exp_data->id, exp_data->signal, signal);
4361 trace("verifying pidls for: %s\n", exp_data->id);
4362 path1 = make_wstr(exp_data->path_1);
4363 path2 = make_wstr(exp_data->path_2);
4364 verify_pidl(pidls[0], path1);
4365 verify_pidl(pidls[1], path2);
4366 HeapFree(GetProcessHeap(), 0, path1);
4367 HeapFree(GetProcessHeap(), 0, path2);
4369 exp_data->missing_events--;
4371 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4374 return DefWindowProc(hwnd, msg, wparam, lparam);
4377 static void register_testwindow_class(void)
4382 ZeroMemory(&cls, sizeof(cls));
4383 cls.cbSize = sizeof(cls);
4385 cls.lpfnWndProc = testwindow_wndproc;
4386 cls.hInstance = GetModuleHandleA(NULL);
4387 cls.lpszClassName = testwindow_class;
4390 ret = RegisterClassExA(&cls);
4391 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4394 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4395 * have to poll repeatedly for the message to appear */
4396 static void do_events(void)
4399 while (exp_data->missing_events && (c++ < 10)){
4401 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4402 TranslateMessage(&msg);
4403 DispatchMessageA(&msg);
4405 if(exp_data->missing_events)
4408 trace("%s: took %d tries\n", exp_data->id, c);
4411 static void test_SHChangeNotify(void)
4416 BOOL br, has_unicode;
4417 SHChangeNotifyEntry entries[1];
4418 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4419 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4421 CreateDirectoryW(NULL, NULL);
4422 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4424 register_testwindow_class();
4426 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4427 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4428 NULL, NULL, GetModuleHandleA(NULL), 0);
4429 ok(wnd != NULL, "Failed to make a window\n");
4431 br = CreateDirectoryA(root_dirA, NULL);
4432 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4434 entries[0].pidl = NULL;
4436 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4438 hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4439 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4440 entries[0].fRecursive = TRUE;
4442 notifyID = SHChangeNotifyRegister(wnd, SHCNRF_ShellLevel,
4443 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4444 ok(notifyID != 0, "Failed to register a window for change notifications\n");
4446 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
4447 exp_data = chnotify_tests + i;
4449 exp_data->missing_events = exp_data->notify_count;
4450 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4451 strlen(exp_data->path_1) > 0 ? exp_data->path_1 : NULL,
4452 strlen(exp_data->path_2) > 0 ? exp_data->path_2 : NULL);
4454 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4457 WCHAR *path1, *path2;
4459 path1 = make_wstr(exp_data->path_1);
4460 path2 = make_wstr(exp_data->path_2);
4462 exp_data->missing_events = exp_data->notify_count;
4463 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
4465 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4467 HeapFree(GetProcessHeap(), 0, path1);
4468 HeapFree(GetProcessHeap(), 0, path2);
4472 SHChangeNotifyDeregister(notifyID);
4475 ILFree((LPITEMIDLIST)entries[0].pidl);
4476 br = RemoveDirectoryA(root_dirA);
4477 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4480 static void test_SHCreateDefaultContextMenu(void)
4483 WCHAR path[MAX_PATH];
4484 IShellFolder *desktop,*folder;
4485 IPersistFolder2 *persist;
4486 IContextMenu *cmenu;
4488 LPITEMIDLIST pidlFolder, pidl_child, pidl;
4489 DEFCONTEXTMENU cminfo;
4492 const WCHAR filename[] =
4493 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4494 if(!pSHCreateDefaultContextMenu)
4496 win_skip("SHCreateDefaultContextMenu missing.\n");
4500 if(!pSHBindToParent)
4502 skip("SHBindToParent missing.\n");
4506 GetCurrentDirectoryW(MAX_PATH, path);
4509 skip("GetCurrentDirectoryW returned an empty string.\n");
4512 lstrcatW(path, filename);
4513 SHGetDesktopFolder(&desktop);
4515 CreateFilesFolders();
4517 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &pidl, 0);
4518 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
4522 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&folder, (LPCITEMIDLIST*)&pidl_child);
4523 ok(hr == S_OK, "Got 0x%08x\n", hr);
4525 IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
4526 IPersistFolder2_GetCurFolder(persist,&pidlFolder);
4527 IPersistFolder2_Release(persist);
4534 cminfo.pidlFolder=NULL;
4535 cminfo.apidl=(LPCITEMIDLIST*)&pidl_child;
4539 cminfo.punkAssociationInfo=NULL;
4540 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
4541 ok(hr==S_OK,"Got 0x%08x\n", hr);
4542 IContextMenu_Release(cmenu);
4543 cminfo.pidlFolder=pidlFolder;
4544 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
4545 ok(hr==S_OK,"Got 0x%08x\n", hr);
4546 IContextMenu_Release(cmenu);
4547 status = RegOpenKeyExA(HKEY_CLASSES_ROOT,"*",0,KEY_READ,keys);
4548 if(status==ERROR_SUCCESS){
4553 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
4554 RegCloseKey(keys[0]);
4555 ok(hr==S_OK,"Got 0x%08x\n", hr);
4556 IContextMenu_Release(cmenu);
4560 IShellFolder_Release(folder);
4562 IShellFolder_Release(desktop);
4567 START_TEST(shlfolder)
4569 init_function_pointers();
4570 /* if OleInitialize doesn't get called, ParseDisplayName returns
4571 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4572 OleInitialize(NULL);
4574 test_ParseDisplayName();
4575 test_SHParseDisplayName();
4576 test_BindToObject();
4577 test_EnumObjects_and_CompareIDs();
4578 test_GetDisplayName();
4579 test_GetAttributesOf();
4580 test_SHGetPathFromIDList();
4581 test_CallForAttributes();
4582 test_FolderShortcut();
4583 test_ITEMIDLIST_format();
4584 test_SHGetFolderPathA();
4585 test_SHGetFolderPathAndSubDirA();
4586 test_LocalizedNames();
4587 test_SHCreateShellItem();
4588 test_SHCreateShellItemArray();
4589 test_desktop_IPersist();
4591 test_SHSimpleIDListFromPath();
4592 test_ParseDisplayNamePBC();
4593 test_SHGetNameFromIDList();
4594 test_SHGetItemFromDataObject();
4595 test_SHGetIDListFromObject();
4596 test_SHGetItemFromObject();
4597 test_ShellItemCompare();
4598 test_SHChangeNotify();
4599 test_ShellItemBindToHandler();
4600 test_ShellItemGetAttributes();
4601 test_SHCreateDefaultContextMenu();