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 HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
50 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
51 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
52 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
53 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
54 static void (WINAPI *pILFree)(LPITEMIDLIST);
55 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
56 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
57 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
58 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
59 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
60 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
61 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
62 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
63 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
65 static void init_function_pointers(void)
71 hmod = GetModuleHandleA("shell32.dll");
73 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
74 MAKEFUNC(SHBindToParent);
75 MAKEFUNC(SHCreateItemFromIDList);
76 MAKEFUNC(SHCreateItemFromParsingName);
77 MAKEFUNC(SHCreateShellItem);
78 MAKEFUNC(SHGetFolderPathA);
79 MAKEFUNC(SHGetFolderPathAndSubDirA);
80 MAKEFUNC(SHGetPathFromIDListW);
81 MAKEFUNC(SHGetSpecialFolderPathA);
82 MAKEFUNC(SHGetSpecialFolderPathW);
83 MAKEFUNC(SHGetSpecialFolderLocation);
84 MAKEFUNC(SHParseDisplayName);
85 MAKEFUNC(SHGetNameFromIDList);
86 MAKEFUNC(SHGetItemFromDataObject);
89 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
90 MAKEFUNC_ORD(ILFindLastID, 16);
91 MAKEFUNC_ORD(ILIsEqual, 21);
92 MAKEFUNC_ORD(ILCombine, 25);
93 MAKEFUNC_ORD(ILFree, 155);
94 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
97 /* test named exports */
98 ptr = GetProcAddress(hmod, "ILFree");
99 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
102 #define TESTNAMED(f) \
103 ptr = (void*)GetProcAddress(hmod, #f); \
104 ok(ptr != 0, "expected named export for " #f "\n");
106 TESTNAMED(ILAppendID);
108 TESTNAMED(ILCloneFirst);
109 TESTNAMED(ILCombine);
110 TESTNAMED(ILCreateFromPath);
111 TESTNAMED(ILCreateFromPathA);
112 TESTNAMED(ILCreateFromPathW);
113 TESTNAMED(ILFindChild);
114 TESTNAMED(ILFindLastID);
115 TESTNAMED(ILGetNext);
116 TESTNAMED(ILGetSize);
117 TESTNAMED(ILIsEqual);
118 TESTNAMED(ILIsParent);
119 TESTNAMED(ILRemoveLastID);
120 TESTNAMED(ILSaveToStream);
124 hmod = GetModuleHandleA("shlwapi.dll");
125 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
127 hr = SHGetMalloc(&ppM);
128 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
131 static void test_ParseDisplayName(void)
134 IShellFolder *IDesktopFolder;
135 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
136 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
137 static const char *cInetTestA = "http:\\yyy";
138 static const char *cInetTest2A = "xx:yyy";
140 WCHAR cTestDirW [MAX_PATH] = {0};
144 hr = SHGetDesktopFolder(&IDesktopFolder);
145 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
146 if(hr != S_OK) return;
148 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
149 if (pSHCreateShellItem)
151 /* null name and pidl */
152 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
153 NULL, NULL, NULL, NULL, NULL, 0);
154 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
157 newPIDL = (ITEMIDLIST*)0xdeadbeef;
158 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
159 NULL, NULL, NULL, NULL, &newPIDL, 0);
160 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
161 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
164 win_skip("Tests would crash on W2K and below\n");
166 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
167 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
168 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
169 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
170 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
173 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
174 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
175 IMalloc_Free(ppM, newPIDL);
178 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
179 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
180 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
181 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
182 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
185 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
186 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
187 IMalloc_Free(ppM, newPIDL);
190 res = GetFileAttributesA(cNonExistDir1A);
191 if(res != INVALID_FILE_ATTRIBUTES)
193 skip("Test directory unexpectedly exists\n");
197 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
198 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
199 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
200 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
201 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
203 res = GetFileAttributesA(cNonExistDir2A);
204 if(res != INVALID_FILE_ATTRIBUTES)
206 skip("Test directory unexpectedly exists\n");
210 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
211 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
212 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
213 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
214 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
216 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
217 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
218 * out it doesn't. The magic seems to happen in the file dialogs, then. */
219 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
221 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
225 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
226 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
227 if (!bRes) goto finished;
229 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
230 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
231 if (hr != S_OK) goto finished;
233 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
234 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
235 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
236 pILFindLastID(newPIDL)->mkid.abID[0]);
237 IMalloc_Free(ppM, newPIDL);
240 IShellFolder_Release(IDesktopFolder);
243 /* creates a file with the specified name for tests */
244 static void CreateTestFile(const CHAR *name)
249 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
250 if (file != INVALID_HANDLE_VALUE)
252 WriteFile(file, name, strlen(name), &written, NULL);
253 WriteFile(file, "\n", strlen("\n"), &written, NULL);
259 /* initializes the tests */
260 static void CreateFilesFolders(void)
262 CreateDirectoryA(".\\testdir", NULL);
263 CreateDirectoryA(".\\testdir\\test.txt", NULL);
264 CreateTestFile (".\\testdir\\test1.txt ");
265 CreateTestFile (".\\testdir\\test2.txt ");
266 CreateTestFile (".\\testdir\\test3.txt ");
267 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
268 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
271 /* cleans after tests */
272 static void Cleanup(void)
274 DeleteFileA(".\\testdir\\test1.txt");
275 DeleteFileA(".\\testdir\\test2.txt");
276 DeleteFileA(".\\testdir\\test3.txt");
277 RemoveDirectoryA(".\\testdir\\test.txt");
278 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
279 RemoveDirectoryA(".\\testdir\\testdir2");
280 RemoveDirectoryA(".\\testdir");
285 static void test_EnumObjects(IShellFolder *iFolder)
287 IEnumIDList *iEnumList;
288 LPITEMIDLIST newPIDL, idlArr[10];
293 static const WORD iResults [5][5] =
302 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
303 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
304 static const ULONG attrs[5] =
306 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
307 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
308 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
309 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
310 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
313 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
314 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
316 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
317 * the filesystem shellfolders return S_OK even if less than 'celt' items are
318 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
319 * only ever returns a single entry per call. */
320 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
322 ok (i == 5, "i: %d\n", i);
324 hr = IEnumIDList_Release(iEnumList);
325 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
327 /* Sort them first in case of wrong order from system */
328 for (i=0;i<5;i++) for (j=0;j<5;j++)
329 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
332 idlArr[i] = idlArr[j];
336 for (i=0;i<5;i++) for (j=0;j<5;j++)
338 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
339 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
343 for (i = 0; i < 5; i++)
346 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
347 /* Native returns all flags no matter what we ask for */
348 flags = SFGAO_CANCOPY;
349 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
350 flags &= SFGAO_testfor;
351 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
352 ok(flags == (attrs[i]) ||
353 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
354 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
355 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
357 flags = SFGAO_testfor;
358 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
359 flags &= SFGAO_testfor;
360 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
361 ok(flags == attrs[i] ||
362 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
363 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
367 IMalloc_Free(ppM, idlArr[i]);
370 static void test_BindToObject(void)
374 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
375 SHITEMID emptyitem = { 0, { 0 } };
376 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
377 WCHAR wszSystemDir[MAX_PATH];
378 char szSystemDir[MAX_PATH];
379 WCHAR wszMyComputer[] = {
380 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
381 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
383 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
384 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
386 hr = SHGetDesktopFolder(&psfDesktop);
387 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
388 if (hr != S_OK) return;
390 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
391 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
393 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
394 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
396 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
397 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
399 IShellFolder_Release(psfDesktop);
403 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
404 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
405 IShellFolder_Release(psfDesktop);
406 IMalloc_Free(ppM, pidlMyComputer);
407 if (hr != S_OK) return;
409 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
410 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
414 /* this call segfaults on 98SE */
415 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
416 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
419 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
420 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
421 if (cChars == 0 || cChars >= MAX_PATH) {
422 IShellFolder_Release(psfMyComputer);
425 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
427 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
428 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
430 IShellFolder_Release(psfMyComputer);
434 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
435 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
436 IShellFolder_Release(psfMyComputer);
437 IMalloc_Free(ppM, pidlSystemDir);
438 if (hr != S_OK) return;
440 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
441 ok (hr == E_INVALIDARG,
442 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
446 /* this call segfaults on 98SE */
447 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
448 ok (hr == E_INVALIDARG,
449 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
452 IShellFolder_Release(psfSystemDir);
455 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
456 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
460 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
466 if (lpszPath[-1] != '\\')
475 static void test_GetDisplayName(void)
480 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
481 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
484 LPSHELLFOLDER psfDesktop, psfPersonal;
486 SHITEMID emptyitem = { 0, { 0 } };
487 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
488 LPCITEMIDLIST pidlLast;
489 static const CHAR szFileName[] = "winetest.foo";
490 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
491 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
493 /* I'm trying to figure if there is a functional difference between calling
494 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
495 * binding to the shellfolder. One thing I thought of was that perhaps
496 * SHGetPathFromIDListW would be able to get the path to a file, which does
497 * not exist anymore, while the other method wouldn't. It turns out there's
498 * no functional difference in this respect.
501 if(!pSHGetSpecialFolderPathA) {
502 win_skip("SHGetSpecialFolderPathA is not available\n");
506 /* First creating a directory in MyDocuments and a file in this directory. */
507 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
508 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
511 /* Use ANSI file functions so this works on Windows 9x */
512 lstrcatA(szTestDir, "\\winetest");
513 CreateDirectoryA(szTestDir, NULL);
514 attr=GetFileAttributesA(szTestDir);
515 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
517 ok(0, "unable to create the '%s' directory\n", szTestDir);
521 lstrcpyA(szTestFile, szTestDir);
522 lstrcatA(szTestFile, "\\");
523 lstrcatA(szTestFile, szFileName);
524 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
525 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
526 if (hTestFile == INVALID_HANDLE_VALUE) return;
527 CloseHandle(hTestFile);
529 /* Getting an itemidlist for the file. */
530 hr = SHGetDesktopFolder(&psfDesktop);
531 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
532 if (hr != S_OK) return;
534 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
536 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
537 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
539 IShellFolder_Release(psfDesktop);
543 pidlLast = pILFindLastID(pidlTestFile);
544 ok(pidlLast->mkid.cb >=76 ||
545 broken(pidlLast->mkid.cb == 28) || /* W2K */
546 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
547 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
548 if (pidlLast->mkid.cb >= 28) {
549 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
550 "Filename should be stored as ansi-string at this position!\n");
552 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
553 if (pidlLast->mkid.cb >= 76) {
554 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
555 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
556 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
557 "Filename should be stored as wchar-string at this position!\n");
560 /* It seems as if we cannot bind to regular files on windows, but only directories.
562 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
564 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
565 hr == E_NOTIMPL || /* Vista */
566 broken(hr == S_OK), /* Win9x, W2K */
569 IShellFolder_Release(psfFile);
572 if (!pSHBindToParent)
574 win_skip("SHBindToParent is missing\n");
575 DeleteFileA(szTestFile);
576 RemoveDirectoryA(szTestDir);
580 /* Some tests for IShellFolder::SetNameOf */
581 if (pSHGetFolderPathAndSubDirA)
583 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
584 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
586 /* It's ok to use this fixed path. Call will fail anyway. */
587 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
588 LPITEMIDLIST pidlNew;
590 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
591 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
592 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
595 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
596 "pidl returned from SetNameOf should be simple!\n");
598 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
599 * is implemented on top of SHFileOperation in WinXP. */
600 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
601 SHGDN_FORPARSING, NULL);
602 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
604 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
605 * SHGDN flags specify an absolute path. */
606 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
607 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
612 IShellFolder_Release(psfPersonal);
616 win_skip("Avoid needs of interaction on Win2k\n");
618 /* Deleting the file and the directory */
619 DeleteFileA(szTestFile);
620 RemoveDirectoryA(szTestDir);
622 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
623 if (pSHGetPathFromIDListW)
625 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
626 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
627 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
630 /* SHBindToParent fails, if called with a NULL PIDL. */
631 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
632 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
634 /* But it succeeds with an empty PIDL. */
635 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
636 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
637 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
639 IShellFolder_Release(psfPersonal);
641 /* Binding to the folder and querying the display name of the file also works. */
642 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
643 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
645 IShellFolder_Release(psfDesktop);
649 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
650 * pidlTestFile (In accordance with MSDN). */
651 ok (pILFindLastID(pidlTestFile) == pidlLast,
652 "SHBindToParent doesn't return the last id of the pidl param!\n");
654 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
655 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
657 IShellFolder_Release(psfDesktop);
658 IShellFolder_Release(psfPersonal);
664 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
665 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
666 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
669 ILFree(pidlTestFile);
670 IShellFolder_Release(psfDesktop);
671 IShellFolder_Release(psfPersonal);
674 static void test_CallForAttributes(void)
680 LPSHELLFOLDER psfDesktop;
681 LPITEMIDLIST pidlMyDocuments;
682 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
683 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
684 static const WCHAR wszCallForAttributes[] = {
685 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
686 static const WCHAR wszMyDocumentsKey[] = {
687 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
688 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
689 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
690 WCHAR wszMyDocuments[] = {
691 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
692 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
694 /* For the root of a namespace extension, the attributes are not queried by binding
695 * to the object and calling GetAttributesOf. Instead, the attributes are read from
696 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
698 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
699 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
700 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
701 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
703 hr = SHGetDesktopFolder(&psfDesktop);
704 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
705 if (hr != S_OK) return;
707 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
708 &pidlMyDocuments, NULL);
710 broken(hr == E_INVALIDARG), /* Win95, NT4 */
711 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
713 IShellFolder_Release(psfDesktop);
717 dwAttributes = 0xffffffff;
718 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
719 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
720 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
722 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
723 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
724 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
725 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
727 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
728 * key. So the test will return at this point, if run on wine.
730 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
731 ok (lResult == ERROR_SUCCESS ||
732 lResult == ERROR_ACCESS_DENIED,
733 "RegOpenKeyEx failed! result: %08x\n", lResult);
734 if (lResult != ERROR_SUCCESS) {
735 if (lResult == ERROR_ACCESS_DENIED)
736 skip("Not enough rights to open the registry key\n");
737 IMalloc_Free(ppM, pidlMyDocuments);
738 IShellFolder_Release(psfDesktop);
742 /* Query MyDocuments' Attributes value, to be able to restore it later. */
743 dwSize = sizeof(DWORD);
744 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
745 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
746 if (lResult != ERROR_SUCCESS) {
748 IMalloc_Free(ppM, pidlMyDocuments);
749 IShellFolder_Release(psfDesktop);
753 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
754 dwSize = sizeof(DWORD);
755 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
756 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
757 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
758 if (lResult != ERROR_SUCCESS) {
760 IMalloc_Free(ppM, pidlMyDocuments);
761 IShellFolder_Release(psfDesktop);
765 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
766 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
767 * SFGAO_FILESYSTEM attributes. */
768 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
769 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
770 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
771 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
772 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
774 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
775 * GetAttributesOf. It seems that once there is a single attribute queried, for which
776 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
777 * the flags in Attributes are ignored.
779 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
780 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
781 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
782 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
784 ok (dwAttributes == SFGAO_FILESYSTEM,
785 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
788 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
789 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
790 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
791 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
793 IMalloc_Free(ppM, pidlMyDocuments);
794 IShellFolder_Release(psfDesktop);
797 static void test_GetAttributesOf(void)
800 LPSHELLFOLDER psfDesktop, psfMyComputer;
801 SHITEMID emptyitem = { 0, { 0 } };
802 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
803 LPITEMIDLIST pidlMyComputer;
805 static const DWORD desktopFlags[] = {
807 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
808 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
810 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
811 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
812 /* WinMe, Win9x, WinNT*/
813 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
814 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
816 static const DWORD myComputerFlags[] = {
818 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
819 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
821 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
822 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
823 /* WinMe, Win9x, WinNT */
824 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
825 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
826 /* Win95, WinNT when queried directly */
827 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
828 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
830 WCHAR wszMyComputer[] = {
831 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
832 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
833 char cCurrDirA [MAX_PATH] = {0};
834 WCHAR cCurrDirW [MAX_PATH];
835 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
836 IShellFolder *IDesktopFolder, *testIShellFolder;
839 BOOL foundFlagsMatch;
841 hr = SHGetDesktopFolder(&psfDesktop);
842 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
843 if (hr != S_OK) return;
845 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
846 dwFlags = 0xffffffff;
847 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
848 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
849 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
850 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
852 if (desktopFlags[i] == dwFlags)
853 foundFlagsMatch = TRUE;
855 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
857 /* .. or with no itemidlist at all. */
858 dwFlags = 0xffffffff;
859 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
860 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
861 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
862 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
864 if (desktopFlags[i] == dwFlags)
865 foundFlagsMatch = TRUE;
867 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
869 /* Testing the attributes of the MyComputer shellfolder */
870 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
871 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
873 IShellFolder_Release(psfDesktop);
877 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
878 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
880 dwFlags = 0xffffffff;
881 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
882 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
883 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
884 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
886 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
887 foundFlagsMatch = TRUE;
890 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
892 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
893 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
894 IShellFolder_Release(psfDesktop);
895 IMalloc_Free(ppM, pidlMyComputer);
896 if (hr != S_OK) return;
898 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
900 ok (hr == E_INVALIDARG ||
901 broken(hr == S_OK), /* W2K and earlier */
902 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
904 dwFlags = 0xffffffff;
905 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
906 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
907 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
908 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
910 if (myComputerFlags[i] == dwFlags)
911 foundFlagsMatch = TRUE;
914 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
916 IShellFolder_Release(psfMyComputer);
918 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
919 len = lstrlenA(cCurrDirA);
922 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
925 if (len > 3 && cCurrDirA[len-1] == '\\')
926 cCurrDirA[len-1] = 0;
928 /* create test directory */
929 CreateFilesFolders();
931 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
933 hr = SHGetDesktopFolder(&IDesktopFolder);
934 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
936 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
937 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
939 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
940 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
942 IMalloc_Free(ppM, newPIDL);
944 /* get relative PIDL */
945 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
946 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
948 /* test the shell attributes of the test directory using the relative PIDL */
949 dwFlags = SFGAO_FOLDER;
950 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
951 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
952 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
955 IMalloc_Free(ppM, newPIDL);
957 /* append testdirectory name to path */
958 if (cCurrDirA[len-1] == '\\')
959 cCurrDirA[len-1] = 0;
960 lstrcatA(cCurrDirA, "\\testdir");
961 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
963 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
964 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
966 /* test the shell attributes of the test directory using the absolute PIDL */
967 dwFlags = SFGAO_FOLDER;
968 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
969 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
970 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
973 IMalloc_Free(ppM, newPIDL);
975 IShellFolder_Release(testIShellFolder);
979 IShellFolder_Release(IDesktopFolder);
982 static void test_SHGetPathFromIDList(void)
984 SHITEMID emptyitem = { 0, { 0 } };
985 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
986 LPITEMIDLIST pidlMyComputer;
987 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
990 LPSHELLFOLDER psfDesktop;
991 WCHAR wszMyComputer[] = {
992 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
993 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
994 WCHAR wszFileName[MAX_PATH];
995 LPITEMIDLIST pidlTestFile;
998 static WCHAR wszTestFile[] = {
999 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1000 LPITEMIDLIST pidlPrograms;
1002 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1004 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1008 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1011 result = pSHGetPathFromIDListW(NULL, wszPath);
1012 ok(!result, "Expected failure\n");
1013 ok(!wszPath[0], "Expected empty string\n");
1015 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1016 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1017 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1018 if (!result) return;
1020 /* Check if we are on Win9x */
1021 SetLastError(0xdeadbeef);
1022 lstrcmpiW(wszDesktop, wszDesktop);
1023 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1025 win_skip("Most W-calls are not implemented\n");
1029 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1030 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1031 if (!result) return;
1032 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1034 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1035 hr = SHGetDesktopFolder(&psfDesktop);
1036 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1037 if (hr != S_OK) return;
1039 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1040 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1042 IShellFolder_Release(psfDesktop);
1046 SetLastError(0xdeadbeef);
1049 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1050 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1051 ok (GetLastError()==0xdeadbeef ||
1052 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1053 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1054 ok (!wszPath[0], "Expected empty path\n");
1056 IShellFolder_Release(psfDesktop);
1060 IMalloc_Free(ppM, pidlMyComputer);
1062 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1063 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1065 IShellFolder_Release(psfDesktop);
1068 myPathAddBackslashW(wszFileName);
1069 lstrcatW(wszFileName, wszTestFile);
1070 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1071 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1072 if (hTestFile == INVALID_HANDLE_VALUE) {
1073 IShellFolder_Release(psfDesktop);
1076 CloseHandle(hTestFile);
1078 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1079 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1081 IShellFolder_Release(psfDesktop);
1082 DeleteFileW(wszFileName);
1083 IMalloc_Free(ppM, pidlTestFile);
1087 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1088 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1089 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1090 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1091 IShellFolder_Release(psfDesktop);
1092 DeleteFileW(wszFileName);
1094 IMalloc_Free(ppM, pidlTestFile);
1099 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1100 ok(0 == lstrcmpW(wszFileName, wszPath),
1101 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1102 "returned incorrect path for file placed on desktop\n");
1105 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1106 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1107 IMalloc_Free(ppM, pidlTestFile);
1108 if (!result) return;
1109 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1112 /* Test if we can get the path from the start menu "program files" PIDL. */
1113 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1114 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1116 SetLastError(0xdeadbeef);
1117 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1118 IMalloc_Free(ppM, pidlPrograms);
1119 ok(result, "SHGetPathFromIDListW failed\n");
1122 static void test_EnumObjects_and_CompareIDs(void)
1124 ITEMIDLIST *newPIDL;
1125 IShellFolder *IDesktopFolder, *testIShellFolder;
1126 char cCurrDirA [MAX_PATH] = {0};
1127 static const CHAR cTestDirA[] = "\\testdir";
1128 WCHAR cTestDirW[MAX_PATH];
1132 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1133 len = lstrlenA(cCurrDirA);
1136 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1139 if(cCurrDirA[len-1] == '\\')
1140 cCurrDirA[len-1] = 0;
1142 lstrcatA(cCurrDirA, cTestDirA);
1143 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1145 hr = SHGetDesktopFolder(&IDesktopFolder);
1146 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1148 CreateFilesFolders();
1150 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1151 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1153 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1154 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1156 test_EnumObjects(testIShellFolder);
1158 IShellFolder_Release(testIShellFolder);
1162 IMalloc_Free(ppM, newPIDL);
1164 IShellFolder_Release(IDesktopFolder);
1167 /* A simple implementation of an IPropertyBag, which returns fixed values for
1168 * 'Target' and 'Attributes' properties.
1170 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1174 return E_INVALIDARG;
1176 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1179 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1180 return E_NOINTERFACE;
1183 IPropertyBag_AddRef(iface);
1187 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1191 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1195 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1196 VARIANT *pVar, IErrorLog *pErrorLog)
1198 static const WCHAR wszTargetSpecialFolder[] = {
1199 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1200 static const WCHAR wszTarget[] = {
1201 'T','a','r','g','e','t',0 };
1202 static const WCHAR wszAttributes[] = {
1203 'A','t','t','r','i','b','u','t','e','s',0 };
1204 static const WCHAR wszResolveLinkFlags[] = {
1205 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1206 static const WCHAR wszTargetKnownFolder[] = {
1207 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1208 static const WCHAR wszCLSID[] = {
1209 'C','L','S','I','D',0 };
1211 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1212 ok(V_VT(pVar) == VT_I4 ||
1213 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1214 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1215 return E_INVALIDARG;
1218 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1220 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1221 return E_INVALIDARG;
1224 if (!lstrcmpW(pszPropName, wszTarget)) {
1225 WCHAR wszPath[MAX_PATH];
1228 ok(V_VT(pVar) == VT_BSTR ||
1229 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1230 "Wrong variant type for 'Target' property!\n");
1231 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1233 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1234 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1235 if (!result) return E_INVALIDARG;
1237 V_BSTR(pVar) = SysAllocString(wszPath);
1241 if (!lstrcmpW(pszPropName, wszAttributes)) {
1242 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1243 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1244 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1245 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1249 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1250 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1252 return E_INVALIDARG;
1255 if (!lstrcmpW(pszPropName, wszCLSID)) {
1256 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1258 return E_INVALIDARG;
1261 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1262 return E_INVALIDARG;
1265 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1268 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1272 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1273 InitPropertyBag_IPropertyBag_QueryInterface,
1274 InitPropertyBag_IPropertyBag_AddRef,
1275 InitPropertyBag_IPropertyBag_Release,
1276 InitPropertyBag_IPropertyBag_Read,
1277 InitPropertyBag_IPropertyBag_Write
1280 static struct IPropertyBag InitPropertyBag = {
1281 &InitPropertyBag_IPropertyBagVtbl
1284 static void test_FolderShortcut(void) {
1285 IPersistPropertyBag *pPersistPropertyBag;
1286 IShellFolder *pShellFolder, *pDesktopFolder;
1287 IPersistFolder3 *pPersistFolder3;
1290 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1293 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1295 WCHAR wszWineTestFolder[] = {
1296 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1297 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1298 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1299 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1300 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1301 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1302 'N','a','m','e','S','p','a','c','e','\\',
1303 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1304 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1306 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1307 static const GUID CLSID_UnixDosFolder =
1308 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1310 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1311 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1315 if (!pSHGetFolderPathAndSubDirA)
1317 win_skip("FolderShortcut test doesn't work on Win2k\n");
1321 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1322 * via their IPersistPropertyBag interface. And that the target folder
1323 * is taken from the IPropertyBag's 'Target' property.
1325 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1326 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1327 if (hr == REGDB_E_CLASSNOTREG) {
1328 win_skip("CLSID_FolderShortcut is not implemented\n");
1331 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1332 if (hr != S_OK) return;
1334 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1335 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1337 IPersistPropertyBag_Release(pPersistPropertyBag);
1341 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1342 (LPVOID*)&pShellFolder);
1343 IPersistPropertyBag_Release(pPersistPropertyBag);
1344 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1345 if (hr != S_OK) return;
1347 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1348 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1350 IShellFolder_Release(pShellFolder);
1354 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1355 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1356 if (!result) return;
1358 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1359 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1361 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1362 IShellFolder_Release(pShellFolder);
1363 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1364 if (hr != S_OK) return;
1366 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1367 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1368 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1370 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1371 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1372 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1374 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1375 * shell namespace. The target folder, read from the property bag above, remains untouched.
1376 * The following tests show this: The itemidlist for some imaginary shellfolder object
1377 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1378 * itemidlist, but GetDisplayNameOf still returns the path from above.
1380 hr = SHGetDesktopFolder(&pDesktopFolder);
1381 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1382 if (hr != S_OK) return;
1384 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1385 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1386 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1387 RegCloseKey(hShellExtKey);
1388 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1389 &pidlWineTestFolder, NULL);
1390 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1391 IShellFolder_Release(pDesktopFolder);
1392 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1393 if (hr != S_OK) return;
1395 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1396 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1398 IPersistFolder3_Release(pPersistFolder3);
1399 pILFree(pidlWineTestFolder);
1403 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1404 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1405 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1406 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1407 pILFree(pidlCurrentFolder);
1408 pILFree(pidlWineTestFolder);
1410 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1411 IPersistFolder3_Release(pPersistFolder3);
1412 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1413 if (hr != S_OK) return;
1415 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1416 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1418 IShellFolder_Release(pShellFolder);
1422 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1423 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1425 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1426 * but ShellFSFolders. */
1427 myPathAddBackslashW(wszDesktopPath);
1428 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1429 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1430 IShellFolder_Release(pShellFolder);
1434 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1435 &pidlSubFolder, NULL);
1436 RemoveDirectoryW(wszDesktopPath);
1437 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1439 IShellFolder_Release(pShellFolder);
1443 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1444 (LPVOID*)&pPersistFolder3);
1445 IShellFolder_Release(pShellFolder);
1446 pILFree(pidlSubFolder);
1447 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1451 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1452 * a little bit and also allow CLSID_UnixDosFolder. */
1453 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1454 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1455 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1456 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1458 IPersistFolder3_Release(pPersistFolder3);
1461 #include "pshpack1.h"
1462 struct FileStructA {
1466 WORD uFileDate; /* In our current implementation this is */
1467 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1472 struct FileStructW {
1473 WORD cbLen; /* Length of this element. */
1474 BYTE abFooBar1[6]; /* Beyond any recognition. */
1475 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1476 WORD uTime; /* (this is currently speculation) */
1477 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1478 WORD uTime2; /* (this is currently speculation) */
1479 BYTE abFooBar2[4]; /* Beyond any recognition. */
1480 WCHAR wszName[1]; /* The long filename in unicode. */
1481 /* Just for documentation: Right after the unicode string: */
1482 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1483 * SHITEMID->cb == uOffset + cbLen */
1485 #include "poppack.h"
1487 static void test_ITEMIDLIST_format(void) {
1488 WCHAR wszPersonal[MAX_PATH];
1489 LPSHELLFOLDER psfDesktop, psfPersonal;
1490 LPITEMIDLIST pidlPersonal, pidlFile;
1494 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1495 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1498 if (!pSHGetSpecialFolderPathW) return;
1500 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1501 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1502 if (!bResult) return;
1504 SetLastError(0xdeadbeef);
1505 bResult = SetCurrentDirectoryW(wszPersonal);
1506 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1507 win_skip("Most W-calls are not implemented\n");
1510 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1511 if (!bResult) return;
1513 hr = SHGetDesktopFolder(&psfDesktop);
1514 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1515 if (hr != S_OK) return;
1517 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1518 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1520 IShellFolder_Release(psfDesktop);
1524 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1525 (LPVOID*)&psfPersonal);
1526 IShellFolder_Release(psfDesktop);
1527 pILFree(pidlPersonal);
1528 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1529 if (hr != S_OK) return;
1531 for (i=0; i<3; i++) {
1532 CHAR szFile[MAX_PATH];
1533 struct FileStructA *pFileStructA;
1536 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1538 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1539 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1540 if (hFile == INVALID_HANDLE_VALUE) {
1541 IShellFolder_Release(psfPersonal);
1546 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1547 DeleteFileW(wszFile[i]);
1548 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1550 IShellFolder_Release(psfPersonal);
1554 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1555 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1556 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1557 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1559 if (i < 2) /* First two file names are already in valid 8.3 format */
1560 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1562 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1563 * can't implement this correctly, since unix filesystems don't support
1564 * this nasty short/long filename stuff. So we'll probably stay with our
1565 * current habbit of storing the long filename here, which seems to work
1568 ok(pidlFile->mkid.abID[18] == '~' ||
1569 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1570 "Should be derived 8.3 name!\n");
1572 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1573 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1574 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1575 "Alignment byte, where there shouldn't be!\n");
1577 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1578 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1579 "There should be an alignment byte, but isn't!\n");
1581 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1582 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1583 ok ((cbOffset >= sizeof(struct FileStructA) &&
1584 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1585 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1586 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1587 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1589 if (cbOffset >= sizeof(struct FileStructA) &&
1590 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1592 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1594 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1595 "FileStructW's offset and length should add up to the PIDL's length!\n");
1597 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1598 /* Since we just created the file, time of creation,
1599 * time of last access and time of last write access just be the same.
1600 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1601 * after the first run. I do remember something with NTFS keeping the creation time
1602 * if a file is deleted and then created again within a couple of seconds or so.
1603 * Might be the reason. */
1604 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1605 pFileStructA->uFileTime == pFileStructW->uTime,
1606 "Last write time should match creation time!\n");
1608 /* On FAT filesystems the last access time is midnight
1609 local time, so the values of uDate2 and uTime2 will
1610 depend on the local timezone. If the times are exactly
1611 equal then the dates should be identical for both FAT
1612 and NTFS as no timezone is more than 1 day away from UTC.
1614 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1616 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1617 "Last write date and time should match last access date and time!\n");
1621 /* Filesystem may be FAT. Check date within 1 day
1622 and seconds are zero. */
1623 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1624 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1625 "Last access time on FAT filesystems should have zero seconds.\n");
1626 /* TODO: Perform check for date being within one day.*/
1629 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1630 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1631 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1632 "The filename should be stored in unicode at this position!\n");
1639 IShellFolder_Release(psfPersonal);
1642 static void test_SHGetFolderPathAndSubDirA(void)
1648 static char wine[] = "wine";
1649 static char winetemp[] = "wine\\temp";
1650 static char appdata[MAX_PATH];
1651 static char testpath[MAX_PATH];
1652 static char toolongpath[MAX_PATH+1];
1654 if(!pSHGetFolderPathAndSubDirA)
1656 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1660 if(!pSHGetFolderPathA) {
1661 win_skip("SHGetFolderPathA not present!\n");
1664 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1666 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1670 sprintf(testpath, "%s\\%s", appdata, winetemp);
1671 delret = RemoveDirectoryA(testpath);
1672 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1673 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1677 sprintf(testpath, "%s\\%s", appdata, wine);
1678 delret = RemoveDirectoryA(testpath);
1679 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1680 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1684 /* test invalid second parameter */
1685 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1686 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1688 /* test fourth parameter */
1689 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1691 case S_OK: /* winvista */
1692 ok(!strncmp(appdata, testpath, strlen(appdata)),
1693 "expected %s to start with %s\n", testpath, appdata);
1694 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1695 "expected %s to end with %s\n", testpath, winetemp);
1697 case E_INVALIDARG: /* winxp, win2k3 */
1700 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
1703 /* test fifth parameter */
1705 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1706 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1707 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1710 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1711 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1712 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1715 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1716 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1717 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1719 for(i=0; i< MAX_PATH; i++)
1720 toolongpath[i] = '0' + i % 10;
1721 toolongpath[MAX_PATH] = '\0';
1722 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1723 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1724 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1727 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1728 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1730 /* test a not existing path */
1732 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1733 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1734 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1736 /* create a directory inside a not existing directory */
1738 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1739 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1740 ok(!strncmp(appdata, testpath, strlen(appdata)),
1741 "expected %s to start with %s\n", testpath, appdata);
1742 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1743 "expected %s to end with %s\n", testpath, winetemp);
1744 dwret = GetFileAttributes(testpath);
1745 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1748 sprintf(testpath, "%s\\%s", appdata, winetemp);
1749 RemoveDirectoryA(testpath);
1750 sprintf(testpath, "%s\\%s", appdata, wine);
1751 RemoveDirectoryA(testpath);
1754 static void test_LocalizedNames(void)
1756 static char cCurrDirA[MAX_PATH];
1757 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1758 IShellFolder *IDesktopFolder, *testIShellFolder;
1759 ITEMIDLIST *newPIDL;
1762 static char resourcefile[MAX_PATH];
1767 static const char desktopini_contents1[] =
1768 "[.ShellClassInfo]\r\n"
1769 "LocalizedResourceName=@";
1770 static const char desktopini_contents2[] =
1772 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1773 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1775 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1776 CreateDirectoryA(".\\testfolder", NULL);
1778 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1780 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1782 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1783 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1784 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1785 ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1786 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1787 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
1788 "WriteFile failed %i\n", GetLastError());
1791 /* get IShellFolder for parent */
1792 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1793 len = lstrlenA(cCurrDirA);
1796 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1799 if(cCurrDirA[len-1] == '\\')
1800 cCurrDirA[len-1] = 0;
1802 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1804 hr = SHGetDesktopFolder(&IDesktopFolder);
1805 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1807 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1808 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1810 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1811 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1813 IMalloc_Free(ppM, newPIDL);
1815 /* windows reads the display name from the resource */
1816 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1817 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1819 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1820 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1822 if (hr == S_OK && pStrRetToBufW)
1824 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1825 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1827 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1828 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1829 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1832 /* editing name is also read from the resource */
1833 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1834 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1836 if (hr == S_OK && pStrRetToBufW)
1838 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1839 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1841 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1842 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1843 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1846 /* parsing name is unchanged */
1847 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1848 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1850 if (hr == S_OK && pStrRetToBufW)
1852 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1853 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1854 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1857 IShellFolder_Release(IDesktopFolder);
1858 IShellFolder_Release(testIShellFolder);
1860 IMalloc_Free(ppM, newPIDL);
1863 DeleteFileA(".\\testfolder\\desktop.ini");
1864 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1865 RemoveDirectoryA(".\\testfolder");
1868 static void test_SHCreateShellItem(void)
1870 IShellItem *shellitem, *shellitem2;
1871 IPersistIDList *persistidl;
1872 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test;
1874 char curdirA[MAX_PATH];
1875 WCHAR curdirW[MAX_PATH];
1876 WCHAR fnbufW[MAX_PATH];
1877 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
1878 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
1880 GetCurrentDirectoryA(MAX_PATH, curdirA);
1882 if (!pSHCreateShellItem)
1884 win_skip("SHCreateShellItem isn't available\n");
1888 if (!lstrlenA(curdirA))
1890 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
1894 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
1896 ret = SHGetDesktopFolder(&desktopfolder);
1897 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
1899 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
1900 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1902 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)¤tfolder);
1903 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
1905 CreateTestFile(".\\testfile");
1907 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
1908 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1910 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
1912 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
1913 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
1915 if (0) /* crashes on Windows XP */
1917 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
1918 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
1919 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
1920 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
1923 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
1924 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1927 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1928 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1931 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1932 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1935 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1938 IPersistIDList_Release(persistidl);
1940 IShellItem_Release(shellitem);
1943 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
1944 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1947 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1948 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1951 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1952 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1955 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1958 IPersistIDList_Release(persistidl);
1961 ret = IShellItem_GetParent(shellitem, &shellitem2);
1962 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
1965 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
1966 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1969 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1970 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1973 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1976 IPersistIDList_Release(persistidl);
1978 IShellItem_Release(shellitem2);
1981 IShellItem_Release(shellitem);
1984 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
1985 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1988 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1989 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1992 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1993 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1996 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1999 IPersistIDList_Release(persistidl);
2001 IShellItem_Release(shellitem);
2004 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2005 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2006 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2009 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2010 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2013 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2014 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2017 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2020 IPersistIDList_Release(persistidl);
2022 IShellItem_Release(shellitem);
2025 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2026 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2029 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2030 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2033 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2034 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2037 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2040 IPersistIDList_Release(persistidl);
2042 IShellItem_Release(shellitem);
2045 /* SHCreateItemFromParsingName */
2046 if(pSHCreateItemFromParsingName)
2050 /* Crashes under windows 7 */
2051 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2054 shellitem = (void*)0xdeadbeef;
2055 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2056 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2057 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2059 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2060 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2061 "SHCreateItemFromParsingName returned %x\n", ret);
2062 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2064 lstrcpyW(fnbufW, curdirW);
2065 myPathAddBackslashW(fnbufW);
2066 lstrcatW(fnbufW, testfileW);
2068 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2069 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2073 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2074 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2077 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2078 CoTaskMemFree(tmp_fname);
2080 IShellItem_Release(shellitem);
2084 win_skip("No SHCreateItemFromParsingName\n");
2087 /* SHCreateItemFromIDList */
2088 if(pSHCreateItemFromIDList)
2092 /* Crashes under win7 */
2093 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2096 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2097 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2099 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2100 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2103 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2104 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2107 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2108 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2111 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2114 IPersistIDList_Release(persistidl);
2116 IShellItem_Release(shellitem);
2119 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2120 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2123 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2124 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2127 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2128 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2131 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2134 IPersistIDList_Release(persistidl);
2136 IShellItem_Release(shellitem);
2140 win_skip("No SHCreateItemFromIDList\n");
2142 DeleteFileA(".\\testfile");
2143 pILFree(pidl_abstestfile);
2144 pILFree(pidl_testfile);
2146 IShellFolder_Release(currentfolder);
2147 IShellFolder_Release(desktopfolder);
2150 static void test_SHGetNameFromIDList(void)
2152 IShellItem *shellitem;
2157 static const DWORD flags[] = {
2158 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2159 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2160 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2161 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2163 if(!pSHGetNameFromIDList)
2165 win_skip("SHGetNameFromIDList missing.\n");
2169 /* These should be available on any platform that passed the above test. */
2170 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2171 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2172 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2173 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2177 /* Crashes under win7 */
2178 hres = pSHGetNameFromIDList(NULL, 0, NULL);
2181 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2182 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2184 /* Test the desktop */
2185 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2186 ok(hres == S_OK, "Got 0x%08x\n", hres);
2187 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2188 ok(hres == S_OK, "Got 0x%08x\n", hres);
2191 WCHAR *nameSI, *nameSH;
2192 WCHAR buf[MAX_PATH];
2193 HRESULT hrSI, hrSH, hrSF;
2198 SHGetDesktopFolder(&psf);
2199 for(i = 0; flags[i] != -1234; i++)
2201 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2202 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2203 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2204 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2205 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2206 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2208 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2209 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2213 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2215 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2217 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2219 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2220 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2222 IShellFolder_Release(psf);
2224 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2225 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2226 res = SHGetPathFromIDListW(pidl, buf);
2227 ok(res == TRUE, "Got %d\n", res);
2228 if(SUCCEEDED(hrSI) && res)
2229 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2230 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2232 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2233 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2234 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2236 IShellItem_Release(shellitem);
2240 /* Test the control panel */
2241 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2242 ok(hres == S_OK, "Got 0x%08x\n", hres);
2243 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2244 ok(hres == S_OK, "Got 0x%08x\n", hres);
2247 WCHAR *nameSI, *nameSH;
2248 WCHAR buf[MAX_PATH];
2249 HRESULT hrSI, hrSH, hrSF;
2254 SHGetDesktopFolder(&psf);
2255 for(i = 0; flags[i] != -1234; i++)
2257 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2258 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2259 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2260 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2261 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2262 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2264 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2265 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2269 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2271 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2273 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2275 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2276 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2278 IShellFolder_Release(psf);
2280 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2281 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2282 res = SHGetPathFromIDListW(pidl, buf);
2283 ok(res == FALSE, "Got %d\n", res);
2284 if(SUCCEEDED(hrSI) && res)
2285 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2286 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2288 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2289 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2290 "Got 0x%08x\n", hres);
2291 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2293 IShellItem_Release(shellitem);
2298 static void test_SHGetItemFromDataObject(void)
2300 IShellFolder *psfdesktop;
2305 if(!pSHGetItemFromDataObject)
2307 win_skip("No SHGetItemFromDataObject.\n");
2313 /* Crashes under win7 */
2314 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2317 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2318 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2320 SHGetDesktopFolder(&psfdesktop);
2322 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2323 ok(hres == S_OK, "got 0x%08x\n", hres);
2330 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2331 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2332 ok(hres == S_OK, "got 0x%08x\n", hres);
2335 LPITEMIDLIST apidl[5];
2338 for(count = 0; count < 5; count++)
2339 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2344 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2345 &IID_IDataObject, NULL, (void**)&pdo);
2346 ok(hres == S_OK, "got 0x%08x\n", hres);
2349 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2350 ok(hres == S_OK, "got 0x%08x\n", hres);
2351 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2352 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2353 ok(hres == S_OK, "got 0x%08x\n", hres);
2354 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2355 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2356 ok(hres == S_OK, "got 0x%08x\n", hres);
2357 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2358 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2359 ok(hres == S_OK, "got 0x%08x\n", hres);
2360 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2361 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2362 ok(hres == S_OK, "got 0x%08x\n", hres);
2363 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2365 IDataObject_Release(pdo);
2369 skip("No file(s) found - skipping single-file test.\n");
2373 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2374 &IID_IDataObject, NULL, (void**)&pdo);
2375 ok(hres == S_OK, "got 0x%08x\n", hres);
2378 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2379 ok(hres == S_OK, "got 0x%08x\n", hres);
2380 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2381 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2382 ok(hres == S_OK, "got 0x%08x\n", hres);
2383 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2384 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2385 ok(hres == S_OK, "got 0x%08x\n", hres);
2386 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2387 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2388 ok(hres == S_OK, "got 0x%08x\n", hres);
2389 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2390 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2391 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2392 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2394 IDataObject_Release(pdo);
2398 skip("zero or one file found - skipping multi-file test.\n");
2400 for(i = 0; i < count; i++)
2403 IEnumIDList_Release(peidl);
2406 IShellView_Release(psv);
2409 IShellFolder_Release(psfdesktop);
2412 static void test_SHParseDisplayName(void)
2414 LPITEMIDLIST pidl1, pidl2;
2415 IShellFolder *desktop;
2416 WCHAR dirW[MAX_PATH];
2421 if (!pSHParseDisplayName)
2423 win_skip("SHParseDisplayName isn't available\n");
2429 /* crashes on native */
2430 hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
2432 hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
2435 pidl1 = (LPITEMIDLIST)0xdeadbeef;
2436 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
2437 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
2438 hr == E_INVALIDARG, "failed %08x\n", hr);
2439 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
2443 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
2444 ok(hr == S_OK, "failed %08x\n", hr);
2445 hr = SHGetDesktopFolder(&desktop);
2446 ok(hr == S_OK, "failed %08x\n", hr);
2447 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
2448 ok(hr == S_OK, "failed %08x\n", hr);
2449 ret = pILIsEqual(pidl1, pidl2);
2450 ok(ret == TRUE, "expected equal idls\n");
2455 GetWindowsDirectoryW( dirW, MAX_PATH );
2457 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
2458 ok(hr == S_OK, "failed %08x\n", hr);
2459 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
2460 ok(hr == S_OK, "failed %08x\n", hr);
2462 ret = pILIsEqual(pidl1, pidl2);
2463 ok(ret == TRUE, "expected equal idls\n");
2467 IShellFolder_Release(desktop);
2470 static void test_desktop_IPersist(void)
2472 IShellFolder *desktop;
2474 IPersistFolder2 *ppf2;
2478 hr = SHGetDesktopFolder(&desktop);
2479 ok(hr == S_OK, "failed %08x\n", hr);
2481 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
2482 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
2488 /* crashes on native */
2489 hr = IPersist_GetClassID(persist, NULL);
2491 memset(&clsid, 0, sizeof(clsid));
2492 hr = IPersist_GetClassID(persist, &clsid);
2493 ok(hr == S_OK, "failed %08x\n", hr);
2494 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
2495 IPersist_Release(persist);
2498 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
2499 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
2502 IPersistFolder *ppf;
2504 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
2505 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
2507 IPersistFolder_Release(ppf);
2510 hr = IPersistFolder2_Initialize(ppf2, NULL);
2511 ok(hr == S_OK, "got %08x\n", hr);
2515 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
2516 ok(hr == S_OK, "got %08x\n", hr);
2517 ok(pidl != NULL, "pidl was NULL.\n");
2518 if(SUCCEEDED(hr)) pILFree(pidl);
2520 IPersistFolder2_Release(ppf2);
2523 IShellFolder_Release(desktop);
2526 static void test_GetUIObject(void)
2528 IShellFolder *psf_desktop;
2532 WCHAR path[MAX_PATH];
2533 const WCHAR filename[] =
2534 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
2536 if(!pSHBindToParent)
2538 win_skip("SHBindToParent missing.\n");
2542 GetCurrentDirectoryW(MAX_PATH, path);
2545 skip("GetCurrentDirectoryW returned an empty string.\n");
2548 lstrcatW(path, filename);
2549 SHGetDesktopFolder(&psf_desktop);
2551 CreateFilesFolders();
2553 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
2554 ok(hr == S_OK, "Got 0x%08x\n", hr);
2558 LPCITEMIDLIST pidl_child;
2559 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
2560 ok(hr == S_OK, "Got 0x%08x\n", hr);
2563 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
2564 &IID_IContextMenu, NULL, (void**)&pcm);
2565 ok(hr == S_OK, "Got 0x%08x\n", hr);
2568 HMENU hmenu = CreatePopupMenu();
2569 INT max_id, max_id_check;
2571 const int id_upper_limit = 32767;
2572 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
2573 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
2574 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
2575 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
2576 count = GetMenuItemCount(hmenu);
2577 ok(count, "Got %d\n", count);
2580 for(i = 0; i < count; i++)
2584 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
2585 mii.cbSize = sizeof(MENUITEMINFOA);
2586 mii.fMask = MIIM_ID | MIIM_FTYPE;
2589 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
2590 ok(res, "Failed (last error: %d).\n", GetLastError());
2592 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
2593 "Got non-separator ID out of range: %d (type: %x) \n", mii.wID, mii.fType);
2594 if(!(mii.fType & MFT_SEPARATOR))
2595 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
2597 ok((max_id_check == max_id) ||
2598 (max_id_check == max_id-1 /* Win 7 */),
2599 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
2601 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
2603 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
2605 CMINVOKECOMMANDINFO cmi;
2606 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
2607 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
2609 /* Attempt to execute non-existing command */
2610 cmi.lpVerb = MAKEINTRESOURCEA(9999);
2611 hr = IContextMenu_InvokeCommand(pcm, &cmi);
2612 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
2614 cmi.lpVerb = "foobar_wine_test";
2615 hr = IContextMenu_InvokeCommand(pcm, &cmi);
2616 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
2617 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
2618 "Got 0x%08x\n", hr);
2623 IContextMenu_Release(pcm);
2625 IShellFolder_Release(psf);
2627 if(pILFree) pILFree(pidl);
2630 IShellFolder_Release(psf_desktop);
2634 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
2635 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
2637 LPCITEMIDLIST child;
2638 IShellFolder *parent;
2642 if(!pSHBindToParent){
2643 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
2645 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
2647 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
2653 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
2657 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
2658 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
2662 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
2663 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
2665 IShellFolder_Release(parent);
2669 ok_(__FILE__,l)(filename.uType == STRRET_WSTR, "Got unexpected string type: %d\n", filename.uType);
2670 ok_(__FILE__,l)(lstrcmpW(path, filename.pOleStr) == 0,
2671 "didn't get expected path (%s), instead: %s\n",
2672 wine_dbgstr_w(path), wine_dbgstr_w(filename.pOleStr));
2674 IShellFolder_Release(parent);
2676 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
2679 static void test_SHSimpleIDListFromPath(void)
2681 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
2682 const CHAR adirA[] = "C:\\sidlfpdir";
2683 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
2685 LPITEMIDLIST pidl = NULL;
2687 if(!pSHSimpleIDListFromPathAW){
2688 win_skip("SHSimpleIDListFromPathAW not available\n");
2692 br = CreateDirectoryA(adirA, NULL);
2693 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
2696 pidl = pSHSimpleIDListFromPathAW(adirW);
2698 pidl = pSHSimpleIDListFromPathAW(adirA);
2699 verify_pidl(pidl, adirW);
2702 br = RemoveDirectoryA(adirA);
2703 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
2706 pidl = pSHSimpleIDListFromPathAW(adirW);
2708 pidl = pSHSimpleIDListFromPathAW(adirA);
2709 verify_pidl(pidl, adirW);
2713 /* IFileSystemBindData impl */
2714 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
2715 REFIID riid, void **ppv)
2717 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
2718 IsEqualIID(riid, &IID_IUnknown)){
2722 return E_NOINTERFACE;
2725 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
2730 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
2735 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
2736 const WIN32_FIND_DATAW *pfd)
2738 ok(0, "SetFindData called\n");
2742 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
2743 WIN32_FIND_DATAW *pfd)
2745 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
2749 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
2750 WIN32_FIND_DATAW *pfd)
2752 memset(pfd, 0xdeadbeef, sizeof(WIN32_FIND_DATAW));
2756 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
2757 WIN32_FIND_DATAW *pfd)
2759 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
2760 *pfd->cFileName = 'a';
2761 *pfd->cAlternateFileName = 'a';
2765 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
2766 WIN32_FIND_DATAW *pfd)
2768 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
2769 HANDLE handle = FindFirstFileW(adirW, pfd);
2774 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
2775 WIN32_FIND_DATAW *pfd)
2780 static IFileSystemBindDataVtbl fsbdVtbl = {
2781 fsbd_QueryInterface,
2788 static IFileSystemBindData fsbd = { &fsbdVtbl };
2790 static void test_ParseDisplayNamePBC(void)
2792 WCHAR wFileSystemBindData[] =
2793 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
2794 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
2795 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
2802 /* Check if we support WCHAR functions */
2803 SetLastError(0xdeadbeef);
2804 lstrcmpiW(adirW, adirW);
2805 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
2806 win_skip("Most W-calls are not implemented\n");
2810 hres = SHGetDesktopFolder(&psf);
2811 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
2813 win_skip("Failed to get IShellFolder, can't run tests\n");
2817 /* fails on unknown dir with no IBindCtx */
2818 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
2819 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
2820 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
2822 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
2823 hres = CreateBindCtx(0, &pbc);
2824 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
2826 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
2827 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
2828 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
2830 /* unknown dir with IBindCtx with IFileSystemBindData */
2831 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
2832 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
2834 /* return E_FAIL from GetFindData */
2835 pidl = (ITEMIDLIST*)0xdeadbeef;
2836 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
2837 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
2838 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
2839 "ParseDisplayName failed: 0x%08x\n", hres);
2840 if(SUCCEEDED(hres)){
2841 verify_pidl(pidl, adirW);
2845 /* set FIND_DATA struct to NULLs */
2846 pidl = (ITEMIDLIST*)0xdeadbeef;
2847 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
2848 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
2849 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
2850 "ParseDisplayName failed: 0x%08x\n", hres);
2851 if(SUCCEEDED(hres)){
2852 verify_pidl(pidl, adirW);
2856 /* set FIND_DATA struct to junk */
2857 pidl = (ITEMIDLIST*)0xdeadbeef;
2858 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
2859 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
2860 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
2861 "ParseDisplayName failed: 0x%08x\n", hres);
2862 if(SUCCEEDED(hres)){
2863 verify_pidl(pidl, adirW);
2867 /* set FIND_DATA struct to invalid data */
2868 pidl = (ITEMIDLIST*)0xdeadbeef;
2869 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
2870 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
2871 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
2872 "ParseDisplayName failed: 0x%08x\n", hres);
2873 if(SUCCEEDED(hres)){
2874 verify_pidl(pidl, adirW);
2878 /* set FIND_DATA struct to valid data */
2879 pidl = (ITEMIDLIST*)0xdeadbeef;
2880 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
2881 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
2882 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
2883 "ParseDisplayName failed: 0x%08x\n", hres);
2884 if(SUCCEEDED(hres)){
2885 verify_pidl(pidl, adirW);
2889 IBindCtx_Release(pbc);
2890 IShellFolder_Release(psf);
2893 START_TEST(shlfolder)
2895 init_function_pointers();
2896 /* if OleInitialize doesn't get called, ParseDisplayName returns
2897 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
2898 OleInitialize(NULL);
2900 test_ParseDisplayName();
2901 test_SHParseDisplayName();
2902 test_BindToObject();
2903 test_EnumObjects_and_CompareIDs();
2904 test_GetDisplayName();
2905 test_GetAttributesOf();
2906 test_SHGetPathFromIDList();
2907 test_CallForAttributes();
2908 test_FolderShortcut();
2909 test_ITEMIDLIST_format();
2910 test_SHGetFolderPathAndSubDirA();
2911 test_LocalizedNames();
2912 test_SHCreateShellItem();
2913 test_desktop_IPersist();
2915 test_SHSimpleIDListFromPath();
2916 test_ParseDisplayNamePBC();
2917 test_SHGetNameFromIDList();
2918 test_SHGetItemFromDataObject();