storage.dll16: Fix get_nth_next_small_blocknr.
[wine.git] / dlls / shell32 / tests / shlfolder.c
blob759cce62676b60b1ab4878eb151ff73442fdaccc
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);
44 DEFINE_GUID(CLSID_ShellDocObjView, 0xe7e4bc40, 0xe76a, 0x11ce, 0xa9,0xbb, 0x00,0xaa,0x00,0x4a,0xe8,0x37);
46 static IMalloc *ppM;
48 static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
49 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
50 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
51 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
52 static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
53 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
54 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
55 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
56 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
57 static void (WINAPI *pILFree)(LPITEMIDLIST);
58 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
59 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
60 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
61 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
62 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
63 static HRESULT (WINAPI *pSHCreateShellItemArrayFromIDLists)(UINT, PCIDLIST_ABSOLUTE*, IShellItemArray**);
64 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
65 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
66 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
67 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
68 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
69 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
70 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
71 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
72 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
73 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
74 static UINT (WINAPI *pGetSystemWow64DirectoryW)(LPWSTR, UINT);
75 static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
76 static HRESULT (WINAPI *pSHCreateShellFolderView)(const SFV_CREATE *pcsfv, IShellView **ppsv);
77 static HRESULT (WINAPI *pSHCreateShellFolderViewEx)(LPCSFV psvcbi, IShellView **ppv);
78 static HRESULT (WINAPI *pSHILCreateFromPath)(LPCWSTR, LPITEMIDLIST *,DWORD*);
79 static BOOL (WINAPI *pSHGetPathFromIDListEx)(PCIDLIST_ABSOLUTE,WCHAR*,DWORD,GPFIDL_FLAGS);
81 static WCHAR *make_wstr(const char *str)
83 WCHAR *ret;
84 int len;
86 if (!str || !str[0])
87 return NULL;
89 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
90 if(!len || len < 0)
91 return NULL;
93 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
94 if(!ret)
95 return NULL;
97 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
98 return ret;
101 static int strcmp_wa(LPCWSTR strw, const char *stra)
103 CHAR buf[512];
104 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
105 return lstrcmpA(stra, buf);
108 static void init_function_pointers(void)
110 HMODULE hmod;
111 HRESULT hr;
112 void *ptr;
114 hmod = GetModuleHandleA("shell32.dll");
116 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
117 MAKEFUNC(SHBindToParent);
118 MAKEFUNC(SHCreateItemFromIDList);
119 MAKEFUNC(SHCreateItemFromParsingName);
120 MAKEFUNC(SHCreateShellItem);
121 MAKEFUNC(SHCreateShellItemArray);
122 MAKEFUNC(SHCreateShellItemArrayFromIDLists);
123 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
124 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
125 MAKEFUNC(SHGetFolderPathA);
126 MAKEFUNC(SHGetFolderPathAndSubDirA);
127 MAKEFUNC(SHGetPathFromIDListW);
128 MAKEFUNC(SHGetSpecialFolderPathA);
129 MAKEFUNC(SHGetSpecialFolderPathW);
130 MAKEFUNC(SHGetSpecialFolderLocation);
131 MAKEFUNC(SHParseDisplayName);
132 MAKEFUNC(SHGetNameFromIDList);
133 MAKEFUNC(SHGetItemFromDataObject);
134 MAKEFUNC(SHGetIDListFromObject);
135 MAKEFUNC(SHGetItemFromObject);
136 MAKEFUNC(SHCreateDefaultContextMenu);
137 MAKEFUNC(SHCreateShellFolderView);
138 MAKEFUNC(SHCreateShellFolderViewEx);
139 MAKEFUNC(SHGetPathFromIDListEx);
140 #undef MAKEFUNC
142 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
143 MAKEFUNC_ORD(ILFindLastID, 16);
144 MAKEFUNC_ORD(ILIsEqual, 21);
145 MAKEFUNC_ORD(ILCombine, 25);
146 MAKEFUNC_ORD(SHILCreateFromPath, 28);
147 MAKEFUNC_ORD(ILFree, 155);
148 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
149 #undef MAKEFUNC_ORD
151 /* test named exports */
152 ptr = GetProcAddress(hmod, "ILFree");
153 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
154 if (ptr)
156 #define TESTNAMED(f) \
157 ptr = (void*)GetProcAddress(hmod, #f); \
158 ok(ptr != 0, "expected named export for " #f "\n");
160 TESTNAMED(ILAppendID);
161 TESTNAMED(ILClone);
162 TESTNAMED(ILCloneFirst);
163 TESTNAMED(ILCombine);
164 TESTNAMED(ILCreateFromPath);
165 TESTNAMED(ILCreateFromPathA);
166 TESTNAMED(ILCreateFromPathW);
167 TESTNAMED(ILFindChild);
168 TESTNAMED(ILFindLastID);
169 TESTNAMED(ILGetNext);
170 TESTNAMED(ILGetSize);
171 TESTNAMED(ILIsEqual);
172 TESTNAMED(ILIsParent);
173 TESTNAMED(ILRemoveLastID);
174 TESTNAMED(ILSaveToStream);
175 #undef TESTNAMED
178 hmod = GetModuleHandleA("shlwapi.dll");
179 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
181 hmod = GetModuleHandleA("kernel32.dll");
182 pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
183 pGetSystemWow64DirectoryW = (void*)GetProcAddress(hmod, "GetSystemWow64DirectoryW");
185 hr = SHGetMalloc(&ppM);
186 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
189 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
190 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
192 size_t iLen;
194 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
195 return NULL;
197 if (iLen)
199 lpszPath += iLen;
200 if (lpszPath[-1] != '\\')
202 *lpszPath++ = '\\';
203 *lpszPath = '\0';
206 return lpszPath;
209 static void test_ParseDisplayName(void)
211 HRESULT hr;
212 IShellFolder *IDesktopFolder;
213 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
214 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
215 static const char *cInetTestA = "http:\\yyy";
216 static const char *cInetTest2A = "xx:yyy";
217 DWORD res;
218 WCHAR cTestDirW [MAX_PATH] = {0};
219 ITEMIDLIST *newPIDL;
220 BOOL bRes;
222 hr = SHGetDesktopFolder(&IDesktopFolder);
223 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
224 if(hr != S_OK) return;
226 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
227 if (pSHCreateShellItem)
229 if (0)
231 /* null name and pidl, also crashes on Windows 8 */
232 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL,
233 NULL, NULL, NULL, 0);
234 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
237 /* null name */
238 newPIDL = (ITEMIDLIST*)0xdeadbeef;
239 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
240 NULL, NULL, NULL, NULL, &newPIDL, 0);
241 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
242 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
244 else
245 win_skip("Tests would crash on W2K and below\n");
247 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
248 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
249 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
250 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
251 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
252 if (hr == S_OK)
254 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
255 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
256 IMalloc_Free(ppM, newPIDL);
259 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
260 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
261 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
262 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
263 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
264 if (hr == S_OK)
266 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
267 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
268 IMalloc_Free(ppM, newPIDL);
271 res = GetFileAttributesA(cNonExistDir1A);
272 if(res != INVALID_FILE_ATTRIBUTES)
274 skip("Test directory unexpectedly exists\n");
275 goto finished;
278 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
279 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
280 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
281 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
282 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
284 res = GetFileAttributesA(cNonExistDir2A);
285 if(res != INVALID_FILE_ATTRIBUTES)
287 skip("Test directory unexpectedly exists\n");
288 goto finished;
291 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
292 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
293 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
294 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
295 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
297 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
298 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
299 * out it doesn't. The magic seems to happen in the file dialogs, then. */
300 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
302 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
303 goto finished;
306 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
307 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
308 if (!bRes) goto finished;
310 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
311 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
312 if (hr != S_OK) goto finished;
314 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
315 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
316 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
317 pILFindLastID(newPIDL)->mkid.abID[0]);
318 IMalloc_Free(ppM, newPIDL);
320 finished:
321 IShellFolder_Release(IDesktopFolder);
324 /* creates a file with the specified name for tests */
325 static void CreateTestFile(const CHAR *name)
327 HANDLE file;
328 DWORD written;
330 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
331 if (file != INVALID_HANDLE_VALUE)
333 WriteFile(file, name, strlen(name), &written, NULL);
334 WriteFile(file, "\n", strlen("\n"), &written, NULL);
335 CloseHandle(file);
340 /* initializes the tests */
341 static void CreateFilesFolders(void)
343 CreateDirectoryA(".\\testdir", NULL);
344 CreateDirectoryA(".\\testdir\\test.txt", NULL);
345 CreateTestFile (".\\testdir\\test1.txt ");
346 CreateTestFile (".\\testdir\\test2.txt ");
347 CreateTestFile (".\\testdir\\test3.txt ");
348 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
349 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
352 /* cleans after tests */
353 static void Cleanup(void)
355 DeleteFileA(".\\testdir\\test1.txt");
356 DeleteFileA(".\\testdir\\test2.txt");
357 DeleteFileA(".\\testdir\\test3.txt");
358 RemoveDirectoryA(".\\testdir\\test.txt");
359 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
360 RemoveDirectoryA(".\\testdir\\testdir2");
361 RemoveDirectoryA(".\\testdir");
365 /* perform test */
366 static void test_EnumObjects(IShellFolder *iFolder)
368 IEnumIDList *iEnumList;
369 LPITEMIDLIST newPIDL, idlArr[10];
370 ULONG NumPIDLs;
371 int i=0, j;
372 HRESULT hr;
374 static const WORD iResults [5][5] =
376 { 0,-1,-1,-1,-1},
377 { 1, 0,-1,-1,-1},
378 { 1, 1, 0,-1,-1},
379 { 1, 1, 1, 0,-1},
380 { 1, 1, 1, 1, 0}
383 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
384 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
385 static const ULONG attrs[5] =
387 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
388 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
389 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
390 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
391 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
393 static const ULONG full_attrs[5] =
395 SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
396 SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
397 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
398 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
399 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
402 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
403 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
405 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
406 * the filesystem shellfolders return S_OK even if less than 'celt' items are
407 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
408 * only ever returns a single entry per call. */
409 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
410 i += NumPIDLs;
411 ok (i == 5, "i: %d\n", i);
413 hr = IEnumIDList_Release(iEnumList);
414 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
416 /* Sort them first in case of wrong order from system */
417 for (i=0;i<5;i++) for (j=0;j<5;j++)
418 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
420 newPIDL = idlArr[i];
421 idlArr[i] = idlArr[j];
422 idlArr[j] = newPIDL;
425 for (i=0;i<5;i++) for (j=0;j<5;j++)
427 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
428 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
432 for (i = 0; i < 5; i++)
434 SFGAOF flags;
435 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
436 /* Native returns all flags no matter what we ask for */
437 flags = SFGAO_CANCOPY;
438 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
439 flags &= SFGAO_testfor;
440 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
441 ok(flags == (attrs[i]) ||
442 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
443 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
444 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
446 flags = SFGAO_testfor;
447 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
448 flags &= SFGAO_testfor;
449 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
450 ok(flags == attrs[i] ||
451 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
452 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
454 flags = ~0u;
455 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
456 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
457 ok((flags & ~SFGAO_HASSUBFOLDER) == full_attrs[i], "%d: got %08x expected %08x\n", i, flags, full_attrs[i]);
460 for (i=0;i<5;i++)
461 IMalloc_Free(ppM, idlArr[i]);
464 static void test_BindToObject(void)
466 HRESULT hr;
467 UINT cChars;
468 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
469 SHITEMID emptyitem = { 0, { 0 } };
470 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
471 WCHAR wszSystemDir[MAX_PATH];
472 char szSystemDir[MAX_PATH];
473 char buf[MAX_PATH];
474 WCHAR path[MAX_PATH];
475 CHAR pathA[MAX_PATH];
476 HANDLE hfile;
477 WCHAR wszMyComputer[] = {
478 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
479 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
480 static const CHAR filename_html[] = "winetest.html";
481 static const CHAR filename_txt[] = "winetest.txt";
482 static const CHAR filename_foo[] = "winetest.foo";
484 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
485 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
487 hr = SHGetDesktopFolder(&psfDesktop);
488 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
489 if (hr != S_OK) return;
491 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
492 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
494 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
495 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
497 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
498 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
499 if (hr != S_OK) {
500 IShellFolder_Release(psfDesktop);
501 return;
504 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
505 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
506 IShellFolder_Release(psfDesktop);
507 IMalloc_Free(ppM, pidlMyComputer);
508 if (hr != S_OK) return;
510 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
511 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
513 if (0)
515 /* this call segfaults on 98SE */
516 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
517 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
520 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
521 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
522 if (cChars == 0 || cChars >= MAX_PATH) {
523 IShellFolder_Release(psfMyComputer);
524 return;
526 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
528 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
529 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
530 if (hr != S_OK) {
531 IShellFolder_Release(psfMyComputer);
532 return;
535 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
536 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
537 IShellFolder_Release(psfMyComputer);
538 IMalloc_Free(ppM, pidlSystemDir);
539 if (hr != S_OK) return;
541 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
542 ok (hr == E_INVALIDARG,
543 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
545 if (0)
547 /* this call segfaults on 98SE */
548 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
549 ok (hr == E_INVALIDARG,
550 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
553 IShellFolder_Release(psfSystemDir);
555 cChars = GetCurrentDirectoryA(MAX_PATH, buf);
556 if(!cChars)
558 skip("Failed to get current directory, skipping tests.\n");
559 return;
561 if(buf[cChars-1] != '\\') lstrcatA(buf, "\\");
563 SHGetDesktopFolder(&psfDesktop);
565 /* Attempt BindToObject on files. */
567 /* .html */
568 lstrcpyA(pathA, buf);
569 lstrcatA(pathA, filename_html);
570 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
571 if(hfile != INVALID_HANDLE_VALUE)
573 CloseHandle(hfile);
574 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
575 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
576 ok(hr == S_OK, "Got 0x%08x\n", hr);
577 if(SUCCEEDED(hr))
579 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
580 ok(hr == S_OK ||
581 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
582 "Got 0x%08x\n", hr);
583 if(SUCCEEDED(hr))
585 IPersist *pp;
586 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
587 ok(hr == S_OK ||
588 broken(hr == E_NOINTERFACE), /* Win9x, NT4, W2K */
589 "Got 0x%08x\n", hr);
590 if(SUCCEEDED(hr))
592 CLSID id;
593 hr = IPersist_GetClassID(pp, &id);
594 ok(hr == S_OK, "Got 0x%08x\n", hr);
595 /* CLSID_ShellFSFolder on some w2k systems */
596 ok(IsEqualIID(&id, &CLSID_ShellDocObjView) || broken(IsEqualIID(&id, &CLSID_ShellFSFolder)),
597 "Unexpected classid %s\n", wine_dbgstr_guid(&id));
598 IPersist_Release(pp);
601 IShellFolder_Release(psfChild);
603 pILFree(pidl);
605 DeleteFileA(pathA);
607 else
608 win_skip("Failed to create .html testfile.\n");
610 /* .txt */
611 lstrcpyA(pathA, buf);
612 lstrcatA(pathA, filename_txt);
613 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
614 if(hfile != INVALID_HANDLE_VALUE)
616 CloseHandle(hfile);
617 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
618 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
619 ok(hr == S_OK, "Got 0x%08x\n", hr);
620 if(SUCCEEDED(hr))
622 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
623 ok(hr == E_FAIL || /* Vista+ */
624 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
625 hr == E_INVALIDARG || /* W2K item in top dir */
626 broken(hr == S_OK), /* Win9x, NT4, W2K */
627 "Got 0x%08x\n", hr);
628 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
629 pILFree(pidl);
631 DeleteFileA(pathA);
633 else
634 win_skip("Failed to create .txt testfile.\n");
636 /* .foo */
637 lstrcpyA(pathA, buf);
638 lstrcatA(pathA, filename_foo);
639 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
640 if(hfile != INVALID_HANDLE_VALUE)
642 CloseHandle(hfile);
643 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
644 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
645 ok(hr == S_OK, "Got 0x%08x\n", hr);
646 if(SUCCEEDED(hr))
648 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
649 ok(hr == E_FAIL || /* Vista+ */
650 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
651 hr == E_INVALIDARG || /* W2K item in top dir */
652 broken(hr == S_OK), /* Win9x, NT4, W2K */
653 "Got 0x%08x\n", hr);
654 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
655 pILFree(pidl);
657 DeleteFileA(pathA);
659 else
660 win_skip("Failed to create .foo testfile.\n");
662 /* And on the desktop */
663 if(pSHGetSpecialFolderPathA)
665 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
666 lstrcatA(pathA, "\\");
667 lstrcatA(pathA, filename_html);
668 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
669 if(hfile != INVALID_HANDLE_VALUE)
671 CloseHandle(hfile);
672 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
673 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
674 ok(hr == S_OK, "Got 0x%08x\n", hr);
675 if(SUCCEEDED(hr))
677 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
678 ok(hr == S_OK ||
679 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
680 "Got 0x%08x\n", hr);
681 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
682 pILFree(pidl);
684 if(!DeleteFileA(pathA))
685 trace("Failed to delete: %d\n", GetLastError());
688 else
689 win_skip("Failed to create .html testfile.\n");
691 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
692 lstrcatA(pathA, "\\");
693 lstrcatA(pathA, filename_foo);
694 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
695 if(hfile != INVALID_HANDLE_VALUE)
697 CloseHandle(hfile);
698 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
699 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
700 ok(hr == S_OK, "Got 0x%08x\n", hr);
701 if(SUCCEEDED(hr))
703 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
704 ok(hr == E_FAIL || /* Vista+ */
705 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
706 broken(hr == S_OK), /* Win9x, NT4, W2K */
707 "Got 0x%08x\n", hr);
708 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
709 pILFree(pidl);
711 DeleteFileA(pathA);
713 else
714 win_skip("Failed to create .foo testfile.\n");
717 IShellFolder_Release(psfDesktop);
720 static void test_GetDisplayName(void)
722 BOOL result;
723 HRESULT hr;
724 HANDLE hTestFile;
725 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
726 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
727 DWORD attr;
728 STRRET strret;
729 LPSHELLFOLDER psfDesktop, psfPersonal;
730 IUnknown *psfFile;
731 SHITEMID emptyitem = { 0, { 0 } };
732 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
733 LPCITEMIDLIST pidlLast;
734 static const CHAR szFileName[] = "winetest.foo";
735 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
736 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
738 /* I'm trying to figure if there is a functional difference between calling
739 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
740 * binding to the shellfolder. One thing I thought of was that perhaps
741 * SHGetPathFromIDListW would be able to get the path to a file, which does
742 * not exist anymore, while the other method wouldn't. It turns out there's
743 * no functional difference in this respect.
746 if(!pSHGetSpecialFolderPathA) {
747 win_skip("SHGetSpecialFolderPathA is not available\n");
748 return;
751 /* First creating a directory in MyDocuments and a file in this directory. */
752 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
753 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
754 if (!result) return;
756 /* Use ANSI file functions so this works on Windows 9x */
757 lstrcatA(szTestDir, "\\winetest");
758 CreateDirectoryA(szTestDir, NULL);
759 attr=GetFileAttributesA(szTestDir);
760 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
762 ok(0, "unable to create the '%s' directory\n", szTestDir);
763 return;
766 lstrcpyA(szTestFile, szTestDir);
767 lstrcatA(szTestFile, "\\");
768 lstrcatA(szTestFile, szFileName);
769 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
770 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
771 if (hTestFile == INVALID_HANDLE_VALUE) return;
772 CloseHandle(hTestFile);
774 /* Getting an itemidlist for the file. */
775 hr = SHGetDesktopFolder(&psfDesktop);
776 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
777 if (hr != S_OK) return;
779 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
781 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
782 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
783 if (hr != S_OK) {
784 IShellFolder_Release(psfDesktop);
785 return;
788 pidlLast = pILFindLastID(pidlTestFile);
789 ok(pidlLast->mkid.cb >=76 ||
790 broken(pidlLast->mkid.cb == 28) || /* W2K */
791 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
792 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
793 if (pidlLast->mkid.cb >= 28) {
794 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
795 "Filename should be stored as ansi-string at this position!\n");
797 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
798 if (pidlLast->mkid.cb >= 76) {
799 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
800 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
801 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)) || /* Win7 */
802 (pidlLast->mkid.cb >= 102 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[72], wszFileName)), /* Win8 */
803 "Filename should be stored as wchar-string at this position!\n");
806 /* It seems as if we cannot bind to regular files on windows, but only directories.
808 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
809 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
810 hr == E_NOTIMPL || /* Vista */
811 broken(hr == S_OK), /* Win9x, W2K */
812 "hr = %08x\n", hr);
813 if (hr == S_OK) {
814 IUnknown_Release(psfFile);
817 if (!pSHBindToParent)
819 win_skip("SHBindToParent is missing\n");
820 DeleteFileA(szTestFile);
821 RemoveDirectoryA(szTestDir);
822 return;
825 /* Some tests for IShellFolder::SetNameOf */
826 if (pSHGetFolderPathAndSubDirA)
828 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
829 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
830 if (hr == S_OK) {
831 /* It's ok to use this fixed path. Call will fail anyway. */
832 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
833 LPITEMIDLIST pidlNew;
835 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
836 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
837 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
838 if (hr == S_OK)
840 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
841 "pidl returned from SetNameOf should be simple!\n");
843 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
844 * is implemented on top of SHFileOperation in WinXP. */
845 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
846 SHGDN_FORPARSING, NULL);
847 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
849 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
850 * SHGDN flags specify an absolute path. */
851 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
852 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
854 pILFree(pidlNew);
857 IShellFolder_Release(psfPersonal);
860 else
861 win_skip("Avoid needs of interaction on Win2k\n");
863 /* Deleting the file and the directory */
864 DeleteFileA(szTestFile);
865 RemoveDirectoryA(szTestDir);
867 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
868 if (pSHGetPathFromIDListW)
870 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
871 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
872 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
875 /* SHBindToParent fails, if called with a NULL PIDL. */
876 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
877 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
879 /* But it succeeds with an empty PIDL. */
880 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
881 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
882 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
883 if (hr == S_OK)
884 IShellFolder_Release(psfPersonal);
886 /* Binding to the folder and querying the display name of the file also works. */
887 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
888 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
889 if (hr != S_OK) {
890 IShellFolder_Release(psfDesktop);
891 return;
894 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
895 * pidlTestFile (In accordance with MSDN). */
896 ok (pILFindLastID(pidlTestFile) == pidlLast,
897 "SHBindToParent doesn't return the last id of the pidl param!\n");
899 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
900 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
901 if (hr != S_OK) {
902 IShellFolder_Release(psfDesktop);
903 IShellFolder_Release(psfPersonal);
904 return;
907 if (pStrRetToBufW)
909 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
910 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
911 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
914 ILFree(pidlTestFile);
915 IShellFolder_Release(psfDesktop);
916 IShellFolder_Release(psfPersonal);
919 static void test_CallForAttributes(void)
921 HKEY hKey;
922 LONG lResult;
923 HRESULT hr;
924 DWORD dwSize;
925 LPSHELLFOLDER psfDesktop;
926 LPITEMIDLIST pidlMyDocuments;
927 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
928 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
929 static const WCHAR wszCallForAttributes[] = {
930 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
931 static const WCHAR wszMyDocumentsKey[] = {
932 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
933 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
934 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
935 WCHAR wszMyDocuments[] = {
936 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
937 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
939 /* For the root of a namespace extension, the attributes are not queried by binding
940 * to the object and calling GetAttributesOf. Instead, the attributes are read from
941 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
943 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
944 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
945 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
946 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
948 hr = SHGetDesktopFolder(&psfDesktop);
949 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
950 if (hr != S_OK) return;
952 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
953 &pidlMyDocuments, NULL);
954 ok (hr == S_OK ||
955 broken(hr == E_INVALIDARG), /* Win95, NT4 */
956 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
957 if (hr != S_OK) {
958 IShellFolder_Release(psfDesktop);
959 return;
962 dwAttributes = 0xffffffff;
963 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
964 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
965 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
967 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
968 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
969 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
970 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
972 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
973 * key. So the test will return at this point, if run on wine.
975 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
976 ok (lResult == ERROR_SUCCESS ||
977 lResult == ERROR_ACCESS_DENIED,
978 "RegOpenKeyEx failed! result: %08x\n", lResult);
979 if (lResult != ERROR_SUCCESS) {
980 if (lResult == ERROR_ACCESS_DENIED)
981 skip("Not enough rights to open the registry key\n");
982 IMalloc_Free(ppM, pidlMyDocuments);
983 IShellFolder_Release(psfDesktop);
984 return;
987 /* Query MyDocuments' Attributes value, to be able to restore it later. */
988 dwSize = sizeof(DWORD);
989 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
990 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
991 if (lResult != ERROR_SUCCESS) {
992 RegCloseKey(hKey);
993 IMalloc_Free(ppM, pidlMyDocuments);
994 IShellFolder_Release(psfDesktop);
995 return;
998 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
999 dwSize = sizeof(DWORD);
1000 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
1001 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
1002 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
1003 if (lResult != ERROR_SUCCESS) {
1004 RegCloseKey(hKey);
1005 IMalloc_Free(ppM, pidlMyDocuments);
1006 IShellFolder_Release(psfDesktop);
1007 return;
1010 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
1011 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
1012 * SFGAO_FILESYSTEM attributes. */
1013 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
1014 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
1015 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
1016 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1017 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
1019 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
1020 * GetAttributesOf. It seems that once there is a single attribute queried, for which
1021 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
1022 * the flags in Attributes are ignored.
1024 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
1025 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
1026 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
1027 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
1028 if (hr == S_OK)
1029 ok (dwAttributes == SFGAO_FILESYSTEM,
1030 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
1031 dwAttributes);
1033 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
1034 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
1035 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1036 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
1037 RegCloseKey(hKey);
1038 IMalloc_Free(ppM, pidlMyDocuments);
1039 IShellFolder_Release(psfDesktop);
1042 static void test_GetAttributesOf(void)
1044 HRESULT hr;
1045 LPSHELLFOLDER psfDesktop, psfMyComputer;
1046 SHITEMID emptyitem = { 0, { 0 } };
1047 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1048 LPITEMIDLIST pidlMyComputer;
1049 DWORD dwFlags;
1050 static const DWORD desktopFlags[] = {
1051 /* WinXP */
1052 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
1053 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1054 /* Win2k */
1055 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
1056 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1057 /* WinMe, Win9x, WinNT*/
1058 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
1059 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1061 static const DWORD myComputerFlags[] = {
1062 /* WinXP */
1063 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
1064 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1065 /* Win2k */
1066 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
1067 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1068 /* WinMe, Win9x, WinNT */
1069 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1070 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1071 /* Win95, WinNT when queried directly */
1072 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1073 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1075 WCHAR wszMyComputer[] = {
1076 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1077 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1078 char cCurrDirA [MAX_PATH] = {0};
1079 WCHAR cCurrDirW [MAX_PATH];
1080 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
1081 IShellFolder *IDesktopFolder, *testIShellFolder;
1082 ITEMIDLIST *newPIDL;
1083 int len, i;
1084 BOOL foundFlagsMatch;
1086 hr = SHGetDesktopFolder(&psfDesktop);
1087 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1088 if (hr != S_OK) return;
1090 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
1091 dwFlags = 0xffffffff;
1092 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
1093 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
1094 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1095 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1097 if (desktopFlags[i] == dwFlags)
1098 foundFlagsMatch = TRUE;
1100 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1102 /* .. or with no itemidlist at all. */
1103 dwFlags = 0xffffffff;
1104 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
1105 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1106 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1107 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1109 if (desktopFlags[i] == dwFlags)
1110 foundFlagsMatch = TRUE;
1112 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1114 /* Testing the attributes of the MyComputer shellfolder */
1115 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1116 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1117 if (hr != S_OK) {
1118 IShellFolder_Release(psfDesktop);
1119 return;
1122 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
1123 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
1125 dwFlags = 0xffffffff;
1126 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
1127 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
1128 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1129 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1131 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
1132 foundFlagsMatch = TRUE;
1134 todo_wine
1135 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1137 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
1138 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
1139 IShellFolder_Release(psfDesktop);
1140 IMalloc_Free(ppM, pidlMyComputer);
1141 if (hr != S_OK) return;
1143 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
1144 todo_wine
1145 ok (hr == E_INVALIDARG ||
1146 broken(hr == S_OK), /* W2K and earlier */
1147 "MyComputer->GetAttributesOf(empty pidl) should fail! hr = %08x\n", hr);
1149 dwFlags = 0xffffffff;
1150 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
1151 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1152 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1153 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1155 if (myComputerFlags[i] == dwFlags)
1156 foundFlagsMatch = TRUE;
1158 todo_wine
1159 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1161 IShellFolder_Release(psfMyComputer);
1163 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1164 len = lstrlenA(cCurrDirA);
1166 if (len == 0) {
1167 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1168 return;
1170 if (len > 3 && cCurrDirA[len-1] == '\\')
1171 cCurrDirA[len-1] = 0;
1173 /* create test directory */
1174 CreateFilesFolders();
1176 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1178 hr = SHGetDesktopFolder(&IDesktopFolder);
1179 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1181 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1182 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1184 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1185 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1187 IMalloc_Free(ppM, newPIDL);
1189 /* get relative PIDL */
1190 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1191 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1193 /* test the shell attributes of the test directory using the relative PIDL */
1194 dwFlags = SFGAO_FOLDER;
1195 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1196 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1197 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1199 /* free memory */
1200 IMalloc_Free(ppM, newPIDL);
1202 /* append testdirectory name to path */
1203 if (cCurrDirA[len-1] == '\\')
1204 cCurrDirA[len-1] = 0;
1205 lstrcatA(cCurrDirA, "\\testdir");
1206 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1208 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1209 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1211 /* test the shell attributes of the test directory using the absolute PIDL */
1212 dwFlags = SFGAO_FOLDER;
1213 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1214 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1215 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1217 /* free memory */
1218 IMalloc_Free(ppM, newPIDL);
1220 IShellFolder_Release(testIShellFolder);
1222 Cleanup();
1224 IShellFolder_Release(IDesktopFolder);
1227 static void test_SHGetPathFromIDList(void)
1229 SHITEMID emptyitem = { 0, { 0 } };
1230 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1231 LPITEMIDLIST pidlMyComputer;
1232 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1233 BOOL result;
1234 HRESULT hr;
1235 LPSHELLFOLDER psfDesktop;
1236 WCHAR wszMyComputer[] = {
1237 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1238 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1239 WCHAR wszFileName[MAX_PATH];
1240 LPITEMIDLIST pidlTestFile;
1241 HANDLE hTestFile;
1242 STRRET strret;
1243 static WCHAR wszTestFile[] = {
1244 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1245 LPITEMIDLIST pidlPrograms;
1247 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1249 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1250 return;
1253 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1254 wszPath[0] = 'a';
1255 wszPath[1] = '\0';
1256 result = pSHGetPathFromIDListW(NULL, wszPath);
1257 ok(!result, "Expected failure\n");
1258 ok(!wszPath[0], "Expected empty string\n");
1260 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1261 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1262 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1263 if (!result) return;
1265 /* Check if we are on Win9x */
1266 SetLastError(0xdeadbeef);
1267 lstrcmpiW(wszDesktop, wszDesktop);
1268 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1270 win_skip("Most W-calls are not implemented\n");
1271 return;
1274 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1275 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1276 if (!result) return;
1277 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1279 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1280 hr = SHGetDesktopFolder(&psfDesktop);
1281 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1282 if (hr != S_OK) return;
1284 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1285 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1286 if (hr != S_OK) {
1287 IShellFolder_Release(psfDesktop);
1288 return;
1291 SetLastError(0xdeadbeef);
1292 wszPath[0] = 'a';
1293 wszPath[1] = '\0';
1294 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1295 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1296 ok (GetLastError()==0xdeadbeef ||
1297 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1298 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1299 ok (!wszPath[0], "Expected empty path\n");
1300 if (result) {
1301 IShellFolder_Release(psfDesktop);
1302 return;
1305 IMalloc_Free(ppM, pidlMyComputer);
1307 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1308 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1309 if (!result) {
1310 IShellFolder_Release(psfDesktop);
1311 return;
1313 myPathAddBackslashW(wszFileName);
1314 lstrcatW(wszFileName, wszTestFile);
1315 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1316 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1317 if (hTestFile == INVALID_HANDLE_VALUE) {
1318 IShellFolder_Release(psfDesktop);
1319 return;
1321 CloseHandle(hTestFile);
1323 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1324 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1325 if (hr != S_OK) {
1326 IShellFolder_Release(psfDesktop);
1327 DeleteFileW(wszFileName);
1328 IMalloc_Free(ppM, pidlTestFile);
1329 return;
1332 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1333 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1334 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1335 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1336 IShellFolder_Release(psfDesktop);
1337 DeleteFileW(wszFileName);
1338 if (hr != S_OK) {
1339 IMalloc_Free(ppM, pidlTestFile);
1340 return;
1342 if (pStrRetToBufW)
1344 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1345 ok(0 == lstrcmpW(wszFileName, wszPath),
1346 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1347 "returned incorrect path for file placed on desktop\n");
1350 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1351 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1352 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1354 if (pSHGetPathFromIDListEx)
1356 result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1357 ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1358 ok(!lstrcmpiW(wszDesktop, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1359 wine_dbgstr_w(wszPath), wine_dbgstr_w(wszDesktop));
1361 result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1362 ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1363 ok(!lstrcmpiW(wszFileName, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1364 wine_dbgstr_w(wszPath), wine_dbgstr_w(wszFileName));
1366 SetLastError(0xdeadbeef);
1367 memset(wszPath, 0x55, sizeof(wszPath));
1368 result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, 5, SFGAO_FILESYSTEM);
1369 ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1371 SetLastError(0xdeadbeef);
1372 memset(wszPath, 0x55, sizeof(wszPath));
1373 result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, 5, SFGAO_FILESYSTEM);
1374 ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1376 else
1377 win_skip("SHGetPathFromIDListEx not available\n");
1379 IMalloc_Free(ppM, pidlTestFile);
1381 /* Test if we can get the path from the start menu "program files" PIDL. */
1382 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1383 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1385 SetLastError(0xdeadbeef);
1386 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1387 IMalloc_Free(ppM, pidlPrograms);
1388 ok(result, "SHGetPathFromIDListW failed\n");
1391 static void test_EnumObjects_and_CompareIDs(void)
1393 ITEMIDLIST *newPIDL;
1394 IShellFolder *IDesktopFolder, *testIShellFolder;
1395 char cCurrDirA [MAX_PATH] = {0};
1396 static const CHAR cTestDirA[] = "\\testdir";
1397 WCHAR cTestDirW[MAX_PATH];
1398 int len;
1399 HRESULT hr;
1401 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1402 len = lstrlenA(cCurrDirA);
1404 if(len == 0) {
1405 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1406 return;
1408 if(cCurrDirA[len-1] == '\\')
1409 cCurrDirA[len-1] = 0;
1411 lstrcatA(cCurrDirA, cTestDirA);
1412 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1414 hr = SHGetDesktopFolder(&IDesktopFolder);
1415 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1417 CreateFilesFolders();
1419 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1420 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1422 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1423 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1425 test_EnumObjects(testIShellFolder);
1427 IShellFolder_Release(testIShellFolder);
1429 Cleanup();
1431 IMalloc_Free(ppM, newPIDL);
1433 IShellFolder_Release(IDesktopFolder);
1436 /* A simple implementation of an IPropertyBag, which returns fixed values for
1437 * 'Target' and 'Attributes' properties.
1439 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1440 void **ppvObject)
1442 if (!ppvObject)
1443 return E_INVALIDARG;
1445 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1446 *ppvObject = iface;
1447 } else {
1448 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1449 return E_NOINTERFACE;
1452 IPropertyBag_AddRef(iface);
1453 return S_OK;
1456 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1457 return 2;
1460 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1461 return 1;
1464 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1465 VARIANT *pVar, IErrorLog *pErrorLog)
1467 static const WCHAR wszTargetSpecialFolder[] = {
1468 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1469 static const WCHAR wszTarget[] = {
1470 'T','a','r','g','e','t',0 };
1471 static const WCHAR wszAttributes[] = {
1472 'A','t','t','r','i','b','u','t','e','s',0 };
1473 static const WCHAR wszResolveLinkFlags[] = {
1474 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1475 static const WCHAR wszTargetKnownFolder[] = {
1476 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1477 static const WCHAR wszCLSID[] = {
1478 'C','L','S','I','D',0 };
1480 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1481 ok(V_VT(pVar) == VT_I4 ||
1482 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1483 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1484 return E_INVALIDARG;
1487 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1489 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1490 return E_INVALIDARG;
1493 if (!lstrcmpW(pszPropName, wszTarget)) {
1494 WCHAR wszPath[MAX_PATH];
1495 BOOL result;
1497 ok(V_VT(pVar) == VT_BSTR ||
1498 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1499 "Wrong variant type for 'Target' property!\n");
1500 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1502 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1503 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1504 if (!result) return E_INVALIDARG;
1506 V_BSTR(pVar) = SysAllocString(wszPath);
1507 return S_OK;
1510 if (!lstrcmpW(pszPropName, wszAttributes)) {
1511 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1512 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1513 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1514 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1515 return S_OK;
1518 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1519 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1520 /* TODO */
1521 return E_INVALIDARG;
1524 if (!lstrcmpW(pszPropName, wszCLSID)) {
1525 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1526 /* TODO */
1527 return E_INVALIDARG;
1530 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1531 return E_INVALIDARG;
1534 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1535 VARIANT *pVar)
1537 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1538 return E_NOTIMPL;
1541 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1542 InitPropertyBag_IPropertyBag_QueryInterface,
1543 InitPropertyBag_IPropertyBag_AddRef,
1544 InitPropertyBag_IPropertyBag_Release,
1545 InitPropertyBag_IPropertyBag_Read,
1546 InitPropertyBag_IPropertyBag_Write
1549 static struct IPropertyBag InitPropertyBag = {
1550 &InitPropertyBag_IPropertyBagVtbl
1553 static void test_FolderShortcut(void) {
1554 IPersistPropertyBag *pPersistPropertyBag;
1555 IShellFolder *pShellFolder, *pDesktopFolder;
1556 IPersistFolder3 *pPersistFolder3;
1557 HRESULT hr;
1558 STRRET strret;
1559 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1560 BOOL result;
1561 CLSID clsid;
1562 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1563 HKEY hShellExtKey;
1564 WCHAR wszWineTestFolder[] = {
1565 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1566 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1567 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1568 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1569 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1570 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1571 'N','a','m','e','S','p','a','c','e','\\',
1572 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1573 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1575 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1576 static const GUID CLSID_UnixDosFolder =
1577 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1579 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1580 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1581 return;
1584 if (!pSHGetFolderPathAndSubDirA)
1586 win_skip("FolderShortcut test doesn't work on Win2k\n");
1587 return;
1590 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1591 * via their IPersistPropertyBag interface. And that the target folder
1592 * is taken from the IPropertyBag's 'Target' property.
1594 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1595 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1596 if (hr == REGDB_E_CLASSNOTREG) {
1597 win_skip("CLSID_FolderShortcut is not implemented\n");
1598 return;
1600 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1601 if (hr != S_OK) return;
1603 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1604 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1605 if (hr != S_OK) {
1606 IPersistPropertyBag_Release(pPersistPropertyBag);
1607 return;
1610 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1611 (LPVOID*)&pShellFolder);
1612 IPersistPropertyBag_Release(pPersistPropertyBag);
1613 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1614 if (hr != S_OK) return;
1616 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1617 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* win10 */,
1618 "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1619 if (hr != S_OK) {
1620 IShellFolder_Release(pShellFolder);
1621 return;
1624 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1625 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1626 if (!result) return;
1628 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1629 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1631 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1632 IShellFolder_Release(pShellFolder);
1633 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1634 if (hr != S_OK) return;
1636 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1637 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1638 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1640 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1641 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1642 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1644 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1645 * shell namespace. The target folder, read from the property bag above, remains untouched.
1646 * The following tests show this: The itemidlist for some imaginary shellfolder object
1647 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1648 * itemidlist, but GetDisplayNameOf still returns the path from above.
1650 hr = SHGetDesktopFolder(&pDesktopFolder);
1651 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1652 if (hr != S_OK) return;
1654 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1655 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1656 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1657 RegCloseKey(hShellExtKey);
1658 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1659 &pidlWineTestFolder, NULL);
1660 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1661 IShellFolder_Release(pDesktopFolder);
1662 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1663 if (hr != S_OK) return;
1665 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1666 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1667 if (hr != S_OK) {
1668 IPersistFolder3_Release(pPersistFolder3);
1669 pILFree(pidlWineTestFolder);
1670 return;
1673 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1674 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1675 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1676 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1677 pILFree(pidlCurrentFolder);
1678 pILFree(pidlWineTestFolder);
1680 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1681 IPersistFolder3_Release(pPersistFolder3);
1682 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1683 if (hr != S_OK) return;
1685 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1686 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1687 if (hr != S_OK) {
1688 IShellFolder_Release(pShellFolder);
1689 return;
1692 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1693 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1695 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1696 * but ShellFSFolders. */
1697 myPathAddBackslashW(wszDesktopPath);
1698 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1699 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1700 IShellFolder_Release(pShellFolder);
1701 return;
1704 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1705 &pidlSubFolder, NULL);
1706 RemoveDirectoryW(wszDesktopPath);
1707 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1708 if (hr != S_OK) {
1709 IShellFolder_Release(pShellFolder);
1710 return;
1713 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1714 (LPVOID*)&pPersistFolder3);
1715 IShellFolder_Release(pShellFolder);
1716 pILFree(pidlSubFolder);
1717 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1718 if (hr != S_OK)
1719 return;
1721 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1722 * a little bit and also allow CLSID_UnixDosFolder. */
1723 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1724 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1725 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1726 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1728 IPersistFolder3_Release(pPersistFolder3);
1731 #include "pshpack1.h"
1732 struct FileStructA {
1733 BYTE type;
1734 BYTE dummy;
1735 DWORD dwFileSize;
1736 WORD uFileDate; /* In our current implementation this is */
1737 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1738 WORD uFileAttribs;
1739 CHAR szName[1];
1742 struct FileStructW {
1743 WORD cbLen; /* Length of this element. */
1744 BYTE abFooBar1[6]; /* Beyond any recognition. */
1745 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1746 WORD uTime; /* (this is currently speculation) */
1747 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1748 WORD uTime2; /* (this is currently speculation) */
1749 BYTE abFooBar2[4]; /* Beyond any recognition. */
1750 WCHAR wszName[1]; /* The long filename in unicode. */
1751 /* Just for documentation: Right after the unicode string: */
1752 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1753 * SHITEMID->cb == uOffset + cbLen */
1755 #include "poppack.h"
1757 static void test_ITEMIDLIST_format(void) {
1758 WCHAR wszPersonal[MAX_PATH];
1759 LPSHELLFOLDER psfDesktop, psfPersonal;
1760 LPITEMIDLIST pidlPersonal, pidlFile;
1761 HANDLE hFile;
1762 HRESULT hr;
1763 BOOL bResult;
1764 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1765 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1766 int i;
1768 if (!pSHGetSpecialFolderPathW) return;
1770 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1771 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1772 if (!bResult) return;
1774 SetLastError(0xdeadbeef);
1775 bResult = SetCurrentDirectoryW(wszPersonal);
1776 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1777 win_skip("Most W-calls are not implemented\n");
1778 return;
1780 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1781 if (!bResult) return;
1783 hr = SHGetDesktopFolder(&psfDesktop);
1784 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1785 if (hr != S_OK) return;
1787 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1788 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1789 if (hr != S_OK) {
1790 IShellFolder_Release(psfDesktop);
1791 return;
1794 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1795 (LPVOID*)&psfPersonal);
1796 IShellFolder_Release(psfDesktop);
1797 pILFree(pidlPersonal);
1798 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1799 if (hr != S_OK) return;
1801 for (i=0; i<3; i++) {
1802 CHAR szFile[MAX_PATH];
1803 struct FileStructA *pFileStructA;
1804 WORD cbOffset;
1806 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1808 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1809 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1810 if (hFile == INVALID_HANDLE_VALUE) {
1811 IShellFolder_Release(psfPersonal);
1812 return;
1814 CloseHandle(hFile);
1816 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1817 DeleteFileW(wszFile[i]);
1818 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1819 if (hr != S_OK) {
1820 IShellFolder_Release(psfPersonal);
1821 return;
1824 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1825 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1826 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1827 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1829 if (i < 2) /* First two file names are already in valid 8.3 format */
1830 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1831 else
1832 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1833 * can't implement this correctly, since unix filesystems don't support
1834 * this nasty short/long filename stuff. So we'll probably stay with our
1835 * current habit of storing the long filename here, which seems to work
1836 * just fine. */
1837 todo_wine
1838 ok(pidlFile->mkid.abID[18] == '~' ||
1839 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1840 "Should be derived 8.3 name!\n");
1842 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1843 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1844 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1845 "Alignment byte, where there shouldn't be!\n");
1847 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1848 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1849 "There should be an alignment byte, but isn't!\n");
1851 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1852 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1853 ok ((cbOffset >= sizeof(struct FileStructA) &&
1854 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1855 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1856 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1857 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1859 if (cbOffset >= sizeof(struct FileStructA) &&
1860 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1862 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1863 WCHAR *name = pFileStructW->wszName;
1865 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1866 "FileStructW's offset and length should add up to the PIDL's length!\n");
1868 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1869 /* Since we just created the file, time of creation,
1870 * time of last access and time of last write access just be the same.
1871 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1872 * after the first run. I do remember something with NTFS keeping the creation time
1873 * if a file is deleted and then created again within a couple of seconds or so.
1874 * Might be the reason. */
1875 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1876 pFileStructA->uFileTime == pFileStructW->uTime,
1877 "Last write time should match creation time!\n");
1879 /* On FAT filesystems the last access time is midnight
1880 local time, so the values of uDate2 and uTime2 will
1881 depend on the local timezone. If the times are exactly
1882 equal then the dates should be identical for both FAT
1883 and NTFS as no timezone is more than 1 day away from UTC.
1885 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1887 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1888 "Last write date and time should match last access date and time!\n");
1890 else
1892 /* Filesystem may be FAT. Check date within 1 day
1893 and seconds are zero. */
1894 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1895 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1896 "Last access time on FAT filesystems should have zero seconds.\n");
1897 /* TODO: Perform check for date being within one day.*/
1900 ok (!lstrcmpW(wszFile[i], name) ||
1901 !lstrcmpW(wszFile[i], name + 9) || /* Vista */
1902 !lstrcmpW(wszFile[i], name + 11) || /* Win7 */
1903 !lstrcmpW(wszFile[i], name + 13), /* Win8 */
1904 "The filename should be stored in unicode at this position!\n");
1908 pILFree(pidlFile);
1911 IShellFolder_Release(psfPersonal);
1914 static void test_SHGetFolderPathA(void)
1916 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1917 BOOL is_wow64;
1918 char path[MAX_PATH];
1919 char path_x86[MAX_PATH];
1920 char path_key[MAX_PATH];
1921 HRESULT hr;
1922 HKEY key;
1924 if (!pSHGetFolderPathA)
1926 win_skip("SHGetFolderPathA not present\n");
1927 return;
1929 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1931 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1932 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1933 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1934 if (hr == E_FAIL)
1936 win_skip( "Program Files (x86) not supported\n" );
1937 return;
1939 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1940 if (is_win64)
1942 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1943 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1944 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1946 else
1948 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1949 if (is_wow64)
1950 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1951 else
1952 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1954 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1956 DWORD type, count = sizeof(path_x86);
1957 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1959 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1960 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1962 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1963 RegCloseKey( key );
1966 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1967 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1968 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1969 if (hr == E_FAIL)
1971 win_skip( "Common Files (x86) not supported\n" );
1972 return;
1974 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1975 if (is_win64)
1977 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1978 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1979 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1981 else
1983 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1984 if (is_wow64)
1985 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1986 else
1987 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1989 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1991 DWORD type, count = sizeof(path_x86);
1992 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1994 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1995 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1997 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
2001 static void test_SHGetFolderPathAndSubDirA(void)
2003 HRESULT ret;
2004 BOOL delret;
2005 DWORD dwret;
2006 int i;
2007 static const char wine[] = "wine";
2008 static const char winetemp[] = "wine\\temp";
2009 static char appdata[MAX_PATH];
2010 static char testpath[MAX_PATH];
2011 static char toolongpath[MAX_PATH+1];
2013 if(!pSHGetFolderPathAndSubDirA)
2015 win_skip("SHGetFolderPathAndSubDirA not present!\n");
2016 return;
2019 if(!pSHGetFolderPathA) {
2020 win_skip("SHGetFolderPathA not present!\n");
2021 return;
2023 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
2025 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
2026 return;
2029 sprintf(testpath, "%s\\%s", appdata, winetemp);
2030 delret = RemoveDirectoryA(testpath);
2031 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
2032 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
2033 return;
2036 sprintf(testpath, "%s\\%s", appdata, wine);
2037 delret = RemoveDirectoryA(testpath);
2038 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
2039 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
2040 return;
2043 /* test invalid second parameter */
2044 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
2045 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
2047 /* test fourth parameter */
2048 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
2049 switch(ret) {
2050 case S_OK: /* winvista */
2051 ok(!strncmp(appdata, testpath, strlen(appdata)),
2052 "expected %s to start with %s\n", testpath, appdata);
2053 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2054 "expected %s to end with %s\n", testpath, winetemp);
2055 break;
2056 case E_INVALIDARG: /* winxp, win2k3 */
2057 break;
2058 default:
2059 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
2062 /* test fifth parameter */
2063 testpath[0] = '\0';
2064 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
2065 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2066 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2068 testpath[0] = '\0';
2069 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
2070 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2071 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2073 testpath[0] = '\0';
2074 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
2075 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2076 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2078 for(i=0; i< MAX_PATH; i++)
2079 toolongpath[i] = '0' + i % 10;
2080 toolongpath[MAX_PATH] = '\0';
2081 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2082 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2083 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2085 testpath[0] = '\0';
2086 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2087 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2089 /* test a not existing path */
2090 testpath[0] = '\0';
2091 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2092 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2093 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2095 /* create a directory inside a not existing directory */
2096 testpath[0] = '\0';
2097 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2098 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2099 ok(!strncmp(appdata, testpath, strlen(appdata)),
2100 "expected %s to start with %s\n", testpath, appdata);
2101 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2102 "expected %s to end with %s\n", testpath, winetemp);
2103 dwret = GetFileAttributesA(testpath);
2104 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2106 /* cleanup */
2107 sprintf(testpath, "%s\\%s", appdata, winetemp);
2108 RemoveDirectoryA(testpath);
2109 sprintf(testpath, "%s\\%s", appdata, wine);
2110 RemoveDirectoryA(testpath);
2113 static void test_LocalizedNames(void)
2115 static char cCurrDirA[MAX_PATH];
2116 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2117 IShellFolder *IDesktopFolder, *testIShellFolder;
2118 ITEMIDLIST *newPIDL;
2119 int len;
2120 HRESULT hr;
2121 static char resourcefile[MAX_PATH];
2122 DWORD res;
2123 HANDLE file;
2124 STRRET strret;
2125 BOOL ret;
2127 static const char desktopini_contents1[] =
2128 "[.ShellClassInfo]\r\n"
2129 "LocalizedResourceName=@";
2130 static const char desktopini_contents2[] =
2131 ",-1\r\n";
2132 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2133 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2135 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2136 CreateDirectoryA(".\\testfolder", NULL);
2138 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2140 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2142 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2143 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2144 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2145 ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2146 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2147 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
2148 ok(ret, "WriteFile failed %i\n", GetLastError());
2149 CloseHandle(file);
2151 /* get IShellFolder for parent */
2152 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2153 len = lstrlenA(cCurrDirA);
2155 if (len == 0) {
2156 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2157 goto cleanup;
2159 if(cCurrDirA[len-1] == '\\')
2160 cCurrDirA[len-1] = 0;
2162 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2164 hr = SHGetDesktopFolder(&IDesktopFolder);
2165 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2167 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2168 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2170 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2171 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2173 IMalloc_Free(ppM, newPIDL);
2175 /* windows reads the display name from the resource */
2176 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2177 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2179 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2180 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2182 if (hr == S_OK && pStrRetToBufW)
2184 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2185 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2186 todo_wine
2187 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2188 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2189 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2192 /* editing name is also read from the resource */
2193 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2194 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2196 if (hr == S_OK && pStrRetToBufW)
2198 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2199 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2200 todo_wine
2201 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2202 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2203 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2206 /* parsing name is unchanged */
2207 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2208 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2210 if (hr == S_OK && pStrRetToBufW)
2212 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2213 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2214 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2217 IShellFolder_Release(IDesktopFolder);
2218 IShellFolder_Release(testIShellFolder);
2220 IMalloc_Free(ppM, newPIDL);
2222 cleanup:
2223 DeleteFileA(".\\testfolder\\desktop.ini");
2224 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2225 RemoveDirectoryA(".\\testfolder");
2228 static void test_SHCreateShellItem(void)
2230 IShellItem *shellitem, *shellitem2;
2231 IPersistIDList *persistidl;
2232 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2233 HRESULT ret;
2234 char curdirA[MAX_PATH];
2235 WCHAR curdirW[MAX_PATH];
2236 WCHAR fnbufW[MAX_PATH];
2237 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2238 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2240 GetCurrentDirectoryA(MAX_PATH, curdirA);
2242 if (!pSHCreateShellItem)
2244 win_skip("SHCreateShellItem isn't available\n");
2245 return;
2248 if (!curdirA[0])
2250 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2251 return;
2254 if(pSHGetSpecialFolderLocation)
2256 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2257 ok(ret == S_OK, "Got 0x%08x\n", ret);
2259 else
2261 win_skip("pSHGetSpecialFolderLocation missing.\n");
2262 pidl_desktop = NULL;
2265 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2267 ret = SHGetDesktopFolder(&desktopfolder);
2268 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2270 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2271 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2273 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2274 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2276 CreateTestFile(".\\testfile");
2278 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2279 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2281 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2283 shellitem = (void*)0xdeadbeef;
2284 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2285 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2286 ok(shellitem == 0, "Got %p\n", shellitem);
2288 if (0) /* crashes on Windows XP */
2290 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2291 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2292 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2293 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2296 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2297 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2298 if (SUCCEEDED(ret))
2300 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2301 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2302 if (SUCCEEDED(ret))
2304 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2305 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2306 if (SUCCEEDED(ret))
2308 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2309 pILFree(pidl_test);
2311 IPersistIDList_Release(persistidl);
2313 IShellItem_Release(shellitem);
2316 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2317 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2318 if (SUCCEEDED(ret))
2320 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2321 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2322 if (SUCCEEDED(ret))
2324 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2325 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2326 if (SUCCEEDED(ret))
2328 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2329 pILFree(pidl_test);
2331 IPersistIDList_Release(persistidl);
2334 ret = IShellItem_GetParent(shellitem, &shellitem2);
2335 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2336 if (SUCCEEDED(ret))
2338 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2339 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2340 if (SUCCEEDED(ret))
2342 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2343 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2344 if (SUCCEEDED(ret))
2346 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2347 pILFree(pidl_test);
2349 IPersistIDList_Release(persistidl);
2351 IShellItem_Release(shellitem2);
2354 IShellItem_Release(shellitem);
2357 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2358 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2359 if (SUCCEEDED(ret))
2361 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2362 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2363 if (SUCCEEDED(ret))
2365 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2366 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2367 if (SUCCEEDED(ret))
2369 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2370 pILFree(pidl_test);
2372 IPersistIDList_Release(persistidl);
2374 IShellItem_Release(shellitem);
2377 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2378 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2379 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2380 if (SUCCEEDED(ret))
2382 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2383 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2384 if (SUCCEEDED(ret))
2386 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2387 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2388 if (SUCCEEDED(ret))
2390 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2391 pILFree(pidl_test);
2393 IPersistIDList_Release(persistidl);
2395 IShellItem_Release(shellitem);
2398 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2399 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2400 if (SUCCEEDED(ret))
2402 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2403 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2404 if (SUCCEEDED(ret))
2406 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2407 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2408 if (SUCCEEDED(ret))
2410 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2411 pILFree(pidl_test);
2413 IPersistIDList_Release(persistidl);
2416 IShellItem_Release(shellitem);
2419 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2420 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2421 if (SUCCEEDED(ret))
2423 ret = IShellItem_GetParent(shellitem, &shellitem2);
2424 ok(FAILED(ret), "Got 0x%08x\n", ret);
2425 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2426 IShellItem_Release(shellitem);
2429 /* SHCreateItemFromParsingName */
2430 if(pSHCreateItemFromParsingName)
2432 if(0)
2434 /* Crashes under windows 7 */
2435 pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2438 shellitem = (void*)0xdeadbeef;
2439 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2440 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2441 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2443 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2444 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2445 "SHCreateItemFromParsingName returned %x\n", ret);
2446 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2448 lstrcpyW(fnbufW, curdirW);
2449 myPathAddBackslashW(fnbufW);
2450 lstrcatW(fnbufW, testfileW);
2452 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2453 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2454 if(SUCCEEDED(ret))
2456 LPWSTR tmp_fname;
2457 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2458 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2459 if(SUCCEEDED(ret))
2461 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2462 CoTaskMemFree(tmp_fname);
2464 IShellItem_Release(shellitem);
2467 else
2468 win_skip("No SHCreateItemFromParsingName\n");
2471 /* SHCreateItemFromIDList */
2472 if(pSHCreateItemFromIDList)
2474 if(0)
2476 /* Crashes under win7 */
2477 pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2480 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2481 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2483 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2484 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2485 if (SUCCEEDED(ret))
2487 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2488 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2489 if (SUCCEEDED(ret))
2491 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2492 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2493 if (SUCCEEDED(ret))
2495 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2496 pILFree(pidl_test);
2498 IPersistIDList_Release(persistidl);
2500 IShellItem_Release(shellitem);
2503 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2504 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2505 if (SUCCEEDED(ret))
2507 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2508 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2509 if (SUCCEEDED(ret))
2511 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2512 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2513 if (SUCCEEDED(ret))
2515 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2516 pILFree(pidl_test);
2518 IPersistIDList_Release(persistidl);
2520 IShellItem_Release(shellitem);
2523 else
2524 win_skip("No SHCreateItemFromIDList\n");
2526 DeleteFileA(".\\testfile");
2527 pILFree(pidl_abstestfile);
2528 pILFree(pidl_testfile);
2529 pILFree(pidl_desktop);
2530 pILFree(pidl_cwd);
2531 IShellFolder_Release(currentfolder);
2532 IShellFolder_Release(desktopfolder);
2535 static void test_SHGetNameFromIDList(void)
2537 IShellItem *shellitem;
2538 LPITEMIDLIST pidl;
2539 LPWSTR name_string;
2540 HRESULT hres;
2541 UINT i;
2542 static const DWORD flags[] = {
2543 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2544 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2545 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2546 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2548 if(!pSHGetNameFromIDList)
2550 win_skip("SHGetNameFromIDList missing.\n");
2551 return;
2554 /* These should be available on any platform that passed the above test. */
2555 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2556 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2557 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2558 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2560 if(0)
2562 /* Crashes under win7 */
2563 pSHGetNameFromIDList(NULL, 0, NULL);
2566 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2567 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2569 /* Test the desktop */
2570 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2571 ok(hres == S_OK, "Got 0x%08x\n", hres);
2572 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2573 ok(hres == S_OK, "Got 0x%08x\n", hres);
2574 if(SUCCEEDED(hres))
2576 WCHAR *nameSI, *nameSH;
2577 WCHAR buf[MAX_PATH];
2578 HRESULT hrSI, hrSH, hrSF;
2579 STRRET strret;
2580 IShellFolder *psf;
2581 BOOL res;
2583 SHGetDesktopFolder(&psf);
2584 for(i = 0; flags[i] != -1234; i++)
2586 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2587 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2588 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2589 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2590 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2591 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2593 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2594 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2596 if(SUCCEEDED(hrSF))
2598 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2599 if(SUCCEEDED(hrSI))
2600 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2601 if(SUCCEEDED(hrSF))
2602 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2604 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2605 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2607 IShellFolder_Release(psf);
2609 if(pSHGetPathFromIDListW){
2610 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2611 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2612 res = pSHGetPathFromIDListW(pidl, buf);
2613 ok(res == TRUE, "Got %d\n", res);
2614 if(SUCCEEDED(hrSI) && res)
2615 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2616 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2617 }else
2618 win_skip("pSHGetPathFromIDListW not available\n");
2620 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2621 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2622 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2624 IShellItem_Release(shellitem);
2626 pILFree(pidl);
2628 /* Test the control panel */
2629 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2630 ok(hres == S_OK, "Got 0x%08x\n", hres);
2631 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2632 ok(hres == S_OK, "Got 0x%08x\n", hres);
2633 if(SUCCEEDED(hres))
2635 WCHAR *nameSI, *nameSH;
2636 WCHAR buf[MAX_PATH];
2637 HRESULT hrSI, hrSH, hrSF;
2638 STRRET strret;
2639 IShellFolder *psf;
2640 BOOL res;
2642 SHGetDesktopFolder(&psf);
2643 for(i = 0; flags[i] != -1234; i++)
2645 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2646 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2647 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2648 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2649 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2650 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2652 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2653 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2655 if(SUCCEEDED(hrSF))
2657 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2658 if(SUCCEEDED(hrSI))
2659 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2660 if(SUCCEEDED(hrSF))
2661 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2663 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2664 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2666 IShellFolder_Release(psf);
2668 if(pSHGetPathFromIDListW){
2669 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2670 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2671 res = pSHGetPathFromIDListW(pidl, buf);
2672 ok(res == FALSE, "Got %d\n", res);
2673 if(SUCCEEDED(hrSI) && res)
2674 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2675 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2676 }else
2677 win_skip("pSHGetPathFromIDListW not available\n");
2679 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2680 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2681 "Got 0x%08x\n", hres);
2682 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2684 IShellItem_Release(shellitem);
2686 pILFree(pidl);
2689 static void test_SHGetItemFromDataObject(void)
2691 IShellFolder *psfdesktop;
2692 IShellItem *psi;
2693 IShellView *psv;
2694 HRESULT hres;
2696 if(!pSHGetItemFromDataObject)
2698 win_skip("No SHGetItemFromDataObject.\n");
2699 return;
2702 if(0)
2704 /* Crashes under win7 */
2705 pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2708 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2709 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2711 SHGetDesktopFolder(&psfdesktop);
2713 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2714 ok(hres == S_OK, "got 0x%08x\n", hres);
2715 if(SUCCEEDED(hres))
2717 IEnumIDList *peidl;
2718 IDataObject *pdo;
2719 SHCONTF enum_flags;
2721 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2722 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2723 ok(hres == S_OK, "got 0x%08x\n", hres);
2724 if(SUCCEEDED(hres))
2726 LPITEMIDLIST apidl[5];
2727 UINT count = 0, i;
2729 for(count = 0; count < 5; count++)
2730 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2731 break;
2733 if(count)
2735 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2736 &IID_IDataObject, NULL, (void**)&pdo);
2737 ok(hres == S_OK, "got 0x%08x\n", hres);
2738 if(SUCCEEDED(hres))
2740 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2741 ok(hres == S_OK, "got 0x%08x\n", hres);
2742 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2743 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2744 ok(hres == S_OK, "got 0x%08x\n", hres);
2745 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2746 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2747 ok(hres == S_OK, "got 0x%08x\n", hres);
2748 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2749 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2750 ok(hres == S_OK, "got 0x%08x\n", hres);
2751 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2752 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2753 ok(hres == S_OK, "got 0x%08x\n", hres);
2754 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2756 IDataObject_Release(pdo);
2759 else
2760 skip("No file(s) found - skipping single-file test.\n");
2762 if(count > 1)
2764 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2765 &IID_IDataObject, NULL, (void**)&pdo);
2766 ok(hres == S_OK, "got 0x%08x\n", hres);
2767 if(SUCCEEDED(hres))
2769 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2770 ok(hres == S_OK, "got 0x%08x\n", hres);
2771 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2772 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2773 ok(hres == S_OK, "got 0x%08x\n", hres);
2774 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2775 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2776 ok(hres == S_OK, "got 0x%08x\n", hres);
2777 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2778 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2779 ok(hres == S_OK, "got 0x%08x\n", hres);
2780 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2781 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2782 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2783 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2784 IDataObject_Release(pdo);
2787 else
2788 skip("zero or one file found - skipping multi-file test.\n");
2790 for(i = 0; i < count; i++)
2791 pILFree(apidl[i]);
2793 IEnumIDList_Release(peidl);
2796 IShellView_Release(psv);
2799 IShellFolder_Release(psfdesktop);
2802 static void test_ShellItemCompare(void)
2804 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2805 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2806 IShellFolder *psf_desktop, *psf_current;
2807 LPITEMIDLIST pidl_cwd;
2808 WCHAR curdirW[MAX_PATH];
2809 BOOL failed;
2810 HRESULT hr;
2811 static const WCHAR filesW[][9] = {
2812 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2813 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2814 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2815 int order;
2816 UINT i;
2818 if(!pSHCreateShellItem)
2820 win_skip("SHCreateShellItem missing.\n");
2821 return;
2824 GetCurrentDirectoryW(MAX_PATH, curdirW);
2825 if (!curdirW[0])
2827 skip("Failed to get current directory, skipping.\n");
2828 return;
2831 CreateDirectoryA(".\\a", NULL);
2832 CreateDirectoryA(".\\b", NULL);
2833 CreateDirectoryA(".\\c", NULL);
2834 CreateTestFile(".\\a\\a");
2835 CreateTestFile(".\\a\\b");
2836 CreateTestFile(".\\a\\c");
2837 CreateTestFile(".\\b\\a");
2838 CreateTestFile(".\\b\\b");
2839 CreateTestFile(".\\b\\c");
2840 CreateTestFile(".\\c\\a");
2841 CreateTestFile(".\\c\\b");
2842 CreateTestFile(".\\c\\c");
2844 SHGetDesktopFolder(&psf_desktop);
2845 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2846 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2847 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2848 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2849 IShellFolder_Release(psf_desktop);
2850 ILFree(pidl_cwd);
2852 /* Generate ShellItems for the files */
2853 memset(&psi, 0, sizeof(psi));
2854 failed = FALSE;
2855 for(i = 0; i < 9; i++)
2857 LPITEMIDLIST pidl_testfile = NULL;
2859 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2860 NULL, &pidl_testfile, NULL);
2861 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2862 if(SUCCEEDED(hr))
2864 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2865 ok(hr == S_OK, "Got 0x%08x\n", hr);
2866 pILFree(pidl_testfile);
2868 if(FAILED(hr)) failed = TRUE;
2870 if(failed)
2872 skip("Failed to create all shellitems.\n");
2873 goto cleanup;
2876 /* Generate ShellItems for the folders */
2877 hr = IShellItem_GetParent(psi[0], &psi_a);
2878 ok(hr == S_OK, "Got 0x%08x\n", hr);
2879 if(FAILED(hr)) failed = TRUE;
2880 hr = IShellItem_GetParent(psi[3], &psi_b);
2881 ok(hr == S_OK, "Got 0x%08x\n", hr);
2882 if(FAILED(hr)) failed = TRUE;
2883 hr = IShellItem_GetParent(psi[6], &psi_c);
2884 ok(hr == S_OK, "Got 0x%08x\n", hr);
2885 if(FAILED(hr)) failed = TRUE;
2887 if(failed)
2889 skip("Failed to create shellitems.\n");
2890 goto cleanup;
2893 if(0)
2895 /* Crashes on native (win7, winxp) */
2896 IShellItem_Compare(psi_a, NULL, 0, NULL);
2897 IShellItem_Compare(psi_a, psi_b, 0, NULL);
2898 IShellItem_Compare(psi_a, NULL, 0, &order);
2901 /* Basics */
2902 for(i = 0; i < 9; i++)
2904 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2905 ok(hr == S_OK, "Got 0x%08x\n", hr);
2906 ok(order == 0, "Got order %d\n", order);
2907 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2908 ok(hr == S_OK, "Got 0x%08x\n", hr);
2909 ok(order == 0, "Got order %d\n", order);
2910 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2911 ok(hr == S_OK, "Got 0x%08x\n", hr);
2912 ok(order == 0, "Got order %d\n", order);
2915 /* Order */
2916 /* a\b:a\a , a\b:a\c, a\b:a\b */
2917 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2918 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2919 ok(order == 1, "Got order %d\n", order);
2920 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2921 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2922 ok(order == -1, "Got order %d\n", order);
2923 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2924 ok(hr == S_OK, "Got 0x%08x\n", hr);
2925 ok(order == 0, "Got order %d\n", order);
2927 /* b\b:a\b, b\b:c\b, b\b:c\b */
2928 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2929 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2930 ok(order == 1, "Got order %d\n", order);
2931 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2932 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2933 ok(order == -1, "Got order %d\n", order);
2934 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2935 ok(hr == S_OK, "Got 0x%08x\n", hr);
2936 ok(order == 0, "Got order %d\n", order);
2938 /* b:a\a, b:a\c, b:a\b */
2939 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2940 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2941 todo_wine ok(order == 1, "Got order %d\n", order);
2942 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2943 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2944 todo_wine ok(order == 1, "Got order %d\n", order);
2945 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2946 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2947 todo_wine ok(order == 1, "Got order %d\n", order);
2949 /* b:c\a, b:c\c, b:c\b */
2950 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2951 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2952 ok(order == -1, "Got order %d\n", order);
2953 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2954 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2955 ok(order == -1, "Got order %d\n", order);
2956 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2957 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2958 ok(order == -1, "Got order %d\n", order);
2960 /* a\b:a\a , a\b:a\c, a\b:a\b */
2961 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2962 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2963 ok(order == 1, "Got order %d\n", order);
2964 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2965 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2966 ok(order == -1, "Got order %d\n", order);
2967 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2968 ok(hr == S_OK, "Got 0x%08x\n", hr);
2969 ok(order == 0, "Got order %d\n", order);
2971 /* b\b:a\b, b\b:c\b, b\b:c\b */
2972 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2973 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2974 ok(order == 1, "Got order %d\n", order);
2975 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2976 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2977 ok(order == -1, "Got order %d\n", order);
2978 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2979 ok(hr == S_OK, "Got 0x%08x\n", hr);
2980 ok(order == 0, "Got order %d\n", order);
2982 /* b:a\a, b:a\c, b:a\b */
2983 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2984 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2985 todo_wine ok(order == 1, "Got order %d\n", order);
2986 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2987 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2988 todo_wine ok(order == 1, "Got order %d\n", order);
2989 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2990 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2991 todo_wine ok(order == 1, "Got order %d\n", order);
2993 /* b:c\a, b:c\c, b:c\b */
2994 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2995 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2996 ok(order == -1, "Got order %d\n", order);
2997 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2998 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2999 ok(order == -1, "Got order %d\n", order);
3000 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
3001 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3002 ok(order == -1, "Got order %d\n", order);
3004 cleanup:
3005 IShellFolder_Release(psf_current);
3007 DeleteFileA(".\\a\\a");
3008 DeleteFileA(".\\a\\b");
3009 DeleteFileA(".\\a\\c");
3010 DeleteFileA(".\\b\\a");
3011 DeleteFileA(".\\b\\b");
3012 DeleteFileA(".\\b\\c");
3013 DeleteFileA(".\\c\\a");
3014 DeleteFileA(".\\c\\b");
3015 DeleteFileA(".\\c\\c");
3016 RemoveDirectoryA(".\\a");
3017 RemoveDirectoryA(".\\b");
3018 RemoveDirectoryA(".\\c");
3020 if(psi_a) IShellItem_Release(psi_a);
3021 if(psi_b) IShellItem_Release(psi_b);
3022 if(psi_c) IShellItem_Release(psi_c);
3024 for(i = 0; i < 9; i++)
3025 if(psi[i]) IShellItem_Release(psi[i]);
3028 /**************************************************************/
3029 /* IUnknown implementation for counting QueryInterface calls. */
3030 typedef struct {
3031 IUnknown IUnknown_iface;
3032 struct if_count {
3033 REFIID id;
3034 LONG count;
3035 } *ifaces;
3036 LONG unknown;
3037 } IUnknownImpl;
3039 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
3041 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
3044 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
3046 IUnknownImpl *This = impl_from_IUnknown(iunk);
3047 UINT i;
3048 BOOL found = FALSE;
3049 for(i = 0; This->ifaces[i].id != NULL; i++)
3051 if(IsEqualIID(This->ifaces[i].id, riid))
3053 This->ifaces[i].count++;
3054 found = TRUE;
3055 break;
3058 if(!found)
3059 This->unknown++;
3060 return E_NOINTERFACE;
3063 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
3065 return 2;
3068 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3070 return 1;
3073 static const IUnknownVtbl vt_IUnknown = {
3074 unk_fnQueryInterface,
3075 unk_fnAddRef,
3076 unk_fnRelease
3079 static void test_SHGetIDListFromObject(void)
3081 IUnknownImpl *punkimpl;
3082 IShellFolder *psfdesktop;
3083 IShellView *psv;
3084 LPITEMIDLIST pidl, pidl_desktop;
3085 HRESULT hres;
3086 UINT i;
3087 struct if_count ifaces[] =
3088 { {&IID_IPersistIDList, 0},
3089 {&IID_IPersistFolder2, 0},
3090 {&IID_IDataObject, 0},
3091 {&IID_IParentAndItem, 0},
3092 {&IID_IFolderView, 0},
3093 {NULL, 0} };
3095 if(!pSHGetIDListFromObject)
3097 win_skip("SHGetIDListFromObject missing.\n");
3098 return;
3101 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3103 if(0)
3105 /* Crashes native */
3106 pSHGetIDListFromObject(NULL, NULL);
3107 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3110 hres = pSHGetIDListFromObject(NULL, &pidl);
3111 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3113 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3114 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3115 punkimpl->ifaces = ifaces;
3116 punkimpl->unknown = 0;
3118 hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3119 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3120 ok(ifaces[0].count, "interface not requested.\n");
3121 ok(ifaces[1].count, "interface not requested.\n");
3122 ok(ifaces[2].count, "interface not requested.\n");
3123 todo_wine
3124 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3125 "interface not requested.\n");
3126 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3127 "interface not requested.\n");
3129 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3130 HeapFree(GetProcessHeap(), 0, punkimpl);
3132 pidl_desktop = NULL;
3133 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3134 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3136 SHGetDesktopFolder(&psfdesktop);
3138 /* Test IShellItem */
3139 if(pSHCreateShellItem)
3141 IShellItem *shellitem;
3142 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3143 ok(hres == S_OK, "got 0x%08x\n", hres);
3144 if(SUCCEEDED(hres))
3146 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3147 ok(hres == S_OK, "got 0x%08x\n", hres);
3148 if(SUCCEEDED(hres))
3150 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3151 pILFree(pidl);
3153 IShellItem_Release(shellitem);
3156 else
3157 skip("no SHCreateShellItem.\n");
3159 /* Test IShellFolder */
3160 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3161 ok(hres == S_OK, "got 0x%08x\n", hres);
3162 if(SUCCEEDED(hres))
3164 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3165 pILFree(pidl);
3168 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3169 ok(hres == S_OK, "got 0x%08x\n", hres);
3170 if(SUCCEEDED(hres))
3172 IEnumIDList *peidl;
3173 IDataObject *pdo;
3174 SHCONTF enum_flags;
3176 /* Test IFolderView */
3177 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3178 ok(hres == S_OK, "got 0x%08x\n", hres);
3179 if(SUCCEEDED(hres))
3181 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3182 pILFree(pidl);
3185 /* Test IDataObject */
3186 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3187 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3188 ok(hres == S_OK, "got 0x%08x\n", hres);
3189 if(SUCCEEDED(hres))
3191 LPITEMIDLIST apidl[5];
3192 UINT count = 0;
3193 for(count = 0; count < 5; count++)
3194 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3195 break;
3197 if(count)
3199 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3200 &IID_IDataObject, NULL, (void**)&pdo);
3201 ok(hres == S_OK, "got 0x%08x\n", hres);
3202 if(SUCCEEDED(hres))
3204 pidl = (void*)0xDEADBEEF;
3205 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3206 ok(hres == S_OK, "got 0x%08x\n", hres);
3207 ok(pidl != NULL, "pidl is NULL.\n");
3208 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3209 pILFree(pidl);
3211 IDataObject_Release(pdo);
3214 else
3215 skip("No files found - skipping single-file test.\n");
3217 if(count > 1)
3219 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3220 &IID_IDataObject, NULL, (void**)&pdo);
3221 ok(hres == S_OK, "got 0x%08x\n", hres);
3222 if(SUCCEEDED(hres))
3224 pidl = (void*)0xDEADBEEF;
3225 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3226 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3227 "got 0x%08x\n", hres);
3228 ok(pidl == NULL, "pidl is not NULL.\n");
3230 IDataObject_Release(pdo);
3233 else
3234 skip("zero or one file found - skipping multi-file test.\n");
3236 for(i = 0; i < count; i++)
3237 pILFree(apidl[i]);
3239 IEnumIDList_Release(peidl);
3242 IShellView_Release(psv);
3245 IShellFolder_Release(psfdesktop);
3246 pILFree(pidl_desktop);
3249 static void test_SHGetItemFromObject(void)
3251 IUnknownImpl *punkimpl;
3252 IShellFolder *psfdesktop;
3253 LPITEMIDLIST pidl;
3254 IShellItem *psi;
3255 IUnknown *punk;
3256 HRESULT hres;
3257 struct if_count ifaces[] =
3258 { {&IID_IPersistIDList, 0},
3259 {&IID_IPersistFolder2, 0},
3260 {&IID_IDataObject, 0},
3261 {&IID_IParentAndItem, 0},
3262 {&IID_IFolderView, 0},
3263 {NULL, 0} };
3265 if(!pSHGetItemFromObject)
3267 skip("No SHGetItemFromObject.\n");
3268 return;
3271 SHGetDesktopFolder(&psfdesktop);
3273 if(0)
3275 /* Crashes with Windows 7 */
3276 pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3277 pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3278 pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3281 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3282 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3284 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3285 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3286 punkimpl->ifaces = ifaces;
3287 punkimpl->unknown = 0;
3289 /* The same as SHGetIDListFromObject */
3290 hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3291 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3292 ok(ifaces[0].count, "interface not requested.\n");
3293 ok(ifaces[1].count, "interface not requested.\n");
3294 ok(ifaces[2].count, "interface not requested.\n");
3295 todo_wine
3296 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3297 "interface not requested.\n");
3298 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3299 "interface not requested.\n");
3301 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3302 HeapFree(GetProcessHeap(), 0, punkimpl);
3304 /* Test IShellItem */
3305 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3306 ok(hres == S_OK, "Got 0x%08x\n", hres);
3307 if(SUCCEEDED(hres))
3309 IShellItem *psi2;
3310 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3311 ok(hres == S_OK, "Got 0x%08x\n", hres);
3312 if(SUCCEEDED(hres))
3314 todo_wine
3315 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3316 IShellItem_Release(psi2);
3318 IShellItem_Release(psi);
3321 IShellFolder_Release(psfdesktop);
3324 static void test_SHCreateShellItemArray(void)
3326 IShellFolder *pdesktopsf, *psf;
3327 IShellItemArray *psia;
3328 IEnumIDList *peidl;
3329 HRESULT hr;
3330 WCHAR cTestDirW[MAX_PATH];
3331 LPITEMIDLIST pidl_testdir, pidl;
3332 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3334 if(!pSHCreateShellItemArray) {
3335 skip("No pSHCreateShellItemArray!\n");
3336 return;
3339 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3341 if(0)
3343 /* Crashes under native */
3344 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3345 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3346 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3347 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3350 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3351 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3353 SHGetDesktopFolder(&pdesktopsf);
3354 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3355 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3357 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3358 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3360 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3361 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3362 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3363 pILFree(pidl);
3365 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3366 myPathAddBackslashW(cTestDirW);
3367 lstrcatW(cTestDirW, testdirW);
3369 CreateFilesFolders();
3371 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3372 ok(hr == S_OK, "got 0x%08x\n", hr);
3373 if(SUCCEEDED(hr))
3375 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3376 (void**)&psf);
3377 ok(hr == S_OK, "Got 0x%08x\n", hr);
3379 IShellFolder_Release(pdesktopsf);
3381 if(FAILED(hr))
3383 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3384 pILFree(pidl_testdir);
3385 Cleanup();
3386 return;
3389 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3390 ok(hr == S_OK, "Got %08x\n", hr);
3391 if(SUCCEEDED(hr))
3393 LPITEMIDLIST apidl[5];
3394 UINT done, numitems, i;
3396 for(done = 0; done < 5; done++)
3397 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3398 break;
3399 ok(done == 5, "Got %d pidls\n", done);
3400 IEnumIDList_Release(peidl);
3402 /* Create a ShellItemArray */
3403 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3404 ok(hr == S_OK, "Got 0x%08x\n", hr);
3405 if(SUCCEEDED(hr))
3407 IShellItem *psi;
3409 if(0)
3411 /* Crashes in Windows 7 */
3412 IShellItemArray_GetCount(psia, NULL);
3415 IShellItemArray_GetCount(psia, &numitems);
3416 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3418 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3419 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3421 /* Compare all the items */
3422 for(i = 0; i < numitems; i++)
3424 LPITEMIDLIST pidl_abs;
3425 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3427 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3428 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3429 if(SUCCEEDED(hr))
3431 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3432 ok(hr == S_OK, "Got 0x%08x\n", hr);
3433 if(SUCCEEDED(hr))
3435 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3436 pILFree(pidl);
3438 IShellItem_Release(psi);
3440 pILFree(pidl_abs);
3442 for(i = 0; i < done; i++)
3443 pILFree(apidl[i]);
3444 IShellItemArray_Release(psia);
3448 /* SHCreateShellItemArrayFromShellItem */
3449 if(pSHCreateShellItemArrayFromShellItem)
3451 IShellItem *psi;
3453 if(0)
3455 /* Crashes under Windows 7 */
3456 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3457 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3458 pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3461 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3462 ok(hr == S_OK, "Got 0x%08x\n", hr);
3463 if(SUCCEEDED(hr))
3465 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3466 ok(hr == S_OK, "Got 0x%08x\n", hr);
3467 if(SUCCEEDED(hr))
3469 IShellItem *psi2;
3470 UINT count;
3471 hr = IShellItemArray_GetCount(psia, &count);
3472 ok(hr == S_OK, "Got 0x%08x\n", hr);
3473 ok(count == 1, "Got count %d\n", count);
3474 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3475 ok(hr == S_OK, "Got 0x%08x\n", hr);
3476 todo_wine
3477 ok(psi != psi2, "ShellItems are of the same instance.\n");
3478 if(SUCCEEDED(hr))
3480 LPITEMIDLIST pidl1, pidl2;
3481 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3482 ok(hr == S_OK, "Got 0x%08x\n", hr);
3483 ok(pidl1 != NULL, "pidl1 was null.\n");
3484 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3485 ok(hr == S_OK, "Got 0x%08x\n", hr);
3486 ok(pidl2 != NULL, "pidl2 was null.\n");
3487 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3488 pILFree(pidl1);
3489 pILFree(pidl2);
3490 IShellItem_Release(psi2);
3492 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3493 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3494 IShellItemArray_Release(psia);
3496 IShellItem_Release(psi);
3499 else
3500 skip("No SHCreateShellItemArrayFromShellItem.\n");
3502 if(pSHCreateShellItemArrayFromDataObject)
3504 IShellView *psv;
3506 if(0)
3508 /* Crashes under Windows 7 */
3509 pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3511 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3512 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3514 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3515 ok(hr == S_OK, "got 0x%08x\n", hr);
3516 if(SUCCEEDED(hr))
3518 IEnumIDList *peidl;
3519 IDataObject *pdo;
3520 SHCONTF enum_flags;
3522 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3523 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3524 ok(hr == S_OK, "got 0x%08x\n", hr);
3525 if(SUCCEEDED(hr))
3527 LPITEMIDLIST apidl[5];
3528 UINT count, i;
3530 for(count = 0; count < 5; count++)
3531 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3532 break;
3533 ok(count == 5, "Got %d\n", count);
3535 if(count)
3537 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3538 &IID_IDataObject, NULL, (void**)&pdo);
3539 ok(hr == S_OK, "Got 0x%08x\n", hr);
3540 if(SUCCEEDED(hr))
3542 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3543 (void**)&psia);
3544 ok(hr == S_OK, "Got 0x%08x\n", hr);
3545 if(SUCCEEDED(hr))
3547 UINT count_sia, i;
3548 hr = IShellItemArray_GetCount(psia, &count_sia);
3549 ok(hr == S_OK, "Got 0x%08x\n", hr);
3550 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3551 for(i = 0; i < count_sia; i++)
3553 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3554 IShellItem *psi;
3555 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3556 ok(hr == S_OK, "Got 0x%08x\n", hr);
3557 if(SUCCEEDED(hr))
3559 LPITEMIDLIST pidl;
3560 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3561 ok(hr == S_OK, "Got 0x%08x\n", hr);
3562 ok(pidl != NULL, "pidl as NULL.\n");
3563 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3564 pILFree(pidl);
3565 IShellItem_Release(psi);
3567 pILFree(pidl_abs);
3570 IShellItemArray_Release(psia);
3573 IDataObject_Release(pdo);
3575 for(i = 0; i < count; i++)
3576 pILFree(apidl[i]);
3578 else
3579 skip("No files found - skipping test.\n");
3581 IEnumIDList_Release(peidl);
3583 IShellView_Release(psv);
3586 else
3587 skip("No SHCreateShellItemArrayFromDataObject.\n");
3589 if(pSHCreateShellItemArrayFromIDLists)
3591 WCHAR test1W[] = {'t','e','s','t','1','.','t','x','t',0};
3592 WCHAR test1pathW[MAX_PATH];
3593 LPITEMIDLIST pidltest1;
3594 LPCITEMIDLIST pidl_array[2];
3596 if(0)
3598 /* Crashes */
3599 hr = pSHCreateShellItemArrayFromIDLists(0, NULL, NULL);
3602 psia = (void*)0xdeadbeef;
3603 hr = pSHCreateShellItemArrayFromIDLists(0, NULL, &psia);
3604 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3605 ok(psia == NULL, "Got %p\n", psia);
3607 psia = (void*)0xdeadbeef;
3608 hr = pSHCreateShellItemArrayFromIDLists(0, pidl_array, &psia);
3609 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3610 ok(psia == NULL, "Got %p\n", psia);
3612 psia = (void*)0xdeadbeef;
3613 pidl_array[0] = NULL;
3614 hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3615 todo_wine ok(hr == E_OUTOFMEMORY, "Got 0x%08x\n", hr);
3616 ok(psia == NULL, "Got %p\n", psia);
3618 psia = (void*)0xdeadbeef;
3619 pidl_array[0] = pidl_testdir;
3620 pidl_array[1] = NULL;
3621 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3622 todo_wine ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Vista */, "Got 0x%08x\n", hr);
3623 todo_wine ok(psia != NULL || broken(psia == NULL) /* Vista */, "Got %p\n", psia);
3624 if(SUCCEEDED(hr))
3626 IShellItem *psi;
3627 UINT count = 0;
3629 hr = IShellItemArray_GetCount(psia, &count);
3630 ok(hr == S_OK, "Got 0x%08x\n", hr);
3631 ok(count == 2, "Got %d\n", count);
3633 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3634 ok(hr == S_OK, "Got 0x%08x\n", hr);
3635 if(SUCCEEDED(hr))
3637 LPWSTR path;
3638 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3639 ok(hr == S_OK, "Got 0x%08x\n", hr);
3640 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3641 if(SUCCEEDED(hr))
3642 CoTaskMemFree(path);
3644 IShellItem_Release(psi);
3647 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3648 ok(hr == S_OK, "Got 0x%08x\n", hr);
3649 if(SUCCEEDED(hr))
3651 LPWSTR path;
3652 WCHAR desktoppath[MAX_PATH];
3653 BOOL result;
3655 result = pSHGetSpecialFolderPathW(NULL, desktoppath, CSIDL_DESKTOPDIRECTORY, FALSE);
3656 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
3658 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3659 ok(hr == S_OK, "Got 0x%08x\n", hr);
3660 ok(!lstrcmpW(path, desktoppath), "Got %s\n", wine_dbgstr_w(path));
3661 if(SUCCEEDED(hr))
3662 CoTaskMemFree(path);
3664 IShellItem_Release(psi);
3668 IShellItemArray_Release(psia);
3672 /* Single pidl */
3673 psia = (void*)0xdeadbeef;
3674 pidl_array[0] = pidl_testdir;
3675 hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3676 ok(hr == S_OK, "Got 0x%08x\n", hr);
3677 if(SUCCEEDED(hr))
3679 IShellItem *psi;
3680 UINT count = 0;
3682 hr = IShellItemArray_GetCount(psia, &count);
3683 ok(hr == S_OK, "Got 0x%08x\n", hr);
3684 ok(count == 1, "Got %d\n", count);
3686 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3687 ok(hr == S_OK, "Got 0x%08x\n", hr);
3688 if(SUCCEEDED(hr))
3690 LPWSTR path;
3691 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3692 ok(hr == S_OK, "Got 0x%08x\n", hr);
3693 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3694 if(SUCCEEDED(hr))
3695 CoTaskMemFree(path);
3697 IShellItem_Release(psi);
3700 IShellItemArray_Release(psia);
3704 lstrcpyW(test1pathW, cTestDirW);
3705 myPathAddBackslashW(test1pathW);
3706 lstrcatW(test1pathW, test1W);
3708 SHGetDesktopFolder(&pdesktopsf);
3710 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, test1pathW, NULL, &pidltest1, NULL);
3711 ok(hr == S_OK, "Got 0x%08x\n", hr);
3712 if(SUCCEEDED(hr))
3714 psia = (void*)0xdeadbeef;
3715 pidl_array[0] = pidl_testdir;
3716 pidl_array[1] = pidltest1;
3717 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3718 ok(hr == S_OK, "Got 0x%08x\n", hr);
3719 if(SUCCEEDED(hr))
3721 IShellItem *psi;
3722 UINT count = 0;
3724 hr = IShellItemArray_GetCount(psia, &count);
3725 ok(hr == S_OK, "Got 0x%08x\n", hr);
3726 ok(count == 2, "Got %d\n", count);
3728 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3729 ok(hr == S_OK, "Got 0x%08x\n", hr);
3730 if(SUCCEEDED(hr))
3732 LPWSTR path;
3733 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3734 ok(hr == S_OK, "Got 0x%08x\n", hr);
3735 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3736 if(SUCCEEDED(hr))
3737 CoTaskMemFree(path);
3739 IShellItem_Release(psi);
3742 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3743 ok(hr == S_OK, "Got 0x%08x\n", hr);
3744 if(SUCCEEDED(hr))
3746 LPWSTR path;
3747 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3748 ok(hr == S_OK, "Got 0x%08x\n", hr);
3749 ok(!lstrcmpW(path, test1pathW), "Got %s\n", wine_dbgstr_w(path));
3750 if(SUCCEEDED(hr))
3751 CoTaskMemFree(path);
3753 IShellItem_Release(psi);
3757 IShellItemArray_Release(psia);
3760 pILFree(pidltest1);
3763 IShellFolder_Release(pdesktopsf);
3765 else
3766 skip("No SHCreateShellItemArrayFromIDLists.\n");
3768 IShellFolder_Release(psf);
3769 pILFree(pidl_testdir);
3770 Cleanup();
3773 static void test_ShellItemArrayEnumItems(void)
3775 IShellFolder *pdesktopsf, *psf;
3776 IEnumIDList *peidl;
3777 WCHAR cTestDirW[MAX_PATH];
3778 HRESULT hr;
3779 LPITEMIDLIST pidl_testdir;
3780 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3782 if(!pSHCreateShellItemArray)
3784 win_skip("No SHCreateShellItemArray, skipping test...\n");
3785 return;
3788 CreateFilesFolders();
3790 SHGetDesktopFolder(&pdesktopsf);
3792 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3793 myPathAddBackslashW(cTestDirW);
3794 lstrcatW(cTestDirW, testdirW);
3796 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3797 ok(hr == S_OK, "got 0x%08x\n", hr);
3798 if(SUCCEEDED(hr))
3800 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3801 (void**)&psf);
3802 ok(hr == S_OK, "Got 0x%08x\n", hr);
3803 if(SUCCEEDED(hr))
3804 pILFree(pidl_testdir);
3806 IShellFolder_Release(pdesktopsf);
3808 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3809 ok(hr == S_OK, "Got %08x\n", hr);
3810 if(SUCCEEDED(hr))
3812 IShellItemArray *psia;
3813 LPITEMIDLIST apidl[5];
3814 UINT done, numitems, i;
3816 for(done = 0; done < 5; done++)
3817 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3818 break;
3819 ok(done == 5, "Got %d pidls\n", done);
3820 IEnumIDList_Release(peidl);
3822 /* Create a ShellItemArray */
3823 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3824 ok(hr == S_OK, "Got 0x%08x\n", hr);
3825 if(SUCCEEDED(hr))
3827 IEnumShellItems *iesi;
3828 IShellItem *my_array[10];
3829 ULONG fetched;
3831 IShellItemArray_GetCount(psia, &numitems);
3832 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3834 iesi = NULL;
3835 hr = IShellItemArray_EnumItems(psia, &iesi);
3836 ok(hr == S_OK, "Got 0x%08x\n", hr);
3837 ok(iesi != NULL, "Got NULL\n");
3838 if(SUCCEEDED(hr))
3840 IEnumShellItems *iesi2;
3842 /* This should fail according to the documentation and Win7+ */
3843 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3844 hr = IEnumShellItems_Next(iesi, 2, my_array, NULL);
3845 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
3846 for(i = 0; i < 2; i++)
3848 ok(my_array[i] == (void*)0xdeadbeef ||
3849 broken(my_array[i] != (void*)0xdeadbeef && my_array[i] != NULL), /* Vista */
3850 "Got %p (%d)\n", my_array[i], i);
3852 if(my_array[i] != (void*)0xdeadbeef)
3853 IShellItem_Release(my_array[i]);
3855 ok(my_array[2] == (void*)0xdeadbeef, "Got %p\n", my_array[2]);
3857 IEnumShellItems_Reset(iesi);
3858 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3859 hr = IEnumShellItems_Next(iesi, 1, my_array, NULL);
3860 ok(hr == S_OK, "Got 0x%08x\n", hr);
3861 ok(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef, "Got %p\n", my_array[0]);
3862 if(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef)
3863 IShellItem_Release(my_array[0]);
3864 ok(my_array[1] == (void*)0xdeadbeef, "Got %p\n", my_array[1]);
3866 IEnumShellItems_Reset(iesi);
3867 fetched = 0;
3868 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3869 hr = IEnumShellItems_Next(iesi, numitems, my_array, &fetched);
3870 ok(hr == S_OK, "Got 0x%08x\n", hr);
3871 ok(fetched == numitems, "Got %d\n", fetched);
3872 for(i = 0;i < numitems; i++)
3874 ok(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef,
3875 "Got %p at %d\n", my_array[i], i);
3877 if(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef)
3878 IShellItem_Release(my_array[i]);
3880 ok(my_array[i] == (void*)0xdeadbeef, "Got %p\n", my_array[i]);
3882 /* Compare all the items */
3883 IEnumShellItems_Reset(iesi);
3884 for(i = 0; i < numitems; i++)
3886 IShellItem *psi;
3887 int order;
3889 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3890 ok(hr == S_OK, "Got 0x%08x\n", hr);
3891 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
3892 ok(hr == S_OK, "Got 0x%08x\n", hr);
3893 ok(fetched == 1, "Got %d\n", fetched);
3895 hr = IShellItem_Compare(psi, my_array[0], 0, &order);
3896 ok(hr == S_OK, "Got 0x%08x\n", hr);
3897 ok(order == 0, "Got %d\n", order);
3899 IShellItem_Release(psi);
3900 IShellItem_Release(my_array[0]);
3903 my_array[0] = (void*)0xdeadbeef;
3904 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
3905 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3906 ok(fetched == 0, "Got %d\n", fetched);
3907 ok(my_array[0] == (void*)0xdeadbeef, "Got %p\n", my_array[0]);
3909 /* Cloning not implemented anywhere */
3910 iesi2 = (void*)0xdeadbeef;
3911 hr = IEnumShellItems_Clone(iesi, &iesi2);
3912 ok(hr == E_NOTIMPL, "Got 0x%08x\n", hr);
3913 ok(iesi2 == NULL || broken(iesi2 == (void*)0xdeadbeef) /* Vista */, "Got %p\n", iesi2);
3915 IEnumShellItems_Release(iesi);
3918 IShellItemArray_Release(psia);
3921 for(i = 0; i < done; i++)
3922 pILFree(apidl[i]);
3927 static void test_ShellItemBindToHandler(void)
3929 IShellItem *psi;
3930 LPITEMIDLIST pidl_desktop;
3931 HRESULT hr;
3933 if(!pSHCreateShellItem)
3935 skip("SHCreateShellItem missing.\n");
3936 return;
3939 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3940 ok(hr == S_OK, "Got 0x%08x\n", hr);
3941 if(SUCCEEDED(hr))
3943 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3944 ok(hr == S_OK, "Got 0x%08x\n", hr);
3946 if(SUCCEEDED(hr))
3948 IPersistFolder2 *ppf2;
3949 IUnknown *punk;
3951 if(0)
3953 /* Crashes under Windows 7 */
3954 IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3955 IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3957 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3958 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3960 /* BHID_SFObject */
3961 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3962 ok(hr == S_OK, "Got 0x%08x\n", hr);
3963 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3964 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3965 ok(hr == S_OK, "Got 0x%08x\n", hr);
3966 if(SUCCEEDED(hr))
3968 LPITEMIDLIST pidl_tmp;
3969 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3970 ok(hr == S_OK, "Got 0x%08x\n", hr);
3971 if(SUCCEEDED(hr))
3973 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3974 pILFree(pidl_tmp);
3976 IPersistFolder2_Release(ppf2);
3979 /* BHID_SFUIObject */
3980 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3981 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3982 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3983 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3984 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3985 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3987 /* BHID_DataObject */
3988 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3989 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3990 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3992 todo_wine
3994 /* BHID_SFViewObject */
3995 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3996 ok(hr == S_OK, "Got 0x%08x\n", hr);
3997 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3998 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3999 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
4000 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4002 /* BHID_Storage */
4003 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
4004 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
4005 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4006 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
4007 ok(hr == S_OK, "Got 0x%08x\n", hr);
4008 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4010 /* BHID_Stream */
4011 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
4012 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
4013 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4014 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
4015 ok(hr == S_OK, "Got 0x%08x\n", hr);
4016 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4018 /* BHID_StorageEnum */
4019 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
4020 ok(hr == S_OK, "Got 0x%08x\n", hr);
4021 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4023 /* BHID_Transfer
4024 ITransferSource and ITransferDestination are accessible starting from Vista, IUnknown is
4025 supported starting from Win8. */
4026 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferSource, (void**)&punk);
4027 ok(hr == S_OK || broken(FAILED(hr)) /* pre-Vista */, "Got 0x%08x\n", hr);
4028 if(SUCCEEDED(hr))
4030 IUnknown_Release(punk);
4032 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferDestination, (void**)&punk);
4033 ok(hr == S_OK, "Got 0x%08x\n", hr);
4034 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4036 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
4037 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Win8 */, "Got 0x%08x\n", hr);
4038 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4041 /* BHID_EnumItems */
4042 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
4043 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4044 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4046 /* BHID_Filter */
4047 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
4048 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4049 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4051 /* BHID_LinkTargetItem */
4052 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
4053 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
4054 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4055 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
4056 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
4057 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4059 /* BHID_PropertyStore */
4060 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
4061 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4062 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4063 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
4064 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4065 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4067 /* BHID_ThumbnailHandler */
4068 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
4069 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4070 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4072 /* BHID_AssociationArray */
4073 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
4074 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4075 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4077 /* BHID_EnumAssocHandlers */
4078 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
4079 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4080 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4083 IShellItem_Release(psi);
4085 else
4086 skip("Failed to create ShellItem.\n");
4088 pILFree(pidl_desktop);
4091 static void test_ShellItemGetAttributes(void)
4093 IShellItem *psi, *psi_folder1, *psi_file1;
4094 IShellFolder *pdesktopsf;
4095 LPITEMIDLIST pidl_desktop, pidl;
4096 SFGAOF sfgao;
4097 HRESULT hr;
4098 WCHAR curdirW[MAX_PATH];
4099 WCHAR buf[MAX_PATH];
4100 static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4101 static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4103 if(!pSHCreateShellItem)
4105 skip("SHCreateShellItem missing.\n");
4106 return;
4109 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
4110 ok(hr == S_OK, "Got 0x%08x\n", hr);
4111 if(SUCCEEDED(hr))
4113 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
4114 ok(hr == S_OK, "Got 0x%08x\n", hr);
4115 pILFree(pidl_desktop);
4117 if(FAILED(hr))
4119 skip("Skipping tests.\n");
4120 return;
4123 if(0)
4125 /* Crashes on native (Win 7) */
4126 IShellItem_GetAttributes(psi, 0, NULL);
4129 /* Test GetAttributes on the desktop folder. */
4130 sfgao = 0xdeadbeef;
4131 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
4132 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
4133 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
4135 IShellItem_Release(psi);
4137 CreateFilesFolders();
4139 SHGetDesktopFolder(&pdesktopsf);
4141 GetCurrentDirectoryW(MAX_PATH, curdirW);
4142 myPathAddBackslashW(curdirW);
4144 lstrcpyW(buf, curdirW);
4145 lstrcatW(buf, testdir1W);
4146 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4147 ok(hr == S_OK, "got 0x%08x\n", hr);
4148 hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_folder1);
4149 ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4150 pILFree(pidl);
4152 lstrcpyW(buf, curdirW);
4153 lstrcatW(buf, testfile1W);
4154 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4155 ok(hr == S_OK, "got 0x%08x\n", hr);
4156 hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_file1);
4157 ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4158 pILFree(pidl);
4160 IShellFolder_Release(pdesktopsf);
4162 sfgao = 0xdeadbeef;
4163 hr = IShellItem_GetAttributes(psi_folder1, 0, &sfgao);
4164 ok(hr == S_OK, "Got 0x%08x\n", hr);
4165 ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4167 sfgao = 0xdeadbeef;
4168 hr = IShellItem_GetAttributes(psi_folder1, SFGAO_FOLDER, &sfgao);
4169 ok(hr == S_OK, "Got 0x%08x\n", hr);
4170 ok(sfgao == SFGAO_FOLDER, "Got 0x%08x\n", sfgao);
4172 sfgao = 0xdeadbeef;
4173 hr = IShellItem_GetAttributes(psi_file1, SFGAO_FOLDER, &sfgao);
4174 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
4175 ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4177 IShellItem_Release(psi_folder1);
4178 IShellItem_Release(psi_file1);
4180 Cleanup();
4183 static void test_ShellItemArrayGetAttributes(void)
4185 IShellItemArray *psia_files, *psia_folders1, *psia_folders2, *psia_all;
4186 IShellFolder *pdesktopsf;
4187 LPCITEMIDLIST pidl_array[5];
4188 SFGAOF attr;
4189 HRESULT hr;
4190 WCHAR curdirW[MAX_PATH];
4191 WCHAR buf[MAX_PATH];
4192 UINT i;
4193 static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4194 static const WCHAR testdir2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','2',0};
4195 static const WCHAR testdir3W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','3',0};
4196 static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4197 static const WCHAR testfile2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','2','.','t','x','t',0};
4198 static const WCHAR *testfilesW[5] = { testdir1W, testdir2W, testdir3W, testfile1W, testfile2W };
4200 if(!pSHCreateShellItemArrayFromShellItem)
4202 win_skip("No SHCreateShellItemArrayFromShellItem, skipping test...\n");
4203 return;
4206 CreateFilesFolders();
4207 CreateDirectoryA(".\\testdir\\testdir3", NULL);
4209 SHGetDesktopFolder(&pdesktopsf);
4211 GetCurrentDirectoryW(MAX_PATH, curdirW);
4212 myPathAddBackslashW(curdirW);
4214 for(i = 0; i < 5; i++)
4216 lstrcpyW(buf, curdirW);
4217 lstrcatW(buf, testfilesW[i]);
4218 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, (LPITEMIDLIST*)&pidl_array[i], NULL);
4219 ok(hr == S_OK, "got 0x%08x\n", hr);
4221 IShellFolder_Release(pdesktopsf);
4223 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia_folders1);
4224 ok(hr == S_OK, "got 0x%08x\n", hr);
4225 hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[1], &psia_folders2);
4226 ok(hr == S_OK, "got 0x%08x\n", hr);
4227 hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[3], &psia_files);
4228 ok(hr == S_OK, "got 0x%08x\n", hr);
4229 hr = pSHCreateShellItemArrayFromIDLists(4, &pidl_array[1], &psia_all); /* All except the first */
4230 ok(hr == S_OK, "got 0x%08x\n", hr);
4232 for(i = 0; i < 5; i++)
4233 pILFree((LPITEMIDLIST)pidl_array[i]);
4235 /* [testfolder/, testfolder/testfolder2] seems to break in Vista */
4236 attr = 0xdeadbeef;
4237 hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4238 ok(hr == S_OK || broken(hr == E_UNEXPECTED) /* Vista */, "Got 0x%08x\n", hr);
4239 ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4240 attr = 0xdeadbeef;
4241 hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4242 ok(hr == S_OK || broken(hr == E_UNEXPECTED) /* Vista */, "Got 0x%08x\n", hr);
4243 ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4245 /* [testfolder/testfolder2, testfolder/testfolder3] works */
4246 attr = 0xdeadbeef;
4247 hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4248 ok(hr == S_OK, "Got 0x%08x\n", hr);
4249 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4250 attr = 0xdeadbeef;
4251 hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4252 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4253 ok(attr == 0, "Got 0x%08x\n", attr);
4254 attr = 0xdeadbeef;
4255 hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4256 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4257 ok(attr == 0, "Got 0x%08x\n", attr);
4258 attr = 0xdeadbeef;
4259 hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4260 ok(hr == S_OK, "Got 0x%08x\n", hr);
4261 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4262 attr = 0xdeadbeef;
4263 hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4264 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4265 ok(attr == 0, "Got 0x%08x\n", attr);
4266 attr = 0xdeadbeef;
4267 hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4268 ok(hr == S_OK, "Got 0x%08x\n", hr);
4269 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4271 IShellItemArray_Release(psia_folders1);
4272 IShellItemArray_Release(psia_folders2);
4273 IShellItemArray_Release(psia_files);
4274 IShellItemArray_Release(psia_all);
4276 RemoveDirectoryA(".\\testdir\\testdir3");
4277 Cleanup();
4280 static void test_SHParseDisplayName(void)
4282 LPITEMIDLIST pidl1, pidl2;
4283 IShellFolder *desktop;
4284 WCHAR dirW[MAX_PATH];
4285 WCHAR nameW[10];
4286 HRESULT hr;
4287 BOOL ret, is_wow64;
4289 if (!pSHParseDisplayName)
4291 win_skip("SHParseDisplayName isn't available\n");
4292 return;
4295 if (0)
4297 /* crashes on native */
4298 pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
4299 nameW[0] = 0;
4300 pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
4303 pidl1 = (LPITEMIDLIST)0xdeadbeef;
4304 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
4305 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
4306 hr == E_INVALIDARG, "failed %08x\n", hr);
4307 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
4309 /* dummy name */
4310 nameW[0] = 0;
4311 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
4312 ok(hr == S_OK, "failed %08x\n", hr);
4313 hr = SHGetDesktopFolder(&desktop);
4314 ok(hr == S_OK, "failed %08x\n", hr);
4315 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
4316 ok(hr == S_OK, "failed %08x\n", hr);
4317 ret = pILIsEqual(pidl1, pidl2);
4318 ok(ret == TRUE, "expected equal idls\n");
4319 pILFree(pidl1);
4320 pILFree(pidl2);
4322 /* with path */
4323 GetWindowsDirectoryW( dirW, MAX_PATH );
4325 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4326 ok(hr == S_OK, "failed %08x\n", hr);
4327 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
4328 ok(hr == S_OK, "failed %08x\n", hr);
4330 ret = pILIsEqual(pidl1, pidl2);
4331 ok(ret == TRUE, "expected equal idls\n");
4332 pILFree(pidl1);
4333 pILFree(pidl2);
4335 /* system32 is not redirected to syswow64 on WOW64 */
4336 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
4337 if (is_wow64 && pGetSystemWow64DirectoryW)
4339 UINT len;
4340 *dirW = 0;
4341 len = GetSystemDirectoryW(dirW, MAX_PATH);
4342 ok(len > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
4343 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4344 ok(hr == S_OK, "failed %08x\n", hr);
4345 *dirW = 0;
4346 len = pGetSystemWow64DirectoryW(dirW, MAX_PATH);
4347 ok(len > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
4348 hr = pSHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
4349 ok(hr == S_OK, "failed %08x\n", hr);
4350 ret = pILIsEqual(pidl1, pidl2);
4351 ok(ret == FALSE, "expected different idls\n");
4352 pILFree(pidl1);
4353 pILFree(pidl2);
4356 IShellFolder_Release(desktop);
4359 static void test_desktop_IPersist(void)
4361 IShellFolder *desktop;
4362 IPersist *persist;
4363 IPersistFolder2 *ppf2;
4364 CLSID clsid;
4365 HRESULT hr;
4367 hr = SHGetDesktopFolder(&desktop);
4368 ok(hr == S_OK, "failed %08x\n", hr);
4370 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
4371 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
4373 if (hr == S_OK)
4375 if (0)
4377 /* crashes on native */
4378 IPersist_GetClassID(persist, NULL);
4380 memset(&clsid, 0, sizeof(clsid));
4381 hr = IPersist_GetClassID(persist, &clsid);
4382 ok(hr == S_OK, "failed %08x\n", hr);
4383 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
4384 IPersist_Release(persist);
4387 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
4388 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
4389 if(SUCCEEDED(hr))
4391 IPersistFolder *ppf;
4392 LPITEMIDLIST pidl;
4393 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
4394 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
4395 if(SUCCEEDED(hr))
4396 IPersistFolder_Release(ppf);
4398 todo_wine {
4399 hr = IPersistFolder2_Initialize(ppf2, NULL);
4400 ok(hr == S_OK, "got %08x\n", hr);
4403 pidl = NULL;
4404 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
4405 ok(hr == S_OK, "got %08x\n", hr);
4406 ok(pidl != NULL, "pidl was NULL.\n");
4407 if(SUCCEEDED(hr)) pILFree(pidl);
4409 IPersistFolder2_Release(ppf2);
4412 IShellFolder_Release(desktop);
4415 static void test_GetUIObject(void)
4417 IShellFolder *psf_desktop;
4418 IContextMenu *pcm;
4419 LPITEMIDLIST pidl;
4420 HRESULT hr;
4421 WCHAR path[MAX_PATH];
4422 const WCHAR filename[] =
4423 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4425 if(!pSHBindToParent)
4427 win_skip("SHBindToParent missing.\n");
4428 return;
4431 GetCurrentDirectoryW(MAX_PATH, path);
4432 if (!path[0])
4434 skip("GetCurrentDirectoryW returned an empty string.\n");
4435 return;
4437 lstrcatW(path, filename);
4438 SHGetDesktopFolder(&psf_desktop);
4440 CreateFilesFolders();
4442 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
4443 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
4444 if(SUCCEEDED(hr))
4446 IShellFolder *psf;
4447 LPCITEMIDLIST pidl_child;
4448 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
4449 ok(hr == S_OK, "Got 0x%08x\n", hr);
4450 if(SUCCEEDED(hr))
4452 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, &pidl_child, &IID_IContextMenu, NULL,
4453 (void**)&pcm);
4454 ok(hr == S_OK, "Got 0x%08x\n", hr);
4455 if(SUCCEEDED(hr))
4457 const int baseItem = 0x40;
4458 HMENU hmenu = CreatePopupMenu();
4459 INT max_id, max_id_check;
4460 UINT count, i;
4461 const int id_upper_limit = 32767;
4462 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, baseItem, id_upper_limit, CMF_NORMAL);
4463 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
4464 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
4465 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
4466 count = GetMenuItemCount(hmenu);
4467 ok(count, "Got %d\n", count);
4469 max_id_check = 0;
4470 for(i = 0; i < count; i++)
4472 MENUITEMINFOA mii;
4473 INT res;
4474 char buf[255], buf2[255];
4475 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
4476 mii.cbSize = sizeof(MENUITEMINFOA);
4477 mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
4478 mii.dwTypeData = buf2;
4479 mii.cch = sizeof(buf2);
4481 SetLastError(0);
4482 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
4483 ok(res, "Failed (last error: %d).\n", GetLastError());
4485 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
4486 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
4487 if(!(mii.fType & MFT_SEPARATOR))
4489 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
4490 hr = IContextMenu_GetCommandString(pcm, mii.wID - baseItem, GCS_VERBA, 0, buf, sizeof(buf));
4491 ok(SUCCEEDED(hr) || hr == E_NOTIMPL, "for id 0x%x got 0x%08x (menustr: %s)\n", mii.wID - baseItem, hr, mii.dwTypeData);
4492 if (SUCCEEDED(hr))
4493 trace("for id 0x%x got string %s (menu string: %s)\n", mii.wID - baseItem, buf, mii.dwTypeData);
4494 else if (hr == E_NOTIMPL)
4495 trace("for id 0x%x got E_NOTIMPL (menu string: %s)\n", mii.wID - baseItem, mii.dwTypeData);
4498 max_id_check -= baseItem;
4499 ok((max_id_check == max_id) ||
4500 (max_id_check == max_id-1) || /* Win 7 */
4501 (max_id_check == max_id-2), /* Win 8 */
4502 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
4504 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
4506 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
4508 CMINVOKECOMMANDINFO cmi;
4509 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
4510 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
4512 /* Attempt to execute a nonexistent command */
4513 cmi.lpVerb = MAKEINTRESOURCEA(9999);
4514 hr = IContextMenu_InvokeCommand(pcm, &cmi);
4515 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
4517 cmi.lpVerb = "foobar_wine_test";
4518 hr = IContextMenu_InvokeCommand(pcm, &cmi);
4519 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
4520 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
4521 "Got 0x%08x\n", hr);
4523 #undef is_win2k
4525 DestroyMenu(hmenu);
4526 IContextMenu_Release(pcm);
4528 IShellFolder_Release(psf);
4530 if(pILFree) pILFree(pidl);
4533 IShellFolder_Release(psf_desktop);
4534 Cleanup();
4537 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
4538 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
4540 LPCITEMIDLIST child;
4541 IShellFolder *parent;
4542 STRRET filename;
4543 HRESULT hr;
4545 if(!pSHBindToParent){
4546 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
4547 if(path)
4548 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
4549 else
4550 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4551 return;
4554 if(path){
4555 if(!pidl){
4556 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
4557 return;
4560 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
4561 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
4562 if(FAILED(hr))
4563 return;
4565 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
4566 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
4567 if(FAILED(hr)){
4568 IShellFolder_Release(parent);
4569 return;
4572 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
4573 "Got unexpected string type: %d\n", filename.uType);
4574 if(filename.uType == STRRET_WSTR){
4575 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
4576 "didn't get expected path (%s), instead: %s\n",
4577 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
4578 SHFree(U(filename).pOleStr);
4579 }else if(filename.uType == STRRET_CSTR){
4580 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
4581 "didn't get expected path (%s), instead: %s\n",
4582 wine_dbgstr_w(path), U(filename).cStr);
4585 IShellFolder_Release(parent);
4586 }else
4587 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4590 static void test_SHSimpleIDListFromPath(void)
4592 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4593 const CHAR adirA[] = "C:\\sidlfpdir";
4594 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4596 LPITEMIDLIST pidl = NULL;
4598 if(!pSHSimpleIDListFromPathAW){
4599 win_skip("SHSimpleIDListFromPathAW not available\n");
4600 return;
4603 br = CreateDirectoryA(adirA, NULL);
4604 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4606 if(is_unicode)
4607 pidl = pSHSimpleIDListFromPathAW(adirW);
4608 else
4609 pidl = pSHSimpleIDListFromPathAW(adirA);
4610 verify_pidl(pidl, adirW);
4611 pILFree(pidl);
4613 br = RemoveDirectoryA(adirA);
4614 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4616 if(is_unicode)
4617 pidl = pSHSimpleIDListFromPathAW(adirW);
4618 else
4619 pidl = pSHSimpleIDListFromPathAW(adirA);
4620 verify_pidl(pidl, adirW);
4621 pILFree(pidl);
4624 /* IFileSystemBindData impl */
4625 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4626 REFIID riid, void **ppv)
4628 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4629 IsEqualIID(riid, &IID_IUnknown)){
4630 *ppv = fsbd;
4631 return S_OK;
4633 return E_NOINTERFACE;
4636 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4638 return 2;
4641 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4643 return 1;
4646 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4647 const WIN32_FIND_DATAW *pfd)
4649 ok(0, "SetFindData called\n");
4650 return E_NOTIMPL;
4653 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4654 WIN32_FIND_DATAW *pfd)
4656 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4657 return S_OK;
4660 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4661 WIN32_FIND_DATAW *pfd)
4663 memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4664 return S_OK;
4667 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4668 WIN32_FIND_DATAW *pfd)
4670 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4671 *pfd->cFileName = 'a';
4672 *pfd->cAlternateFileName = 'a';
4673 return S_OK;
4676 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4677 WIN32_FIND_DATAW *pfd)
4679 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4680 HANDLE handle = FindFirstFileW(adirW, pfd);
4681 FindClose(handle);
4682 return S_OK;
4685 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4686 WIN32_FIND_DATAW *pfd)
4688 return E_FAIL;
4691 static IFileSystemBindDataVtbl fsbdVtbl = {
4692 fsbd_QueryInterface,
4693 fsbd_AddRef,
4694 fsbd_Release,
4695 fsbd_SetFindData,
4696 NULL
4699 static IFileSystemBindData fsbd = { &fsbdVtbl };
4701 static void test_ParseDisplayNamePBC(void)
4703 WCHAR wFileSystemBindData[] =
4704 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4705 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4706 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4707 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4708 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4710 IShellFolder *psf;
4711 IBindCtx *pbc;
4712 HRESULT hres;
4713 ITEMIDLIST *pidl;
4715 /* Check if we support WCHAR functions */
4716 SetLastError(0xdeadbeef);
4717 lstrcmpiW(adirW, adirW);
4718 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4719 win_skip("Most W-calls are not implemented\n");
4720 return;
4723 hres = SHGetDesktopFolder(&psf);
4724 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4725 if(FAILED(hres)){
4726 win_skip("Failed to get IShellFolder, can't run tests\n");
4727 return;
4730 /* fails on unknown dir with no IBindCtx */
4731 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4732 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4733 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4734 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4735 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4736 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4737 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4738 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4739 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4741 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4742 hres = CreateBindCtx(0, &pbc);
4743 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4745 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4746 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4747 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4748 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4749 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4750 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4751 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4752 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4753 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4755 /* unknown dir with IBindCtx with IFileSystemBindData */
4756 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4757 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4759 /* return E_FAIL from GetFindData */
4760 pidl = (ITEMIDLIST*)0xdeadbeef;
4761 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4762 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4763 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4764 "ParseDisplayName failed: 0x%08x\n", hres);
4765 if(SUCCEEDED(hres)){
4766 verify_pidl(pidl, adirW);
4767 ILFree(pidl);
4770 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4771 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4772 "ParseDisplayName failed: 0x%08x\n", hres);
4773 if(SUCCEEDED(hres)){
4774 verify_pidl(pidl, afileW);
4775 ILFree(pidl);
4778 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4779 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4780 "ParseDisplayName failed: 0x%08x\n", hres);
4781 if(SUCCEEDED(hres)){
4782 verify_pidl(pidl, afile2W);
4783 ILFree(pidl);
4786 /* set FIND_DATA struct to NULLs */
4787 pidl = (ITEMIDLIST*)0xdeadbeef;
4788 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4789 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4790 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4791 "ParseDisplayName failed: 0x%08x\n", hres);
4792 if(SUCCEEDED(hres)){
4793 verify_pidl(pidl, adirW);
4794 ILFree(pidl);
4797 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4798 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4799 "ParseDisplayName failed: 0x%08x\n", hres);
4800 if(SUCCEEDED(hres)){
4801 verify_pidl(pidl, afileW);
4802 ILFree(pidl);
4805 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4806 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4807 "ParseDisplayName failed: 0x%08x\n", hres);
4808 if(SUCCEEDED(hres)){
4809 verify_pidl(pidl, afile2W);
4810 ILFree(pidl);
4813 /* set FIND_DATA struct to junk */
4814 pidl = (ITEMIDLIST*)0xdeadbeef;
4815 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4816 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4817 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4818 "ParseDisplayName failed: 0x%08x\n", hres);
4819 if(SUCCEEDED(hres)){
4820 verify_pidl(pidl, adirW);
4821 ILFree(pidl);
4824 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4825 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4826 "ParseDisplayName failed: 0x%08x\n", hres);
4827 if(SUCCEEDED(hres)){
4828 verify_pidl(pidl, afileW);
4829 ILFree(pidl);
4832 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4833 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4834 "ParseDisplayName failed: 0x%08x\n", hres);
4835 if(SUCCEEDED(hres)){
4836 verify_pidl(pidl, afile2W);
4837 ILFree(pidl);
4840 /* set FIND_DATA struct to invalid data */
4841 pidl = (ITEMIDLIST*)0xdeadbeef;
4842 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4843 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4844 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4845 "ParseDisplayName failed: 0x%08x\n", hres);
4846 if(SUCCEEDED(hres)){
4847 verify_pidl(pidl, adirW);
4848 ILFree(pidl);
4851 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4852 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4853 "ParseDisplayName failed: 0x%08x\n", hres);
4854 if(SUCCEEDED(hres)){
4855 verify_pidl(pidl, afileW);
4856 ILFree(pidl);
4859 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4860 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4861 "ParseDisplayName failed: 0x%08x\n", hres);
4862 if(SUCCEEDED(hres)){
4863 verify_pidl(pidl, afile2W);
4864 ILFree(pidl);
4867 /* set FIND_DATA struct to valid data */
4868 pidl = (ITEMIDLIST*)0xdeadbeef;
4869 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4870 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4871 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4872 "ParseDisplayName failed: 0x%08x\n", hres);
4873 if(SUCCEEDED(hres)){
4874 verify_pidl(pidl, adirW);
4875 ILFree(pidl);
4878 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4879 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4880 "ParseDisplayName failed: 0x%08x\n", hres);
4881 if(SUCCEEDED(hres)){
4882 verify_pidl(pidl, afileW);
4883 ILFree(pidl);
4886 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4887 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4888 "ParseDisplayName failed: 0x%08x\n", hres);
4889 if(SUCCEEDED(hres)){
4890 verify_pidl(pidl, afile2W);
4891 ILFree(pidl);
4894 IBindCtx_Release(pbc);
4895 IShellFolder_Release(psf);
4898 static const CHAR testwindow_class[] = "testwindow";
4899 #define WM_USER_NOTIFY (WM_APP+1)
4901 struct ChNotifyTest {
4902 const char id[256];
4903 const UINT notify_count;
4904 UINT missing_events;
4905 UINT signal;
4906 const char path_1[256];
4907 const char path_2[256];
4908 } chnotify_tests[] = {
4909 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4910 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4911 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4914 struct ChNotifyTest *exp_data;
4915 BOOL test_new_delivery_flag;
4917 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4919 LONG signal = (LONG)lparam;
4921 switch(msg){
4922 case WM_USER_NOTIFY:
4923 if(exp_data->missing_events > 0) {
4924 WCHAR *path1, *path2;
4925 LPITEMIDLIST *pidls = (LPITEMIDLIST*)wparam;
4926 HANDLE hLock = NULL;
4928 if(test_new_delivery_flag) {
4929 hLock = SHChangeNotification_Lock((HANDLE)wparam, lparam, &pidls, &signal);
4930 ok(hLock != NULL, "SHChangeNotification_Lock returned NULL\n");
4933 ok(exp_data->signal == signal,
4934 "%s: expected notification type %x, got: %x\n",
4935 exp_data->id, exp_data->signal, signal);
4937 trace("verifying pidls for: %s\n", exp_data->id);
4938 path1 = make_wstr(exp_data->path_1);
4939 path2 = make_wstr(exp_data->path_2);
4940 verify_pidl(pidls[0], path1);
4941 verify_pidl(pidls[1], path2);
4942 HeapFree(GetProcessHeap(), 0, path1);
4943 HeapFree(GetProcessHeap(), 0, path2);
4945 exp_data->missing_events--;
4947 if(test_new_delivery_flag)
4948 SHChangeNotification_Unlock(hLock);
4949 }else
4950 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4951 return 0;
4953 return DefWindowProcA(hwnd, msg, wparam, lparam);
4956 static void register_testwindow_class(void)
4958 WNDCLASSEXA cls;
4959 ATOM ret;
4961 ZeroMemory(&cls, sizeof(cls));
4962 cls.cbSize = sizeof(cls);
4963 cls.style = 0;
4964 cls.lpfnWndProc = testwindow_wndproc;
4965 cls.hInstance = GetModuleHandleA(NULL);
4966 cls.lpszClassName = testwindow_class;
4968 SetLastError(0);
4969 ret = RegisterClassExA(&cls);
4970 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4973 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4974 * have to poll repeatedly for the message to appear */
4975 static void do_events(void)
4977 int c = 0;
4978 while (exp_data->missing_events && (c++ < 10)){
4979 MSG msg;
4980 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4981 TranslateMessage(&msg);
4982 DispatchMessageA(&msg);
4984 if(exp_data->missing_events)
4985 Sleep(500);
4987 trace("%s: took %d tries\n", exp_data->id, c);
4990 static void test_SHChangeNotify(BOOL test_new_delivery)
4992 HWND wnd;
4993 ULONG notifyID, i;
4994 HRESULT hr;
4995 BOOL br, has_unicode;
4996 SHChangeNotifyEntry entries[1];
4997 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4998 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
5000 trace("SHChangeNotify tests (%x)\n", test_new_delivery);
5002 CreateDirectoryW(NULL, NULL);
5003 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
5005 test_new_delivery_flag = test_new_delivery;
5006 if(!test_new_delivery)
5007 register_testwindow_class();
5009 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
5010 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
5011 NULL, NULL, GetModuleHandleA(NULL), 0);
5012 ok(wnd != NULL, "Failed to make a window\n");
5014 br = CreateDirectoryA(root_dirA, NULL);
5015 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
5017 entries[0].pidl = NULL;
5018 if(has_unicode)
5019 hr = pSHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
5020 else
5021 hr = pSHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
5022 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
5023 entries[0].fRecursive = TRUE;
5025 notifyID = SHChangeNotifyRegister(wnd, !test_new_delivery ? SHCNRF_ShellLevel : SHCNRF_ShellLevel|SHCNRF_NewDelivery,
5026 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
5027 ok(notifyID != 0, "Failed to register a window for change notifications\n");
5029 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
5030 exp_data = chnotify_tests + i;
5032 exp_data->missing_events = exp_data->notify_count;
5033 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
5034 exp_data->path_1[0] ? exp_data->path_1 : NULL,
5035 exp_data->path_2[0] ? exp_data->path_2 : NULL);
5036 do_events();
5037 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
5039 if(has_unicode){
5040 WCHAR *path1, *path2;
5042 path1 = make_wstr(exp_data->path_1);
5043 path2 = make_wstr(exp_data->path_2);
5045 exp_data->missing_events = exp_data->notify_count;
5046 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
5047 do_events();
5048 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
5050 HeapFree(GetProcessHeap(), 0, path1);
5051 HeapFree(GetProcessHeap(), 0, path2);
5055 SHChangeNotifyDeregister(notifyID);
5056 DestroyWindow(wnd);
5058 ILFree((LPITEMIDLIST)entries[0].pidl);
5059 br = RemoveDirectoryA(root_dirA);
5060 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
5063 static void test_SHCreateDefaultContextMenu(void)
5065 HKEY keys[16];
5066 WCHAR path[MAX_PATH];
5067 IShellFolder *desktop,*folder;
5068 IPersistFolder2 *persist;
5069 IContextMenu *cmenu;
5070 LONG status;
5071 LPITEMIDLIST pidlFolder, pidl_child, pidl;
5072 DEFCONTEXTMENU cminfo;
5073 HRESULT hr;
5074 UINT i;
5075 const WCHAR filename[] =
5076 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
5077 if(!pSHCreateDefaultContextMenu)
5079 win_skip("SHCreateDefaultContextMenu missing.\n");
5080 return;
5083 if(!pSHBindToParent)
5085 skip("SHBindToParent missing.\n");
5086 return;
5089 GetCurrentDirectoryW(MAX_PATH, path);
5090 if (!path[0])
5092 skip("GetCurrentDirectoryW returned an empty string.\n");
5093 return;
5095 lstrcatW(path, filename);
5096 SHGetDesktopFolder(&desktop);
5098 CreateFilesFolders();
5100 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &pidl, 0);
5101 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
5102 if(SUCCEEDED(hr))
5105 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&folder, (LPCITEMIDLIST*)&pidl_child);
5106 ok(hr == S_OK, "Got 0x%08x\n", hr);
5108 IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
5109 IPersistFolder2_GetCurFolder(persist,&pidlFolder);
5110 IPersistFolder2_Release(persist);
5111 if(SUCCEEDED(hr))
5114 cminfo.hwnd=NULL;
5115 cminfo.pcmcb=NULL;
5116 cminfo.psf=folder;
5117 cminfo.pidlFolder=NULL;
5118 cminfo.apidl=(LPCITEMIDLIST*)&pidl_child;
5119 cminfo.cidl=1;
5120 cminfo.aKeys=NULL;
5121 cminfo.cKeys=0;
5122 cminfo.punkAssociationInfo=NULL;
5123 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5124 ok(hr==S_OK,"Got 0x%08x\n", hr);
5125 IContextMenu_Release(cmenu);
5126 cminfo.pidlFolder=pidlFolder;
5127 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5128 ok(hr==S_OK,"Got 0x%08x\n", hr);
5129 IContextMenu_Release(cmenu);
5130 status = RegOpenKeyExA(HKEY_CLASSES_ROOT,"*",0,KEY_READ,keys);
5131 if(status==ERROR_SUCCESS){
5132 for(i=1;i<16;i++)
5133 keys[i]=keys[0];
5134 cminfo.aKeys=keys;
5135 cminfo.cKeys=16;
5136 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5137 RegCloseKey(keys[0]);
5138 ok(hr==S_OK,"Got 0x%08x\n", hr);
5139 IContextMenu_Release(cmenu);
5142 ILFree(pidlFolder);
5143 IShellFolder_Release(folder);
5145 IShellFolder_Release(desktop);
5146 ILFree(pidl);
5147 Cleanup();
5150 static void test_SHCreateShellFolderView(void)
5152 HRESULT hr;
5153 IShellView *psv;
5154 SFV_CREATE sfvc;
5155 IShellFolder *desktop;
5156 ULONG refCount;
5158 if (!pSHCreateShellFolderView)
5160 win_skip("SHCreateShellFolderView missing.\n");
5161 return;
5164 hr = SHGetDesktopFolder(&desktop);
5165 ok(hr == S_OK, "got (0x%08x)\n", hr);
5167 if (0)
5169 /* crash on win7 */
5170 pSHCreateShellFolderView(NULL, NULL);
5173 psv = (void *)0xdeadbeef;
5174 hr = pSHCreateShellFolderView(NULL, &psv);
5175 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
5176 ok(psv == NULL, "psv = %p\n", psv);
5178 memset(&sfvc, 0, sizeof(sfvc));
5179 psv = (void *)0xdeadbeef;
5180 hr = pSHCreateShellFolderView(&sfvc, &psv);
5181 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
5182 ok(psv == NULL, "psv = %p\n", psv);
5184 memset(&sfvc, 0, sizeof(sfvc));
5185 sfvc.cbSize = sizeof(sfvc) - 1;
5186 psv = (void *)0xdeadbeef;
5187 hr = pSHCreateShellFolderView(&sfvc, &psv);
5188 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
5189 ok(psv == NULL, "psv = %p\n", psv);
5191 memset(&sfvc, 0, sizeof(sfvc));
5192 sfvc.cbSize = sizeof(sfvc) + 1;
5193 psv = (void *)0xdeadbeef;
5194 hr = pSHCreateShellFolderView(&sfvc, &psv);
5195 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
5196 ok(psv == NULL, "psv = %p\n", psv);
5198 memset(&sfvc, 0, sizeof(sfvc));
5199 sfvc.cbSize = sizeof(sfvc);
5200 sfvc.pshf = desktop;
5201 psv = NULL;
5202 hr = pSHCreateShellFolderView(&sfvc, &psv);
5203 ok(hr == S_OK, "Got 0x%08x\n", hr);
5204 ok(psv != NULL, "psv = %p\n", psv);
5205 if (psv)
5207 refCount = IShellView_Release(psv);
5208 ok(refCount == 0, "refCount = %u\n", refCount);
5211 IShellFolder_Release(desktop);
5214 static void test_SHCreateShellFolderViewEx(void)
5216 HRESULT hr;
5217 IShellView *psv;
5218 CSFV csfv;
5219 IShellFolder *desktop;
5220 ULONG refCount;
5222 if (!pSHCreateShellFolderViewEx)
5224 win_skip("SHCreateShellFolderViewEx missing.\n");
5225 return;
5228 hr = SHGetDesktopFolder(&desktop);
5229 ok(hr == S_OK, "got (0x%08x)\n", hr);
5231 if (0)
5233 /* crash on win7 */
5234 pSHCreateShellFolderViewEx(NULL, NULL);
5235 pSHCreateShellFolderViewEx(NULL, &psv);
5236 pSHCreateShellFolderViewEx(&csfv, NULL);
5239 memset(&csfv, 0, sizeof(csfv));
5240 csfv.pshf = desktop;
5241 psv = NULL;
5242 hr = pSHCreateShellFolderViewEx(&csfv, &psv);
5243 ok(hr == S_OK, "Got 0x%08x\n", hr);
5244 ok(psv != NULL, "psv = %p\n", psv);
5245 if (psv)
5247 refCount = IShellView_Release(psv);
5248 ok(refCount == 0, "refCount = %u\n", refCount);
5251 memset(&csfv, 0, sizeof(csfv));
5252 csfv.cbSize = sizeof(csfv);
5253 csfv.pshf = desktop;
5254 psv = NULL;
5255 hr = pSHCreateShellFolderViewEx(&csfv, &psv);
5256 ok(hr == S_OK, "Got 0x%08x\n", hr);
5257 ok(psv != NULL, "psv = %p\n", psv);
5258 if (psv)
5260 refCount = IShellView_Release(psv);
5261 ok(refCount == 0, "refCount = %u\n", refCount);
5264 IShellFolder_Release(desktop);
5267 static void test_DataObject(void)
5269 IShellFolder *desktop;
5270 IDataObject *data_obj;
5271 HRESULT hres;
5272 IEnumIDList *peidl;
5273 LPITEMIDLIST apidl;
5274 FORMATETC fmt;
5275 DWORD cf_shellidlist;
5276 STGMEDIUM medium;
5278 SHGetDesktopFolder(&desktop);
5280 hres = IShellFolder_EnumObjects(desktop, NULL,
5281 SHCONTF_NONFOLDERS|SHCONTF_FOLDERS|SHCONTF_INCLUDEHIDDEN, &peidl);
5282 ok(hres == S_OK, "got %x\n", hres);
5284 if(IEnumIDList_Next(peidl, 1, &apidl, NULL) != S_OK) {
5285 skip("no files on desktop - skipping GetDataObject tests\n");
5286 IEnumIDList_Release(peidl);
5287 IShellFolder_Release(desktop);
5288 return;
5290 IEnumIDList_Release(peidl);
5292 hres = IShellFolder_GetUIObjectOf(desktop, NULL, 1, (LPCITEMIDLIST*)&apidl,
5293 &IID_IDataObject, NULL, (void**)&data_obj);
5294 ok(hres == S_OK, "got %x\n", hres);
5295 pILFree(apidl);
5296 IShellFolder_Release(desktop);
5298 cf_shellidlist = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
5299 fmt.cfFormat = cf_shellidlist;
5300 fmt.ptd = NULL;
5301 fmt.dwAspect = DVASPECT_CONTENT;
5302 fmt.lindex = -1;
5303 fmt.tymed = TYMED_HGLOBAL;
5304 hres = IDataObject_QueryGetData(data_obj, &fmt);
5305 ok(hres == S_OK, "got %x\n", hres);
5307 fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5308 hres = IDataObject_QueryGetData(data_obj, &fmt);
5309 ok(hres == S_OK, "got %x\n", hres);
5311 fmt.tymed = TYMED_ISTREAM;
5312 hres = IDataObject_QueryGetData(data_obj, &fmt);
5313 todo_wine ok(hres == S_FALSE, "got %x\n", hres);
5315 fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5316 hres = IDataObject_GetData(data_obj, &fmt, &medium);
5317 ok(hres == S_OK, "got %x\n", hres);
5318 ok(medium.tymed == TYMED_HGLOBAL, "medium.tymed = %x\n", medium.tymed);
5319 ReleaseStgMedium(&medium);
5321 IDataObject_Release(data_obj);
5324 START_TEST(shlfolder)
5326 init_function_pointers();
5327 /* if OleInitialize doesn't get called, ParseDisplayName returns
5328 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
5329 OleInitialize(NULL);
5331 test_ParseDisplayName();
5332 test_SHParseDisplayName();
5333 test_BindToObject();
5334 test_EnumObjects_and_CompareIDs();
5335 test_GetDisplayName();
5336 test_GetAttributesOf();
5337 test_SHGetPathFromIDList();
5338 test_CallForAttributes();
5339 test_FolderShortcut();
5340 test_ITEMIDLIST_format();
5341 test_SHGetFolderPathA();
5342 test_SHGetFolderPathAndSubDirA();
5343 test_LocalizedNames();
5344 test_SHCreateShellItem();
5345 test_SHCreateShellItemArray();
5346 test_ShellItemArrayEnumItems();
5347 test_desktop_IPersist();
5348 test_GetUIObject();
5349 test_SHSimpleIDListFromPath();
5350 test_ParseDisplayNamePBC();
5351 test_SHGetNameFromIDList();
5352 test_SHGetItemFromDataObject();
5353 test_SHGetIDListFromObject();
5354 test_SHGetItemFromObject();
5355 test_ShellItemCompare();
5356 test_SHChangeNotify(FALSE);
5357 test_SHChangeNotify(TRUE);
5358 test_ShellItemBindToHandler();
5359 test_ShellItemGetAttributes();
5360 test_ShellItemArrayGetAttributes();
5361 test_SHCreateDefaultContextMenu();
5362 test_SHCreateShellFolderView();
5363 test_SHCreateShellFolderViewEx();
5364 test_DataObject();
5366 OleUninitialize();