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"
45 static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
46 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
47 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
48 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
49 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
50 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
51 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
52 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
53 static void (WINAPI *pILFree)(LPITEMIDLIST);
54 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
55 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
56 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
57 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
59 static void init_function_pointers(void)
64 hmod = GetModuleHandleA("shell32.dll");
66 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
67 MAKEFUNC(SHBindToParent);
68 MAKEFUNC(SHCreateShellItem);
69 MAKEFUNC(SHGetFolderPathA);
70 MAKEFUNC(SHGetFolderPathAndSubDirA);
71 MAKEFUNC(SHGetPathFromIDListW);
72 MAKEFUNC(SHGetSpecialFolderPathA);
73 MAKEFUNC(SHGetSpecialFolderPathW);
74 MAKEFUNC(SHParseDisplayName);
77 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
78 MAKEFUNC_ORD(ILFindLastID, 16);
79 MAKEFUNC_ORD(ILIsEqual, 21);
80 MAKEFUNC_ORD(ILCombine, 25);
81 MAKEFUNC_ORD(ILFree, 155);
84 hmod = GetModuleHandleA("shlwapi.dll");
85 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
87 hr = SHGetMalloc(&ppM);
88 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
91 static void test_ParseDisplayName(void)
94 IShellFolder *IDesktopFolder;
95 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
96 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
97 static const char *cInetTestA = "http:\\yyy";
98 static const char *cInetTest2A = "xx:yyy";
100 WCHAR cTestDirW [MAX_PATH] = {0};
104 hr = SHGetDesktopFolder(&IDesktopFolder);
105 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
106 if(hr != S_OK) return;
108 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
109 if (pSHCreateShellItem)
111 /* null name and pidl */
112 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
113 NULL, NULL, NULL, NULL, NULL, 0);
114 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
117 newPIDL = (ITEMIDLIST*)0xdeadbeef;
118 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
119 NULL, NULL, NULL, NULL, &newPIDL, 0);
120 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
121 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
124 win_skip("Tests would crash on W2K and below\n");
126 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
127 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
128 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
129 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
130 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
133 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
134 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
135 IMalloc_Free(ppM, newPIDL);
138 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
139 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
140 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
141 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
142 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
145 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
146 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
147 IMalloc_Free(ppM, newPIDL);
150 res = GetFileAttributesA(cNonExistDir1A);
151 if(res != INVALID_FILE_ATTRIBUTES)
153 skip("Test directory unexpectedly exists\n");
157 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
158 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
159 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
160 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
161 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
163 res = GetFileAttributesA(cNonExistDir2A);
164 if(res != INVALID_FILE_ATTRIBUTES)
166 skip("Test directory unexpectedly exists\n");
170 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
171 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
172 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
173 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
174 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
176 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
177 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
178 * out it doesn't. The magic seems to happen in the file dialogs, then. */
179 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
181 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
185 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
186 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
187 if (!bRes) goto finished;
189 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
190 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
191 if (hr != S_OK) goto finished;
193 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
194 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
195 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
196 pILFindLastID(newPIDL)->mkid.abID[0]);
197 IMalloc_Free(ppM, newPIDL);
200 IShellFolder_Release(IDesktopFolder);
203 /* creates a file with the specified name for tests */
204 static void CreateTestFile(const CHAR *name)
209 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
210 if (file != INVALID_HANDLE_VALUE)
212 WriteFile(file, name, strlen(name), &written, NULL);
213 WriteFile(file, "\n", strlen("\n"), &written, NULL);
219 /* initializes the tests */
220 static void CreateFilesFolders(void)
222 CreateDirectoryA(".\\testdir", NULL);
223 CreateDirectoryA(".\\testdir\\test.txt", NULL);
224 CreateTestFile (".\\testdir\\test1.txt ");
225 CreateTestFile (".\\testdir\\test2.txt ");
226 CreateTestFile (".\\testdir\\test3.txt ");
227 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
228 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
231 /* cleans after tests */
232 static void Cleanup(void)
234 DeleteFileA(".\\testdir\\test1.txt");
235 DeleteFileA(".\\testdir\\test2.txt");
236 DeleteFileA(".\\testdir\\test3.txt");
237 RemoveDirectoryA(".\\testdir\\test.txt");
238 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
239 RemoveDirectoryA(".\\testdir\\testdir2");
240 RemoveDirectoryA(".\\testdir");
245 static void test_EnumObjects(IShellFolder *iFolder)
247 IEnumIDList *iEnumList;
248 LPITEMIDLIST newPIDL, idlArr[10];
253 static const WORD iResults [5][5] =
262 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
263 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
264 static const ULONG attrs[5] =
266 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
267 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
268 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
269 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
270 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
273 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
274 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
276 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
277 * the filesystem shellfolders return S_OK even if less than 'celt' items are
278 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
279 * only ever returns a single entry per call. */
280 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
282 ok (i == 5, "i: %d\n", i);
284 hr = IEnumIDList_Release(iEnumList);
285 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
287 /* Sort them first in case of wrong order from system */
288 for (i=0;i<5;i++) for (j=0;j<5;j++)
289 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
292 idlArr[i] = idlArr[j];
296 for (i=0;i<5;i++) for (j=0;j<5;j++)
298 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
299 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
303 for (i = 0; i < 5; i++)
306 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
307 /* Native returns all flags no matter what we ask for */
308 flags = SFGAO_CANCOPY;
309 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
310 flags &= SFGAO_testfor;
311 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
312 ok(flags == (attrs[i]) ||
313 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
314 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
315 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
317 flags = SFGAO_testfor;
318 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
319 flags &= SFGAO_testfor;
320 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
321 ok(flags == attrs[i] ||
322 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
323 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
327 IMalloc_Free(ppM, idlArr[i]);
330 static void test_BindToObject(void)
334 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
335 SHITEMID emptyitem = { 0, { 0 } };
336 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
337 WCHAR wszSystemDir[MAX_PATH];
338 char szSystemDir[MAX_PATH];
339 WCHAR wszMyComputer[] = {
340 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
341 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
343 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
344 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
346 hr = SHGetDesktopFolder(&psfDesktop);
347 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
348 if (hr != S_OK) return;
350 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
351 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
353 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
354 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
356 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
357 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
359 IShellFolder_Release(psfDesktop);
363 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
364 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
365 IShellFolder_Release(psfDesktop);
366 IMalloc_Free(ppM, pidlMyComputer);
367 if (hr != S_OK) return;
369 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
370 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
374 /* this call segfaults on 98SE */
375 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
376 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
379 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
380 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
381 if (cChars == 0 || cChars >= MAX_PATH) {
382 IShellFolder_Release(psfMyComputer);
385 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
387 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
388 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
390 IShellFolder_Release(psfMyComputer);
394 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
395 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
396 IShellFolder_Release(psfMyComputer);
397 IMalloc_Free(ppM, pidlSystemDir);
398 if (hr != S_OK) return;
400 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
401 ok (hr == E_INVALIDARG,
402 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
406 /* this call segfaults on 98SE */
407 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
408 ok (hr == E_INVALIDARG,
409 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
412 IShellFolder_Release(psfSystemDir);
415 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
416 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
420 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
426 if (lpszPath[-1] != '\\')
435 static void test_GetDisplayName(void)
440 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
441 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
444 LPSHELLFOLDER psfDesktop, psfPersonal;
446 SHITEMID emptyitem = { 0, { 0 } };
447 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
448 LPCITEMIDLIST pidlLast;
449 static const CHAR szFileName[] = "winetest.foo";
450 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
451 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
453 /* I'm trying to figure if there is a functional difference between calling
454 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
455 * binding to the shellfolder. One thing I thought of was that perhaps
456 * SHGetPathFromIDListW would be able to get the path to a file, which does
457 * not exist anymore, while the other method wouldn't. It turns out there's
458 * no functional difference in this respect.
461 if(!pSHGetSpecialFolderPathA) {
462 win_skip("SHGetSpecialFolderPathA is not available\n");
466 /* First creating a directory in MyDocuments and a file in this directory. */
467 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
468 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
471 /* Use ANSI file functions so this works on Windows 9x */
472 lstrcatA(szTestDir, "\\winetest");
473 CreateDirectoryA(szTestDir, NULL);
474 attr=GetFileAttributesA(szTestDir);
475 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
477 ok(0, "unable to create the '%s' directory\n", szTestDir);
481 lstrcpyA(szTestFile, szTestDir);
482 lstrcatA(szTestFile, "\\");
483 lstrcatA(szTestFile, szFileName);
484 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
485 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
486 if (hTestFile == INVALID_HANDLE_VALUE) return;
487 CloseHandle(hTestFile);
489 /* Getting an itemidlist for the file. */
490 hr = SHGetDesktopFolder(&psfDesktop);
491 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
492 if (hr != S_OK) return;
494 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
496 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
497 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
499 IShellFolder_Release(psfDesktop);
503 pidlLast = pILFindLastID(pidlTestFile);
504 ok(pidlLast->mkid.cb >=76 ||
505 broken(pidlLast->mkid.cb == 28) || /* W2K */
506 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
507 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
508 if (pidlLast->mkid.cb >= 28) {
509 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
510 "Filename should be stored as ansi-string at this position!\n");
512 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
513 if (pidlLast->mkid.cb >= 76) {
514 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
515 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
516 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
517 "Filename should be stored as wchar-string at this position!\n");
520 /* It seems as if we cannot bind to regular files on windows, but only directories.
522 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
524 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
525 hr == E_NOTIMPL || /* Vista */
526 broken(hr == S_OK), /* Win9x, W2K */
529 IShellFolder_Release(psfFile);
532 if (!pSHBindToParent)
534 win_skip("SHBindToParent is missing\n");
535 DeleteFileA(szTestFile);
536 RemoveDirectoryA(szTestDir);
540 /* Some tests for IShellFolder::SetNameOf */
541 if (pSHGetFolderPathAndSubDirA)
543 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
544 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
546 /* It's ok to use this fixed path. Call will fail anyway. */
547 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
548 LPITEMIDLIST pidlNew;
550 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
551 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
552 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
555 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
556 "pidl returned from SetNameOf should be simple!\n");
558 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
559 * is implemented on top of SHFileOperation in WinXP. */
560 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
561 SHGDN_FORPARSING, NULL);
562 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
564 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
565 * SHGDN flags specify an absolute path. */
566 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
567 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
572 IShellFolder_Release(psfPersonal);
576 win_skip("Avoid needs of interaction on Win2k\n");
578 /* Deleting the file and the directory */
579 DeleteFileA(szTestFile);
580 RemoveDirectoryA(szTestDir);
582 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
583 if (pSHGetPathFromIDListW)
585 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
586 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
587 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
590 /* SHBindToParent fails, if called with a NULL PIDL. */
591 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
592 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
594 /* But it succeeds with an empty PIDL. */
595 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
596 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
597 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
599 IShellFolder_Release(psfPersonal);
601 /* Binding to the folder and querying the display name of the file also works. */
602 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
603 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
605 IShellFolder_Release(psfDesktop);
609 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
610 * pidlTestFile (In accordance with MSDN). */
611 ok (pILFindLastID(pidlTestFile) == pidlLast,
612 "SHBindToParent doesn't return the last id of the pidl param!\n");
614 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
615 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
617 IShellFolder_Release(psfDesktop);
618 IShellFolder_Release(psfPersonal);
624 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
625 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
626 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
629 ILFree(pidlTestFile);
630 IShellFolder_Release(psfDesktop);
631 IShellFolder_Release(psfPersonal);
634 static void test_CallForAttributes(void)
640 LPSHELLFOLDER psfDesktop;
641 LPITEMIDLIST pidlMyDocuments;
642 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
643 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
644 static const WCHAR wszCallForAttributes[] = {
645 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
646 static const WCHAR wszMyDocumentsKey[] = {
647 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
648 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
649 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
650 WCHAR wszMyDocuments[] = {
651 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
652 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
654 /* For the root of a namespace extension, the attributes are not queried by binding
655 * to the object and calling GetAttributesOf. Instead, the attributes are read from
656 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
658 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
659 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
660 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
661 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
663 hr = SHGetDesktopFolder(&psfDesktop);
664 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
665 if (hr != S_OK) return;
667 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
668 &pidlMyDocuments, NULL);
670 broken(hr == E_INVALIDARG), /* Win95, NT4 */
671 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
673 IShellFolder_Release(psfDesktop);
677 dwAttributes = 0xffffffff;
678 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
679 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
680 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
682 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
683 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
684 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
685 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
687 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
688 * key. So the test will return at this point, if run on wine.
690 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
691 ok (lResult == ERROR_SUCCESS ||
692 lResult == ERROR_ACCESS_DENIED,
693 "RegOpenKeyEx failed! result: %08x\n", lResult);
694 if (lResult != ERROR_SUCCESS) {
695 if (lResult == ERROR_ACCESS_DENIED)
696 skip("Not enough rights to open the registry key\n");
697 IMalloc_Free(ppM, pidlMyDocuments);
698 IShellFolder_Release(psfDesktop);
702 /* Query MyDocuments' Attributes value, to be able to restore it later. */
703 dwSize = sizeof(DWORD);
704 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
705 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
706 if (lResult != ERROR_SUCCESS) {
708 IMalloc_Free(ppM, pidlMyDocuments);
709 IShellFolder_Release(psfDesktop);
713 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
714 dwSize = sizeof(DWORD);
715 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
716 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
717 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
718 if (lResult != ERROR_SUCCESS) {
720 IMalloc_Free(ppM, pidlMyDocuments);
721 IShellFolder_Release(psfDesktop);
725 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
726 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
727 * SFGAO_FILESYSTEM attributes. */
728 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
729 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
730 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
731 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
732 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
734 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
735 * GetAttributesOf. It seems that once there is a single attribute queried, for which
736 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
737 * the flags in Attributes are ignored.
739 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
740 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
741 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
742 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
744 ok (dwAttributes == SFGAO_FILESYSTEM,
745 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
748 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
749 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
750 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
751 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
753 IMalloc_Free(ppM, pidlMyDocuments);
754 IShellFolder_Release(psfDesktop);
757 static void test_GetAttributesOf(void)
760 LPSHELLFOLDER psfDesktop, psfMyComputer;
761 SHITEMID emptyitem = { 0, { 0 } };
762 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
763 LPITEMIDLIST pidlMyComputer;
765 static const DWORD desktopFlags[] = {
767 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
768 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
770 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
771 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
772 /* WinMe, Win9x, WinNT*/
773 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
774 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
776 static const DWORD myComputerFlags[] = {
778 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
779 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
781 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
782 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
783 /* WinMe, Win9x, WinNT */
784 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
785 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
786 /* Win95, WinNT when queried directly */
787 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
788 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
790 WCHAR wszMyComputer[] = {
791 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
792 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
793 char cCurrDirA [MAX_PATH] = {0};
794 WCHAR cCurrDirW [MAX_PATH];
795 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
796 IShellFolder *IDesktopFolder, *testIShellFolder;
799 BOOL foundFlagsMatch;
801 hr = SHGetDesktopFolder(&psfDesktop);
802 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
803 if (hr != S_OK) return;
805 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
806 dwFlags = 0xffffffff;
807 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
808 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
809 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
810 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
812 if (desktopFlags[i] == dwFlags)
813 foundFlagsMatch = TRUE;
815 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
817 /* .. or with no itemidlist at all. */
818 dwFlags = 0xffffffff;
819 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
820 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
821 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
822 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
824 if (desktopFlags[i] == dwFlags)
825 foundFlagsMatch = TRUE;
827 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
829 /* Testing the attributes of the MyComputer shellfolder */
830 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
831 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
833 IShellFolder_Release(psfDesktop);
837 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
838 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
840 dwFlags = 0xffffffff;
841 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
842 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
843 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
844 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
846 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
847 foundFlagsMatch = TRUE;
850 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
852 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
853 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
854 IShellFolder_Release(psfDesktop);
855 IMalloc_Free(ppM, pidlMyComputer);
856 if (hr != S_OK) return;
858 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
860 ok (hr == E_INVALIDARG ||
861 broken(hr == S_OK), /* W2K and earlier */
862 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
864 dwFlags = 0xffffffff;
865 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
866 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
867 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
868 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
870 if (myComputerFlags[i] == dwFlags)
871 foundFlagsMatch = TRUE;
874 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
876 IShellFolder_Release(psfMyComputer);
878 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
879 len = lstrlenA(cCurrDirA);
882 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
885 if (len > 3 && cCurrDirA[len-1] == '\\')
886 cCurrDirA[len-1] = 0;
888 /* create test directory */
889 CreateFilesFolders();
891 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
893 hr = SHGetDesktopFolder(&IDesktopFolder);
894 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
896 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
897 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
899 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
900 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
902 IMalloc_Free(ppM, newPIDL);
904 /* get relative PIDL */
905 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
906 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
908 /* test the shell attributes of the test directory using the relative PIDL */
909 dwFlags = SFGAO_FOLDER;
910 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
911 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
912 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
915 IMalloc_Free(ppM, newPIDL);
917 /* append testdirectory name to path */
918 if (cCurrDirA[len-1] == '\\')
919 cCurrDirA[len-1] = 0;
920 lstrcatA(cCurrDirA, "\\testdir");
921 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
923 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
924 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
926 /* test the shell attributes of the test directory using the absolute PIDL */
927 dwFlags = SFGAO_FOLDER;
928 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
929 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
930 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
933 IMalloc_Free(ppM, newPIDL);
935 IShellFolder_Release(testIShellFolder);
939 IShellFolder_Release(IDesktopFolder);
942 static void test_SHGetPathFromIDList(void)
944 SHITEMID emptyitem = { 0, { 0 } };
945 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
946 LPITEMIDLIST pidlMyComputer;
947 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
950 LPSHELLFOLDER psfDesktop;
951 WCHAR wszMyComputer[] = {
952 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
953 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
954 WCHAR wszFileName[MAX_PATH];
955 LPITEMIDLIST pidlTestFile;
958 static WCHAR wszTestFile[] = {
959 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
960 HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
962 LPITEMIDLIST pidlPrograms;
964 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
966 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
970 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
973 result = pSHGetPathFromIDListW(NULL, wszPath);
974 ok(!result, "Expected failure\n");
975 ok(!wszPath[0], "Expected empty string\n");
977 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
978 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
979 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
982 /* Check if we are on Win9x */
983 SetLastError(0xdeadbeef);
984 lstrcmpiW(wszDesktop, wszDesktop);
985 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
987 win_skip("Most W-calls are not implemented\n");
991 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
992 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
994 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
996 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
997 hr = SHGetDesktopFolder(&psfDesktop);
998 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
999 if (hr != S_OK) return;
1001 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1002 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1004 IShellFolder_Release(psfDesktop);
1008 SetLastError(0xdeadbeef);
1011 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1012 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1013 ok (GetLastError()==0xdeadbeef ||
1014 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1015 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1016 ok (!wszPath[0], "Expected empty path\n");
1018 IShellFolder_Release(psfDesktop);
1022 IMalloc_Free(ppM, pidlMyComputer);
1024 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1025 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1027 IShellFolder_Release(psfDesktop);
1030 myPathAddBackslashW(wszFileName);
1031 lstrcatW(wszFileName, wszTestFile);
1032 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1033 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1034 if (hTestFile == INVALID_HANDLE_VALUE) {
1035 IShellFolder_Release(psfDesktop);
1038 CloseHandle(hTestFile);
1040 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1041 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1043 IShellFolder_Release(psfDesktop);
1044 DeleteFileW(wszFileName);
1045 IMalloc_Free(ppM, pidlTestFile);
1049 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1050 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1051 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1052 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1053 IShellFolder_Release(psfDesktop);
1054 DeleteFileW(wszFileName);
1056 IMalloc_Free(ppM, pidlTestFile);
1061 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1062 ok(0 == lstrcmpW(wszFileName, wszPath),
1063 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1064 "returned incorrect path for file placed on desktop\n");
1067 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1068 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1069 IMalloc_Free(ppM, pidlTestFile);
1070 if (!result) return;
1071 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1074 /* Test if we can get the path from the start menu "program files" PIDL. */
1075 hShell32 = GetModuleHandleA("shell32");
1076 pSHGetSpecialFolderLocation = (void *)GetProcAddress(hShell32, "SHGetSpecialFolderLocation");
1078 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1079 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1081 SetLastError(0xdeadbeef);
1082 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1083 IMalloc_Free(ppM, pidlPrograms);
1084 ok(result, "SHGetPathFromIDListW failed\n");
1087 static void test_EnumObjects_and_CompareIDs(void)
1089 ITEMIDLIST *newPIDL;
1090 IShellFolder *IDesktopFolder, *testIShellFolder;
1091 char cCurrDirA [MAX_PATH] = {0};
1092 static const CHAR cTestDirA[] = "\\testdir";
1093 WCHAR cTestDirW[MAX_PATH];
1097 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1098 len = lstrlenA(cCurrDirA);
1101 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1104 if(cCurrDirA[len-1] == '\\')
1105 cCurrDirA[len-1] = 0;
1107 lstrcatA(cCurrDirA, cTestDirA);
1108 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1110 hr = SHGetDesktopFolder(&IDesktopFolder);
1111 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1113 CreateFilesFolders();
1115 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1116 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1118 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1119 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1121 test_EnumObjects(testIShellFolder);
1123 IShellFolder_Release(testIShellFolder);
1127 IMalloc_Free(ppM, newPIDL);
1129 IShellFolder_Release(IDesktopFolder);
1132 /* A simple implementation of an IPropertyBag, which returns fixed values for
1133 * 'Target' and 'Attributes' properties.
1135 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1139 return E_INVALIDARG;
1141 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1144 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1145 return E_NOINTERFACE;
1148 IPropertyBag_AddRef(iface);
1152 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1156 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1160 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1161 VARIANT *pVar, IErrorLog *pErrorLog)
1163 static const WCHAR wszTargetSpecialFolder[] = {
1164 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1165 static const WCHAR wszTarget[] = {
1166 'T','a','r','g','e','t',0 };
1167 static const WCHAR wszAttributes[] = {
1168 'A','t','t','r','i','b','u','t','e','s',0 };
1169 static const WCHAR wszResolveLinkFlags[] = {
1170 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1171 static const WCHAR wszTargetKnownFolder[] = {
1172 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1173 static const WCHAR wszCLSID[] = {
1174 'C','L','S','I','D',0 };
1176 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1177 ok(V_VT(pVar) == VT_I4 ||
1178 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1179 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1180 return E_INVALIDARG;
1183 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1185 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1186 return E_INVALIDARG;
1189 if (!lstrcmpW(pszPropName, wszTarget)) {
1190 WCHAR wszPath[MAX_PATH];
1193 ok(V_VT(pVar) == VT_BSTR ||
1194 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1195 "Wrong variant type for 'Target' property!\n");
1196 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1198 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1199 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1200 if (!result) return E_INVALIDARG;
1202 V_BSTR(pVar) = SysAllocString(wszPath);
1206 if (!lstrcmpW(pszPropName, wszAttributes)) {
1207 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1208 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1209 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1210 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1214 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1215 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1217 return E_INVALIDARG;
1220 if (!lstrcmpW(pszPropName, wszCLSID)) {
1221 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1223 return E_INVALIDARG;
1226 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1227 return E_INVALIDARG;
1230 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1233 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1237 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1238 InitPropertyBag_IPropertyBag_QueryInterface,
1239 InitPropertyBag_IPropertyBag_AddRef,
1240 InitPropertyBag_IPropertyBag_Release,
1241 InitPropertyBag_IPropertyBag_Read,
1242 InitPropertyBag_IPropertyBag_Write
1245 static struct IPropertyBag InitPropertyBag = {
1246 &InitPropertyBag_IPropertyBagVtbl
1249 static void test_FolderShortcut(void) {
1250 IPersistPropertyBag *pPersistPropertyBag;
1251 IShellFolder *pShellFolder, *pDesktopFolder;
1252 IPersistFolder3 *pPersistFolder3;
1255 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1258 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1260 WCHAR wszWineTestFolder[] = {
1261 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1262 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1263 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1264 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1265 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1266 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1267 'N','a','m','e','S','p','a','c','e','\\',
1268 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1269 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1271 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1272 static const GUID CLSID_UnixDosFolder =
1273 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1275 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1276 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1280 if (!pSHGetFolderPathAndSubDirA)
1282 win_skip("FolderShortcut test doesn't work on Win2k\n");
1286 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1287 * via their IPersistPropertyBag interface. And that the target folder
1288 * is taken from the IPropertyBag's 'Target' property.
1290 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1291 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1292 if (hr == REGDB_E_CLASSNOTREG) {
1293 win_skip("CLSID_FolderShortcut is not implemented\n");
1296 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1297 if (hr != S_OK) return;
1299 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1300 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1302 IPersistPropertyBag_Release(pPersistPropertyBag);
1306 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1307 (LPVOID*)&pShellFolder);
1308 IPersistPropertyBag_Release(pPersistPropertyBag);
1309 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1310 if (hr != S_OK) return;
1312 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1313 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1315 IShellFolder_Release(pShellFolder);
1319 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1320 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1321 if (!result) return;
1323 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1324 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1326 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1327 IShellFolder_Release(pShellFolder);
1328 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1329 if (hr != S_OK) return;
1331 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1332 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1333 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1335 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1336 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1337 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1339 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1340 * shell namespace. The target folder, read from the property bag above, remains untouched.
1341 * The following tests show this: The itemidlist for some imaginary shellfolder object
1342 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1343 * itemidlist, but GetDisplayNameOf still returns the path from above.
1345 hr = SHGetDesktopFolder(&pDesktopFolder);
1346 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1347 if (hr != S_OK) return;
1349 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1350 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1351 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1352 RegCloseKey(hShellExtKey);
1353 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1354 &pidlWineTestFolder, NULL);
1355 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1356 IShellFolder_Release(pDesktopFolder);
1357 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1358 if (hr != S_OK) return;
1360 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1361 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1363 IPersistFolder3_Release(pPersistFolder3);
1364 pILFree(pidlWineTestFolder);
1368 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1369 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1370 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1371 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1372 pILFree(pidlCurrentFolder);
1373 pILFree(pidlWineTestFolder);
1375 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1376 IPersistFolder3_Release(pPersistFolder3);
1377 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1378 if (hr != S_OK) return;
1380 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1381 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1383 IShellFolder_Release(pShellFolder);
1387 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1388 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1390 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1391 * but ShellFSFolders. */
1392 myPathAddBackslashW(wszDesktopPath);
1393 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1394 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1395 IShellFolder_Release(pShellFolder);
1399 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1400 &pidlSubFolder, NULL);
1401 RemoveDirectoryW(wszDesktopPath);
1402 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1404 IShellFolder_Release(pShellFolder);
1408 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1409 (LPVOID*)&pPersistFolder3);
1410 IShellFolder_Release(pShellFolder);
1411 pILFree(pidlSubFolder);
1412 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1416 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1417 * a little bit and also allow CLSID_UnixDosFolder. */
1418 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1419 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1420 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1421 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1423 IPersistFolder3_Release(pPersistFolder3);
1426 #include "pshpack1.h"
1427 struct FileStructA {
1431 WORD uFileDate; /* In our current implementation this is */
1432 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1437 struct FileStructW {
1438 WORD cbLen; /* Length of this element. */
1439 BYTE abFooBar1[6]; /* Beyond any recognition. */
1440 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1441 WORD uTime; /* (this is currently speculation) */
1442 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1443 WORD uTime2; /* (this is currently speculation) */
1444 BYTE abFooBar2[4]; /* Beyond any recognition. */
1445 WCHAR wszName[1]; /* The long filename in unicode. */
1446 /* Just for documentation: Right after the unicode string: */
1447 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1448 * SHITEMID->cb == uOffset + cbLen */
1450 #include "poppack.h"
1452 static void test_ITEMIDLIST_format(void) {
1453 WCHAR wszPersonal[MAX_PATH];
1454 LPSHELLFOLDER psfDesktop, psfPersonal;
1455 LPITEMIDLIST pidlPersonal, pidlFile;
1459 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1460 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1463 if (!pSHGetSpecialFolderPathW) return;
1465 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1466 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1467 if (!bResult) return;
1469 SetLastError(0xdeadbeef);
1470 bResult = SetCurrentDirectoryW(wszPersonal);
1471 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1472 win_skip("Most W-calls are not implemented\n");
1475 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1476 if (!bResult) return;
1478 hr = SHGetDesktopFolder(&psfDesktop);
1479 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1480 if (hr != S_OK) return;
1482 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1483 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1485 IShellFolder_Release(psfDesktop);
1489 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1490 (LPVOID*)&psfPersonal);
1491 IShellFolder_Release(psfDesktop);
1492 pILFree(pidlPersonal);
1493 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1494 if (hr != S_OK) return;
1496 for (i=0; i<3; i++) {
1497 CHAR szFile[MAX_PATH];
1498 struct FileStructA *pFileStructA;
1501 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1503 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1504 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1505 if (hFile == INVALID_HANDLE_VALUE) {
1506 IShellFolder_Release(psfPersonal);
1511 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1512 DeleteFileW(wszFile[i]);
1513 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1515 IShellFolder_Release(psfPersonal);
1519 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1520 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1521 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1522 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1524 if (i < 2) /* First two file names are already in valid 8.3 format */
1525 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1527 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1528 * can't implement this correctly, since unix filesystems don't support
1529 * this nasty short/long filename stuff. So we'll probably stay with our
1530 * current habbit of storing the long filename here, which seems to work
1533 ok(pidlFile->mkid.abID[18] == '~' ||
1534 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1535 "Should be derived 8.3 name!\n");
1537 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1538 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1539 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1540 "Alignment byte, where there shouldn't be!\n");
1542 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1543 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1544 "There should be an alignment byte, but isn't!\n");
1546 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1547 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1548 ok ((cbOffset >= sizeof(struct FileStructA) &&
1549 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1550 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1551 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1552 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1554 if (cbOffset >= sizeof(struct FileStructA) &&
1555 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1557 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1559 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1560 "FileStructW's offset and length should add up to the PIDL's length!\n");
1562 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1563 /* Since we just created the file, time of creation,
1564 * time of last access and time of last write access just be the same.
1565 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1566 * after the first run. I do remember something with NTFS keeping the creation time
1567 * if a file is deleted and then created again within a couple of seconds or so.
1568 * Might be the reason. */
1569 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1570 pFileStructA->uFileTime == pFileStructW->uTime,
1571 "Last write time should match creation time!\n");
1573 /* On FAT filesystems the last access time is midnight
1574 local time, so the values of uDate2 and uTime2 will
1575 depend on the local timezone. If the times are exactly
1576 equal then the dates should be identical for both FAT
1577 and NTFS as no timezone is more than 1 day away from UTC.
1579 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1581 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1582 "Last write date and time should match last access date and time!\n");
1586 /* Filesystem may be FAT. Check date within 1 day
1587 and seconds are zero. */
1588 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1589 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1590 "Last access time on FAT filesystems should have zero seconds.\n");
1591 /* TODO: Perform check for date being within one day.*/
1594 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1595 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1596 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1597 "The filename should be stored in unicode at this position!\n");
1604 IShellFolder_Release(psfPersonal);
1607 static void test_SHGetFolderPathAndSubDirA(void)
1613 static char wine[] = "wine";
1614 static char winetemp[] = "wine\\temp";
1615 static char appdata[MAX_PATH];
1616 static char testpath[MAX_PATH];
1617 static char toolongpath[MAX_PATH+1];
1619 if(!pSHGetFolderPathAndSubDirA)
1621 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1625 if(!pSHGetFolderPathA) {
1626 win_skip("SHGetFolderPathA not present!\n");
1629 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1631 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1635 sprintf(testpath, "%s\\%s", appdata, winetemp);
1636 delret = RemoveDirectoryA(testpath);
1637 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1638 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1642 sprintf(testpath, "%s\\%s", appdata, wine);
1643 delret = RemoveDirectoryA(testpath);
1644 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1645 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1649 /* test invalid second parameter */
1650 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1651 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1653 /* test fourth parameter */
1654 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1656 case S_OK: /* winvista */
1657 ok(!strncmp(appdata, testpath, strlen(appdata)),
1658 "expected %s to start with %s\n", testpath, appdata);
1659 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1660 "expected %s to end with %s\n", testpath, winetemp);
1662 case E_INVALIDARG: /* winxp, win2k3 */
1665 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
1668 /* test fifth parameter */
1670 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1671 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1672 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1675 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1676 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1677 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1680 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1681 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1682 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1684 for(i=0; i< MAX_PATH; i++)
1685 toolongpath[i] = '0' + i % 10;
1686 toolongpath[MAX_PATH] = '\0';
1687 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1688 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1689 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1692 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1693 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1695 /* test a not existing path */
1697 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1698 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1699 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1701 /* create a directory inside a not existing directory */
1703 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1704 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1705 ok(!strncmp(appdata, testpath, strlen(appdata)),
1706 "expected %s to start with %s\n", testpath, appdata);
1707 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1708 "expected %s to end with %s\n", testpath, winetemp);
1709 dwret = GetFileAttributes(testpath);
1710 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1713 sprintf(testpath, "%s\\%s", appdata, winetemp);
1714 RemoveDirectoryA(testpath);
1715 sprintf(testpath, "%s\\%s", appdata, wine);
1716 RemoveDirectoryA(testpath);
1719 static void test_LocalizedNames(void)
1721 static char cCurrDirA[MAX_PATH];
1722 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1723 IShellFolder *IDesktopFolder, *testIShellFolder;
1724 ITEMIDLIST *newPIDL;
1727 static char resourcefile[MAX_PATH];
1732 static const char desktopini_contents1[] =
1733 "[.ShellClassInfo]\r\n"
1734 "LocalizedResourceName=@";
1735 static const char desktopini_contents2[] =
1737 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1738 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1740 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1741 CreateDirectoryA(".\\testfolder", NULL);
1743 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1745 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1747 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1748 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1749 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1750 ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1751 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1752 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
1753 "WriteFile failed %i\n", GetLastError());
1756 /* get IShellFolder for parent */
1757 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1758 len = lstrlenA(cCurrDirA);
1761 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1764 if(cCurrDirA[len-1] == '\\')
1765 cCurrDirA[len-1] = 0;
1767 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1769 hr = SHGetDesktopFolder(&IDesktopFolder);
1770 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1772 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1773 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1775 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1776 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1778 IMalloc_Free(ppM, newPIDL);
1780 /* windows reads the display name from the resource */
1781 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1782 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1784 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1785 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1787 if (hr == S_OK && pStrRetToBufW)
1789 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1790 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1792 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1793 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1794 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1797 /* editing name is also read from the resource */
1798 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1799 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1801 if (hr == S_OK && pStrRetToBufW)
1803 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1804 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1806 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1807 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1808 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1811 /* parsing name is unchanged */
1812 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1813 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1815 if (hr == S_OK && pStrRetToBufW)
1817 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1818 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1819 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1822 IShellFolder_Release(IDesktopFolder);
1823 IShellFolder_Release(testIShellFolder);
1825 IMalloc_Free(ppM, newPIDL);
1828 DeleteFileA(".\\testfolder\\desktop.ini");
1829 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1830 RemoveDirectoryA(".\\testfolder");
1833 static void test_SHCreateShellItem(void)
1835 IShellItem *shellitem, *shellitem2;
1836 IPersistIDList *persistidl;
1837 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test;
1839 char curdirA[MAX_PATH];
1840 WCHAR curdirW[MAX_PATH];
1841 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
1842 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
1844 GetCurrentDirectoryA(MAX_PATH, curdirA);
1846 if (!pSHCreateShellItem)
1848 win_skip("SHCreateShellItem isn't available\n");
1852 if (!lstrlenA(curdirA))
1854 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
1858 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
1860 ret = SHGetDesktopFolder(&desktopfolder);
1861 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
1863 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
1864 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1866 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)¤tfolder);
1867 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
1869 CreateTestFile(".\\testfile");
1871 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
1872 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1874 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
1876 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
1877 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
1879 if (0) /* crashes on Windows XP */
1881 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
1882 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
1883 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
1884 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
1887 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
1888 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1891 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1892 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1895 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1896 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1899 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1902 IPersistIDList_Release(persistidl);
1904 IShellItem_Release(shellitem);
1907 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
1908 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1911 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1912 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1915 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1916 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1919 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1922 IPersistIDList_Release(persistidl);
1925 ret = IShellItem_GetParent(shellitem, &shellitem2);
1926 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
1929 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
1930 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1933 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1934 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1937 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1940 IPersistIDList_Release(persistidl);
1942 IShellItem_Release(shellitem2);
1945 IShellItem_Release(shellitem);
1948 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
1949 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1952 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1953 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1956 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1957 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1960 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1963 IPersistIDList_Release(persistidl);
1965 IShellItem_Release(shellitem);
1968 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
1969 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
1970 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1973 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1974 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1977 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1978 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1981 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1984 IPersistIDList_Release(persistidl);
1986 IShellItem_Release(shellitem);
1989 DeleteFileA(".\\testfile");
1990 pILFree(pidl_abstestfile);
1991 pILFree(pidl_testfile);
1993 IShellFolder_Release(currentfolder);
1994 IShellFolder_Release(desktopfolder);
1997 static void test_SHParseDisplayName(void)
1999 static const WCHAR prefixW[] = {'w','t',0};
2000 LPITEMIDLIST pidl1, pidl2;
2001 IShellFolder *desktop;
2002 WCHAR dirW[MAX_PATH];
2007 if (!pSHParseDisplayName)
2009 win_skip("SHParseDisplayName isn't available\n");
2015 /* crashes on native */
2016 hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
2018 hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
2021 pidl1 = (LPITEMIDLIST)0xdeadbeef;
2022 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
2023 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
2024 hr == E_INVALIDARG, "failed %08x\n", hr);
2025 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
2029 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
2030 ok(hr == S_OK, "failed %08x\n", hr);
2031 hr = SHGetDesktopFolder(&desktop);
2032 ok(hr == S_OK, "failed %08x\n", hr);
2033 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
2034 ok(hr == S_OK, "failed %08x\n", hr);
2035 ret = pILIsEqual(pidl1, pidl2);
2036 ok(ret == TRUE, "expected equal idls\n");
2041 GetTempPathW(sizeof(dirW)/sizeof(WCHAR), dirW);
2042 GetTempFileNameW(dirW, prefixW, 0, dirW);
2043 CreateFileW(dirW, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2045 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
2046 ok(hr == S_OK, "failed %08x\n", hr);
2047 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
2048 ok(hr == S_OK, "failed %08x\n", hr);
2050 ret = pILIsEqual(pidl1, pidl2);
2051 ok(ret == TRUE, "expected equal idls\n");
2057 IShellFolder_Release(desktop);
2060 static void test_desktop_IPersist(void)
2062 IShellFolder *desktop;
2067 hr = SHGetDesktopFolder(&desktop);
2068 ok(hr == S_OK, "failed %08x\n", hr);
2070 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
2071 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
2077 /* crashes on native */
2078 hr = IPersist_GetClassID(persist, NULL);
2080 memset(&clsid, 0, sizeof(clsid));
2081 hr = IPersist_GetClassID(persist, &clsid);
2082 ok(hr == S_OK, "failed %08x\n", hr);
2083 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
2084 IPersist_Release(persist);
2087 IShellFolder_Release(desktop);
2090 START_TEST(shlfolder)
2092 init_function_pointers();
2093 /* if OleInitialize doesn't get called, ParseDisplayName returns
2094 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
2095 OleInitialize(NULL);
2097 test_ParseDisplayName();
2098 test_SHParseDisplayName();
2099 test_BindToObject();
2100 test_EnumObjects_and_CompareIDs();
2101 test_GetDisplayName();
2102 test_GetAttributesOf();
2103 test_SHGetPathFromIDList();
2104 test_CallForAttributes();
2105 test_FolderShortcut();
2106 test_ITEMIDLIST_format();
2107 test_SHGetFolderPathAndSubDirA();
2108 test_LocalizedNames();
2109 test_SHCreateShellItem();
2110 test_desktop_IPersist();