shell32: Implement SHCreateItemInKnownFolder.
[wine.git] / dlls / shell32 / tests / shlfolder.c
blob739e6854a98ecb4f3db9a26accc326693f9b149e
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 *pSHCreateItemFromRelativeName)(IShellItem*,PCWSTR,IBindCtx*,REFIID,void**);
62 static HRESULT (WINAPI *pSHCreateItemInKnownFolder)(REFKNOWNFOLDERID,DWORD,PCWSTR,REFIID,void **);
63 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
64 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
65 static HRESULT (WINAPI *pSHCreateShellItemArrayFromIDLists)(UINT, PCIDLIST_ABSOLUTE*, IShellItemArray**);
66 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
67 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
68 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
69 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
70 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
71 static HRESULT (WINAPI *pSHGetKnownFolderPath)(REFKNOWNFOLDERID,DWORD,HANDLE,PWSTR*);
72 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
73 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
74 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
75 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
76 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
77 static UINT (WINAPI *pGetSystemWow64DirectoryW)(LPWSTR, UINT);
78 static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
79 static HRESULT (WINAPI *pSHILCreateFromPath)(LPCWSTR, LPITEMIDLIST *,DWORD*);
80 static BOOL (WINAPI *pSHGetPathFromIDListEx)(PCIDLIST_ABSOLUTE,WCHAR*,DWORD,GPFIDL_FLAGS);
82 static WCHAR *make_wstr(const char *str)
84 WCHAR *ret;
85 int len;
87 if (!str || !str[0])
88 return NULL;
90 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
91 if(!len || len < 0)
92 return NULL;
94 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
95 if(!ret)
96 return NULL;
98 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
99 return ret;
102 static int strcmp_wa(LPCWSTR strw, const char *stra)
104 CHAR buf[512];
105 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
106 return lstrcmpA(stra, buf);
109 static void init_function_pointers(void)
111 HMODULE hmod;
112 HRESULT hr;
113 void *ptr;
115 hmod = GetModuleHandleA("shell32.dll");
117 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
118 MAKEFUNC(SHBindToParent);
119 MAKEFUNC(SHCreateItemFromIDList);
120 MAKEFUNC(SHCreateItemFromParsingName);
121 MAKEFUNC(SHCreateItemFromRelativeName);
122 MAKEFUNC(SHCreateItemInKnownFolder);
123 MAKEFUNC(SHCreateShellItem);
124 MAKEFUNC(SHCreateShellItemArray);
125 MAKEFUNC(SHCreateShellItemArrayFromIDLists);
126 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
127 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
128 MAKEFUNC(SHGetFolderPathA);
129 MAKEFUNC(SHGetFolderPathAndSubDirA);
130 MAKEFUNC(SHGetPathFromIDListW);
131 MAKEFUNC(SHGetSpecialFolderPathA);
132 MAKEFUNC(SHGetSpecialFolderPathW);
133 MAKEFUNC(SHGetSpecialFolderLocation);
134 MAKEFUNC(SHParseDisplayName);
135 MAKEFUNC(SHGetKnownFolderPath);
136 MAKEFUNC(SHGetNameFromIDList);
137 MAKEFUNC(SHGetItemFromDataObject);
138 MAKEFUNC(SHGetIDListFromObject);
139 MAKEFUNC(SHGetItemFromObject);
140 MAKEFUNC(SHCreateDefaultContextMenu);
141 MAKEFUNC(SHGetPathFromIDListEx);
142 #undef MAKEFUNC
144 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
145 MAKEFUNC_ORD(ILFindLastID, 16);
146 MAKEFUNC_ORD(ILIsEqual, 21);
147 MAKEFUNC_ORD(ILCombine, 25);
148 MAKEFUNC_ORD(SHILCreateFromPath, 28);
149 MAKEFUNC_ORD(ILFree, 155);
150 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
151 #undef MAKEFUNC_ORD
153 /* test named exports */
154 ptr = GetProcAddress(hmod, "ILFree");
155 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
156 if (ptr)
158 #define TESTNAMED(f) \
159 ptr = (void*)GetProcAddress(hmod, #f); \
160 ok(ptr != 0, "expected named export for " #f "\n");
162 TESTNAMED(ILAppendID);
163 TESTNAMED(ILClone);
164 TESTNAMED(ILCloneFirst);
165 TESTNAMED(ILCombine);
166 TESTNAMED(ILCreateFromPath);
167 TESTNAMED(ILCreateFromPathA);
168 TESTNAMED(ILCreateFromPathW);
169 TESTNAMED(ILFindChild);
170 TESTNAMED(ILFindLastID);
171 TESTNAMED(ILGetNext);
172 TESTNAMED(ILGetSize);
173 TESTNAMED(ILIsEqual);
174 TESTNAMED(ILIsParent);
175 TESTNAMED(ILRemoveLastID);
176 TESTNAMED(ILSaveToStream);
177 #undef TESTNAMED
180 hmod = GetModuleHandleA("shlwapi.dll");
181 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
183 hmod = GetModuleHandleA("kernel32.dll");
184 pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
185 pGetSystemWow64DirectoryW = (void*)GetProcAddress(hmod, "GetSystemWow64DirectoryW");
187 hr = SHGetMalloc(&ppM);
188 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
191 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
192 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
194 size_t iLen;
196 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
197 return NULL;
199 if (iLen)
201 lpszPath += iLen;
202 if (lpszPath[-1] != '\\')
204 *lpszPath++ = '\\';
205 *lpszPath = '\0';
208 return lpszPath;
211 static void test_ParseDisplayName(void)
213 HRESULT hr;
214 IShellFolder *IDesktopFolder;
215 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
216 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
217 static const char *cInetTestA = "http:\\yyy";
218 static const char *cInetTest2A = "xx:yyy";
219 DWORD res;
220 WCHAR cTestDirW [MAX_PATH] = {0};
221 ITEMIDLIST *newPIDL;
222 BOOL bRes;
224 hr = SHGetDesktopFolder(&IDesktopFolder);
225 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
226 if(hr != S_OK) return;
228 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
229 if (pSHCreateShellItem)
231 if (0)
233 /* null name and pidl, also crashes on Windows 8 */
234 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL,
235 NULL, NULL, NULL, 0);
236 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
239 /* null name */
240 newPIDL = (ITEMIDLIST*)0xdeadbeef;
241 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
242 NULL, NULL, NULL, NULL, &newPIDL, 0);
243 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
244 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
246 else
247 win_skip("Tests would crash on W2K and below\n");
249 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
250 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
251 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
252 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
253 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
254 if (hr == S_OK)
256 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
257 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
258 IMalloc_Free(ppM, newPIDL);
261 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
262 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
263 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
264 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
265 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
266 if (hr == S_OK)
268 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
269 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
270 IMalloc_Free(ppM, newPIDL);
273 res = GetFileAttributesA(cNonExistDir1A);
274 if(res != INVALID_FILE_ATTRIBUTES)
276 skip("Test directory unexpectedly exists\n");
277 goto finished;
280 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
281 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
282 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
283 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
284 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
286 res = GetFileAttributesA(cNonExistDir2A);
287 if(res != INVALID_FILE_ATTRIBUTES)
289 skip("Test directory unexpectedly exists\n");
290 goto finished;
293 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
294 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
295 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
296 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
297 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
299 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
300 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
301 * out it doesn't. The magic seems to happen in the file dialogs, then. */
302 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
304 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
305 goto finished;
308 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
309 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
310 if (!bRes) goto finished;
312 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
313 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
314 if (hr != S_OK) goto finished;
316 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
317 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
318 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
319 pILFindLastID(newPIDL)->mkid.abID[0]);
320 IMalloc_Free(ppM, newPIDL);
322 finished:
323 IShellFolder_Release(IDesktopFolder);
326 /* creates a file with the specified name for tests */
327 static void CreateTestFile(const CHAR *name)
329 HANDLE file;
330 DWORD written;
332 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
333 if (file != INVALID_HANDLE_VALUE)
335 WriteFile(file, name, strlen(name), &written, NULL);
336 WriteFile(file, "\n", strlen("\n"), &written, NULL);
337 CloseHandle(file);
342 /* initializes the tests */
343 static void CreateFilesFolders(void)
345 CreateDirectoryA(".\\testdir", NULL);
346 CreateDirectoryA(".\\testdir\\test.txt", NULL);
347 CreateTestFile (".\\testdir\\test1.txt ");
348 CreateTestFile (".\\testdir\\test2.txt ");
349 CreateTestFile (".\\testdir\\test3.txt ");
350 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
351 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
354 /* cleans after tests */
355 static void Cleanup(void)
357 DeleteFileA(".\\testdir\\test1.txt");
358 DeleteFileA(".\\testdir\\test2.txt");
359 DeleteFileA(".\\testdir\\test3.txt");
360 RemoveDirectoryA(".\\testdir\\test.txt");
361 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
362 RemoveDirectoryA(".\\testdir\\testdir2");
363 RemoveDirectoryA(".\\testdir");
367 /* perform test */
368 static void test_EnumObjects(IShellFolder *iFolder)
370 IEnumIDList *iEnumList;
371 LPITEMIDLIST newPIDL, idlArr[10];
372 ULONG NumPIDLs;
373 int i=0, j;
374 HRESULT hr;
376 static const WORD iResults [5][5] =
378 { 0,-1,-1,-1,-1},
379 { 1, 0,-1,-1,-1},
380 { 1, 1, 0,-1,-1},
381 { 1, 1, 1, 0,-1},
382 { 1, 1, 1, 1, 0}
385 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
386 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
387 static const ULONG attrs[5] =
389 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
390 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
391 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
392 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
393 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
395 static const ULONG full_attrs[5] =
397 SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
398 SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
399 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
400 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
401 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
404 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
405 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
407 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
408 * the filesystem shellfolders return S_OK even if less than 'celt' items are
409 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
410 * only ever returns a single entry per call. */
411 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
412 i += NumPIDLs;
413 ok (i == 5, "i: %d\n", i);
415 hr = IEnumIDList_Release(iEnumList);
416 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
418 /* Sort them first in case of wrong order from system */
419 for (i=0;i<5;i++) for (j=0;j<5;j++)
420 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
422 newPIDL = idlArr[i];
423 idlArr[i] = idlArr[j];
424 idlArr[j] = newPIDL;
427 for (i=0;i<5;i++) for (j=0;j<5;j++)
429 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
430 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
434 for (i = 0; i < 5; i++)
436 SFGAOF flags;
437 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
438 /* Native returns all flags no matter what we ask for */
439 flags = SFGAO_CANCOPY;
440 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
441 flags &= SFGAO_testfor;
442 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
443 ok(flags == (attrs[i]) ||
444 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
445 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
446 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
448 flags = SFGAO_testfor;
449 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
450 flags &= SFGAO_testfor;
451 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
452 ok(flags == attrs[i] ||
453 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
454 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
456 flags = ~0u;
457 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
458 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
459 ok((flags & ~(SFGAO_HASSUBFOLDER|SFGAO_COMPRESSED)) == full_attrs[i], "%d: got %08x expected %08x\n", i, flags, full_attrs[i]);
462 for (i=0;i<5;i++)
463 IMalloc_Free(ppM, idlArr[i]);
466 static void test_BindToObject(void)
468 HRESULT hr;
469 UINT cChars;
470 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
471 SHITEMID emptyitem = { 0, { 0 } };
472 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
473 WCHAR wszSystemDir[MAX_PATH];
474 char szSystemDir[MAX_PATH];
475 char buf[MAX_PATH];
476 WCHAR path[MAX_PATH];
477 CHAR pathA[MAX_PATH];
478 HANDLE hfile;
479 WCHAR wszMyComputer[] = {
480 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
481 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
482 static const CHAR filename_html[] = "winetest.html";
483 static const CHAR filename_txt[] = "winetest.txt";
484 static const CHAR filename_foo[] = "winetest.foo";
486 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
487 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
489 hr = SHGetDesktopFolder(&psfDesktop);
490 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
491 if (hr != S_OK) return;
493 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
494 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
496 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
497 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
499 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
500 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
501 if (hr != S_OK) {
502 IShellFolder_Release(psfDesktop);
503 return;
506 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
507 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
508 IShellFolder_Release(psfDesktop);
509 IMalloc_Free(ppM, pidlMyComputer);
510 if (hr != S_OK) return;
512 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
513 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
515 if (0)
517 /* this call segfaults on 98SE */
518 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
519 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
522 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
523 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
524 if (cChars == 0 || cChars >= MAX_PATH) {
525 IShellFolder_Release(psfMyComputer);
526 return;
528 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
530 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
531 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
532 if (hr != S_OK) {
533 IShellFolder_Release(psfMyComputer);
534 return;
537 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
538 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
539 IShellFolder_Release(psfMyComputer);
540 IMalloc_Free(ppM, pidlSystemDir);
541 if (hr != S_OK) return;
543 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
544 ok (hr == E_INVALIDARG,
545 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
547 if (0)
549 /* this call segfaults on 98SE */
550 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
551 ok (hr == E_INVALIDARG,
552 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
555 IShellFolder_Release(psfSystemDir);
557 cChars = GetCurrentDirectoryA(MAX_PATH, buf);
558 if(!cChars)
560 skip("Failed to get current directory, skipping tests.\n");
561 return;
563 if(buf[cChars-1] != '\\') lstrcatA(buf, "\\");
565 SHGetDesktopFolder(&psfDesktop);
567 /* Attempt BindToObject on files. */
569 /* .html */
570 lstrcpyA(pathA, buf);
571 lstrcatA(pathA, filename_html);
572 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
573 if(hfile != INVALID_HANDLE_VALUE)
575 CloseHandle(hfile);
576 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
577 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
578 ok(hr == S_OK, "Got 0x%08x\n", hr);
579 if(SUCCEEDED(hr))
581 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
582 ok(hr == S_OK ||
583 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
584 "Got 0x%08x\n", hr);
585 if(SUCCEEDED(hr))
587 IPersist *pp;
588 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
589 ok(hr == S_OK ||
590 broken(hr == E_NOINTERFACE), /* Win9x, NT4, W2K */
591 "Got 0x%08x\n", hr);
592 if(SUCCEEDED(hr))
594 CLSID id;
595 hr = IPersist_GetClassID(pp, &id);
596 ok(hr == S_OK, "Got 0x%08x\n", hr);
597 /* CLSID_ShellFSFolder on some w2k systems */
598 ok(IsEqualIID(&id, &CLSID_ShellDocObjView) || broken(IsEqualIID(&id, &CLSID_ShellFSFolder)),
599 "Unexpected classid %s\n", wine_dbgstr_guid(&id));
600 IPersist_Release(pp);
603 IShellFolder_Release(psfChild);
605 pILFree(pidl);
607 DeleteFileA(pathA);
609 else
610 win_skip("Failed to create .html testfile.\n");
612 /* .txt */
613 lstrcpyA(pathA, buf);
614 lstrcatA(pathA, filename_txt);
615 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
616 if(hfile != INVALID_HANDLE_VALUE)
618 CloseHandle(hfile);
619 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
620 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
621 ok(hr == S_OK, "Got 0x%08x\n", hr);
622 if(SUCCEEDED(hr))
624 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
625 ok(hr == E_FAIL || /* Vista+ */
626 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
627 hr == E_INVALIDARG || /* W2K item in top dir */
628 broken(hr == S_OK), /* Win9x, NT4, W2K */
629 "Got 0x%08x\n", hr);
630 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
631 pILFree(pidl);
633 DeleteFileA(pathA);
635 else
636 win_skip("Failed to create .txt testfile.\n");
638 /* .foo */
639 lstrcpyA(pathA, buf);
640 lstrcatA(pathA, filename_foo);
641 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
642 if(hfile != INVALID_HANDLE_VALUE)
644 CloseHandle(hfile);
645 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
646 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
647 ok(hr == S_OK, "Got 0x%08x\n", hr);
648 if(SUCCEEDED(hr))
650 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
651 ok(hr == E_FAIL || /* Vista+ */
652 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
653 hr == E_INVALIDARG || /* W2K item in top dir */
654 broken(hr == S_OK), /* Win9x, NT4, W2K */
655 "Got 0x%08x\n", hr);
656 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
657 pILFree(pidl);
659 DeleteFileA(pathA);
661 else
662 win_skip("Failed to create .foo testfile.\n");
664 /* And on the desktop */
665 if(pSHGetSpecialFolderPathA)
667 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
668 lstrcatA(pathA, "\\");
669 lstrcatA(pathA, filename_html);
670 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
671 if(hfile != INVALID_HANDLE_VALUE)
673 CloseHandle(hfile);
674 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
675 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
676 ok(hr == S_OK, "Got 0x%08x\n", hr);
677 if(SUCCEEDED(hr))
679 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
680 ok(hr == S_OK ||
681 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
682 "Got 0x%08x\n", hr);
683 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
684 pILFree(pidl);
686 if(!DeleteFileA(pathA))
687 trace("Failed to delete: %d\n", GetLastError());
690 else
691 win_skip("Failed to create .html testfile.\n");
693 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
694 lstrcatA(pathA, "\\");
695 lstrcatA(pathA, filename_foo);
696 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
697 if(hfile != INVALID_HANDLE_VALUE)
699 CloseHandle(hfile);
700 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
701 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
702 ok(hr == S_OK, "Got 0x%08x\n", hr);
703 if(SUCCEEDED(hr))
705 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
706 ok(hr == E_FAIL || /* Vista+ */
707 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
708 broken(hr == S_OK), /* Win9x, NT4, W2K */
709 "Got 0x%08x\n", hr);
710 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
711 pILFree(pidl);
713 DeleteFileA(pathA);
715 else
716 win_skip("Failed to create .foo testfile.\n");
719 IShellFolder_Release(psfDesktop);
722 static void test_GetDisplayName(void)
724 BOOL result;
725 HRESULT hr;
726 HANDLE hTestFile;
727 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
728 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
729 DWORD attr;
730 STRRET strret;
731 LPSHELLFOLDER psfDesktop, psfPersonal;
732 IUnknown *psfFile;
733 SHITEMID emptyitem = { 0, { 0 } };
734 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
735 LPCITEMIDLIST pidlLast;
736 static const CHAR szFileName[] = "winetest.foo";
737 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
738 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
740 /* I'm trying to figure if there is a functional difference between calling
741 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
742 * binding to the shellfolder. One thing I thought of was that perhaps
743 * SHGetPathFromIDListW would be able to get the path to a file, which does
744 * not exist anymore, while the other method wouldn't. It turns out there's
745 * no functional difference in this respect.
748 if(!pSHGetSpecialFolderPathA) {
749 win_skip("SHGetSpecialFolderPathA is not available\n");
750 return;
753 /* First creating a directory in MyDocuments and a file in this directory. */
754 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
755 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
756 if (!result) return;
758 /* Use ANSI file functions so this works on Windows 9x */
759 lstrcatA(szTestDir, "\\winetest");
760 CreateDirectoryA(szTestDir, NULL);
761 attr=GetFileAttributesA(szTestDir);
762 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
764 ok(0, "unable to create the '%s' directory\n", szTestDir);
765 return;
768 lstrcpyA(szTestFile, szTestDir);
769 lstrcatA(szTestFile, "\\");
770 lstrcatA(szTestFile, szFileName);
771 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
772 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
773 if (hTestFile == INVALID_HANDLE_VALUE) return;
774 CloseHandle(hTestFile);
776 /* Getting an itemidlist for the file. */
777 hr = SHGetDesktopFolder(&psfDesktop);
778 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
779 if (hr != S_OK) return;
781 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
783 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
784 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
785 if (hr != S_OK) {
786 IShellFolder_Release(psfDesktop);
787 return;
790 pidlLast = pILFindLastID(pidlTestFile);
791 ok(pidlLast->mkid.cb >=76 ||
792 broken(pidlLast->mkid.cb == 28) || /* W2K */
793 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
794 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
795 if (pidlLast->mkid.cb >= 28) {
796 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
797 "Filename should be stored as ansi-string at this position!\n");
799 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
800 if (pidlLast->mkid.cb >= 76) {
801 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
802 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
803 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)) || /* Win7 */
804 (pidlLast->mkid.cb >= 102 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[72], wszFileName)), /* Win8 */
805 "Filename should be stored as wchar-string at this position!\n");
808 /* It seems as if we cannot bind to regular files on windows, but only directories.
810 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
811 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
812 hr == E_NOTIMPL || /* Vista */
813 broken(hr == S_OK), /* Win9x, W2K */
814 "hr = %08x\n", hr);
815 if (hr == S_OK) {
816 IUnknown_Release(psfFile);
819 if (!pSHBindToParent)
821 win_skip("SHBindToParent is missing\n");
822 DeleteFileA(szTestFile);
823 RemoveDirectoryA(szTestDir);
824 return;
827 /* Some tests for IShellFolder::SetNameOf */
828 if (pSHGetFolderPathAndSubDirA)
830 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
831 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
832 if (hr == S_OK) {
833 /* It's ok to use this fixed path. Call will fail anyway. */
834 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
835 LPITEMIDLIST pidlNew;
837 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
838 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
839 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
840 if (hr == S_OK)
842 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
843 "pidl returned from SetNameOf should be simple!\n");
845 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
846 * is implemented on top of SHFileOperation in WinXP. */
847 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
848 SHGDN_FORPARSING, NULL);
849 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
851 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
852 * SHGDN flags specify an absolute path. */
853 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
854 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
856 pILFree(pidlNew);
859 IShellFolder_Release(psfPersonal);
862 else
863 win_skip("Avoid needs of interaction on Win2k\n");
865 /* Deleting the file and the directory */
866 DeleteFileA(szTestFile);
867 RemoveDirectoryA(szTestDir);
869 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
870 if (pSHGetPathFromIDListW)
872 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
873 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
874 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
877 /* SHBindToParent fails, if called with a NULL PIDL. */
878 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
879 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
881 /* But it succeeds with an empty PIDL. */
882 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
883 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
884 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
885 if (hr == S_OK)
886 IShellFolder_Release(psfPersonal);
888 /* Binding to the folder and querying the display name of the file also works. */
889 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
890 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
891 if (hr != S_OK) {
892 IShellFolder_Release(psfDesktop);
893 return;
896 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
897 * pidlTestFile (In accordance with MSDN). */
898 ok (pILFindLastID(pidlTestFile) == pidlLast,
899 "SHBindToParent doesn't return the last id of the pidl param!\n");
901 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
902 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
903 if (hr != S_OK) {
904 IShellFolder_Release(psfDesktop);
905 IShellFolder_Release(psfPersonal);
906 return;
909 if (pStrRetToBufW)
911 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
912 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
913 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
916 ILFree(pidlTestFile);
917 IShellFolder_Release(psfDesktop);
918 IShellFolder_Release(psfPersonal);
921 static void test_CallForAttributes(void)
923 HKEY hKey;
924 LONG lResult;
925 HRESULT hr;
926 DWORD dwSize;
927 LPSHELLFOLDER psfDesktop;
928 LPITEMIDLIST pidlMyDocuments;
929 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
930 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
931 static const WCHAR wszCallForAttributes[] = {
932 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
933 static const WCHAR wszMyDocumentsKey[] = {
934 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
935 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
936 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
937 WCHAR wszMyDocuments[] = {
938 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
939 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
941 /* For the root of a namespace extension, the attributes are not queried by binding
942 * to the object and calling GetAttributesOf. Instead, the attributes are read from
943 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
945 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
946 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
947 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
948 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
950 hr = SHGetDesktopFolder(&psfDesktop);
951 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
952 if (hr != S_OK) return;
954 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
955 &pidlMyDocuments, NULL);
956 ok (hr == S_OK ||
957 broken(hr == E_INVALIDARG), /* Win95, NT4 */
958 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
959 if (hr != S_OK) {
960 IShellFolder_Release(psfDesktop);
961 return;
964 dwAttributes = 0xffffffff;
965 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
966 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
967 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
969 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
970 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
971 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
972 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
974 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
975 * key. So the test will return at this point, if run on wine.
977 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
978 ok (lResult == ERROR_SUCCESS ||
979 lResult == ERROR_ACCESS_DENIED,
980 "RegOpenKeyEx failed! result: %08x\n", lResult);
981 if (lResult != ERROR_SUCCESS) {
982 if (lResult == ERROR_ACCESS_DENIED)
983 skip("Not enough rights to open the registry key\n");
984 IMalloc_Free(ppM, pidlMyDocuments);
985 IShellFolder_Release(psfDesktop);
986 return;
989 /* Query MyDocuments' Attributes value, to be able to restore it later. */
990 dwSize = sizeof(DWORD);
991 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
992 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
993 if (lResult != ERROR_SUCCESS) {
994 RegCloseKey(hKey);
995 IMalloc_Free(ppM, pidlMyDocuments);
996 IShellFolder_Release(psfDesktop);
997 return;
1000 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
1001 dwSize = sizeof(DWORD);
1002 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
1003 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
1004 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
1005 if (lResult != ERROR_SUCCESS) {
1006 RegCloseKey(hKey);
1007 IMalloc_Free(ppM, pidlMyDocuments);
1008 IShellFolder_Release(psfDesktop);
1009 return;
1012 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
1013 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
1014 * SFGAO_FILESYSTEM attributes. */
1015 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
1016 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
1017 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
1018 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1019 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
1021 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
1022 * GetAttributesOf. It seems that once there is a single attribute queried, for which
1023 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
1024 * the flags in Attributes are ignored.
1026 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
1027 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
1028 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
1029 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
1030 if (hr == S_OK)
1031 ok (dwAttributes == SFGAO_FILESYSTEM,
1032 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
1033 dwAttributes);
1035 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
1036 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
1037 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1038 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
1039 RegCloseKey(hKey);
1040 IMalloc_Free(ppM, pidlMyDocuments);
1041 IShellFolder_Release(psfDesktop);
1044 static void test_GetAttributesOf(void)
1046 HRESULT hr;
1047 LPSHELLFOLDER psfDesktop, psfMyComputer;
1048 SHITEMID emptyitem = { 0, { 0 } };
1049 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1050 LPITEMIDLIST pidlMyComputer;
1051 DWORD dwFlags;
1052 static const DWORD desktopFlags[] = {
1053 /* WinXP */
1054 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
1055 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1056 /* Win2k */
1057 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
1058 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1059 /* WinMe, Win9x, WinNT*/
1060 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
1061 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1063 static const DWORD myComputerFlags[] = {
1064 /* WinXP */
1065 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
1066 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1067 /* Win2k */
1068 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
1069 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1070 /* WinMe, Win9x, WinNT */
1071 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1072 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1073 /* Win95, WinNT when queried directly */
1074 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1075 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1077 WCHAR wszMyComputer[] = {
1078 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1079 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1080 char cCurrDirA [MAX_PATH] = {0};
1081 WCHAR cCurrDirW [MAX_PATH];
1082 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
1083 IShellFolder *IDesktopFolder, *testIShellFolder;
1084 ITEMIDLIST *newPIDL;
1085 int len, i;
1086 BOOL foundFlagsMatch;
1088 hr = SHGetDesktopFolder(&psfDesktop);
1089 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1090 if (hr != S_OK) return;
1092 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
1093 dwFlags = 0xffffffff;
1094 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
1095 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
1096 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1097 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1099 if (desktopFlags[i] == dwFlags)
1100 foundFlagsMatch = TRUE;
1102 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1104 /* .. or with no itemidlist at all. */
1105 dwFlags = 0xffffffff;
1106 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
1107 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1108 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1109 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1111 if (desktopFlags[i] == dwFlags)
1112 foundFlagsMatch = TRUE;
1114 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1116 /* Testing the attributes of the MyComputer shellfolder */
1117 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1118 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1119 if (hr != S_OK) {
1120 IShellFolder_Release(psfDesktop);
1121 return;
1124 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
1125 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
1127 dwFlags = 0xffffffff;
1128 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
1129 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
1130 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1131 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1133 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
1134 foundFlagsMatch = TRUE;
1136 todo_wine
1137 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1139 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
1140 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
1141 IShellFolder_Release(psfDesktop);
1142 IMalloc_Free(ppM, pidlMyComputer);
1143 if (hr != S_OK) return;
1145 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
1146 todo_wine
1147 ok (hr == E_INVALIDARG ||
1148 broken(hr == S_OK), /* W2K and earlier */
1149 "MyComputer->GetAttributesOf(empty pidl) should fail! hr = %08x\n", hr);
1151 dwFlags = 0xffffffff;
1152 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
1153 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1154 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1155 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1157 if (myComputerFlags[i] == dwFlags)
1158 foundFlagsMatch = TRUE;
1160 todo_wine
1161 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1163 IShellFolder_Release(psfMyComputer);
1165 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1166 len = lstrlenA(cCurrDirA);
1168 if (len == 0) {
1169 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1170 return;
1172 if (len > 3 && cCurrDirA[len-1] == '\\')
1173 cCurrDirA[len-1] = 0;
1175 /* create test directory */
1176 CreateFilesFolders();
1178 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1180 hr = SHGetDesktopFolder(&IDesktopFolder);
1181 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1183 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1184 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1186 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1187 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1189 IMalloc_Free(ppM, newPIDL);
1191 /* get relative PIDL */
1192 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1193 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1195 /* test the shell attributes of the test directory using the relative PIDL */
1196 dwFlags = SFGAO_FOLDER;
1197 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1198 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1199 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1201 /* free memory */
1202 IMalloc_Free(ppM, newPIDL);
1204 /* append testdirectory name to path */
1205 if (cCurrDirA[len-1] == '\\')
1206 cCurrDirA[len-1] = 0;
1207 lstrcatA(cCurrDirA, "\\testdir");
1208 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1210 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1211 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1213 /* test the shell attributes of the test directory using the absolute PIDL */
1214 dwFlags = SFGAO_FOLDER;
1215 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1216 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1217 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1219 /* free memory */
1220 IMalloc_Free(ppM, newPIDL);
1222 IShellFolder_Release(testIShellFolder);
1224 Cleanup();
1226 IShellFolder_Release(IDesktopFolder);
1229 static void test_SHGetPathFromIDList(void)
1231 SHITEMID emptyitem = { 0, { 0 } };
1232 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1233 LPITEMIDLIST pidlMyComputer;
1234 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1235 BOOL result;
1236 HRESULT hr;
1237 LPSHELLFOLDER psfDesktop;
1238 WCHAR wszMyComputer[] = {
1239 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1240 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1241 WCHAR wszFileName[MAX_PATH];
1242 LPITEMIDLIST pidlTestFile;
1243 HANDLE hTestFile;
1244 STRRET strret;
1245 static WCHAR wszTestFile[] = {
1246 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1247 LPITEMIDLIST pidlPrograms;
1249 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1251 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1252 return;
1255 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1256 wszPath[0] = 'a';
1257 wszPath[1] = '\0';
1258 result = pSHGetPathFromIDListW(NULL, wszPath);
1259 ok(!result, "Expected failure\n");
1260 ok(!wszPath[0], "Expected empty string\n");
1262 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1263 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1264 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1265 if (!result) return;
1267 /* Check if we are on Win9x */
1268 SetLastError(0xdeadbeef);
1269 lstrcmpiW(wszDesktop, wszDesktop);
1270 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1272 win_skip("Most W-calls are not implemented\n");
1273 return;
1276 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1277 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1278 if (!result) return;
1279 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1281 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1282 hr = SHGetDesktopFolder(&psfDesktop);
1283 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1284 if (hr != S_OK) return;
1286 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1287 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1288 if (hr != S_OK) {
1289 IShellFolder_Release(psfDesktop);
1290 return;
1293 SetLastError(0xdeadbeef);
1294 wszPath[0] = 'a';
1295 wszPath[1] = '\0';
1296 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1297 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1298 ok (GetLastError()==0xdeadbeef ||
1299 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1300 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1301 ok (!wszPath[0], "Expected empty path\n");
1302 if (result) {
1303 IShellFolder_Release(psfDesktop);
1304 return;
1307 IMalloc_Free(ppM, pidlMyComputer);
1309 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1310 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1311 if (!result) {
1312 IShellFolder_Release(psfDesktop);
1313 return;
1315 myPathAddBackslashW(wszFileName);
1316 lstrcatW(wszFileName, wszTestFile);
1317 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1318 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1319 if (hTestFile == INVALID_HANDLE_VALUE) {
1320 IShellFolder_Release(psfDesktop);
1321 return;
1323 CloseHandle(hTestFile);
1325 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1326 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1327 if (hr != S_OK) {
1328 IShellFolder_Release(psfDesktop);
1329 DeleteFileW(wszFileName);
1330 IMalloc_Free(ppM, pidlTestFile);
1331 return;
1334 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1335 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1336 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1337 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1338 IShellFolder_Release(psfDesktop);
1339 DeleteFileW(wszFileName);
1340 if (hr != S_OK) {
1341 IMalloc_Free(ppM, pidlTestFile);
1342 return;
1344 if (pStrRetToBufW)
1346 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1347 ok(0 == lstrcmpW(wszFileName, wszPath),
1348 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1349 "returned incorrect path for file placed on desktop\n");
1352 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1353 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1354 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1356 if (pSHGetPathFromIDListEx)
1358 result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1359 ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1360 ok(!lstrcmpiW(wszDesktop, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1361 wine_dbgstr_w(wszPath), wine_dbgstr_w(wszDesktop));
1363 result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1364 ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1365 ok(!lstrcmpiW(wszFileName, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1366 wine_dbgstr_w(wszPath), wine_dbgstr_w(wszFileName));
1368 SetLastError(0xdeadbeef);
1369 memset(wszPath, 0x55, sizeof(wszPath));
1370 result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, 5, SFGAO_FILESYSTEM);
1371 ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1373 SetLastError(0xdeadbeef);
1374 memset(wszPath, 0x55, sizeof(wszPath));
1375 result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, 5, SFGAO_FILESYSTEM);
1376 ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1378 else
1379 win_skip("SHGetPathFromIDListEx not available\n");
1381 IMalloc_Free(ppM, pidlTestFile);
1383 /* Test if we can get the path from the start menu "program files" PIDL. */
1384 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1385 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1387 SetLastError(0xdeadbeef);
1388 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1389 IMalloc_Free(ppM, pidlPrograms);
1390 ok(result, "SHGetPathFromIDListW failed\n");
1393 static void test_EnumObjects_and_CompareIDs(void)
1395 ITEMIDLIST *newPIDL;
1396 IShellFolder *IDesktopFolder, *testIShellFolder;
1397 char cCurrDirA [MAX_PATH] = {0};
1398 static const CHAR cTestDirA[] = "\\testdir";
1399 WCHAR cTestDirW[MAX_PATH];
1400 int len;
1401 HRESULT hr;
1403 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1404 len = lstrlenA(cCurrDirA);
1406 if(len == 0) {
1407 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1408 return;
1410 if(cCurrDirA[len-1] == '\\')
1411 cCurrDirA[len-1] = 0;
1413 lstrcatA(cCurrDirA, cTestDirA);
1414 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1416 hr = SHGetDesktopFolder(&IDesktopFolder);
1417 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1419 CreateFilesFolders();
1421 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1422 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1424 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1425 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1427 test_EnumObjects(testIShellFolder);
1429 IShellFolder_Release(testIShellFolder);
1431 Cleanup();
1433 IMalloc_Free(ppM, newPIDL);
1435 IShellFolder_Release(IDesktopFolder);
1438 /* A simple implementation of an IPropertyBag, which returns fixed values for
1439 * 'Target' and 'Attributes' properties.
1441 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1442 void **ppvObject)
1444 if (!ppvObject)
1445 return E_INVALIDARG;
1447 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1448 *ppvObject = iface;
1449 } else {
1450 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1451 return E_NOINTERFACE;
1454 IPropertyBag_AddRef(iface);
1455 return S_OK;
1458 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1459 return 2;
1462 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1463 return 1;
1466 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1467 VARIANT *pVar, IErrorLog *pErrorLog)
1469 static const WCHAR wszTargetSpecialFolder[] = {
1470 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1471 static const WCHAR wszTarget[] = {
1472 'T','a','r','g','e','t',0 };
1473 static const WCHAR wszAttributes[] = {
1474 'A','t','t','r','i','b','u','t','e','s',0 };
1475 static const WCHAR wszResolveLinkFlags[] = {
1476 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1477 static const WCHAR wszTargetKnownFolder[] = {
1478 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1479 static const WCHAR wszCLSID[] = {
1480 'C','L','S','I','D',0 };
1482 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1483 ok(V_VT(pVar) == VT_I4 ||
1484 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1485 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1486 return E_INVALIDARG;
1489 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1491 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1492 return E_INVALIDARG;
1495 if (!lstrcmpW(pszPropName, wszTarget)) {
1496 WCHAR wszPath[MAX_PATH];
1497 BOOL result;
1499 ok(V_VT(pVar) == VT_BSTR ||
1500 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1501 "Wrong variant type for 'Target' property!\n");
1502 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1504 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1505 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1506 if (!result) return E_INVALIDARG;
1508 V_BSTR(pVar) = SysAllocString(wszPath);
1509 return S_OK;
1512 if (!lstrcmpW(pszPropName, wszAttributes)) {
1513 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1514 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1515 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1516 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1517 return S_OK;
1520 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1521 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1522 /* TODO */
1523 return E_INVALIDARG;
1526 if (!lstrcmpW(pszPropName, wszCLSID)) {
1527 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1528 /* TODO */
1529 return E_INVALIDARG;
1532 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1533 return E_INVALIDARG;
1536 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1537 VARIANT *pVar)
1539 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1540 return E_NOTIMPL;
1543 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1544 InitPropertyBag_IPropertyBag_QueryInterface,
1545 InitPropertyBag_IPropertyBag_AddRef,
1546 InitPropertyBag_IPropertyBag_Release,
1547 InitPropertyBag_IPropertyBag_Read,
1548 InitPropertyBag_IPropertyBag_Write
1551 static struct IPropertyBag InitPropertyBag = {
1552 &InitPropertyBag_IPropertyBagVtbl
1555 static void test_FolderShortcut(void) {
1556 IPersistPropertyBag *pPersistPropertyBag;
1557 IShellFolder *pShellFolder, *pDesktopFolder;
1558 IPersistFolder3 *pPersistFolder3;
1559 HRESULT hr;
1560 STRRET strret;
1561 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1562 BOOL result;
1563 CLSID clsid;
1564 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1565 HKEY hShellExtKey;
1566 WCHAR wszWineTestFolder[] = {
1567 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1568 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1569 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1570 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1571 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1572 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1573 'N','a','m','e','S','p','a','c','e','\\',
1574 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1575 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1577 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1578 static const GUID CLSID_UnixDosFolder =
1579 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1581 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1582 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1583 return;
1586 if (!pSHGetFolderPathAndSubDirA)
1588 win_skip("FolderShortcut test doesn't work on Win2k\n");
1589 return;
1592 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1593 * via their IPersistPropertyBag interface. And that the target folder
1594 * is taken from the IPropertyBag's 'Target' property.
1596 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1597 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1598 if (hr == REGDB_E_CLASSNOTREG) {
1599 win_skip("CLSID_FolderShortcut is not implemented\n");
1600 return;
1602 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1603 if (hr != S_OK) return;
1605 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1606 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1607 if (hr != S_OK) {
1608 IPersistPropertyBag_Release(pPersistPropertyBag);
1609 return;
1612 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1613 (LPVOID*)&pShellFolder);
1614 IPersistPropertyBag_Release(pPersistPropertyBag);
1615 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1616 if (hr != S_OK) return;
1618 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1619 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* win10 */,
1620 "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1621 if (hr != S_OK) {
1622 IShellFolder_Release(pShellFolder);
1623 return;
1626 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1627 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1628 if (!result) return;
1630 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1631 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1633 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1634 IShellFolder_Release(pShellFolder);
1635 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1636 if (hr != S_OK) return;
1638 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1639 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1640 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1642 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1643 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1644 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1646 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1647 * shell namespace. The target folder, read from the property bag above, remains untouched.
1648 * The following tests show this: The itemidlist for some imaginary shellfolder object
1649 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1650 * itemidlist, but GetDisplayNameOf still returns the path from above.
1652 hr = SHGetDesktopFolder(&pDesktopFolder);
1653 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1654 if (hr != S_OK) return;
1656 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1657 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1658 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1659 RegCloseKey(hShellExtKey);
1660 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1661 &pidlWineTestFolder, NULL);
1662 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1663 IShellFolder_Release(pDesktopFolder);
1664 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1665 if (hr != S_OK) return;
1667 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1668 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1669 if (hr != S_OK) {
1670 IPersistFolder3_Release(pPersistFolder3);
1671 pILFree(pidlWineTestFolder);
1672 return;
1675 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1676 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1677 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1678 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1679 pILFree(pidlCurrentFolder);
1680 pILFree(pidlWineTestFolder);
1682 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1683 IPersistFolder3_Release(pPersistFolder3);
1684 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1685 if (hr != S_OK) return;
1687 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1688 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1689 if (hr != S_OK) {
1690 IShellFolder_Release(pShellFolder);
1691 return;
1694 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1695 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1697 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1698 * but ShellFSFolders. */
1699 myPathAddBackslashW(wszDesktopPath);
1700 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1701 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1702 IShellFolder_Release(pShellFolder);
1703 return;
1706 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1707 &pidlSubFolder, NULL);
1708 RemoveDirectoryW(wszDesktopPath);
1709 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1710 if (hr != S_OK) {
1711 IShellFolder_Release(pShellFolder);
1712 return;
1715 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1716 (LPVOID*)&pPersistFolder3);
1717 IShellFolder_Release(pShellFolder);
1718 pILFree(pidlSubFolder);
1719 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1720 if (hr != S_OK)
1721 return;
1723 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1724 * a little bit and also allow CLSID_UnixDosFolder. */
1725 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1726 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1727 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1728 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1730 IPersistFolder3_Release(pPersistFolder3);
1733 #include "pshpack1.h"
1734 struct FileStructA {
1735 BYTE type;
1736 BYTE dummy;
1737 DWORD dwFileSize;
1738 WORD uFileDate; /* In our current implementation this is */
1739 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1740 WORD uFileAttribs;
1741 CHAR szName[1];
1744 struct FileStructW {
1745 WORD cbLen; /* Length of this element. */
1746 BYTE abFooBar1[6]; /* Beyond any recognition. */
1747 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1748 WORD uTime; /* (this is currently speculation) */
1749 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1750 WORD uTime2; /* (this is currently speculation) */
1751 BYTE abFooBar2[4]; /* Beyond any recognition. */
1752 WCHAR wszName[1]; /* The long filename in unicode. */
1753 /* Just for documentation: Right after the unicode string: */
1754 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1755 * SHITEMID->cb == uOffset + cbLen */
1757 #include "poppack.h"
1759 static void test_ITEMIDLIST_format(void) {
1760 WCHAR wszPersonal[MAX_PATH];
1761 LPSHELLFOLDER psfDesktop, psfPersonal;
1762 LPITEMIDLIST pidlPersonal, pidlFile;
1763 HANDLE hFile;
1764 HRESULT hr;
1765 BOOL bResult;
1766 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1767 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1768 int i;
1770 if (!pSHGetSpecialFolderPathW) return;
1772 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1773 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1774 if (!bResult) return;
1776 SetLastError(0xdeadbeef);
1777 bResult = SetCurrentDirectoryW(wszPersonal);
1778 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1779 win_skip("Most W-calls are not implemented\n");
1780 return;
1782 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1783 if (!bResult) return;
1785 hr = SHGetDesktopFolder(&psfDesktop);
1786 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1787 if (hr != S_OK) return;
1789 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1790 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1791 if (hr != S_OK) {
1792 IShellFolder_Release(psfDesktop);
1793 return;
1796 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1797 (LPVOID*)&psfPersonal);
1798 IShellFolder_Release(psfDesktop);
1799 pILFree(pidlPersonal);
1800 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1801 if (hr != S_OK) return;
1803 for (i=0; i<3; i++) {
1804 CHAR szFile[MAX_PATH];
1805 struct FileStructA *pFileStructA;
1806 WORD cbOffset;
1808 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1810 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1811 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1812 if (hFile == INVALID_HANDLE_VALUE) {
1813 IShellFolder_Release(psfPersonal);
1814 return;
1816 CloseHandle(hFile);
1818 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1819 DeleteFileW(wszFile[i]);
1820 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1821 if (hr != S_OK) {
1822 IShellFolder_Release(psfPersonal);
1823 return;
1826 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1827 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1828 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1829 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1831 if (i < 2) /* First two file names are already in valid 8.3 format */
1832 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1833 else
1834 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1835 * can't implement this correctly, since unix filesystems don't support
1836 * this nasty short/long filename stuff. So we'll probably stay with our
1837 * current habit of storing the long filename here, which seems to work
1838 * just fine. */
1839 todo_wine
1840 ok(pidlFile->mkid.abID[18] == '~' ||
1841 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1842 "Should be derived 8.3 name!\n");
1844 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1845 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1846 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1847 "Alignment byte, where there shouldn't be!\n");
1849 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1850 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1851 "There should be an alignment byte, but isn't!\n");
1853 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1854 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1855 ok ((cbOffset >= sizeof(struct FileStructA) &&
1856 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1857 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1858 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1859 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1861 if (cbOffset >= sizeof(struct FileStructA) &&
1862 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1864 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1865 WCHAR *name = pFileStructW->wszName;
1867 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1868 "FileStructW's offset and length should add up to the PIDL's length!\n");
1870 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1871 /* Since we just created the file, time of creation,
1872 * time of last access and time of last write access just be the same.
1873 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1874 * after the first run. I do remember something with NTFS keeping the creation time
1875 * if a file is deleted and then created again within a couple of seconds or so.
1876 * Might be the reason. */
1877 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1878 pFileStructA->uFileTime == pFileStructW->uTime,
1879 "Last write time should match creation time!\n");
1881 /* On FAT filesystems the last access time is midnight
1882 local time, so the values of uDate2 and uTime2 will
1883 depend on the local timezone. If the times are exactly
1884 equal then the dates should be identical for both FAT
1885 and NTFS as no timezone is more than 1 day away from UTC.
1887 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1889 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1890 "Last write date and time should match last access date and time!\n");
1892 else
1894 /* Filesystem may be FAT. Check date within 1 day
1895 and seconds are zero. */
1896 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1897 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1898 "Last access time on FAT filesystems should have zero seconds.\n");
1899 /* TODO: Perform check for date being within one day.*/
1902 ok (!lstrcmpW(wszFile[i], name) ||
1903 !lstrcmpW(wszFile[i], name + 9) || /* Vista */
1904 !lstrcmpW(wszFile[i], name + 11) || /* Win7 */
1905 !lstrcmpW(wszFile[i], name + 13), /* Win8 */
1906 "The filename should be stored in unicode at this position!\n");
1910 pILFree(pidlFile);
1913 IShellFolder_Release(psfPersonal);
1916 static void test_SHGetFolderPathA(void)
1918 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1919 BOOL is_wow64;
1920 char path[MAX_PATH];
1921 char path_x86[MAX_PATH];
1922 char path_key[MAX_PATH];
1923 HRESULT hr;
1924 HKEY key;
1926 if (!pSHGetFolderPathA)
1928 win_skip("SHGetFolderPathA not present\n");
1929 return;
1931 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1933 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1934 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1935 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1936 if (hr == E_FAIL)
1938 win_skip( "Program Files (x86) not supported\n" );
1939 return;
1941 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1942 if (is_win64)
1944 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1945 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1946 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1948 else
1950 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1951 if (is_wow64)
1952 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1953 else
1954 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1956 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1958 DWORD type, count = sizeof(path_x86);
1959 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1961 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1962 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1964 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1965 RegCloseKey( key );
1968 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1969 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1970 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1971 if (hr == E_FAIL)
1973 win_skip( "Common Files (x86) not supported\n" );
1974 return;
1976 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1977 if (is_win64)
1979 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1980 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1981 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1983 else
1985 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1986 if (is_wow64)
1987 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1988 else
1989 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1991 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1993 DWORD type, count = sizeof(path_x86);
1994 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1996 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1997 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1999 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
2003 static void test_SHGetFolderPathAndSubDirA(void)
2005 HRESULT ret;
2006 BOOL delret;
2007 DWORD dwret;
2008 int i;
2009 static const char wine[] = "wine";
2010 static const char winetemp[] = "wine\\temp";
2011 static char appdata[MAX_PATH];
2012 static char testpath[MAX_PATH];
2013 static char toolongpath[MAX_PATH+1];
2015 if(!pSHGetFolderPathAndSubDirA)
2017 win_skip("SHGetFolderPathAndSubDirA not present!\n");
2018 return;
2021 if(!pSHGetFolderPathA) {
2022 win_skip("SHGetFolderPathA not present!\n");
2023 return;
2025 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
2027 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
2028 return;
2031 sprintf(testpath, "%s\\%s", appdata, winetemp);
2032 delret = RemoveDirectoryA(testpath);
2033 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
2034 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
2035 return;
2038 sprintf(testpath, "%s\\%s", appdata, wine);
2039 delret = RemoveDirectoryA(testpath);
2040 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
2041 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
2042 return;
2045 /* test invalid second parameter */
2046 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
2047 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
2049 /* test fourth parameter */
2050 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
2051 switch(ret) {
2052 case S_OK: /* winvista */
2053 ok(!strncmp(appdata, testpath, strlen(appdata)),
2054 "expected %s to start with %s\n", testpath, appdata);
2055 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2056 "expected %s to end with %s\n", testpath, winetemp);
2057 break;
2058 case E_INVALIDARG: /* winxp, win2k3 */
2059 break;
2060 default:
2061 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
2064 /* test fifth parameter */
2065 testpath[0] = '\0';
2066 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
2067 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2068 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2070 testpath[0] = '\0';
2071 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
2072 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2073 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2075 testpath[0] = '\0';
2076 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
2077 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2078 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2080 for(i=0; i< MAX_PATH; i++)
2081 toolongpath[i] = '0' + i % 10;
2082 toolongpath[MAX_PATH] = '\0';
2083 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2084 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2085 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2087 testpath[0] = '\0';
2088 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2089 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2091 /* test a not existing path */
2092 testpath[0] = '\0';
2093 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2094 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2095 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2097 /* create a directory inside a not existing directory */
2098 testpath[0] = '\0';
2099 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2100 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2101 ok(!strncmp(appdata, testpath, strlen(appdata)),
2102 "expected %s to start with %s\n", testpath, appdata);
2103 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2104 "expected %s to end with %s\n", testpath, winetemp);
2105 dwret = GetFileAttributesA(testpath);
2106 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2108 /* cleanup */
2109 sprintf(testpath, "%s\\%s", appdata, winetemp);
2110 RemoveDirectoryA(testpath);
2111 sprintf(testpath, "%s\\%s", appdata, wine);
2112 RemoveDirectoryA(testpath);
2115 static void test_LocalizedNames(void)
2117 static char cCurrDirA[MAX_PATH];
2118 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2119 IShellFolder *IDesktopFolder, *testIShellFolder;
2120 ITEMIDLIST *newPIDL;
2121 int len;
2122 HRESULT hr;
2123 static char resourcefile[MAX_PATH];
2124 DWORD res;
2125 HANDLE file;
2126 STRRET strret;
2127 BOOL ret;
2129 static const char desktopini_contents1[] =
2130 "[.ShellClassInfo]\r\n"
2131 "LocalizedResourceName=@";
2132 static const char desktopini_contents2[] =
2133 ",-1\r\n";
2134 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2135 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2137 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2138 CreateDirectoryA(".\\testfolder", NULL);
2140 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2142 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2144 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2145 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2146 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2147 ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2148 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2149 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
2150 ok(ret, "WriteFile failed %i\n", GetLastError());
2151 CloseHandle(file);
2153 /* get IShellFolder for parent */
2154 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2155 len = lstrlenA(cCurrDirA);
2157 if (len == 0) {
2158 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2159 goto cleanup;
2161 if(cCurrDirA[len-1] == '\\')
2162 cCurrDirA[len-1] = 0;
2164 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2166 hr = SHGetDesktopFolder(&IDesktopFolder);
2167 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2169 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2170 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2172 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2173 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2175 IMalloc_Free(ppM, newPIDL);
2177 /* windows reads the display name from the resource */
2178 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2179 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2181 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2182 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2184 if (hr == S_OK && pStrRetToBufW)
2186 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2187 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2188 todo_wine
2189 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2190 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2191 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2194 /* editing name is also read from the resource */
2195 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2196 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2198 if (hr == S_OK && pStrRetToBufW)
2200 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2201 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2202 todo_wine
2203 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2204 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2205 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2208 /* parsing name is unchanged */
2209 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2210 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2212 if (hr == S_OK && pStrRetToBufW)
2214 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2215 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2216 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2219 IShellFolder_Release(IDesktopFolder);
2220 IShellFolder_Release(testIShellFolder);
2222 IMalloc_Free(ppM, newPIDL);
2224 cleanup:
2225 DeleteFileA(".\\testfolder\\desktop.ini");
2226 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2227 RemoveDirectoryA(".\\testfolder");
2230 static void test_SHCreateShellItem(void)
2232 IShellItem *shellitem, *shellitem2;
2233 IPersistIDList *persistidl;
2234 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2235 HRESULT ret;
2236 char curdirA[MAX_PATH];
2237 WCHAR curdirW[MAX_PATH];
2238 WCHAR fnbufW[MAX_PATH];
2239 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2240 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2242 GetCurrentDirectoryA(MAX_PATH, curdirA);
2244 if (!pSHCreateShellItem)
2246 win_skip("SHCreateShellItem isn't available\n");
2247 return;
2250 if (!curdirA[0])
2252 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2253 return;
2256 if(pSHGetSpecialFolderLocation)
2258 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2259 ok(ret == S_OK, "Got 0x%08x\n", ret);
2261 else
2263 win_skip("pSHGetSpecialFolderLocation missing.\n");
2264 pidl_desktop = NULL;
2267 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2269 ret = SHGetDesktopFolder(&desktopfolder);
2270 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2272 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2273 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2275 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2276 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2278 CreateTestFile(".\\testfile");
2280 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2281 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2283 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2285 shellitem = (void*)0xdeadbeef;
2286 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2287 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2288 ok(shellitem == 0, "Got %p\n", shellitem);
2290 if (0) /* crashes on Windows XP */
2292 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2293 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2294 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2295 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2298 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2299 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2300 if (SUCCEEDED(ret))
2302 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2303 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2304 if (SUCCEEDED(ret))
2306 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2307 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2308 if (SUCCEEDED(ret))
2310 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2311 pILFree(pidl_test);
2313 IPersistIDList_Release(persistidl);
2315 IShellItem_Release(shellitem);
2318 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2319 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2320 if (SUCCEEDED(ret))
2322 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2323 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2324 if (SUCCEEDED(ret))
2326 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2327 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2328 if (SUCCEEDED(ret))
2330 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2331 pILFree(pidl_test);
2333 IPersistIDList_Release(persistidl);
2336 ret = IShellItem_GetParent(shellitem, &shellitem2);
2337 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2338 if (SUCCEEDED(ret))
2340 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2341 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2342 if (SUCCEEDED(ret))
2344 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2345 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2346 if (SUCCEEDED(ret))
2348 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2349 pILFree(pidl_test);
2351 IPersistIDList_Release(persistidl);
2353 IShellItem_Release(shellitem2);
2356 IShellItem_Release(shellitem);
2359 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2360 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2361 if (SUCCEEDED(ret))
2363 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2364 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2365 if (SUCCEEDED(ret))
2367 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2368 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2369 if (SUCCEEDED(ret))
2371 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2372 pILFree(pidl_test);
2374 IPersistIDList_Release(persistidl);
2376 IShellItem_Release(shellitem);
2379 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2380 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2381 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2382 if (SUCCEEDED(ret))
2384 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2385 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2386 if (SUCCEEDED(ret))
2388 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2389 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2390 if (SUCCEEDED(ret))
2392 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2393 pILFree(pidl_test);
2395 IPersistIDList_Release(persistidl);
2397 IShellItem_Release(shellitem);
2400 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2401 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2402 if (SUCCEEDED(ret))
2404 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2405 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2406 if (SUCCEEDED(ret))
2408 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2409 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2410 if (SUCCEEDED(ret))
2412 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2413 pILFree(pidl_test);
2415 IPersistIDList_Release(persistidl);
2418 IShellItem_Release(shellitem);
2421 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2422 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2423 if (SUCCEEDED(ret))
2425 ret = IShellItem_GetParent(shellitem, &shellitem2);
2426 ok(FAILED(ret), "Got 0x%08x\n", ret);
2427 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2428 IShellItem_Release(shellitem);
2431 /* SHCreateItemFromParsingName */
2432 if(pSHCreateItemFromParsingName)
2434 if(0)
2436 /* Crashes under windows 7 */
2437 pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2440 shellitem = (void*)0xdeadbeef;
2441 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2442 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2443 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2445 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2446 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2447 "SHCreateItemFromParsingName returned %x\n", ret);
2448 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2450 lstrcpyW(fnbufW, curdirW);
2451 myPathAddBackslashW(fnbufW);
2452 lstrcatW(fnbufW, testfileW);
2454 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2455 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2456 if(SUCCEEDED(ret))
2458 LPWSTR tmp_fname;
2459 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2460 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2461 if(SUCCEEDED(ret))
2463 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2464 CoTaskMemFree(tmp_fname);
2466 IShellItem_Release(shellitem);
2469 else
2470 win_skip("No SHCreateItemFromParsingName\n");
2473 /* SHCreateItemFromIDList */
2474 if(pSHCreateItemFromIDList)
2476 if(0)
2478 /* Crashes under win7 */
2479 pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2482 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2483 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2485 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2486 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2487 if (SUCCEEDED(ret))
2489 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2490 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2491 if (SUCCEEDED(ret))
2493 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2494 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2495 if (SUCCEEDED(ret))
2497 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2498 pILFree(pidl_test);
2500 IPersistIDList_Release(persistidl);
2502 IShellItem_Release(shellitem);
2505 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2506 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2507 if (SUCCEEDED(ret))
2509 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2510 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2511 if (SUCCEEDED(ret))
2513 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2514 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2515 if (SUCCEEDED(ret))
2517 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2518 pILFree(pidl_test);
2520 IPersistIDList_Release(persistidl);
2522 IShellItem_Release(shellitem);
2525 else
2526 win_skip("No SHCreateItemFromIDList\n");
2528 /* SHCreateItemFromRelativeName */
2529 if(pSHCreateItemFromRelativeName && pSHGetKnownFolderPath)
2531 IShellItem *shellitem_desktop = NULL;
2532 WCHAR *desktop_path, *displayname;
2533 WCHAR testfile_path[MAX_PATH] = {0};
2534 HANDLE file;
2535 LPITEMIDLIST pidl_desktop_testfile = NULL;
2536 int order;
2538 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem_desktop);
2539 ok(ret == S_OK, "SHCreateShellItem failed: 0x%08x.\n", ret);
2541 shellitem = (void*)0xdeadbeef;
2542 ret = pSHCreateItemFromRelativeName(shellitem_desktop, NULL, NULL, &IID_IShellItem,
2543 (void**)&shellitem);
2544 ok(ret == E_INVALIDARG, "Expected 0x%08x but SHCreateItemFromRelativeName return: 0x%08x.\n",
2545 E_INVALIDARG, ret);
2546 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2548 /* Test with a non-existent file */
2549 shellitem = (void*)0xdeadbeef;
2550 ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2551 (void**)&shellitem);
2552 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2553 "Expected 0x%08x but SHCreateItemFromRelativeName return: 0x%08x.\n",
2554 HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), ret);
2555 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2557 /* Create a file for testing in desktop folder */
2558 pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &desktop_path);
2559 lstrcatW(testfile_path, desktop_path);
2560 myPathAddBackslashW(testfile_path);
2561 lstrcatW(testfile_path, testfileW);
2562 file = CreateFileW(testfile_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
2563 ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: 0x%08x.\n", GetLastError());
2564 CloseHandle(file);
2566 shellitem = (void*)0xdeadbeef;
2567 ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2568 (void**)&shellitem);
2569 ok(ret == S_OK, "SHCreateItemFromRelativeName failed: 0x%08x.\n", ret);
2570 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2571 if(SUCCEEDED(ret))
2573 ret = IShellItem_GetDisplayName(shellitem, 0, &displayname);
2574 ok(ret == S_OK, "IShellItem_GetDisplayName failed: 0x%08x.\n", ret);
2575 ok(!lstrcmpW(displayname, testfileW), "got wrong display name: %s.\n", wine_dbgstr_w(displayname));
2576 CoTaskMemFree(displayname);
2578 shellitem2 = (void*)0xdeadbeef;
2579 ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2580 (void**)&shellitem2);
2581 ok(ret == S_OK, "SHCreateItemFromRelativeName failed: 0x%08x.\n", ret);
2582 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2583 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2584 ok(!order, "order got wrong value: %d.\n", order);
2585 IShellItem_Release(shellitem2);
2587 shellitem2 = (void*)0xdeadbeef;
2588 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, testfileW, NULL,
2589 &pidl_desktop_testfile, NULL);
2590 ok(ret == S_OK, "ParseDisplayName failed 0x%08x.\n", ret);
2591 ret = pSHCreateItemFromIDList(pidl_desktop_testfile, &IID_IShellItem, (void**)&shellitem2);
2592 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2593 ok(ret == S_OK, "IShellItem_Compare fail: 0x%08x.\n", ret);
2594 ok(!order, "order got wrong value: %d.\n", order);
2595 pILFree(pidl_desktop_testfile);
2596 IShellItem_Release(shellitem2);
2598 IShellItem_Release(shellitem);
2601 DeleteFileW(testfile_path);
2602 CoTaskMemFree(desktop_path);
2603 IShellItem_Release(shellitem_desktop);
2605 else
2606 win_skip("No SHCreateItemFromRelativeName or SHGetKnownFolderPath\n");
2608 /* SHCreateItemInKnownFolder */
2609 if(pSHCreateItemInKnownFolder && pSHGetKnownFolderPath)
2611 WCHAR *desktop_path;
2612 WCHAR testfile_path[MAX_PATH] = {0};
2613 HANDLE file;
2614 WCHAR *displayname = NULL;
2615 int order;
2616 LPITEMIDLIST pidl_desktop_testfile = NULL;
2618 shellitem = (void*)0xdeadbeef;
2619 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, NULL, &IID_IShellItem,
2620 (void**)&shellitem);
2621 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2622 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2623 if(SUCCEEDED(ret))
2625 shellitem2 = (void*)0xdeadbeef;
2626 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem2);
2627 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2628 if(SUCCEEDED(ret))
2630 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2631 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2632 ok(!order, "order got wrong value: %d.\n", order);
2633 IShellItem_Release(shellitem2);
2635 IShellItem_Release(shellitem);
2638 /* Test with a non-existent file */
2639 shellitem = (void*)0xdeadbeef;
2640 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2641 (void**)&shellitem);
2642 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2643 "Expected 0x%08x but SHCreateItemInKnownFolder return: 0x%08x.\n",
2644 HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), ret);
2645 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2647 pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &desktop_path);
2648 lstrcatW(testfile_path, desktop_path);
2649 myPathAddBackslashW(testfile_path);
2650 lstrcatW(testfile_path, testfileW);
2651 file = CreateFileW(testfile_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
2652 ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: 0x%08x.\n", GetLastError());
2653 CloseHandle(file);
2655 shellitem = (void*)0xdeadbeef;
2656 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2657 (void**)&shellitem);
2658 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2659 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2660 if(SUCCEEDED(ret))
2662 ret = IShellItem_GetDisplayName(shellitem, 0, &displayname);
2663 ok(ret == S_OK, "IShellItem_GetDisplayName failed: 0x%08x.\n", ret);
2664 ok(!lstrcmpW(displayname, testfileW), "got wrong display name: %s.\n",
2665 wine_dbgstr_w(displayname));
2666 CoTaskMemFree(displayname);
2668 shellitem2 = (void*)0xdeadbeef;
2669 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2670 (void**)&shellitem2);
2671 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2672 ok(shellitem2 != NULL, "shellitem was %p.\n", shellitem);
2673 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2674 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2675 ok(!order, "order got wrong value: %d.\n", order);
2676 IShellItem_Release(shellitem2);
2678 shellitem2 = (void*)0xdeadbeef;
2679 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, testfileW, NULL,
2680 &pidl_desktop_testfile, NULL);
2681 ok(SUCCEEDED(ret), "ParseDisplayName returned %x.\n", ret);
2682 ret = pSHCreateItemFromIDList(pidl_desktop_testfile, &IID_IShellItem, (void**)&shellitem2);
2683 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2684 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2685 ok(!order, "order got wrong value: %d.\n", order);
2686 pILFree(pidl_desktop_testfile);
2687 IShellItem_Release(shellitem2);
2689 IShellItem_Release(shellitem);
2692 shellitem = (void*)0xdeadbeef;
2693 ret = pSHCreateItemInKnownFolder(&FOLDERID_Documents, 0, NULL, &IID_IShellItem,
2694 (void**)&shellitem);
2695 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2696 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2697 if(SUCCEEDED(ret))
2699 shellitem2 = (void*)0xdeadbeef;
2700 ret = pSHCreateItemInKnownFolder(&FOLDERID_Documents, 0, NULL, &IID_IShellItem,
2701 (void**)&shellitem2);
2702 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2703 ok(shellitem2 != NULL, "shellitem was %p.\n", shellitem);
2704 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2705 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2706 ok(!order, "order got wrong value: %d.\n", order);
2707 IShellItem_Release(shellitem2);
2709 IShellItem_Release(shellitem);
2711 DeleteFileW(testfile_path);
2712 CoTaskMemFree(desktop_path);
2714 else
2715 win_skip("No SHCreateItemInKnownFolder or SHGetKnownFolderPath\n");
2717 DeleteFileA(".\\testfile");
2718 pILFree(pidl_abstestfile);
2719 pILFree(pidl_testfile);
2720 pILFree(pidl_desktop);
2721 pILFree(pidl_cwd);
2722 IShellFolder_Release(currentfolder);
2723 IShellFolder_Release(desktopfolder);
2726 static void test_SHGetNameFromIDList(void)
2728 IShellItem *shellitem;
2729 LPITEMIDLIST pidl;
2730 LPWSTR name_string;
2731 HRESULT hres;
2732 UINT i;
2733 static const DWORD flags[] = {
2734 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2735 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2736 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2737 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2739 if(!pSHGetNameFromIDList)
2741 win_skip("SHGetNameFromIDList missing.\n");
2742 return;
2745 /* These should be available on any platform that passed the above test. */
2746 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2747 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2748 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2749 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2751 if(0)
2753 /* Crashes under win7 */
2754 pSHGetNameFromIDList(NULL, 0, NULL);
2757 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2758 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2760 /* Test the desktop */
2761 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2762 ok(hres == S_OK, "Got 0x%08x\n", hres);
2763 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2764 ok(hres == S_OK, "Got 0x%08x\n", hres);
2765 if(SUCCEEDED(hres))
2767 WCHAR *nameSI, *nameSH;
2768 WCHAR buf[MAX_PATH];
2769 HRESULT hrSI, hrSH, hrSF;
2770 STRRET strret;
2771 IShellFolder *psf;
2772 BOOL res;
2774 SHGetDesktopFolder(&psf);
2775 for(i = 0; flags[i] != -1234; i++)
2777 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2778 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2779 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2780 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2781 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2782 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2784 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2785 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2787 if(SUCCEEDED(hrSF))
2789 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2790 if(SUCCEEDED(hrSI))
2791 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2792 if(SUCCEEDED(hrSF))
2793 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2795 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2796 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2798 IShellFolder_Release(psf);
2800 if(pSHGetPathFromIDListW){
2801 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2802 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2803 res = pSHGetPathFromIDListW(pidl, buf);
2804 ok(res == TRUE, "Got %d\n", res);
2805 if(SUCCEEDED(hrSI) && res)
2806 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2807 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2808 }else
2809 win_skip("pSHGetPathFromIDListW not available\n");
2811 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2812 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2813 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2815 IShellItem_Release(shellitem);
2817 pILFree(pidl);
2819 /* Test the control panel */
2820 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2821 ok(hres == S_OK, "Got 0x%08x\n", hres);
2822 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2823 ok(hres == S_OK, "Got 0x%08x\n", hres);
2824 if(SUCCEEDED(hres))
2826 WCHAR *nameSI, *nameSH;
2827 WCHAR buf[MAX_PATH];
2828 HRESULT hrSI, hrSH, hrSF;
2829 STRRET strret;
2830 IShellFolder *psf;
2831 BOOL res;
2833 SHGetDesktopFolder(&psf);
2834 for(i = 0; flags[i] != -1234; i++)
2836 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2837 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2838 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2839 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2840 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2841 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2843 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2844 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2846 if(SUCCEEDED(hrSF))
2848 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2849 if(SUCCEEDED(hrSI))
2850 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2851 if(SUCCEEDED(hrSF))
2852 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2854 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2855 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2857 IShellFolder_Release(psf);
2859 if(pSHGetPathFromIDListW){
2860 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2861 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2862 res = pSHGetPathFromIDListW(pidl, buf);
2863 ok(res == FALSE, "Got %d\n", res);
2864 if(SUCCEEDED(hrSI) && res)
2865 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2866 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2867 }else
2868 win_skip("pSHGetPathFromIDListW not available\n");
2870 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2871 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2872 "Got 0x%08x\n", hres);
2873 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2875 IShellItem_Release(shellitem);
2877 pILFree(pidl);
2880 static void test_SHGetItemFromDataObject(void)
2882 IShellFolder *psfdesktop;
2883 IShellItem *psi;
2884 IShellView *psv;
2885 HRESULT hres;
2887 if(!pSHGetItemFromDataObject)
2889 win_skip("No SHGetItemFromDataObject.\n");
2890 return;
2893 if(0)
2895 /* Crashes under win7 */
2896 pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2899 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2900 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2902 SHGetDesktopFolder(&psfdesktop);
2904 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2905 ok(hres == S_OK, "got 0x%08x\n", hres);
2906 if(SUCCEEDED(hres))
2908 IEnumIDList *peidl;
2909 IDataObject *pdo;
2910 SHCONTF enum_flags;
2912 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2913 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2914 ok(hres == S_OK, "got 0x%08x\n", hres);
2915 if(SUCCEEDED(hres))
2917 LPITEMIDLIST apidl[5];
2918 UINT count = 0, i;
2920 for(count = 0; count < 5; count++)
2921 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2922 break;
2924 if(count)
2926 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2927 &IID_IDataObject, NULL, (void**)&pdo);
2928 ok(hres == S_OK, "got 0x%08x\n", hres);
2929 if(SUCCEEDED(hres))
2931 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2932 ok(hres == S_OK, "got 0x%08x\n", hres);
2933 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2934 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2935 ok(hres == S_OK, "got 0x%08x\n", hres);
2936 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2937 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2938 ok(hres == S_OK, "got 0x%08x\n", hres);
2939 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2940 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2941 ok(hres == S_OK, "got 0x%08x\n", hres);
2942 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2943 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2944 ok(hres == S_OK, "got 0x%08x\n", hres);
2945 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2947 IDataObject_Release(pdo);
2950 else
2951 skip("No file(s) found - skipping single-file test.\n");
2953 if(count > 1)
2955 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2956 &IID_IDataObject, NULL, (void**)&pdo);
2957 ok(hres == S_OK, "got 0x%08x\n", hres);
2958 if(SUCCEEDED(hres))
2960 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2961 ok(hres == S_OK, "got 0x%08x\n", hres);
2962 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2963 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2964 ok(hres == S_OK, "got 0x%08x\n", hres);
2965 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2966 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2967 ok(hres == S_OK, "got 0x%08x\n", hres);
2968 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2969 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2970 ok(hres == S_OK, "got 0x%08x\n", hres);
2971 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2972 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2973 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2974 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2975 IDataObject_Release(pdo);
2978 else
2979 skip("zero or one file found - skipping multi-file test.\n");
2981 for(i = 0; i < count; i++)
2982 pILFree(apidl[i]);
2984 IEnumIDList_Release(peidl);
2987 IShellView_Release(psv);
2990 IShellFolder_Release(psfdesktop);
2993 static void test_ShellItemCompare(void)
2995 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2996 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2997 IShellFolder *psf_desktop, *psf_current;
2998 LPITEMIDLIST pidl_cwd;
2999 WCHAR curdirW[MAX_PATH];
3000 BOOL failed;
3001 HRESULT hr;
3002 static const WCHAR filesW[][9] = {
3003 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
3004 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
3005 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
3006 int order;
3007 UINT i;
3009 if(!pSHCreateShellItem)
3011 win_skip("SHCreateShellItem missing.\n");
3012 return;
3015 GetCurrentDirectoryW(MAX_PATH, curdirW);
3016 if (!curdirW[0])
3018 skip("Failed to get current directory, skipping.\n");
3019 return;
3022 CreateDirectoryA(".\\a", NULL);
3023 CreateDirectoryA(".\\b", NULL);
3024 CreateDirectoryA(".\\c", NULL);
3025 CreateTestFile(".\\a\\a");
3026 CreateTestFile(".\\a\\b");
3027 CreateTestFile(".\\a\\c");
3028 CreateTestFile(".\\b\\a");
3029 CreateTestFile(".\\b\\b");
3030 CreateTestFile(".\\b\\c");
3031 CreateTestFile(".\\c\\a");
3032 CreateTestFile(".\\c\\b");
3033 CreateTestFile(".\\c\\c");
3035 SHGetDesktopFolder(&psf_desktop);
3036 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
3037 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
3038 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
3039 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
3040 IShellFolder_Release(psf_desktop);
3041 ILFree(pidl_cwd);
3043 /* Generate ShellItems for the files */
3044 memset(&psi, 0, sizeof(psi));
3045 failed = FALSE;
3046 for(i = 0; i < 9; i++)
3048 LPITEMIDLIST pidl_testfile = NULL;
3050 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
3051 NULL, &pidl_testfile, NULL);
3052 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
3053 if(SUCCEEDED(hr))
3055 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
3056 ok(hr == S_OK, "Got 0x%08x\n", hr);
3057 pILFree(pidl_testfile);
3059 if(FAILED(hr)) failed = TRUE;
3061 if(failed)
3063 skip("Failed to create all shellitems.\n");
3064 goto cleanup;
3067 /* Generate ShellItems for the folders */
3068 hr = IShellItem_GetParent(psi[0], &psi_a);
3069 ok(hr == S_OK, "Got 0x%08x\n", hr);
3070 if(FAILED(hr)) failed = TRUE;
3071 hr = IShellItem_GetParent(psi[3], &psi_b);
3072 ok(hr == S_OK, "Got 0x%08x\n", hr);
3073 if(FAILED(hr)) failed = TRUE;
3074 hr = IShellItem_GetParent(psi[6], &psi_c);
3075 ok(hr == S_OK, "Got 0x%08x\n", hr);
3076 if(FAILED(hr)) failed = TRUE;
3078 if(failed)
3080 skip("Failed to create shellitems.\n");
3081 goto cleanup;
3084 if(0)
3086 /* Crashes on native (win7, winxp) */
3087 IShellItem_Compare(psi_a, NULL, 0, NULL);
3088 IShellItem_Compare(psi_a, psi_b, 0, NULL);
3089 IShellItem_Compare(psi_a, NULL, 0, &order);
3092 /* Basics */
3093 for(i = 0; i < 9; i++)
3095 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
3096 ok(hr == S_OK, "Got 0x%08x\n", hr);
3097 ok(order == 0, "Got order %d\n", order);
3098 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
3099 ok(hr == S_OK, "Got 0x%08x\n", hr);
3100 ok(order == 0, "Got order %d\n", order);
3101 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
3102 ok(hr == S_OK, "Got 0x%08x\n", hr);
3103 ok(order == 0, "Got order %d\n", order);
3106 /* Order */
3107 /* a\b:a\a , a\b:a\c, a\b:a\b */
3108 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
3109 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3110 ok(order == 1, "Got order %d\n", order);
3111 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
3112 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3113 ok(order == -1, "Got order %d\n", order);
3114 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
3115 ok(hr == S_OK, "Got 0x%08x\n", hr);
3116 ok(order == 0, "Got order %d\n", order);
3118 /* b\b:a\b, b\b:c\b, b\b:c\b */
3119 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
3120 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3121 ok(order == 1, "Got order %d\n", order);
3122 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
3123 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3124 ok(order == -1, "Got order %d\n", order);
3125 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
3126 ok(hr == S_OK, "Got 0x%08x\n", hr);
3127 ok(order == 0, "Got order %d\n", order);
3129 /* b:a\a, b:a\c, b:a\b */
3130 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
3131 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3132 todo_wine ok(order == 1, "Got order %d\n", order);
3133 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
3134 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3135 todo_wine ok(order == 1, "Got order %d\n", order);
3136 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
3137 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3138 todo_wine ok(order == 1, "Got order %d\n", order);
3140 /* b:c\a, b:c\c, b:c\b */
3141 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
3142 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3143 ok(order == -1, "Got order %d\n", order);
3144 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
3145 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3146 ok(order == -1, "Got order %d\n", order);
3147 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
3148 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3149 ok(order == -1, "Got order %d\n", order);
3151 /* a\b:a\a , a\b:a\c, a\b:a\b */
3152 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
3153 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3154 ok(order == 1, "Got order %d\n", order);
3155 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
3156 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3157 ok(order == -1, "Got order %d\n", order);
3158 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
3159 ok(hr == S_OK, "Got 0x%08x\n", hr);
3160 ok(order == 0, "Got order %d\n", order);
3162 /* b\b:a\b, b\b:c\b, b\b:c\b */
3163 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
3164 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3165 ok(order == 1, "Got order %d\n", order);
3166 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
3167 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3168 ok(order == -1, "Got order %d\n", order);
3169 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
3170 ok(hr == S_OK, "Got 0x%08x\n", hr);
3171 ok(order == 0, "Got order %d\n", order);
3173 /* b:a\a, b:a\c, b:a\b */
3174 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
3175 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3176 todo_wine ok(order == 1, "Got order %d\n", order);
3177 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
3178 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3179 todo_wine ok(order == 1, "Got order %d\n", order);
3180 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
3181 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3182 todo_wine ok(order == 1, "Got order %d\n", order);
3184 /* b:c\a, b:c\c, b:c\b */
3185 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
3186 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3187 ok(order == -1, "Got order %d\n", order);
3188 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
3189 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3190 ok(order == -1, "Got order %d\n", order);
3191 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
3192 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3193 ok(order == -1, "Got order %d\n", order);
3195 cleanup:
3196 IShellFolder_Release(psf_current);
3198 DeleteFileA(".\\a\\a");
3199 DeleteFileA(".\\a\\b");
3200 DeleteFileA(".\\a\\c");
3201 DeleteFileA(".\\b\\a");
3202 DeleteFileA(".\\b\\b");
3203 DeleteFileA(".\\b\\c");
3204 DeleteFileA(".\\c\\a");
3205 DeleteFileA(".\\c\\b");
3206 DeleteFileA(".\\c\\c");
3207 RemoveDirectoryA(".\\a");
3208 RemoveDirectoryA(".\\b");
3209 RemoveDirectoryA(".\\c");
3211 if(psi_a) IShellItem_Release(psi_a);
3212 if(psi_b) IShellItem_Release(psi_b);
3213 if(psi_c) IShellItem_Release(psi_c);
3215 for(i = 0; i < 9; i++)
3216 if(psi[i]) IShellItem_Release(psi[i]);
3219 /**************************************************************/
3220 /* IUnknown implementation for counting QueryInterface calls. */
3221 typedef struct {
3222 IUnknown IUnknown_iface;
3223 struct if_count {
3224 REFIID id;
3225 LONG count;
3226 } *ifaces;
3227 LONG unknown;
3228 } IUnknownImpl;
3230 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
3232 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
3235 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
3237 IUnknownImpl *This = impl_from_IUnknown(iunk);
3238 UINT i;
3239 BOOL found = FALSE;
3240 for(i = 0; This->ifaces[i].id != NULL; i++)
3242 if(IsEqualIID(This->ifaces[i].id, riid))
3244 This->ifaces[i].count++;
3245 found = TRUE;
3246 break;
3249 if(!found)
3250 This->unknown++;
3251 return E_NOINTERFACE;
3254 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
3256 return 2;
3259 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3261 return 1;
3264 static const IUnknownVtbl vt_IUnknown = {
3265 unk_fnQueryInterface,
3266 unk_fnAddRef,
3267 unk_fnRelease
3270 static void test_SHGetIDListFromObject(void)
3272 IUnknownImpl *punkimpl;
3273 IShellFolder *psfdesktop;
3274 IShellView *psv;
3275 LPITEMIDLIST pidl, pidl_desktop;
3276 HRESULT hres;
3277 UINT i;
3278 struct if_count ifaces[] =
3279 { {&IID_IPersistIDList, 0},
3280 {&IID_IPersistFolder2, 0},
3281 {&IID_IDataObject, 0},
3282 {&IID_IParentAndItem, 0},
3283 {&IID_IFolderView, 0},
3284 {NULL, 0} };
3286 if(!pSHGetIDListFromObject)
3288 win_skip("SHGetIDListFromObject missing.\n");
3289 return;
3292 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3294 if(0)
3296 /* Crashes native */
3297 pSHGetIDListFromObject(NULL, NULL);
3298 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3301 hres = pSHGetIDListFromObject(NULL, &pidl);
3302 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3304 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3305 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3306 punkimpl->ifaces = ifaces;
3307 punkimpl->unknown = 0;
3309 hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3310 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3311 ok(ifaces[0].count, "interface not requested.\n");
3312 ok(ifaces[1].count, "interface not requested.\n");
3313 ok(ifaces[2].count, "interface not requested.\n");
3314 todo_wine
3315 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3316 "interface not requested.\n");
3317 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3318 "interface not requested.\n");
3320 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3321 HeapFree(GetProcessHeap(), 0, punkimpl);
3323 pidl_desktop = NULL;
3324 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3325 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3327 SHGetDesktopFolder(&psfdesktop);
3329 /* Test IShellItem */
3330 if(pSHCreateShellItem)
3332 IShellItem *shellitem;
3333 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3334 ok(hres == S_OK, "got 0x%08x\n", hres);
3335 if(SUCCEEDED(hres))
3337 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3338 ok(hres == S_OK, "got 0x%08x\n", hres);
3339 if(SUCCEEDED(hres))
3341 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3342 pILFree(pidl);
3344 IShellItem_Release(shellitem);
3347 else
3348 skip("no SHCreateShellItem.\n");
3350 /* Test IShellFolder */
3351 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3352 ok(hres == S_OK, "got 0x%08x\n", hres);
3353 if(SUCCEEDED(hres))
3355 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3356 pILFree(pidl);
3359 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3360 ok(hres == S_OK, "got 0x%08x\n", hres);
3361 if(SUCCEEDED(hres))
3363 IEnumIDList *peidl;
3364 IDataObject *pdo;
3365 SHCONTF enum_flags;
3367 /* Test IFolderView */
3368 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3369 ok(hres == S_OK, "got 0x%08x\n", hres);
3370 if(SUCCEEDED(hres))
3372 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3373 pILFree(pidl);
3376 /* Test IDataObject */
3377 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3378 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3379 ok(hres == S_OK, "got 0x%08x\n", hres);
3380 if(SUCCEEDED(hres))
3382 LPITEMIDLIST apidl[5];
3383 UINT count = 0;
3384 for(count = 0; count < 5; count++)
3385 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3386 break;
3388 if(count)
3390 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3391 &IID_IDataObject, NULL, (void**)&pdo);
3392 ok(hres == S_OK, "got 0x%08x\n", hres);
3393 if(SUCCEEDED(hres))
3395 pidl = (void*)0xDEADBEEF;
3396 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3397 ok(hres == S_OK, "got 0x%08x\n", hres);
3398 ok(pidl != NULL, "pidl is NULL.\n");
3399 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3400 pILFree(pidl);
3402 IDataObject_Release(pdo);
3405 else
3406 skip("No files found - skipping single-file test.\n");
3408 if(count > 1)
3410 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3411 &IID_IDataObject, NULL, (void**)&pdo);
3412 ok(hres == S_OK, "got 0x%08x\n", hres);
3413 if(SUCCEEDED(hres))
3415 pidl = (void*)0xDEADBEEF;
3416 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3417 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3418 "got 0x%08x\n", hres);
3419 ok(pidl == NULL, "pidl is not NULL.\n");
3421 IDataObject_Release(pdo);
3424 else
3425 skip("zero or one file found - skipping multi-file test.\n");
3427 for(i = 0; i < count; i++)
3428 pILFree(apidl[i]);
3430 IEnumIDList_Release(peidl);
3433 IShellView_Release(psv);
3436 IShellFolder_Release(psfdesktop);
3437 pILFree(pidl_desktop);
3440 static void test_SHGetItemFromObject(void)
3442 IUnknownImpl *punkimpl;
3443 IShellFolder *psfdesktop;
3444 LPITEMIDLIST pidl;
3445 IShellItem *psi;
3446 IUnknown *punk;
3447 HRESULT hres;
3448 struct if_count ifaces[] =
3449 { {&IID_IPersistIDList, 0},
3450 {&IID_IPersistFolder2, 0},
3451 {&IID_IDataObject, 0},
3452 {&IID_IParentAndItem, 0},
3453 {&IID_IFolderView, 0},
3454 {NULL, 0} };
3456 if(!pSHGetItemFromObject)
3458 skip("No SHGetItemFromObject.\n");
3459 return;
3462 SHGetDesktopFolder(&psfdesktop);
3464 if(0)
3466 /* Crashes with Windows 7 */
3467 pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3468 pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3469 pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3472 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3473 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3475 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3476 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3477 punkimpl->ifaces = ifaces;
3478 punkimpl->unknown = 0;
3480 /* The same as SHGetIDListFromObject */
3481 hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3482 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3483 ok(ifaces[0].count, "interface not requested.\n");
3484 ok(ifaces[1].count, "interface not requested.\n");
3485 ok(ifaces[2].count, "interface not requested.\n");
3486 todo_wine
3487 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3488 "interface not requested.\n");
3489 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3490 "interface not requested.\n");
3492 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3493 HeapFree(GetProcessHeap(), 0, punkimpl);
3495 /* Test IShellItem */
3496 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3497 ok(hres == S_OK, "Got 0x%08x\n", hres);
3498 if(SUCCEEDED(hres))
3500 IShellItem *psi2;
3501 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3502 ok(hres == S_OK, "Got 0x%08x\n", hres);
3503 if(SUCCEEDED(hres))
3505 todo_wine
3506 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3507 IShellItem_Release(psi2);
3509 IShellItem_Release(psi);
3512 IShellFolder_Release(psfdesktop);
3515 static void test_SHCreateShellItemArray(void)
3517 IShellFolder *pdesktopsf, *psf;
3518 IShellItemArray *psia;
3519 IEnumIDList *peidl;
3520 HRESULT hr;
3521 WCHAR cTestDirW[MAX_PATH];
3522 LPITEMIDLIST pidl_testdir, pidl;
3523 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3525 if(!pSHCreateShellItemArray) {
3526 skip("No pSHCreateShellItemArray!\n");
3527 return;
3530 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3532 if(0)
3534 /* Crashes under native */
3535 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3536 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3537 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3538 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3541 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3542 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3544 SHGetDesktopFolder(&pdesktopsf);
3545 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3546 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3548 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3549 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3551 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3552 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3553 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3554 pILFree(pidl);
3556 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3557 myPathAddBackslashW(cTestDirW);
3558 lstrcatW(cTestDirW, testdirW);
3560 CreateFilesFolders();
3562 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3563 ok(hr == S_OK, "got 0x%08x\n", hr);
3564 if(SUCCEEDED(hr))
3566 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3567 (void**)&psf);
3568 ok(hr == S_OK, "Got 0x%08x\n", hr);
3570 IShellFolder_Release(pdesktopsf);
3572 if(FAILED(hr))
3574 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3575 pILFree(pidl_testdir);
3576 Cleanup();
3577 return;
3580 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3581 ok(hr == S_OK, "Got %08x\n", hr);
3582 if(SUCCEEDED(hr))
3584 LPITEMIDLIST apidl[5];
3585 UINT done, numitems, i;
3587 for(done = 0; done < 5; done++)
3588 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3589 break;
3590 ok(done == 5, "Got %d pidls\n", done);
3591 IEnumIDList_Release(peidl);
3593 /* Create a ShellItemArray */
3594 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3595 ok(hr == S_OK, "Got 0x%08x\n", hr);
3596 if(SUCCEEDED(hr))
3598 IShellItem *psi;
3600 if(0)
3602 /* Crashes in Windows 7 */
3603 IShellItemArray_GetCount(psia, NULL);
3606 IShellItemArray_GetCount(psia, &numitems);
3607 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3609 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3610 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3612 /* Compare all the items */
3613 for(i = 0; i < numitems; i++)
3615 LPITEMIDLIST pidl_abs;
3616 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3618 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3619 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3620 if(SUCCEEDED(hr))
3622 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3623 ok(hr == S_OK, "Got 0x%08x\n", hr);
3624 if(SUCCEEDED(hr))
3626 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3627 pILFree(pidl);
3629 IShellItem_Release(psi);
3631 pILFree(pidl_abs);
3633 for(i = 0; i < done; i++)
3634 pILFree(apidl[i]);
3635 IShellItemArray_Release(psia);
3639 /* SHCreateShellItemArrayFromShellItem */
3640 if(pSHCreateShellItemArrayFromShellItem)
3642 IShellItem *psi;
3644 if(0)
3646 /* Crashes under Windows 7 */
3647 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3648 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3649 pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3652 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3653 ok(hr == S_OK, "Got 0x%08x\n", hr);
3654 if(SUCCEEDED(hr))
3656 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3657 ok(hr == S_OK, "Got 0x%08x\n", hr);
3658 if(SUCCEEDED(hr))
3660 IShellItem *psi2;
3661 UINT count;
3662 hr = IShellItemArray_GetCount(psia, &count);
3663 ok(hr == S_OK, "Got 0x%08x\n", hr);
3664 ok(count == 1, "Got count %d\n", count);
3665 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3666 ok(hr == S_OK, "Got 0x%08x\n", hr);
3667 todo_wine
3668 ok(psi != psi2, "ShellItems are of the same instance.\n");
3669 if(SUCCEEDED(hr))
3671 LPITEMIDLIST pidl1, pidl2;
3672 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3673 ok(hr == S_OK, "Got 0x%08x\n", hr);
3674 ok(pidl1 != NULL, "pidl1 was null.\n");
3675 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3676 ok(hr == S_OK, "Got 0x%08x\n", hr);
3677 ok(pidl2 != NULL, "pidl2 was null.\n");
3678 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3679 pILFree(pidl1);
3680 pILFree(pidl2);
3681 IShellItem_Release(psi2);
3683 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3684 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3685 IShellItemArray_Release(psia);
3687 IShellItem_Release(psi);
3690 else
3691 skip("No SHCreateShellItemArrayFromShellItem.\n");
3693 if(pSHCreateShellItemArrayFromDataObject)
3695 IShellView *psv;
3697 if(0)
3699 /* Crashes under Windows 7 */
3700 pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3702 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3703 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3705 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3706 ok(hr == S_OK, "got 0x%08x\n", hr);
3707 if(SUCCEEDED(hr))
3709 IEnumIDList *peidl;
3710 IDataObject *pdo;
3711 SHCONTF enum_flags;
3713 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3714 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3715 ok(hr == S_OK, "got 0x%08x\n", hr);
3716 if(SUCCEEDED(hr))
3718 LPITEMIDLIST apidl[5];
3719 UINT count, i;
3721 for(count = 0; count < 5; count++)
3722 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3723 break;
3724 ok(count == 5, "Got %d\n", count);
3726 if(count)
3728 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3729 &IID_IDataObject, NULL, (void**)&pdo);
3730 ok(hr == S_OK, "Got 0x%08x\n", hr);
3731 if(SUCCEEDED(hr))
3733 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3734 (void**)&psia);
3735 ok(hr == S_OK, "Got 0x%08x\n", hr);
3736 if(SUCCEEDED(hr))
3738 UINT count_sia, i;
3739 hr = IShellItemArray_GetCount(psia, &count_sia);
3740 ok(hr == S_OK, "Got 0x%08x\n", hr);
3741 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3742 for(i = 0; i < count_sia; i++)
3744 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3745 IShellItem *psi;
3746 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3747 ok(hr == S_OK, "Got 0x%08x\n", hr);
3748 if(SUCCEEDED(hr))
3750 LPITEMIDLIST pidl;
3751 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3752 ok(hr == S_OK, "Got 0x%08x\n", hr);
3753 ok(pidl != NULL, "pidl as NULL.\n");
3754 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3755 pILFree(pidl);
3756 IShellItem_Release(psi);
3758 pILFree(pidl_abs);
3761 IShellItemArray_Release(psia);
3764 IDataObject_Release(pdo);
3766 for(i = 0; i < count; i++)
3767 pILFree(apidl[i]);
3769 else
3770 skip("No files found - skipping test.\n");
3772 IEnumIDList_Release(peidl);
3774 IShellView_Release(psv);
3777 else
3778 skip("No SHCreateShellItemArrayFromDataObject.\n");
3780 if(pSHCreateShellItemArrayFromIDLists)
3782 WCHAR test1W[] = {'t','e','s','t','1','.','t','x','t',0};
3783 WCHAR test1pathW[MAX_PATH];
3784 LPITEMIDLIST pidltest1;
3785 LPCITEMIDLIST pidl_array[2];
3787 if(0)
3789 /* Crashes */
3790 hr = pSHCreateShellItemArrayFromIDLists(0, NULL, NULL);
3793 psia = (void*)0xdeadbeef;
3794 hr = pSHCreateShellItemArrayFromIDLists(0, NULL, &psia);
3795 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3796 ok(psia == NULL, "Got %p\n", psia);
3798 psia = (void*)0xdeadbeef;
3799 hr = pSHCreateShellItemArrayFromIDLists(0, pidl_array, &psia);
3800 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3801 ok(psia == NULL, "Got %p\n", psia);
3803 psia = (void*)0xdeadbeef;
3804 pidl_array[0] = NULL;
3805 hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3806 todo_wine ok(hr == E_OUTOFMEMORY, "Got 0x%08x\n", hr);
3807 ok(psia == NULL, "Got %p\n", psia);
3809 psia = (void*)0xdeadbeef;
3810 pidl_array[0] = pidl_testdir;
3811 pidl_array[1] = NULL;
3812 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3813 todo_wine ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Vista */, "Got 0x%08x\n", hr);
3814 todo_wine ok(psia != NULL || broken(psia == NULL) /* Vista */, "Got %p\n", psia);
3815 if(SUCCEEDED(hr))
3817 IShellItem *psi;
3818 UINT count = 0;
3820 hr = IShellItemArray_GetCount(psia, &count);
3821 ok(hr == S_OK, "Got 0x%08x\n", hr);
3822 ok(count == 2, "Got %d\n", count);
3824 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3825 ok(hr == S_OK, "Got 0x%08x\n", hr);
3826 if(SUCCEEDED(hr))
3828 LPWSTR path;
3829 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3830 ok(hr == S_OK, "Got 0x%08x\n", hr);
3831 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3832 if(SUCCEEDED(hr))
3833 CoTaskMemFree(path);
3835 IShellItem_Release(psi);
3838 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3839 ok(hr == S_OK, "Got 0x%08x\n", hr);
3840 if(SUCCEEDED(hr))
3842 LPWSTR path;
3843 WCHAR desktoppath[MAX_PATH];
3844 BOOL result;
3846 result = pSHGetSpecialFolderPathW(NULL, desktoppath, CSIDL_DESKTOPDIRECTORY, FALSE);
3847 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
3849 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3850 ok(hr == S_OK, "Got 0x%08x\n", hr);
3851 ok(!lstrcmpW(path, desktoppath), "Got %s\n", wine_dbgstr_w(path));
3852 if(SUCCEEDED(hr))
3853 CoTaskMemFree(path);
3855 IShellItem_Release(psi);
3859 IShellItemArray_Release(psia);
3863 /* Single pidl */
3864 psia = (void*)0xdeadbeef;
3865 pidl_array[0] = pidl_testdir;
3866 hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3867 ok(hr == S_OK, "Got 0x%08x\n", hr);
3868 if(SUCCEEDED(hr))
3870 IShellItem *psi;
3871 UINT count = 0;
3873 hr = IShellItemArray_GetCount(psia, &count);
3874 ok(hr == S_OK, "Got 0x%08x\n", hr);
3875 ok(count == 1, "Got %d\n", count);
3877 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3878 ok(hr == S_OK, "Got 0x%08x\n", hr);
3879 if(SUCCEEDED(hr))
3881 LPWSTR path;
3882 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3883 ok(hr == S_OK, "Got 0x%08x\n", hr);
3884 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3885 if(SUCCEEDED(hr))
3886 CoTaskMemFree(path);
3888 IShellItem_Release(psi);
3891 IShellItemArray_Release(psia);
3895 lstrcpyW(test1pathW, cTestDirW);
3896 myPathAddBackslashW(test1pathW);
3897 lstrcatW(test1pathW, test1W);
3899 SHGetDesktopFolder(&pdesktopsf);
3901 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, test1pathW, NULL, &pidltest1, NULL);
3902 ok(hr == S_OK, "Got 0x%08x\n", hr);
3903 if(SUCCEEDED(hr))
3905 psia = (void*)0xdeadbeef;
3906 pidl_array[0] = pidl_testdir;
3907 pidl_array[1] = pidltest1;
3908 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3909 ok(hr == S_OK, "Got 0x%08x\n", hr);
3910 if(SUCCEEDED(hr))
3912 IShellItem *psi;
3913 UINT count = 0;
3915 hr = IShellItemArray_GetCount(psia, &count);
3916 ok(hr == S_OK, "Got 0x%08x\n", hr);
3917 ok(count == 2, "Got %d\n", count);
3919 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3920 ok(hr == S_OK, "Got 0x%08x\n", hr);
3921 if(SUCCEEDED(hr))
3923 LPWSTR path;
3924 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3925 ok(hr == S_OK, "Got 0x%08x\n", hr);
3926 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3927 if(SUCCEEDED(hr))
3928 CoTaskMemFree(path);
3930 IShellItem_Release(psi);
3933 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3934 ok(hr == S_OK, "Got 0x%08x\n", hr);
3935 if(SUCCEEDED(hr))
3937 LPWSTR path;
3938 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3939 ok(hr == S_OK, "Got 0x%08x\n", hr);
3940 ok(!lstrcmpW(path, test1pathW), "Got %s\n", wine_dbgstr_w(path));
3941 if(SUCCEEDED(hr))
3942 CoTaskMemFree(path);
3944 IShellItem_Release(psi);
3948 IShellItemArray_Release(psia);
3951 pILFree(pidltest1);
3954 IShellFolder_Release(pdesktopsf);
3956 else
3957 skip("No SHCreateShellItemArrayFromIDLists.\n");
3959 IShellFolder_Release(psf);
3960 pILFree(pidl_testdir);
3961 Cleanup();
3964 static void test_ShellItemArrayEnumItems(void)
3966 IShellFolder *pdesktopsf, *psf;
3967 IEnumIDList *peidl;
3968 WCHAR cTestDirW[MAX_PATH];
3969 HRESULT hr;
3970 LPITEMIDLIST pidl_testdir;
3971 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3973 if(!pSHCreateShellItemArray)
3975 win_skip("No SHCreateShellItemArray, skipping test...\n");
3976 return;
3979 CreateFilesFolders();
3981 SHGetDesktopFolder(&pdesktopsf);
3983 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3984 myPathAddBackslashW(cTestDirW);
3985 lstrcatW(cTestDirW, testdirW);
3987 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3988 ok(hr == S_OK, "got 0x%08x\n", hr);
3989 if(SUCCEEDED(hr))
3991 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3992 (void**)&psf);
3993 ok(hr == S_OK, "Got 0x%08x\n", hr);
3994 pILFree(pidl_testdir);
3996 IShellFolder_Release(pdesktopsf);
3997 if (FAILED(hr)) return;
3999 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
4000 ok(hr == S_OK, "Got %08x\n", hr);
4001 if(SUCCEEDED(hr))
4003 IShellItemArray *psia;
4004 LPITEMIDLIST apidl[5];
4005 UINT done, numitems, i;
4007 for(done = 0; done < 5; done++)
4008 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
4009 break;
4010 ok(done == 5, "Got %d pidls\n", done);
4011 IEnumIDList_Release(peidl);
4013 /* Create a ShellItemArray */
4014 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
4015 ok(hr == S_OK, "Got 0x%08x\n", hr);
4016 if(SUCCEEDED(hr))
4018 IEnumShellItems *iesi;
4019 IShellItem *my_array[10];
4020 ULONG fetched;
4022 IShellItemArray_GetCount(psia, &numitems);
4023 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
4025 iesi = NULL;
4026 hr = IShellItemArray_EnumItems(psia, &iesi);
4027 ok(hr == S_OK, "Got 0x%08x\n", hr);
4028 ok(iesi != NULL, "Got NULL\n");
4029 if(SUCCEEDED(hr))
4031 IEnumShellItems *iesi2;
4033 /* This should fail according to the documentation and Win7+ */
4034 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
4035 hr = IEnumShellItems_Next(iesi, 2, my_array, NULL);
4036 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4037 for(i = 0; i < 2; i++)
4039 ok(my_array[i] == (void*)0xdeadbeef ||
4040 broken(my_array[i] != (void*)0xdeadbeef && my_array[i] != NULL), /* Vista */
4041 "Got %p (%d)\n", my_array[i], i);
4043 if(my_array[i] != (void*)0xdeadbeef)
4044 IShellItem_Release(my_array[i]);
4046 ok(my_array[2] == (void*)0xdeadbeef, "Got %p\n", my_array[2]);
4048 IEnumShellItems_Reset(iesi);
4049 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
4050 hr = IEnumShellItems_Next(iesi, 1, my_array, NULL);
4051 ok(hr == S_OK, "Got 0x%08x\n", hr);
4052 ok(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef, "Got %p\n", my_array[0]);
4053 if(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef)
4054 IShellItem_Release(my_array[0]);
4055 ok(my_array[1] == (void*)0xdeadbeef, "Got %p\n", my_array[1]);
4057 IEnumShellItems_Reset(iesi);
4058 fetched = 0;
4059 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
4060 hr = IEnumShellItems_Next(iesi, numitems, my_array, &fetched);
4061 ok(hr == S_OK, "Got 0x%08x\n", hr);
4062 ok(fetched == numitems, "Got %d\n", fetched);
4063 for(i = 0;i < numitems; i++)
4065 ok(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef,
4066 "Got %p at %d\n", my_array[i], i);
4068 if(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef)
4069 IShellItem_Release(my_array[i]);
4071 ok(my_array[i] == (void*)0xdeadbeef, "Got %p\n", my_array[i]);
4073 /* Compare all the items */
4074 IEnumShellItems_Reset(iesi);
4075 for(i = 0; i < numitems; i++)
4077 IShellItem *psi;
4078 int order;
4080 hr = IShellItemArray_GetItemAt(psia, i, &psi);
4081 ok(hr == S_OK, "Got 0x%08x\n", hr);
4082 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
4083 ok(hr == S_OK, "Got 0x%08x\n", hr);
4084 ok(fetched == 1, "Got %d\n", fetched);
4086 hr = IShellItem_Compare(psi, my_array[0], 0, &order);
4087 ok(hr == S_OK, "Got 0x%08x\n", hr);
4088 ok(order == 0, "Got %d\n", order);
4090 IShellItem_Release(psi);
4091 IShellItem_Release(my_array[0]);
4094 my_array[0] = (void*)0xdeadbeef;
4095 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
4096 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
4097 ok(fetched == 0, "Got %d\n", fetched);
4098 ok(my_array[0] == (void*)0xdeadbeef, "Got %p\n", my_array[0]);
4100 /* Cloning not implemented anywhere */
4101 iesi2 = (void*)0xdeadbeef;
4102 hr = IEnumShellItems_Clone(iesi, &iesi2);
4103 ok(hr == E_NOTIMPL, "Got 0x%08x\n", hr);
4104 ok(iesi2 == NULL || broken(iesi2 == (void*)0xdeadbeef) /* Vista */, "Got %p\n", iesi2);
4106 IEnumShellItems_Release(iesi);
4109 IShellItemArray_Release(psia);
4112 for(i = 0; i < done; i++)
4113 pILFree(apidl[i]);
4118 static void test_ShellItemBindToHandler(void)
4120 IShellItem *psi;
4121 LPITEMIDLIST pidl_desktop;
4122 HRESULT hr;
4124 if(!pSHCreateShellItem)
4126 skip("SHCreateShellItem missing.\n");
4127 return;
4130 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
4131 ok(hr == S_OK, "Got 0x%08x\n", hr);
4132 if(SUCCEEDED(hr))
4134 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
4135 ok(hr == S_OK, "Got 0x%08x\n", hr);
4137 if(SUCCEEDED(hr))
4139 IPersistFolder2 *ppf2;
4140 IUnknown *punk;
4142 if(0)
4144 /* Crashes under Windows 7 */
4145 IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
4146 IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
4148 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
4149 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
4151 /* BHID_SFObject */
4152 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
4153 ok(hr == S_OK, "Got 0x%08x\n", hr);
4154 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4155 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
4156 ok(hr == S_OK, "Got 0x%08x\n", hr);
4157 if(SUCCEEDED(hr))
4159 LPITEMIDLIST pidl_tmp;
4160 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
4161 ok(hr == S_OK, "Got 0x%08x\n", hr);
4162 if(SUCCEEDED(hr))
4164 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
4165 pILFree(pidl_tmp);
4167 IPersistFolder2_Release(ppf2);
4170 /* BHID_SFUIObject */
4171 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
4172 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
4173 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4174 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
4175 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
4176 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4178 /* BHID_DataObject */
4179 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
4180 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4181 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4183 todo_wine
4185 /* BHID_SFViewObject */
4186 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
4187 ok(hr == S_OK, "Got 0x%08x\n", hr);
4188 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4189 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
4190 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
4191 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4193 /* BHID_Storage */
4194 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
4195 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
4196 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4197 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
4198 ok(hr == S_OK, "Got 0x%08x\n", hr);
4199 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4201 /* BHID_Stream */
4202 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
4203 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
4204 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4205 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
4206 ok(hr == S_OK, "Got 0x%08x\n", hr);
4207 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4209 /* BHID_StorageEnum */
4210 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
4211 ok(hr == S_OK, "Got 0x%08x\n", hr);
4212 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4214 /* BHID_Transfer
4215 ITransferSource and ITransferDestination are accessible starting from Vista, IUnknown is
4216 supported starting from Win8. */
4217 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferSource, (void**)&punk);
4218 ok(hr == S_OK || broken(FAILED(hr)) /* pre-Vista */, "Got 0x%08x\n", hr);
4219 if(SUCCEEDED(hr))
4221 IUnknown_Release(punk);
4223 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferDestination, (void**)&punk);
4224 ok(hr == S_OK, "Got 0x%08x\n", hr);
4225 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4227 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
4228 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Win8 */, "Got 0x%08x\n", hr);
4229 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4232 /* BHID_EnumItems */
4233 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
4234 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4235 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4237 /* BHID_Filter */
4238 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
4239 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4240 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4242 /* BHID_LinkTargetItem */
4243 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
4244 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
4245 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4246 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
4247 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
4248 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4250 /* BHID_PropertyStore */
4251 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
4252 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4253 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4254 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
4255 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4256 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4258 /* BHID_ThumbnailHandler */
4259 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
4260 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4261 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4263 /* BHID_AssociationArray */
4264 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
4265 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4266 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4268 /* BHID_EnumAssocHandlers */
4269 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
4270 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4271 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4274 IShellItem_Release(psi);
4276 else
4277 skip("Failed to create ShellItem.\n");
4279 pILFree(pidl_desktop);
4282 static void test_ShellItemGetAttributes(void)
4284 IShellItem *psi, *psi_folder1, *psi_file1;
4285 IShellFolder *pdesktopsf;
4286 LPITEMIDLIST pidl_desktop, pidl;
4287 SFGAOF sfgao;
4288 HRESULT hr;
4289 WCHAR curdirW[MAX_PATH];
4290 WCHAR buf[MAX_PATH];
4291 static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4292 static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4294 if(!pSHCreateShellItem)
4296 skip("SHCreateShellItem missing.\n");
4297 return;
4300 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
4301 ok(hr == S_OK, "Got 0x%08x\n", hr);
4302 if(SUCCEEDED(hr))
4304 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
4305 ok(hr == S_OK, "Got 0x%08x\n", hr);
4306 pILFree(pidl_desktop);
4308 if(FAILED(hr))
4310 skip("Skipping tests.\n");
4311 return;
4314 if(0)
4316 /* Crashes on native (Win 7) */
4317 IShellItem_GetAttributes(psi, 0, NULL);
4320 /* Test GetAttributes on the desktop folder. */
4321 sfgao = 0xdeadbeef;
4322 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
4323 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
4324 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
4326 IShellItem_Release(psi);
4328 CreateFilesFolders();
4330 SHGetDesktopFolder(&pdesktopsf);
4332 GetCurrentDirectoryW(MAX_PATH, curdirW);
4333 myPathAddBackslashW(curdirW);
4335 lstrcpyW(buf, curdirW);
4336 lstrcatW(buf, testdir1W);
4337 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4338 ok(hr == S_OK, "got 0x%08x\n", hr);
4339 hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_folder1);
4340 ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4341 pILFree(pidl);
4343 lstrcpyW(buf, curdirW);
4344 lstrcatW(buf, testfile1W);
4345 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4346 ok(hr == S_OK, "got 0x%08x\n", hr);
4347 hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_file1);
4348 ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4349 pILFree(pidl);
4351 IShellFolder_Release(pdesktopsf);
4353 sfgao = 0xdeadbeef;
4354 hr = IShellItem_GetAttributes(psi_folder1, 0, &sfgao);
4355 ok(hr == S_OK, "Got 0x%08x\n", hr);
4356 ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4358 sfgao = 0xdeadbeef;
4359 hr = IShellItem_GetAttributes(psi_folder1, SFGAO_FOLDER, &sfgao);
4360 ok(hr == S_OK, "Got 0x%08x\n", hr);
4361 ok(sfgao == SFGAO_FOLDER, "Got 0x%08x\n", sfgao);
4363 sfgao = 0xdeadbeef;
4364 hr = IShellItem_GetAttributes(psi_file1, SFGAO_FOLDER, &sfgao);
4365 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
4366 ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4368 IShellItem_Release(psi_folder1);
4369 IShellItem_Release(psi_file1);
4371 Cleanup();
4374 static void test_ShellItemArrayGetAttributes(void)
4376 IShellItemArray *psia_files, *psia_folders1, *psia_folders2, *psia_all;
4377 IShellFolder *pdesktopsf;
4378 LPCITEMIDLIST pidl_array[5];
4379 SFGAOF attr;
4380 HRESULT hr;
4381 WCHAR curdirW[MAX_PATH];
4382 WCHAR buf[MAX_PATH];
4383 UINT i;
4384 static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4385 static const WCHAR testdir2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','2',0};
4386 static const WCHAR testdir3W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','3',0};
4387 static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4388 static const WCHAR testfile2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','2','.','t','x','t',0};
4389 static const WCHAR *testfilesW[5] = { testdir1W, testdir2W, testdir3W, testfile1W, testfile2W };
4391 if(!pSHCreateShellItemArrayFromShellItem)
4393 win_skip("No SHCreateShellItemArrayFromShellItem, skipping test...\n");
4394 return;
4397 CreateFilesFolders();
4398 CreateDirectoryA(".\\testdir\\testdir3", NULL);
4400 SHGetDesktopFolder(&pdesktopsf);
4402 GetCurrentDirectoryW(MAX_PATH, curdirW);
4403 myPathAddBackslashW(curdirW);
4405 for(i = 0; i < 5; i++)
4407 lstrcpyW(buf, curdirW);
4408 lstrcatW(buf, testfilesW[i]);
4409 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, (LPITEMIDLIST*)&pidl_array[i], NULL);
4410 ok(hr == S_OK, "got 0x%08x\n", hr);
4412 IShellFolder_Release(pdesktopsf);
4414 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia_folders1);
4415 ok(hr == S_OK, "got 0x%08x\n", hr);
4416 hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[1], &psia_folders2);
4417 ok(hr == S_OK, "got 0x%08x\n", hr);
4418 hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[3], &psia_files);
4419 ok(hr == S_OK, "got 0x%08x\n", hr);
4420 hr = pSHCreateShellItemArrayFromIDLists(4, &pidl_array[1], &psia_all); /* All except the first */
4421 ok(hr == S_OK, "got 0x%08x\n", hr);
4423 for(i = 0; i < 5; i++)
4424 pILFree((LPITEMIDLIST)pidl_array[i]);
4426 /* [testfolder/, testfolder/testfolder2] seems to break in Vista */
4427 attr = 0xdeadbeef;
4428 hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4429 ok(hr == S_OK || broken(hr == E_UNEXPECTED) /* Vista */, "Got 0x%08x\n", hr);
4430 ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4431 attr = 0xdeadbeef;
4432 hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4433 ok(hr == S_OK || broken(hr == E_UNEXPECTED) /* Vista */, "Got 0x%08x\n", hr);
4434 ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4436 /* [testfolder/testfolder2, testfolder/testfolder3] works */
4437 attr = 0xdeadbeef;
4438 hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4439 ok(hr == S_OK, "Got 0x%08x\n", hr);
4440 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4441 attr = 0xdeadbeef;
4442 hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4443 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4444 ok(attr == 0, "Got 0x%08x\n", attr);
4445 attr = 0xdeadbeef;
4446 hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4447 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4448 ok(attr == 0, "Got 0x%08x\n", attr);
4449 attr = 0xdeadbeef;
4450 hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4451 ok(hr == S_OK, "Got 0x%08x\n", hr);
4452 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4453 attr = 0xdeadbeef;
4454 hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4455 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4456 ok(attr == 0, "Got 0x%08x\n", attr);
4457 attr = 0xdeadbeef;
4458 hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4459 ok(hr == S_OK, "Got 0x%08x\n", hr);
4460 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4462 IShellItemArray_Release(psia_folders1);
4463 IShellItemArray_Release(psia_folders2);
4464 IShellItemArray_Release(psia_files);
4465 IShellItemArray_Release(psia_all);
4467 RemoveDirectoryA(".\\testdir\\testdir3");
4468 Cleanup();
4471 static void test_SHParseDisplayName(void)
4473 LPITEMIDLIST pidl1, pidl2;
4474 IShellFolder *desktop;
4475 WCHAR dirW[MAX_PATH];
4476 WCHAR nameW[10];
4477 HRESULT hr;
4478 BOOL ret, is_wow64;
4480 if (!pSHParseDisplayName)
4482 win_skip("SHParseDisplayName isn't available\n");
4483 return;
4486 if (0)
4488 /* crashes on native */
4489 pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
4490 nameW[0] = 0;
4491 pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
4494 pidl1 = (LPITEMIDLIST)0xdeadbeef;
4495 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
4496 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
4497 hr == E_INVALIDARG, "failed %08x\n", hr);
4498 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
4500 /* dummy name */
4501 nameW[0] = 0;
4502 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
4503 ok(hr == S_OK, "failed %08x\n", hr);
4504 hr = SHGetDesktopFolder(&desktop);
4505 ok(hr == S_OK, "failed %08x\n", hr);
4506 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
4507 ok(hr == S_OK, "failed %08x\n", hr);
4508 ret = pILIsEqual(pidl1, pidl2);
4509 ok(ret == TRUE, "expected equal idls\n");
4510 pILFree(pidl1);
4511 pILFree(pidl2);
4513 /* with path */
4514 GetWindowsDirectoryW( dirW, MAX_PATH );
4516 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4517 ok(hr == S_OK, "failed %08x\n", hr);
4518 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
4519 ok(hr == S_OK, "failed %08x\n", hr);
4521 ret = pILIsEqual(pidl1, pidl2);
4522 ok(ret == TRUE, "expected equal idls\n");
4523 pILFree(pidl1);
4524 pILFree(pidl2);
4526 /* system32 is not redirected to syswow64 on WOW64 */
4527 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
4528 if (is_wow64 && pGetSystemWow64DirectoryW)
4530 UINT len;
4531 *dirW = 0;
4532 len = GetSystemDirectoryW(dirW, MAX_PATH);
4533 ok(len > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
4534 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4535 ok(hr == S_OK, "failed %08x\n", hr);
4536 *dirW = 0;
4537 len = pGetSystemWow64DirectoryW(dirW, MAX_PATH);
4538 ok(len > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
4539 hr = pSHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
4540 ok(hr == S_OK, "failed %08x\n", hr);
4541 ret = pILIsEqual(pidl1, pidl2);
4542 ok(ret == FALSE, "expected different idls\n");
4543 pILFree(pidl1);
4544 pILFree(pidl2);
4547 IShellFolder_Release(desktop);
4550 static void test_desktop_IPersist(void)
4552 IShellFolder *desktop;
4553 IPersist *persist;
4554 IPersistFolder2 *ppf2;
4555 CLSID clsid;
4556 HRESULT hr;
4558 hr = SHGetDesktopFolder(&desktop);
4559 ok(hr == S_OK, "failed %08x\n", hr);
4561 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
4562 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
4564 if (hr == S_OK)
4566 if (0)
4568 /* crashes on native */
4569 IPersist_GetClassID(persist, NULL);
4571 memset(&clsid, 0, sizeof(clsid));
4572 hr = IPersist_GetClassID(persist, &clsid);
4573 ok(hr == S_OK, "failed %08x\n", hr);
4574 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
4575 IPersist_Release(persist);
4578 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
4579 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
4580 if(SUCCEEDED(hr))
4582 IPersistFolder *ppf;
4583 LPITEMIDLIST pidl;
4584 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
4585 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
4586 if(SUCCEEDED(hr))
4587 IPersistFolder_Release(ppf);
4589 todo_wine {
4590 hr = IPersistFolder2_Initialize(ppf2, NULL);
4591 ok(hr == S_OK, "got %08x\n", hr);
4594 pidl = NULL;
4595 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
4596 ok(hr == S_OK, "got %08x\n", hr);
4597 ok(pidl != NULL, "pidl was NULL.\n");
4598 if(SUCCEEDED(hr)) pILFree(pidl);
4600 IPersistFolder2_Release(ppf2);
4603 IShellFolder_Release(desktop);
4606 static void test_GetUIObject(void)
4608 IShellFolder *psf_desktop;
4609 IContextMenu *pcm;
4610 LPITEMIDLIST pidl;
4611 HRESULT hr;
4612 WCHAR path[MAX_PATH];
4613 const WCHAR filename[] =
4614 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4616 if(!pSHBindToParent)
4618 win_skip("SHBindToParent missing.\n");
4619 return;
4622 GetCurrentDirectoryW(MAX_PATH, path);
4623 if (!path[0])
4625 skip("GetCurrentDirectoryW returned an empty string.\n");
4626 return;
4628 lstrcatW(path, filename);
4629 SHGetDesktopFolder(&psf_desktop);
4631 CreateFilesFolders();
4633 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
4634 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
4635 if(SUCCEEDED(hr))
4637 IShellFolder *psf;
4638 LPCITEMIDLIST pidl_child;
4639 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
4640 ok(hr == S_OK, "Got 0x%08x\n", hr);
4641 if(SUCCEEDED(hr))
4643 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, &pidl_child, &IID_IContextMenu, NULL,
4644 (void**)&pcm);
4645 ok(hr == S_OK, "Got 0x%08x\n", hr);
4646 if(SUCCEEDED(hr))
4648 const int baseItem = 0x40;
4649 HMENU hmenu = CreatePopupMenu();
4650 INT max_id, max_id_check;
4651 UINT count, i;
4652 const int id_upper_limit = 32767;
4653 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, baseItem, id_upper_limit, CMF_NORMAL);
4654 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
4655 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
4656 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
4657 count = GetMenuItemCount(hmenu);
4658 ok(count, "Got %d\n", count);
4660 max_id_check = 0;
4661 for(i = 0; i < count; i++)
4663 MENUITEMINFOA mii;
4664 INT res;
4665 char buf[255], buf2[255];
4666 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
4667 mii.cbSize = sizeof(MENUITEMINFOA);
4668 mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
4669 mii.dwTypeData = buf2;
4670 mii.cch = sizeof(buf2);
4672 SetLastError(0);
4673 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
4674 ok(res, "Failed (last error: %d).\n", GetLastError());
4676 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
4677 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
4678 if(!(mii.fType & MFT_SEPARATOR))
4680 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
4681 hr = IContextMenu_GetCommandString(pcm, mii.wID - baseItem, GCS_VERBA, 0, buf, sizeof(buf));
4682 ok(SUCCEEDED(hr) || hr == E_NOTIMPL, "for id 0x%x got 0x%08x (menustr: %s)\n", mii.wID - baseItem, hr, mii.dwTypeData);
4683 if (SUCCEEDED(hr))
4684 trace("for id 0x%x got string %s (menu string: %s)\n", mii.wID - baseItem, buf, mii.dwTypeData);
4685 else if (hr == E_NOTIMPL)
4686 trace("for id 0x%x got E_NOTIMPL (menu string: %s)\n", mii.wID - baseItem, mii.dwTypeData);
4689 max_id_check -= baseItem;
4690 ok((max_id_check == max_id) ||
4691 (max_id_check == max_id-1) || /* Win 7 */
4692 (max_id_check == max_id-2), /* Win 8 */
4693 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
4695 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
4697 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
4699 CMINVOKECOMMANDINFO cmi;
4700 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
4701 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
4703 /* Attempt to execute a nonexistent command */
4704 cmi.lpVerb = MAKEINTRESOURCEA(9999);
4705 hr = IContextMenu_InvokeCommand(pcm, &cmi);
4706 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
4708 cmi.lpVerb = "foobar_wine_test";
4709 hr = IContextMenu_InvokeCommand(pcm, &cmi);
4710 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
4711 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
4712 "Got 0x%08x\n", hr);
4714 #undef is_win2k
4716 DestroyMenu(hmenu);
4717 IContextMenu_Release(pcm);
4719 IShellFolder_Release(psf);
4721 if(pILFree) pILFree(pidl);
4724 IShellFolder_Release(psf_desktop);
4725 Cleanup();
4728 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
4729 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
4731 LPCITEMIDLIST child;
4732 IShellFolder *parent;
4733 STRRET filename;
4734 HRESULT hr;
4736 if(!pSHBindToParent){
4737 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
4738 if(path)
4739 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
4740 else
4741 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4742 return;
4745 if(path){
4746 if(!pidl){
4747 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
4748 return;
4751 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
4752 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
4753 if(FAILED(hr))
4754 return;
4756 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
4757 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
4758 if(FAILED(hr)){
4759 IShellFolder_Release(parent);
4760 return;
4763 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
4764 "Got unexpected string type: %d\n", filename.uType);
4765 if(filename.uType == STRRET_WSTR){
4766 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
4767 "didn't get expected path (%s), instead: %s\n",
4768 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
4769 SHFree(U(filename).pOleStr);
4770 }else if(filename.uType == STRRET_CSTR){
4771 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
4772 "didn't get expected path (%s), instead: %s\n",
4773 wine_dbgstr_w(path), U(filename).cStr);
4776 IShellFolder_Release(parent);
4777 }else
4778 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4781 static void test_SHSimpleIDListFromPath(void)
4783 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4784 const CHAR adirA[] = "C:\\sidlfpdir";
4785 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4787 LPITEMIDLIST pidl = NULL;
4789 if(!pSHSimpleIDListFromPathAW){
4790 win_skip("SHSimpleIDListFromPathAW not available\n");
4791 return;
4794 br = CreateDirectoryA(adirA, NULL);
4795 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4797 if(is_unicode)
4798 pidl = pSHSimpleIDListFromPathAW(adirW);
4799 else
4800 pidl = pSHSimpleIDListFromPathAW(adirA);
4801 verify_pidl(pidl, adirW);
4802 pILFree(pidl);
4804 br = RemoveDirectoryA(adirA);
4805 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4807 if(is_unicode)
4808 pidl = pSHSimpleIDListFromPathAW(adirW);
4809 else
4810 pidl = pSHSimpleIDListFromPathAW(adirA);
4811 verify_pidl(pidl, adirW);
4812 pILFree(pidl);
4815 /* IFileSystemBindData impl */
4816 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4817 REFIID riid, void **ppv)
4819 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4820 IsEqualIID(riid, &IID_IUnknown)){
4821 *ppv = fsbd;
4822 return S_OK;
4824 return E_NOINTERFACE;
4827 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4829 return 2;
4832 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4834 return 1;
4837 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4838 const WIN32_FIND_DATAW *pfd)
4840 ok(0, "SetFindData called\n");
4841 return E_NOTIMPL;
4844 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4845 WIN32_FIND_DATAW *pfd)
4847 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4848 return S_OK;
4851 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4852 WIN32_FIND_DATAW *pfd)
4854 memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4855 return S_OK;
4858 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4859 WIN32_FIND_DATAW *pfd)
4861 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4862 *pfd->cFileName = 'a';
4863 *pfd->cAlternateFileName = 'a';
4864 return S_OK;
4867 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4868 WIN32_FIND_DATAW *pfd)
4870 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4871 HANDLE handle = FindFirstFileW(adirW, pfd);
4872 FindClose(handle);
4873 return S_OK;
4876 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4877 WIN32_FIND_DATAW *pfd)
4879 return E_FAIL;
4882 static IFileSystemBindDataVtbl fsbdVtbl = {
4883 fsbd_QueryInterface,
4884 fsbd_AddRef,
4885 fsbd_Release,
4886 fsbd_SetFindData,
4887 NULL
4890 static IFileSystemBindData fsbd = { &fsbdVtbl };
4892 static void test_ParseDisplayNamePBC(void)
4894 WCHAR wFileSystemBindData[] =
4895 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4896 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4897 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4898 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4899 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4901 IShellFolder *psf;
4902 IBindCtx *pbc;
4903 HRESULT hres;
4904 ITEMIDLIST *pidl;
4906 /* Check if we support WCHAR functions */
4907 SetLastError(0xdeadbeef);
4908 lstrcmpiW(adirW, adirW);
4909 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4910 win_skip("Most W-calls are not implemented\n");
4911 return;
4914 hres = SHGetDesktopFolder(&psf);
4915 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4916 if(FAILED(hres)){
4917 win_skip("Failed to get IShellFolder, can't run tests\n");
4918 return;
4921 /* fails on unknown dir with no IBindCtx */
4922 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4923 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4924 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4925 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4926 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4927 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4928 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4929 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4930 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4932 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4933 hres = CreateBindCtx(0, &pbc);
4934 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4936 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4937 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4938 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4939 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4940 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4941 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4942 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4943 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4944 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4946 /* unknown dir with IBindCtx with IFileSystemBindData */
4947 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4948 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4950 /* return E_FAIL from GetFindData */
4951 pidl = (ITEMIDLIST*)0xdeadbeef;
4952 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4953 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4954 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4955 "ParseDisplayName failed: 0x%08x\n", hres);
4956 if(SUCCEEDED(hres)){
4957 verify_pidl(pidl, adirW);
4958 ILFree(pidl);
4961 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4962 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4963 "ParseDisplayName failed: 0x%08x\n", hres);
4964 if(SUCCEEDED(hres)){
4965 verify_pidl(pidl, afileW);
4966 ILFree(pidl);
4969 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4970 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4971 "ParseDisplayName failed: 0x%08x\n", hres);
4972 if(SUCCEEDED(hres)){
4973 verify_pidl(pidl, afile2W);
4974 ILFree(pidl);
4977 /* set FIND_DATA struct to NULLs */
4978 pidl = (ITEMIDLIST*)0xdeadbeef;
4979 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4980 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4981 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4982 "ParseDisplayName failed: 0x%08x\n", hres);
4983 if(SUCCEEDED(hres)){
4984 verify_pidl(pidl, adirW);
4985 ILFree(pidl);
4988 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4989 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4990 "ParseDisplayName failed: 0x%08x\n", hres);
4991 if(SUCCEEDED(hres)){
4992 verify_pidl(pidl, afileW);
4993 ILFree(pidl);
4996 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4997 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4998 "ParseDisplayName failed: 0x%08x\n", hres);
4999 if(SUCCEEDED(hres)){
5000 verify_pidl(pidl, afile2W);
5001 ILFree(pidl);
5004 /* set FIND_DATA struct to junk */
5005 pidl = (ITEMIDLIST*)0xdeadbeef;
5006 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
5007 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
5008 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5009 "ParseDisplayName failed: 0x%08x\n", hres);
5010 if(SUCCEEDED(hres)){
5011 verify_pidl(pidl, adirW);
5012 ILFree(pidl);
5015 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
5016 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5017 "ParseDisplayName failed: 0x%08x\n", hres);
5018 if(SUCCEEDED(hres)){
5019 verify_pidl(pidl, afileW);
5020 ILFree(pidl);
5023 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
5024 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5025 "ParseDisplayName failed: 0x%08x\n", hres);
5026 if(SUCCEEDED(hres)){
5027 verify_pidl(pidl, afile2W);
5028 ILFree(pidl);
5031 /* set FIND_DATA struct to invalid data */
5032 pidl = (ITEMIDLIST*)0xdeadbeef;
5033 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
5034 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
5035 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5036 "ParseDisplayName failed: 0x%08x\n", hres);
5037 if(SUCCEEDED(hres)){
5038 verify_pidl(pidl, adirW);
5039 ILFree(pidl);
5042 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
5043 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5044 "ParseDisplayName failed: 0x%08x\n", hres);
5045 if(SUCCEEDED(hres)){
5046 verify_pidl(pidl, afileW);
5047 ILFree(pidl);
5050 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
5051 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5052 "ParseDisplayName failed: 0x%08x\n", hres);
5053 if(SUCCEEDED(hres)){
5054 verify_pidl(pidl, afile2W);
5055 ILFree(pidl);
5058 /* set FIND_DATA struct to valid data */
5059 pidl = (ITEMIDLIST*)0xdeadbeef;
5060 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
5061 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
5062 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5063 "ParseDisplayName failed: 0x%08x\n", hres);
5064 if(SUCCEEDED(hres)){
5065 verify_pidl(pidl, adirW);
5066 ILFree(pidl);
5069 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
5070 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5071 "ParseDisplayName failed: 0x%08x\n", hres);
5072 if(SUCCEEDED(hres)){
5073 verify_pidl(pidl, afileW);
5074 ILFree(pidl);
5077 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
5078 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
5079 "ParseDisplayName failed: 0x%08x\n", hres);
5080 if(SUCCEEDED(hres)){
5081 verify_pidl(pidl, afile2W);
5082 ILFree(pidl);
5085 IBindCtx_Release(pbc);
5086 IShellFolder_Release(psf);
5089 static const CHAR testwindow_class[] = "testwindow";
5090 #define WM_USER_NOTIFY (WM_APP+1)
5092 struct ChNotifyTest {
5093 const char id[256];
5094 const UINT notify_count;
5095 UINT missing_events;
5096 UINT signal;
5097 const char path_1[256];
5098 const char path_2[256];
5099 } chnotify_tests[] = {
5100 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
5101 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
5102 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
5105 struct ChNotifyTest *exp_data;
5106 BOOL test_new_delivery_flag;
5108 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5110 LONG signal = (LONG)lparam;
5112 switch(msg){
5113 case WM_USER_NOTIFY:
5114 if(exp_data->missing_events > 0) {
5115 WCHAR *path1, *path2;
5116 LPITEMIDLIST *pidls = (LPITEMIDLIST*)wparam;
5117 HANDLE hLock = NULL;
5119 if(test_new_delivery_flag) {
5120 hLock = SHChangeNotification_Lock((HANDLE)wparam, lparam, &pidls, &signal);
5121 ok(hLock != NULL, "SHChangeNotification_Lock returned NULL\n");
5124 ok(exp_data->signal == signal,
5125 "%s: expected notification type %x, got: %x\n",
5126 exp_data->id, exp_data->signal, signal);
5128 trace("verifying pidls for: %s\n", exp_data->id);
5129 path1 = make_wstr(exp_data->path_1);
5130 path2 = make_wstr(exp_data->path_2);
5131 verify_pidl(pidls[0], path1);
5132 verify_pidl(pidls[1], path2);
5133 HeapFree(GetProcessHeap(), 0, path1);
5134 HeapFree(GetProcessHeap(), 0, path2);
5136 exp_data->missing_events--;
5138 if(test_new_delivery_flag)
5139 SHChangeNotification_Unlock(hLock);
5140 }else
5141 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
5142 return 0;
5144 return DefWindowProcA(hwnd, msg, wparam, lparam);
5147 static void register_testwindow_class(void)
5149 WNDCLASSEXA cls;
5150 ATOM ret;
5152 ZeroMemory(&cls, sizeof(cls));
5153 cls.cbSize = sizeof(cls);
5154 cls.style = 0;
5155 cls.lpfnWndProc = testwindow_wndproc;
5156 cls.hInstance = GetModuleHandleA(NULL);
5157 cls.lpszClassName = testwindow_class;
5159 SetLastError(0);
5160 ret = RegisterClassExA(&cls);
5161 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
5164 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
5165 * have to poll repeatedly for the message to appear */
5166 static void do_events(void)
5168 int c = 0;
5169 while (exp_data->missing_events && (c++ < 10)){
5170 MSG msg;
5171 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
5172 TranslateMessage(&msg);
5173 DispatchMessageA(&msg);
5175 if(exp_data->missing_events)
5176 Sleep(500);
5178 trace("%s: took %d tries\n", exp_data->id, c);
5181 static void test_SHChangeNotify(BOOL test_new_delivery)
5183 HWND wnd;
5184 ULONG notifyID, i;
5185 HRESULT hr;
5186 BOOL br, has_unicode;
5187 SHChangeNotifyEntry entries[1];
5188 const CHAR root_dirA[] = "C:\\shell32_cn_test";
5189 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
5191 trace("SHChangeNotify tests (%x)\n", test_new_delivery);
5193 CreateDirectoryW(NULL, NULL);
5194 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
5196 test_new_delivery_flag = test_new_delivery;
5197 if(!test_new_delivery)
5198 register_testwindow_class();
5200 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
5201 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
5202 NULL, NULL, GetModuleHandleA(NULL), 0);
5203 ok(wnd != NULL, "Failed to make a window\n");
5205 br = CreateDirectoryA(root_dirA, NULL);
5206 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
5208 entries[0].pidl = NULL;
5209 if(has_unicode)
5210 hr = pSHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
5211 else
5212 hr = pSHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
5213 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
5214 entries[0].fRecursive = TRUE;
5216 notifyID = SHChangeNotifyRegister(wnd, !test_new_delivery ? SHCNRF_ShellLevel : SHCNRF_ShellLevel|SHCNRF_NewDelivery,
5217 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
5218 ok(notifyID != 0, "Failed to register a window for change notifications\n");
5220 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
5221 exp_data = chnotify_tests + i;
5223 exp_data->missing_events = exp_data->notify_count;
5224 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
5225 exp_data->path_1[0] ? exp_data->path_1 : NULL,
5226 exp_data->path_2[0] ? exp_data->path_2 : NULL);
5227 do_events();
5228 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
5230 if(has_unicode){
5231 WCHAR *path1, *path2;
5233 path1 = make_wstr(exp_data->path_1);
5234 path2 = make_wstr(exp_data->path_2);
5236 exp_data->missing_events = exp_data->notify_count;
5237 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
5238 do_events();
5239 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
5241 HeapFree(GetProcessHeap(), 0, path1);
5242 HeapFree(GetProcessHeap(), 0, path2);
5246 SHChangeNotifyDeregister(notifyID);
5247 DestroyWindow(wnd);
5249 ILFree((LPITEMIDLIST)entries[0].pidl);
5250 br = RemoveDirectoryA(root_dirA);
5251 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
5254 static void test_SHCreateDefaultContextMenu(void)
5256 HKEY keys[16];
5257 WCHAR path[MAX_PATH];
5258 IShellFolder *desktop,*folder;
5259 IPersistFolder2 *persist;
5260 IContextMenu *cmenu;
5261 LONG status;
5262 LPITEMIDLIST pidlFolder, pidl_child, pidl;
5263 DEFCONTEXTMENU cminfo;
5264 HRESULT hr;
5265 UINT i;
5266 const WCHAR filename[] =
5267 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
5268 if(!pSHCreateDefaultContextMenu)
5270 win_skip("SHCreateDefaultContextMenu missing.\n");
5271 return;
5274 if(!pSHBindToParent)
5276 skip("SHBindToParent missing.\n");
5277 return;
5280 GetCurrentDirectoryW(MAX_PATH, path);
5281 if (!path[0])
5283 skip("GetCurrentDirectoryW returned an empty string.\n");
5284 return;
5286 lstrcatW(path, filename);
5287 SHGetDesktopFolder(&desktop);
5289 CreateFilesFolders();
5291 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &pidl, 0);
5292 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
5293 if(SUCCEEDED(hr))
5296 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&folder, (LPCITEMIDLIST*)&pidl_child);
5297 ok(hr == S_OK, "Got 0x%08x\n", hr);
5299 IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
5300 IPersistFolder2_GetCurFolder(persist,&pidlFolder);
5301 IPersistFolder2_Release(persist);
5302 if(SUCCEEDED(hr))
5305 cminfo.hwnd=NULL;
5306 cminfo.pcmcb=NULL;
5307 cminfo.psf=folder;
5308 cminfo.pidlFolder=NULL;
5309 cminfo.apidl=(LPCITEMIDLIST*)&pidl_child;
5310 cminfo.cidl=1;
5311 cminfo.aKeys=NULL;
5312 cminfo.cKeys=0;
5313 cminfo.punkAssociationInfo=NULL;
5314 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5315 ok(hr==S_OK,"Got 0x%08x\n", hr);
5316 IContextMenu_Release(cmenu);
5317 cminfo.pidlFolder=pidlFolder;
5318 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5319 ok(hr==S_OK,"Got 0x%08x\n", hr);
5320 IContextMenu_Release(cmenu);
5321 status = RegOpenKeyExA(HKEY_CLASSES_ROOT,"*",0,KEY_READ,keys);
5322 if(status==ERROR_SUCCESS){
5323 for(i=1;i<16;i++)
5324 keys[i]=keys[0];
5325 cminfo.aKeys=keys;
5326 cminfo.cKeys=16;
5327 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5328 RegCloseKey(keys[0]);
5329 ok(hr==S_OK,"Got 0x%08x\n", hr);
5330 IContextMenu_Release(cmenu);
5333 ILFree(pidlFolder);
5334 IShellFolder_Release(folder);
5336 IShellFolder_Release(desktop);
5337 ILFree(pidl);
5338 Cleanup();
5341 static void test_DataObject(void)
5343 IShellFolder *desktop;
5344 IDataObject *data_obj;
5345 HRESULT hres;
5346 IEnumIDList *peidl;
5347 LPITEMIDLIST apidl;
5348 FORMATETC fmt;
5349 DWORD cf_shellidlist;
5350 STGMEDIUM medium;
5352 SHGetDesktopFolder(&desktop);
5354 hres = IShellFolder_EnumObjects(desktop, NULL,
5355 SHCONTF_NONFOLDERS|SHCONTF_FOLDERS|SHCONTF_INCLUDEHIDDEN, &peidl);
5356 ok(hres == S_OK, "got %x\n", hres);
5358 if(IEnumIDList_Next(peidl, 1, &apidl, NULL) != S_OK) {
5359 skip("no files on desktop - skipping GetDataObject tests\n");
5360 IEnumIDList_Release(peidl);
5361 IShellFolder_Release(desktop);
5362 return;
5364 IEnumIDList_Release(peidl);
5366 hres = IShellFolder_GetUIObjectOf(desktop, NULL, 1, (LPCITEMIDLIST*)&apidl,
5367 &IID_IDataObject, NULL, (void**)&data_obj);
5368 ok(hres == S_OK, "got %x\n", hres);
5369 pILFree(apidl);
5370 IShellFolder_Release(desktop);
5372 cf_shellidlist = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
5373 fmt.cfFormat = cf_shellidlist;
5374 fmt.ptd = NULL;
5375 fmt.dwAspect = DVASPECT_CONTENT;
5376 fmt.lindex = -1;
5377 fmt.tymed = TYMED_HGLOBAL;
5378 hres = IDataObject_QueryGetData(data_obj, &fmt);
5379 ok(hres == S_OK, "got %x\n", hres);
5381 fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5382 hres = IDataObject_QueryGetData(data_obj, &fmt);
5383 ok(hres == S_OK, "got %x\n", hres);
5385 fmt.tymed = TYMED_ISTREAM;
5386 hres = IDataObject_QueryGetData(data_obj, &fmt);
5387 todo_wine ok(hres == S_FALSE, "got %x\n", hres);
5389 fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5390 hres = IDataObject_GetData(data_obj, &fmt, &medium);
5391 ok(hres == S_OK, "got %x\n", hres);
5392 ok(medium.tymed == TYMED_HGLOBAL, "medium.tymed = %x\n", medium.tymed);
5393 ReleaseStgMedium(&medium);
5395 IDataObject_Release(data_obj);
5398 START_TEST(shlfolder)
5400 init_function_pointers();
5401 /* if OleInitialize doesn't get called, ParseDisplayName returns
5402 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
5403 OleInitialize(NULL);
5405 test_ParseDisplayName();
5406 test_SHParseDisplayName();
5407 test_BindToObject();
5408 test_EnumObjects_and_CompareIDs();
5409 test_GetDisplayName();
5410 test_GetAttributesOf();
5411 test_SHGetPathFromIDList();
5412 test_CallForAttributes();
5413 test_FolderShortcut();
5414 test_ITEMIDLIST_format();
5415 test_SHGetFolderPathA();
5416 test_SHGetFolderPathAndSubDirA();
5417 test_LocalizedNames();
5418 test_SHCreateShellItem();
5419 test_SHCreateShellItemArray();
5420 test_ShellItemArrayEnumItems();
5421 test_desktop_IPersist();
5422 test_GetUIObject();
5423 test_SHSimpleIDListFromPath();
5424 test_ParseDisplayNamePBC();
5425 test_SHGetNameFromIDList();
5426 test_SHGetItemFromDataObject();
5427 test_SHGetIDListFromObject();
5428 test_SHGetItemFromObject();
5429 test_ShellItemCompare();
5430 test_SHChangeNotify(FALSE);
5431 test_SHChangeNotify(TRUE);
5432 test_ShellItemBindToHandler();
5433 test_ShellItemGetAttributes();
5434 test_ShellItemArrayGetAttributes();
5435 test_SHCreateDefaultContextMenu();
5436 test_DataObject();
5438 OleUninitialize();