2 * Unit test of the IShellFolder functions.
4 * Copyright 2004 Vitaliy Margolen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
40 #include "wine/test.h"
45 static HRESULT (WINAPI
*pSHBindToParent
)(LPCITEMIDLIST
, REFIID
, LPVOID
*, LPCITEMIDLIST
*);
46 static HRESULT (WINAPI
*pSHGetFolderPathA
)(HWND
, int, HANDLE
, DWORD
, LPSTR
);
47 static HRESULT (WINAPI
*pSHGetFolderPathAndSubDirA
)(HWND
, int, HANDLE
, DWORD
, LPCSTR
, LPSTR
);
48 static BOOL (WINAPI
*pSHGetPathFromIDListW
)(LPCITEMIDLIST
,LPWSTR
);
49 static BOOL (WINAPI
*pSHGetSpecialFolderPathA
)(HWND
, LPSTR
, int, BOOL
);
50 static BOOL (WINAPI
*pSHGetSpecialFolderPathW
)(HWND
, LPWSTR
, int, BOOL
);
51 static HRESULT (WINAPI
*pStrRetToBufW
)(STRRET
*,LPCITEMIDLIST
,LPWSTR
,UINT
);
52 static LPITEMIDLIST (WINAPI
*pILFindLastID
)(LPCITEMIDLIST
);
53 static void (WINAPI
*pILFree
)(LPITEMIDLIST
);
54 static BOOL (WINAPI
*pILIsEqual
)(LPCITEMIDLIST
, LPCITEMIDLIST
);
55 static HRESULT (WINAPI
*pSHCreateShellItem
)(LPCITEMIDLIST
,IShellFolder
*,LPCITEMIDLIST
,IShellItem
**);
56 static LPITEMIDLIST (WINAPI
*pILCombine
)(LPCITEMIDLIST
,LPCITEMIDLIST
);
57 static HRESULT (WINAPI
*pSHParseDisplayName
)(LPCWSTR
,IBindCtx
*,LPITEMIDLIST
*,SFGAOF
,SFGAOF
*);
59 static void init_function_pointers(void)
65 hmod
= GetModuleHandleA("shell32.dll");
67 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
68 MAKEFUNC(SHBindToParent
);
69 MAKEFUNC(SHCreateShellItem
);
70 MAKEFUNC(SHGetFolderPathA
);
71 MAKEFUNC(SHGetFolderPathAndSubDirA
);
72 MAKEFUNC(SHGetPathFromIDListW
);
73 MAKEFUNC(SHGetSpecialFolderPathA
);
74 MAKEFUNC(SHGetSpecialFolderPathW
);
75 MAKEFUNC(SHParseDisplayName
);
78 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
79 MAKEFUNC_ORD(ILFindLastID
, 16);
80 MAKEFUNC_ORD(ILIsEqual
, 21);
81 MAKEFUNC_ORD(ILCombine
, 25);
82 MAKEFUNC_ORD(ILFree
, 155);
85 /* test named exports */
86 ptr
= GetProcAddress(hmod
, "ILFree");
87 ok(broken(ptr
== 0) || ptr
!= 0, "expected named export for ILFree\n");
90 #define TESTNAMED(f) \
91 ptr = (void*)GetProcAddress(hmod, #f); \
92 ok(ptr != 0, "expected named export for " #f "\n");
94 TESTNAMED(ILAppendID
);
96 TESTNAMED(ILCloneFirst
);
98 TESTNAMED(ILCreateFromPath
);
99 TESTNAMED(ILCreateFromPathA
);
100 TESTNAMED(ILCreateFromPathW
);
101 TESTNAMED(ILFindChild
);
102 TESTNAMED(ILFindLastID
);
103 TESTNAMED(ILGetNext
);
104 TESTNAMED(ILGetSize
);
105 TESTNAMED(ILIsEqual
);
106 TESTNAMED(ILIsParent
);
107 TESTNAMED(ILRemoveLastID
);
108 TESTNAMED(ILSaveToStream
);
112 hmod
= GetModuleHandleA("shlwapi.dll");
113 pStrRetToBufW
= (void*)GetProcAddress(hmod
, "StrRetToBufW");
115 hr
= SHGetMalloc(&ppM
);
116 ok(hr
== S_OK
, "SHGetMalloc failed %08x\n", hr
);
119 static void test_ParseDisplayName(void)
122 IShellFolder
*IDesktopFolder
;
123 static const char *cNonExistDir1A
= "c:\\nonexist_subdir";
124 static const char *cNonExistDir2A
= "c:\\\\nonexist_subdir";
125 static const char *cInetTestA
= "http:\\yyy";
126 static const char *cInetTest2A
= "xx:yyy";
128 WCHAR cTestDirW
[MAX_PATH
] = {0};
132 hr
= SHGetDesktopFolder(&IDesktopFolder
);
133 ok(hr
== S_OK
, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr
);
134 if(hr
!= S_OK
) return;
136 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
137 if (pSHCreateShellItem
)
139 /* null name and pidl */
140 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
,
141 NULL
, NULL
, NULL
, NULL
, NULL
, 0);
142 ok(hr
== E_INVALIDARG
, "returned %08x, expected E_INVALIDARG\n", hr
);
145 newPIDL
= (ITEMIDLIST
*)0xdeadbeef;
146 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
,
147 NULL
, NULL
, NULL
, NULL
, &newPIDL
, 0);
148 ok(newPIDL
== 0, "expected null, got %p\n", newPIDL
);
149 ok(hr
== E_INVALIDARG
, "returned %08x, expected E_INVALIDARG\n", hr
);
152 win_skip("Tests would crash on W2K and below\n");
154 MultiByteToWideChar(CP_ACP
, 0, cInetTestA
, -1, cTestDirW
, MAX_PATH
);
155 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
,
156 NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
157 todo_wine
ok(hr
== S_OK
|| broken(hr
== E_FAIL
) /* NT4 */,
158 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr
);
161 ok(pILFindLastID(newPIDL
)->mkid
.abID
[0] == 0x61, "Last pidl should be of type "
162 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL
)->mkid
.abID
[0]);
163 IMalloc_Free(ppM
, newPIDL
);
166 MultiByteToWideChar(CP_ACP
, 0, cInetTest2A
, -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 res
= GetFileAttributesA(cNonExistDir1A
);
179 if(res
!= INVALID_FILE_ATTRIBUTES
)
181 skip("Test directory unexpectedly exists\n");
185 MultiByteToWideChar(CP_ACP
, 0, cNonExistDir1A
, -1, cTestDirW
, MAX_PATH
);
186 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
,
187 NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
188 ok((hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
)) || (hr
== E_FAIL
),
189 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr
);
191 res
= GetFileAttributesA(cNonExistDir2A
);
192 if(res
!= INVALID_FILE_ATTRIBUTES
)
194 skip("Test directory unexpectedly exists\n");
198 MultiByteToWideChar(CP_ACP
, 0, cNonExistDir2A
, -1, cTestDirW
, MAX_PATH
);
199 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
,
200 NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
201 ok((hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
)) || (hr
== E_FAIL
) || (hr
== E_INVALIDARG
),
202 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr
);
204 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
205 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
206 * out it doesn't. The magic seems to happen in the file dialogs, then. */
207 if (!pSHGetSpecialFolderPathW
|| !pILFindLastID
)
209 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
213 bRes
= pSHGetSpecialFolderPathW(NULL
, cTestDirW
, CSIDL_PERSONAL
, FALSE
);
214 ok(bRes
, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
215 if (!bRes
) goto finished
;
217 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
, NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
218 ok(hr
== S_OK
, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr
);
219 if (hr
!= S_OK
) goto finished
;
221 ok(pILFindLastID(newPIDL
)->mkid
.abID
[0] == 0x31 ||
222 pILFindLastID(newPIDL
)->mkid
.abID
[0] == 0xb1, /* Win98 */
223 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
224 pILFindLastID(newPIDL
)->mkid
.abID
[0]);
225 IMalloc_Free(ppM
, newPIDL
);
228 IShellFolder_Release(IDesktopFolder
);
231 /* creates a file with the specified name for tests */
232 static void CreateTestFile(const CHAR
*name
)
237 file
= CreateFileA(name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
238 if (file
!= INVALID_HANDLE_VALUE
)
240 WriteFile(file
, name
, strlen(name
), &written
, NULL
);
241 WriteFile(file
, "\n", strlen("\n"), &written
, NULL
);
247 /* initializes the tests */
248 static void CreateFilesFolders(void)
250 CreateDirectoryA(".\\testdir", NULL
);
251 CreateDirectoryA(".\\testdir\\test.txt", NULL
);
252 CreateTestFile (".\\testdir\\test1.txt ");
253 CreateTestFile (".\\testdir\\test2.txt ");
254 CreateTestFile (".\\testdir\\test3.txt ");
255 CreateDirectoryA(".\\testdir\\testdir2 ", NULL
);
256 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL
);
259 /* cleans after tests */
260 static void Cleanup(void)
262 DeleteFileA(".\\testdir\\test1.txt");
263 DeleteFileA(".\\testdir\\test2.txt");
264 DeleteFileA(".\\testdir\\test3.txt");
265 RemoveDirectoryA(".\\testdir\\test.txt");
266 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
267 RemoveDirectoryA(".\\testdir\\testdir2");
268 RemoveDirectoryA(".\\testdir");
273 static void test_EnumObjects(IShellFolder
*iFolder
)
275 IEnumIDList
*iEnumList
;
276 LPITEMIDLIST newPIDL
, idlArr
[10];
281 static const WORD iResults
[5][5] =
290 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
291 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
292 static const ULONG attrs
[5] =
294 SFGAO_CAPABILITYMASK
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
| SFGAO_FILESYSANCESTOR
,
295 SFGAO_CAPABILITYMASK
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
| SFGAO_FILESYSANCESTOR
,
296 SFGAO_CAPABILITYMASK
| SFGAO_FILESYSTEM
,
297 SFGAO_CAPABILITYMASK
| SFGAO_FILESYSTEM
,
298 SFGAO_CAPABILITYMASK
| SFGAO_FILESYSTEM
,
301 hr
= IShellFolder_EnumObjects(iFolder
, NULL
, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
| SHCONTF_INCLUDEHIDDEN
, &iEnumList
);
302 ok(hr
== S_OK
, "EnumObjects failed %08x\n", hr
);
304 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
305 * the filesystem shellfolders return S_OK even if less than 'celt' items are
306 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
307 * only ever returns a single entry per call. */
308 while (IEnumIDList_Next(iEnumList
, 10-i
, &idlArr
[i
], &NumPIDLs
) == S_OK
)
310 ok (i
== 5, "i: %d\n", i
);
312 hr
= IEnumIDList_Release(iEnumList
);
313 ok(hr
== S_OK
, "IEnumIDList_Release failed %08x\n", hr
);
315 /* Sort them first in case of wrong order from system */
316 for (i
=0;i
<5;i
++) for (j
=0;j
<5;j
++)
317 if ((SHORT
)IShellFolder_CompareIDs(iFolder
, 0, idlArr
[i
], idlArr
[j
]) < 0)
320 idlArr
[i
] = idlArr
[j
];
324 for (i
=0;i
<5;i
++) for (j
=0;j
<5;j
++)
326 hr
= IShellFolder_CompareIDs(iFolder
, 0, idlArr
[i
], idlArr
[j
]);
327 ok(hr
== iResults
[i
][j
], "Got %x expected [%d]-[%d]=%x\n", hr
, i
, j
, iResults
[i
][j
]);
331 for (i
= 0; i
< 5; i
++)
334 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
335 /* Native returns all flags no matter what we ask for */
336 flags
= SFGAO_CANCOPY
;
337 hr
= IShellFolder_GetAttributesOf(iFolder
, 1, (LPCITEMIDLIST
*)(idlArr
+ i
), &flags
);
338 flags
&= SFGAO_testfor
;
339 ok(hr
== S_OK
, "GetAttributesOf returns %08x\n", hr
);
340 ok(flags
== (attrs
[i
]) ||
341 flags
== (attrs
[i
] & ~SFGAO_FILESYSANCESTOR
) || /* Win9x, NT4 */
342 flags
== ((attrs
[i
] & ~SFGAO_CAPABILITYMASK
) | SFGAO_VISTA
), /* Vista and higher */
343 "GetAttributesOf[%i] got %08x, expected %08x\n", i
, flags
, attrs
[i
]);
345 flags
= SFGAO_testfor
;
346 hr
= IShellFolder_GetAttributesOf(iFolder
, 1, (LPCITEMIDLIST
*)(idlArr
+ i
), &flags
);
347 flags
&= SFGAO_testfor
;
348 ok(hr
== S_OK
, "GetAttributesOf returns %08x\n", hr
);
349 ok(flags
== attrs
[i
] ||
350 flags
== (attrs
[i
] & ~SFGAO_FILESYSANCESTOR
), /* Win9x, NT4 */
351 "GetAttributesOf[%i] got %08x, expected %08x\n", i
, flags
, attrs
[i
]);
355 IMalloc_Free(ppM
, idlArr
[i
]);
358 static void test_BindToObject(void)
362 IShellFolder
*psfDesktop
, *psfChild
, *psfMyComputer
, *psfSystemDir
;
363 SHITEMID emptyitem
= { 0, { 0 } };
364 LPITEMIDLIST pidlMyComputer
, pidlSystemDir
, pidlEmpty
= (LPITEMIDLIST
)&emptyitem
;
365 WCHAR wszSystemDir
[MAX_PATH
];
366 char szSystemDir
[MAX_PATH
];
367 WCHAR wszMyComputer
[] = {
368 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
369 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
371 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
372 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
374 hr
= SHGetDesktopFolder(&psfDesktop
);
375 ok (hr
== S_OK
, "SHGetDesktopFolder failed! hr = %08x\n", hr
);
376 if (hr
!= S_OK
) return;
378 hr
= IShellFolder_BindToObject(psfDesktop
, pidlEmpty
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfChild
);
379 ok (hr
== E_INVALIDARG
, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr
);
381 hr
= IShellFolder_BindToObject(psfDesktop
, NULL
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfChild
);
382 ok (hr
== E_INVALIDARG
, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr
);
384 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszMyComputer
, NULL
, &pidlMyComputer
, NULL
);
385 ok (hr
== S_OK
, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr
);
387 IShellFolder_Release(psfDesktop
);
391 hr
= IShellFolder_BindToObject(psfDesktop
, pidlMyComputer
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfMyComputer
);
392 ok (hr
== S_OK
, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr
);
393 IShellFolder_Release(psfDesktop
);
394 IMalloc_Free(ppM
, pidlMyComputer
);
395 if (hr
!= S_OK
) return;
397 hr
= IShellFolder_BindToObject(psfMyComputer
, pidlEmpty
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfChild
);
398 ok (hr
== E_INVALIDARG
, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr
);
402 /* this call segfaults on 98SE */
403 hr
= IShellFolder_BindToObject(psfMyComputer
, NULL
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfChild
);
404 ok (hr
== E_INVALIDARG
, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr
);
407 cChars
= GetSystemDirectoryA(szSystemDir
, MAX_PATH
);
408 ok (cChars
> 0 && cChars
< MAX_PATH
, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
409 if (cChars
== 0 || cChars
>= MAX_PATH
) {
410 IShellFolder_Release(psfMyComputer
);
413 MultiByteToWideChar(CP_ACP
, 0, szSystemDir
, -1, wszSystemDir
, MAX_PATH
);
415 hr
= IShellFolder_ParseDisplayName(psfMyComputer
, NULL
, NULL
, wszSystemDir
, NULL
, &pidlSystemDir
, NULL
);
416 ok (hr
== S_OK
, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr
);
418 IShellFolder_Release(psfMyComputer
);
422 hr
= IShellFolder_BindToObject(psfMyComputer
, pidlSystemDir
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfSystemDir
);
423 ok (hr
== S_OK
, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr
);
424 IShellFolder_Release(psfMyComputer
);
425 IMalloc_Free(ppM
, pidlSystemDir
);
426 if (hr
!= S_OK
) return;
428 hr
= IShellFolder_BindToObject(psfSystemDir
, pidlEmpty
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfChild
);
429 ok (hr
== E_INVALIDARG
,
430 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr
);
434 /* this call segfaults on 98SE */
435 hr
= IShellFolder_BindToObject(psfSystemDir
, NULL
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfChild
);
436 ok (hr
== E_INVALIDARG
,
437 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr
);
440 IShellFolder_Release(psfSystemDir
);
443 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
444 static LPWSTR
myPathAddBackslashW( LPWSTR lpszPath
)
448 if (!lpszPath
|| (iLen
= lstrlenW(lpszPath
)) >= MAX_PATH
)
454 if (lpszPath
[-1] != '\\')
463 static void test_GetDisplayName(void)
468 WCHAR wszTestFile
[MAX_PATH
], wszTestFile2
[MAX_PATH
];
469 char szTestFile
[MAX_PATH
], szTestDir
[MAX_PATH
];
472 LPSHELLFOLDER psfDesktop
, psfPersonal
;
474 SHITEMID emptyitem
= { 0, { 0 } };
475 LPITEMIDLIST pidlTestFile
, pidlEmpty
= (LPITEMIDLIST
)&emptyitem
;
476 LPCITEMIDLIST pidlLast
;
477 static const CHAR szFileName
[] = "winetest.foo";
478 static const WCHAR wszFileName
[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
479 static const WCHAR wszDirName
[] = { 'w','i','n','e','t','e','s','t',0 };
481 /* I'm trying to figure if there is a functional difference between calling
482 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
483 * binding to the shellfolder. One thing I thought of was that perhaps
484 * SHGetPathFromIDListW would be able to get the path to a file, which does
485 * not exist anymore, while the other method wouldn't. It turns out there's
486 * no functional difference in this respect.
489 if(!pSHGetSpecialFolderPathA
) {
490 win_skip("SHGetSpecialFolderPathA is not available\n");
494 /* First creating a directory in MyDocuments and a file in this directory. */
495 result
= pSHGetSpecialFolderPathA(NULL
, szTestDir
, CSIDL_PERSONAL
, FALSE
);
496 ok(result
, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
499 /* Use ANSI file functions so this works on Windows 9x */
500 lstrcatA(szTestDir
, "\\winetest");
501 CreateDirectoryA(szTestDir
, NULL
);
502 attr
=GetFileAttributesA(szTestDir
);
503 if (attr
== INVALID_FILE_ATTRIBUTES
|| !(attr
& FILE_ATTRIBUTE_DIRECTORY
))
505 ok(0, "unable to create the '%s' directory\n", szTestDir
);
509 lstrcpyA(szTestFile
, szTestDir
);
510 lstrcatA(szTestFile
, "\\");
511 lstrcatA(szTestFile
, szFileName
);
512 hTestFile
= CreateFileA(szTestFile
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
513 ok((hTestFile
!= INVALID_HANDLE_VALUE
), "CreateFileA failed! Last error: %u\n", GetLastError());
514 if (hTestFile
== INVALID_HANDLE_VALUE
) return;
515 CloseHandle(hTestFile
);
517 /* Getting an itemidlist for the file. */
518 hr
= SHGetDesktopFolder(&psfDesktop
);
519 ok(hr
== S_OK
, "SHGetDesktopFolder failed! hr = %08x\n", hr
);
520 if (hr
!= S_OK
) return;
522 MultiByteToWideChar(CP_ACP
, 0, szTestFile
, -1, wszTestFile
, MAX_PATH
);
524 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszTestFile
, NULL
, &pidlTestFile
, NULL
);
525 ok(hr
== S_OK
, "Desktop->ParseDisplayName failed! hr = %08x\n", hr
);
527 IShellFolder_Release(psfDesktop
);
531 pidlLast
= pILFindLastID(pidlTestFile
);
532 ok(pidlLast
->mkid
.cb
>=76 ||
533 broken(pidlLast
->mkid
.cb
== 28) || /* W2K */
534 broken(pidlLast
->mkid
.cb
== 40), /* Win9x, WinME */
535 "Expected pidl length of at least 76, got %d.\n", pidlLast
->mkid
.cb
);
536 if (pidlLast
->mkid
.cb
>= 28) {
537 ok(!lstrcmpA((CHAR
*)&pidlLast
->mkid
.abID
[12], szFileName
),
538 "Filename should be stored as ansi-string at this position!\n");
540 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
541 if (pidlLast
->mkid
.cb
>= 76) {
542 ok(!lstrcmpW((WCHAR
*)&pidlLast
->mkid
.abID
[46], wszFileName
) ||
543 (pidlLast
->mkid
.cb
>= 94 && !lstrcmpW((WCHAR
*)&pidlLast
->mkid
.abID
[64], wszFileName
)) || /* Vista */
544 (pidlLast
->mkid
.cb
>= 98 && !lstrcmpW((WCHAR
*)&pidlLast
->mkid
.abID
[68], wszFileName
)), /* Win7 */
545 "Filename should be stored as wchar-string at this position!\n");
548 /* It seems as if we cannot bind to regular files on windows, but only directories.
550 hr
= IShellFolder_BindToObject(psfDesktop
, pidlTestFile
, NULL
, &IID_IUnknown
, (VOID
**)&psfFile
);
552 ok (hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
) ||
553 hr
== E_NOTIMPL
|| /* Vista */
554 broken(hr
== S_OK
), /* Win9x, W2K */
557 IShellFolder_Release(psfFile
);
560 if (!pSHBindToParent
)
562 win_skip("SHBindToParent is missing\n");
563 DeleteFileA(szTestFile
);
564 RemoveDirectoryA(szTestDir
);
568 /* Some tests for IShellFolder::SetNameOf */
569 if (pSHGetFolderPathAndSubDirA
)
571 hr
= pSHBindToParent(pidlTestFile
, &IID_IShellFolder
, (VOID
**)&psfPersonal
, &pidlLast
);
572 ok(hr
== S_OK
, "SHBindToParent failed! hr = %08x\n", hr
);
574 /* It's ok to use this fixed path. Call will fail anyway. */
575 WCHAR wszAbsoluteFilename
[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
576 LPITEMIDLIST pidlNew
;
578 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
579 hr
= IShellFolder_SetNameOf(psfPersonal
, NULL
, pidlLast
, wszDirName
, SHGDN_NORMAL
, &pidlNew
);
580 ok (hr
== S_OK
, "SetNameOf failed! hr = %08x\n", hr
);
583 ok (((LPITEMIDLIST
)((LPBYTE
)pidlNew
+pidlNew
->mkid
.cb
))->mkid
.cb
== 0,
584 "pidl returned from SetNameOf should be simple!\n");
586 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
587 * is implemented on top of SHFileOperation in WinXP. */
588 hr
= IShellFolder_SetNameOf(psfPersonal
, NULL
, pidlNew
, wszAbsoluteFilename
,
589 SHGDN_FORPARSING
, NULL
);
590 ok (hr
== HRESULT_FROM_WIN32(ERROR_CANCELLED
), "SetNameOf succeeded! hr = %08x\n", hr
);
592 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
593 * SHGDN flags specify an absolute path. */
594 hr
= IShellFolder_SetNameOf(psfPersonal
, NULL
, pidlNew
, wszFileName
, SHGDN_FORPARSING
, NULL
);
595 ok (hr
== S_OK
, "SetNameOf failed! hr = %08x\n", hr
);
600 IShellFolder_Release(psfPersonal
);
604 win_skip("Avoid needs of interaction on Win2k\n");
606 /* Deleting the file and the directory */
607 DeleteFileA(szTestFile
);
608 RemoveDirectoryA(szTestDir
);
610 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
611 if (pSHGetPathFromIDListW
)
613 result
= pSHGetPathFromIDListW(pidlTestFile
, wszTestFile2
);
614 ok (result
, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
615 ok (!lstrcmpiW(wszTestFile
, wszTestFile2
), "SHGetPathFromIDListW returns incorrect path!\n");
618 /* SHBindToParent fails, if called with a NULL PIDL. */
619 hr
= pSHBindToParent(NULL
, &IID_IShellFolder
, (VOID
**)&psfPersonal
, &pidlLast
);
620 ok (hr
!= S_OK
, "SHBindToParent(NULL) should fail!\n");
622 /* But it succeeds with an empty PIDL. */
623 hr
= pSHBindToParent(pidlEmpty
, &IID_IShellFolder
, (VOID
**)&psfPersonal
, &pidlLast
);
624 ok (hr
== S_OK
, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr
);
625 ok (pidlLast
== pidlEmpty
, "The last element of an empty PIDL should be the PIDL itself!\n");
627 IShellFolder_Release(psfPersonal
);
629 /* Binding to the folder and querying the display name of the file also works. */
630 hr
= pSHBindToParent(pidlTestFile
, &IID_IShellFolder
, (VOID
**)&psfPersonal
, &pidlLast
);
631 ok (hr
== S_OK
, "SHBindToParent failed! hr = %08x\n", hr
);
633 IShellFolder_Release(psfDesktop
);
637 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
638 * pidlTestFile (In accordance with MSDN). */
639 ok (pILFindLastID(pidlTestFile
) == pidlLast
,
640 "SHBindToParent doesn't return the last id of the pidl param!\n");
642 hr
= IShellFolder_GetDisplayNameOf(psfPersonal
, pidlLast
, SHGDN_FORPARSING
, &strret
);
643 ok (hr
== S_OK
, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr
);
645 IShellFolder_Release(psfDesktop
);
646 IShellFolder_Release(psfPersonal
);
652 hr
= pStrRetToBufW(&strret
, pidlLast
, wszTestFile2
, MAX_PATH
);
653 ok (hr
== S_OK
, "StrRetToBufW failed! hr = %08x\n", hr
);
654 ok (!lstrcmpiW(wszTestFile
, wszTestFile2
), "GetDisplayNameOf returns incorrect path!\n");
657 ILFree(pidlTestFile
);
658 IShellFolder_Release(psfDesktop
);
659 IShellFolder_Release(psfPersonal
);
662 static void test_CallForAttributes(void)
668 LPSHELLFOLDER psfDesktop
;
669 LPITEMIDLIST pidlMyDocuments
;
670 DWORD dwAttributes
, dwCallForAttributes
, dwOrigAttributes
, dwOrigCallForAttributes
;
671 static const WCHAR wszAttributes
[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
672 static const WCHAR wszCallForAttributes
[] = {
673 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
674 static const WCHAR wszMyDocumentsKey
[] = {
675 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
676 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
677 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
678 WCHAR wszMyDocuments
[] = {
679 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
680 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
682 /* For the root of a namespace extension, the attributes are not queried by binding
683 * to the object and calling GetAttributesOf. Instead, the attributes are read from
684 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
686 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
687 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
688 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
689 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
691 hr
= SHGetDesktopFolder(&psfDesktop
);
692 ok (hr
== S_OK
, "SHGetDesktopFolder failed! hr = %08x\n", hr
);
693 if (hr
!= S_OK
) return;
695 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszMyDocuments
, NULL
,
696 &pidlMyDocuments
, NULL
);
698 broken(hr
== E_INVALIDARG
), /* Win95, NT4 */
699 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr
);
701 IShellFolder_Release(psfDesktop
);
705 dwAttributes
= 0xffffffff;
706 hr
= IShellFolder_GetAttributesOf(psfDesktop
, 1,
707 (LPCITEMIDLIST
*)&pidlMyDocuments
, &dwAttributes
);
708 ok (hr
== S_OK
, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr
);
710 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
711 ok (dwAttributes
& SFGAO_FILESYSTEM
, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
712 ok (!(dwAttributes
& SFGAO_ISSLOW
), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
713 ok (!(dwAttributes
& SFGAO_GHOSTED
), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
715 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
716 * key. So the test will return at this point, if run on wine.
718 lResult
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, wszMyDocumentsKey
, 0, KEY_WRITE
|KEY_READ
, &hKey
);
719 ok (lResult
== ERROR_SUCCESS
||
720 lResult
== ERROR_ACCESS_DENIED
,
721 "RegOpenKeyEx failed! result: %08x\n", lResult
);
722 if (lResult
!= ERROR_SUCCESS
) {
723 if (lResult
== ERROR_ACCESS_DENIED
)
724 skip("Not enough rights to open the registry key\n");
725 IMalloc_Free(ppM
, pidlMyDocuments
);
726 IShellFolder_Release(psfDesktop
);
730 /* Query MyDocuments' Attributes value, to be able to restore it later. */
731 dwSize
= sizeof(DWORD
);
732 lResult
= RegQueryValueExW(hKey
, wszAttributes
, NULL
, NULL
, (LPBYTE
)&dwOrigAttributes
, &dwSize
);
733 ok (lResult
== ERROR_SUCCESS
, "RegQueryValueEx failed! result: %08x\n", lResult
);
734 if (lResult
!= ERROR_SUCCESS
) {
736 IMalloc_Free(ppM
, pidlMyDocuments
);
737 IShellFolder_Release(psfDesktop
);
741 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
742 dwSize
= sizeof(DWORD
);
743 lResult
= RegQueryValueExW(hKey
, wszCallForAttributes
, NULL
, NULL
,
744 (LPBYTE
)&dwOrigCallForAttributes
, &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 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
754 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
755 * SFGAO_FILESYSTEM attributes. */
756 dwAttributes
= SFGAO_ISSLOW
|SFGAO_GHOSTED
;
757 RegSetValueExW(hKey
, wszAttributes
, 0, REG_DWORD
, (LPBYTE
)&dwAttributes
, sizeof(DWORD
));
758 dwCallForAttributes
= SFGAO_ISSLOW
|SFGAO_FILESYSTEM
;
759 RegSetValueExW(hKey
, wszCallForAttributes
, 0, REG_DWORD
,
760 (LPBYTE
)&dwCallForAttributes
, sizeof(DWORD
));
762 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
763 * GetAttributesOf. It seems that once there is a single attribute queried, for which
764 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
765 * the flags in Attributes are ignored.
767 dwAttributes
= SFGAO_ISSLOW
|SFGAO_GHOSTED
|SFGAO_FILESYSTEM
;
768 hr
= IShellFolder_GetAttributesOf(psfDesktop
, 1,
769 (LPCITEMIDLIST
*)&pidlMyDocuments
, &dwAttributes
);
770 ok (hr
== S_OK
, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr
);
772 ok (dwAttributes
== SFGAO_FILESYSTEM
,
773 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
776 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
777 RegSetValueExW(hKey
, wszAttributes
, 0, REG_DWORD
, (LPBYTE
)&dwOrigAttributes
, sizeof(DWORD
));
778 RegSetValueExW(hKey
, wszCallForAttributes
, 0, REG_DWORD
,
779 (LPBYTE
)&dwOrigCallForAttributes
, sizeof(DWORD
));
781 IMalloc_Free(ppM
, pidlMyDocuments
);
782 IShellFolder_Release(psfDesktop
);
785 static void test_GetAttributesOf(void)
788 LPSHELLFOLDER psfDesktop
, psfMyComputer
;
789 SHITEMID emptyitem
= { 0, { 0 } };
790 LPCITEMIDLIST pidlEmpty
= (LPCITEMIDLIST
)&emptyitem
;
791 LPITEMIDLIST pidlMyComputer
;
793 static const DWORD desktopFlags
[] = {
795 SFGAO_STORAGE
| SFGAO_HASPROPSHEET
| SFGAO_STORAGEANCESTOR
| SFGAO_FILESYSANCESTOR
|
796 SFGAO_FOLDER
| SFGAO_FILESYSTEM
| SFGAO_HASSUBFOLDER
,
798 SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_STREAM
| SFGAO_FILESYSANCESTOR
|
799 SFGAO_FOLDER
| SFGAO_FILESYSTEM
| SFGAO_HASSUBFOLDER
,
800 /* WinMe, Win9x, WinNT*/
801 SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_FILESYSANCESTOR
|
802 SFGAO_FOLDER
| SFGAO_FILESYSTEM
| SFGAO_HASSUBFOLDER
804 static const DWORD myComputerFlags
[] = {
806 SFGAO_CANRENAME
| SFGAO_CANDELETE
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
|
807 SFGAO_FILESYSANCESTOR
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
,
809 SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
| SFGAO_STREAM
|
810 SFGAO_FILESYSANCESTOR
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
,
811 /* WinMe, Win9x, WinNT */
812 SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
| SFGAO_FILESYSANCESTOR
|
813 SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
,
814 /* Win95, WinNT when queried directly */
815 SFGAO_CANLINK
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
| SFGAO_FILESYSANCESTOR
|
816 SFGAO_FOLDER
| SFGAO_FILESYSTEM
| SFGAO_HASSUBFOLDER
818 WCHAR wszMyComputer
[] = {
819 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
820 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
821 char cCurrDirA
[MAX_PATH
] = {0};
822 WCHAR cCurrDirW
[MAX_PATH
];
823 static WCHAR cTestDirW
[] = {'t','e','s','t','d','i','r',0};
824 IShellFolder
*IDesktopFolder
, *testIShellFolder
;
827 BOOL foundFlagsMatch
;
829 hr
= SHGetDesktopFolder(&psfDesktop
);
830 ok (hr
== S_OK
, "SHGetDesktopFolder failed! hr = %08x\n", hr
);
831 if (hr
!= S_OK
) return;
833 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
834 dwFlags
= 0xffffffff;
835 hr
= IShellFolder_GetAttributesOf(psfDesktop
, 1, &pidlEmpty
, &dwFlags
);
836 ok (hr
== S_OK
, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr
);
837 for (i
= 0, foundFlagsMatch
= FALSE
; !foundFlagsMatch
&&
838 i
< sizeof(desktopFlags
) / sizeof(desktopFlags
[0]); i
++)
840 if (desktopFlags
[i
] == dwFlags
)
841 foundFlagsMatch
= TRUE
;
843 ok (foundFlagsMatch
, "Wrong Desktop attributes: %08x\n", dwFlags
);
845 /* .. or with no itemidlist at all. */
846 dwFlags
= 0xffffffff;
847 hr
= IShellFolder_GetAttributesOf(psfDesktop
, 0, NULL
, &dwFlags
);
848 ok (hr
== S_OK
, "Desktop->GetAttributesOf(NULL) 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 /* Testing the attributes of the MyComputer shellfolder */
858 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszMyComputer
, NULL
, &pidlMyComputer
, NULL
);
859 ok (hr
== S_OK
, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr
);
861 IShellFolder_Release(psfDesktop
);
865 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
866 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
868 dwFlags
= 0xffffffff;
869 hr
= IShellFolder_GetAttributesOf(psfDesktop
, 1, (LPCITEMIDLIST
*)&pidlMyComputer
, &dwFlags
);
870 ok (hr
== S_OK
, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr
);
871 for (i
= 0, foundFlagsMatch
= FALSE
; !foundFlagsMatch
&&
872 i
< sizeof(myComputerFlags
) / sizeof(myComputerFlags
[0]); i
++)
874 if ((myComputerFlags
[i
] | SFGAO_CANLINK
) == dwFlags
)
875 foundFlagsMatch
= TRUE
;
878 ok (foundFlagsMatch
, "Wrong MyComputer attributes: %08x\n", dwFlags
);
880 hr
= IShellFolder_BindToObject(psfDesktop
, pidlMyComputer
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfMyComputer
);
881 ok (hr
== S_OK
, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr
);
882 IShellFolder_Release(psfDesktop
);
883 IMalloc_Free(ppM
, pidlMyComputer
);
884 if (hr
!= S_OK
) return;
886 hr
= IShellFolder_GetAttributesOf(psfMyComputer
, 1, &pidlEmpty
, &dwFlags
);
888 ok (hr
== E_INVALIDARG
||
889 broken(hr
== S_OK
), /* W2K and earlier */
890 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr
);
892 dwFlags
= 0xffffffff;
893 hr
= IShellFolder_GetAttributesOf(psfMyComputer
, 0, NULL
, &dwFlags
);
894 ok (hr
== S_OK
, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr
);
895 for (i
= 0, foundFlagsMatch
= FALSE
; !foundFlagsMatch
&&
896 i
< sizeof(myComputerFlags
) / sizeof(myComputerFlags
[0]); i
++)
898 if (myComputerFlags
[i
] == dwFlags
)
899 foundFlagsMatch
= TRUE
;
902 ok (foundFlagsMatch
, "Wrong MyComputer attributes: %08x\n", dwFlags
);
904 IShellFolder_Release(psfMyComputer
);
906 GetCurrentDirectoryA(MAX_PATH
, cCurrDirA
);
907 len
= lstrlenA(cCurrDirA
);
910 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
913 if (len
> 3 && cCurrDirA
[len
-1] == '\\')
914 cCurrDirA
[len
-1] = 0;
916 /* create test directory */
917 CreateFilesFolders();
919 MultiByteToWideChar(CP_ACP
, 0, cCurrDirA
, -1, cCurrDirW
, MAX_PATH
);
921 hr
= SHGetDesktopFolder(&IDesktopFolder
);
922 ok(hr
== S_OK
, "SHGetDesktopfolder failed %08x\n", hr
);
924 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
, NULL
, NULL
, cCurrDirW
, NULL
, &newPIDL
, 0);
925 ok(hr
== S_OK
, "ParseDisplayName failed %08x\n", hr
);
927 hr
= IShellFolder_BindToObject(IDesktopFolder
, newPIDL
, NULL
, (REFIID
)&IID_IShellFolder
, (LPVOID
*)&testIShellFolder
);
928 ok(hr
== S_OK
, "BindToObject failed %08x\n", hr
);
930 IMalloc_Free(ppM
, newPIDL
);
932 /* get relative PIDL */
933 hr
= IShellFolder_ParseDisplayName(testIShellFolder
, NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
934 ok(hr
== S_OK
, "ParseDisplayName failed %08x\n", hr
);
936 /* test the shell attributes of the test directory using the relative PIDL */
937 dwFlags
= SFGAO_FOLDER
;
938 hr
= IShellFolder_GetAttributesOf(testIShellFolder
, 1, (LPCITEMIDLIST
*)&newPIDL
, &dwFlags
);
939 ok (hr
== S_OK
, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr
);
940 ok ((dwFlags
&SFGAO_FOLDER
), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags
);
943 IMalloc_Free(ppM
, newPIDL
);
945 /* append testdirectory name to path */
946 if (cCurrDirA
[len
-1] == '\\')
947 cCurrDirA
[len
-1] = 0;
948 lstrcatA(cCurrDirA
, "\\testdir");
949 MultiByteToWideChar(CP_ACP
, 0, cCurrDirA
, -1, cCurrDirW
, MAX_PATH
);
951 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
, NULL
, NULL
, cCurrDirW
, NULL
, &newPIDL
, 0);
952 ok(hr
== S_OK
, "ParseDisplayName failed %08x\n", hr
);
954 /* test the shell attributes of the test directory using the absolute PIDL */
955 dwFlags
= SFGAO_FOLDER
;
956 hr
= IShellFolder_GetAttributesOf(IDesktopFolder
, 1, (LPCITEMIDLIST
*)&newPIDL
, &dwFlags
);
957 ok (hr
== S_OK
, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr
);
958 ok ((dwFlags
&SFGAO_FOLDER
), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags
);
961 IMalloc_Free(ppM
, newPIDL
);
963 IShellFolder_Release(testIShellFolder
);
967 IShellFolder_Release(IDesktopFolder
);
970 static void test_SHGetPathFromIDList(void)
972 SHITEMID emptyitem
= { 0, { 0 } };
973 LPCITEMIDLIST pidlEmpty
= (LPCITEMIDLIST
)&emptyitem
;
974 LPITEMIDLIST pidlMyComputer
;
975 WCHAR wszPath
[MAX_PATH
], wszDesktop
[MAX_PATH
];
978 LPSHELLFOLDER psfDesktop
;
979 WCHAR wszMyComputer
[] = {
980 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
981 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
982 WCHAR wszFileName
[MAX_PATH
];
983 LPITEMIDLIST pidlTestFile
;
986 static WCHAR wszTestFile
[] = {
987 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
988 HRESULT (WINAPI
*pSHGetSpecialFolderLocation
)(HWND
, int, LPITEMIDLIST
*);
990 LPITEMIDLIST pidlPrograms
;
992 if(!pSHGetPathFromIDListW
|| !pSHGetSpecialFolderPathW
)
994 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
998 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1001 result
= pSHGetPathFromIDListW(NULL
, wszPath
);
1002 ok(!result
, "Expected failure\n");
1003 ok(!wszPath
[0], "Expected empty string\n");
1005 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1006 result
= pSHGetSpecialFolderPathW(NULL
, wszDesktop
, CSIDL_DESKTOP
, FALSE
);
1007 ok(result
, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1008 if (!result
) return;
1010 /* Check if we are on Win9x */
1011 SetLastError(0xdeadbeef);
1012 lstrcmpiW(wszDesktop
, wszDesktop
);
1013 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1015 win_skip("Most W-calls are not implemented\n");
1019 result
= pSHGetPathFromIDListW(pidlEmpty
, wszPath
);
1020 ok(result
, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1021 if (!result
) return;
1022 ok(!lstrcmpiW(wszDesktop
, wszPath
), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1024 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1025 hr
= SHGetDesktopFolder(&psfDesktop
);
1026 ok (hr
== S_OK
, "SHGetDesktopFolder failed! hr = %08x\n", hr
);
1027 if (hr
!= S_OK
) return;
1029 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszMyComputer
, NULL
, &pidlMyComputer
, NULL
);
1030 ok (hr
== S_OK
, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr
);
1032 IShellFolder_Release(psfDesktop
);
1036 SetLastError(0xdeadbeef);
1039 result
= pSHGetPathFromIDListW(pidlMyComputer
, wszPath
);
1040 ok (!result
, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1041 ok (GetLastError()==0xdeadbeef ||
1042 GetLastError()==ERROR_SUCCESS
, /* Vista and higher */
1043 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1044 ok (!wszPath
[0], "Expected empty path\n");
1046 IShellFolder_Release(psfDesktop
);
1050 IMalloc_Free(ppM
, pidlMyComputer
);
1052 result
= pSHGetSpecialFolderPathW(NULL
, wszFileName
, CSIDL_DESKTOPDIRECTORY
, FALSE
);
1053 ok(result
, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1055 IShellFolder_Release(psfDesktop
);
1058 myPathAddBackslashW(wszFileName
);
1059 lstrcatW(wszFileName
, wszTestFile
);
1060 hTestFile
= CreateFileW(wszFileName
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
1061 ok(hTestFile
!= INVALID_HANDLE_VALUE
, "CreateFileW failed! Last error: %u\n", GetLastError());
1062 if (hTestFile
== INVALID_HANDLE_VALUE
) {
1063 IShellFolder_Release(psfDesktop
);
1066 CloseHandle(hTestFile
);
1068 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszTestFile
, NULL
, &pidlTestFile
, NULL
);
1069 ok (hr
== S_OK
, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr
);
1071 IShellFolder_Release(psfDesktop
);
1072 DeleteFileW(wszFileName
);
1073 IMalloc_Free(ppM
, pidlTestFile
);
1077 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1078 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1079 hr
= IShellFolder_GetDisplayNameOf(psfDesktop
, pidlTestFile
, SHGDN_FORPARSING
, &strret
);
1080 ok (hr
== S_OK
, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr
);
1081 IShellFolder_Release(psfDesktop
);
1082 DeleteFileW(wszFileName
);
1084 IMalloc_Free(ppM
, pidlTestFile
);
1089 pStrRetToBufW(&strret
, pidlTestFile
, wszPath
, MAX_PATH
);
1090 ok(0 == lstrcmpW(wszFileName
, wszPath
),
1091 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1092 "returned incorrect path for file placed on desktop\n");
1095 result
= pSHGetPathFromIDListW(pidlTestFile
, wszPath
);
1096 ok(result
, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1097 IMalloc_Free(ppM
, pidlTestFile
);
1098 if (!result
) return;
1099 ok(0 == lstrcmpW(wszFileName
, wszPath
), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1102 /* Test if we can get the path from the start menu "program files" PIDL. */
1103 hShell32
= GetModuleHandleA("shell32");
1104 pSHGetSpecialFolderLocation
= (void *)GetProcAddress(hShell32
, "SHGetSpecialFolderLocation");
1106 hr
= pSHGetSpecialFolderLocation(NULL
, CSIDL_PROGRAM_FILES
, &pidlPrograms
);
1107 ok(hr
== S_OK
, "SHGetFolderLocation failed: 0x%08x\n", hr
);
1109 SetLastError(0xdeadbeef);
1110 result
= pSHGetPathFromIDListW(pidlPrograms
, wszPath
);
1111 IMalloc_Free(ppM
, pidlPrograms
);
1112 ok(result
, "SHGetPathFromIDListW failed\n");
1115 static void test_EnumObjects_and_CompareIDs(void)
1117 ITEMIDLIST
*newPIDL
;
1118 IShellFolder
*IDesktopFolder
, *testIShellFolder
;
1119 char cCurrDirA
[MAX_PATH
] = {0};
1120 static const CHAR cTestDirA
[] = "\\testdir";
1121 WCHAR cTestDirW
[MAX_PATH
];
1125 GetCurrentDirectoryA(MAX_PATH
, cCurrDirA
);
1126 len
= lstrlenA(cCurrDirA
);
1129 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1132 if(cCurrDirA
[len
-1] == '\\')
1133 cCurrDirA
[len
-1] = 0;
1135 lstrcatA(cCurrDirA
, cTestDirA
);
1136 MultiByteToWideChar(CP_ACP
, 0, cCurrDirA
, -1, cTestDirW
, MAX_PATH
);
1138 hr
= SHGetDesktopFolder(&IDesktopFolder
);
1139 ok(hr
== S_OK
, "SHGetDesktopfolder failed %08x\n", hr
);
1141 CreateFilesFolders();
1143 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
, NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
1144 ok(hr
== S_OK
, "ParseDisplayName failed %08x\n", hr
);
1146 hr
= IShellFolder_BindToObject(IDesktopFolder
, newPIDL
, NULL
, (REFIID
)&IID_IShellFolder
, (LPVOID
*)&testIShellFolder
);
1147 ok(hr
== S_OK
, "BindToObject failed %08x\n", hr
);
1149 test_EnumObjects(testIShellFolder
);
1151 IShellFolder_Release(testIShellFolder
);
1155 IMalloc_Free(ppM
, newPIDL
);
1157 IShellFolder_Release(IDesktopFolder
);
1160 /* A simple implementation of an IPropertyBag, which returns fixed values for
1161 * 'Target' and 'Attributes' properties.
1163 static HRESULT WINAPI
InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag
*iface
, REFIID riid
,
1167 return E_INVALIDARG
;
1169 if (IsEqualIID(&IID_IUnknown
, riid
) || IsEqualIID(&IID_IPropertyBag
, riid
)) {
1172 ok (FALSE
, "InitPropertyBag asked for unknown interface!\n");
1173 return E_NOINTERFACE
;
1176 IPropertyBag_AddRef(iface
);
1180 static ULONG WINAPI
InitPropertyBag_IPropertyBag_AddRef(IPropertyBag
*iface
) {
1184 static ULONG WINAPI
InitPropertyBag_IPropertyBag_Release(IPropertyBag
*iface
) {
1188 static HRESULT WINAPI
InitPropertyBag_IPropertyBag_Read(IPropertyBag
*iface
, LPCOLESTR pszPropName
,
1189 VARIANT
*pVar
, IErrorLog
*pErrorLog
)
1191 static const WCHAR wszTargetSpecialFolder
[] = {
1192 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1193 static const WCHAR wszTarget
[] = {
1194 'T','a','r','g','e','t',0 };
1195 static const WCHAR wszAttributes
[] = {
1196 'A','t','t','r','i','b','u','t','e','s',0 };
1197 static const WCHAR wszResolveLinkFlags
[] = {
1198 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1199 static const WCHAR wszTargetKnownFolder
[] = {
1200 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1201 static const WCHAR wszCLSID
[] = {
1202 'C','L','S','I','D',0 };
1204 if (!lstrcmpW(pszPropName
, wszTargetSpecialFolder
)) {
1205 ok(V_VT(pVar
) == VT_I4
||
1206 broken(V_VT(pVar
) == VT_BSTR
), /* Win2k */
1207 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1208 return E_INVALIDARG
;
1211 if (!lstrcmpW(pszPropName
, wszResolveLinkFlags
))
1213 ok(V_VT(pVar
) == VT_UI4
, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1214 return E_INVALIDARG
;
1217 if (!lstrcmpW(pszPropName
, wszTarget
)) {
1218 WCHAR wszPath
[MAX_PATH
];
1221 ok(V_VT(pVar
) == VT_BSTR
||
1222 broken(V_VT(pVar
) == VT_EMPTY
), /* Win2k */
1223 "Wrong variant type for 'Target' property!\n");
1224 if (V_VT(pVar
) != VT_BSTR
) return E_INVALIDARG
;
1226 result
= pSHGetSpecialFolderPathW(NULL
, wszPath
, CSIDL_DESKTOPDIRECTORY
, FALSE
);
1227 ok(result
, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1228 if (!result
) return E_INVALIDARG
;
1230 V_BSTR(pVar
) = SysAllocString(wszPath
);
1234 if (!lstrcmpW(pszPropName
, wszAttributes
)) {
1235 ok(V_VT(pVar
) == VT_UI4
, "Wrong variant type for 'Attributes' property!\n");
1236 if (V_VT(pVar
) != VT_UI4
) return E_INVALIDARG
;
1237 V_UI4(pVar
) = SFGAO_FOLDER
|SFGAO_HASSUBFOLDER
|SFGAO_FILESYSANCESTOR
|
1238 SFGAO_CANRENAME
|SFGAO_FILESYSTEM
;
1242 if (!lstrcmpW(pszPropName
, wszTargetKnownFolder
)) {
1243 ok(V_VT(pVar
) == VT_BSTR
, "Wrong variant type for 'TargetKnownFolder' property!\n");
1245 return E_INVALIDARG
;
1248 if (!lstrcmpW(pszPropName
, wszCLSID
)) {
1249 ok(V_VT(pVar
) == VT_EMPTY
, "Wrong variant type for 'CLSID' property!\n");
1251 return E_INVALIDARG
;
1254 ok(FALSE
, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName
), V_VT(pVar
));
1255 return E_INVALIDARG
;
1258 static HRESULT WINAPI
InitPropertyBag_IPropertyBag_Write(IPropertyBag
*iface
, LPCOLESTR pszPropName
,
1261 ok(FALSE
, "Unexpected call to IPropertyBag_Write\n");
1265 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl
= {
1266 InitPropertyBag_IPropertyBag_QueryInterface
,
1267 InitPropertyBag_IPropertyBag_AddRef
,
1268 InitPropertyBag_IPropertyBag_Release
,
1269 InitPropertyBag_IPropertyBag_Read
,
1270 InitPropertyBag_IPropertyBag_Write
1273 static struct IPropertyBag InitPropertyBag
= {
1274 &InitPropertyBag_IPropertyBagVtbl
1277 static void test_FolderShortcut(void) {
1278 IPersistPropertyBag
*pPersistPropertyBag
;
1279 IShellFolder
*pShellFolder
, *pDesktopFolder
;
1280 IPersistFolder3
*pPersistFolder3
;
1283 WCHAR wszDesktopPath
[MAX_PATH
], wszBuffer
[MAX_PATH
];
1286 LPITEMIDLIST pidlCurrentFolder
, pidlWineTestFolder
, pidlSubFolder
;
1288 WCHAR wszWineTestFolder
[] = {
1289 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1290 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1291 WCHAR wszShellExtKey
[] = { 'S','o','f','t','w','a','r','e','\\',
1292 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1293 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1294 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1295 'N','a','m','e','S','p','a','c','e','\\',
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 };
1299 WCHAR wszSomeSubFolder
[] = { 'S','u','b','F','o','l','d','e','r', 0};
1300 static const GUID CLSID_UnixDosFolder
=
1301 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1303 if (!pSHGetSpecialFolderPathW
|| !pStrRetToBufW
) {
1304 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1308 if (!pSHGetFolderPathAndSubDirA
)
1310 win_skip("FolderShortcut test doesn't work on Win2k\n");
1314 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1315 * via their IPersistPropertyBag interface. And that the target folder
1316 * is taken from the IPropertyBag's 'Target' property.
1318 hr
= CoCreateInstance(&CLSID_FolderShortcut
, NULL
, CLSCTX_INPROC_SERVER
,
1319 &IID_IPersistPropertyBag
, (LPVOID
*)&pPersistPropertyBag
);
1320 if (hr
== REGDB_E_CLASSNOTREG
) {
1321 win_skip("CLSID_FolderShortcut is not implemented\n");
1324 ok (hr
== S_OK
, "CoCreateInstance failed! hr = 0x%08x\n", hr
);
1325 if (hr
!= S_OK
) return;
1327 hr
= IPersistPropertyBag_Load(pPersistPropertyBag
, &InitPropertyBag
, NULL
);
1328 ok(hr
== S_OK
, "IPersistPropertyBag_Load failed! hr = %08x\n", hr
);
1330 IPersistPropertyBag_Release(pPersistPropertyBag
);
1334 hr
= IPersistPropertyBag_QueryInterface(pPersistPropertyBag
, &IID_IShellFolder
,
1335 (LPVOID
*)&pShellFolder
);
1336 IPersistPropertyBag_Release(pPersistPropertyBag
);
1337 ok(hr
== S_OK
, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr
);
1338 if (hr
!= S_OK
) return;
1340 hr
= IShellFolder_GetDisplayNameOf(pShellFolder
, NULL
, SHGDN_FORPARSING
, &strret
);
1341 ok(hr
== S_OK
, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr
);
1343 IShellFolder_Release(pShellFolder
);
1347 result
= pSHGetSpecialFolderPathW(NULL
, wszDesktopPath
, CSIDL_DESKTOPDIRECTORY
, FALSE
);
1348 ok(result
, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1349 if (!result
) return;
1351 pStrRetToBufW(&strret
, NULL
, wszBuffer
, MAX_PATH
);
1352 ok(!lstrcmpiW(wszDesktopPath
, wszBuffer
), "FolderShortcut returned incorrect folder!\n");
1354 hr
= IShellFolder_QueryInterface(pShellFolder
, &IID_IPersistFolder3
, (LPVOID
*)&pPersistFolder3
);
1355 IShellFolder_Release(pShellFolder
);
1356 ok(hr
== S_OK
, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr
);
1357 if (hr
!= S_OK
) return;
1359 hr
= IPersistFolder3_GetClassID(pPersistFolder3
, &clsid
);
1360 ok(hr
== S_OK
, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr
);
1361 ok(IsEqualCLSID(&clsid
, &CLSID_FolderShortcut
), "Unexpected CLSID!\n");
1363 hr
= IPersistFolder3_GetCurFolder(pPersistFolder3
, &pidlCurrentFolder
);
1364 todo_wine
ok(hr
== S_FALSE
, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr
);
1365 ok(!pidlCurrentFolder
, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1367 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1368 * shell namespace. The target folder, read from the property bag above, remains untouched.
1369 * The following tests show this: The itemidlist for some imaginary shellfolder object
1370 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1371 * itemidlist, but GetDisplayNameOf still returns the path from above.
1373 hr
= SHGetDesktopFolder(&pDesktopFolder
);
1374 ok (hr
== S_OK
, "SHGetDesktopFolder failed! hr = %08x\n", hr
);
1375 if (hr
!= S_OK
) return;
1377 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1378 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1379 RegCreateKeyW(HKEY_CURRENT_USER
, wszShellExtKey
, &hShellExtKey
);
1380 RegCloseKey(hShellExtKey
);
1381 hr
= IShellFolder_ParseDisplayName(pDesktopFolder
, NULL
, NULL
, wszWineTestFolder
, NULL
,
1382 &pidlWineTestFolder
, NULL
);
1383 RegDeleteKeyW(HKEY_CURRENT_USER
, wszShellExtKey
);
1384 IShellFolder_Release(pDesktopFolder
);
1385 ok (hr
== S_OK
, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr
);
1386 if (hr
!= S_OK
) return;
1388 hr
= IPersistFolder3_Initialize(pPersistFolder3
, pidlWineTestFolder
);
1389 ok (hr
== S_OK
, "IPersistFolder3::Initialize failed! hr = %08x\n", hr
);
1391 IPersistFolder3_Release(pPersistFolder3
);
1392 pILFree(pidlWineTestFolder
);
1396 hr
= IPersistFolder3_GetCurFolder(pPersistFolder3
, &pidlCurrentFolder
);
1397 ok(hr
== S_OK
, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr
);
1398 ok(pILIsEqual(pidlCurrentFolder
, pidlWineTestFolder
),
1399 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1400 pILFree(pidlCurrentFolder
);
1401 pILFree(pidlWineTestFolder
);
1403 hr
= IPersistFolder3_QueryInterface(pPersistFolder3
, &IID_IShellFolder
, (LPVOID
*)&pShellFolder
);
1404 IPersistFolder3_Release(pPersistFolder3
);
1405 ok(hr
== S_OK
, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr
);
1406 if (hr
!= S_OK
) return;
1408 hr
= IShellFolder_GetDisplayNameOf(pShellFolder
, NULL
, SHGDN_FORPARSING
, &strret
);
1409 ok(hr
== S_OK
, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr
);
1411 IShellFolder_Release(pShellFolder
);
1415 pStrRetToBufW(&strret
, NULL
, wszBuffer
, MAX_PATH
);
1416 ok(!lstrcmpiW(wszDesktopPath
, wszBuffer
), "FolderShortcut returned incorrect folder!\n");
1418 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1419 * but ShellFSFolders. */
1420 myPathAddBackslashW(wszDesktopPath
);
1421 lstrcatW(wszDesktopPath
, wszSomeSubFolder
);
1422 if (!CreateDirectoryW(wszDesktopPath
, NULL
)) {
1423 IShellFolder_Release(pShellFolder
);
1427 hr
= IShellFolder_ParseDisplayName(pShellFolder
, NULL
, NULL
, wszSomeSubFolder
, NULL
,
1428 &pidlSubFolder
, NULL
);
1429 RemoveDirectoryW(wszDesktopPath
);
1430 ok (hr
== S_OK
, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr
);
1432 IShellFolder_Release(pShellFolder
);
1436 hr
= IShellFolder_BindToObject(pShellFolder
, pidlSubFolder
, NULL
, &IID_IPersistFolder3
,
1437 (LPVOID
*)&pPersistFolder3
);
1438 IShellFolder_Release(pShellFolder
);
1439 pILFree(pidlSubFolder
);
1440 ok (hr
== S_OK
, "IShellFolder::BindToObject failed! hr = %08x\n", hr
);
1444 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1445 * a little bit and also allow CLSID_UnixDosFolder. */
1446 hr
= IPersistFolder3_GetClassID(pPersistFolder3
, &clsid
);
1447 ok(hr
== S_OK
, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr
);
1448 ok(IsEqualCLSID(&clsid
, &CLSID_ShellFSFolder
) || IsEqualCLSID(&clsid
, &CLSID_UnixDosFolder
),
1449 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1451 IPersistFolder3_Release(pPersistFolder3
);
1454 #include "pshpack1.h"
1455 struct FileStructA
{
1459 WORD uFileDate
; /* In our current implementation this is */
1460 WORD uFileTime
; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1465 struct FileStructW
{
1466 WORD cbLen
; /* Length of this element. */
1467 BYTE abFooBar1
[6]; /* Beyond any recognition. */
1468 WORD uDate
; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1469 WORD uTime
; /* (this is currently speculation) */
1470 WORD uDate2
; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1471 WORD uTime2
; /* (this is currently speculation) */
1472 BYTE abFooBar2
[4]; /* Beyond any recognition. */
1473 WCHAR wszName
[1]; /* The long filename in unicode. */
1474 /* Just for documentation: Right after the unicode string: */
1475 WORD cbOffset
; /* FileStructW's offset from the beginning of the SHITMEID.
1476 * SHITEMID->cb == uOffset + cbLen */
1478 #include "poppack.h"
1480 static void test_ITEMIDLIST_format(void) {
1481 WCHAR wszPersonal
[MAX_PATH
];
1482 LPSHELLFOLDER psfDesktop
, psfPersonal
;
1483 LPITEMIDLIST pidlPersonal
, pidlFile
;
1487 WCHAR wszFile
[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1488 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1491 if (!pSHGetSpecialFolderPathW
) return;
1493 bResult
= pSHGetSpecialFolderPathW(NULL
, wszPersonal
, CSIDL_PERSONAL
, FALSE
);
1494 ok(bResult
, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1495 if (!bResult
) return;
1497 SetLastError(0xdeadbeef);
1498 bResult
= SetCurrentDirectoryW(wszPersonal
);
1499 if (!bResult
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
) {
1500 win_skip("Most W-calls are not implemented\n");
1503 ok(bResult
, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1504 if (!bResult
) return;
1506 hr
= SHGetDesktopFolder(&psfDesktop
);
1507 ok(hr
== S_OK
, "SHGetDesktopFolder failed! hr: %08x\n", hr
);
1508 if (hr
!= S_OK
) return;
1510 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszPersonal
, NULL
, &pidlPersonal
, NULL
);
1511 ok(hr
== S_OK
, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr
);
1513 IShellFolder_Release(psfDesktop
);
1517 hr
= IShellFolder_BindToObject(psfDesktop
, pidlPersonal
, NULL
, &IID_IShellFolder
,
1518 (LPVOID
*)&psfPersonal
);
1519 IShellFolder_Release(psfDesktop
);
1520 pILFree(pidlPersonal
);
1521 ok(hr
== S_OK
, "psfDesktop->BindToObject failed! hr = %08x\n", hr
);
1522 if (hr
!= S_OK
) return;
1524 for (i
=0; i
<3; i
++) {
1525 CHAR szFile
[MAX_PATH
];
1526 struct FileStructA
*pFileStructA
;
1529 WideCharToMultiByte(CP_ACP
, 0, wszFile
[i
], -1, szFile
, MAX_PATH
, NULL
, NULL
);
1531 hFile
= CreateFileW(wszFile
[i
], GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_FLAG_WRITE_THROUGH
, NULL
);
1532 ok(hFile
!= INVALID_HANDLE_VALUE
, "CreateFile failed! (%u)\n", GetLastError());
1533 if (hFile
== INVALID_HANDLE_VALUE
) {
1534 IShellFolder_Release(psfPersonal
);
1539 hr
= IShellFolder_ParseDisplayName(psfPersonal
, NULL
, NULL
, wszFile
[i
], NULL
, &pidlFile
, NULL
);
1540 DeleteFileW(wszFile
[i
]);
1541 ok(hr
== S_OK
, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr
);
1543 IShellFolder_Release(psfPersonal
);
1547 pFileStructA
= (struct FileStructA
*)pidlFile
->mkid
.abID
;
1548 ok(pFileStructA
->type
== 0x32, "PIDLTYPE should be 0x32!\n");
1549 ok(pFileStructA
->dummy
== 0x00, "Dummy Byte should be 0x00!\n");
1550 ok(pFileStructA
->dwFileSize
== 0, "Filesize should be zero!\n");
1552 if (i
< 2) /* First two file names are already in valid 8.3 format */
1553 ok(!strcmp(szFile
, (CHAR
*)&pidlFile
->mkid
.abID
[12]), "Wrong file name!\n");
1555 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1556 * can't implement this correctly, since unix filesystems don't support
1557 * this nasty short/long filename stuff. So we'll probably stay with our
1558 * current habbit of storing the long filename here, which seems to work
1561 ok(pidlFile
->mkid
.abID
[18] == '~' ||
1562 broken(pidlFile
->mkid
.abID
[34] == '~'), /* Win2k */
1563 "Should be derived 8.3 name!\n");
1565 if (i
== 0) /* First file name has an even number of chars. No need for alignment. */
1566 ok(pidlFile
->mkid
.abID
[12 + strlen(szFile
) + 1] != '\0' ||
1567 broken(pidlFile
->mkid
.cb
== 2 + 12 + strlen(szFile
) + 1 + 1), /* Win2k */
1568 "Alignment byte, where there shouldn't be!\n");
1570 if (i
== 1) /* Second file name has an uneven number of chars => alignment byte */
1571 ok(pidlFile
->mkid
.abID
[12 + strlen(szFile
) + 1] == '\0',
1572 "There should be an alignment byte, but isn't!\n");
1574 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1575 cbOffset
= *(WORD
*)(((LPBYTE
)pidlFile
)+pidlFile
->mkid
.cb
-sizeof(WORD
));
1576 ok ((cbOffset
>= sizeof(struct FileStructA
) &&
1577 cbOffset
<= pidlFile
->mkid
.cb
- sizeof(struct FileStructW
)) ||
1578 broken(pidlFile
->mkid
.cb
== 2 + 12 + strlen(szFile
) + 1 + 1) || /* Win2k on short names */
1579 broken(pidlFile
->mkid
.cb
== 2 + 12 + strlen(szFile
) + 1 + 12 + 1), /* Win2k on long names */
1580 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset
);
1582 if (cbOffset
>= sizeof(struct FileStructA
) &&
1583 cbOffset
<= pidlFile
->mkid
.cb
- sizeof(struct FileStructW
))
1585 struct FileStructW
*pFileStructW
= (struct FileStructW
*)(((LPBYTE
)pidlFile
)+cbOffset
);
1587 ok(pidlFile
->mkid
.cb
== cbOffset
+ pFileStructW
->cbLen
,
1588 "FileStructW's offset and length should add up to the PIDL's length!\n");
1590 if (pidlFile
->mkid
.cb
== cbOffset
+ pFileStructW
->cbLen
) {
1591 /* Since we just created the file, time of creation,
1592 * time of last access and time of last write access just be the same.
1593 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1594 * after the first run. I do remember something with NTFS keeping the creation time
1595 * if a file is deleted and then created again within a couple of seconds or so.
1596 * Might be the reason. */
1597 ok (pFileStructA
->uFileDate
== pFileStructW
->uDate
&&
1598 pFileStructA
->uFileTime
== pFileStructW
->uTime
,
1599 "Last write time should match creation time!\n");
1601 /* On FAT filesystems the last access time is midnight
1602 local time, so the values of uDate2 and uTime2 will
1603 depend on the local timezone. If the times are exactly
1604 equal then the dates should be identical for both FAT
1605 and NTFS as no timezone is more than 1 day away from UTC.
1607 if (pFileStructA
->uFileTime
== pFileStructW
->uTime2
)
1609 ok (pFileStructA
->uFileDate
== pFileStructW
->uDate2
,
1610 "Last write date and time should match last access date and time!\n");
1614 /* Filesystem may be FAT. Check date within 1 day
1615 and seconds are zero. */
1616 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1617 ok ((pFileStructW
->uTime2
& 0x1F) == 0,
1618 "Last access time on FAT filesystems should have zero seconds.\n");
1619 /* TODO: Perform check for date being within one day.*/
1622 ok (!lstrcmpW(wszFile
[i
], pFileStructW
->wszName
) ||
1623 !lstrcmpW(wszFile
[i
], (WCHAR
*)(pFileStructW
->abFooBar2
+ 22)) || /* Vista */
1624 !lstrcmpW(wszFile
[i
], (WCHAR
*)(pFileStructW
->abFooBar2
+ 26)), /* Win7 */
1625 "The filename should be stored in unicode at this position!\n");
1632 IShellFolder_Release(psfPersonal
);
1635 static void test_SHGetFolderPathAndSubDirA(void)
1641 static char wine
[] = "wine";
1642 static char winetemp
[] = "wine\\temp";
1643 static char appdata
[MAX_PATH
];
1644 static char testpath
[MAX_PATH
];
1645 static char toolongpath
[MAX_PATH
+1];
1647 if(!pSHGetFolderPathAndSubDirA
)
1649 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1653 if(!pSHGetFolderPathA
) {
1654 win_skip("SHGetFolderPathA not present!\n");
1657 if(FAILED(pSHGetFolderPathA(NULL
, CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, appdata
)))
1659 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1663 sprintf(testpath
, "%s\\%s", appdata
, winetemp
);
1664 delret
= RemoveDirectoryA(testpath
);
1665 if(!delret
&& (ERROR_PATH_NOT_FOUND
!= GetLastError()) ) {
1666 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath
, GetLastError());
1670 sprintf(testpath
, "%s\\%s", appdata
, wine
);
1671 delret
= RemoveDirectoryA(testpath
);
1672 if(!delret
&& (ERROR_PATH_NOT_FOUND
!= GetLastError()) && (ERROR_FILE_NOT_FOUND
!= GetLastError())) {
1673 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath
, GetLastError());
1677 /* test invalid second parameter */
1678 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| 0xff, NULL
, SHGFP_TYPE_CURRENT
, wine
, testpath
);
1679 ok(E_INVALIDARG
== ret
, "expected E_INVALIDARG, got %x\n", ret
);
1681 /* test fourth parameter */
1682 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| CSIDL_LOCAL_APPDATA
, NULL
, 2, winetemp
, testpath
);
1684 case S_OK
: /* winvista */
1685 ok(!strncmp(appdata
, testpath
, strlen(appdata
)),
1686 "expected %s to start with %s\n", testpath
, appdata
);
1687 ok(!lstrcmpA(&testpath
[1 + strlen(appdata
)], winetemp
),
1688 "expected %s to end with %s\n", testpath
, winetemp
);
1690 case E_INVALIDARG
: /* winxp, win2k3 */
1693 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret
);
1696 /* test fifth parameter */
1698 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, NULL
, testpath
);
1699 ok(S_OK
== ret
, "expected S_OK, got %x\n", ret
);
1700 ok(!lstrcmpA(appdata
, testpath
), "expected %s, got %s\n", appdata
, testpath
);
1703 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, "", testpath
);
1704 ok(S_OK
== ret
, "expected S_OK, got %x\n", ret
);
1705 ok(!lstrcmpA(appdata
, testpath
), "expected %s, got %s\n", appdata
, testpath
);
1708 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, "\\", testpath
);
1709 ok(S_OK
== ret
, "expected S_OK, got %x\n", ret
);
1710 ok(!lstrcmpA(appdata
, testpath
), "expected %s, got %s\n", appdata
, testpath
);
1712 for(i
=0; i
< MAX_PATH
; i
++)
1713 toolongpath
[i
] = '0' + i
% 10;
1714 toolongpath
[MAX_PATH
] = '\0';
1715 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, toolongpath
, testpath
);
1716 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE
) == ret
,
1717 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE
), ret
);
1720 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, wine
, NULL
);
1721 ok((S_OK
== ret
) || (E_INVALIDARG
== ret
), "expected S_OK or E_INVALIDARG, got %x\n", ret
);
1723 /* test a not existing path */
1725 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, winetemp
, testpath
);
1726 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
) == ret
,
1727 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
), ret
);
1729 /* create a directory inside a not existing directory */
1731 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_CREATE
| CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, winetemp
, testpath
);
1732 ok(S_OK
== ret
, "expected S_OK, got %x\n", ret
);
1733 ok(!strncmp(appdata
, testpath
, strlen(appdata
)),
1734 "expected %s to start with %s\n", testpath
, appdata
);
1735 ok(!lstrcmpA(&testpath
[1 + strlen(appdata
)], winetemp
),
1736 "expected %s to end with %s\n", testpath
, winetemp
);
1737 dwret
= GetFileAttributes(testpath
);
1738 ok(FILE_ATTRIBUTE_DIRECTORY
| dwret
, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret
);
1741 sprintf(testpath
, "%s\\%s", appdata
, winetemp
);
1742 RemoveDirectoryA(testpath
);
1743 sprintf(testpath
, "%s\\%s", appdata
, wine
);
1744 RemoveDirectoryA(testpath
);
1747 static void test_LocalizedNames(void)
1749 static char cCurrDirA
[MAX_PATH
];
1750 WCHAR cCurrDirW
[MAX_PATH
], tempbufW
[25];
1751 IShellFolder
*IDesktopFolder
, *testIShellFolder
;
1752 ITEMIDLIST
*newPIDL
;
1755 static char resourcefile
[MAX_PATH
];
1760 static const char desktopini_contents1
[] =
1761 "[.ShellClassInfo]\r\n"
1762 "LocalizedResourceName=@";
1763 static const char desktopini_contents2
[] =
1765 static WCHAR foldernameW
[] = {'t','e','s','t','f','o','l','d','e','r',0};
1766 static const WCHAR folderdisplayW
[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1768 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1769 CreateDirectoryA(".\\testfolder", NULL
);
1771 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM
);
1773 GetModuleFileNameA(NULL
, resourcefile
, MAX_PATH
);
1775 file
= CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE
, 0, NULL
,
1776 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1777 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFileA failed %i\n", GetLastError());
1778 ok(WriteFile(file
, desktopini_contents1
, strlen(desktopini_contents1
), &res
, NULL
) &&
1779 WriteFile(file
, resourcefile
, strlen(resourcefile
), &res
, NULL
) &&
1780 WriteFile(file
, desktopini_contents2
, strlen(desktopini_contents2
), &res
, NULL
),
1781 "WriteFile failed %i\n", GetLastError());
1784 /* get IShellFolder for parent */
1785 GetCurrentDirectoryA(MAX_PATH
, cCurrDirA
);
1786 len
= lstrlenA(cCurrDirA
);
1789 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1792 if(cCurrDirA
[len
-1] == '\\')
1793 cCurrDirA
[len
-1] = 0;
1795 MultiByteToWideChar(CP_ACP
, 0, cCurrDirA
, -1, cCurrDirW
, MAX_PATH
);
1797 hr
= SHGetDesktopFolder(&IDesktopFolder
);
1798 ok(hr
== S_OK
, "SHGetDesktopfolder failed %08x\n", hr
);
1800 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
, NULL
, NULL
, cCurrDirW
, NULL
, &newPIDL
, 0);
1801 ok(hr
== S_OK
, "ParseDisplayName failed %08x\n", hr
);
1803 hr
= IShellFolder_BindToObject(IDesktopFolder
, newPIDL
, NULL
, (REFIID
)&IID_IShellFolder
, (LPVOID
*)&testIShellFolder
);
1804 ok(hr
== S_OK
, "BindToObject failed %08x\n", hr
);
1806 IMalloc_Free(ppM
, newPIDL
);
1808 /* windows reads the display name from the resource */
1809 hr
= IShellFolder_ParseDisplayName(testIShellFolder
, NULL
, NULL
, foldernameW
, NULL
, &newPIDL
, 0);
1810 ok(hr
== S_OK
, "ParseDisplayName failed %08x\n", hr
);
1812 hr
= IShellFolder_GetDisplayNameOf(testIShellFolder
, newPIDL
, SHGDN_INFOLDER
, &strret
);
1813 ok(hr
== S_OK
, "GetDisplayNameOf failed %08x\n", hr
);
1815 if (hr
== S_OK
&& pStrRetToBufW
)
1817 hr
= pStrRetToBufW(&strret
, newPIDL
, tempbufW
, sizeof(tempbufW
)/sizeof(WCHAR
));
1818 ok (hr
== S_OK
, "StrRetToBufW failed! hr = %08x\n", hr
);
1820 ok (!lstrcmpiW(tempbufW
, folderdisplayW
) ||
1821 broken(!lstrcmpiW(tempbufW
, foldernameW
)), /* W2K */
1822 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW
));
1825 /* editing name is also read from the resource */
1826 hr
= IShellFolder_GetDisplayNameOf(testIShellFolder
, newPIDL
, SHGDN_INFOLDER
|SHGDN_FOREDITING
, &strret
);
1827 ok(hr
== S_OK
, "GetDisplayNameOf failed %08x\n", hr
);
1829 if (hr
== S_OK
&& pStrRetToBufW
)
1831 hr
= pStrRetToBufW(&strret
, newPIDL
, tempbufW
, sizeof(tempbufW
)/sizeof(WCHAR
));
1832 ok (hr
== S_OK
, "StrRetToBufW failed! hr = %08x\n", hr
);
1834 ok (!lstrcmpiW(tempbufW
, folderdisplayW
) ||
1835 broken(!lstrcmpiW(tempbufW
, foldernameW
)), /* W2K */
1836 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW
));
1839 /* parsing name is unchanged */
1840 hr
= IShellFolder_GetDisplayNameOf(testIShellFolder
, newPIDL
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, &strret
);
1841 ok(hr
== S_OK
, "GetDisplayNameOf failed %08x\n", hr
);
1843 if (hr
== S_OK
&& pStrRetToBufW
)
1845 hr
= pStrRetToBufW(&strret
, newPIDL
, tempbufW
, sizeof(tempbufW
)/sizeof(WCHAR
));
1846 ok (hr
== S_OK
, "StrRetToBufW failed! hr = %08x\n", hr
);
1847 ok (!lstrcmpiW(tempbufW
, foldernameW
), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW
));
1850 IShellFolder_Release(IDesktopFolder
);
1851 IShellFolder_Release(testIShellFolder
);
1853 IMalloc_Free(ppM
, newPIDL
);
1856 DeleteFileA(".\\testfolder\\desktop.ini");
1857 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM
);
1858 RemoveDirectoryA(".\\testfolder");
1861 static void test_SHCreateShellItem(void)
1863 IShellItem
*shellitem
, *shellitem2
;
1864 IPersistIDList
*persistidl
;
1865 LPITEMIDLIST pidl_cwd
=NULL
, pidl_testfile
, pidl_abstestfile
, pidl_test
;
1867 char curdirA
[MAX_PATH
];
1868 WCHAR curdirW
[MAX_PATH
];
1869 IShellFolder
*desktopfolder
=NULL
, *currentfolder
=NULL
;
1870 static WCHAR testfileW
[] = {'t','e','s','t','f','i','l','e',0};
1872 GetCurrentDirectoryA(MAX_PATH
, curdirA
);
1874 if (!pSHCreateShellItem
)
1876 win_skip("SHCreateShellItem isn't available\n");
1880 if (!lstrlenA(curdirA
))
1882 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
1886 MultiByteToWideChar(CP_ACP
, 0, curdirA
, -1, curdirW
, MAX_PATH
);
1888 ret
= SHGetDesktopFolder(&desktopfolder
);
1889 ok(SUCCEEDED(ret
), "SHGetShellFolder returned %x\n", ret
);
1891 ret
= IShellFolder_ParseDisplayName(desktopfolder
, NULL
, NULL
, curdirW
, NULL
, &pidl_cwd
, NULL
);
1892 ok(SUCCEEDED(ret
), "ParseDisplayName returned %x\n", ret
);
1894 ret
= IShellFolder_BindToObject(desktopfolder
, pidl_cwd
, NULL
, &IID_IShellFolder
, (void**)¤tfolder
);
1895 ok(SUCCEEDED(ret
), "BindToObject returned %x\n", ret
);
1897 CreateTestFile(".\\testfile");
1899 ret
= IShellFolder_ParseDisplayName(currentfolder
, NULL
, NULL
, testfileW
, NULL
, &pidl_testfile
, NULL
);
1900 ok(SUCCEEDED(ret
), "ParseDisplayName returned %x\n", ret
);
1902 pidl_abstestfile
= pILCombine(pidl_cwd
, pidl_testfile
);
1904 ret
= pSHCreateShellItem(NULL
, NULL
, NULL
, &shellitem
);
1905 ok(ret
== E_INVALIDARG
, "SHCreateShellItem returned %x\n", ret
);
1907 if (0) /* crashes on Windows XP */
1909 pSHCreateShellItem(NULL
, NULL
, pidl_cwd
, NULL
);
1910 pSHCreateShellItem(pidl_cwd
, NULL
, NULL
, &shellitem
);
1911 pSHCreateShellItem(NULL
, currentfolder
, NULL
, &shellitem
);
1912 pSHCreateShellItem(pidl_cwd
, currentfolder
, NULL
, &shellitem
);
1915 ret
= pSHCreateShellItem(NULL
, NULL
, pidl_cwd
, &shellitem
);
1916 ok(SUCCEEDED(ret
), "SHCreateShellItem returned %x\n", ret
);
1919 ret
= IShellItem_QueryInterface(shellitem
, &IID_IPersistIDList
, (void**)&persistidl
);
1920 ok(SUCCEEDED(ret
), "QueryInterface returned %x\n", ret
);
1923 ret
= IPersistIDList_GetIDList(persistidl
, &pidl_test
);
1924 ok(SUCCEEDED(ret
), "GetIDList returned %x\n", ret
);
1927 ok(ILIsEqual(pidl_cwd
, pidl_test
), "id lists are not equal\n");
1930 IPersistIDList_Release(persistidl
);
1932 IShellItem_Release(shellitem
);
1935 ret
= pSHCreateShellItem(pidl_cwd
, NULL
, pidl_testfile
, &shellitem
);
1936 ok(SUCCEEDED(ret
), "SHCreateShellItem returned %x\n", ret
);
1939 ret
= IShellItem_QueryInterface(shellitem
, &IID_IPersistIDList
, (void**)&persistidl
);
1940 ok(SUCCEEDED(ret
), "QueryInterface returned %x\n", ret
);
1943 ret
= IPersistIDList_GetIDList(persistidl
, &pidl_test
);
1944 ok(SUCCEEDED(ret
), "GetIDList returned %x\n", ret
);
1947 ok(ILIsEqual(pidl_abstestfile
, pidl_test
), "id lists are not equal\n");
1950 IPersistIDList_Release(persistidl
);
1953 ret
= IShellItem_GetParent(shellitem
, &shellitem2
);
1954 ok(SUCCEEDED(ret
), "GetParent returned %x\n", ret
);
1957 ret
= IShellItem_QueryInterface(shellitem2
, &IID_IPersistIDList
, (void**)&persistidl
);
1958 ok(SUCCEEDED(ret
), "QueryInterface returned %x\n", ret
);
1961 ret
= IPersistIDList_GetIDList(persistidl
, &pidl_test
);
1962 ok(SUCCEEDED(ret
), "GetIDList returned %x\n", ret
);
1965 ok(ILIsEqual(pidl_cwd
, pidl_test
), "id lists are not equal\n");
1968 IPersistIDList_Release(persistidl
);
1970 IShellItem_Release(shellitem2
);
1973 IShellItem_Release(shellitem
);
1976 ret
= pSHCreateShellItem(NULL
, currentfolder
, pidl_testfile
, &shellitem
);
1977 ok(SUCCEEDED(ret
), "SHCreateShellItem returned %x\n", ret
);
1980 ret
= IShellItem_QueryInterface(shellitem
, &IID_IPersistIDList
, (void**)&persistidl
);
1981 ok(SUCCEEDED(ret
), "QueryInterface returned %x\n", ret
);
1984 ret
= IPersistIDList_GetIDList(persistidl
, &pidl_test
);
1985 ok(SUCCEEDED(ret
), "GetIDList returned %x\n", ret
);
1988 ok(ILIsEqual(pidl_abstestfile
, pidl_test
), "id lists are not equal\n");
1991 IPersistIDList_Release(persistidl
);
1993 IShellItem_Release(shellitem
);
1996 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
1997 ret
= pSHCreateShellItem(pidl_cwd
, desktopfolder
, pidl_testfile
, &shellitem
);
1998 ok(SUCCEEDED(ret
), "SHCreateShellItem returned %x\n", ret
);
2001 ret
= IShellItem_QueryInterface(shellitem
, &IID_IPersistIDList
, (void**)&persistidl
);
2002 ok(SUCCEEDED(ret
), "QueryInterface returned %x\n", ret
);
2005 ret
= IPersistIDList_GetIDList(persistidl
, &pidl_test
);
2006 ok(SUCCEEDED(ret
), "GetIDList returned %x\n", ret
);
2009 ok(ILIsEqual(pidl_abstestfile
, pidl_test
), "id lists are not equal\n");
2012 IPersistIDList_Release(persistidl
);
2014 IShellItem_Release(shellitem
);
2017 DeleteFileA(".\\testfile");
2018 pILFree(pidl_abstestfile
);
2019 pILFree(pidl_testfile
);
2021 IShellFolder_Release(currentfolder
);
2022 IShellFolder_Release(desktopfolder
);
2025 static void test_SHParseDisplayName(void)
2027 LPITEMIDLIST pidl1
, pidl2
;
2028 IShellFolder
*desktop
;
2029 WCHAR dirW
[MAX_PATH
];
2034 if (!pSHParseDisplayName
)
2036 win_skip("SHParseDisplayName isn't available\n");
2042 /* crashes on native */
2043 hr
= pSHParseDisplayName(NULL
, NULL
, NULL
, 0, NULL
);
2045 hr
= pSHParseDisplayName(nameW
, NULL
, NULL
, 0, NULL
);
2048 pidl1
= (LPITEMIDLIST
)0xdeadbeef;
2049 hr
= pSHParseDisplayName(NULL
, NULL
, &pidl1
, 0, NULL
);
2050 ok(broken(hr
== E_OUTOFMEMORY
) /* < Vista */ ||
2051 hr
== E_INVALIDARG
, "failed %08x\n", hr
);
2052 ok(pidl1
== 0, "expected null ptr, got %p\n", pidl1
);
2056 hr
= pSHParseDisplayName(nameW
, NULL
, &pidl1
, 0, NULL
);
2057 ok(hr
== S_OK
, "failed %08x\n", hr
);
2058 hr
= SHGetDesktopFolder(&desktop
);
2059 ok(hr
== S_OK
, "failed %08x\n", hr
);
2060 hr
= IShellFolder_ParseDisplayName(desktop
, NULL
, NULL
, nameW
, NULL
, &pidl2
, NULL
);
2061 ok(hr
== S_OK
, "failed %08x\n", hr
);
2062 ret
= pILIsEqual(pidl1
, pidl2
);
2063 ok(ret
== TRUE
, "expected equal idls\n");
2068 GetWindowsDirectoryW( dirW
, MAX_PATH
);
2070 hr
= pSHParseDisplayName(dirW
, NULL
, &pidl1
, 0, NULL
);
2071 ok(hr
== S_OK
, "failed %08x\n", hr
);
2072 hr
= IShellFolder_ParseDisplayName(desktop
, NULL
, NULL
, dirW
, NULL
, &pidl2
, NULL
);
2073 ok(hr
== S_OK
, "failed %08x\n", hr
);
2075 ret
= pILIsEqual(pidl1
, pidl2
);
2076 ok(ret
== TRUE
, "expected equal idls\n");
2080 IShellFolder_Release(desktop
);
2083 static void test_desktop_IPersist(void)
2085 IShellFolder
*desktop
;
2090 hr
= SHGetDesktopFolder(&desktop
);
2091 ok(hr
== S_OK
, "failed %08x\n", hr
);
2093 hr
= IShellFolder_QueryInterface(desktop
, &IID_IPersist
, (void**)&persist
);
2094 ok(hr
== S_OK
|| broken(hr
== E_NOINTERFACE
) /* NT4, W9X */, "failed %08x\n", hr
);
2100 /* crashes on native */
2101 hr
= IPersist_GetClassID(persist
, NULL
);
2103 memset(&clsid
, 0, sizeof(clsid
));
2104 hr
= IPersist_GetClassID(persist
, &clsid
);
2105 ok(hr
== S_OK
, "failed %08x\n", hr
);
2106 ok(IsEqualIID(&CLSID_ShellDesktop
, &clsid
), "Expected CLSID_ShellDesktop\n");
2107 IPersist_Release(persist
);
2110 IShellFolder_Release(desktop
);
2113 START_TEST(shlfolder
)
2115 init_function_pointers();
2116 /* if OleInitialize doesn't get called, ParseDisplayName returns
2117 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
2118 OleInitialize(NULL
);
2120 test_ParseDisplayName();
2121 test_SHParseDisplayName();
2122 test_BindToObject();
2123 test_EnumObjects_and_CompareIDs();
2124 test_GetDisplayName();
2125 test_GetAttributesOf();
2126 test_SHGetPathFromIDList();
2127 test_CallForAttributes();
2128 test_FolderShortcut();
2129 test_ITEMIDLIST_format();
2130 test_SHGetFolderPathAndSubDirA();
2131 test_LocalizedNames();
2132 test_SHCreateShellItem();
2133 test_desktop_IPersist();