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
);
59 static void init_function_pointers(void)
64 hmod
= GetModuleHandleA("shell32.dll");
65 pSHBindToParent
= (void*)GetProcAddress(hmod
, "SHBindToParent");
66 pSHGetFolderPathA
= (void*)GetProcAddress(hmod
, "SHGetFolderPathA");
67 pSHGetFolderPathAndSubDirA
= (void*)GetProcAddress(hmod
, "SHGetFolderPathAndSubDirA");
68 pSHGetPathFromIDListW
= (void*)GetProcAddress(hmod
, "SHGetPathFromIDListW");
69 pSHGetSpecialFolderPathA
= (void*)GetProcAddress(hmod
, "SHGetSpecialFolderPathA");
70 pSHGetSpecialFolderPathW
= (void*)GetProcAddress(hmod
, "SHGetSpecialFolderPathW");
71 pILFindLastID
= (void *)GetProcAddress(hmod
, (LPCSTR
)16);
72 pILFree
= (void*)GetProcAddress(hmod
, (LPSTR
)155);
73 pILIsEqual
= (void*)GetProcAddress(hmod
, (LPSTR
)21);
74 pSHCreateShellItem
= (void*)GetProcAddress(hmod
, "SHCreateShellItem");
75 pILCombine
= (void*)GetProcAddress(hmod
, (LPSTR
)25);
77 hmod
= GetModuleHandleA("shlwapi.dll");
78 pStrRetToBufW
= (void*)GetProcAddress(hmod
, "StrRetToBufW");
80 hr
= SHGetMalloc(&ppM
);
81 ok(hr
== S_OK
, "SHGetMalloc failed %08x\n", hr
);
84 static void test_ParseDisplayName(void)
87 IShellFolder
*IDesktopFolder
;
88 static const char *cNonExistDir1A
= "c:\\nonexist_subdir";
89 static const char *cNonExistDir2A
= "c:\\\\nonexist_subdir";
90 static const char *cInetTestA
= "http:\\yyy";
91 static const char *cInetTest2A
= "xx:yyy";
93 WCHAR cTestDirW
[MAX_PATH
] = {0};
97 hr
= SHGetDesktopFolder(&IDesktopFolder
);
98 if(hr
!= S_OK
) return;
100 MultiByteToWideChar(CP_ACP
, 0, cInetTestA
, -1, cTestDirW
, MAX_PATH
);
101 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
,
102 NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
103 todo_wine
ok((SUCCEEDED(hr
) || broken(hr
== E_FAIL
) /* NT4 */),
104 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr
);
107 ok(pILFindLastID(newPIDL
)->mkid
.abID
[0] == 0x61, "Last pidl should be of type "
108 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL
)->mkid
.abID
[0]);
109 IMalloc_Free(ppM
, newPIDL
);
112 MultiByteToWideChar(CP_ACP
, 0, cInetTest2A
, -1, cTestDirW
, MAX_PATH
);
113 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
,
114 NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
115 todo_wine
ok((SUCCEEDED(hr
) || broken(hr
== E_FAIL
) /* NT4 */),
116 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr
);
119 ok(pILFindLastID(newPIDL
)->mkid
.abID
[0] == 0x61, "Last pidl should be of type "
120 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL
)->mkid
.abID
[0]);
121 IMalloc_Free(ppM
, newPIDL
);
124 res
= GetFileAttributesA(cNonExistDir1A
);
125 if(res
!= INVALID_FILE_ATTRIBUTES
) return;
127 MultiByteToWideChar(CP_ACP
, 0, cNonExistDir1A
, -1, cTestDirW
, MAX_PATH
);
128 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
,
129 NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
130 ok((hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
)) || (hr
== E_FAIL
),
131 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr
);
133 res
= GetFileAttributesA(cNonExistDir2A
);
134 if(res
!= INVALID_FILE_ATTRIBUTES
) return;
136 MultiByteToWideChar(CP_ACP
, 0, cNonExistDir2A
, -1, cTestDirW
, MAX_PATH
);
137 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
,
138 NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
139 ok((hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
)) || (hr
== E_FAIL
) || (hr
== E_INVALIDARG
),
140 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr
);
142 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
143 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
144 * out it doesn't. The magic seems to happen in the file dialogs, then. */
145 if (!pSHGetSpecialFolderPathW
|| !pILFindLastID
) goto finished
;
147 bRes
= pSHGetSpecialFolderPathW(NULL
, cTestDirW
, CSIDL_PERSONAL
, FALSE
);
148 ok(bRes
, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
149 if (!bRes
) goto finished
;
151 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
, NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
152 ok(SUCCEEDED(hr
), "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr
);
153 if (FAILED(hr
)) goto finished
;
155 ok(pILFindLastID(newPIDL
)->mkid
.abID
[0] == 0x31 ||
156 pILFindLastID(newPIDL
)->mkid
.abID
[0] == 0xb1, /* Win98 */
157 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
158 pILFindLastID(newPIDL
)->mkid
.abID
[0]);
159 IMalloc_Free(ppM
, newPIDL
);
162 IShellFolder_Release(IDesktopFolder
);
165 /* creates a file with the specified name for tests */
166 static void CreateTestFile(const CHAR
*name
)
171 file
= CreateFileA(name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
172 if (file
!= INVALID_HANDLE_VALUE
)
174 WriteFile(file
, name
, strlen(name
), &written
, NULL
);
175 WriteFile(file
, "\n", strlen("\n"), &written
, NULL
);
181 /* initializes the tests */
182 static void CreateFilesFolders(void)
184 CreateDirectoryA(".\\testdir", NULL
);
185 CreateDirectoryA(".\\testdir\\test.txt", NULL
);
186 CreateTestFile (".\\testdir\\test1.txt ");
187 CreateTestFile (".\\testdir\\test2.txt ");
188 CreateTestFile (".\\testdir\\test3.txt ");
189 CreateDirectoryA(".\\testdir\\testdir2 ", NULL
);
190 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL
);
193 /* cleans after tests */
194 static void Cleanup(void)
196 DeleteFileA(".\\testdir\\test1.txt");
197 DeleteFileA(".\\testdir\\test2.txt");
198 DeleteFileA(".\\testdir\\test3.txt");
199 RemoveDirectoryA(".\\testdir\\test.txt");
200 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
201 RemoveDirectoryA(".\\testdir\\testdir2");
202 RemoveDirectoryA(".\\testdir");
207 static void test_EnumObjects(IShellFolder
*iFolder
)
209 IEnumIDList
*iEnumList
;
210 LPITEMIDLIST newPIDL
, idlArr
[10];
215 static const WORD iResults
[5][5] =
224 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
225 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
226 static const ULONG attrs
[5] =
228 SFGAO_CAPABILITYMASK
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
| SFGAO_FILESYSANCESTOR
,
229 SFGAO_CAPABILITYMASK
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
| SFGAO_FILESYSANCESTOR
,
230 SFGAO_CAPABILITYMASK
| SFGAO_FILESYSTEM
,
231 SFGAO_CAPABILITYMASK
| SFGAO_FILESYSTEM
,
232 SFGAO_CAPABILITYMASK
| SFGAO_FILESYSTEM
,
235 hr
= IShellFolder_EnumObjects(iFolder
, NULL
, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
| SHCONTF_INCLUDEHIDDEN
, &iEnumList
);
236 ok(hr
== S_OK
, "EnumObjects failed %08x\n", hr
);
238 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
239 * the filesystem shellfolders return S_OK even if less than 'celt' items are
240 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
241 * only ever returns a single entry per call. */
242 while (IEnumIDList_Next(iEnumList
, 10-i
, &idlArr
[i
], &NumPIDLs
) == S_OK
)
244 ok (i
== 5, "i: %d\n", i
);
246 hr
= IEnumIDList_Release(iEnumList
);
247 ok(hr
== S_OK
, "IEnumIDList_Release failed %08x\n", hr
);
249 /* Sort them first in case of wrong order from system */
250 for (i
=0;i
<5;i
++) for (j
=0;j
<5;j
++)
251 if ((SHORT
)IShellFolder_CompareIDs(iFolder
, 0, idlArr
[i
], idlArr
[j
]) < 0)
254 idlArr
[i
] = idlArr
[j
];
258 for (i
=0;i
<5;i
++) for (j
=0;j
<5;j
++)
260 hr
= IShellFolder_CompareIDs(iFolder
, 0, idlArr
[i
], idlArr
[j
]);
261 ok(hr
== iResults
[i
][j
], "Got %x expected [%d]-[%d]=%x\n", hr
, i
, j
, iResults
[i
][j
]);
265 for (i
= 0; i
< 5; i
++)
268 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
269 /* Native returns all flags no matter what we ask for */
270 flags
= SFGAO_CANCOPY
;
271 hr
= IShellFolder_GetAttributesOf(iFolder
, 1, (LPCITEMIDLIST
*)(idlArr
+ i
), &flags
);
272 flags
&= SFGAO_testfor
;
273 ok(hr
== S_OK
, "GetAttributesOf returns %08x\n", hr
);
274 ok(flags
== (attrs
[i
]) ||
275 flags
== (attrs
[i
] & ~SFGAO_FILESYSANCESTOR
) || /* Win9x, NT4 */
276 flags
== ((attrs
[i
] & ~SFGAO_CAPABILITYMASK
) | SFGAO_VISTA
), /* Vista and higher */
277 "GetAttributesOf[%i] got %08x, expected %08x\n", i
, flags
, attrs
[i
]);
279 flags
= SFGAO_testfor
;
280 hr
= IShellFolder_GetAttributesOf(iFolder
, 1, (LPCITEMIDLIST
*)(idlArr
+ i
), &flags
);
281 flags
&= SFGAO_testfor
;
282 ok(hr
== S_OK
, "GetAttributesOf returns %08x\n", hr
);
283 ok(flags
== attrs
[i
] ||
284 flags
== (attrs
[i
] & ~SFGAO_FILESYSANCESTOR
), /* Win9x, NT4 */
285 "GetAttributesOf[%i] got %08x, expected %08x\n", i
, flags
, attrs
[i
]);
289 IMalloc_Free(ppM
, idlArr
[i
]);
292 static void test_BindToObject(void)
296 IShellFolder
*psfDesktop
, *psfChild
, *psfMyComputer
, *psfSystemDir
;
297 SHITEMID emptyitem
= { 0, { 0 } };
298 LPITEMIDLIST pidlMyComputer
, pidlSystemDir
, pidlEmpty
= (LPITEMIDLIST
)&emptyitem
;
299 WCHAR wszSystemDir
[MAX_PATH
];
300 char szSystemDir
[MAX_PATH
];
301 WCHAR wszMyComputer
[] = {
302 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
303 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
305 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
306 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
308 hr
= SHGetDesktopFolder(&psfDesktop
);
309 ok (SUCCEEDED(hr
), "SHGetDesktopFolder failed! hr = %08x\n", hr
);
310 if (FAILED(hr
)) return;
312 hr
= IShellFolder_BindToObject(psfDesktop
, pidlEmpty
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfChild
);
313 ok (hr
== E_INVALIDARG
, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr
);
315 hr
= IShellFolder_BindToObject(psfDesktop
, NULL
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfChild
);
316 ok (hr
== E_INVALIDARG
, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr
);
318 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszMyComputer
, NULL
, &pidlMyComputer
, NULL
);
319 ok (SUCCEEDED(hr
), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr
);
321 IShellFolder_Release(psfDesktop
);
325 hr
= IShellFolder_BindToObject(psfDesktop
, pidlMyComputer
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfMyComputer
);
326 ok (SUCCEEDED(hr
), "Desktop failed to bind to MyComputer object! hr = %08x\n", hr
);
327 IShellFolder_Release(psfDesktop
);
328 IMalloc_Free(ppM
, pidlMyComputer
);
329 if (FAILED(hr
)) return;
331 hr
= IShellFolder_BindToObject(psfMyComputer
, pidlEmpty
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfChild
);
332 ok (hr
== E_INVALIDARG
, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr
);
335 /* this call segfaults on 98SE */
336 hr
= IShellFolder_BindToObject(psfMyComputer
, NULL
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfChild
);
337 ok (hr
== E_INVALIDARG
, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr
);
340 cChars
= GetSystemDirectoryA(szSystemDir
, MAX_PATH
);
341 ok (cChars
> 0 && cChars
< MAX_PATH
, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
342 if (cChars
== 0 || cChars
>= MAX_PATH
) {
343 IShellFolder_Release(psfMyComputer
);
346 MultiByteToWideChar(CP_ACP
, 0, szSystemDir
, -1, wszSystemDir
, MAX_PATH
);
348 hr
= IShellFolder_ParseDisplayName(psfMyComputer
, NULL
, NULL
, wszSystemDir
, NULL
, &pidlSystemDir
, NULL
);
349 ok (SUCCEEDED(hr
), "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr
);
351 IShellFolder_Release(psfMyComputer
);
355 hr
= IShellFolder_BindToObject(psfMyComputer
, pidlSystemDir
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfSystemDir
);
356 ok (SUCCEEDED(hr
), "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr
);
357 IShellFolder_Release(psfMyComputer
);
358 IMalloc_Free(ppM
, pidlSystemDir
);
359 if (FAILED(hr
)) return;
361 hr
= IShellFolder_BindToObject(psfSystemDir
, pidlEmpty
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfChild
);
362 ok (hr
== E_INVALIDARG
,
363 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr
);
366 /* this call segfaults on 98SE */
367 hr
= IShellFolder_BindToObject(psfSystemDir
, NULL
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfChild
);
368 ok (hr
== E_INVALIDARG
,
369 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr
);
372 IShellFolder_Release(psfSystemDir
);
375 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
376 static LPWSTR
myPathAddBackslashW( LPWSTR lpszPath
)
380 if (!lpszPath
|| (iLen
= lstrlenW(lpszPath
)) >= MAX_PATH
)
386 if (lpszPath
[-1] != '\\')
395 static void test_GetDisplayName(void)
400 WCHAR wszTestFile
[MAX_PATH
], wszTestFile2
[MAX_PATH
];
401 char szTestFile
[MAX_PATH
], szTestDir
[MAX_PATH
];
404 LPSHELLFOLDER psfDesktop
, psfPersonal
;
406 SHITEMID emptyitem
= { 0, { 0 } };
407 LPITEMIDLIST pidlTestFile
, pidlEmpty
= (LPITEMIDLIST
)&emptyitem
;
408 LPCITEMIDLIST pidlLast
;
409 static const CHAR szFileName
[] = "winetest.foo";
410 static const WCHAR wszFileName
[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
411 static const WCHAR wszDirName
[] = { 'w','i','n','e','t','e','s','t',0 };
413 /* I'm trying to figure if there is a functional difference between calling
414 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
415 * binding to the shellfolder. One thing I thought of was that perhaps
416 * SHGetPathFromIDListW would be able to get the path to a file, which does
417 * not exist anymore, while the other method wouldn't. It turns out there's
418 * no functional difference in this respect.
421 if(!pSHGetSpecialFolderPathA
) {
422 win_skip("SHGetSpecialFolderPathA is not available\n");
426 /* First creating a directory in MyDocuments and a file in this directory. */
427 result
= pSHGetSpecialFolderPathA(NULL
, szTestDir
, CSIDL_PERSONAL
, FALSE
);
428 ok(result
, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
431 /* Use ANSI file functions so this works on Windows 9x */
432 lstrcatA(szTestDir
, "\\winetest");
433 CreateDirectoryA(szTestDir
, NULL
);
434 attr
=GetFileAttributesA(szTestDir
);
435 if (attr
== INVALID_FILE_ATTRIBUTES
|| !(attr
& FILE_ATTRIBUTE_DIRECTORY
))
437 ok(0, "unable to create the '%s' directory\n", szTestDir
);
441 lstrcpyA(szTestFile
, szTestDir
);
442 lstrcatA(szTestFile
, "\\");
443 lstrcatA(szTestFile
, szFileName
);
444 hTestFile
= CreateFileA(szTestFile
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
445 ok((hTestFile
!= INVALID_HANDLE_VALUE
), "CreateFileA failed! Last error: %u\n", GetLastError());
446 if (hTestFile
== INVALID_HANDLE_VALUE
) return;
447 CloseHandle(hTestFile
);
449 /* Getting an itemidlist for the file. */
450 hr
= SHGetDesktopFolder(&psfDesktop
);
451 ok(SUCCEEDED(hr
), "SHGetDesktopFolder failed! hr = %08x\n", hr
);
452 if (FAILED(hr
)) return;
454 MultiByteToWideChar(CP_ACP
, 0, szTestFile
, -1, wszTestFile
, MAX_PATH
);
456 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszTestFile
, NULL
, &pidlTestFile
, NULL
);
457 ok(SUCCEEDED(hr
), "Desktop->ParseDisplayName failed! hr = %08x\n", hr
);
459 IShellFolder_Release(psfDesktop
);
463 pidlLast
= pILFindLastID(pidlTestFile
);
464 ok(pidlLast
->mkid
.cb
>=76 ||
465 broken(pidlLast
->mkid
.cb
== 28) || /* W2K */
466 broken(pidlLast
->mkid
.cb
== 40), /* Win9x, WinME */
467 "Expected pidl length of at least 76, got %d.\n", pidlLast
->mkid
.cb
);
468 if (pidlLast
->mkid
.cb
>= 28) {
469 ok(!lstrcmpA((CHAR
*)&pidlLast
->mkid
.abID
[12], szFileName
),
470 "Filename should be stored as ansi-string at this position!\n");
472 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
473 if (pidlLast
->mkid
.cb
>= 76) {
474 ok(!lstrcmpW((WCHAR
*)&pidlLast
->mkid
.abID
[46], wszFileName
) ||
475 (pidlLast
->mkid
.cb
>= 94 && !lstrcmpW((WCHAR
*)&pidlLast
->mkid
.abID
[64], wszFileName
)) || /* Vista */
476 (pidlLast
->mkid
.cb
>= 98 && !lstrcmpW((WCHAR
*)&pidlLast
->mkid
.abID
[68], wszFileName
)), /* Win7 */
477 "Filename should be stored as wchar-string at this position!\n");
480 /* It seems as if we cannot bind to regular files on windows, but only directories.
482 hr
= IShellFolder_BindToObject(psfDesktop
, pidlTestFile
, NULL
, &IID_IUnknown
, (VOID
**)&psfFile
);
484 ok (hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
) ||
485 hr
== E_NOTIMPL
|| /* Vista */
486 broken(SUCCEEDED(hr
)), /* Win9x, W2K */
489 IShellFolder_Release(psfFile
);
492 if (!pSHBindToParent
)
494 win_skip("SHBindToParent is missing\n");
495 DeleteFileA(szTestFile
);
496 RemoveDirectoryA(szTestDir
);
500 /* Some tests for IShellFolder::SetNameOf */
501 if (pSHGetFolderPathAndSubDirA
)
503 hr
= pSHBindToParent(pidlTestFile
, &IID_IShellFolder
, (VOID
**)&psfPersonal
, &pidlLast
);
504 ok(SUCCEEDED(hr
), "SHBindToParent failed! hr = %08x\n", hr
);
506 /* It's ok to use this fixed path. Call will fail anyway. */
507 WCHAR wszAbsoluteFilename
[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
508 LPITEMIDLIST pidlNew
;
510 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
511 hr
= IShellFolder_SetNameOf(psfPersonal
, NULL
, pidlLast
, wszDirName
, SHGDN_NORMAL
, &pidlNew
);
512 ok (SUCCEEDED(hr
), "SetNameOf failed! hr = %08x\n", hr
);
515 ok (((LPITEMIDLIST
)((LPBYTE
)pidlNew
+pidlNew
->mkid
.cb
))->mkid
.cb
== 0,
516 "pidl returned from SetNameOf should be simple!\n");
518 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
519 * is implemented on top of SHFileOperation in WinXP. */
520 hr
= IShellFolder_SetNameOf(psfPersonal
, NULL
, pidlNew
, wszAbsoluteFilename
,
521 SHGDN_FORPARSING
, NULL
);
522 ok (hr
== HRESULT_FROM_WIN32(ERROR_CANCELLED
), "SetNameOf succeeded! hr = %08x\n", hr
);
524 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
525 * SHGDN flags specify an absolute path. */
526 hr
= IShellFolder_SetNameOf(psfPersonal
, NULL
, pidlNew
, wszFileName
, SHGDN_FORPARSING
, NULL
);
527 ok (SUCCEEDED(hr
), "SetNameOf failed! hr = %08x\n", hr
);
532 IShellFolder_Release(psfPersonal
);
536 win_skip("Avoid needs of interaction on Win2k\n");
538 /* Deleting the file and the directory */
539 DeleteFileA(szTestFile
);
540 RemoveDirectoryA(szTestDir
);
542 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
543 if (pSHGetPathFromIDListW
)
545 result
= pSHGetPathFromIDListW(pidlTestFile
, wszTestFile2
);
546 ok (result
, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
547 ok (!lstrcmpiW(wszTestFile
, wszTestFile2
), "SHGetPathFromIDListW returns incorrect path!\n");
550 /* SHBindToParent fails, if called with a NULL PIDL. */
551 hr
= pSHBindToParent(NULL
, &IID_IShellFolder
, (VOID
**)&psfPersonal
, &pidlLast
);
552 ok (FAILED(hr
), "SHBindToParent(NULL) should fail!\n");
554 /* But it succeeds with an empty PIDL. */
555 hr
= pSHBindToParent(pidlEmpty
, &IID_IShellFolder
, (VOID
**)&psfPersonal
, &pidlLast
);
556 ok (SUCCEEDED(hr
), "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr
);
557 ok (pidlLast
== pidlEmpty
, "The last element of an empty PIDL should be the PIDL itself!\n");
559 IShellFolder_Release(psfPersonal
);
561 /* Binding to the folder and querying the display name of the file also works. */
562 hr
= pSHBindToParent(pidlTestFile
, &IID_IShellFolder
, (VOID
**)&psfPersonal
, &pidlLast
);
563 ok (SUCCEEDED(hr
), "SHBindToParent failed! hr = %08x\n", hr
);
565 IShellFolder_Release(psfDesktop
);
569 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
570 * pidlTestFile (In accordance with MSDN). */
571 ok (pILFindLastID(pidlTestFile
) == pidlLast
,
572 "SHBindToParent doesn't return the last id of the pidl param!\n");
574 hr
= IShellFolder_GetDisplayNameOf(psfPersonal
, pidlLast
, SHGDN_FORPARSING
, &strret
);
575 ok (SUCCEEDED(hr
), "Personal->GetDisplayNameOf failed! hr = %08x\n", hr
);
577 IShellFolder_Release(psfDesktop
);
578 IShellFolder_Release(psfPersonal
);
584 hr
= pStrRetToBufW(&strret
, pidlLast
, wszTestFile2
, MAX_PATH
);
585 ok (SUCCEEDED(hr
), "StrRetToBufW failed! hr = %08x\n", hr
);
586 ok (!lstrcmpiW(wszTestFile
, wszTestFile2
), "GetDisplayNameOf returns incorrect path!\n");
589 IShellFolder_Release(psfDesktop
);
590 IShellFolder_Release(psfPersonal
);
593 static void test_CallForAttributes(void)
599 LPSHELLFOLDER psfDesktop
;
600 LPITEMIDLIST pidlMyDocuments
;
601 DWORD dwAttributes
, dwCallForAttributes
, dwOrigAttributes
, dwOrigCallForAttributes
;
602 static const WCHAR wszAttributes
[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
603 static const WCHAR wszCallForAttributes
[] = {
604 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
605 static const WCHAR wszMyDocumentsKey
[] = {
606 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
607 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
608 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
609 WCHAR wszMyDocuments
[] = {
610 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
611 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
613 /* For the root of a namespace extension, the attributes are not queried by binding
614 * to the object and calling GetAttributesOf. Instead, the attributes are read from
615 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
617 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
618 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
619 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
620 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
622 hr
= SHGetDesktopFolder(&psfDesktop
);
623 ok (SUCCEEDED(hr
), "SHGetDesktopFolder failed! hr = %08x\n", hr
);
624 if (FAILED(hr
)) return;
626 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszMyDocuments
, NULL
,
627 &pidlMyDocuments
, NULL
);
629 broken(hr
== E_INVALIDARG
), /* Win95, NT4 */
630 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr
);
632 IShellFolder_Release(psfDesktop
);
636 dwAttributes
= 0xffffffff;
637 hr
= IShellFolder_GetAttributesOf(psfDesktop
, 1,
638 (LPCITEMIDLIST
*)&pidlMyDocuments
, &dwAttributes
);
639 ok (SUCCEEDED(hr
), "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr
);
641 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
642 ok (dwAttributes
& SFGAO_FILESYSTEM
, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
643 ok (!(dwAttributes
& SFGAO_ISSLOW
), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
644 ok (!(dwAttributes
& SFGAO_GHOSTED
), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
646 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
647 * key. So the test will return at this point, if run on wine.
649 lResult
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, wszMyDocumentsKey
, 0, KEY_WRITE
|KEY_READ
, &hKey
);
650 ok (lResult
== ERROR_SUCCESS
, "RegOpenKeyEx failed! result: %08x\n", lResult
);
651 if (lResult
!= ERROR_SUCCESS
) {
652 IMalloc_Free(ppM
, pidlMyDocuments
);
653 IShellFolder_Release(psfDesktop
);
657 /* Query MyDocuments' Attributes value, to be able to restore it later. */
658 dwSize
= sizeof(DWORD
);
659 lResult
= RegQueryValueExW(hKey
, wszAttributes
, NULL
, NULL
, (LPBYTE
)&dwOrigAttributes
, &dwSize
);
660 ok (lResult
== ERROR_SUCCESS
, "RegQueryValueEx failed! result: %08x\n", lResult
);
661 if (lResult
!= ERROR_SUCCESS
) {
663 IMalloc_Free(ppM
, pidlMyDocuments
);
664 IShellFolder_Release(psfDesktop
);
668 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
669 dwSize
= sizeof(DWORD
);
670 lResult
= RegQueryValueExW(hKey
, wszCallForAttributes
, NULL
, NULL
,
671 (LPBYTE
)&dwOrigCallForAttributes
, &dwSize
);
672 ok (lResult
== ERROR_SUCCESS
, "RegQueryValueEx failed! result: %08x\n", lResult
);
673 if (lResult
!= ERROR_SUCCESS
) {
675 IMalloc_Free(ppM
, pidlMyDocuments
);
676 IShellFolder_Release(psfDesktop
);
680 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
681 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
682 * SFGAO_FILESYSTEM attributes. */
683 dwAttributes
= SFGAO_ISSLOW
|SFGAO_GHOSTED
;
684 RegSetValueExW(hKey
, wszAttributes
, 0, REG_DWORD
, (LPBYTE
)&dwAttributes
, sizeof(DWORD
));
685 dwCallForAttributes
= SFGAO_ISSLOW
|SFGAO_FILESYSTEM
;
686 RegSetValueExW(hKey
, wszCallForAttributes
, 0, REG_DWORD
,
687 (LPBYTE
)&dwCallForAttributes
, sizeof(DWORD
));
689 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
690 * GetAttributesOf. It seems that once there is a single attribute queried, for which
691 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
692 * the flags in Attributes are ignored.
694 dwAttributes
= SFGAO_ISSLOW
|SFGAO_GHOSTED
|SFGAO_FILESYSTEM
;
695 hr
= IShellFolder_GetAttributesOf(psfDesktop
, 1,
696 (LPCITEMIDLIST
*)&pidlMyDocuments
, &dwAttributes
);
697 ok (SUCCEEDED(hr
), "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr
);
699 ok (dwAttributes
== SFGAO_FILESYSTEM
,
700 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
703 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
704 RegSetValueExW(hKey
, wszAttributes
, 0, REG_DWORD
, (LPBYTE
)&dwOrigAttributes
, sizeof(DWORD
));
705 RegSetValueExW(hKey
, wszCallForAttributes
, 0, REG_DWORD
,
706 (LPBYTE
)&dwOrigCallForAttributes
, sizeof(DWORD
));
708 IMalloc_Free(ppM
, pidlMyDocuments
);
709 IShellFolder_Release(psfDesktop
);
712 static void test_GetAttributesOf(void)
715 LPSHELLFOLDER psfDesktop
, psfMyComputer
;
716 SHITEMID emptyitem
= { 0, { 0 } };
717 LPCITEMIDLIST pidlEmpty
= (LPCITEMIDLIST
)&emptyitem
;
718 LPITEMIDLIST pidlMyComputer
;
720 static const DWORD desktopFlags
[] = {
722 SFGAO_STORAGE
| SFGAO_HASPROPSHEET
| SFGAO_STORAGEANCESTOR
| SFGAO_FILESYSANCESTOR
|
723 SFGAO_FOLDER
| SFGAO_FILESYSTEM
| SFGAO_HASSUBFOLDER
,
725 SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_STREAM
| SFGAO_FILESYSANCESTOR
|
726 SFGAO_FOLDER
| SFGAO_FILESYSTEM
| SFGAO_HASSUBFOLDER
,
727 /* WinMe, Win9x, WinNT*/
728 SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_FILESYSANCESTOR
|
729 SFGAO_FOLDER
| SFGAO_FILESYSTEM
| SFGAO_HASSUBFOLDER
731 static const DWORD myComputerFlags
[] = {
733 SFGAO_CANRENAME
| SFGAO_CANDELETE
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
|
734 SFGAO_FILESYSANCESTOR
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
,
736 SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
| SFGAO_STREAM
|
737 SFGAO_FILESYSANCESTOR
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
,
738 /* WinMe, Win9x, WinNT */
739 SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
| SFGAO_FILESYSANCESTOR
|
740 SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
,
741 /* Win95, WinNT when queried directly */
742 SFGAO_CANLINK
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
| SFGAO_FILESYSANCESTOR
|
743 SFGAO_FOLDER
| SFGAO_FILESYSTEM
| SFGAO_HASSUBFOLDER
745 WCHAR wszMyComputer
[] = {
746 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
747 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
748 char cCurrDirA
[MAX_PATH
] = {0};
749 WCHAR cCurrDirW
[MAX_PATH
];
750 static WCHAR cTestDirW
[] = {'t','e','s','t','d','i','r',0};
751 IShellFolder
*IDesktopFolder
, *testIShellFolder
;
754 BOOL foundFlagsMatch
;
756 hr
= SHGetDesktopFolder(&psfDesktop
);
757 ok (SUCCEEDED(hr
), "SHGetDesktopFolder failed! hr = %08x\n", hr
);
758 if (FAILED(hr
)) return;
760 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
761 dwFlags
= 0xffffffff;
762 hr
= IShellFolder_GetAttributesOf(psfDesktop
, 1, &pidlEmpty
, &dwFlags
);
763 ok (SUCCEEDED(hr
), "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr
);
764 for (i
= 0, foundFlagsMatch
= FALSE
; !foundFlagsMatch
&&
765 i
< sizeof(desktopFlags
) / sizeof(desktopFlags
[0]); i
++)
767 if (desktopFlags
[i
] == dwFlags
)
768 foundFlagsMatch
= TRUE
;
770 ok (foundFlagsMatch
, "Wrong Desktop attributes: %08x\n", dwFlags
);
772 /* .. or with no itemidlist at all. */
773 dwFlags
= 0xffffffff;
774 hr
= IShellFolder_GetAttributesOf(psfDesktop
, 0, NULL
, &dwFlags
);
775 ok (SUCCEEDED(hr
), "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr
);
776 for (i
= 0, foundFlagsMatch
= FALSE
; !foundFlagsMatch
&&
777 i
< sizeof(desktopFlags
) / sizeof(desktopFlags
[0]); i
++)
779 if (desktopFlags
[i
] == dwFlags
)
780 foundFlagsMatch
= TRUE
;
782 ok (foundFlagsMatch
, "Wrong Desktop attributes: %08x\n", dwFlags
);
784 /* Testing the attributes of the MyComputer shellfolder */
785 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszMyComputer
, NULL
, &pidlMyComputer
, NULL
);
786 ok (SUCCEEDED(hr
), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr
);
788 IShellFolder_Release(psfDesktop
);
792 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
793 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
795 dwFlags
= 0xffffffff;
796 hr
= IShellFolder_GetAttributesOf(psfDesktop
, 1, (LPCITEMIDLIST
*)&pidlMyComputer
, &dwFlags
);
797 ok (SUCCEEDED(hr
), "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr
);
798 for (i
= 0, foundFlagsMatch
= FALSE
; !foundFlagsMatch
&&
799 i
< sizeof(myComputerFlags
) / sizeof(myComputerFlags
[0]); i
++)
801 if ((myComputerFlags
[i
] | SFGAO_CANLINK
) == dwFlags
)
802 foundFlagsMatch
= TRUE
;
805 ok (foundFlagsMatch
, "Wrong MyComputer attributes: %08x\n", dwFlags
);
807 hr
= IShellFolder_BindToObject(psfDesktop
, pidlMyComputer
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfMyComputer
);
808 ok (SUCCEEDED(hr
), "Desktop failed to bind to MyComputer object! hr = %08x\n", hr
);
809 IShellFolder_Release(psfDesktop
);
810 IMalloc_Free(ppM
, pidlMyComputer
);
811 if (FAILED(hr
)) return;
813 hr
= IShellFolder_GetAttributesOf(psfMyComputer
, 1, &pidlEmpty
, &dwFlags
);
815 ok (hr
== E_INVALIDARG
||
816 broken(SUCCEEDED(hr
)), /* W2K and earlier */
817 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr
);
819 dwFlags
= 0xffffffff;
820 hr
= IShellFolder_GetAttributesOf(psfMyComputer
, 0, NULL
, &dwFlags
);
821 ok (SUCCEEDED(hr
), "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr
);
822 for (i
= 0, foundFlagsMatch
= FALSE
; !foundFlagsMatch
&&
823 i
< sizeof(myComputerFlags
) / sizeof(myComputerFlags
[0]); i
++)
825 if (myComputerFlags
[i
] == dwFlags
)
826 foundFlagsMatch
= TRUE
;
829 ok (foundFlagsMatch
, "Wrong MyComputer attributes: %08x\n", dwFlags
);
831 IShellFolder_Release(psfMyComputer
);
833 GetCurrentDirectoryA(MAX_PATH
, cCurrDirA
);
834 len
= lstrlenA(cCurrDirA
);
837 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
840 if (len
> 3 && cCurrDirA
[len
-1] == '\\')
841 cCurrDirA
[len
-1] = 0;
843 /* create test directory */
844 CreateFilesFolders();
846 MultiByteToWideChar(CP_ACP
, 0, cCurrDirA
, -1, cCurrDirW
, MAX_PATH
);
848 hr
= SHGetDesktopFolder(&IDesktopFolder
);
849 ok(hr
== S_OK
, "SHGetDesktopfolder failed %08x\n", hr
);
851 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
, NULL
, NULL
, cCurrDirW
, NULL
, &newPIDL
, 0);
852 ok(hr
== S_OK
, "ParseDisplayName failed %08x\n", hr
);
854 hr
= IShellFolder_BindToObject(IDesktopFolder
, newPIDL
, NULL
, (REFIID
)&IID_IShellFolder
, (LPVOID
*)&testIShellFolder
);
855 ok(hr
== S_OK
, "BindToObject failed %08x\n", hr
);
857 IMalloc_Free(ppM
, newPIDL
);
859 /* get relative PIDL */
860 hr
= IShellFolder_ParseDisplayName(testIShellFolder
, NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
861 ok(hr
== S_OK
, "ParseDisplayName failed %08x\n", hr
);
863 /* test the shell attributes of the test directory using the relative PIDL */
864 dwFlags
= SFGAO_FOLDER
;
865 hr
= IShellFolder_GetAttributesOf(testIShellFolder
, 1, (LPCITEMIDLIST
*)&newPIDL
, &dwFlags
);
866 ok (SUCCEEDED(hr
), "Desktop->GetAttributesOf() failed! hr = %08x\n", hr
);
867 ok ((dwFlags
&SFGAO_FOLDER
), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags
);
870 IMalloc_Free(ppM
, newPIDL
);
872 /* append testdirectory name to path */
873 if (cCurrDirA
[len
-1] == '\\')
874 cCurrDirA
[len
-1] = 0;
875 lstrcatA(cCurrDirA
, "\\testdir");
876 MultiByteToWideChar(CP_ACP
, 0, cCurrDirA
, -1, cCurrDirW
, MAX_PATH
);
878 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
, NULL
, NULL
, cCurrDirW
, NULL
, &newPIDL
, 0);
879 ok(hr
== S_OK
, "ParseDisplayName failed %08x\n", hr
);
881 /* test the shell attributes of the test directory using the absolute PIDL */
882 dwFlags
= SFGAO_FOLDER
;
883 hr
= IShellFolder_GetAttributesOf(IDesktopFolder
, 1, (LPCITEMIDLIST
*)&newPIDL
, &dwFlags
);
884 ok (SUCCEEDED(hr
), "Desktop->GetAttributesOf() failed! hr = %08x\n", hr
);
885 ok ((dwFlags
&SFGAO_FOLDER
), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags
);
888 IMalloc_Free(ppM
, newPIDL
);
890 IShellFolder_Release(testIShellFolder
);
894 IShellFolder_Release(IDesktopFolder
);
897 static void test_SHGetPathFromIDList(void)
899 SHITEMID emptyitem
= { 0, { 0 } };
900 LPCITEMIDLIST pidlEmpty
= (LPCITEMIDLIST
)&emptyitem
;
901 LPITEMIDLIST pidlMyComputer
;
902 WCHAR wszPath
[MAX_PATH
], wszDesktop
[MAX_PATH
];
905 LPSHELLFOLDER psfDesktop
;
906 WCHAR wszMyComputer
[] = {
907 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
908 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
909 WCHAR wszFileName
[MAX_PATH
];
910 LPITEMIDLIST pidlTestFile
;
913 static WCHAR wszTestFile
[] = {
914 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
915 HRESULT (WINAPI
*pSHGetSpecialFolderLocation
)(HWND
, int, LPITEMIDLIST
*);
917 LPITEMIDLIST pidlPrograms
;
919 if(!pSHGetPathFromIDListW
|| !pSHGetSpecialFolderPathW
)
921 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
925 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
928 result
= pSHGetPathFromIDListW(NULL
, wszPath
);
929 ok(!result
, "Expected failure\n");
930 ok(!wszPath
[0], "Expected empty string\n");
932 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
933 result
= pSHGetSpecialFolderPathW(NULL
, wszDesktop
, CSIDL_DESKTOP
, FALSE
);
934 ok(result
, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
937 /* Check if we are on Win9x */
938 SetLastError(0xdeadbeef);
939 lstrcmpiW(wszDesktop
, wszDesktop
);
940 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
942 win_skip("Most W-calls are not implemented\n");
946 result
= pSHGetPathFromIDListW(pidlEmpty
, wszPath
);
947 ok(result
, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
949 ok(!lstrcmpiW(wszDesktop
, wszPath
), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
951 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
952 hr
= SHGetDesktopFolder(&psfDesktop
);
953 ok (SUCCEEDED(hr
), "SHGetDesktopFolder failed! hr = %08x\n", hr
);
954 if (FAILED(hr
)) return;
956 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszMyComputer
, NULL
, &pidlMyComputer
, NULL
);
957 ok (SUCCEEDED(hr
), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr
);
959 IShellFolder_Release(psfDesktop
);
963 SetLastError(0xdeadbeef);
966 result
= pSHGetPathFromIDListW(pidlMyComputer
, wszPath
);
967 ok (!result
, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
968 ok (GetLastError()==0xdeadbeef ||
969 GetLastError()==ERROR_SUCCESS
, /* Vista and higher */
970 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
971 ok (!wszPath
[0], "Expected empty path\n");
973 IShellFolder_Release(psfDesktop
);
977 IMalloc_Free(ppM
, pidlMyComputer
);
979 result
= pSHGetSpecialFolderPathW(NULL
, wszFileName
, CSIDL_DESKTOPDIRECTORY
, FALSE
);
980 ok(result
, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
982 IShellFolder_Release(psfDesktop
);
985 myPathAddBackslashW(wszFileName
);
986 lstrcatW(wszFileName
, wszTestFile
);
987 hTestFile
= CreateFileW(wszFileName
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
988 ok(hTestFile
!= INVALID_HANDLE_VALUE
, "CreateFileW failed! Last error: %u\n", GetLastError());
989 if (hTestFile
== INVALID_HANDLE_VALUE
) {
990 IShellFolder_Release(psfDesktop
);
993 CloseHandle(hTestFile
);
995 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszTestFile
, NULL
, &pidlTestFile
, NULL
);
996 ok (SUCCEEDED(hr
), "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr
);
998 IShellFolder_Release(psfDesktop
);
999 DeleteFileW(wszFileName
);
1000 IMalloc_Free(ppM
, pidlTestFile
);
1004 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1005 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1006 hr
= IShellFolder_GetDisplayNameOf(psfDesktop
, pidlTestFile
, SHGDN_FORPARSING
, &strret
);
1007 ok (SUCCEEDED(hr
), "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr
);
1008 IShellFolder_Release(psfDesktop
);
1009 DeleteFileW(wszFileName
);
1011 IMalloc_Free(ppM
, pidlTestFile
);
1016 pStrRetToBufW(&strret
, pidlTestFile
, wszPath
, MAX_PATH
);
1017 ok(0 == lstrcmpW(wszFileName
, wszPath
),
1018 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1019 "returned incorrect path for file placed on desktop\n");
1022 result
= pSHGetPathFromIDListW(pidlTestFile
, wszPath
);
1023 ok(result
, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1024 IMalloc_Free(ppM
, pidlTestFile
);
1025 if (!result
) return;
1026 ok(0 == lstrcmpW(wszFileName
, wszPath
), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1029 /* Test if we can get the path from the start menu "program files" PIDL. */
1030 hShell32
= GetModuleHandleA("shell32");
1031 pSHGetSpecialFolderLocation
= (void *)GetProcAddress(hShell32
, "SHGetSpecialFolderLocation");
1033 hr
= pSHGetSpecialFolderLocation(NULL
, CSIDL_PROGRAM_FILES
, &pidlPrograms
);
1034 ok(SUCCEEDED(hr
), "SHGetFolderLocation failed: 0x%08x\n", hr
);
1036 SetLastError(0xdeadbeef);
1037 result
= pSHGetPathFromIDListW(pidlPrograms
, wszPath
);
1038 IMalloc_Free(ppM
, pidlPrograms
);
1039 ok(result
, "SHGetPathFromIDListW failed\n");
1042 static void test_EnumObjects_and_CompareIDs(void)
1044 ITEMIDLIST
*newPIDL
;
1045 IShellFolder
*IDesktopFolder
, *testIShellFolder
;
1046 char cCurrDirA
[MAX_PATH
] = {0};
1047 static const CHAR cTestDirA
[] = "\\testdir";
1048 WCHAR cTestDirW
[MAX_PATH
];
1052 GetCurrentDirectoryA(MAX_PATH
, cCurrDirA
);
1053 len
= lstrlenA(cCurrDirA
);
1056 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1059 if(cCurrDirA
[len
-1] == '\\')
1060 cCurrDirA
[len
-1] = 0;
1062 lstrcatA(cCurrDirA
, cTestDirA
);
1063 MultiByteToWideChar(CP_ACP
, 0, cCurrDirA
, -1, cTestDirW
, MAX_PATH
);
1065 hr
= SHGetDesktopFolder(&IDesktopFolder
);
1066 ok(hr
== S_OK
, "SHGetDesktopfolder failed %08x\n", hr
);
1068 CreateFilesFolders();
1070 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
, NULL
, NULL
, cTestDirW
, NULL
, &newPIDL
, 0);
1071 ok(hr
== S_OK
, "ParseDisplayName failed %08x\n", hr
);
1073 hr
= IShellFolder_BindToObject(IDesktopFolder
, newPIDL
, NULL
, (REFIID
)&IID_IShellFolder
, (LPVOID
*)&testIShellFolder
);
1074 ok(hr
== S_OK
, "BindToObject failed %08x\n", hr
);
1076 test_EnumObjects(testIShellFolder
);
1078 IShellFolder_Release(testIShellFolder
);
1082 IMalloc_Free(ppM
, newPIDL
);
1084 IShellFolder_Release(IDesktopFolder
);
1087 /* A simple implementation of an IPropertyBag, which returns fixed values for
1088 * 'Target' and 'Attributes' properties.
1090 static HRESULT WINAPI
InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag
*iface
, REFIID riid
,
1094 return E_INVALIDARG
;
1096 if (IsEqualIID(&IID_IUnknown
, riid
) || IsEqualIID(&IID_IPropertyBag
, riid
)) {
1099 ok (FALSE
, "InitPropertyBag asked for unknown interface!\n");
1100 return E_NOINTERFACE
;
1103 IPropertyBag_AddRef(iface
);
1107 static ULONG WINAPI
InitPropertyBag_IPropertyBag_AddRef(IPropertyBag
*iface
) {
1111 static ULONG WINAPI
InitPropertyBag_IPropertyBag_Release(IPropertyBag
*iface
) {
1115 static HRESULT WINAPI
InitPropertyBag_IPropertyBag_Read(IPropertyBag
*iface
, LPCOLESTR pszPropName
,
1116 VARIANT
*pVar
, IErrorLog
*pErrorLog
)
1118 static const WCHAR wszTargetSpecialFolder
[] = {
1119 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1120 static const WCHAR wszTarget
[] = {
1121 'T','a','r','g','e','t',0 };
1122 static const WCHAR wszAttributes
[] = {
1123 'A','t','t','r','i','b','u','t','e','s',0 };
1124 static const WCHAR wszResolveLinkFlags
[] = {
1125 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1126 static const WCHAR wszTargetKnownFolder
[] = {
1127 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1128 static const WCHAR wszCLSID
[] = {
1129 'C','L','S','I','D',0 };
1131 if (!lstrcmpW(pszPropName
, wszTargetSpecialFolder
)) {
1132 ok(V_VT(pVar
) == VT_I4
||
1133 broken(V_VT(pVar
) == VT_BSTR
), /* Win2k */
1134 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1135 return E_INVALIDARG
;
1138 if (!lstrcmpW(pszPropName
, wszResolveLinkFlags
))
1140 ok(V_VT(pVar
) == VT_UI4
, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1141 return E_INVALIDARG
;
1144 if (!lstrcmpW(pszPropName
, wszTarget
)) {
1145 WCHAR wszPath
[MAX_PATH
];
1148 ok(V_VT(pVar
) == VT_BSTR
||
1149 broken(V_VT(pVar
) == VT_EMPTY
), /* Win2k */
1150 "Wrong variant type for 'Target' property!\n");
1151 if (V_VT(pVar
) != VT_BSTR
) return E_INVALIDARG
;
1153 result
= pSHGetSpecialFolderPathW(NULL
, wszPath
, CSIDL_DESKTOPDIRECTORY
, FALSE
);
1154 ok(result
, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1155 if (!result
) return E_INVALIDARG
;
1157 V_BSTR(pVar
) = SysAllocString(wszPath
);
1161 if (!lstrcmpW(pszPropName
, wszAttributes
)) {
1162 ok(V_VT(pVar
) == VT_UI4
, "Wrong variant type for 'Attributes' property!\n");
1163 if (V_VT(pVar
) != VT_UI4
) return E_INVALIDARG
;
1164 V_UI4(pVar
) = SFGAO_FOLDER
|SFGAO_HASSUBFOLDER
|SFGAO_FILESYSANCESTOR
|
1165 SFGAO_CANRENAME
|SFGAO_FILESYSTEM
;
1169 if (!lstrcmpW(pszPropName
, wszTargetKnownFolder
)) {
1170 ok(V_VT(pVar
) == VT_BSTR
, "Wrong variant type for 'TargetKnownFolder' property!\n");
1172 return E_INVALIDARG
;
1175 if (!lstrcmpW(pszPropName
, wszCLSID
)) {
1176 ok(V_VT(pVar
) == VT_EMPTY
, "Wrong variant type for 'CLSID' property!\n");
1178 return E_INVALIDARG
;
1181 ok(FALSE
, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName
), V_VT(pVar
));
1182 return E_INVALIDARG
;
1185 static HRESULT WINAPI
InitPropertyBag_IPropertyBag_Write(IPropertyBag
*iface
, LPCOLESTR pszPropName
,
1188 ok(FALSE
, "Unexpected call to IPropertyBag_Write\n");
1192 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl
= {
1193 InitPropertyBag_IPropertyBag_QueryInterface
,
1194 InitPropertyBag_IPropertyBag_AddRef
,
1195 InitPropertyBag_IPropertyBag_Release
,
1196 InitPropertyBag_IPropertyBag_Read
,
1197 InitPropertyBag_IPropertyBag_Write
1200 static struct IPropertyBag InitPropertyBag
= {
1201 &InitPropertyBag_IPropertyBagVtbl
1204 static void test_FolderShortcut(void) {
1205 IPersistPropertyBag
*pPersistPropertyBag
;
1206 IShellFolder
*pShellFolder
, *pDesktopFolder
;
1207 IPersistFolder3
*pPersistFolder3
;
1210 WCHAR wszDesktopPath
[MAX_PATH
], wszBuffer
[MAX_PATH
];
1213 LPITEMIDLIST pidlCurrentFolder
, pidlWineTestFolder
, pidlSubFolder
;
1215 WCHAR wszWineTestFolder
[] = {
1216 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1217 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1218 WCHAR wszShellExtKey
[] = { 'S','o','f','t','w','a','r','e','\\',
1219 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1220 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1221 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1222 'N','a','m','e','S','p','a','c','e','\\',
1223 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1224 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1226 WCHAR wszSomeSubFolder
[] = { 'S','u','b','F','o','l','d','e','r', 0};
1227 static const GUID CLSID_UnixDosFolder
=
1228 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1230 if (!pSHGetSpecialFolderPathW
|| !pStrRetToBufW
) {
1231 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1235 if (!pSHGetFolderPathAndSubDirA
)
1237 win_skip("FolderShortcut test doesn't work on Win2k\n");
1241 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1242 * via their IPersistPropertyBag interface. And that the target folder
1243 * is taken from the IPropertyBag's 'Target' property.
1245 hr
= CoCreateInstance(&CLSID_FolderShortcut
, NULL
, CLSCTX_INPROC_SERVER
,
1246 &IID_IPersistPropertyBag
, (LPVOID
*)&pPersistPropertyBag
);
1247 if (hr
== REGDB_E_CLASSNOTREG
) {
1248 win_skip("CLSID_FolderShortcut is not implemented\n");
1251 ok (SUCCEEDED(hr
), "CoCreateInstance failed! hr = 0x%08x\n", hr
);
1252 if (FAILED(hr
)) return;
1254 hr
= IPersistPropertyBag_Load(pPersistPropertyBag
, &InitPropertyBag
, NULL
);
1255 ok(SUCCEEDED(hr
), "IPersistPropertyBag_Load failed! hr = %08x\n", hr
);
1257 IPersistPropertyBag_Release(pPersistPropertyBag
);
1261 hr
= IPersistPropertyBag_QueryInterface(pPersistPropertyBag
, &IID_IShellFolder
,
1262 (LPVOID
*)&pShellFolder
);
1263 IPersistPropertyBag_Release(pPersistPropertyBag
);
1264 ok(SUCCEEDED(hr
), "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr
);
1265 if (FAILED(hr
)) return;
1267 hr
= IShellFolder_GetDisplayNameOf(pShellFolder
, NULL
, SHGDN_FORPARSING
, &strret
);
1268 ok(SUCCEEDED(hr
), "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr
);
1270 IShellFolder_Release(pShellFolder
);
1274 result
= pSHGetSpecialFolderPathW(NULL
, wszDesktopPath
, CSIDL_DESKTOPDIRECTORY
, FALSE
);
1275 ok(result
, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1276 if (!result
) return;
1278 pStrRetToBufW(&strret
, NULL
, wszBuffer
, MAX_PATH
);
1279 ok(!lstrcmpiW(wszDesktopPath
, wszBuffer
), "FolderShortcut returned incorrect folder!\n");
1281 hr
= IShellFolder_QueryInterface(pShellFolder
, &IID_IPersistFolder3
, (LPVOID
*)&pPersistFolder3
);
1282 IShellFolder_Release(pShellFolder
);
1283 ok(SUCCEEDED(hr
), "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr
);
1284 if (FAILED(hr
)) return;
1286 hr
= IPersistFolder3_GetClassID(pPersistFolder3
, &clsid
);
1287 ok(SUCCEEDED(hr
), "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr
);
1288 ok(IsEqualCLSID(&clsid
, &CLSID_FolderShortcut
), "Unexpected CLSID!\n");
1290 hr
= IPersistFolder3_GetCurFolder(pPersistFolder3
, &pidlCurrentFolder
);
1291 ok(SUCCEEDED(hr
), "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr
);
1292 ok(!pidlCurrentFolder
, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1294 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1295 * shell namespace. The target folder, read from the property bag above, remains untouched.
1296 * The following tests show this: The itemidlist for some imaginary shellfolder object
1297 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1298 * itemidlist, but GetDisplayNameOf still returns the path from above.
1300 hr
= SHGetDesktopFolder(&pDesktopFolder
);
1301 ok (SUCCEEDED(hr
), "SHGetDesktopFolder failed! hr = %08x\n", hr
);
1302 if (FAILED(hr
)) return;
1304 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1305 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1306 RegCreateKeyW(HKEY_CURRENT_USER
, wszShellExtKey
, &hShellExtKey
);
1307 RegCloseKey(hShellExtKey
);
1308 hr
= IShellFolder_ParseDisplayName(pDesktopFolder
, NULL
, NULL
, wszWineTestFolder
, NULL
,
1309 &pidlWineTestFolder
, NULL
);
1310 RegDeleteKeyW(HKEY_CURRENT_USER
, wszShellExtKey
);
1311 IShellFolder_Release(pDesktopFolder
);
1312 ok (SUCCEEDED(hr
), "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr
);
1313 if (FAILED(hr
)) return;
1315 hr
= IPersistFolder3_Initialize(pPersistFolder3
, pidlWineTestFolder
);
1316 ok (SUCCEEDED(hr
), "IPersistFolder3::Initialize failed! hr = %08x\n", hr
);
1318 IPersistFolder3_Release(pPersistFolder3
);
1319 pILFree(pidlWineTestFolder
);
1323 hr
= IPersistFolder3_GetCurFolder(pPersistFolder3
, &pidlCurrentFolder
);
1324 ok(SUCCEEDED(hr
), "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr
);
1325 ok(pILIsEqual(pidlCurrentFolder
, pidlWineTestFolder
),
1326 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1327 pILFree(pidlCurrentFolder
);
1328 pILFree(pidlWineTestFolder
);
1330 hr
= IPersistFolder3_QueryInterface(pPersistFolder3
, &IID_IShellFolder
, (LPVOID
*)&pShellFolder
);
1331 IPersistFolder3_Release(pPersistFolder3
);
1332 ok(SUCCEEDED(hr
), "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr
);
1333 if (FAILED(hr
)) return;
1335 hr
= IShellFolder_GetDisplayNameOf(pShellFolder
, NULL
, SHGDN_FORPARSING
, &strret
);
1336 ok(SUCCEEDED(hr
), "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr
);
1338 IShellFolder_Release(pShellFolder
);
1342 pStrRetToBufW(&strret
, NULL
, wszBuffer
, MAX_PATH
);
1343 ok(!lstrcmpiW(wszDesktopPath
, wszBuffer
), "FolderShortcut returned incorrect folder!\n");
1345 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1346 * but ShellFSFolders. */
1347 myPathAddBackslashW(wszDesktopPath
);
1348 lstrcatW(wszDesktopPath
, wszSomeSubFolder
);
1349 if (!CreateDirectoryW(wszDesktopPath
, NULL
)) {
1350 IShellFolder_Release(pShellFolder
);
1354 hr
= IShellFolder_ParseDisplayName(pShellFolder
, NULL
, NULL
, wszSomeSubFolder
, NULL
,
1355 &pidlSubFolder
, NULL
);
1356 RemoveDirectoryW(wszDesktopPath
);
1357 ok (SUCCEEDED(hr
), "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr
);
1359 IShellFolder_Release(pShellFolder
);
1363 hr
= IShellFolder_BindToObject(pShellFolder
, pidlSubFolder
, NULL
, &IID_IPersistFolder3
,
1364 (LPVOID
*)&pPersistFolder3
);
1365 IShellFolder_Release(pShellFolder
);
1366 pILFree(pidlSubFolder
);
1367 ok (SUCCEEDED(hr
), "IShellFolder::BindToObject failed! hr = %08x\n", hr
);
1371 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1372 * a little bit and also allow CLSID_UnixDosFolder. */
1373 hr
= IPersistFolder3_GetClassID(pPersistFolder3
, &clsid
);
1374 ok(SUCCEEDED(hr
), "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr
);
1375 ok(IsEqualCLSID(&clsid
, &CLSID_ShellFSFolder
) || IsEqualCLSID(&clsid
, &CLSID_UnixDosFolder
),
1376 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1378 IPersistFolder3_Release(pPersistFolder3
);
1381 #include "pshpack1.h"
1382 struct FileStructA
{
1386 WORD uFileDate
; /* In our current implementation this is */
1387 WORD uFileTime
; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1392 struct FileStructW
{
1393 WORD cbLen
; /* Length of this element. */
1394 BYTE abFooBar1
[6]; /* Beyond any recognition. */
1395 WORD uDate
; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1396 WORD uTime
; /* (this is currently speculation) */
1397 WORD uDate2
; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1398 WORD uTime2
; /* (this is currently speculation) */
1399 BYTE abFooBar2
[4]; /* Beyond any recognition. */
1400 WCHAR wszName
[1]; /* The long filename in unicode. */
1401 /* Just for documentation: Right after the unicode string: */
1402 WORD cbOffset
; /* FileStructW's offset from the beginning of the SHITMEID.
1403 * SHITEMID->cb == uOffset + cbLen */
1405 #include "poppack.h"
1407 static void test_ITEMIDLIST_format(void) {
1408 WCHAR wszPersonal
[MAX_PATH
];
1409 LPSHELLFOLDER psfDesktop
, psfPersonal
;
1410 LPITEMIDLIST pidlPersonal
, pidlFile
;
1414 WCHAR wszFile
[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1415 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1418 if (!pSHGetSpecialFolderPathW
) return;
1420 bResult
= pSHGetSpecialFolderPathW(NULL
, wszPersonal
, CSIDL_PERSONAL
, FALSE
);
1421 ok(bResult
, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1422 if (!bResult
) return;
1424 SetLastError(0xdeadbeef);
1425 bResult
= SetCurrentDirectoryW(wszPersonal
);
1426 if (!bResult
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
) {
1427 win_skip("Most W-calls are not implemented\n");
1430 ok(bResult
, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1431 if (!bResult
) return;
1433 hr
= SHGetDesktopFolder(&psfDesktop
);
1434 ok(SUCCEEDED(hr
), "SHGetDesktopFolder failed! hr: %08x\n", hr
);
1435 if (FAILED(hr
)) return;
1437 hr
= IShellFolder_ParseDisplayName(psfDesktop
, NULL
, NULL
, wszPersonal
, NULL
, &pidlPersonal
, NULL
);
1438 ok(SUCCEEDED(hr
), "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr
);
1440 IShellFolder_Release(psfDesktop
);
1444 hr
= IShellFolder_BindToObject(psfDesktop
, pidlPersonal
, NULL
, &IID_IShellFolder
,
1445 (LPVOID
*)&psfPersonal
);
1446 IShellFolder_Release(psfDesktop
);
1447 pILFree(pidlPersonal
);
1448 ok(SUCCEEDED(hr
), "psfDesktop->BindToObject failed! hr = %08x\n", hr
);
1449 if (FAILED(hr
)) return;
1451 for (i
=0; i
<3; i
++) {
1452 CHAR szFile
[MAX_PATH
];
1453 struct FileStructA
*pFileStructA
;
1456 WideCharToMultiByte(CP_ACP
, 0, wszFile
[i
], -1, szFile
, MAX_PATH
, NULL
, NULL
);
1458 hFile
= CreateFileW(wszFile
[i
], GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_FLAG_WRITE_THROUGH
, NULL
);
1459 ok(hFile
!= INVALID_HANDLE_VALUE
, "CreateFile failed! (%u)\n", GetLastError());
1460 if (hFile
== INVALID_HANDLE_VALUE
) {
1461 IShellFolder_Release(psfPersonal
);
1466 hr
= IShellFolder_ParseDisplayName(psfPersonal
, NULL
, NULL
, wszFile
[i
], NULL
, &pidlFile
, NULL
);
1467 DeleteFileW(wszFile
[i
]);
1468 ok(SUCCEEDED(hr
), "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr
);
1470 IShellFolder_Release(psfPersonal
);
1474 pFileStructA
= (struct FileStructA
*)pidlFile
->mkid
.abID
;
1475 ok(pFileStructA
->type
== 0x32, "PIDLTYPE should be 0x32!\n");
1476 ok(pFileStructA
->dummy
== 0x00, "Dummy Byte should be 0x00!\n");
1477 ok(pFileStructA
->dwFileSize
== 0, "Filesize should be zero!\n");
1479 if (i
< 2) /* First two file names are already in valid 8.3 format */
1480 ok(!strcmp(szFile
, (CHAR
*)&pidlFile
->mkid
.abID
[12]), "Wrong file name!\n");
1482 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1483 * can't implement this correctly, since unix filesystems don't support
1484 * this nasty short/long filename stuff. So we'll probably stay with our
1485 * current habbit of storing the long filename here, which seems to work
1488 ok(pidlFile
->mkid
.abID
[18] == '~' ||
1489 broken(pidlFile
->mkid
.abID
[34] == '~'), /* Win2k */
1490 "Should be derived 8.3 name!\n");
1492 if (i
== 0) /* First file name has an even number of chars. No need for alignment. */
1493 ok(pidlFile
->mkid
.abID
[12 + strlen(szFile
) + 1] != '\0' ||
1494 broken(pidlFile
->mkid
.cb
== 2 + 12 + strlen(szFile
) + 1 + 1), /* Win2k */
1495 "Alignment byte, where there shouldn't be!\n");
1497 if (i
== 1) /* Second file name has an uneven number of chars => alignment byte */
1498 ok(pidlFile
->mkid
.abID
[12 + strlen(szFile
) + 1] == '\0',
1499 "There should be an alignment byte, but isn't!\n");
1501 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1502 cbOffset
= *(WORD
*)(((LPBYTE
)pidlFile
)+pidlFile
->mkid
.cb
-sizeof(WORD
));
1503 ok ((cbOffset
>= sizeof(struct FileStructA
) &&
1504 cbOffset
<= pidlFile
->mkid
.cb
- sizeof(struct FileStructW
)) ||
1505 broken(pidlFile
->mkid
.cb
== 2 + 12 + strlen(szFile
) + 1 + 1) || /* Win2k on short names */
1506 broken(pidlFile
->mkid
.cb
== 2 + 12 + strlen(szFile
) + 1 + 12 + 1), /* Win2k on long names */
1507 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset
);
1509 if (cbOffset
>= sizeof(struct FileStructA
) &&
1510 cbOffset
<= pidlFile
->mkid
.cb
- sizeof(struct FileStructW
))
1512 struct FileStructW
*pFileStructW
= (struct FileStructW
*)(((LPBYTE
)pidlFile
)+cbOffset
);
1514 ok(pidlFile
->mkid
.cb
== cbOffset
+ pFileStructW
->cbLen
,
1515 "FileStructW's offset and length should add up to the PIDL's length!\n");
1517 if (pidlFile
->mkid
.cb
== cbOffset
+ pFileStructW
->cbLen
) {
1518 /* Since we just created the file, time of creation,
1519 * time of last access and time of last write access just be the same.
1520 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1521 * after the first run. I do remember something with NTFS keeping the creation time
1522 * if a file is deleted and then created again within a couple of seconds or so.
1523 * Might be the reason. */
1524 ok (pFileStructA
->uFileDate
== pFileStructW
->uDate
&&
1525 pFileStructA
->uFileTime
== pFileStructW
->uTime
,
1526 "Last write time should match creation time!\n");
1528 /* On FAT filesystems the last access time is midnight
1529 local time, so the values of uDate2 and uTime2 will
1530 depend on the local timezone. If the times are exactly
1531 equal then the dates should be identical for both FAT
1532 and NTFS as no timezone is more than 1 day away from UTC.
1534 if (pFileStructA
->uFileTime
== pFileStructW
->uTime2
)
1536 ok (pFileStructA
->uFileDate
== pFileStructW
->uDate2
,
1537 "Last write date and time should match last access date and time!\n");
1541 /* Filesystem may be FAT. Check date within 1 day
1542 and seconds are zero. */
1543 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1544 ok ((pFileStructW
->uTime2
& 0x1F) == 0,
1545 "Last access time on FAT filesystems should have zero seconds.\n");
1546 /* TODO: Perform check for date being within one day.*/
1549 ok (!lstrcmpW(wszFile
[i
], pFileStructW
->wszName
) ||
1550 !lstrcmpW(wszFile
[i
], (WCHAR
*)(pFileStructW
->abFooBar2
+ 22)) || /* Vista */
1551 !lstrcmpW(wszFile
[i
], (WCHAR
*)(pFileStructW
->abFooBar2
+ 26)), /* Win7 */
1552 "The filename should be stored in unicode at this position!\n");
1560 static void testSHGetFolderPathAndSubDirA(void)
1566 static char wine
[] = "wine";
1567 static char winetemp
[] = "wine\\temp";
1568 static char appdata
[MAX_PATH
];
1569 static char testpath
[MAX_PATH
];
1570 static char toolongpath
[MAX_PATH
+1];
1572 if(!pSHGetFolderPathA
) {
1573 win_skip("SHGetFolderPathA not present!\n");
1576 if(FAILED(pSHGetFolderPathA(NULL
, CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, appdata
)))
1578 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1582 sprintf(testpath
, "%s\\%s", appdata
, winetemp
);
1583 delret
= RemoveDirectoryA(testpath
);
1584 if(!delret
&& (ERROR_PATH_NOT_FOUND
!= GetLastError()) ) {
1585 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath
, GetLastError());
1589 sprintf(testpath
, "%s\\%s", appdata
, wine
);
1590 delret
= RemoveDirectoryA(testpath
);
1591 if(!delret
&& (ERROR_PATH_NOT_FOUND
!= GetLastError()) && (ERROR_FILE_NOT_FOUND
!= GetLastError())) {
1592 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath
, GetLastError());
1596 /* test invalid second parameter */
1597 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| 0xff, NULL
, SHGFP_TYPE_CURRENT
, wine
, testpath
);
1598 ok(E_INVALIDARG
== ret
, "expected E_INVALIDARG, got %x\n", ret
);
1600 /* test fourth parameter */
1601 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| CSIDL_LOCAL_APPDATA
, NULL
, 2, winetemp
, testpath
);
1603 case S_OK
: /* winvista */
1604 ok(!strncmp(appdata
, testpath
, strlen(appdata
)),
1605 "expected %s to start with %s\n", testpath
, appdata
);
1606 ok(!lstrcmpA(&testpath
[1 + strlen(appdata
)], winetemp
),
1607 "expected %s to end with %s\n", testpath
, winetemp
);
1609 case E_INVALIDARG
: /* winxp, win2k3 */
1612 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret
);
1615 /* test fifth parameter */
1617 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, NULL
, testpath
);
1618 ok(S_OK
== ret
, "expected S_OK, got %x\n", ret
);
1619 ok(!lstrcmpA(appdata
, testpath
), "expected %s, got %s\n", appdata
, testpath
);
1622 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, "", testpath
);
1623 ok(S_OK
== ret
, "expected S_OK, got %x\n", ret
);
1624 ok(!lstrcmpA(appdata
, testpath
), "expected %s, got %s\n", appdata
, testpath
);
1627 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, "\\", testpath
);
1628 ok(S_OK
== ret
, "expected S_OK, got %x\n", ret
);
1629 ok(!lstrcmpA(appdata
, testpath
), "expected %s, got %s\n", appdata
, testpath
);
1631 for(i
=0; i
< MAX_PATH
; i
++)
1632 toolongpath
[i
] = '0' + i
% 10;
1633 toolongpath
[MAX_PATH
] = '\0';
1634 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, toolongpath
, testpath
);
1635 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE
) == ret
,
1636 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE
), ret
);
1639 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_DONT_VERIFY
| CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, wine
, NULL
);
1640 ok((S_OK
== ret
) || (E_INVALIDARG
== ret
), "expected S_OK or E_INVALIDARG, got %x\n", ret
);
1642 /* test a not existing path */
1644 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, winetemp
, testpath
);
1645 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
) == ret
,
1646 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
), ret
);
1648 /* create a directory inside a not existing directory */
1650 ret
= pSHGetFolderPathAndSubDirA(NULL
, CSIDL_FLAG_CREATE
| CSIDL_LOCAL_APPDATA
, NULL
, SHGFP_TYPE_CURRENT
, winetemp
, testpath
);
1651 ok(S_OK
== ret
, "expected S_OK, got %x\n", ret
);
1652 ok(!strncmp(appdata
, testpath
, strlen(appdata
)),
1653 "expected %s to start with %s\n", testpath
, appdata
);
1654 ok(!lstrcmpA(&testpath
[1 + strlen(appdata
)], winetemp
),
1655 "expected %s to end with %s\n", testpath
, winetemp
);
1656 dwret
= GetFileAttributes(testpath
);
1657 ok(FILE_ATTRIBUTE_DIRECTORY
| dwret
, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret
);
1660 sprintf(testpath
, "%s\\%s", appdata
, winetemp
);
1661 RemoveDirectoryA(testpath
);
1662 sprintf(testpath
, "%s\\%s", appdata
, wine
);
1663 RemoveDirectoryA(testpath
);
1666 static void test_LocalizedNames(void)
1668 static char cCurrDirA
[MAX_PATH
];
1669 WCHAR cCurrDirW
[MAX_PATH
], tempbufW
[25];
1670 IShellFolder
*IDesktopFolder
, *testIShellFolder
;
1671 ITEMIDLIST
*newPIDL
;
1674 static char resourcefile
[MAX_PATH
];
1679 static const char desktopini_contents1
[] =
1680 "[.ShellClassInfo]\r\n"
1681 "LocalizedResourceName=@";
1682 static const char desktopini_contents2
[] =
1684 static WCHAR foldernameW
[] = {'t','e','s','t','f','o','l','d','e','r',0};
1685 static const WCHAR folderdisplayW
[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1687 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1688 CreateDirectoryA(".\\testfolder", NULL
);
1690 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM
);
1692 GetModuleFileNameA(NULL
, resourcefile
, MAX_PATH
);
1694 file
= CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE
, 0, NULL
,
1695 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1696 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFileA failed %i\n", GetLastError());
1697 ok(WriteFile(file
, desktopini_contents1
, strlen(desktopini_contents1
), &res
, NULL
) &&
1698 WriteFile(file
, resourcefile
, strlen(resourcefile
), &res
, NULL
) &&
1699 WriteFile(file
, desktopini_contents2
, strlen(desktopini_contents2
), &res
, NULL
),
1700 "WriteFile failed %i\n", GetLastError());
1703 /* get IShellFolder for parent */
1704 GetCurrentDirectoryA(MAX_PATH
, cCurrDirA
);
1705 len
= lstrlenA(cCurrDirA
);
1708 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1711 if(cCurrDirA
[len
-1] == '\\')
1712 cCurrDirA
[len
-1] = 0;
1714 MultiByteToWideChar(CP_ACP
, 0, cCurrDirA
, -1, cCurrDirW
, MAX_PATH
);
1716 hr
= SHGetDesktopFolder(&IDesktopFolder
);
1717 ok(hr
== S_OK
, "SHGetDesktopfolder failed %08x\n", hr
);
1719 hr
= IShellFolder_ParseDisplayName(IDesktopFolder
, NULL
, NULL
, cCurrDirW
, NULL
, &newPIDL
, 0);
1720 ok(hr
== S_OK
, "ParseDisplayName failed %08x\n", hr
);
1722 hr
= IShellFolder_BindToObject(IDesktopFolder
, newPIDL
, NULL
, (REFIID
)&IID_IShellFolder
, (LPVOID
*)&testIShellFolder
);
1723 ok(hr
== S_OK
, "BindToObject failed %08x\n", hr
);
1725 IMalloc_Free(ppM
, newPIDL
);
1727 /* windows reads the display name from the resource */
1728 hr
= IShellFolder_ParseDisplayName(testIShellFolder
, NULL
, NULL
, foldernameW
, NULL
, &newPIDL
, 0);
1729 ok(hr
== S_OK
, "ParseDisplayName failed %08x\n", hr
);
1731 hr
= IShellFolder_GetDisplayNameOf(testIShellFolder
, newPIDL
, SHGDN_INFOLDER
, &strret
);
1732 ok(hr
== S_OK
, "GetDisplayNameOf failed %08x\n", hr
);
1734 if (SUCCEEDED(hr
) && pStrRetToBufW
)
1736 hr
= pStrRetToBufW(&strret
, newPIDL
, tempbufW
, sizeof(tempbufW
)/sizeof(WCHAR
));
1737 ok (SUCCEEDED(hr
), "StrRetToBufW failed! hr = %08x\n", hr
);
1739 ok (!lstrcmpiW(tempbufW
, folderdisplayW
) ||
1740 broken(!lstrcmpiW(tempbufW
, foldernameW
)), /* W2K */
1741 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW
));
1744 /* editing name is also read from the resource */
1745 hr
= IShellFolder_GetDisplayNameOf(testIShellFolder
, newPIDL
, SHGDN_INFOLDER
|SHGDN_FOREDITING
, &strret
);
1746 ok(hr
== S_OK
, "GetDisplayNameOf failed %08x\n", hr
);
1748 if (SUCCEEDED(hr
) && pStrRetToBufW
)
1750 hr
= pStrRetToBufW(&strret
, newPIDL
, tempbufW
, sizeof(tempbufW
)/sizeof(WCHAR
));
1751 ok (SUCCEEDED(hr
), "StrRetToBufW failed! hr = %08x\n", hr
);
1753 ok (!lstrcmpiW(tempbufW
, folderdisplayW
) ||
1754 broken(!lstrcmpiW(tempbufW
, foldernameW
)), /* W2K */
1755 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW
));
1758 /* parsing name is unchanged */
1759 hr
= IShellFolder_GetDisplayNameOf(testIShellFolder
, newPIDL
, SHGDN_INFOLDER
|SHGDN_FORPARSING
, &strret
);
1760 ok(hr
== S_OK
, "GetDisplayNameOf failed %08x\n", hr
);
1762 if (SUCCEEDED(hr
) && pStrRetToBufW
)
1764 hr
= pStrRetToBufW(&strret
, newPIDL
, tempbufW
, sizeof(tempbufW
)/sizeof(WCHAR
));
1765 ok (SUCCEEDED(hr
), "StrRetToBufW failed! hr = %08x\n", hr
);
1766 ok (!lstrcmpiW(tempbufW
, foldernameW
), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW
));
1769 IShellFolder_Release(IDesktopFolder
);
1770 IShellFolder_Release(testIShellFolder
);
1772 IMalloc_Free(ppM
, newPIDL
);
1775 DeleteFileA(".\\testfolder\\desktop.ini");
1776 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM
);
1777 RemoveDirectoryA(".\\testfolder");
1780 static void test_SHCreateShellItem(void)
1782 IShellItem
*shellitem
, *shellitem2
;
1783 IPersistIDList
*persistidl
;
1784 LPITEMIDLIST pidl_cwd
=NULL
, pidl_testfile
, pidl_abstestfile
, pidl_test
;
1786 char curdirA
[MAX_PATH
];
1787 WCHAR curdirW
[MAX_PATH
];
1788 IShellFolder
*desktopfolder
=NULL
, *currentfolder
=NULL
;
1789 static WCHAR testfileW
[] = {'t','e','s','t','f','i','l','e',0};
1791 GetCurrentDirectoryA(MAX_PATH
, curdirA
);
1793 if (!lstrlenA(curdirA
))
1795 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
1799 MultiByteToWideChar(CP_ACP
, 0, curdirA
, -1, curdirW
, MAX_PATH
);
1801 ret
= SHGetDesktopFolder(&desktopfolder
);
1802 ok(SUCCEEDED(ret
), "SHGetShellFolder returned %x\n", ret
);
1804 ret
= IShellFolder_ParseDisplayName(desktopfolder
, NULL
, NULL
, curdirW
, NULL
, &pidl_cwd
, NULL
);
1805 ok(SUCCEEDED(ret
), "ParseDisplayName returned %x\n", ret
);
1807 ret
= IShellFolder_BindToObject(desktopfolder
, pidl_cwd
, NULL
, &IID_IShellFolder
, (void**)¤tfolder
);
1808 ok(SUCCEEDED(ret
), "BindToObject returned %x\n", ret
);
1810 CreateTestFile(".\\testfile");
1812 ret
= IShellFolder_ParseDisplayName(currentfolder
, NULL
, NULL
, testfileW
, NULL
, &pidl_testfile
, NULL
);
1813 ok(SUCCEEDED(ret
), "ParseDisplayName returned %x\n", ret
);
1815 pidl_abstestfile
= pILCombine(pidl_cwd
, pidl_testfile
);
1817 ret
= pSHCreateShellItem(NULL
, NULL
, NULL
, &shellitem
);
1818 ok(ret
== E_INVALIDARG
, "SHCreateShellItem returned %x\n", ret
);
1820 if (0) /* crashes on Windows XP */
1822 pSHCreateShellItem(NULL
, NULL
, pidl_cwd
, NULL
);
1823 pSHCreateShellItem(pidl_cwd
, NULL
, NULL
, &shellitem
);
1824 pSHCreateShellItem(NULL
, currentfolder
, NULL
, &shellitem
);
1825 pSHCreateShellItem(pidl_cwd
, currentfolder
, NULL
, &shellitem
);
1828 ret
= pSHCreateShellItem(NULL
, NULL
, pidl_cwd
, &shellitem
);
1829 ok(SUCCEEDED(ret
), "SHCreateShellItem returned %x\n", ret
);
1832 ret
= IShellItem_QueryInterface(shellitem
, &IID_IPersistIDList
, (void**)&persistidl
);
1833 ok(SUCCEEDED(ret
), "QueryInterface returned %x\n", ret
);
1836 ret
= IPersistIDList_GetIDList(persistidl
, &pidl_test
);
1837 ok(SUCCEEDED(ret
), "GetIDList returned %x\n", ret
);
1840 ok(ILIsEqual(pidl_cwd
, pidl_test
), "id lists are not equal\n");
1843 IPersistIDList_Release(persistidl
);
1845 IShellItem_Release(shellitem
);
1848 ret
= pSHCreateShellItem(pidl_cwd
, NULL
, pidl_testfile
, &shellitem
);
1849 ok(SUCCEEDED(ret
), "SHCreateShellItem returned %x\n", ret
);
1852 ret
= IShellItem_QueryInterface(shellitem
, &IID_IPersistIDList
, (void**)&persistidl
);
1853 ok(SUCCEEDED(ret
), "QueryInterface returned %x\n", ret
);
1856 ret
= IPersistIDList_GetIDList(persistidl
, &pidl_test
);
1857 ok(SUCCEEDED(ret
), "GetIDList returned %x\n", ret
);
1860 ok(ILIsEqual(pidl_abstestfile
, pidl_test
), "id lists are not equal\n");
1863 IPersistIDList_Release(persistidl
);
1866 ret
= IShellItem_GetParent(shellitem
, &shellitem2
);
1867 ok(SUCCEEDED(ret
), "GetParent returned %x\n", ret
);
1870 ret
= IShellItem_QueryInterface(shellitem2
, &IID_IPersistIDList
, (void**)&persistidl
);
1871 ok(SUCCEEDED(ret
), "QueryInterface returned %x\n", ret
);
1874 ret
= IPersistIDList_GetIDList(persistidl
, &pidl_test
);
1875 ok(SUCCEEDED(ret
), "GetIDList returned %x\n", ret
);
1878 ok(ILIsEqual(pidl_cwd
, pidl_test
), "id lists are not equal\n");
1881 IPersistIDList_Release(persistidl
);
1883 IShellItem_Release(shellitem2
);
1886 IShellItem_Release(shellitem
);
1889 ret
= pSHCreateShellItem(NULL
, currentfolder
, pidl_testfile
, &shellitem
);
1890 ok(SUCCEEDED(ret
), "SHCreateShellItem returned %x\n", ret
);
1893 ret
= IShellItem_QueryInterface(shellitem
, &IID_IPersistIDList
, (void**)&persistidl
);
1894 ok(SUCCEEDED(ret
), "QueryInterface returned %x\n", ret
);
1897 ret
= IPersistIDList_GetIDList(persistidl
, &pidl_test
);
1898 ok(SUCCEEDED(ret
), "GetIDList returned %x\n", ret
);
1901 ok(ILIsEqual(pidl_abstestfile
, pidl_test
), "id lists are not equal\n");
1904 IPersistIDList_Release(persistidl
);
1906 IShellItem_Release(shellitem
);
1909 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
1910 ret
= pSHCreateShellItem(pidl_cwd
, desktopfolder
, pidl_testfile
, &shellitem
);
1911 ok(SUCCEEDED(ret
), "SHCreateShellItem returned %x\n", ret
);
1914 ret
= IShellItem_QueryInterface(shellitem
, &IID_IPersistIDList
, (void**)&persistidl
);
1915 ok(SUCCEEDED(ret
), "QueryInterface returned %x\n", ret
);
1918 ret
= IPersistIDList_GetIDList(persistidl
, &pidl_test
);
1919 ok(SUCCEEDED(ret
), "GetIDList returned %x\n", ret
);
1922 ok(ILIsEqual(pidl_abstestfile
, pidl_test
), "id lists are not equal\n");
1925 IPersistIDList_Release(persistidl
);
1927 IShellItem_Release(shellitem
);
1930 DeleteFileA(".\\testfile");
1931 pILFree(pidl_abstestfile
);
1932 pILFree(pidl_testfile
);
1934 IShellFolder_Release(currentfolder
);
1935 IShellFolder_Release(desktopfolder
);
1938 START_TEST(shlfolder
)
1940 init_function_pointers();
1941 /* if OleInitialize doesn't get called, ParseDisplayName returns
1942 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
1943 OleInitialize(NULL
);
1945 test_ParseDisplayName();
1946 test_BindToObject();
1947 test_EnumObjects_and_CompareIDs();
1948 test_GetDisplayName();
1949 test_GetAttributesOf();
1950 test_SHGetPathFromIDList();
1951 test_CallForAttributes();
1952 test_FolderShortcut();
1953 test_ITEMIDLIST_format();
1954 if(pSHGetFolderPathAndSubDirA
)
1955 testSHGetFolderPathAndSubDirA();
1957 win_skip("SHGetFolderPathAndSubDirA not present\n");
1958 test_LocalizedNames();
1959 if(pSHCreateShellItem
)
1960 test_SHCreateShellItem();
1962 win_skip("SHCreateShellItem not present\n");