shell32: Implement IShellItem::Compare.
[wine/multimedia.git] / dlls / shell32 / tests / shlfolder.c
blob2781b233c9c646c7fa7b5bd27680e834126b5d8b
1 /*
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
21 #include <stdarg.h>
22 #include <stdio.h>
24 #define COBJMACROS
25 #define CONST_VTABLE
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wtypes.h"
30 #include "shellapi.h"
33 #include "shlguid.h"
34 #include "shlobj.h"
35 #include "shobjidl.h"
36 #include "shlwapi.h"
37 #include "ocidl.h"
38 #include "oleauto.h"
40 #include "wine/test.h"
42 #include <initguid.h>
43 DEFINE_GUID(IID_IParentAndItem, 0xB3A4B685, 0xB685, 0x4805, 0x99,0xD9, 0x5D,0xEA,0xD2,0x87,0x32,0x36);
45 static IMalloc *ppM;
47 static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
48 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
49 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
50 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
51 static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
52 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
53 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
54 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
55 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
56 static void (WINAPI *pILFree)(LPITEMIDLIST);
57 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
58 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
59 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
60 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
61 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
62 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
63 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
64 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
65 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
66 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
67 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
69 static void init_function_pointers(void)
71 HMODULE hmod;
72 HRESULT hr;
73 void *ptr;
75 hmod = GetModuleHandleA("shell32.dll");
77 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
78 MAKEFUNC(SHBindToParent);
79 MAKEFUNC(SHCreateItemFromIDList);
80 MAKEFUNC(SHCreateItemFromParsingName);
81 MAKEFUNC(SHCreateShellItem);
82 MAKEFUNC(SHGetFolderPathA);
83 MAKEFUNC(SHGetFolderPathAndSubDirA);
84 MAKEFUNC(SHGetPathFromIDListW);
85 MAKEFUNC(SHGetSpecialFolderPathA);
86 MAKEFUNC(SHGetSpecialFolderPathW);
87 MAKEFUNC(SHGetSpecialFolderLocation);
88 MAKEFUNC(SHParseDisplayName);
89 MAKEFUNC(SHGetNameFromIDList);
90 MAKEFUNC(SHGetItemFromDataObject);
91 MAKEFUNC(SHGetIDListFromObject);
92 MAKEFUNC(SHGetItemFromObject);
93 #undef MAKEFUNC
95 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
96 MAKEFUNC_ORD(ILFindLastID, 16);
97 MAKEFUNC_ORD(ILIsEqual, 21);
98 MAKEFUNC_ORD(ILCombine, 25);
99 MAKEFUNC_ORD(ILFree, 155);
100 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
101 #undef MAKEFUNC_ORD
103 /* test named exports */
104 ptr = GetProcAddress(hmod, "ILFree");
105 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
106 if (ptr)
108 #define TESTNAMED(f) \
109 ptr = (void*)GetProcAddress(hmod, #f); \
110 ok(ptr != 0, "expected named export for " #f "\n");
112 TESTNAMED(ILAppendID);
113 TESTNAMED(ILClone);
114 TESTNAMED(ILCloneFirst);
115 TESTNAMED(ILCombine);
116 TESTNAMED(ILCreateFromPath);
117 TESTNAMED(ILCreateFromPathA);
118 TESTNAMED(ILCreateFromPathW);
119 TESTNAMED(ILFindChild);
120 TESTNAMED(ILFindLastID);
121 TESTNAMED(ILGetNext);
122 TESTNAMED(ILGetSize);
123 TESTNAMED(ILIsEqual);
124 TESTNAMED(ILIsParent);
125 TESTNAMED(ILRemoveLastID);
126 TESTNAMED(ILSaveToStream);
127 #undef TESTNAMED
130 hmod = GetModuleHandleA("shlwapi.dll");
131 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
133 hr = SHGetMalloc(&ppM);
134 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
137 static void test_ParseDisplayName(void)
139 HRESULT hr;
140 IShellFolder *IDesktopFolder;
141 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
142 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
143 static const char *cInetTestA = "http:\\yyy";
144 static const char *cInetTest2A = "xx:yyy";
145 DWORD res;
146 WCHAR cTestDirW [MAX_PATH] = {0};
147 ITEMIDLIST *newPIDL;
148 BOOL bRes;
150 hr = SHGetDesktopFolder(&IDesktopFolder);
151 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
152 if(hr != S_OK) return;
154 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
155 if (pSHCreateShellItem)
157 /* null name and pidl */
158 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
159 NULL, NULL, NULL, NULL, NULL, 0);
160 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
162 /* null name */
163 newPIDL = (ITEMIDLIST*)0xdeadbeef;
164 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
165 NULL, NULL, NULL, NULL, &newPIDL, 0);
166 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
167 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
169 else
170 win_skip("Tests would crash on W2K and below\n");
172 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
173 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
174 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
175 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
176 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
177 if (hr == S_OK)
179 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
180 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
181 IMalloc_Free(ppM, newPIDL);
184 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
185 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
186 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
187 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
188 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
189 if (hr == S_OK)
191 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
192 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
193 IMalloc_Free(ppM, newPIDL);
196 res = GetFileAttributesA(cNonExistDir1A);
197 if(res != INVALID_FILE_ATTRIBUTES)
199 skip("Test directory unexpectedly exists\n");
200 goto finished;
203 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
204 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
205 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
206 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
207 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
209 res = GetFileAttributesA(cNonExistDir2A);
210 if(res != INVALID_FILE_ATTRIBUTES)
212 skip("Test directory unexpectedly exists\n");
213 goto finished;
216 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
217 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
218 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
219 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
220 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
222 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
223 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
224 * out it doesn't. The magic seems to happen in the file dialogs, then. */
225 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
227 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
228 goto finished;
231 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
232 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
233 if (!bRes) goto finished;
235 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
236 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
237 if (hr != S_OK) goto finished;
239 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
240 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
241 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
242 pILFindLastID(newPIDL)->mkid.abID[0]);
243 IMalloc_Free(ppM, newPIDL);
245 finished:
246 IShellFolder_Release(IDesktopFolder);
249 /* creates a file with the specified name for tests */
250 static void CreateTestFile(const CHAR *name)
252 HANDLE file;
253 DWORD written;
255 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
256 if (file != INVALID_HANDLE_VALUE)
258 WriteFile(file, name, strlen(name), &written, NULL);
259 WriteFile(file, "\n", strlen("\n"), &written, NULL);
260 CloseHandle(file);
265 /* initializes the tests */
266 static void CreateFilesFolders(void)
268 CreateDirectoryA(".\\testdir", NULL);
269 CreateDirectoryA(".\\testdir\\test.txt", NULL);
270 CreateTestFile (".\\testdir\\test1.txt ");
271 CreateTestFile (".\\testdir\\test2.txt ");
272 CreateTestFile (".\\testdir\\test3.txt ");
273 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
274 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
277 /* cleans after tests */
278 static void Cleanup(void)
280 DeleteFileA(".\\testdir\\test1.txt");
281 DeleteFileA(".\\testdir\\test2.txt");
282 DeleteFileA(".\\testdir\\test3.txt");
283 RemoveDirectoryA(".\\testdir\\test.txt");
284 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
285 RemoveDirectoryA(".\\testdir\\testdir2");
286 RemoveDirectoryA(".\\testdir");
290 /* perform test */
291 static void test_EnumObjects(IShellFolder *iFolder)
293 IEnumIDList *iEnumList;
294 LPITEMIDLIST newPIDL, idlArr[10];
295 ULONG NumPIDLs;
296 int i=0, j;
297 HRESULT hr;
299 static const WORD iResults [5][5] =
301 { 0,-1,-1,-1,-1},
302 { 1, 0,-1,-1,-1},
303 { 1, 1, 0,-1,-1},
304 { 1, 1, 1, 0,-1},
305 { 1, 1, 1, 1, 0}
308 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
309 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
310 static const ULONG attrs[5] =
312 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
313 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
314 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
315 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
316 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
319 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
320 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
322 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
323 * the filesystem shellfolders return S_OK even if less than 'celt' items are
324 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
325 * only ever returns a single entry per call. */
326 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
327 i += NumPIDLs;
328 ok (i == 5, "i: %d\n", i);
330 hr = IEnumIDList_Release(iEnumList);
331 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
333 /* Sort them first in case of wrong order from system */
334 for (i=0;i<5;i++) for (j=0;j<5;j++)
335 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
337 newPIDL = idlArr[i];
338 idlArr[i] = idlArr[j];
339 idlArr[j] = newPIDL;
342 for (i=0;i<5;i++) for (j=0;j<5;j++)
344 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
345 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
349 for (i = 0; i < 5; i++)
351 SFGAOF flags;
352 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
353 /* Native returns all flags no matter what we ask for */
354 flags = SFGAO_CANCOPY;
355 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
356 flags &= SFGAO_testfor;
357 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
358 ok(flags == (attrs[i]) ||
359 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
360 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
361 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
363 flags = SFGAO_testfor;
364 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
365 flags &= SFGAO_testfor;
366 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
367 ok(flags == attrs[i] ||
368 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
369 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
372 for (i=0;i<5;i++)
373 IMalloc_Free(ppM, idlArr[i]);
376 static void test_BindToObject(void)
378 HRESULT hr;
379 UINT cChars;
380 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
381 SHITEMID emptyitem = { 0, { 0 } };
382 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
383 WCHAR wszSystemDir[MAX_PATH];
384 char szSystemDir[MAX_PATH];
385 WCHAR wszMyComputer[] = {
386 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
387 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
389 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
390 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
392 hr = SHGetDesktopFolder(&psfDesktop);
393 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
394 if (hr != S_OK) return;
396 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
397 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
399 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
400 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
402 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
403 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
404 if (hr != S_OK) {
405 IShellFolder_Release(psfDesktop);
406 return;
409 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
410 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
411 IShellFolder_Release(psfDesktop);
412 IMalloc_Free(ppM, pidlMyComputer);
413 if (hr != S_OK) return;
415 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
416 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
418 if (0)
420 /* this call segfaults on 98SE */
421 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
422 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
425 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
426 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
427 if (cChars == 0 || cChars >= MAX_PATH) {
428 IShellFolder_Release(psfMyComputer);
429 return;
431 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
433 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
434 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
435 if (hr != S_OK) {
436 IShellFolder_Release(psfMyComputer);
437 return;
440 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
441 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
442 IShellFolder_Release(psfMyComputer);
443 IMalloc_Free(ppM, pidlSystemDir);
444 if (hr != S_OK) return;
446 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
447 ok (hr == E_INVALIDARG,
448 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
450 if (0)
452 /* this call segfaults on 98SE */
453 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
454 ok (hr == E_INVALIDARG,
455 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
458 IShellFolder_Release(psfSystemDir);
461 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
462 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
464 size_t iLen;
466 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
467 return NULL;
469 if (iLen)
471 lpszPath += iLen;
472 if (lpszPath[-1] != '\\')
474 *lpszPath++ = '\\';
475 *lpszPath = '\0';
478 return lpszPath;
481 static void test_GetDisplayName(void)
483 BOOL result;
484 HRESULT hr;
485 HANDLE hTestFile;
486 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
487 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
488 DWORD attr;
489 STRRET strret;
490 LPSHELLFOLDER psfDesktop, psfPersonal;
491 IUnknown *psfFile;
492 SHITEMID emptyitem = { 0, { 0 } };
493 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
494 LPCITEMIDLIST pidlLast;
495 static const CHAR szFileName[] = "winetest.foo";
496 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
497 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
499 /* I'm trying to figure if there is a functional difference between calling
500 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
501 * binding to the shellfolder. One thing I thought of was that perhaps
502 * SHGetPathFromIDListW would be able to get the path to a file, which does
503 * not exist anymore, while the other method wouldn't. It turns out there's
504 * no functional difference in this respect.
507 if(!pSHGetSpecialFolderPathA) {
508 win_skip("SHGetSpecialFolderPathA is not available\n");
509 return;
512 /* First creating a directory in MyDocuments and a file in this directory. */
513 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
514 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
515 if (!result) return;
517 /* Use ANSI file functions so this works on Windows 9x */
518 lstrcatA(szTestDir, "\\winetest");
519 CreateDirectoryA(szTestDir, NULL);
520 attr=GetFileAttributesA(szTestDir);
521 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
523 ok(0, "unable to create the '%s' directory\n", szTestDir);
524 return;
527 lstrcpyA(szTestFile, szTestDir);
528 lstrcatA(szTestFile, "\\");
529 lstrcatA(szTestFile, szFileName);
530 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
531 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
532 if (hTestFile == INVALID_HANDLE_VALUE) return;
533 CloseHandle(hTestFile);
535 /* Getting an itemidlist for the file. */
536 hr = SHGetDesktopFolder(&psfDesktop);
537 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
538 if (hr != S_OK) return;
540 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
542 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
543 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
544 if (hr != S_OK) {
545 IShellFolder_Release(psfDesktop);
546 return;
549 pidlLast = pILFindLastID(pidlTestFile);
550 ok(pidlLast->mkid.cb >=76 ||
551 broken(pidlLast->mkid.cb == 28) || /* W2K */
552 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
553 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
554 if (pidlLast->mkid.cb >= 28) {
555 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
556 "Filename should be stored as ansi-string at this position!\n");
558 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
559 if (pidlLast->mkid.cb >= 76) {
560 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
561 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
562 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
563 "Filename should be stored as wchar-string at this position!\n");
566 /* It seems as if we cannot bind to regular files on windows, but only directories.
568 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
569 todo_wine
570 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
571 hr == E_NOTIMPL || /* Vista */
572 broken(hr == S_OK), /* Win9x, W2K */
573 "hr = %08x\n", hr);
574 if (hr == S_OK) {
575 IShellFolder_Release(psfFile);
578 if (!pSHBindToParent)
580 win_skip("SHBindToParent is missing\n");
581 DeleteFileA(szTestFile);
582 RemoveDirectoryA(szTestDir);
583 return;
586 /* Some tests for IShellFolder::SetNameOf */
587 if (pSHGetFolderPathAndSubDirA)
589 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
590 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
591 if (hr == S_OK) {
592 /* It's ok to use this fixed path. Call will fail anyway. */
593 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
594 LPITEMIDLIST pidlNew;
596 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
597 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
598 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
599 if (hr == S_OK)
601 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
602 "pidl returned from SetNameOf should be simple!\n");
604 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
605 * is implemented on top of SHFileOperation in WinXP. */
606 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
607 SHGDN_FORPARSING, NULL);
608 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
610 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
611 * SHGDN flags specify an absolute path. */
612 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
613 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
615 pILFree(pidlNew);
618 IShellFolder_Release(psfPersonal);
621 else
622 win_skip("Avoid needs of interaction on Win2k\n");
624 /* Deleting the file and the directory */
625 DeleteFileA(szTestFile);
626 RemoveDirectoryA(szTestDir);
628 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
629 if (pSHGetPathFromIDListW)
631 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
632 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
633 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
636 /* SHBindToParent fails, if called with a NULL PIDL. */
637 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
638 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
640 /* But it succeeds with an empty PIDL. */
641 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
642 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
643 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
644 if (hr == S_OK)
645 IShellFolder_Release(psfPersonal);
647 /* Binding to the folder and querying the display name of the file also works. */
648 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
649 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
650 if (hr != S_OK) {
651 IShellFolder_Release(psfDesktop);
652 return;
655 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
656 * pidlTestFile (In accordance with MSDN). */
657 ok (pILFindLastID(pidlTestFile) == pidlLast,
658 "SHBindToParent doesn't return the last id of the pidl param!\n");
660 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
661 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
662 if (hr != S_OK) {
663 IShellFolder_Release(psfDesktop);
664 IShellFolder_Release(psfPersonal);
665 return;
668 if (pStrRetToBufW)
670 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
671 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
672 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
675 ILFree(pidlTestFile);
676 IShellFolder_Release(psfDesktop);
677 IShellFolder_Release(psfPersonal);
680 static void test_CallForAttributes(void)
682 HKEY hKey;
683 LONG lResult;
684 HRESULT hr;
685 DWORD dwSize;
686 LPSHELLFOLDER psfDesktop;
687 LPITEMIDLIST pidlMyDocuments;
688 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
689 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
690 static const WCHAR wszCallForAttributes[] = {
691 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
692 static const WCHAR wszMyDocumentsKey[] = {
693 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
694 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
695 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
696 WCHAR wszMyDocuments[] = {
697 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
698 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
700 /* For the root of a namespace extension, the attributes are not queried by binding
701 * to the object and calling GetAttributesOf. Instead, the attributes are read from
702 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
704 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
705 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
706 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
707 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
709 hr = SHGetDesktopFolder(&psfDesktop);
710 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
711 if (hr != S_OK) return;
713 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
714 &pidlMyDocuments, NULL);
715 ok (hr == S_OK ||
716 broken(hr == E_INVALIDARG), /* Win95, NT4 */
717 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
718 if (hr != S_OK) {
719 IShellFolder_Release(psfDesktop);
720 return;
723 dwAttributes = 0xffffffff;
724 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
725 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
726 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
728 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
729 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
730 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
731 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
733 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
734 * key. So the test will return at this point, if run on wine.
736 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
737 ok (lResult == ERROR_SUCCESS ||
738 lResult == ERROR_ACCESS_DENIED,
739 "RegOpenKeyEx failed! result: %08x\n", lResult);
740 if (lResult != ERROR_SUCCESS) {
741 if (lResult == ERROR_ACCESS_DENIED)
742 skip("Not enough rights to open the registry key\n");
743 IMalloc_Free(ppM, pidlMyDocuments);
744 IShellFolder_Release(psfDesktop);
745 return;
748 /* Query MyDocuments' Attributes value, to be able to restore it later. */
749 dwSize = sizeof(DWORD);
750 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
751 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
752 if (lResult != ERROR_SUCCESS) {
753 RegCloseKey(hKey);
754 IMalloc_Free(ppM, pidlMyDocuments);
755 IShellFolder_Release(psfDesktop);
756 return;
759 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
760 dwSize = sizeof(DWORD);
761 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
762 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
763 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
764 if (lResult != ERROR_SUCCESS) {
765 RegCloseKey(hKey);
766 IMalloc_Free(ppM, pidlMyDocuments);
767 IShellFolder_Release(psfDesktop);
768 return;
771 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
772 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
773 * SFGAO_FILESYSTEM attributes. */
774 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
775 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
776 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
777 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
778 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
780 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
781 * GetAttributesOf. It seems that once there is a single attribute queried, for which
782 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
783 * the flags in Attributes are ignored.
785 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
786 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
787 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
788 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
789 if (hr == S_OK)
790 ok (dwAttributes == SFGAO_FILESYSTEM,
791 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
792 dwAttributes);
794 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
795 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
796 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
797 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
798 RegCloseKey(hKey);
799 IMalloc_Free(ppM, pidlMyDocuments);
800 IShellFolder_Release(psfDesktop);
803 static void test_GetAttributesOf(void)
805 HRESULT hr;
806 LPSHELLFOLDER psfDesktop, psfMyComputer;
807 SHITEMID emptyitem = { 0, { 0 } };
808 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
809 LPITEMIDLIST pidlMyComputer;
810 DWORD dwFlags;
811 static const DWORD desktopFlags[] = {
812 /* WinXP */
813 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
814 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
815 /* Win2k */
816 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
817 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
818 /* WinMe, Win9x, WinNT*/
819 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
820 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
822 static const DWORD myComputerFlags[] = {
823 /* WinXP */
824 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
825 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
826 /* Win2k */
827 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
828 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
829 /* WinMe, Win9x, WinNT */
830 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
831 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
832 /* Win95, WinNT when queried directly */
833 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
834 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
836 WCHAR wszMyComputer[] = {
837 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
838 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
839 char cCurrDirA [MAX_PATH] = {0};
840 WCHAR cCurrDirW [MAX_PATH];
841 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
842 IShellFolder *IDesktopFolder, *testIShellFolder;
843 ITEMIDLIST *newPIDL;
844 int len, i;
845 BOOL foundFlagsMatch;
847 hr = SHGetDesktopFolder(&psfDesktop);
848 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
849 if (hr != S_OK) return;
851 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
852 dwFlags = 0xffffffff;
853 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
854 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
855 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
856 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
858 if (desktopFlags[i] == dwFlags)
859 foundFlagsMatch = TRUE;
861 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
863 /* .. or with no itemidlist at all. */
864 dwFlags = 0xffffffff;
865 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
866 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
867 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
868 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
870 if (desktopFlags[i] == dwFlags)
871 foundFlagsMatch = TRUE;
873 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
875 /* Testing the attributes of the MyComputer shellfolder */
876 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
877 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
878 if (hr != S_OK) {
879 IShellFolder_Release(psfDesktop);
880 return;
883 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
884 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
886 dwFlags = 0xffffffff;
887 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
888 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
889 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
890 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
892 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
893 foundFlagsMatch = TRUE;
895 todo_wine
896 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
898 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
899 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
900 IShellFolder_Release(psfDesktop);
901 IMalloc_Free(ppM, pidlMyComputer);
902 if (hr != S_OK) return;
904 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
905 todo_wine
906 ok (hr == E_INVALIDARG ||
907 broken(hr == S_OK), /* W2K and earlier */
908 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
910 dwFlags = 0xffffffff;
911 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
912 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
913 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
914 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
916 if (myComputerFlags[i] == dwFlags)
917 foundFlagsMatch = TRUE;
919 todo_wine
920 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
922 IShellFolder_Release(psfMyComputer);
924 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
925 len = lstrlenA(cCurrDirA);
927 if (len == 0) {
928 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
929 return;
931 if (len > 3 && cCurrDirA[len-1] == '\\')
932 cCurrDirA[len-1] = 0;
934 /* create test directory */
935 CreateFilesFolders();
937 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
939 hr = SHGetDesktopFolder(&IDesktopFolder);
940 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
942 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
943 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
945 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
946 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
948 IMalloc_Free(ppM, newPIDL);
950 /* get relative PIDL */
951 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
952 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
954 /* test the shell attributes of the test directory using the relative PIDL */
955 dwFlags = SFGAO_FOLDER;
956 hr = IShellFolder_GetAttributesOf(testIShellFolder, 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 relative PIDL: %08x\n", dwFlags);
960 /* free memory */
961 IMalloc_Free(ppM, newPIDL);
963 /* append testdirectory name to path */
964 if (cCurrDirA[len-1] == '\\')
965 cCurrDirA[len-1] = 0;
966 lstrcatA(cCurrDirA, "\\testdir");
967 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
969 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
970 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
972 /* test the shell attributes of the test directory using the absolute PIDL */
973 dwFlags = SFGAO_FOLDER;
974 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
975 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
976 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
978 /* free memory */
979 IMalloc_Free(ppM, newPIDL);
981 IShellFolder_Release(testIShellFolder);
983 Cleanup();
985 IShellFolder_Release(IDesktopFolder);
988 static void test_SHGetPathFromIDList(void)
990 SHITEMID emptyitem = { 0, { 0 } };
991 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
992 LPITEMIDLIST pidlMyComputer;
993 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
994 BOOL result;
995 HRESULT hr;
996 LPSHELLFOLDER psfDesktop;
997 WCHAR wszMyComputer[] = {
998 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
999 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1000 WCHAR wszFileName[MAX_PATH];
1001 LPITEMIDLIST pidlTestFile;
1002 HANDLE hTestFile;
1003 STRRET strret;
1004 static WCHAR wszTestFile[] = {
1005 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1006 LPITEMIDLIST pidlPrograms;
1008 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1010 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1011 return;
1014 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1015 wszPath[0] = 'a';
1016 wszPath[1] = '\0';
1017 result = pSHGetPathFromIDListW(NULL, wszPath);
1018 ok(!result, "Expected failure\n");
1019 ok(!wszPath[0], "Expected empty string\n");
1021 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1022 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1023 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1024 if (!result) return;
1026 /* Check if we are on Win9x */
1027 SetLastError(0xdeadbeef);
1028 lstrcmpiW(wszDesktop, wszDesktop);
1029 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1031 win_skip("Most W-calls are not implemented\n");
1032 return;
1035 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1036 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1037 if (!result) return;
1038 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1040 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1041 hr = SHGetDesktopFolder(&psfDesktop);
1042 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1043 if (hr != S_OK) return;
1045 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1046 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1047 if (hr != S_OK) {
1048 IShellFolder_Release(psfDesktop);
1049 return;
1052 SetLastError(0xdeadbeef);
1053 wszPath[0] = 'a';
1054 wszPath[1] = '\0';
1055 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1056 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1057 ok (GetLastError()==0xdeadbeef ||
1058 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1059 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1060 ok (!wszPath[0], "Expected empty path\n");
1061 if (result) {
1062 IShellFolder_Release(psfDesktop);
1063 return;
1066 IMalloc_Free(ppM, pidlMyComputer);
1068 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1069 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1070 if (!result) {
1071 IShellFolder_Release(psfDesktop);
1072 return;
1074 myPathAddBackslashW(wszFileName);
1075 lstrcatW(wszFileName, wszTestFile);
1076 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1077 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1078 if (hTestFile == INVALID_HANDLE_VALUE) {
1079 IShellFolder_Release(psfDesktop);
1080 return;
1082 CloseHandle(hTestFile);
1084 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1085 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1086 if (hr != S_OK) {
1087 IShellFolder_Release(psfDesktop);
1088 DeleteFileW(wszFileName);
1089 IMalloc_Free(ppM, pidlTestFile);
1090 return;
1093 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1094 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1095 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1096 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1097 IShellFolder_Release(psfDesktop);
1098 DeleteFileW(wszFileName);
1099 if (hr != S_OK) {
1100 IMalloc_Free(ppM, pidlTestFile);
1101 return;
1103 if (pStrRetToBufW)
1105 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1106 ok(0 == lstrcmpW(wszFileName, wszPath),
1107 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1108 "returned incorrect path for file placed on desktop\n");
1111 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1112 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1113 IMalloc_Free(ppM, pidlTestFile);
1114 if (!result) return;
1115 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1118 /* Test if we can get the path from the start menu "program files" PIDL. */
1119 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1120 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1122 SetLastError(0xdeadbeef);
1123 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1124 IMalloc_Free(ppM, pidlPrograms);
1125 ok(result, "SHGetPathFromIDListW failed\n");
1128 static void test_EnumObjects_and_CompareIDs(void)
1130 ITEMIDLIST *newPIDL;
1131 IShellFolder *IDesktopFolder, *testIShellFolder;
1132 char cCurrDirA [MAX_PATH] = {0};
1133 static const CHAR cTestDirA[] = "\\testdir";
1134 WCHAR cTestDirW[MAX_PATH];
1135 int len;
1136 HRESULT hr;
1138 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1139 len = lstrlenA(cCurrDirA);
1141 if(len == 0) {
1142 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1143 return;
1145 if(cCurrDirA[len-1] == '\\')
1146 cCurrDirA[len-1] = 0;
1148 lstrcatA(cCurrDirA, cTestDirA);
1149 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1151 hr = SHGetDesktopFolder(&IDesktopFolder);
1152 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1154 CreateFilesFolders();
1156 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1157 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1159 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1160 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1162 test_EnumObjects(testIShellFolder);
1164 IShellFolder_Release(testIShellFolder);
1166 Cleanup();
1168 IMalloc_Free(ppM, newPIDL);
1170 IShellFolder_Release(IDesktopFolder);
1173 /* A simple implementation of an IPropertyBag, which returns fixed values for
1174 * 'Target' and 'Attributes' properties.
1176 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1177 void **ppvObject)
1179 if (!ppvObject)
1180 return E_INVALIDARG;
1182 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1183 *ppvObject = iface;
1184 } else {
1185 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1186 return E_NOINTERFACE;
1189 IPropertyBag_AddRef(iface);
1190 return S_OK;
1193 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1194 return 2;
1197 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1198 return 1;
1201 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1202 VARIANT *pVar, IErrorLog *pErrorLog)
1204 static const WCHAR wszTargetSpecialFolder[] = {
1205 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1206 static const WCHAR wszTarget[] = {
1207 'T','a','r','g','e','t',0 };
1208 static const WCHAR wszAttributes[] = {
1209 'A','t','t','r','i','b','u','t','e','s',0 };
1210 static const WCHAR wszResolveLinkFlags[] = {
1211 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1212 static const WCHAR wszTargetKnownFolder[] = {
1213 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1214 static const WCHAR wszCLSID[] = {
1215 'C','L','S','I','D',0 };
1217 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1218 ok(V_VT(pVar) == VT_I4 ||
1219 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1220 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1221 return E_INVALIDARG;
1224 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1226 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1227 return E_INVALIDARG;
1230 if (!lstrcmpW(pszPropName, wszTarget)) {
1231 WCHAR wszPath[MAX_PATH];
1232 BOOL result;
1234 ok(V_VT(pVar) == VT_BSTR ||
1235 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1236 "Wrong variant type for 'Target' property!\n");
1237 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1239 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1240 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1241 if (!result) return E_INVALIDARG;
1243 V_BSTR(pVar) = SysAllocString(wszPath);
1244 return S_OK;
1247 if (!lstrcmpW(pszPropName, wszAttributes)) {
1248 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1249 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1250 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1251 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1252 return S_OK;
1255 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1256 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1257 /* TODO */
1258 return E_INVALIDARG;
1261 if (!lstrcmpW(pszPropName, wszCLSID)) {
1262 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1263 /* TODO */
1264 return E_INVALIDARG;
1267 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1268 return E_INVALIDARG;
1271 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1272 VARIANT *pVar)
1274 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1275 return E_NOTIMPL;
1278 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1279 InitPropertyBag_IPropertyBag_QueryInterface,
1280 InitPropertyBag_IPropertyBag_AddRef,
1281 InitPropertyBag_IPropertyBag_Release,
1282 InitPropertyBag_IPropertyBag_Read,
1283 InitPropertyBag_IPropertyBag_Write
1286 static struct IPropertyBag InitPropertyBag = {
1287 &InitPropertyBag_IPropertyBagVtbl
1290 static void test_FolderShortcut(void) {
1291 IPersistPropertyBag *pPersistPropertyBag;
1292 IShellFolder *pShellFolder, *pDesktopFolder;
1293 IPersistFolder3 *pPersistFolder3;
1294 HRESULT hr;
1295 STRRET strret;
1296 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1297 BOOL result;
1298 CLSID clsid;
1299 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1300 HKEY hShellExtKey;
1301 WCHAR wszWineTestFolder[] = {
1302 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1303 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1304 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1305 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1306 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1307 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1308 'N','a','m','e','S','p','a','c','e','\\',
1309 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1310 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1312 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1313 static const GUID CLSID_UnixDosFolder =
1314 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1316 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1317 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1318 return;
1321 if (!pSHGetFolderPathAndSubDirA)
1323 win_skip("FolderShortcut test doesn't work on Win2k\n");
1324 return;
1327 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1328 * via their IPersistPropertyBag interface. And that the target folder
1329 * is taken from the IPropertyBag's 'Target' property.
1331 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1332 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1333 if (hr == REGDB_E_CLASSNOTREG) {
1334 win_skip("CLSID_FolderShortcut is not implemented\n");
1335 return;
1337 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1338 if (hr != S_OK) return;
1340 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1341 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1342 if (hr != S_OK) {
1343 IPersistPropertyBag_Release(pPersistPropertyBag);
1344 return;
1347 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1348 (LPVOID*)&pShellFolder);
1349 IPersistPropertyBag_Release(pPersistPropertyBag);
1350 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1351 if (hr != S_OK) return;
1353 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1354 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1355 if (hr != S_OK) {
1356 IShellFolder_Release(pShellFolder);
1357 return;
1360 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1361 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1362 if (!result) return;
1364 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1365 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1367 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1368 IShellFolder_Release(pShellFolder);
1369 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1370 if (hr != S_OK) return;
1372 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1373 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1374 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1376 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1377 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1378 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1380 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1381 * shell namespace. The target folder, read from the property bag above, remains untouched.
1382 * The following tests show this: The itemidlist for some imaginary shellfolder object
1383 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1384 * itemidlist, but GetDisplayNameOf still returns the path from above.
1386 hr = SHGetDesktopFolder(&pDesktopFolder);
1387 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1388 if (hr != S_OK) return;
1390 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1391 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1392 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1393 RegCloseKey(hShellExtKey);
1394 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1395 &pidlWineTestFolder, NULL);
1396 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1397 IShellFolder_Release(pDesktopFolder);
1398 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1399 if (hr != S_OK) return;
1401 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1402 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1403 if (hr != S_OK) {
1404 IPersistFolder3_Release(pPersistFolder3);
1405 pILFree(pidlWineTestFolder);
1406 return;
1409 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1410 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1411 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1412 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1413 pILFree(pidlCurrentFolder);
1414 pILFree(pidlWineTestFolder);
1416 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1417 IPersistFolder3_Release(pPersistFolder3);
1418 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1419 if (hr != S_OK) return;
1421 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1422 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1423 if (hr != S_OK) {
1424 IShellFolder_Release(pShellFolder);
1425 return;
1428 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1429 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1431 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1432 * but ShellFSFolders. */
1433 myPathAddBackslashW(wszDesktopPath);
1434 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1435 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1436 IShellFolder_Release(pShellFolder);
1437 return;
1440 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1441 &pidlSubFolder, NULL);
1442 RemoveDirectoryW(wszDesktopPath);
1443 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1444 if (hr != S_OK) {
1445 IShellFolder_Release(pShellFolder);
1446 return;
1449 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1450 (LPVOID*)&pPersistFolder3);
1451 IShellFolder_Release(pShellFolder);
1452 pILFree(pidlSubFolder);
1453 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1454 if (hr != S_OK)
1455 return;
1457 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1458 * a little bit and also allow CLSID_UnixDosFolder. */
1459 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1460 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1461 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1462 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1464 IPersistFolder3_Release(pPersistFolder3);
1467 #include "pshpack1.h"
1468 struct FileStructA {
1469 BYTE type;
1470 BYTE dummy;
1471 DWORD dwFileSize;
1472 WORD uFileDate; /* In our current implementation this is */
1473 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1474 WORD uFileAttribs;
1475 CHAR szName[1];
1478 struct FileStructW {
1479 WORD cbLen; /* Length of this element. */
1480 BYTE abFooBar1[6]; /* Beyond any recognition. */
1481 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1482 WORD uTime; /* (this is currently speculation) */
1483 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1484 WORD uTime2; /* (this is currently speculation) */
1485 BYTE abFooBar2[4]; /* Beyond any recognition. */
1486 WCHAR wszName[1]; /* The long filename in unicode. */
1487 /* Just for documentation: Right after the unicode string: */
1488 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1489 * SHITEMID->cb == uOffset + cbLen */
1491 #include "poppack.h"
1493 static void test_ITEMIDLIST_format(void) {
1494 WCHAR wszPersonal[MAX_PATH];
1495 LPSHELLFOLDER psfDesktop, psfPersonal;
1496 LPITEMIDLIST pidlPersonal, pidlFile;
1497 HANDLE hFile;
1498 HRESULT hr;
1499 BOOL bResult;
1500 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1501 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1502 int i;
1504 if (!pSHGetSpecialFolderPathW) return;
1506 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1507 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1508 if (!bResult) return;
1510 SetLastError(0xdeadbeef);
1511 bResult = SetCurrentDirectoryW(wszPersonal);
1512 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1513 win_skip("Most W-calls are not implemented\n");
1514 return;
1516 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1517 if (!bResult) return;
1519 hr = SHGetDesktopFolder(&psfDesktop);
1520 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1521 if (hr != S_OK) return;
1523 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1524 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1525 if (hr != S_OK) {
1526 IShellFolder_Release(psfDesktop);
1527 return;
1530 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1531 (LPVOID*)&psfPersonal);
1532 IShellFolder_Release(psfDesktop);
1533 pILFree(pidlPersonal);
1534 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1535 if (hr != S_OK) return;
1537 for (i=0; i<3; i++) {
1538 CHAR szFile[MAX_PATH];
1539 struct FileStructA *pFileStructA;
1540 WORD cbOffset;
1542 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1544 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1545 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1546 if (hFile == INVALID_HANDLE_VALUE) {
1547 IShellFolder_Release(psfPersonal);
1548 return;
1550 CloseHandle(hFile);
1552 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1553 DeleteFileW(wszFile[i]);
1554 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1555 if (hr != S_OK) {
1556 IShellFolder_Release(psfPersonal);
1557 return;
1560 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1561 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1562 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1563 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1565 if (i < 2) /* First two file names are already in valid 8.3 format */
1566 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1567 else
1568 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1569 * can't implement this correctly, since unix filesystems don't support
1570 * this nasty short/long filename stuff. So we'll probably stay with our
1571 * current habbit of storing the long filename here, which seems to work
1572 * just fine. */
1573 todo_wine
1574 ok(pidlFile->mkid.abID[18] == '~' ||
1575 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1576 "Should be derived 8.3 name!\n");
1578 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1579 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1580 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1581 "Alignment byte, where there shouldn't be!\n");
1583 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1584 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1585 "There should be an alignment byte, but isn't!\n");
1587 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1588 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1589 ok ((cbOffset >= sizeof(struct FileStructA) &&
1590 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1591 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1592 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1593 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1595 if (cbOffset >= sizeof(struct FileStructA) &&
1596 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1598 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1600 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1601 "FileStructW's offset and length should add up to the PIDL's length!\n");
1603 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1604 /* Since we just created the file, time of creation,
1605 * time of last access and time of last write access just be the same.
1606 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1607 * after the first run. I do remember something with NTFS keeping the creation time
1608 * if a file is deleted and then created again within a couple of seconds or so.
1609 * Might be the reason. */
1610 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1611 pFileStructA->uFileTime == pFileStructW->uTime,
1612 "Last write time should match creation time!\n");
1614 /* On FAT filesystems the last access time is midnight
1615 local time, so the values of uDate2 and uTime2 will
1616 depend on the local timezone. If the times are exactly
1617 equal then the dates should be identical for both FAT
1618 and NTFS as no timezone is more than 1 day away from UTC.
1620 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1622 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1623 "Last write date and time should match last access date and time!\n");
1625 else
1627 /* Filesystem may be FAT. Check date within 1 day
1628 and seconds are zero. */
1629 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1630 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1631 "Last access time on FAT filesystems should have zero seconds.\n");
1632 /* TODO: Perform check for date being within one day.*/
1635 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1636 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1637 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1638 "The filename should be stored in unicode at this position!\n");
1642 pILFree(pidlFile);
1645 IShellFolder_Release(psfPersonal);
1648 static void test_SHGetFolderPathAndSubDirA(void)
1650 HRESULT ret;
1651 BOOL delret;
1652 DWORD dwret;
1653 int i;
1654 static char wine[] = "wine";
1655 static char winetemp[] = "wine\\temp";
1656 static char appdata[MAX_PATH];
1657 static char testpath[MAX_PATH];
1658 static char toolongpath[MAX_PATH+1];
1660 if(!pSHGetFolderPathAndSubDirA)
1662 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1663 return;
1666 if(!pSHGetFolderPathA) {
1667 win_skip("SHGetFolderPathA not present!\n");
1668 return;
1670 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1672 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1673 return;
1676 sprintf(testpath, "%s\\%s", appdata, winetemp);
1677 delret = RemoveDirectoryA(testpath);
1678 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1679 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1680 return;
1683 sprintf(testpath, "%s\\%s", appdata, wine);
1684 delret = RemoveDirectoryA(testpath);
1685 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1686 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1687 return;
1690 /* test invalid second parameter */
1691 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1692 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1694 /* test fourth parameter */
1695 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1696 switch(ret) {
1697 case S_OK: /* winvista */
1698 ok(!strncmp(appdata, testpath, strlen(appdata)),
1699 "expected %s to start with %s\n", testpath, appdata);
1700 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1701 "expected %s to end with %s\n", testpath, winetemp);
1702 break;
1703 case E_INVALIDARG: /* winxp, win2k3 */
1704 break;
1705 default:
1706 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
1709 /* test fifth parameter */
1710 testpath[0] = '\0';
1711 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1712 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1713 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1715 testpath[0] = '\0';
1716 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1717 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1718 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1720 testpath[0] = '\0';
1721 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1722 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1723 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1725 for(i=0; i< MAX_PATH; i++)
1726 toolongpath[i] = '0' + i % 10;
1727 toolongpath[MAX_PATH] = '\0';
1728 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1729 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1730 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1732 testpath[0] = '\0';
1733 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1734 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1736 /* test a not existing path */
1737 testpath[0] = '\0';
1738 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1739 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1740 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1742 /* create a directory inside a not existing directory */
1743 testpath[0] = '\0';
1744 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1745 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1746 ok(!strncmp(appdata, testpath, strlen(appdata)),
1747 "expected %s to start with %s\n", testpath, appdata);
1748 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1749 "expected %s to end with %s\n", testpath, winetemp);
1750 dwret = GetFileAttributes(testpath);
1751 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1753 /* cleanup */
1754 sprintf(testpath, "%s\\%s", appdata, winetemp);
1755 RemoveDirectoryA(testpath);
1756 sprintf(testpath, "%s\\%s", appdata, wine);
1757 RemoveDirectoryA(testpath);
1760 static void test_LocalizedNames(void)
1762 static char cCurrDirA[MAX_PATH];
1763 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1764 IShellFolder *IDesktopFolder, *testIShellFolder;
1765 ITEMIDLIST *newPIDL;
1766 int len;
1767 HRESULT hr;
1768 static char resourcefile[MAX_PATH];
1769 DWORD res;
1770 HANDLE file;
1771 STRRET strret;
1773 static const char desktopini_contents1[] =
1774 "[.ShellClassInfo]\r\n"
1775 "LocalizedResourceName=@";
1776 static const char desktopini_contents2[] =
1777 ",-1\r\n";
1778 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1779 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1781 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1782 CreateDirectoryA(".\\testfolder", NULL);
1784 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1786 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1788 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1789 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1790 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1791 ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1792 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1793 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
1794 "WriteFile failed %i\n", GetLastError());
1795 CloseHandle(file);
1797 /* get IShellFolder for parent */
1798 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1799 len = lstrlenA(cCurrDirA);
1801 if (len == 0) {
1802 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1803 goto cleanup;
1805 if(cCurrDirA[len-1] == '\\')
1806 cCurrDirA[len-1] = 0;
1808 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1810 hr = SHGetDesktopFolder(&IDesktopFolder);
1811 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1813 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1814 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1816 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1817 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1819 IMalloc_Free(ppM, newPIDL);
1821 /* windows reads the display name from the resource */
1822 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1823 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1825 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1826 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1828 if (hr == S_OK && pStrRetToBufW)
1830 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1831 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1832 todo_wine
1833 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1834 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1835 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1838 /* editing name is also read from the resource */
1839 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1840 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1842 if (hr == S_OK && pStrRetToBufW)
1844 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1845 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1846 todo_wine
1847 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1848 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1849 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1852 /* parsing name is unchanged */
1853 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1854 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1856 if (hr == S_OK && pStrRetToBufW)
1858 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1859 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1860 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1863 IShellFolder_Release(IDesktopFolder);
1864 IShellFolder_Release(testIShellFolder);
1866 IMalloc_Free(ppM, newPIDL);
1868 cleanup:
1869 DeleteFileA(".\\testfolder\\desktop.ini");
1870 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1871 RemoveDirectoryA(".\\testfolder");
1874 static void test_SHCreateShellItem(void)
1876 IShellItem *shellitem, *shellitem2;
1877 IPersistIDList *persistidl;
1878 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test;
1879 HRESULT ret;
1880 char curdirA[MAX_PATH];
1881 WCHAR curdirW[MAX_PATH];
1882 WCHAR fnbufW[MAX_PATH];
1883 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
1884 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
1886 GetCurrentDirectoryA(MAX_PATH, curdirA);
1888 if (!pSHCreateShellItem)
1890 win_skip("SHCreateShellItem isn't available\n");
1891 return;
1894 if (!lstrlenA(curdirA))
1896 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
1897 return;
1900 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
1902 ret = SHGetDesktopFolder(&desktopfolder);
1903 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
1905 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
1906 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1908 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
1909 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
1911 CreateTestFile(".\\testfile");
1913 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
1914 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1916 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
1918 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
1919 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
1921 if (0) /* crashes on Windows XP */
1923 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
1924 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
1925 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
1926 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
1929 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
1930 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1931 if (SUCCEEDED(ret))
1933 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1934 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1935 if (SUCCEEDED(ret))
1937 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1938 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1939 if (SUCCEEDED(ret))
1941 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1942 pILFree(pidl_test);
1944 IPersistIDList_Release(persistidl);
1946 IShellItem_Release(shellitem);
1949 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
1950 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1951 if (SUCCEEDED(ret))
1953 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1954 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1955 if (SUCCEEDED(ret))
1957 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1958 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1959 if (SUCCEEDED(ret))
1961 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1962 pILFree(pidl_test);
1964 IPersistIDList_Release(persistidl);
1967 ret = IShellItem_GetParent(shellitem, &shellitem2);
1968 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
1969 if (SUCCEEDED(ret))
1971 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
1972 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1973 if (SUCCEEDED(ret))
1975 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1976 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1977 if (SUCCEEDED(ret))
1979 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1980 pILFree(pidl_test);
1982 IPersistIDList_Release(persistidl);
1984 IShellItem_Release(shellitem2);
1987 IShellItem_Release(shellitem);
1990 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
1991 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1992 if (SUCCEEDED(ret))
1994 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1995 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1996 if (SUCCEEDED(ret))
1998 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1999 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2000 if (SUCCEEDED(ret))
2002 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2003 pILFree(pidl_test);
2005 IPersistIDList_Release(persistidl);
2007 IShellItem_Release(shellitem);
2010 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2011 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2012 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2013 if (SUCCEEDED(ret))
2015 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2016 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2017 if (SUCCEEDED(ret))
2019 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2020 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2021 if (SUCCEEDED(ret))
2023 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2024 pILFree(pidl_test);
2026 IPersistIDList_Release(persistidl);
2028 IShellItem_Release(shellitem);
2031 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2032 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2033 if (SUCCEEDED(ret))
2035 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2036 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2037 if (SUCCEEDED(ret))
2039 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2040 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2041 if (SUCCEEDED(ret))
2043 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2044 pILFree(pidl_test);
2046 IPersistIDList_Release(persistidl);
2048 IShellItem_Release(shellitem);
2051 /* SHCreateItemFromParsingName */
2052 if(pSHCreateItemFromParsingName)
2054 if(0)
2056 /* Crashes under windows 7 */
2057 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2060 shellitem = (void*)0xdeadbeef;
2061 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2062 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2063 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2065 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2066 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2067 "SHCreateItemFromParsingName returned %x\n", ret);
2068 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2070 lstrcpyW(fnbufW, curdirW);
2071 myPathAddBackslashW(fnbufW);
2072 lstrcatW(fnbufW, testfileW);
2074 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2075 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2076 if(SUCCEEDED(ret))
2078 LPWSTR tmp_fname;
2079 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2080 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2081 if(SUCCEEDED(ret))
2083 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2084 CoTaskMemFree(tmp_fname);
2086 IShellItem_Release(shellitem);
2089 else
2090 win_skip("No SHCreateItemFromParsingName\n");
2093 /* SHCreateItemFromIDList */
2094 if(pSHCreateItemFromIDList)
2096 if(0)
2098 /* Crashes under win7 */
2099 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2102 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2103 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2105 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2106 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2107 if (SUCCEEDED(ret))
2109 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2110 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2111 if (SUCCEEDED(ret))
2113 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2114 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2115 if (SUCCEEDED(ret))
2117 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2118 pILFree(pidl_test);
2120 IPersistIDList_Release(persistidl);
2122 IShellItem_Release(shellitem);
2125 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2126 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2127 if (SUCCEEDED(ret))
2129 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2130 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2131 if (SUCCEEDED(ret))
2133 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2134 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2135 if (SUCCEEDED(ret))
2137 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2138 pILFree(pidl_test);
2140 IPersistIDList_Release(persistidl);
2142 IShellItem_Release(shellitem);
2145 else
2146 win_skip("No SHCreateItemFromIDList\n");
2148 DeleteFileA(".\\testfile");
2149 pILFree(pidl_abstestfile);
2150 pILFree(pidl_testfile);
2151 pILFree(pidl_cwd);
2152 IShellFolder_Release(currentfolder);
2153 IShellFolder_Release(desktopfolder);
2156 static void test_SHGetNameFromIDList(void)
2158 IShellItem *shellitem;
2159 LPITEMIDLIST pidl;
2160 LPWSTR name_string;
2161 HRESULT hres;
2162 UINT i;
2163 static const DWORD flags[] = {
2164 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2165 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2166 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2167 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2169 if(!pSHGetNameFromIDList)
2171 win_skip("SHGetNameFromIDList missing.\n");
2172 return;
2175 /* These should be available on any platform that passed the above test. */
2176 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2177 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2178 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2179 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2181 if(0)
2183 /* Crashes under win7 */
2184 hres = pSHGetNameFromIDList(NULL, 0, NULL);
2187 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2188 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2190 /* Test the desktop */
2191 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2192 ok(hres == S_OK, "Got 0x%08x\n", hres);
2193 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2194 ok(hres == S_OK, "Got 0x%08x\n", hres);
2195 if(SUCCEEDED(hres))
2197 WCHAR *nameSI, *nameSH;
2198 WCHAR buf[MAX_PATH];
2199 HRESULT hrSI, hrSH, hrSF;
2200 STRRET strret;
2201 IShellFolder *psf;
2202 BOOL res;
2204 SHGetDesktopFolder(&psf);
2205 for(i = 0; flags[i] != -1234; i++)
2207 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2208 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2209 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2210 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2211 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2212 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2214 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2215 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2217 if(SUCCEEDED(hrSF))
2219 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2220 if(SUCCEEDED(hrSI))
2221 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2222 if(SUCCEEDED(hrSF))
2223 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2225 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2226 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2228 IShellFolder_Release(psf);
2230 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2231 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2232 res = SHGetPathFromIDListW(pidl, buf);
2233 ok(res == TRUE, "Got %d\n", res);
2234 if(SUCCEEDED(hrSI) && res)
2235 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2236 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2238 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2239 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2240 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2242 IShellItem_Release(shellitem);
2244 pILFree(pidl);
2246 /* Test the control panel */
2247 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2248 ok(hres == S_OK, "Got 0x%08x\n", hres);
2249 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2250 ok(hres == S_OK, "Got 0x%08x\n", hres);
2251 if(SUCCEEDED(hres))
2253 WCHAR *nameSI, *nameSH;
2254 WCHAR buf[MAX_PATH];
2255 HRESULT hrSI, hrSH, hrSF;
2256 STRRET strret;
2257 IShellFolder *psf;
2258 BOOL res;
2260 SHGetDesktopFolder(&psf);
2261 for(i = 0; flags[i] != -1234; i++)
2263 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2264 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2265 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2266 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2267 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2268 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2270 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2271 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2273 if(SUCCEEDED(hrSF))
2275 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2276 if(SUCCEEDED(hrSI))
2277 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2278 if(SUCCEEDED(hrSF))
2279 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2281 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2282 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2284 IShellFolder_Release(psf);
2286 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2287 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2288 res = SHGetPathFromIDListW(pidl, buf);
2289 ok(res == FALSE, "Got %d\n", res);
2290 if(SUCCEEDED(hrSI) && res)
2291 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2292 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2294 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2295 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2296 "Got 0x%08x\n", hres);
2297 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2299 IShellItem_Release(shellitem);
2301 pILFree(pidl);
2304 static void test_SHGetItemFromDataObject(void)
2306 IShellFolder *psfdesktop;
2307 IShellItem *psi;
2308 IShellView *psv;
2309 HRESULT hres;
2311 if(!pSHGetItemFromDataObject)
2313 win_skip("No SHGetItemFromDataObject.\n");
2314 return;
2317 if(0)
2319 /* Crashes under win7 */
2320 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2323 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2324 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2326 SHGetDesktopFolder(&psfdesktop);
2328 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2329 ok(hres == S_OK, "got 0x%08x\n", hres);
2330 if(SUCCEEDED(hres))
2332 IEnumIDList *peidl;
2333 IDataObject *pdo;
2334 SHCONTF enum_flags;
2336 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2337 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2338 ok(hres == S_OK, "got 0x%08x\n", hres);
2339 if(SUCCEEDED(hres))
2341 LPITEMIDLIST apidl[5];
2342 UINT count = 0, i;
2344 for(count = 0; count < 5; count++)
2345 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2346 break;
2348 if(count)
2350 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2351 &IID_IDataObject, NULL, (void**)&pdo);
2352 ok(hres == S_OK, "got 0x%08x\n", hres);
2353 if(SUCCEEDED(hres))
2355 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2356 ok(hres == S_OK, "got 0x%08x\n", hres);
2357 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2358 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2359 ok(hres == S_OK, "got 0x%08x\n", hres);
2360 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2361 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2362 ok(hres == S_OK, "got 0x%08x\n", hres);
2363 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2364 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2365 ok(hres == S_OK, "got 0x%08x\n", hres);
2366 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2367 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2368 ok(hres == S_OK, "got 0x%08x\n", hres);
2369 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2371 IDataObject_Release(pdo);
2374 else
2375 skip("No file(s) found - skipping single-file test.\n");
2377 if(count > 1)
2379 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2380 &IID_IDataObject, NULL, (void**)&pdo);
2381 ok(hres == S_OK, "got 0x%08x\n", hres);
2382 if(SUCCEEDED(hres))
2384 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2385 ok(hres == S_OK, "got 0x%08x\n", hres);
2386 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2387 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2388 ok(hres == S_OK, "got 0x%08x\n", hres);
2389 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2390 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2391 ok(hres == S_OK, "got 0x%08x\n", hres);
2392 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2393 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2394 ok(hres == S_OK, "got 0x%08x\n", hres);
2395 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2396 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2397 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2398 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2399 IDataObject_Release(pdo);
2402 else
2403 skip("zero or one file found - skipping multi-file test.\n");
2405 for(i = 0; i < count; i++)
2406 pILFree(apidl[i]);
2408 IEnumIDList_Release(peidl);
2411 IShellView_Release(psv);
2414 IShellFolder_Release(psfdesktop);
2417 static void test_ShellItemCompare(void)
2419 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2420 IShellItem *psi_a, *psi_b, *psi_c;
2421 IShellFolder *psf_desktop, *psf_current;
2422 LPITEMIDLIST pidl_cwd;
2423 WCHAR curdirW[MAX_PATH];
2424 BOOL failed;
2425 HRESULT hr;
2426 static const WCHAR filesW[][9] = {
2427 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2428 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2429 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2430 int order;
2431 UINT i;
2433 if(!pSHCreateShellItem)
2435 win_skip("SHCreateShellItem missing.\n");
2436 return;
2439 GetCurrentDirectoryW(MAX_PATH, curdirW);
2440 if(!lstrlenW(curdirW))
2442 skip("Failed to get current directory, skipping.\n");
2443 return;
2446 CreateDirectoryA(".\\a", NULL);
2447 CreateDirectoryA(".\\b", NULL);
2448 CreateDirectoryA(".\\c", NULL);
2449 CreateTestFile(".\\a\\a");
2450 CreateTestFile(".\\a\\b");
2451 CreateTestFile(".\\a\\c");
2452 CreateTestFile(".\\b\\a");
2453 CreateTestFile(".\\b\\b");
2454 CreateTestFile(".\\b\\c");
2455 CreateTestFile(".\\c\\a");
2456 CreateTestFile(".\\c\\b");
2457 CreateTestFile(".\\c\\c");
2459 SHGetDesktopFolder(&psf_desktop);
2460 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2461 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2462 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2463 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2464 IShellFolder_Release(psf_desktop);
2466 /* Generate ShellItems for the files */
2467 ZeroMemory(&psi, sizeof(IShellItem*)*9);
2468 failed = FALSE;
2469 for(i = 0; i < 9; i++)
2471 LPITEMIDLIST pidl_testfile = NULL;
2473 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2474 NULL, &pidl_testfile, NULL);
2475 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2476 if(SUCCEEDED(hr))
2478 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2479 ok(hr == S_OK, "Got 0x%08x\n", hr);
2480 pILFree(pidl_testfile);
2482 if(FAILED(hr)) failed = TRUE;
2484 if(failed)
2486 skip("Failed to create all shellitems. \n");
2487 goto cleanup;
2490 /* Generate ShellItems for the folders */
2491 psi_a = psi_b = psi_c = NULL;
2492 hr = IShellItem_GetParent(psi[0], &psi_a);
2493 ok(hr == S_OK, "Got 0x%08x\n", hr);
2494 if(FAILED(hr)) failed = TRUE;
2495 hr = IShellItem_GetParent(psi[3], &psi_b);
2496 ok(hr == S_OK, "Got 0x%08x\n", hr);
2497 if(FAILED(hr)) failed = TRUE;
2498 hr = IShellItem_GetParent(psi[6], &psi_c);
2499 ok(hr == S_OK, "Got 0x%08x\n", hr);
2500 if(FAILED(hr)) failed = TRUE;
2502 if(failed)
2504 skip("Failed to create shellitems. \n");
2505 goto cleanup;
2508 if(0)
2510 /* Crashes on native (win7, winxp) */
2511 hr = IShellItem_Compare(psi_a, NULL, 0, NULL);
2512 hr = IShellItem_Compare(psi_a, psi_b, 0, NULL);
2513 hr = IShellItem_Compare(psi_a, NULL, 0, &order);
2516 /* Basics */
2517 for(i = 0; i < 9; i++)
2519 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2520 ok(hr == S_OK, "Got 0x%08x\n", hr);
2521 ok(order == 0, "Got order %d\n", order);
2522 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2523 ok(hr == S_OK, "Got 0x%08x\n", hr);
2524 ok(order == 0, "Got order %d\n", order);
2525 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2526 ok(hr == S_OK, "Got 0x%08x\n", hr);
2527 ok(order == 0, "Got order %d\n", order);
2530 /* Order */
2531 /* a\b:a\a , a\b:a\c, a\b:a\b */
2532 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2533 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2534 ok(order == 1, "Got order %d\n", order);
2535 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2536 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2537 ok(order == -1, "Got order %d\n", order);
2538 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2539 ok(hr == S_OK, "Got 0x%08x\n", hr);
2540 ok(order == 0, "Got order %d\n", order);
2542 /* b\b:a\b, b\b:c\b, b\b:c\b */
2543 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2544 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2545 ok(order == 1, "Got order %d\n", order);
2546 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2547 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2548 ok(order == -1, "Got order %d\n", order);
2549 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2550 ok(hr == S_OK, "Got 0x%08x\n", hr);
2551 ok(order == 0, "Got order %d\n", order);
2553 /* b:a\a, b:a\c, b:a\b */
2554 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2555 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2556 todo_wine ok(order == 1, "Got order %d\n", order);
2557 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2558 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2559 todo_wine ok(order == 1, "Got order %d\n", order);
2560 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2561 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2562 todo_wine ok(order == 1, "Got order %d\n", order);
2564 /* b:c\a, b:c\c, b:c\b */
2565 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2566 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2567 ok(order == -1, "Got order %d\n", order);
2568 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2569 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2570 ok(order == -1, "Got order %d\n", order);
2571 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2572 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2573 ok(order == -1, "Got order %d\n", order);
2575 /* a\b:a\a , a\b:a\c, a\b:a\b */
2576 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2577 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2578 ok(order == 1, "Got order %d\n", order);
2579 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2580 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2581 ok(order == -1, "Got order %d\n", order);
2582 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2583 ok(hr == S_OK, "Got 0x%08x\n", hr);
2584 ok(order == 0, "Got order %d\n", order);
2586 /* b\b:a\b, b\b:c\b, b\b:c\b */
2587 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2588 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2589 ok(order == 1, "Got order %d\n", order);
2590 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2591 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2592 ok(order == -1, "Got order %d\n", order);
2593 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2594 ok(hr == S_OK, "Got 0x%08x\n", hr);
2595 ok(order == 0, "Got order %d\n", order);
2597 /* b:a\a, b:a\c, b:a\b */
2598 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2599 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2600 todo_wine ok(order == 1, "Got order %d\n", order);
2601 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2602 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2603 todo_wine ok(order == 1, "Got order %d\n", order);
2604 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2605 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2606 todo_wine ok(order == 1, "Got order %d\n", order);
2608 /* b:c\a, b:c\c, b:c\b */
2609 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2610 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2611 ok(order == -1, "Got order %d\n", order);
2612 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2613 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2614 ok(order == -1, "Got order %d\n", order);
2615 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2616 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2617 ok(order == -1, "Got order %d\n", order);
2619 cleanup:
2620 IShellFolder_Release(psf_current);
2622 DeleteFileA(".\\a\\a");
2623 DeleteFileA(".\\a\\b");
2624 DeleteFileA(".\\a\\c");
2625 DeleteFileA(".\\b\\a");
2626 DeleteFileA(".\\b\\b");
2627 DeleteFileA(".\\b\\c");
2628 DeleteFileA(".\\c\\a");
2629 DeleteFileA(".\\c\\b");
2630 DeleteFileA(".\\c\\c");
2631 RemoveDirectoryA(".\\a");
2632 RemoveDirectoryA(".\\b");
2633 RemoveDirectoryA(".\\c");
2635 if(psi_a) IShellItem_Release(psi_a);
2636 if(psi_b) IShellItem_Release(psi_b);
2637 if(psi_c) IShellItem_Release(psi_c);
2639 for(i = 0; i < 9; i++)
2640 if(psi[i]) IShellItem_Release(psi[i]);
2643 /**************************************************************/
2644 /* IUnknown implementation for counting QueryInterface calls. */
2645 typedef struct {
2646 const IUnknownVtbl *lpVtbl;
2647 struct if_count {
2648 REFIID id;
2649 LONG count;
2650 } *ifaces;
2651 LONG unknown;
2652 } IUnknownImpl;
2654 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2656 IUnknownImpl *This = (IUnknownImpl*)iunk;
2657 UINT i, found;
2658 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2660 if(IsEqualIID(This->ifaces[i].id, riid))
2662 This->ifaces[i].count++;
2663 found = 1;
2664 break;
2667 if(!found)
2668 This->unknown++;
2669 return E_NOINTERFACE;
2672 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
2674 return 2;
2677 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
2679 return 1;
2682 const IUnknownVtbl vt_IUnknown = {
2683 unk_fnQueryInterface,
2684 unk_fnAddRef,
2685 unk_fnRelease
2688 static void test_SHGetIDListFromObject(void)
2690 IUnknownImpl *punkimpl;
2691 IShellFolder *psfdesktop;
2692 IShellView *psv;
2693 LPITEMIDLIST pidl, pidl_desktop;
2694 HRESULT hres;
2695 UINT i;
2696 struct if_count ifaces[] =
2697 { {&IID_IPersistIDList, 0},
2698 {&IID_IPersistFolder2, 0},
2699 {&IID_IDataObject, 0},
2700 {&IID_IParentAndItem, 0},
2701 {&IID_IFolderView, 0},
2702 {NULL, 0} };
2704 if(!pSHGetIDListFromObject)
2706 win_skip("SHGetIDListFromObject missing.\n");
2707 return;
2710 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2712 if(0)
2714 /* Crashes native */
2715 pSHGetIDListFromObject(NULL, NULL);
2716 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
2719 hres = pSHGetIDListFromObject(NULL, &pidl);
2720 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2722 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
2723 punkimpl->lpVtbl = &vt_IUnknown;
2724 punkimpl->ifaces = ifaces;
2725 punkimpl->unknown = 0;
2727 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
2728 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2729 ok(ifaces[0].count, "interface not requested.\n");
2730 ok(ifaces[1].count, "interface not requested.\n");
2731 ok(ifaces[2].count, "interface not requested.\n");
2732 todo_wine
2733 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
2734 "interface not requested.\n");
2735 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
2736 "interface not requested.\n");
2738 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
2739 HeapFree(GetProcessHeap(), 0, punkimpl);
2741 pidl_desktop = NULL;
2742 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2743 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
2745 SHGetDesktopFolder(&psfdesktop);
2747 /* Test IShellItem */
2748 if(pSHCreateShellItem)
2750 IShellItem *shellitem;
2751 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2752 ok(hres == S_OK, "got 0x%08x\n", hres);
2753 if(SUCCEEDED(hres))
2755 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
2756 ok(hres == S_OK, "got 0x%08x\n", hres);
2757 if(SUCCEEDED(hres))
2759 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2760 pILFree(pidl);
2762 IShellItem_Release(shellitem);
2765 else
2766 skip("no SHCreateShellItem.\n");
2768 /* Test IShellFolder */
2769 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
2770 ok(hres == S_OK, "got 0x%08x\n", hres);
2771 if(SUCCEEDED(hres))
2773 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2774 pILFree(pidl);
2777 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2778 ok(hres == S_OK, "got 0x%08x\n", hres);
2779 if(SUCCEEDED(hres))
2781 IEnumIDList *peidl;
2782 IDataObject *pdo;
2783 SHCONTF enum_flags;
2785 /* Test IFolderView */
2786 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
2787 ok(hres == S_OK, "got 0x%08x\n", hres);
2788 if(SUCCEEDED(hres))
2790 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2791 pILFree(pidl);
2794 /* Test IDataObject */
2795 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2796 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2797 ok(hres == S_OK, "got 0x%08x\n", hres);
2798 if(SUCCEEDED(hres))
2800 LPITEMIDLIST apidl[5];
2801 UINT count = 0;
2802 for(count = 0; count < 5; count++)
2803 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2804 break;
2806 if(count)
2808 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2809 &IID_IDataObject, NULL, (void**)&pdo);
2810 ok(hres == S_OK, "got 0x%08x\n", hres);
2811 if(SUCCEEDED(hres))
2813 pidl = (void*)0xDEADBEEF;
2814 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
2815 ok(hres == S_OK, "got 0x%08x\n", hres);
2816 ok(pidl != NULL, "pidl is NULL.\n");
2817 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
2818 pILFree(pidl);
2820 IDataObject_Release(pdo);
2823 else
2824 skip("No files found - skipping single-file test.\n");
2826 if(count > 1)
2828 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2829 &IID_IDataObject, NULL, (void**)&pdo);
2830 ok(hres == S_OK, "got 0x%08x\n", hres);
2831 if(SUCCEEDED(hres))
2833 pidl = (void*)0xDEADBEEF;
2834 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
2835 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
2836 "got 0x%08x\n", hres);
2837 ok(pidl == NULL, "pidl is not NULL.\n");
2839 IDataObject_Release(pdo);
2842 else
2843 skip("zero or one file found - skipping multi-file test.\n");
2845 for(i = 0; i < count; i++)
2846 pILFree(apidl[i]);
2848 IEnumIDList_Release(peidl);
2851 IShellView_Release(psv);
2854 IShellFolder_Release(psfdesktop);
2855 pILFree(pidl_desktop);
2858 static void test_SHGetItemFromObject(void)
2860 IUnknownImpl *punkimpl;
2861 IShellFolder *psfdesktop;
2862 LPITEMIDLIST pidl;
2863 IShellItem *psi;
2864 IUnknown *punk;
2865 HRESULT hres;
2866 struct if_count ifaces[] =
2867 { {&IID_IPersistIDList, 0},
2868 {&IID_IPersistFolder2, 0},
2869 {&IID_IDataObject, 0},
2870 {&IID_IParentAndItem, 0},
2871 {&IID_IFolderView, 0},
2872 {NULL, 0} };
2874 if(!pSHGetItemFromObject)
2876 skip("No SHGetItemFromObject.\n");
2877 return;
2880 SHGetDesktopFolder(&psfdesktop);
2882 if(0)
2884 /* Crashes with Windows 7 */
2885 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, (void**)NULL);
2886 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)NULL);
2887 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
2890 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
2891 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
2893 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
2894 punkimpl->lpVtbl = &vt_IUnknown;
2895 punkimpl->ifaces = ifaces;
2896 punkimpl->unknown = 0;
2898 /* The same as SHGetIDListFromObject */
2899 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
2900 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2901 ok(ifaces[0].count, "interface not requested.\n");
2902 ok(ifaces[1].count, "interface not requested.\n");
2903 ok(ifaces[2].count, "interface not requested.\n");
2904 todo_wine
2905 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
2906 "interface not requested.\n");
2907 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
2908 "interface not requested.\n");
2910 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
2911 HeapFree(GetProcessHeap(), 0, punkimpl);
2913 /* Test IShellItem */
2914 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
2915 ok(hres == S_OK, "Got 0x%08x\n", hres);
2916 if(SUCCEEDED(hres))
2918 IShellItem *psi2;
2919 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
2920 ok(hres == S_OK, "Got 0x%08x\n", hres);
2921 if(SUCCEEDED(hres))
2923 todo_wine
2924 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
2925 IShellItem_Release(psi2);
2927 IShellItem_Release(psi);
2930 IShellFolder_Release(psfdesktop);
2933 static void test_SHParseDisplayName(void)
2935 LPITEMIDLIST pidl1, pidl2;
2936 IShellFolder *desktop;
2937 WCHAR dirW[MAX_PATH];
2938 WCHAR nameW[10];
2939 HRESULT hr;
2940 BOOL ret;
2942 if (!pSHParseDisplayName)
2944 win_skip("SHParseDisplayName isn't available\n");
2945 return;
2948 if (0)
2950 /* crashes on native */
2951 hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
2952 nameW[0] = 0;
2953 hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
2956 pidl1 = (LPITEMIDLIST)0xdeadbeef;
2957 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
2958 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
2959 hr == E_INVALIDARG, "failed %08x\n", hr);
2960 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
2962 /* dummy name */
2963 nameW[0] = 0;
2964 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
2965 ok(hr == S_OK, "failed %08x\n", hr);
2966 hr = SHGetDesktopFolder(&desktop);
2967 ok(hr == S_OK, "failed %08x\n", hr);
2968 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
2969 ok(hr == S_OK, "failed %08x\n", hr);
2970 ret = pILIsEqual(pidl1, pidl2);
2971 ok(ret == TRUE, "expected equal idls\n");
2972 pILFree(pidl1);
2973 pILFree(pidl2);
2975 /* with path */
2976 GetWindowsDirectoryW( dirW, MAX_PATH );
2978 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
2979 ok(hr == S_OK, "failed %08x\n", hr);
2980 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
2981 ok(hr == S_OK, "failed %08x\n", hr);
2983 ret = pILIsEqual(pidl1, pidl2);
2984 ok(ret == TRUE, "expected equal idls\n");
2985 pILFree(pidl1);
2986 pILFree(pidl2);
2988 IShellFolder_Release(desktop);
2991 static void test_desktop_IPersist(void)
2993 IShellFolder *desktop;
2994 IPersist *persist;
2995 IPersistFolder2 *ppf2;
2996 CLSID clsid;
2997 HRESULT hr;
2999 hr = SHGetDesktopFolder(&desktop);
3000 ok(hr == S_OK, "failed %08x\n", hr);
3002 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3003 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3005 if (hr == S_OK)
3007 if (0)
3009 /* crashes on native */
3010 hr = IPersist_GetClassID(persist, NULL);
3012 memset(&clsid, 0, sizeof(clsid));
3013 hr = IPersist_GetClassID(persist, &clsid);
3014 ok(hr == S_OK, "failed %08x\n", hr);
3015 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3016 IPersist_Release(persist);
3019 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3020 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3021 if(SUCCEEDED(hr))
3023 IPersistFolder *ppf;
3024 LPITEMIDLIST pidl;
3025 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3026 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3027 if(SUCCEEDED(hr))
3028 IPersistFolder_Release(ppf);
3030 todo_wine {
3031 hr = IPersistFolder2_Initialize(ppf2, NULL);
3032 ok(hr == S_OK, "got %08x\n", hr);
3035 pidl = NULL;
3036 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3037 ok(hr == S_OK, "got %08x\n", hr);
3038 ok(pidl != NULL, "pidl was NULL.\n");
3039 if(SUCCEEDED(hr)) pILFree(pidl);
3041 IPersistFolder2_Release(ppf2);
3044 IShellFolder_Release(desktop);
3047 static void test_GetUIObject(void)
3049 IShellFolder *psf_desktop;
3050 IContextMenu *pcm;
3051 LPITEMIDLIST pidl;
3052 HRESULT hr;
3053 WCHAR path[MAX_PATH];
3054 const WCHAR filename[] =
3055 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3057 if(!pSHBindToParent)
3059 win_skip("SHBindToParent missing.\n");
3060 return;
3063 GetCurrentDirectoryW(MAX_PATH, path);
3064 if(!lstrlenW(path))
3066 skip("GetCurrentDirectoryW returned an empty string.\n");
3067 return;
3069 lstrcatW(path, filename);
3070 SHGetDesktopFolder(&psf_desktop);
3072 CreateFilesFolders();
3074 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3075 ok(hr == S_OK, "Got 0x%08x\n", hr);
3076 if(SUCCEEDED(hr))
3078 IShellFolder *psf;
3079 LPCITEMIDLIST pidl_child;
3080 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3081 ok(hr == S_OK, "Got 0x%08x\n", hr);
3082 if(SUCCEEDED(hr))
3084 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3085 &IID_IContextMenu, NULL, (void**)&pcm);
3086 ok(hr == S_OK, "Got 0x%08x\n", hr);
3087 if(SUCCEEDED(hr))
3089 HMENU hmenu = CreatePopupMenu();
3090 INT max_id, max_id_check;
3091 UINT count, i;
3092 const int id_upper_limit = 32767;
3093 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3094 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3095 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3096 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3097 count = GetMenuItemCount(hmenu);
3098 ok(count, "Got %d\n", count);
3100 max_id_check = 0;
3101 for(i = 0; i < count; i++)
3103 MENUITEMINFOA mii;
3104 INT res;
3105 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3106 mii.cbSize = sizeof(MENUITEMINFOA);
3107 mii.fMask = MIIM_ID | MIIM_FTYPE;
3109 SetLastError(0);
3110 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3111 ok(res, "Failed (last error: %d).\n", GetLastError());
3113 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3114 "Got non-separator ID out of range: %d (type: %x) \n", mii.wID, mii.fType);
3115 if(!(mii.fType & MFT_SEPARATOR))
3116 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3118 ok((max_id_check == max_id) ||
3119 (max_id_check == max_id-1 /* Win 7 */),
3120 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3122 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3124 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3126 CMINVOKECOMMANDINFO cmi;
3127 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3128 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3130 /* Attempt to execute non-existing command */
3131 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3132 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3133 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3135 cmi.lpVerb = "foobar_wine_test";
3136 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3137 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3138 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3139 "Got 0x%08x\n", hr);
3141 #undef is_win2k
3143 DestroyMenu(hmenu);
3144 IContextMenu_Release(pcm);
3146 IShellFolder_Release(psf);
3148 if(pILFree) pILFree(pidl);
3151 IShellFolder_Release(psf_desktop);
3152 Cleanup();
3155 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3156 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3158 LPCITEMIDLIST child;
3159 IShellFolder *parent;
3160 STRRET filename;
3161 HRESULT hr;
3163 if(!pSHBindToParent){
3164 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3165 if(path)
3166 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3167 else
3168 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3169 return;
3172 if(path){
3173 if(!pidl){
3174 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3175 return;
3178 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3179 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3180 if(FAILED(hr))
3181 return;
3183 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3184 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3185 if(FAILED(hr)){
3186 IShellFolder_Release(parent);
3187 return;
3190 ok_(__FILE__,l)(filename.uType == STRRET_WSTR, "Got unexpected string type: %d\n", filename.uType);
3191 ok_(__FILE__,l)(lstrcmpW(path, filename.pOleStr) == 0,
3192 "didn't get expected path (%s), instead: %s\n",
3193 wine_dbgstr_w(path), wine_dbgstr_w(filename.pOleStr));
3195 IShellFolder_Release(parent);
3196 }else
3197 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3200 static void test_SHSimpleIDListFromPath(void)
3202 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
3203 const CHAR adirA[] = "C:\\sidlfpdir";
3204 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
3206 LPITEMIDLIST pidl = NULL;
3208 if(!pSHSimpleIDListFromPathAW){
3209 win_skip("SHSimpleIDListFromPathAW not available\n");
3210 return;
3213 br = CreateDirectoryA(adirA, NULL);
3214 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3216 if(is_unicode)
3217 pidl = pSHSimpleIDListFromPathAW(adirW);
3218 else
3219 pidl = pSHSimpleIDListFromPathAW(adirA);
3220 verify_pidl(pidl, adirW);
3221 pILFree(pidl);
3223 br = RemoveDirectoryA(adirA);
3224 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
3226 if(is_unicode)
3227 pidl = pSHSimpleIDListFromPathAW(adirW);
3228 else
3229 pidl = pSHSimpleIDListFromPathAW(adirA);
3230 verify_pidl(pidl, adirW);
3231 pILFree(pidl);
3234 /* IFileSystemBindData impl */
3235 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
3236 REFIID riid, void **ppv)
3238 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
3239 IsEqualIID(riid, &IID_IUnknown)){
3240 *ppv = fsbd;
3241 return S_OK;
3243 return E_NOINTERFACE;
3246 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
3248 return 2;
3251 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
3253 return 1;
3256 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
3257 const WIN32_FIND_DATAW *pfd)
3259 ok(0, "SetFindData called\n");
3260 return E_NOTIMPL;
3263 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
3264 WIN32_FIND_DATAW *pfd)
3266 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3267 return S_OK;
3270 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
3271 WIN32_FIND_DATAW *pfd)
3273 memset(pfd, 0xdeadbeef, sizeof(WIN32_FIND_DATAW));
3274 return S_OK;
3277 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
3278 WIN32_FIND_DATAW *pfd)
3280 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3281 *pfd->cFileName = 'a';
3282 *pfd->cAlternateFileName = 'a';
3283 return S_OK;
3286 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
3287 WIN32_FIND_DATAW *pfd)
3289 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
3290 HANDLE handle = FindFirstFileW(adirW, pfd);
3291 FindClose(handle);
3292 return S_OK;
3295 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
3296 WIN32_FIND_DATAW *pfd)
3298 return E_FAIL;
3301 static IFileSystemBindDataVtbl fsbdVtbl = {
3302 fsbd_QueryInterface,
3303 fsbd_AddRef,
3304 fsbd_Release,
3305 fsbd_SetFindData,
3306 NULL
3309 static IFileSystemBindData fsbd = { &fsbdVtbl };
3311 static void test_ParseDisplayNamePBC(void)
3313 WCHAR wFileSystemBindData[] =
3314 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
3315 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
3316 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
3318 IShellFolder *psf;
3319 IBindCtx *pbc;
3320 HRESULT hres;
3321 ITEMIDLIST *pidl;
3323 /* Check if we support WCHAR functions */
3324 SetLastError(0xdeadbeef);
3325 lstrcmpiW(adirW, adirW);
3326 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
3327 win_skip("Most W-calls are not implemented\n");
3328 return;
3331 hres = SHGetDesktopFolder(&psf);
3332 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
3333 if(FAILED(hres)){
3334 win_skip("Failed to get IShellFolder, can't run tests\n");
3335 return;
3338 /* fails on unknown dir with no IBindCtx */
3339 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
3340 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
3341 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
3343 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
3344 hres = CreateBindCtx(0, &pbc);
3345 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
3347 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3348 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
3349 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
3351 /* unknown dir with IBindCtx with IFileSystemBindData */
3352 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
3353 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
3355 /* return E_FAIL from GetFindData */
3356 pidl = (ITEMIDLIST*)0xdeadbeef;
3357 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
3358 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3359 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3360 "ParseDisplayName failed: 0x%08x\n", hres);
3361 if(SUCCEEDED(hres)){
3362 verify_pidl(pidl, adirW);
3363 ILFree(pidl);
3366 /* set FIND_DATA struct to NULLs */
3367 pidl = (ITEMIDLIST*)0xdeadbeef;
3368 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
3369 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3370 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3371 "ParseDisplayName failed: 0x%08x\n", hres);
3372 if(SUCCEEDED(hres)){
3373 verify_pidl(pidl, adirW);
3374 ILFree(pidl);
3377 /* set FIND_DATA struct to junk */
3378 pidl = (ITEMIDLIST*)0xdeadbeef;
3379 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
3380 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3381 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3382 "ParseDisplayName failed: 0x%08x\n", hres);
3383 if(SUCCEEDED(hres)){
3384 verify_pidl(pidl, adirW);
3385 ILFree(pidl);
3388 /* set FIND_DATA struct to invalid data */
3389 pidl = (ITEMIDLIST*)0xdeadbeef;
3390 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
3391 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3392 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3393 "ParseDisplayName failed: 0x%08x\n", hres);
3394 if(SUCCEEDED(hres)){
3395 verify_pidl(pidl, adirW);
3396 ILFree(pidl);
3399 /* set FIND_DATA struct to valid data */
3400 pidl = (ITEMIDLIST*)0xdeadbeef;
3401 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
3402 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3403 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3404 "ParseDisplayName failed: 0x%08x\n", hres);
3405 if(SUCCEEDED(hres)){
3406 verify_pidl(pidl, adirW);
3407 ILFree(pidl);
3410 IBindCtx_Release(pbc);
3411 IShellFolder_Release(psf);
3414 START_TEST(shlfolder)
3416 init_function_pointers();
3417 /* if OleInitialize doesn't get called, ParseDisplayName returns
3418 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
3419 OleInitialize(NULL);
3421 test_ParseDisplayName();
3422 test_SHParseDisplayName();
3423 test_BindToObject();
3424 test_EnumObjects_and_CompareIDs();
3425 test_GetDisplayName();
3426 test_GetAttributesOf();
3427 test_SHGetPathFromIDList();
3428 test_CallForAttributes();
3429 test_FolderShortcut();
3430 test_ITEMIDLIST_format();
3431 test_SHGetFolderPathAndSubDirA();
3432 test_LocalizedNames();
3433 test_SHCreateShellItem();
3434 test_desktop_IPersist();
3435 test_GetUIObject();
3436 test_SHSimpleIDListFromPath();
3437 test_ParseDisplayNamePBC();
3438 test_SHGetNameFromIDList();
3439 test_SHGetItemFromDataObject();
3440 test_SHGetIDListFromObject();
3441 test_SHGetItemFromObject();
3442 test_ShellItemCompare();
3444 OleUninitialize();