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);
74 static WCHAR *make_wstr(const char *str)
79 if(!str || strlen(str) == 0)
82 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
86 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
90 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
94 static int strcmp_wa(LPCWSTR strw, const char *stra)
97 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
98 return lstrcmpA(stra, buf);
101 static void init_function_pointers(void)
107 hmod = GetModuleHandleA("shell32.dll");
109 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
110 MAKEFUNC(SHBindToParent);
111 MAKEFUNC(SHCreateItemFromIDList);
112 MAKEFUNC(SHCreateItemFromParsingName);
113 MAKEFUNC(SHCreateShellItem);
114 MAKEFUNC(SHCreateShellItemArray);
115 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
116 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
117 MAKEFUNC(SHGetFolderPathA);
118 MAKEFUNC(SHGetFolderPathAndSubDirA);
119 MAKEFUNC(SHGetPathFromIDListW);
120 MAKEFUNC(SHGetSpecialFolderPathA);
121 MAKEFUNC(SHGetSpecialFolderPathW);
122 MAKEFUNC(SHGetSpecialFolderLocation);
123 MAKEFUNC(SHParseDisplayName);
124 MAKEFUNC(SHGetNameFromIDList);
125 MAKEFUNC(SHGetItemFromDataObject);
126 MAKEFUNC(SHGetIDListFromObject);
127 MAKEFUNC(SHGetItemFromObject);
130 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
131 MAKEFUNC_ORD(ILFindLastID, 16);
132 MAKEFUNC_ORD(ILIsEqual, 21);
133 MAKEFUNC_ORD(ILCombine, 25);
134 MAKEFUNC_ORD(ILFree, 155);
135 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
138 /* test named exports */
139 ptr = GetProcAddress(hmod, "ILFree");
140 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
143 #define TESTNAMED(f) \
144 ptr = (void*)GetProcAddress(hmod, #f); \
145 ok(ptr != 0, "expected named export for " #f "\n");
147 TESTNAMED(ILAppendID);
149 TESTNAMED(ILCloneFirst);
150 TESTNAMED(ILCombine);
151 TESTNAMED(ILCreateFromPath);
152 TESTNAMED(ILCreateFromPathA);
153 TESTNAMED(ILCreateFromPathW);
154 TESTNAMED(ILFindChild);
155 TESTNAMED(ILFindLastID);
156 TESTNAMED(ILGetNext);
157 TESTNAMED(ILGetSize);
158 TESTNAMED(ILIsEqual);
159 TESTNAMED(ILIsParent);
160 TESTNAMED(ILRemoveLastID);
161 TESTNAMED(ILSaveToStream);
165 hmod = GetModuleHandleA("shlwapi.dll");
166 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
168 pIsWow64Process = (void*)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
170 hr = SHGetMalloc(&ppM);
171 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
174 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
175 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
179 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
185 if (lpszPath[-1] != '\\')
194 static void test_ParseDisplayName(void)
197 IShellFolder *IDesktopFolder;
198 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
199 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
200 static const char *cInetTestA = "http:\\yyy";
201 static const char *cInetTest2A = "xx:yyy";
203 WCHAR cTestDirW [MAX_PATH] = {0};
207 hr = SHGetDesktopFolder(&IDesktopFolder);
208 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
209 if(hr != S_OK) return;
211 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
212 if (pSHCreateShellItem)
214 /* null name and pidl */
215 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
216 NULL, NULL, NULL, NULL, NULL, 0);
217 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
220 newPIDL = (ITEMIDLIST*)0xdeadbeef;
221 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
222 NULL, NULL, NULL, NULL, &newPIDL, 0);
223 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
224 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
227 win_skip("Tests would crash on W2K and below\n");
229 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
230 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
231 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
232 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
233 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
236 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
237 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
238 IMalloc_Free(ppM, newPIDL);
241 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
242 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
243 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
244 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
245 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
248 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
249 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
250 IMalloc_Free(ppM, newPIDL);
253 res = GetFileAttributesA(cNonExistDir1A);
254 if(res != INVALID_FILE_ATTRIBUTES)
256 skip("Test directory unexpectedly exists\n");
260 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
261 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
262 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
263 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
264 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
266 res = GetFileAttributesA(cNonExistDir2A);
267 if(res != INVALID_FILE_ATTRIBUTES)
269 skip("Test directory unexpectedly exists\n");
273 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
274 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
275 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
276 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
277 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
279 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
280 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
281 * out it doesn't. The magic seems to happen in the file dialogs, then. */
282 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
284 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
288 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
289 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
290 if (!bRes) goto finished;
292 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
293 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
294 if (hr != S_OK) goto finished;
296 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
297 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
298 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
299 pILFindLastID(newPIDL)->mkid.abID[0]);
300 IMalloc_Free(ppM, newPIDL);
303 IShellFolder_Release(IDesktopFolder);
306 /* creates a file with the specified name for tests */
307 static void CreateTestFile(const CHAR *name)
312 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
313 if (file != INVALID_HANDLE_VALUE)
315 WriteFile(file, name, strlen(name), &written, NULL);
316 WriteFile(file, "\n", strlen("\n"), &written, NULL);
322 /* initializes the tests */
323 static void CreateFilesFolders(void)
325 CreateDirectoryA(".\\testdir", NULL);
326 CreateDirectoryA(".\\testdir\\test.txt", NULL);
327 CreateTestFile (".\\testdir\\test1.txt ");
328 CreateTestFile (".\\testdir\\test2.txt ");
329 CreateTestFile (".\\testdir\\test3.txt ");
330 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
331 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
334 /* cleans after tests */
335 static void Cleanup(void)
337 DeleteFileA(".\\testdir\\test1.txt");
338 DeleteFileA(".\\testdir\\test2.txt");
339 DeleteFileA(".\\testdir\\test3.txt");
340 RemoveDirectoryA(".\\testdir\\test.txt");
341 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
342 RemoveDirectoryA(".\\testdir\\testdir2");
343 RemoveDirectoryA(".\\testdir");
348 static void test_EnumObjects(IShellFolder *iFolder)
350 IEnumIDList *iEnumList;
351 LPITEMIDLIST newPIDL, idlArr[10];
356 static const WORD iResults [5][5] =
365 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
366 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
367 static const ULONG attrs[5] =
369 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
370 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
371 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
372 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
373 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
376 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
377 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
379 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
380 * the filesystem shellfolders return S_OK even if less than 'celt' items are
381 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
382 * only ever returns a single entry per call. */
383 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
385 ok (i == 5, "i: %d\n", i);
387 hr = IEnumIDList_Release(iEnumList);
388 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
390 /* Sort them first in case of wrong order from system */
391 for (i=0;i<5;i++) for (j=0;j<5;j++)
392 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
395 idlArr[i] = idlArr[j];
399 for (i=0;i<5;i++) for (j=0;j<5;j++)
401 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
402 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
406 for (i = 0; i < 5; i++)
409 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
410 /* Native returns all flags no matter what we ask for */
411 flags = SFGAO_CANCOPY;
412 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
413 flags &= SFGAO_testfor;
414 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
415 ok(flags == (attrs[i]) ||
416 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
417 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
418 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
420 flags = SFGAO_testfor;
421 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
422 flags &= SFGAO_testfor;
423 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
424 ok(flags == attrs[i] ||
425 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
426 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
430 IMalloc_Free(ppM, idlArr[i]);
433 static void test_BindToObject(void)
437 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
438 SHITEMID emptyitem = { 0, { 0 } };
439 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
440 WCHAR wszSystemDir[MAX_PATH];
441 char szSystemDir[MAX_PATH];
444 WCHAR path[MAX_PATH];
446 WCHAR wszMyComputer[] = {
447 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
448 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
449 static const WCHAR filename_html[] = {'w','i','n','e','t','e','s','t','.','h','t','m','l',0};
450 static const WCHAR filename_txt[] = {'w','i','n','e','t','e','s','t','.','t','x','t',0};
451 static const WCHAR filename_foo[] = {'w','i','n','e','t','e','s','t','.','f','o','o',0};
453 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
454 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
456 hr = SHGetDesktopFolder(&psfDesktop);
457 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
458 if (hr != S_OK) return;
460 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
461 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
463 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
464 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
466 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
467 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
469 IShellFolder_Release(psfDesktop);
473 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
474 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
475 IShellFolder_Release(psfDesktop);
476 IMalloc_Free(ppM, pidlMyComputer);
477 if (hr != S_OK) return;
479 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
480 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
484 /* this call segfaults on 98SE */
485 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
486 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
489 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
490 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
491 if (cChars == 0 || cChars >= MAX_PATH) {
492 IShellFolder_Release(psfMyComputer);
495 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
497 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
498 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
500 IShellFolder_Release(psfMyComputer);
504 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
505 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
506 IShellFolder_Release(psfMyComputer);
507 IMalloc_Free(ppM, pidlSystemDir);
508 if (hr != S_OK) return;
510 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
511 ok (hr == E_INVALIDARG,
512 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
516 /* this call segfaults on 98SE */
517 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
518 ok (hr == E_INVALIDARG,
519 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
522 IShellFolder_Release(psfSystemDir);
524 GetCurrentDirectoryA(MAX_PATH, buf);
527 skip("Failed to get current directory, skipping tests.\n");
530 MultiByteToWideChar(CP_ACP, 0, buf, -1, cwd, MAX_PATH);
532 SHGetDesktopFolder(&psfDesktop);
534 /* Attempt BindToObject on files. */
538 myPathAddBackslashW(path);
539 lstrcatW(path, filename_html);
540 hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
541 if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
544 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
546 broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */ ||
547 broken(hr == E_FAIL) /* Win95 */,
551 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
552 ok(hr == S_OK /* Win 7 */ || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) /* WinXP */,
557 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
558 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* W2K */, "Got 0x%08x\n", hr);
562 hr = IPersist_GetClassID(pp, &id);
563 ok(hr == S_OK, "Got 0x%08x\n", hr);
564 ok(IsEqualIID(&id, &CLSID_ShellDocObjView), "Unexpected classid\n");
565 IPersist_Release(pp);
568 IShellFolder_Release(psfChild);
575 win_skip("Failed to create .html testfile.\n");
579 myPathAddBackslashW(path);
580 lstrcatW(path, filename_txt);
581 hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
582 if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
585 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
587 broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */ ||
588 broken(hr == E_FAIL) /* Win95 */,
592 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
593 ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
594 || broken(hr == S_OK) /* W2K */,
596 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
602 win_skip("Failed to create .txt testfile.\n");
606 myPathAddBackslashW(path);
607 lstrcatW(path, filename_foo);
608 hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
609 if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
612 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
614 broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */ ||
615 broken(hr == E_FAIL) /* Win95 */,
619 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
620 ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
621 || broken(hr == S_OK) /* W2K */,
623 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
629 win_skip("Failed to create .foo testfile.\n");
631 /* And on the desktop */
632 if(pSHGetSpecialFolderPathW)
635 pSHGetSpecialFolderPathW(NULL, path, CSIDL_DESKTOP, FALSE);
636 myPathAddBackslashW(path);
637 lstrcatW(path, filename_html);
638 hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
639 if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
642 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
643 ok(hr == S_OK || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */,
647 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
648 ok(hr == S_OK || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
650 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
653 if(!DeleteFileW(path))
654 trace("Failed to delete: %d\n", GetLastError());
658 win_skip("Failed to create .html testfile.\n");
660 pSHGetSpecialFolderPathW(NULL, path, CSIDL_DESKTOP, FALSE);
661 myPathAddBackslashW(path);
662 lstrcatW(path, filename_foo);
663 hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
664 if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
667 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
668 ok(hr == S_OK || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */,
672 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
673 ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
674 || broken(hr == S_OK) /* W2K */,
676 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
682 win_skip("Failed to create .foo testfile.\n");
685 IShellFolder_Release(psfDesktop);
688 static void test_GetDisplayName(void)
693 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
694 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
697 LPSHELLFOLDER psfDesktop, psfPersonal;
699 SHITEMID emptyitem = { 0, { 0 } };
700 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
701 LPCITEMIDLIST pidlLast;
702 static const CHAR szFileName[] = "winetest.foo";
703 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
704 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
706 /* I'm trying to figure if there is a functional difference between calling
707 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
708 * binding to the shellfolder. One thing I thought of was that perhaps
709 * SHGetPathFromIDListW would be able to get the path to a file, which does
710 * not exist anymore, while the other method wouldn't. It turns out there's
711 * no functional difference in this respect.
714 if(!pSHGetSpecialFolderPathA) {
715 win_skip("SHGetSpecialFolderPathA is not available\n");
719 /* First creating a directory in MyDocuments and a file in this directory. */
720 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
721 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
724 /* Use ANSI file functions so this works on Windows 9x */
725 lstrcatA(szTestDir, "\\winetest");
726 CreateDirectoryA(szTestDir, NULL);
727 attr=GetFileAttributesA(szTestDir);
728 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
730 ok(0, "unable to create the '%s' directory\n", szTestDir);
734 lstrcpyA(szTestFile, szTestDir);
735 lstrcatA(szTestFile, "\\");
736 lstrcatA(szTestFile, szFileName);
737 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
738 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
739 if (hTestFile == INVALID_HANDLE_VALUE) return;
740 CloseHandle(hTestFile);
742 /* Getting an itemidlist for the file. */
743 hr = SHGetDesktopFolder(&psfDesktop);
744 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
745 if (hr != S_OK) return;
747 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
749 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
750 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
752 IShellFolder_Release(psfDesktop);
756 pidlLast = pILFindLastID(pidlTestFile);
757 ok(pidlLast->mkid.cb >=76 ||
758 broken(pidlLast->mkid.cb == 28) || /* W2K */
759 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
760 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
761 if (pidlLast->mkid.cb >= 28) {
762 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
763 "Filename should be stored as ansi-string at this position!\n");
765 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
766 if (pidlLast->mkid.cb >= 76) {
767 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
768 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
769 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
770 "Filename should be stored as wchar-string at this position!\n");
773 /* It seems as if we cannot bind to regular files on windows, but only directories.
775 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
776 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
777 hr == E_NOTIMPL || /* Vista */
778 broken(hr == S_OK), /* Win9x, W2K */
781 IShellFolder_Release(psfFile);
784 if (!pSHBindToParent)
786 win_skip("SHBindToParent is missing\n");
787 DeleteFileA(szTestFile);
788 RemoveDirectoryA(szTestDir);
792 /* Some tests for IShellFolder::SetNameOf */
793 if (pSHGetFolderPathAndSubDirA)
795 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
796 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
798 /* It's ok to use this fixed path. Call will fail anyway. */
799 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
800 LPITEMIDLIST pidlNew;
802 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
803 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
804 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
807 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
808 "pidl returned from SetNameOf should be simple!\n");
810 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
811 * is implemented on top of SHFileOperation in WinXP. */
812 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
813 SHGDN_FORPARSING, NULL);
814 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
816 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
817 * SHGDN flags specify an absolute path. */
818 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
819 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
824 IShellFolder_Release(psfPersonal);
828 win_skip("Avoid needs of interaction on Win2k\n");
830 /* Deleting the file and the directory */
831 DeleteFileA(szTestFile);
832 RemoveDirectoryA(szTestDir);
834 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
835 if (pSHGetPathFromIDListW)
837 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
838 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
839 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
842 /* SHBindToParent fails, if called with a NULL PIDL. */
843 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
844 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
846 /* But it succeeds with an empty PIDL. */
847 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
848 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
849 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
851 IShellFolder_Release(psfPersonal);
853 /* Binding to the folder and querying the display name of the file also works. */
854 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
855 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
857 IShellFolder_Release(psfDesktop);
861 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
862 * pidlTestFile (In accordance with MSDN). */
863 ok (pILFindLastID(pidlTestFile) == pidlLast,
864 "SHBindToParent doesn't return the last id of the pidl param!\n");
866 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
867 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
869 IShellFolder_Release(psfDesktop);
870 IShellFolder_Release(psfPersonal);
876 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
877 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
878 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
881 ILFree(pidlTestFile);
882 IShellFolder_Release(psfDesktop);
883 IShellFolder_Release(psfPersonal);
886 static void test_CallForAttributes(void)
892 LPSHELLFOLDER psfDesktop;
893 LPITEMIDLIST pidlMyDocuments;
894 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
895 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
896 static const WCHAR wszCallForAttributes[] = {
897 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
898 static const WCHAR wszMyDocumentsKey[] = {
899 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
900 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
901 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
902 WCHAR wszMyDocuments[] = {
903 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
904 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
906 /* For the root of a namespace extension, the attributes are not queried by binding
907 * to the object and calling GetAttributesOf. Instead, the attributes are read from
908 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
910 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
911 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
912 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
913 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
915 hr = SHGetDesktopFolder(&psfDesktop);
916 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
917 if (hr != S_OK) return;
919 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
920 &pidlMyDocuments, NULL);
922 broken(hr == E_INVALIDARG), /* Win95, NT4 */
923 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
925 IShellFolder_Release(psfDesktop);
929 dwAttributes = 0xffffffff;
930 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
931 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
932 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
934 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
935 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
936 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
937 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
939 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
940 * key. So the test will return at this point, if run on wine.
942 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
943 ok (lResult == ERROR_SUCCESS ||
944 lResult == ERROR_ACCESS_DENIED,
945 "RegOpenKeyEx failed! result: %08x\n", lResult);
946 if (lResult != ERROR_SUCCESS) {
947 if (lResult == ERROR_ACCESS_DENIED)
948 skip("Not enough rights to open the registry key\n");
949 IMalloc_Free(ppM, pidlMyDocuments);
950 IShellFolder_Release(psfDesktop);
954 /* Query MyDocuments' Attributes value, to be able to restore it later. */
955 dwSize = sizeof(DWORD);
956 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
957 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
958 if (lResult != ERROR_SUCCESS) {
960 IMalloc_Free(ppM, pidlMyDocuments);
961 IShellFolder_Release(psfDesktop);
965 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
966 dwSize = sizeof(DWORD);
967 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
968 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
969 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
970 if (lResult != ERROR_SUCCESS) {
972 IMalloc_Free(ppM, pidlMyDocuments);
973 IShellFolder_Release(psfDesktop);
977 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
978 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
979 * SFGAO_FILESYSTEM attributes. */
980 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
981 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
982 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
983 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
984 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
986 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
987 * GetAttributesOf. It seems that once there is a single attribute queried, for which
988 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
989 * the flags in Attributes are ignored.
991 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
992 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
993 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
994 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
996 ok (dwAttributes == SFGAO_FILESYSTEM,
997 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
1000 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
1001 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
1002 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1003 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
1005 IMalloc_Free(ppM, pidlMyDocuments);
1006 IShellFolder_Release(psfDesktop);
1009 static void test_GetAttributesOf(void)
1012 LPSHELLFOLDER psfDesktop, psfMyComputer;
1013 SHITEMID emptyitem = { 0, { 0 } };
1014 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1015 LPITEMIDLIST pidlMyComputer;
1017 static const DWORD desktopFlags[] = {
1019 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
1020 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1022 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
1023 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1024 /* WinMe, Win9x, WinNT*/
1025 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
1026 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1028 static const DWORD myComputerFlags[] = {
1030 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
1031 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1033 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
1034 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1035 /* WinMe, Win9x, WinNT */
1036 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1037 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1038 /* Win95, WinNT when queried directly */
1039 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1040 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1042 WCHAR wszMyComputer[] = {
1043 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1044 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1045 char cCurrDirA [MAX_PATH] = {0};
1046 WCHAR cCurrDirW [MAX_PATH];
1047 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
1048 IShellFolder *IDesktopFolder, *testIShellFolder;
1049 ITEMIDLIST *newPIDL;
1051 BOOL foundFlagsMatch;
1053 hr = SHGetDesktopFolder(&psfDesktop);
1054 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1055 if (hr != S_OK) return;
1057 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
1058 dwFlags = 0xffffffff;
1059 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
1060 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
1061 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1062 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1064 if (desktopFlags[i] == dwFlags)
1065 foundFlagsMatch = TRUE;
1067 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1069 /* .. or with no itemidlist at all. */
1070 dwFlags = 0xffffffff;
1071 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
1072 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1073 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1074 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1076 if (desktopFlags[i] == dwFlags)
1077 foundFlagsMatch = TRUE;
1079 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1081 /* Testing the attributes of the MyComputer shellfolder */
1082 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1083 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1085 IShellFolder_Release(psfDesktop);
1089 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
1090 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
1092 dwFlags = 0xffffffff;
1093 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
1094 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
1095 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1096 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1098 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
1099 foundFlagsMatch = TRUE;
1102 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1104 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
1105 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
1106 IShellFolder_Release(psfDesktop);
1107 IMalloc_Free(ppM, pidlMyComputer);
1108 if (hr != S_OK) return;
1110 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
1112 ok (hr == E_INVALIDARG ||
1113 broken(hr == S_OK), /* W2K and earlier */
1114 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
1116 dwFlags = 0xffffffff;
1117 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
1118 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1119 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1120 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1122 if (myComputerFlags[i] == dwFlags)
1123 foundFlagsMatch = TRUE;
1126 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1128 IShellFolder_Release(psfMyComputer);
1130 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1131 len = lstrlenA(cCurrDirA);
1134 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1137 if (len > 3 && cCurrDirA[len-1] == '\\')
1138 cCurrDirA[len-1] = 0;
1140 /* create test directory */
1141 CreateFilesFolders();
1143 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1145 hr = SHGetDesktopFolder(&IDesktopFolder);
1146 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1148 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1149 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1151 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1152 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1154 IMalloc_Free(ppM, newPIDL);
1156 /* get relative PIDL */
1157 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1158 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1160 /* test the shell attributes of the test directory using the relative PIDL */
1161 dwFlags = SFGAO_FOLDER;
1162 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1163 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1164 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1167 IMalloc_Free(ppM, newPIDL);
1169 /* append testdirectory name to path */
1170 if (cCurrDirA[len-1] == '\\')
1171 cCurrDirA[len-1] = 0;
1172 lstrcatA(cCurrDirA, "\\testdir");
1173 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1175 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1176 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1178 /* test the shell attributes of the test directory using the absolute PIDL */
1179 dwFlags = SFGAO_FOLDER;
1180 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1181 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1182 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1185 IMalloc_Free(ppM, newPIDL);
1187 IShellFolder_Release(testIShellFolder);
1191 IShellFolder_Release(IDesktopFolder);
1194 static void test_SHGetPathFromIDList(void)
1196 SHITEMID emptyitem = { 0, { 0 } };
1197 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1198 LPITEMIDLIST pidlMyComputer;
1199 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1202 LPSHELLFOLDER psfDesktop;
1203 WCHAR wszMyComputer[] = {
1204 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1205 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1206 WCHAR wszFileName[MAX_PATH];
1207 LPITEMIDLIST pidlTestFile;
1210 static WCHAR wszTestFile[] = {
1211 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1212 LPITEMIDLIST pidlPrograms;
1214 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1216 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1220 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1223 result = pSHGetPathFromIDListW(NULL, wszPath);
1224 ok(!result, "Expected failure\n");
1225 ok(!wszPath[0], "Expected empty string\n");
1227 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1228 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1229 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1230 if (!result) return;
1232 /* Check if we are on Win9x */
1233 SetLastError(0xdeadbeef);
1234 lstrcmpiW(wszDesktop, wszDesktop);
1235 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1237 win_skip("Most W-calls are not implemented\n");
1241 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1242 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1243 if (!result) return;
1244 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1246 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1247 hr = SHGetDesktopFolder(&psfDesktop);
1248 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1249 if (hr != S_OK) return;
1251 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1252 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1254 IShellFolder_Release(psfDesktop);
1258 SetLastError(0xdeadbeef);
1261 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1262 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1263 ok (GetLastError()==0xdeadbeef ||
1264 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1265 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1266 ok (!wszPath[0], "Expected empty path\n");
1268 IShellFolder_Release(psfDesktop);
1272 IMalloc_Free(ppM, pidlMyComputer);
1274 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1275 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1277 IShellFolder_Release(psfDesktop);
1280 myPathAddBackslashW(wszFileName);
1281 lstrcatW(wszFileName, wszTestFile);
1282 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1283 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1284 if (hTestFile == INVALID_HANDLE_VALUE) {
1285 IShellFolder_Release(psfDesktop);
1288 CloseHandle(hTestFile);
1290 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1291 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1293 IShellFolder_Release(psfDesktop);
1294 DeleteFileW(wszFileName);
1295 IMalloc_Free(ppM, pidlTestFile);
1299 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1300 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1301 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1302 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1303 IShellFolder_Release(psfDesktop);
1304 DeleteFileW(wszFileName);
1306 IMalloc_Free(ppM, pidlTestFile);
1311 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1312 ok(0 == lstrcmpW(wszFileName, wszPath),
1313 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1314 "returned incorrect path for file placed on desktop\n");
1317 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1318 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1319 IMalloc_Free(ppM, pidlTestFile);
1320 if (!result) return;
1321 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1324 /* Test if we can get the path from the start menu "program files" PIDL. */
1325 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1326 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1328 SetLastError(0xdeadbeef);
1329 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1330 IMalloc_Free(ppM, pidlPrograms);
1331 ok(result, "SHGetPathFromIDListW failed\n");
1334 static void test_EnumObjects_and_CompareIDs(void)
1336 ITEMIDLIST *newPIDL;
1337 IShellFolder *IDesktopFolder, *testIShellFolder;
1338 char cCurrDirA [MAX_PATH] = {0};
1339 static const CHAR cTestDirA[] = "\\testdir";
1340 WCHAR cTestDirW[MAX_PATH];
1344 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1345 len = lstrlenA(cCurrDirA);
1348 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1351 if(cCurrDirA[len-1] == '\\')
1352 cCurrDirA[len-1] = 0;
1354 lstrcatA(cCurrDirA, cTestDirA);
1355 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1357 hr = SHGetDesktopFolder(&IDesktopFolder);
1358 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1360 CreateFilesFolders();
1362 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1363 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1365 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1366 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1368 test_EnumObjects(testIShellFolder);
1370 IShellFolder_Release(testIShellFolder);
1374 IMalloc_Free(ppM, newPIDL);
1376 IShellFolder_Release(IDesktopFolder);
1379 /* A simple implementation of an IPropertyBag, which returns fixed values for
1380 * 'Target' and 'Attributes' properties.
1382 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1386 return E_INVALIDARG;
1388 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1391 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1392 return E_NOINTERFACE;
1395 IPropertyBag_AddRef(iface);
1399 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1403 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1407 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1408 VARIANT *pVar, IErrorLog *pErrorLog)
1410 static const WCHAR wszTargetSpecialFolder[] = {
1411 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1412 static const WCHAR wszTarget[] = {
1413 'T','a','r','g','e','t',0 };
1414 static const WCHAR wszAttributes[] = {
1415 'A','t','t','r','i','b','u','t','e','s',0 };
1416 static const WCHAR wszResolveLinkFlags[] = {
1417 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1418 static const WCHAR wszTargetKnownFolder[] = {
1419 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1420 static const WCHAR wszCLSID[] = {
1421 'C','L','S','I','D',0 };
1423 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1424 ok(V_VT(pVar) == VT_I4 ||
1425 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1426 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1427 return E_INVALIDARG;
1430 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1432 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1433 return E_INVALIDARG;
1436 if (!lstrcmpW(pszPropName, wszTarget)) {
1437 WCHAR wszPath[MAX_PATH];
1440 ok(V_VT(pVar) == VT_BSTR ||
1441 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1442 "Wrong variant type for 'Target' property!\n");
1443 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1445 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1446 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1447 if (!result) return E_INVALIDARG;
1449 V_BSTR(pVar) = SysAllocString(wszPath);
1453 if (!lstrcmpW(pszPropName, wszAttributes)) {
1454 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1455 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1456 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1457 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1461 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1462 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1464 return E_INVALIDARG;
1467 if (!lstrcmpW(pszPropName, wszCLSID)) {
1468 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1470 return E_INVALIDARG;
1473 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1474 return E_INVALIDARG;
1477 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1480 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1484 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1485 InitPropertyBag_IPropertyBag_QueryInterface,
1486 InitPropertyBag_IPropertyBag_AddRef,
1487 InitPropertyBag_IPropertyBag_Release,
1488 InitPropertyBag_IPropertyBag_Read,
1489 InitPropertyBag_IPropertyBag_Write
1492 static struct IPropertyBag InitPropertyBag = {
1493 &InitPropertyBag_IPropertyBagVtbl
1496 static void test_FolderShortcut(void) {
1497 IPersistPropertyBag *pPersistPropertyBag;
1498 IShellFolder *pShellFolder, *pDesktopFolder;
1499 IPersistFolder3 *pPersistFolder3;
1502 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1505 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1507 WCHAR wszWineTestFolder[] = {
1508 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1509 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1510 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1511 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1512 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1513 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1514 'N','a','m','e','S','p','a','c','e','\\',
1515 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1516 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1518 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1519 static const GUID CLSID_UnixDosFolder =
1520 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1522 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1523 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1527 if (!pSHGetFolderPathAndSubDirA)
1529 win_skip("FolderShortcut test doesn't work on Win2k\n");
1533 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1534 * via their IPersistPropertyBag interface. And that the target folder
1535 * is taken from the IPropertyBag's 'Target' property.
1537 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1538 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1539 if (hr == REGDB_E_CLASSNOTREG) {
1540 win_skip("CLSID_FolderShortcut is not implemented\n");
1543 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1544 if (hr != S_OK) return;
1546 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1547 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1549 IPersistPropertyBag_Release(pPersistPropertyBag);
1553 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1554 (LPVOID*)&pShellFolder);
1555 IPersistPropertyBag_Release(pPersistPropertyBag);
1556 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1557 if (hr != S_OK) return;
1559 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1560 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1562 IShellFolder_Release(pShellFolder);
1566 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1567 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1568 if (!result) return;
1570 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1571 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1573 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1574 IShellFolder_Release(pShellFolder);
1575 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1576 if (hr != S_OK) return;
1578 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1579 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1580 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1582 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1583 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1584 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1586 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1587 * shell namespace. The target folder, read from the property bag above, remains untouched.
1588 * The following tests show this: The itemidlist for some imaginary shellfolder object
1589 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1590 * itemidlist, but GetDisplayNameOf still returns the path from above.
1592 hr = SHGetDesktopFolder(&pDesktopFolder);
1593 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1594 if (hr != S_OK) return;
1596 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1597 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1598 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1599 RegCloseKey(hShellExtKey);
1600 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1601 &pidlWineTestFolder, NULL);
1602 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1603 IShellFolder_Release(pDesktopFolder);
1604 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1605 if (hr != S_OK) return;
1607 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1608 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1610 IPersistFolder3_Release(pPersistFolder3);
1611 pILFree(pidlWineTestFolder);
1615 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1616 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1617 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1618 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1619 pILFree(pidlCurrentFolder);
1620 pILFree(pidlWineTestFolder);
1622 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1623 IPersistFolder3_Release(pPersistFolder3);
1624 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1625 if (hr != S_OK) return;
1627 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1628 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1630 IShellFolder_Release(pShellFolder);
1634 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1635 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1637 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1638 * but ShellFSFolders. */
1639 myPathAddBackslashW(wszDesktopPath);
1640 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1641 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1642 IShellFolder_Release(pShellFolder);
1646 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1647 &pidlSubFolder, NULL);
1648 RemoveDirectoryW(wszDesktopPath);
1649 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1651 IShellFolder_Release(pShellFolder);
1655 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1656 (LPVOID*)&pPersistFolder3);
1657 IShellFolder_Release(pShellFolder);
1658 pILFree(pidlSubFolder);
1659 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1663 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1664 * a little bit and also allow CLSID_UnixDosFolder. */
1665 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1666 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1667 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1668 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1670 IPersistFolder3_Release(pPersistFolder3);
1673 #include "pshpack1.h"
1674 struct FileStructA {
1678 WORD uFileDate; /* In our current implementation this is */
1679 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1684 struct FileStructW {
1685 WORD cbLen; /* Length of this element. */
1686 BYTE abFooBar1[6]; /* Beyond any recognition. */
1687 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1688 WORD uTime; /* (this is currently speculation) */
1689 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1690 WORD uTime2; /* (this is currently speculation) */
1691 BYTE abFooBar2[4]; /* Beyond any recognition. */
1692 WCHAR wszName[1]; /* The long filename in unicode. */
1693 /* Just for documentation: Right after the unicode string: */
1694 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1695 * SHITEMID->cb == uOffset + cbLen */
1697 #include "poppack.h"
1699 static void test_ITEMIDLIST_format(void) {
1700 WCHAR wszPersonal[MAX_PATH];
1701 LPSHELLFOLDER psfDesktop, psfPersonal;
1702 LPITEMIDLIST pidlPersonal, pidlFile;
1706 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1707 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1710 if (!pSHGetSpecialFolderPathW) return;
1712 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1713 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1714 if (!bResult) return;
1716 SetLastError(0xdeadbeef);
1717 bResult = SetCurrentDirectoryW(wszPersonal);
1718 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1719 win_skip("Most W-calls are not implemented\n");
1722 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1723 if (!bResult) return;
1725 hr = SHGetDesktopFolder(&psfDesktop);
1726 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1727 if (hr != S_OK) return;
1729 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1730 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1732 IShellFolder_Release(psfDesktop);
1736 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1737 (LPVOID*)&psfPersonal);
1738 IShellFolder_Release(psfDesktop);
1739 pILFree(pidlPersonal);
1740 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1741 if (hr != S_OK) return;
1743 for (i=0; i<3; i++) {
1744 CHAR szFile[MAX_PATH];
1745 struct FileStructA *pFileStructA;
1748 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1750 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1751 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1752 if (hFile == INVALID_HANDLE_VALUE) {
1753 IShellFolder_Release(psfPersonal);
1758 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1759 DeleteFileW(wszFile[i]);
1760 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1762 IShellFolder_Release(psfPersonal);
1766 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1767 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1768 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1769 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1771 if (i < 2) /* First two file names are already in valid 8.3 format */
1772 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1774 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1775 * can't implement this correctly, since unix filesystems don't support
1776 * this nasty short/long filename stuff. So we'll probably stay with our
1777 * current habbit of storing the long filename here, which seems to work
1780 ok(pidlFile->mkid.abID[18] == '~' ||
1781 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1782 "Should be derived 8.3 name!\n");
1784 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1785 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1786 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1787 "Alignment byte, where there shouldn't be!\n");
1789 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1790 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1791 "There should be an alignment byte, but isn't!\n");
1793 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1794 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1795 ok ((cbOffset >= sizeof(struct FileStructA) &&
1796 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1797 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1798 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1799 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1801 if (cbOffset >= sizeof(struct FileStructA) &&
1802 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1804 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1806 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1807 "FileStructW's offset and length should add up to the PIDL's length!\n");
1809 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1810 /* Since we just created the file, time of creation,
1811 * time of last access and time of last write access just be the same.
1812 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1813 * after the first run. I do remember something with NTFS keeping the creation time
1814 * if a file is deleted and then created again within a couple of seconds or so.
1815 * Might be the reason. */
1816 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1817 pFileStructA->uFileTime == pFileStructW->uTime,
1818 "Last write time should match creation time!\n");
1820 /* On FAT filesystems the last access time is midnight
1821 local time, so the values of uDate2 and uTime2 will
1822 depend on the local timezone. If the times are exactly
1823 equal then the dates should be identical for both FAT
1824 and NTFS as no timezone is more than 1 day away from UTC.
1826 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1828 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1829 "Last write date and time should match last access date and time!\n");
1833 /* Filesystem may be FAT. Check date within 1 day
1834 and seconds are zero. */
1835 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1836 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1837 "Last access time on FAT filesystems should have zero seconds.\n");
1838 /* TODO: Perform check for date being within one day.*/
1841 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1842 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1843 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1844 "The filename should be stored in unicode at this position!\n");
1851 IShellFolder_Release(psfPersonal);
1854 static void test_SHGetFolderPathA(void)
1856 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1858 char path[MAX_PATH];
1859 char path_x86[MAX_PATH];
1860 char path_key[MAX_PATH];
1864 if (!pSHGetFolderPathA)
1866 win_skip("SHGetFolderPathA not present\n");
1869 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1871 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1872 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1873 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1876 win_skip( "Program Files (x86) not supported\n" );
1879 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1882 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1883 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1884 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1888 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1890 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1892 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1894 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1896 DWORD type, count = sizeof(path_x86);
1897 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1899 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1900 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1902 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1906 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1907 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1908 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1911 win_skip( "Common Files (x86) not supported\n" );
1914 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1917 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1918 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1919 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1923 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1925 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1927 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1929 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1931 DWORD type, count = sizeof(path_x86);
1932 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1934 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1935 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1937 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1941 static void test_SHGetFolderPathAndSubDirA(void)
1947 static char wine[] = "wine";
1948 static char winetemp[] = "wine\\temp";
1949 static char appdata[MAX_PATH];
1950 static char testpath[MAX_PATH];
1951 static char toolongpath[MAX_PATH+1];
1953 if(!pSHGetFolderPathAndSubDirA)
1955 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1959 if(!pSHGetFolderPathA) {
1960 win_skip("SHGetFolderPathA not present!\n");
1963 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1965 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1969 sprintf(testpath, "%s\\%s", appdata, winetemp);
1970 delret = RemoveDirectoryA(testpath);
1971 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1972 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1976 sprintf(testpath, "%s\\%s", appdata, wine);
1977 delret = RemoveDirectoryA(testpath);
1978 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1979 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1983 /* test invalid second parameter */
1984 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1985 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1987 /* test fourth parameter */
1988 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1990 case S_OK: /* winvista */
1991 ok(!strncmp(appdata, testpath, strlen(appdata)),
1992 "expected %s to start with %s\n", testpath, appdata);
1993 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1994 "expected %s to end with %s\n", testpath, winetemp);
1996 case E_INVALIDARG: /* winxp, win2k3 */
1999 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
2002 /* test fifth parameter */
2004 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
2005 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2006 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2009 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
2010 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2011 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2014 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
2015 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2016 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2018 for(i=0; i< MAX_PATH; i++)
2019 toolongpath[i] = '0' + i % 10;
2020 toolongpath[MAX_PATH] = '\0';
2021 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2022 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2023 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2026 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2027 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2029 /* test a not existing path */
2031 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2032 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2033 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2035 /* create a directory inside a not existing directory */
2037 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2038 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2039 ok(!strncmp(appdata, testpath, strlen(appdata)),
2040 "expected %s to start with %s\n", testpath, appdata);
2041 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2042 "expected %s to end with %s\n", testpath, winetemp);
2043 dwret = GetFileAttributes(testpath);
2044 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2047 sprintf(testpath, "%s\\%s", appdata, winetemp);
2048 RemoveDirectoryA(testpath);
2049 sprintf(testpath, "%s\\%s", appdata, wine);
2050 RemoveDirectoryA(testpath);
2053 static void test_LocalizedNames(void)
2055 static char cCurrDirA[MAX_PATH];
2056 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2057 IShellFolder *IDesktopFolder, *testIShellFolder;
2058 ITEMIDLIST *newPIDL;
2061 static char resourcefile[MAX_PATH];
2066 static const char desktopini_contents1[] =
2067 "[.ShellClassInfo]\r\n"
2068 "LocalizedResourceName=@";
2069 static const char desktopini_contents2[] =
2071 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2072 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2074 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2075 CreateDirectoryA(".\\testfolder", NULL);
2077 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2079 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2081 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2082 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2083 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2084 ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2085 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2086 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
2087 "WriteFile failed %i\n", GetLastError());
2090 /* get IShellFolder for parent */
2091 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2092 len = lstrlenA(cCurrDirA);
2095 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2098 if(cCurrDirA[len-1] == '\\')
2099 cCurrDirA[len-1] = 0;
2101 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2103 hr = SHGetDesktopFolder(&IDesktopFolder);
2104 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2106 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2107 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2109 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2110 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2112 IMalloc_Free(ppM, newPIDL);
2114 /* windows reads the display name from the resource */
2115 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2116 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2118 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2119 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2121 if (hr == S_OK && pStrRetToBufW)
2123 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2124 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2126 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2127 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2128 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2131 /* editing name is also read from the resource */
2132 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2133 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2135 if (hr == S_OK && pStrRetToBufW)
2137 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2138 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2140 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2141 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2142 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2145 /* parsing name is unchanged */
2146 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2147 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2149 if (hr == S_OK && pStrRetToBufW)
2151 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2152 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2153 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2156 IShellFolder_Release(IDesktopFolder);
2157 IShellFolder_Release(testIShellFolder);
2159 IMalloc_Free(ppM, newPIDL);
2162 DeleteFileA(".\\testfolder\\desktop.ini");
2163 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2164 RemoveDirectoryA(".\\testfolder");
2167 static void test_SHCreateShellItem(void)
2169 IShellItem *shellitem, *shellitem2;
2170 IPersistIDList *persistidl;
2171 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2173 char curdirA[MAX_PATH];
2174 WCHAR curdirW[MAX_PATH];
2175 WCHAR fnbufW[MAX_PATH];
2176 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2177 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2179 GetCurrentDirectoryA(MAX_PATH, curdirA);
2181 if (!pSHCreateShellItem)
2183 win_skip("SHCreateShellItem isn't available\n");
2187 if (!lstrlenA(curdirA))
2189 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2193 if(pSHGetSpecialFolderLocation)
2195 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2196 ok(ret == S_OK, "Got 0x%08x\n", ret);
2200 win_skip("pSHGetSpecialFolderLocation missing.\n");
2201 pidl_desktop = NULL;
2204 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2206 ret = SHGetDesktopFolder(&desktopfolder);
2207 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2209 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2210 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2212 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)¤tfolder);
2213 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2215 CreateTestFile(".\\testfile");
2217 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2218 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2220 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2222 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2223 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2225 if (0) /* crashes on Windows XP */
2227 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2228 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2229 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2230 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2233 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2234 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2237 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2238 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2241 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2242 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2245 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2248 IPersistIDList_Release(persistidl);
2250 IShellItem_Release(shellitem);
2253 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2254 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2257 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2258 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2261 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2262 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2265 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2268 IPersistIDList_Release(persistidl);
2271 ret = IShellItem_GetParent(shellitem, &shellitem2);
2272 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2275 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2276 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2279 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2280 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2283 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2286 IPersistIDList_Release(persistidl);
2288 IShellItem_Release(shellitem2);
2291 IShellItem_Release(shellitem);
2294 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2295 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2298 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2299 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2302 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2303 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2306 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2309 IPersistIDList_Release(persistidl);
2311 IShellItem_Release(shellitem);
2314 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2315 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2316 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2319 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2320 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2323 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2324 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2327 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2330 IPersistIDList_Release(persistidl);
2332 IShellItem_Release(shellitem);
2335 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2336 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2339 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2340 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2343 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2344 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2347 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2350 IPersistIDList_Release(persistidl);
2353 IShellItem_Release(shellitem);
2356 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2357 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2360 ret = IShellItem_GetParent(shellitem, &shellitem2);
2361 ok(FAILED(ret), "Got 0x%08x\n", ret);
2362 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2363 IShellItem_Release(shellitem);
2366 /* SHCreateItemFromParsingName */
2367 if(pSHCreateItemFromParsingName)
2371 /* Crashes under windows 7 */
2372 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2375 shellitem = (void*)0xdeadbeef;
2376 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2377 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2378 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2380 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2381 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2382 "SHCreateItemFromParsingName returned %x\n", ret);
2383 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2385 lstrcpyW(fnbufW, curdirW);
2386 myPathAddBackslashW(fnbufW);
2387 lstrcatW(fnbufW, testfileW);
2389 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2390 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2394 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2395 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2398 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2399 CoTaskMemFree(tmp_fname);
2401 IShellItem_Release(shellitem);
2405 win_skip("No SHCreateItemFromParsingName\n");
2408 /* SHCreateItemFromIDList */
2409 if(pSHCreateItemFromIDList)
2413 /* Crashes under win7 */
2414 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2417 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2418 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2420 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2421 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2424 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2425 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2428 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2429 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2432 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2435 IPersistIDList_Release(persistidl);
2437 IShellItem_Release(shellitem);
2440 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2441 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2444 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2445 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2448 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2449 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2452 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2455 IPersistIDList_Release(persistidl);
2457 IShellItem_Release(shellitem);
2461 win_skip("No SHCreateItemFromIDList\n");
2463 DeleteFileA(".\\testfile");
2464 pILFree(pidl_abstestfile);
2465 pILFree(pidl_testfile);
2466 pILFree(pidl_desktop);
2468 IShellFolder_Release(currentfolder);
2469 IShellFolder_Release(desktopfolder);
2472 static void test_SHGetNameFromIDList(void)
2474 IShellItem *shellitem;
2479 static const DWORD flags[] = {
2480 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2481 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2482 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2483 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2485 if(!pSHGetNameFromIDList)
2487 win_skip("SHGetNameFromIDList missing.\n");
2491 /* These should be available on any platform that passed the above test. */
2492 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2493 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2494 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2495 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2499 /* Crashes under win7 */
2500 hres = pSHGetNameFromIDList(NULL, 0, NULL);
2503 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2504 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2506 /* Test the desktop */
2507 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2508 ok(hres == S_OK, "Got 0x%08x\n", hres);
2509 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2510 ok(hres == S_OK, "Got 0x%08x\n", hres);
2513 WCHAR *nameSI, *nameSH;
2514 WCHAR buf[MAX_PATH];
2515 HRESULT hrSI, hrSH, hrSF;
2520 SHGetDesktopFolder(&psf);
2521 for(i = 0; flags[i] != -1234; i++)
2523 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2524 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2525 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2526 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2527 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2528 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2530 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2531 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2535 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2537 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2539 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2541 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2542 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2544 IShellFolder_Release(psf);
2546 if(pSHGetPathFromIDListW){
2547 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2548 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2549 res = pSHGetPathFromIDListW(pidl, buf);
2550 ok(res == TRUE, "Got %d\n", res);
2551 if(SUCCEEDED(hrSI) && res)
2552 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2553 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2555 win_skip("pSHGetPathFromIDListW not available\n");
2557 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2558 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2559 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2561 IShellItem_Release(shellitem);
2565 /* Test the control panel */
2566 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2567 ok(hres == S_OK, "Got 0x%08x\n", hres);
2568 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2569 ok(hres == S_OK, "Got 0x%08x\n", hres);
2572 WCHAR *nameSI, *nameSH;
2573 WCHAR buf[MAX_PATH];
2574 HRESULT hrSI, hrSH, hrSF;
2579 SHGetDesktopFolder(&psf);
2580 for(i = 0; flags[i] != -1234; i++)
2582 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2583 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2584 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2585 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2586 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2587 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2589 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2590 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2594 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2596 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2598 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2600 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2601 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2603 IShellFolder_Release(psf);
2605 if(pSHGetPathFromIDListW){
2606 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2607 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2608 res = pSHGetPathFromIDListW(pidl, buf);
2609 ok(res == FALSE, "Got %d\n", res);
2610 if(SUCCEEDED(hrSI) && res)
2611 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2612 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2614 win_skip("pSHGetPathFromIDListW not available\n");
2616 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2617 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2618 "Got 0x%08x\n", hres);
2619 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2621 IShellItem_Release(shellitem);
2626 static void test_SHGetItemFromDataObject(void)
2628 IShellFolder *psfdesktop;
2633 if(!pSHGetItemFromDataObject)
2635 win_skip("No SHGetItemFromDataObject.\n");
2641 /* Crashes under win7 */
2642 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2645 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2646 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2648 SHGetDesktopFolder(&psfdesktop);
2650 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2651 ok(hres == S_OK, "got 0x%08x\n", hres);
2658 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2659 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2660 ok(hres == S_OK, "got 0x%08x\n", hres);
2663 LPITEMIDLIST apidl[5];
2666 for(count = 0; count < 5; count++)
2667 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2672 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2673 &IID_IDataObject, NULL, (void**)&pdo);
2674 ok(hres == S_OK, "got 0x%08x\n", hres);
2677 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2678 ok(hres == S_OK, "got 0x%08x\n", hres);
2679 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2680 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2681 ok(hres == S_OK, "got 0x%08x\n", hres);
2682 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2683 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2684 ok(hres == S_OK, "got 0x%08x\n", hres);
2685 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2686 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2687 ok(hres == S_OK, "got 0x%08x\n", hres);
2688 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2689 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2690 ok(hres == S_OK, "got 0x%08x\n", hres);
2691 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2693 IDataObject_Release(pdo);
2697 skip("No file(s) found - skipping single-file test.\n");
2701 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2702 &IID_IDataObject, NULL, (void**)&pdo);
2703 ok(hres == S_OK, "got 0x%08x\n", hres);
2706 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2707 ok(hres == S_OK, "got 0x%08x\n", hres);
2708 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2709 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2710 ok(hres == S_OK, "got 0x%08x\n", hres);
2711 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2712 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2713 ok(hres == S_OK, "got 0x%08x\n", hres);
2714 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2715 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2716 ok(hres == S_OK, "got 0x%08x\n", hres);
2717 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2718 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2719 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2720 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2721 IDataObject_Release(pdo);
2725 skip("zero or one file found - skipping multi-file test.\n");
2727 for(i = 0; i < count; i++)
2730 IEnumIDList_Release(peidl);
2733 IShellView_Release(psv);
2736 IShellFolder_Release(psfdesktop);
2739 static void test_ShellItemCompare(void)
2741 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2742 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2743 IShellFolder *psf_desktop, *psf_current;
2744 LPITEMIDLIST pidl_cwd;
2745 WCHAR curdirW[MAX_PATH];
2748 static const WCHAR filesW[][9] = {
2749 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2750 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2751 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2755 if(!pSHCreateShellItem)
2757 win_skip("SHCreateShellItem missing.\n");
2761 GetCurrentDirectoryW(MAX_PATH, curdirW);
2762 if(!lstrlenW(curdirW))
2764 skip("Failed to get current directory, skipping.\n");
2768 CreateDirectoryA(".\\a", NULL);
2769 CreateDirectoryA(".\\b", NULL);
2770 CreateDirectoryA(".\\c", NULL);
2771 CreateTestFile(".\\a\\a");
2772 CreateTestFile(".\\a\\b");
2773 CreateTestFile(".\\a\\c");
2774 CreateTestFile(".\\b\\a");
2775 CreateTestFile(".\\b\\b");
2776 CreateTestFile(".\\b\\c");
2777 CreateTestFile(".\\c\\a");
2778 CreateTestFile(".\\c\\b");
2779 CreateTestFile(".\\c\\c");
2781 SHGetDesktopFolder(&psf_desktop);
2782 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2783 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2784 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2785 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2786 IShellFolder_Release(psf_desktop);
2788 /* Generate ShellItems for the files */
2789 ZeroMemory(&psi, sizeof(IShellItem*)*9);
2791 for(i = 0; i < 9; i++)
2793 LPITEMIDLIST pidl_testfile = NULL;
2795 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2796 NULL, &pidl_testfile, NULL);
2797 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2800 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2801 ok(hr == S_OK, "Got 0x%08x\n", hr);
2802 pILFree(pidl_testfile);
2804 if(FAILED(hr)) failed = TRUE;
2808 skip("Failed to create all shellitems.\n");
2812 /* Generate ShellItems for the folders */
2813 hr = IShellItem_GetParent(psi[0], &psi_a);
2814 ok(hr == S_OK, "Got 0x%08x\n", hr);
2815 if(FAILED(hr)) failed = TRUE;
2816 hr = IShellItem_GetParent(psi[3], &psi_b);
2817 ok(hr == S_OK, "Got 0x%08x\n", hr);
2818 if(FAILED(hr)) failed = TRUE;
2819 hr = IShellItem_GetParent(psi[6], &psi_c);
2820 ok(hr == S_OK, "Got 0x%08x\n", hr);
2821 if(FAILED(hr)) failed = TRUE;
2825 skip("Failed to create shellitems.\n");
2831 /* Crashes on native (win7, winxp) */
2832 hr = IShellItem_Compare(psi_a, NULL, 0, NULL);
2833 hr = IShellItem_Compare(psi_a, psi_b, 0, NULL);
2834 hr = IShellItem_Compare(psi_a, NULL, 0, &order);
2838 for(i = 0; i < 9; i++)
2840 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2841 ok(hr == S_OK, "Got 0x%08x\n", hr);
2842 ok(order == 0, "Got order %d\n", order);
2843 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2844 ok(hr == S_OK, "Got 0x%08x\n", hr);
2845 ok(order == 0, "Got order %d\n", order);
2846 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2847 ok(hr == S_OK, "Got 0x%08x\n", hr);
2848 ok(order == 0, "Got order %d\n", order);
2852 /* a\b:a\a , a\b:a\c, a\b:a\b */
2853 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2854 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2855 ok(order == 1, "Got order %d\n", order);
2856 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2857 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2858 ok(order == -1, "Got order %d\n", order);
2859 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2860 ok(hr == S_OK, "Got 0x%08x\n", hr);
2861 ok(order == 0, "Got order %d\n", order);
2863 /* b\b:a\b, b\b:c\b, b\b:c\b */
2864 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2865 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2866 ok(order == 1, "Got order %d\n", order);
2867 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2868 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2869 ok(order == -1, "Got order %d\n", order);
2870 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2871 ok(hr == S_OK, "Got 0x%08x\n", hr);
2872 ok(order == 0, "Got order %d\n", order);
2874 /* b:a\a, b:a\c, b:a\b */
2875 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2876 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2877 todo_wine ok(order == 1, "Got order %d\n", order);
2878 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2879 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2880 todo_wine ok(order == 1, "Got order %d\n", order);
2881 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2882 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2883 todo_wine ok(order == 1, "Got order %d\n", order);
2885 /* b:c\a, b:c\c, b:c\b */
2886 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2887 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2888 ok(order == -1, "Got order %d\n", order);
2889 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2890 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2891 ok(order == -1, "Got order %d\n", order);
2892 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2893 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2894 ok(order == -1, "Got order %d\n", order);
2896 /* a\b:a\a , a\b:a\c, a\b:a\b */
2897 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2898 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2899 ok(order == 1, "Got order %d\n", order);
2900 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2901 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2902 ok(order == -1, "Got order %d\n", order);
2903 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2904 ok(hr == S_OK, "Got 0x%08x\n", hr);
2905 ok(order == 0, "Got order %d\n", order);
2907 /* b\b:a\b, b\b:c\b, b\b:c\b */
2908 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2909 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2910 ok(order == 1, "Got order %d\n", order);
2911 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2912 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2913 ok(order == -1, "Got order %d\n", order);
2914 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2915 ok(hr == S_OK, "Got 0x%08x\n", hr);
2916 ok(order == 0, "Got order %d\n", order);
2918 /* b:a\a, b:a\c, b:a\b */
2919 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2920 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2921 todo_wine ok(order == 1, "Got order %d\n", order);
2922 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2923 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2924 todo_wine ok(order == 1, "Got order %d\n", order);
2925 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2926 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2927 todo_wine ok(order == 1, "Got order %d\n", order);
2929 /* b:c\a, b:c\c, b:c\b */
2930 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2931 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2932 ok(order == -1, "Got order %d\n", order);
2933 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2934 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2935 ok(order == -1, "Got order %d\n", order);
2936 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2937 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2938 ok(order == -1, "Got order %d\n", order);
2941 IShellFolder_Release(psf_current);
2943 DeleteFileA(".\\a\\a");
2944 DeleteFileA(".\\a\\b");
2945 DeleteFileA(".\\a\\c");
2946 DeleteFileA(".\\b\\a");
2947 DeleteFileA(".\\b\\b");
2948 DeleteFileA(".\\b\\c");
2949 DeleteFileA(".\\c\\a");
2950 DeleteFileA(".\\c\\b");
2951 DeleteFileA(".\\c\\c");
2952 RemoveDirectoryA(".\\a");
2953 RemoveDirectoryA(".\\b");
2954 RemoveDirectoryA(".\\c");
2956 if(psi_a) IShellItem_Release(psi_a);
2957 if(psi_b) IShellItem_Release(psi_b);
2958 if(psi_c) IShellItem_Release(psi_c);
2960 for(i = 0; i < 9; i++)
2961 if(psi[i]) IShellItem_Release(psi[i]);
2964 /**************************************************************/
2965 /* IUnknown implementation for counting QueryInterface calls. */
2967 const IUnknownVtbl *lpVtbl;
2975 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2977 IUnknownImpl *This = (IUnknownImpl*)iunk;
2979 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2981 if(IsEqualIID(This->ifaces[i].id, riid))
2983 This->ifaces[i].count++;
2990 return E_NOINTERFACE;
2993 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
2998 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3003 static const IUnknownVtbl vt_IUnknown = {
3004 unk_fnQueryInterface,
3009 static void test_SHGetIDListFromObject(void)
3011 IUnknownImpl *punkimpl;
3012 IShellFolder *psfdesktop;
3014 LPITEMIDLIST pidl, pidl_desktop;
3017 struct if_count ifaces[] =
3018 { {&IID_IPersistIDList, 0},
3019 {&IID_IPersistFolder2, 0},
3020 {&IID_IDataObject, 0},
3021 {&IID_IParentAndItem, 0},
3022 {&IID_IFolderView, 0},
3025 if(!pSHGetIDListFromObject)
3027 win_skip("SHGetIDListFromObject missing.\n");
3031 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3035 /* Crashes native */
3036 pSHGetIDListFromObject(NULL, NULL);
3037 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3040 hres = pSHGetIDListFromObject(NULL, &pidl);
3041 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3043 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3044 punkimpl->lpVtbl = &vt_IUnknown;
3045 punkimpl->ifaces = ifaces;
3046 punkimpl->unknown = 0;
3048 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3049 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3050 ok(ifaces[0].count, "interface not requested.\n");
3051 ok(ifaces[1].count, "interface not requested.\n");
3052 ok(ifaces[2].count, "interface not requested.\n");
3054 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3055 "interface not requested.\n");
3056 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3057 "interface not requested.\n");
3059 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3060 HeapFree(GetProcessHeap(), 0, punkimpl);
3062 pidl_desktop = NULL;
3063 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3064 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3066 SHGetDesktopFolder(&psfdesktop);
3068 /* Test IShellItem */
3069 if(pSHCreateShellItem)
3071 IShellItem *shellitem;
3072 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3073 ok(hres == S_OK, "got 0x%08x\n", hres);
3076 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3077 ok(hres == S_OK, "got 0x%08x\n", hres);
3080 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3083 IShellItem_Release(shellitem);
3087 skip("no SHCreateShellItem.\n");
3089 /* Test IShellFolder */
3090 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3091 ok(hres == S_OK, "got 0x%08x\n", hres);
3094 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3098 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3099 ok(hres == S_OK, "got 0x%08x\n", hres);
3106 /* Test IFolderView */
3107 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3108 ok(hres == S_OK, "got 0x%08x\n", hres);
3111 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3115 /* Test IDataObject */
3116 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3117 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3118 ok(hres == S_OK, "got 0x%08x\n", hres);
3121 LPITEMIDLIST apidl[5];
3123 for(count = 0; count < 5; count++)
3124 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3129 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3130 &IID_IDataObject, NULL, (void**)&pdo);
3131 ok(hres == S_OK, "got 0x%08x\n", hres);
3134 pidl = (void*)0xDEADBEEF;
3135 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3136 ok(hres == S_OK, "got 0x%08x\n", hres);
3137 ok(pidl != NULL, "pidl is NULL.\n");
3138 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3141 IDataObject_Release(pdo);
3145 skip("No files found - skipping single-file test.\n");
3149 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3150 &IID_IDataObject, NULL, (void**)&pdo);
3151 ok(hres == S_OK, "got 0x%08x\n", hres);
3154 pidl = (void*)0xDEADBEEF;
3155 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3156 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3157 "got 0x%08x\n", hres);
3158 ok(pidl == NULL, "pidl is not NULL.\n");
3160 IDataObject_Release(pdo);
3164 skip("zero or one file found - skipping multi-file test.\n");
3166 for(i = 0; i < count; i++)
3169 IEnumIDList_Release(peidl);
3172 IShellView_Release(psv);
3175 IShellFolder_Release(psfdesktop);
3176 pILFree(pidl_desktop);
3179 static void test_SHGetItemFromObject(void)
3181 IUnknownImpl *punkimpl;
3182 IShellFolder *psfdesktop;
3187 struct if_count ifaces[] =
3188 { {&IID_IPersistIDList, 0},
3189 {&IID_IPersistFolder2, 0},
3190 {&IID_IDataObject, 0},
3191 {&IID_IParentAndItem, 0},
3192 {&IID_IFolderView, 0},
3195 if(!pSHGetItemFromObject)
3197 skip("No SHGetItemFromObject.\n");
3201 SHGetDesktopFolder(&psfdesktop);
3205 /* Crashes with Windows 7 */
3206 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3207 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3208 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3211 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3212 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3214 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3215 punkimpl->lpVtbl = &vt_IUnknown;
3216 punkimpl->ifaces = ifaces;
3217 punkimpl->unknown = 0;
3219 /* The same as SHGetIDListFromObject */
3220 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3221 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3222 ok(ifaces[0].count, "interface not requested.\n");
3223 ok(ifaces[1].count, "interface not requested.\n");
3224 ok(ifaces[2].count, "interface not requested.\n");
3226 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3227 "interface not requested.\n");
3228 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3229 "interface not requested.\n");
3231 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3232 HeapFree(GetProcessHeap(), 0, punkimpl);
3234 /* Test IShellItem */
3235 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3236 ok(hres == S_OK, "Got 0x%08x\n", hres);
3240 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3241 ok(hres == S_OK, "Got 0x%08x\n", hres);
3245 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3246 IShellItem_Release(psi2);
3248 IShellItem_Release(psi);
3251 IShellFolder_Release(psfdesktop);
3254 static void test_SHCreateShellItemArray(void)
3256 IShellFolder *pdesktopsf, *psf;
3257 IShellItemArray *psia;
3260 WCHAR cTestDirW[MAX_PATH];
3261 LPITEMIDLIST pidl_testdir, pidl;
3262 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3264 if(!pSHCreateShellItemArray) {
3265 skip("No pSHCreateShellItemArray!\n");
3269 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3273 /* Crashes under native */
3274 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3275 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3276 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3277 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3280 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3281 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3283 SHGetDesktopFolder(&pdesktopsf);
3284 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3285 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3287 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3288 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3290 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3291 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3292 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3295 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3296 myPathAddBackslashW(cTestDirW);
3297 lstrcatW(cTestDirW, testdirW);
3299 CreateFilesFolders();
3301 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3302 ok(hr == S_OK, "got 0x%08x\n", hr);
3305 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3307 ok(hr == S_OK, "Got 0x%08x\n", hr);
3309 IShellFolder_Release(pdesktopsf);
3313 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3314 pILFree(pidl_testdir);
3319 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3320 ok(hr == S_OK, "Got %08x\n", hr);
3323 LPITEMIDLIST apidl[5];
3324 UINT done, numitems, i;
3326 for(done = 0; done < 5; done++)
3327 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3329 ok(done == 5, "Got %d pidls\n", done);
3330 IEnumIDList_Release(peidl);
3332 /* Create a ShellItemArray */
3333 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3334 ok(hr == S_OK, "Got 0x%08x\n", hr);
3341 /* Crashes in Windows 7 */
3342 hr = IShellItemArray_GetCount(psia, NULL);
3345 IShellItemArray_GetCount(psia, &numitems);
3346 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3348 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3349 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3351 /* Compare all the items */
3352 for(i = 0; i < numitems; i++)
3354 LPITEMIDLIST pidl_abs;
3355 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3357 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3358 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3361 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3362 ok(hr == S_OK, "Got 0x%08x\n", hr);
3365 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3368 IShellItem_Release(psi);
3372 for(i = 0; i < done; i++)
3374 IShellItemArray_Release(psia);
3378 /* SHCreateShellItemArrayFromShellItem */
3379 if(pSHCreateShellItemArrayFromShellItem)
3385 /* Crashes under Windows 7 */
3386 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3387 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3388 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3391 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3392 ok(hr == S_OK, "Got 0x%08x\n", hr);
3395 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3396 ok(hr == S_OK, "Got 0x%08x\n", hr);
3401 hr = IShellItemArray_GetCount(psia, &count);
3402 ok(hr == S_OK, "Got 0x%08x\n", hr);
3403 ok(count == 1, "Got count %d\n", count);
3404 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3405 ok(hr == S_OK, "Got 0x%08x\n", hr);
3407 ok(psi != psi2, "ShellItems are of the same instance.\n");
3410 LPITEMIDLIST pidl1, pidl2;
3411 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3412 ok(hr == S_OK, "Got 0x%08x\n", hr);
3413 ok(pidl1 != NULL, "pidl1 was null.\n");
3414 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3415 ok(hr == S_OK, "Got 0x%08x\n", hr);
3416 ok(pidl2 != NULL, "pidl2 was null.\n");
3417 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3420 IShellItem_Release(psi2);
3422 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3423 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3424 IShellItemArray_Release(psia);
3426 IShellItem_Release(psi);
3430 skip("No SHCreateShellItemArrayFromShellItem.\n");
3432 if(pSHCreateShellItemArrayFromDataObject)
3438 /* Crashes under Windows 7 */
3439 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3441 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3442 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3444 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3445 ok(hr == S_OK, "got 0x%08x\n", hr);
3452 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3453 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3454 ok(hr == S_OK, "got 0x%08x\n", hr);
3457 LPITEMIDLIST apidl[5];
3460 for(count = 0; count < 5; count++)
3461 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3463 ok(count == 5, "Got %d\n", count);
3467 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3468 &IID_IDataObject, NULL, (void**)&pdo);
3469 ok(hr == S_OK, "Got 0x%08x\n", hr);
3472 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3474 ok(hr == S_OK, "Got 0x%08x\n", hr);
3478 hr = IShellItemArray_GetCount(psia, &count_sia);
3479 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3480 for(i = 0; i < count_sia; i++)
3482 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3484 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3485 ok(hr == S_OK, "Got 0x%08x\n", hr);
3489 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3490 ok(hr == S_OK, "Got 0x%08x\n", hr);
3491 ok(pidl != NULL, "pidl as NULL.\n");
3492 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3494 IShellItem_Release(psi);
3499 IShellItemArray_Release(psia);
3502 IDataObject_Release(pdo);
3504 for(i = 0; i < count; i++)
3508 skip("No files found - skipping test.\n");
3510 IEnumIDList_Release(peidl);
3512 IShellView_Release(psv);
3516 skip("No SHCreateShellItemArrayFromDataObject.\n");
3518 IShellFolder_Release(psf);
3519 pILFree(pidl_testdir);
3523 static void test_ShellItemBindToHandler(void)
3526 LPITEMIDLIST pidl_desktop;
3529 if(!pSHCreateShellItem)
3531 skip("SHCreateShellItem missing.\n");
3535 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3536 ok(hr == S_OK, "Got 0x%08x\n", hr);
3539 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3540 ok(hr == S_OK, "Got 0x%08x\n", hr);
3544 IPersistFolder2 *ppf2;
3549 /* Crashes under Windows 7 */
3550 hr = IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3551 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3553 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3554 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3557 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3558 ok(hr == S_OK, "Got 0x%08x\n", hr);
3559 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3560 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3561 ok(hr == S_OK, "Got 0x%08x\n", hr);
3564 LPITEMIDLIST pidl_tmp;
3565 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3566 ok(hr == S_OK, "Got 0x%08x\n", hr);
3569 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3572 IPersistFolder2_Release(ppf2);
3575 /* BHID_SFUIObject */
3576 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3577 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3578 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3579 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3580 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3581 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3583 /* BHID_DataObject */
3584 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3585 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3586 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3590 /* BHID_SFViewObject */
3591 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3592 ok(hr == S_OK, "Got 0x%08x\n", hr);
3593 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3594 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3595 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3596 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3599 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3600 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3601 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3602 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3603 ok(hr == S_OK, "Got 0x%08x\n", hr);
3604 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3607 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3608 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3609 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3610 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3611 ok(hr == S_OK, "Got 0x%08x\n", hr);
3612 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3614 /* BHID_StorageEnum */
3615 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3616 ok(hr == S_OK, "Got 0x%08x\n", hr);
3617 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3620 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3621 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3622 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3624 /* BHID_EnumItems */
3625 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3626 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3627 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3630 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3631 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3632 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3634 /* BHID_LinkTargetItem */
3635 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3636 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3637 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3638 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3639 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3640 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3642 /* BHID_PropertyStore */
3643 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3644 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3645 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3646 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3647 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3648 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3650 /* BHID_ThumbnailHandler */
3651 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3652 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3653 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3655 /* BHID_AssociationArray */
3656 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3657 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3658 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3660 /* BHID_EnumAssocHandlers */
3661 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3662 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3663 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3666 IShellItem_Release(psi);
3669 skip("Failed to create ShellItem.\n");
3671 pILFree(pidl_desktop);
3674 static void test_SHParseDisplayName(void)
3676 LPITEMIDLIST pidl1, pidl2;
3677 IShellFolder *desktop;
3678 WCHAR dirW[MAX_PATH];
3683 if (!pSHParseDisplayName)
3685 win_skip("SHParseDisplayName isn't available\n");
3691 /* crashes on native */
3692 hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3694 hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3697 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3698 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3699 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3700 hr == E_INVALIDARG, "failed %08x\n", hr);
3701 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3705 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3706 ok(hr == S_OK, "failed %08x\n", hr);
3707 hr = SHGetDesktopFolder(&desktop);
3708 ok(hr == S_OK, "failed %08x\n", hr);
3709 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3710 ok(hr == S_OK, "failed %08x\n", hr);
3711 ret = pILIsEqual(pidl1, pidl2);
3712 ok(ret == TRUE, "expected equal idls\n");
3717 GetWindowsDirectoryW( dirW, MAX_PATH );
3719 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3720 ok(hr == S_OK, "failed %08x\n", hr);
3721 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3722 ok(hr == S_OK, "failed %08x\n", hr);
3724 ret = pILIsEqual(pidl1, pidl2);
3725 ok(ret == TRUE, "expected equal idls\n");
3729 IShellFolder_Release(desktop);
3732 static void test_desktop_IPersist(void)
3734 IShellFolder *desktop;
3736 IPersistFolder2 *ppf2;
3740 hr = SHGetDesktopFolder(&desktop);
3741 ok(hr == S_OK, "failed %08x\n", hr);
3743 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3744 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3750 /* crashes on native */
3751 hr = IPersist_GetClassID(persist, NULL);
3753 memset(&clsid, 0, sizeof(clsid));
3754 hr = IPersist_GetClassID(persist, &clsid);
3755 ok(hr == S_OK, "failed %08x\n", hr);
3756 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3757 IPersist_Release(persist);
3760 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3761 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3764 IPersistFolder *ppf;
3766 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3767 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3769 IPersistFolder_Release(ppf);
3772 hr = IPersistFolder2_Initialize(ppf2, NULL);
3773 ok(hr == S_OK, "got %08x\n", hr);
3777 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3778 ok(hr == S_OK, "got %08x\n", hr);
3779 ok(pidl != NULL, "pidl was NULL.\n");
3780 if(SUCCEEDED(hr)) pILFree(pidl);
3782 IPersistFolder2_Release(ppf2);
3785 IShellFolder_Release(desktop);
3788 static void test_GetUIObject(void)
3790 IShellFolder *psf_desktop;
3794 WCHAR path[MAX_PATH];
3795 const WCHAR filename[] =
3796 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3798 if(!pSHBindToParent)
3800 win_skip("SHBindToParent missing.\n");
3804 GetCurrentDirectoryW(MAX_PATH, path);
3807 skip("GetCurrentDirectoryW returned an empty string.\n");
3810 lstrcatW(path, filename);
3811 SHGetDesktopFolder(&psf_desktop);
3813 CreateFilesFolders();
3815 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3816 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3820 LPCITEMIDLIST pidl_child;
3821 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3822 ok(hr == S_OK, "Got 0x%08x\n", hr);
3825 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3826 &IID_IContextMenu, NULL, (void**)&pcm);
3827 ok(hr == S_OK, "Got 0x%08x\n", hr);
3830 HMENU hmenu = CreatePopupMenu();
3831 INT max_id, max_id_check;
3833 const int id_upper_limit = 32767;
3834 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3835 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3836 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3837 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3838 count = GetMenuItemCount(hmenu);
3839 ok(count, "Got %d\n", count);
3842 for(i = 0; i < count; i++)
3846 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3847 mii.cbSize = sizeof(MENUITEMINFOA);
3848 mii.fMask = MIIM_ID | MIIM_FTYPE;
3851 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3852 ok(res, "Failed (last error: %d).\n", GetLastError());
3854 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3855 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3856 if(!(mii.fType & MFT_SEPARATOR))
3857 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3859 ok((max_id_check == max_id) ||
3860 (max_id_check == max_id-1 /* Win 7 */),
3861 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3863 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3865 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3867 CMINVOKECOMMANDINFO cmi;
3868 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3869 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3871 /* Attempt to execute a nonexistent command */
3872 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3873 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3874 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3876 cmi.lpVerb = "foobar_wine_test";
3877 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3878 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3879 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3880 "Got 0x%08x\n", hr);
3885 IContextMenu_Release(pcm);
3887 IShellFolder_Release(psf);
3889 if(pILFree) pILFree(pidl);
3892 IShellFolder_Release(psf_desktop);
3896 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3897 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3899 LPCITEMIDLIST child;
3900 IShellFolder *parent;
3904 if(!pSHBindToParent){
3905 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3907 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3909 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3915 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3919 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3920 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3924 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3925 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3927 IShellFolder_Release(parent);
3931 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
3932 "Got unexpected string type: %d\n", filename.uType);
3933 if(filename.uType == STRRET_WSTR){
3934 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
3935 "didn't get expected path (%s), instead: %s\n",
3936 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
3937 }else if(filename.uType == STRRET_CSTR){
3938 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
3939 "didn't get expected path (%s), instead: %s\n",
3940 wine_dbgstr_w(path), U(filename).cStr);
3943 IShellFolder_Release(parent);
3945 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3948 static void test_SHSimpleIDListFromPath(void)
3950 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
3951 const CHAR adirA[] = "C:\\sidlfpdir";
3952 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
3954 LPITEMIDLIST pidl = NULL;
3956 if(!pSHSimpleIDListFromPathAW){
3957 win_skip("SHSimpleIDListFromPathAW not available\n");
3961 br = CreateDirectoryA(adirA, NULL);
3962 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3965 pidl = pSHSimpleIDListFromPathAW(adirW);
3967 pidl = pSHSimpleIDListFromPathAW(adirA);
3968 verify_pidl(pidl, adirW);
3971 br = RemoveDirectoryA(adirA);
3972 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
3975 pidl = pSHSimpleIDListFromPathAW(adirW);
3977 pidl = pSHSimpleIDListFromPathAW(adirA);
3978 verify_pidl(pidl, adirW);
3982 /* IFileSystemBindData impl */
3983 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
3984 REFIID riid, void **ppv)
3986 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
3987 IsEqualIID(riid, &IID_IUnknown)){
3991 return E_NOINTERFACE;
3994 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
3999 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4004 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4005 const WIN32_FIND_DATAW *pfd)
4007 ok(0, "SetFindData called\n");
4011 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4012 WIN32_FIND_DATAW *pfd)
4014 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4018 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4019 WIN32_FIND_DATAW *pfd)
4021 memset(pfd, 0xdeadbeef, sizeof(WIN32_FIND_DATAW));
4025 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4026 WIN32_FIND_DATAW *pfd)
4028 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4029 *pfd->cFileName = 'a';
4030 *pfd->cAlternateFileName = 'a';
4034 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4035 WIN32_FIND_DATAW *pfd)
4037 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4038 HANDLE handle = FindFirstFileW(adirW, pfd);
4043 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4044 WIN32_FIND_DATAW *pfd)
4049 static IFileSystemBindDataVtbl fsbdVtbl = {
4050 fsbd_QueryInterface,
4057 static IFileSystemBindData fsbd = { &fsbdVtbl };
4059 static void test_ParseDisplayNamePBC(void)
4061 WCHAR wFileSystemBindData[] =
4062 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4063 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4064 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4065 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4066 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4073 /* Check if we support WCHAR functions */
4074 SetLastError(0xdeadbeef);
4075 lstrcmpiW(adirW, adirW);
4076 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4077 win_skip("Most W-calls are not implemented\n");
4081 hres = SHGetDesktopFolder(&psf);
4082 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4084 win_skip("Failed to get IShellFolder, can't run tests\n");
4088 /* fails on unknown dir with no IBindCtx */
4089 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4090 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4091 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4092 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4093 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4094 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4095 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4096 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4097 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4099 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4100 hres = CreateBindCtx(0, &pbc);
4101 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4103 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4104 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4105 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4106 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4107 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4108 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4109 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4110 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4111 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4113 /* unknown dir with IBindCtx with IFileSystemBindData */
4114 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4115 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4117 /* return E_FAIL from GetFindData */
4118 pidl = (ITEMIDLIST*)0xdeadbeef;
4119 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4120 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4121 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4122 "ParseDisplayName failed: 0x%08x\n", hres);
4123 if(SUCCEEDED(hres)){
4124 verify_pidl(pidl, adirW);
4128 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4129 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4130 "ParseDisplayName failed: 0x%08x\n", hres);
4131 if(SUCCEEDED(hres)){
4132 verify_pidl(pidl, afileW);
4136 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4137 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4138 "ParseDisplayName failed: 0x%08x\n", hres);
4139 if(SUCCEEDED(hres)){
4140 verify_pidl(pidl, afile2W);
4144 /* set FIND_DATA struct to NULLs */
4145 pidl = (ITEMIDLIST*)0xdeadbeef;
4146 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4147 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4148 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4149 "ParseDisplayName failed: 0x%08x\n", hres);
4150 if(SUCCEEDED(hres)){
4151 verify_pidl(pidl, adirW);
4155 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4156 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4157 "ParseDisplayName failed: 0x%08x\n", hres);
4158 if(SUCCEEDED(hres)){
4159 verify_pidl(pidl, afileW);
4163 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4164 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4165 "ParseDisplayName failed: 0x%08x\n", hres);
4166 if(SUCCEEDED(hres)){
4167 verify_pidl(pidl, afile2W);
4171 /* set FIND_DATA struct to junk */
4172 pidl = (ITEMIDLIST*)0xdeadbeef;
4173 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4174 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4175 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4176 "ParseDisplayName failed: 0x%08x\n", hres);
4177 if(SUCCEEDED(hres)){
4178 verify_pidl(pidl, adirW);
4182 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4183 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4184 "ParseDisplayName failed: 0x%08x\n", hres);
4185 if(SUCCEEDED(hres)){
4186 verify_pidl(pidl, afileW);
4190 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4191 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4192 "ParseDisplayName failed: 0x%08x\n", hres);
4193 if(SUCCEEDED(hres)){
4194 verify_pidl(pidl, afile2W);
4198 /* set FIND_DATA struct to invalid data */
4199 pidl = (ITEMIDLIST*)0xdeadbeef;
4200 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4201 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, 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, adirW);
4209 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, 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, afileW);
4217 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4218 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4219 "ParseDisplayName failed: 0x%08x\n", hres);
4220 if(SUCCEEDED(hres)){
4221 verify_pidl(pidl, afile2W);
4225 /* set FIND_DATA struct to valid data */
4226 pidl = (ITEMIDLIST*)0xdeadbeef;
4227 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4228 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, 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, adirW);
4236 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, 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, afileW);
4244 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4245 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4246 "ParseDisplayName failed: 0x%08x\n", hres);
4247 if(SUCCEEDED(hres)){
4248 verify_pidl(pidl, afile2W);
4252 IBindCtx_Release(pbc);
4253 IShellFolder_Release(psf);
4256 static const CHAR testwindow_class[] = "testwindow";
4257 #define WM_USER_NOTIFY (WM_APP+1)
4259 struct ChNotifyTest {
4261 const UINT notify_count;
4262 UINT missing_events;
4264 const char path_1[256];
4265 const char path_2[256];
4266 } chnotify_tests[] = {
4267 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4268 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4269 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4272 struct ChNotifyTest *exp_data;
4274 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4276 UINT signal = (UINT)lparam;
4279 case WM_USER_NOTIFY:
4280 if(exp_data->missing_events > 0){
4281 WCHAR *path1, *path2;
4282 LPCITEMIDLIST *pidls = (LPCITEMIDLIST*)wparam;
4284 ok(exp_data->signal == signal,
4285 "%s: expected notification type %x, got: %x\n",
4286 exp_data->id, exp_data->signal, signal);
4288 trace("verifying pidls for: %s\n", exp_data->id);
4289 path1 = make_wstr(exp_data->path_1);
4290 path2 = make_wstr(exp_data->path_2);
4291 verify_pidl(pidls[0], path1);
4292 verify_pidl(pidls[1], path2);
4293 HeapFree(GetProcessHeap(), 0, path1);
4294 HeapFree(GetProcessHeap(), 0, path2);
4296 exp_data->missing_events--;
4298 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4301 return DefWindowProc(hwnd, msg, wparam, lparam);
4304 static void register_testwindow_class(void)
4309 ZeroMemory(&cls, sizeof(cls));
4310 cls.cbSize = sizeof(cls);
4312 cls.lpfnWndProc = testwindow_wndproc;
4313 cls.hInstance = GetModuleHandleA(NULL);
4314 cls.lpszClassName = testwindow_class;
4317 ret = RegisterClassExA(&cls);
4318 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4321 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4322 * have to poll repeatedly for the message to appear */
4323 static void do_events(void)
4326 while (exp_data->missing_events && (c++ < 10)){
4328 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4329 TranslateMessage(&msg);
4330 DispatchMessageA(&msg);
4332 if(exp_data->missing_events)
4335 trace("%s: took %d tries\n", exp_data->id, c);
4338 static void test_SHChangeNotify(void)
4343 BOOL br, has_unicode;
4344 SHChangeNotifyEntry entries[1];
4345 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4346 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4348 CreateDirectoryW(NULL, NULL);
4349 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4351 register_testwindow_class();
4353 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4354 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4355 NULL, NULL, GetModuleHandleA(NULL), 0);
4356 ok(wnd != NULL, "Failed to make a window\n");
4358 br = CreateDirectoryA(root_dirA, NULL);
4359 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4361 entries[0].pidl = NULL;
4363 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4365 hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4366 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4367 entries[0].fRecursive = TRUE;
4369 notifyID = SHChangeNotifyRegister(wnd, SHCNRF_ShellLevel,
4370 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4371 ok(notifyID != 0, "Failed to register a window for change notifications\n");
4373 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
4374 exp_data = chnotify_tests + i;
4376 exp_data->missing_events = exp_data->notify_count;
4377 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4378 strlen(exp_data->path_1) > 0 ? exp_data->path_1 : NULL,
4379 strlen(exp_data->path_2) > 0 ? exp_data->path_2 : NULL);
4381 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4384 WCHAR *path1, *path2;
4386 path1 = make_wstr(exp_data->path_1);
4387 path2 = make_wstr(exp_data->path_2);
4389 exp_data->missing_events = exp_data->notify_count;
4390 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
4392 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4396 SHChangeNotifyDeregister(notifyID);
4399 br = RemoveDirectoryA(root_dirA);
4400 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4403 START_TEST(shlfolder)
4405 init_function_pointers();
4406 /* if OleInitialize doesn't get called, ParseDisplayName returns
4407 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4408 OleInitialize(NULL);
4410 test_ParseDisplayName();
4411 test_SHParseDisplayName();
4412 test_BindToObject();
4413 test_EnumObjects_and_CompareIDs();
4414 test_GetDisplayName();
4415 test_GetAttributesOf();
4416 test_SHGetPathFromIDList();
4417 test_CallForAttributes();
4418 test_FolderShortcut();
4419 test_ITEMIDLIST_format();
4420 test_SHGetFolderPathA();
4421 test_SHGetFolderPathAndSubDirA();
4422 test_LocalizedNames();
4423 test_SHCreateShellItem();
4424 test_SHCreateShellItemArray();
4425 test_desktop_IPersist();
4427 test_SHSimpleIDListFromPath();
4428 test_ParseDisplayNamePBC();
4429 test_SHGetNameFromIDList();
4430 test_SHGetItemFromDataObject();
4431 test_SHGetIDListFromObject();
4432 test_SHGetItemFromObject();
4433 test_ShellItemCompare();
4434 test_SHChangeNotify();
4435 test_ShellItemBindToHandler();