shell32/tests: Drop shell folder test workarounds for Windows <= 2000.
[wine.git] / dlls / shell32 / tests / shlfolder.c
blob40ba378cc1a286250073e512f2640c743b93d794
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 *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
49 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
50 static HRESULT (WINAPI *pSHCreateItemFromRelativeName)(IShellItem*,PCWSTR,IBindCtx*,REFIID,void**);
51 static HRESULT (WINAPI *pSHCreateItemInKnownFolder)(REFKNOWNFOLDERID,DWORD,PCWSTR,REFIID,void **);
52 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
53 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
54 static HRESULT (WINAPI *pSHCreateShellItemArrayFromIDLists)(UINT, PCIDLIST_ABSOLUTE*, IShellItemArray**);
55 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
56 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
57 static HRESULT (WINAPI *pSHGetKnownFolderPath)(REFKNOWNFOLDERID,DWORD,HANDLE,PWSTR*);
58 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
59 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
60 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
61 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
62 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
63 static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
64 static BOOL (WINAPI *pSHGetPathFromIDListEx)(PCIDLIST_ABSOLUTE,WCHAR*,DWORD,GPFIDL_FLAGS);
66 static WCHAR *make_wstr(const char *str)
68 WCHAR *ret;
69 int len;
71 if (!str || !str[0])
72 return NULL;
74 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
75 if(!len || len < 0)
76 return NULL;
78 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
79 if(!ret)
80 return NULL;
82 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
83 return ret;
86 static int strcmp_wa(LPCWSTR strw, const char *stra)
88 CHAR buf[512];
89 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
90 return lstrcmpA(stra, buf);
93 static void init_function_pointers(void)
95 HMODULE hmod;
96 HRESULT hr;
97 void *ptr;
99 hmod = GetModuleHandleA("shell32.dll");
101 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
102 MAKEFUNC(SHCreateItemFromIDList);
103 MAKEFUNC(SHCreateItemFromParsingName);
104 MAKEFUNC(SHCreateItemFromRelativeName);
105 MAKEFUNC(SHCreateItemInKnownFolder);
106 MAKEFUNC(SHCreateShellItem);
107 MAKEFUNC(SHCreateShellItemArray);
108 MAKEFUNC(SHCreateShellItemArrayFromIDLists);
109 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
110 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
111 MAKEFUNC(SHGetKnownFolderPath);
112 MAKEFUNC(SHGetNameFromIDList);
113 MAKEFUNC(SHGetItemFromDataObject);
114 MAKEFUNC(SHGetIDListFromObject);
115 MAKEFUNC(SHGetItemFromObject);
116 MAKEFUNC(SHCreateDefaultContextMenu);
117 MAKEFUNC(SHGetPathFromIDListEx);
118 #undef MAKEFUNC
120 /* test named exports */
121 ptr = GetProcAddress(hmod, "ILFree");
122 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
123 if (ptr)
125 #define TESTNAMED(f) \
126 ptr = (void*)GetProcAddress(hmod, #f); \
127 ok(ptr != 0, "expected named export for " #f "\n");
129 TESTNAMED(ILAppendID);
130 TESTNAMED(ILClone);
131 TESTNAMED(ILCloneFirst);
132 TESTNAMED(ILCombine);
133 TESTNAMED(ILCreateFromPath);
134 TESTNAMED(ILCreateFromPathA);
135 TESTNAMED(ILCreateFromPathW);
136 TESTNAMED(ILFindChild);
137 TESTNAMED(ILFindLastID);
138 TESTNAMED(ILGetNext);
139 TESTNAMED(ILGetSize);
140 TESTNAMED(ILIsEqual);
141 TESTNAMED(ILIsParent);
142 TESTNAMED(ILRemoveLastID);
143 TESTNAMED(ILSaveToStream);
144 #undef TESTNAMED
147 hmod = GetModuleHandleA("kernel32.dll");
148 pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
150 hr = SHGetMalloc(&ppM);
151 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
154 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
155 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
157 size_t iLen;
159 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
160 return NULL;
162 if (iLen)
164 lpszPath += iLen;
165 if (lpszPath[-1] != '\\')
167 *lpszPath++ = '\\';
168 *lpszPath = '\0';
171 return lpszPath;
174 static void test_ParseDisplayName(void)
176 HRESULT hr;
177 IShellFolder *IDesktopFolder;
178 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
179 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
180 static const char *cInetTestA = "http:\\yyy";
181 static const char *cInetTest2A = "xx:yyy";
182 DWORD res;
183 WCHAR cTestDirW [MAX_PATH] = {0};
184 ITEMIDLIST *newPIDL;
185 BOOL bRes;
187 hr = SHGetDesktopFolder(&IDesktopFolder);
188 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
189 if(hr != S_OK) return;
191 if (pSHCreateShellItem)
193 if (0)
195 /* null name and pidl, crashes on Windows 8 */
196 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL,
197 NULL, NULL, NULL, 0);
198 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
201 /* null name */
202 newPIDL = (ITEMIDLIST*)0xdeadbeef;
203 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
204 NULL, NULL, NULL, NULL, &newPIDL, 0);
205 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
206 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
208 else
209 win_skip("SHCreateShellItem requires XP SP1 or later\n");
211 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
212 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
213 todo_wine ok(hr == S_OK, "ParseDisplayName returned %08x, expected SUCCESS\n", hr);
214 if (hr == S_OK)
216 ok(ILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
217 "PT_IESPECIAL1, but is: %02x\n", ILFindLastID(newPIDL)->mkid.abID[0]);
218 IMalloc_Free(ppM, newPIDL);
221 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
222 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
223 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
224 todo_wine ok(hr == S_OK, "ParseDisplayName returned %08x, expected SUCCESS\n", hr);
225 if (hr == S_OK)
227 ok(ILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
228 "PT_IESPECIAL1, but is: %02x\n", ILFindLastID(newPIDL)->mkid.abID[0]);
229 IMalloc_Free(ppM, newPIDL);
232 res = GetFileAttributesA(cNonExistDir1A);
233 if(res != INVALID_FILE_ATTRIBUTES)
235 skip("Test directory unexpectedly exists\n");
236 goto finished;
239 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
240 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
241 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
242 ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
243 "ParseDisplayName returned %08x, expected 0x80070002\n", hr);
245 res = GetFileAttributesA(cNonExistDir2A);
246 if(res != INVALID_FILE_ATTRIBUTES)
248 skip("Test directory unexpectedly exists\n");
249 goto finished;
252 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
253 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
254 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
255 todo_wine ok(hr == E_INVALIDARG, "ParseDisplayName returned %08x, expected E_INVALIDARG\n", hr);
257 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
258 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
259 * out it doesn't. The magic seems to happen in the file dialogs, then. */
261 bRes = SHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
262 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
263 if (!bRes) goto finished;
265 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
266 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
267 if (hr != S_OK) goto finished;
269 ok(ILFindLastID(newPIDL)->mkid.abID[0] == 0x31,
270 "Last pidl should be of type PT_FOLDER, but is: %02x\n",
271 ILFindLastID(newPIDL)->mkid.abID[0]);
272 IMalloc_Free(ppM, newPIDL);
274 finished:
275 IShellFolder_Release(IDesktopFolder);
278 /* creates a file with the specified name for tests */
279 static void CreateTestFile(const CHAR *name)
281 HANDLE file;
282 DWORD written;
284 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
285 if (file != INVALID_HANDLE_VALUE)
287 WriteFile(file, name, strlen(name), &written, NULL);
288 WriteFile(file, "\n", strlen("\n"), &written, NULL);
289 CloseHandle(file);
294 /* initializes the tests */
295 static void CreateFilesFolders(void)
297 CreateDirectoryA(".\\testdir", NULL);
298 CreateDirectoryA(".\\testdir\\test.txt", NULL);
299 CreateTestFile (".\\testdir\\test1.txt ");
300 CreateTestFile (".\\testdir\\test2.txt ");
301 CreateTestFile (".\\testdir\\test3.txt ");
302 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
303 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
306 /* cleans after tests */
307 static void Cleanup(void)
309 DeleteFileA(".\\testdir\\test1.txt");
310 DeleteFileA(".\\testdir\\test2.txt");
311 DeleteFileA(".\\testdir\\test3.txt");
312 RemoveDirectoryA(".\\testdir\\test.txt");
313 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
314 RemoveDirectoryA(".\\testdir\\testdir2");
315 RemoveDirectoryA(".\\testdir");
319 /* perform test */
320 static void test_EnumObjects(IShellFolder *iFolder)
322 IEnumIDList *iEnumList;
323 LPITEMIDLIST newPIDL, idlArr[10];
324 ULONG NumPIDLs;
325 int i=0, j;
326 HRESULT hr;
328 static const WORD iResults [5][5] =
330 { 0,-1,-1,-1,-1},
331 { 1, 0,-1,-1,-1},
332 { 1, 1, 0,-1,-1},
333 { 1, 1, 1, 0,-1},
334 { 1, 1, 1, 1, 0}
337 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
338 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
339 static const ULONG attrs[5] =
341 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
342 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
343 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
344 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
345 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
347 static const ULONG full_attrs[5] =
349 SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
350 SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
351 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
352 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
353 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
356 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
357 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
359 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
360 * the filesystem shellfolders return S_OK even if less than 'celt' items are
361 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
362 * only ever returns a single entry per call. */
363 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
364 i += NumPIDLs;
365 ok (i == 5, "i: %d\n", i);
367 hr = IEnumIDList_Release(iEnumList);
368 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
370 /* Sort them first in case of wrong order from system */
371 for (i=0;i<5;i++) for (j=0;j<5;j++)
372 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
374 newPIDL = idlArr[i];
375 idlArr[i] = idlArr[j];
376 idlArr[j] = newPIDL;
379 for (i=0;i<5;i++) for (j=0;j<5;j++)
381 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
382 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
386 for (i = 0; i < 5; i++)
388 SFGAOF flags;
389 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
390 /* Native returns all flags no matter what we ask for */
391 flags = SFGAO_CANCOPY;
392 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
393 flags &= SFGAO_testfor;
394 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
395 ok(flags == (attrs[i]) ||
396 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
397 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
399 flags = SFGAO_testfor;
400 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
401 flags &= SFGAO_testfor;
402 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
403 ok(flags == attrs[i], "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
405 flags = ~0u;
406 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
407 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
408 ok((flags & ~(SFGAO_HASSUBFOLDER|SFGAO_COMPRESSED)) == full_attrs[i], "%d: got %08x expected %08x\n", i, flags, full_attrs[i]);
411 for (i=0;i<5;i++)
412 IMalloc_Free(ppM, idlArr[i]);
415 static void test_BindToObject(void)
417 HRESULT hr;
418 UINT cChars;
419 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
420 SHITEMID emptyitem = { 0, { 0 } };
421 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
422 WCHAR wszSystemDir[MAX_PATH];
423 char szSystemDir[MAX_PATH];
424 char buf[MAX_PATH];
425 WCHAR path[MAX_PATH];
426 CHAR pathA[MAX_PATH];
427 HANDLE hfile;
428 WCHAR wszMyComputer[] = {
429 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
430 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
431 static const CHAR filename_html[] = "winetest.html";
432 static const CHAR filename_txt[] = "winetest.txt";
433 static const CHAR filename_foo[] = "winetest.foo";
435 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
436 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
438 hr = SHGetDesktopFolder(&psfDesktop);
439 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
440 if (hr != S_OK) return;
442 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
443 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
445 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
446 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
448 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
449 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
450 if (hr != S_OK) {
451 IShellFolder_Release(psfDesktop);
452 return;
455 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
456 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
457 IShellFolder_Release(psfDesktop);
458 IMalloc_Free(ppM, pidlMyComputer);
459 if (hr != S_OK) return;
461 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
462 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
464 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
465 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
467 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
468 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
469 if (cChars == 0 || cChars >= MAX_PATH) {
470 IShellFolder_Release(psfMyComputer);
471 return;
473 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
475 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
476 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
477 if (hr != S_OK) {
478 IShellFolder_Release(psfMyComputer);
479 return;
482 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
483 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
484 IShellFolder_Release(psfMyComputer);
485 IMalloc_Free(ppM, pidlSystemDir);
486 if (hr != S_OK) return;
488 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
489 ok (hr == E_INVALIDARG,
490 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
492 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
493 ok (hr == E_INVALIDARG,
494 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
496 IShellFolder_Release(psfSystemDir);
498 cChars = GetCurrentDirectoryA(MAX_PATH, buf);
499 if(!cChars)
501 skip("Failed to get current directory, skipping tests.\n");
502 return;
504 if(buf[cChars-1] != '\\') lstrcatA(buf, "\\");
506 SHGetDesktopFolder(&psfDesktop);
508 /* Attempt BindToObject on files. */
510 /* .html */
511 lstrcpyA(pathA, buf);
512 lstrcatA(pathA, filename_html);
513 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
514 if(hfile != INVALID_HANDLE_VALUE)
516 CloseHandle(hfile);
517 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
518 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
519 ok(hr == S_OK, "Got 0x%08x\n", hr);
520 if(SUCCEEDED(hr))
522 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
523 ok(hr == S_OK ||
524 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
525 "Got 0x%08x\n", hr);
526 if(SUCCEEDED(hr))
528 IPersist *pp;
529 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
530 ok(hr == S_OK, "Got 0x%08x\n", hr);
531 if(SUCCEEDED(hr))
533 CLSID id;
534 hr = IPersist_GetClassID(pp, &id);
535 ok(hr == S_OK, "Got 0x%08x\n", hr);
536 ok(IsEqualIID(&id, &CLSID_ShellDocObjView), "Unexpected classid %s\n", wine_dbgstr_guid(&id));
537 IPersist_Release(pp);
540 IShellFolder_Release(psfChild);
542 ILFree(pidl);
544 DeleteFileA(pathA);
546 else
547 win_skip("Failed to create .html testfile.\n");
549 /* .txt */
550 lstrcpyA(pathA, buf);
551 lstrcatA(pathA, filename_txt);
552 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
553 if(hfile != INVALID_HANDLE_VALUE)
555 CloseHandle(hfile);
556 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
557 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
558 ok(hr == S_OK, "Got 0x%08x\n", hr);
559 if(SUCCEEDED(hr))
561 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
562 ok(hr == E_FAIL || /* Vista+ */
563 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
564 "Got 0x%08x\n", hr);
565 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
566 ILFree(pidl);
568 DeleteFileA(pathA);
570 else
571 win_skip("Failed to create .txt testfile.\n");
573 /* .foo */
574 lstrcpyA(pathA, buf);
575 lstrcatA(pathA, filename_foo);
576 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
577 if(hfile != INVALID_HANDLE_VALUE)
579 CloseHandle(hfile);
580 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
581 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
582 ok(hr == S_OK, "Got 0x%08x\n", hr);
583 if(SUCCEEDED(hr))
585 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
586 ok(hr == E_FAIL || /* Vista+ */
587 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
588 "Got 0x%08x\n", hr);
589 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
590 ILFree(pidl);
592 DeleteFileA(pathA);
594 else
595 win_skip("Failed to create .foo testfile.\n");
597 /* And on the desktop */
598 SHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
599 lstrcatA(pathA, "\\");
600 lstrcatA(pathA, filename_html);
601 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
603 CloseHandle(hfile);
604 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
605 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
606 ok(hr == S_OK, "Got 0x%08x\n", hr);
608 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void **)&psfChild);
609 ok(hr == S_OK ||
610 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
611 "Got 0x%08x\n", hr);
612 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
613 ILFree(pidl);
614 if(!DeleteFileA(pathA))
615 trace("Failed to delete: %d\n", GetLastError());
617 SHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
618 lstrcatA(pathA, "\\");
619 lstrcatA(pathA, filename_foo);
620 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
622 CloseHandle(hfile);
623 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
624 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
625 ok(hr == S_OK, "Got 0x%08x\n", hr);
627 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void **)&psfChild);
628 ok(hr == E_FAIL || /* Vista+ */
629 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
630 "Got 0x%08x\n", hr);
631 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
632 ILFree(pidl);
633 DeleteFileA(pathA);
635 IShellFolder_Release(psfDesktop);
638 static void test_GetDisplayName(void)
640 BOOL result;
641 HRESULT hr;
642 HANDLE hTestFile;
643 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
644 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
645 DWORD attr;
646 STRRET strret;
647 LPSHELLFOLDER psfDesktop, psfPersonal;
648 IUnknown *psfFile;
649 SHITEMID emptyitem = { 0, { 0 } };
650 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
651 LPCITEMIDLIST pidlLast;
652 static const CHAR szFileName[] = "winetest.foo";
653 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
654 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
656 /* It's ok to use this fixed path. Call will fail anyway. */
657 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
658 LPITEMIDLIST pidlNew;
660 /* I'm trying to figure if there is a functional difference between calling
661 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
662 * binding to the shellfolder. One thing I thought of was that perhaps
663 * SHGetPathFromIDListW would be able to get the path to a file, which does
664 * not exist anymore, while the other method wouldn't. It turns out there's
665 * no functional difference in this respect.
668 /* First creating a directory in MyDocuments and a file in this directory. */
669 result = SHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
670 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
671 if (!result) return;
673 /* Use ANSI file functions so this works on Windows 9x */
674 lstrcatA(szTestDir, "\\winetest");
675 CreateDirectoryA(szTestDir, NULL);
676 attr=GetFileAttributesA(szTestDir);
677 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
679 ok(0, "unable to create the '%s' directory\n", szTestDir);
680 return;
683 lstrcpyA(szTestFile, szTestDir);
684 lstrcatA(szTestFile, "\\");
685 lstrcatA(szTestFile, szFileName);
686 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
687 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
688 if (hTestFile == INVALID_HANDLE_VALUE) return;
689 CloseHandle(hTestFile);
691 /* Getting an itemidlist for the file. */
692 hr = SHGetDesktopFolder(&psfDesktop);
693 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
694 if (hr != S_OK) return;
696 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
698 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
699 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
700 if (hr != S_OK) {
701 IShellFolder_Release(psfDesktop);
702 return;
705 pidlLast = ILFindLastID(pidlTestFile);
706 ok(pidlLast->mkid.cb >= 76, "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
707 if (pidlLast->mkid.cb >= 28) {
708 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
709 "Filename should be stored as ansi-string at this position!\n");
711 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
712 if (pidlLast->mkid.cb >= 76) {
713 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
714 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
715 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)) || /* Win7 */
716 (pidlLast->mkid.cb >= 102 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[72], wszFileName)), /* Win8 */
717 "Filename should be stored as wchar-string at this position!\n");
720 /* It seems as if we cannot bind to regular files on windows, but only directories.
722 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
723 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
724 hr == E_NOTIMPL, /* Vista */
725 "hr = %08x\n", hr);
726 if (hr == S_OK) {
727 IUnknown_Release(psfFile);
730 /* Some tests for IShellFolder::SetNameOf */
731 hr = SHBindToParent(pidlTestFile, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
732 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
734 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
735 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
736 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
738 ok (((ITEMIDLIST *)((BYTE *)pidlNew + pidlNew->mkid.cb))->mkid.cb == 0,
739 "pidl returned from SetNameOf should be simple!\n");
741 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
742 * is implemented on top of SHFileOperation in WinXP. */
743 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename, SHGDN_FORPARSING, NULL);
744 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
746 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
747 * SHGDN flags specify an absolute path. */
748 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
749 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
751 ILFree(pidlNew);
752 IShellFolder_Release(psfPersonal);
754 /* Deleting the file and the directory */
755 DeleteFileA(szTestFile);
756 RemoveDirectoryA(szTestDir);
758 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
759 result = SHGetPathFromIDListW(pidlTestFile, wszTestFile2);
760 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
761 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
763 /* SHBindToParent fails, if called with a NULL PIDL. */
764 hr = SHBindToParent(NULL, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
765 ok (hr == E_INVALIDARG || broken(hr == E_OUTOFMEMORY) /* XP */,
766 "SHBindToParent(NULL) should fail! hr = %08x\n", hr);
768 /* But it succeeds with an empty PIDL. */
769 hr = SHBindToParent(pidlEmpty, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
770 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
771 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
772 if (hr == S_OK)
773 IShellFolder_Release(psfPersonal);
775 /* Binding to the folder and querying the display name of the file also works. */
776 hr = SHBindToParent(pidlTestFile, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
777 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
778 if (hr != S_OK) {
779 IShellFolder_Release(psfDesktop);
780 return;
783 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
784 * pidlTestFile (In accordance with MSDN). */
785 ok (ILFindLastID(pidlTestFile) == pidlLast,
786 "SHBindToParent doesn't return the last id of the pidl param!\n");
788 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
789 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
790 if (hr != S_OK) {
791 IShellFolder_Release(psfDesktop);
792 IShellFolder_Release(psfPersonal);
793 return;
796 hr = StrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
797 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
798 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
800 ILFree(pidlTestFile);
801 IShellFolder_Release(psfDesktop);
802 IShellFolder_Release(psfPersonal);
805 static void test_CallForAttributes(void)
807 HKEY hKey;
808 LONG lResult;
809 HRESULT hr;
810 DWORD dwSize;
811 LPSHELLFOLDER psfDesktop;
812 LPITEMIDLIST pidlMyDocuments;
813 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
814 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
815 static const WCHAR wszCallForAttributes[] = {
816 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
817 static const WCHAR wszMyDocumentsKey[] = {
818 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
819 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
820 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
821 WCHAR wszMyDocuments[] = {
822 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
823 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
825 /* For the root of a namespace extension, the attributes are not queried by binding
826 * to the object and calling GetAttributesOf. Instead, the attributes are read from
827 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
829 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
830 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
831 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
832 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
834 hr = SHGetDesktopFolder(&psfDesktop);
835 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
836 if (hr != S_OK) return;
838 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
839 &pidlMyDocuments, NULL);
840 ok (hr == S_OK,
841 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
842 if (hr != S_OK) {
843 IShellFolder_Release(psfDesktop);
844 return;
847 dwAttributes = 0xffffffff;
848 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
849 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
850 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
852 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
853 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
854 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
855 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
857 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
858 * key. So the test will return at this point, if run on wine.
860 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
861 ok (lResult == ERROR_SUCCESS ||
862 lResult == ERROR_ACCESS_DENIED,
863 "RegOpenKeyEx failed! result: %08x\n", lResult);
864 if (lResult != ERROR_SUCCESS) {
865 if (lResult == ERROR_ACCESS_DENIED)
866 skip("Not enough rights to open the registry key\n");
867 IMalloc_Free(ppM, pidlMyDocuments);
868 IShellFolder_Release(psfDesktop);
869 return;
872 /* Query MyDocuments' Attributes value, to be able to restore it later. */
873 dwSize = sizeof(DWORD);
874 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
875 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
876 if (lResult != ERROR_SUCCESS) {
877 RegCloseKey(hKey);
878 IMalloc_Free(ppM, pidlMyDocuments);
879 IShellFolder_Release(psfDesktop);
880 return;
883 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
884 dwSize = sizeof(DWORD);
885 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
886 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
887 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
888 if (lResult != ERROR_SUCCESS) {
889 RegCloseKey(hKey);
890 IMalloc_Free(ppM, pidlMyDocuments);
891 IShellFolder_Release(psfDesktop);
892 return;
895 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
896 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
897 * SFGAO_FILESYSTEM attributes. */
898 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
899 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
900 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
901 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
902 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
904 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
905 * GetAttributesOf. It seems that once there is a single attribute queried, for which
906 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
907 * the flags in Attributes are ignored.
909 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
910 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
911 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
912 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
913 if (hr == S_OK)
914 ok (dwAttributes == SFGAO_FILESYSTEM,
915 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
916 dwAttributes);
918 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
919 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
920 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
921 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
922 RegCloseKey(hKey);
923 IMalloc_Free(ppM, pidlMyDocuments);
924 IShellFolder_Release(psfDesktop);
927 static void test_GetAttributesOf(void)
929 HRESULT hr;
930 LPSHELLFOLDER psfDesktop, psfMyComputer;
931 SHITEMID emptyitem = { 0, { 0 } };
932 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
933 LPITEMIDLIST pidlMyComputer;
934 DWORD dwFlags;
935 static const DWORD desktopFlags = SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
936 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER;
937 static const DWORD myComputerFlags = SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET |
938 SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
939 WCHAR wszMyComputer[] = {
940 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
941 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
942 char cCurrDirA [MAX_PATH] = {0};
943 WCHAR cCurrDirW [MAX_PATH];
944 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
945 IShellFolder *IDesktopFolder, *testIShellFolder;
946 ITEMIDLIST *newPIDL;
947 int len;
949 hr = SHGetDesktopFolder(&psfDesktop);
950 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
951 if (hr != S_OK) return;
953 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
954 dwFlags = 0xffffffff;
955 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
956 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
957 ok (dwFlags == desktopFlags, "Wrong Desktop attributes: %08x\n", dwFlags);
959 /* .. or with no itemidlist at all. */
960 dwFlags = 0xffffffff;
961 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
962 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
963 ok (dwFlags == desktopFlags, "Wrong Desktop attributes: %08x\n", dwFlags);
965 /* Testing the attributes of the MyComputer shellfolder */
966 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
967 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
968 if (hr != S_OK) {
969 IShellFolder_Release(psfDesktop);
970 return;
973 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
974 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
976 dwFlags = 0xffffffff;
977 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
978 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
979 todo_wine
980 ok (dwFlags == (myComputerFlags | SFGAO_CANLINK), "Wrong MyComputer attributes: %08x\n", dwFlags);
982 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
983 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
984 IShellFolder_Release(psfDesktop);
985 IMalloc_Free(ppM, pidlMyComputer);
986 if (hr != S_OK) return;
988 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
989 todo_wine
990 ok (hr == E_INVALIDARG, "MyComputer->GetAttributesOf(empty pidl) should fail! hr = %08x\n", hr);
992 dwFlags = 0xffffffff;
993 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
994 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
995 todo_wine
996 ok (dwFlags == myComputerFlags, "Wrong MyComputer attributes: %08x\n", dwFlags);
998 IShellFolder_Release(psfMyComputer);
1000 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1001 len = lstrlenA(cCurrDirA);
1003 if (len == 0) {
1004 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1005 return;
1007 if (len > 3 && cCurrDirA[len-1] == '\\')
1008 cCurrDirA[len-1] = 0;
1010 /* create test directory */
1011 CreateFilesFolders();
1013 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1015 hr = SHGetDesktopFolder(&IDesktopFolder);
1016 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1018 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1019 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1021 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1022 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1024 IMalloc_Free(ppM, newPIDL);
1026 /* get relative PIDL */
1027 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1028 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1030 /* test the shell attributes of the test directory using the relative PIDL */
1031 dwFlags = SFGAO_FOLDER;
1032 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1033 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1034 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1036 /* free memory */
1037 IMalloc_Free(ppM, newPIDL);
1039 /* append testdirectory name to path */
1040 if (cCurrDirA[len-1] == '\\')
1041 cCurrDirA[len-1] = 0;
1042 lstrcatA(cCurrDirA, "\\testdir");
1043 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1045 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1046 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1048 /* test the shell attributes of the test directory using the absolute PIDL */
1049 dwFlags = SFGAO_FOLDER;
1050 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1051 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1052 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1054 /* free memory */
1055 IMalloc_Free(ppM, newPIDL);
1057 IShellFolder_Release(testIShellFolder);
1059 Cleanup();
1061 IShellFolder_Release(IDesktopFolder);
1064 static void test_SHGetPathFromIDList(void)
1066 SHITEMID emptyitem = { 0, { 0 } };
1067 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1068 LPITEMIDLIST pidlMyComputer;
1069 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1070 BOOL result;
1071 HRESULT hr;
1072 LPSHELLFOLDER psfDesktop;
1073 WCHAR wszMyComputer[] = {
1074 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1075 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1076 WCHAR wszFileName[MAX_PATH];
1077 LPITEMIDLIST pidlTestFile;
1078 HANDLE hTestFile;
1079 STRRET strret;
1080 static WCHAR wszTestFile[] = {
1081 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1082 LPITEMIDLIST pidlPrograms;
1084 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1085 wszPath[0] = 'a';
1086 wszPath[1] = '\0';
1087 result = SHGetPathFromIDListW(NULL, wszPath);
1088 ok(!result, "Expected failure\n");
1089 ok(!wszPath[0], "Expected empty string\n");
1091 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1092 result = SHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1093 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1094 if (!result) return;
1096 result = SHGetPathFromIDListW(pidlEmpty, wszPath);
1097 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1098 if (!result) return;
1099 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1101 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1102 hr = SHGetDesktopFolder(&psfDesktop);
1103 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1104 if (hr != S_OK) return;
1106 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1107 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1108 if (hr != S_OK) {
1109 IShellFolder_Release(psfDesktop);
1110 return;
1113 SetLastError(0xdeadbeef);
1114 wszPath[0] = 'a';
1115 wszPath[1] = '\0';
1116 result = SHGetPathFromIDListW(pidlMyComputer, wszPath);
1117 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1118 ok (GetLastError()==0xdeadbeef ||
1119 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1120 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1121 ok (!wszPath[0], "Expected empty path\n");
1122 if (result) {
1123 IShellFolder_Release(psfDesktop);
1124 return;
1127 IMalloc_Free(ppM, pidlMyComputer);
1129 result = SHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1130 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1131 if (!result) {
1132 IShellFolder_Release(psfDesktop);
1133 return;
1135 myPathAddBackslashW(wszFileName);
1136 lstrcatW(wszFileName, wszTestFile);
1137 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1138 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1139 if (hTestFile == INVALID_HANDLE_VALUE) {
1140 IShellFolder_Release(psfDesktop);
1141 return;
1143 CloseHandle(hTestFile);
1145 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1146 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1147 if (hr != S_OK) {
1148 IShellFolder_Release(psfDesktop);
1149 DeleteFileW(wszFileName);
1150 IMalloc_Free(ppM, pidlTestFile);
1151 return;
1154 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1155 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1156 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1157 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1158 IShellFolder_Release(psfDesktop);
1159 DeleteFileW(wszFileName);
1160 if (hr != S_OK) {
1161 IMalloc_Free(ppM, pidlTestFile);
1162 return;
1164 StrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1165 ok(0 == lstrcmpW(wszFileName, wszPath),
1166 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1167 "returned incorrect path for file placed on desktop\n");
1169 result = SHGetPathFromIDListW(pidlTestFile, wszPath);
1170 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1171 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1173 if (pSHGetPathFromIDListEx)
1175 result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1176 ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1177 ok(!lstrcmpiW(wszDesktop, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1178 wine_dbgstr_w(wszPath), wine_dbgstr_w(wszDesktop));
1180 result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1181 ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1182 ok(!lstrcmpiW(wszFileName, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1183 wine_dbgstr_w(wszPath), wine_dbgstr_w(wszFileName));
1185 SetLastError(0xdeadbeef);
1186 memset(wszPath, 0x55, sizeof(wszPath));
1187 result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, 5, SFGAO_FILESYSTEM);
1188 ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1190 SetLastError(0xdeadbeef);
1191 memset(wszPath, 0x55, sizeof(wszPath));
1192 result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, 5, SFGAO_FILESYSTEM);
1193 ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1195 else
1196 win_skip("SHGetPathFromIDListEx not available\n");
1198 IMalloc_Free(ppM, pidlTestFile);
1200 /* Test if we can get the path from the start menu "program files" PIDL. */
1201 hr = SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1202 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1204 SetLastError(0xdeadbeef);
1205 result = SHGetPathFromIDListW(pidlPrograms, wszPath);
1206 IMalloc_Free(ppM, pidlPrograms);
1207 ok(result, "SHGetPathFromIDListW failed\n");
1210 static void test_EnumObjects_and_CompareIDs(void)
1212 ITEMIDLIST *newPIDL;
1213 IShellFolder *IDesktopFolder, *testIShellFolder;
1214 char cCurrDirA [MAX_PATH] = {0};
1215 static const CHAR cTestDirA[] = "\\testdir";
1216 WCHAR cTestDirW[MAX_PATH];
1217 int len;
1218 HRESULT hr;
1220 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1221 len = lstrlenA(cCurrDirA);
1223 if(len == 0) {
1224 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1225 return;
1227 if(cCurrDirA[len-1] == '\\')
1228 cCurrDirA[len-1] = 0;
1230 lstrcatA(cCurrDirA, cTestDirA);
1231 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1233 hr = SHGetDesktopFolder(&IDesktopFolder);
1234 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1236 CreateFilesFolders();
1238 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1239 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1241 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1242 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1244 test_EnumObjects(testIShellFolder);
1246 IShellFolder_Release(testIShellFolder);
1248 Cleanup();
1250 IMalloc_Free(ppM, newPIDL);
1252 IShellFolder_Release(IDesktopFolder);
1255 /* A simple implementation of an IPropertyBag, which returns fixed values for
1256 * 'Target' and 'Attributes' properties.
1258 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1259 void **ppvObject)
1261 if (!ppvObject)
1262 return E_INVALIDARG;
1264 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1265 *ppvObject = iface;
1266 } else {
1267 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1268 return E_NOINTERFACE;
1271 IPropertyBag_AddRef(iface);
1272 return S_OK;
1275 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1276 return 2;
1279 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1280 return 1;
1283 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1284 VARIANT *pVar, IErrorLog *pErrorLog)
1286 static const WCHAR wszTargetSpecialFolder[] = {
1287 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1288 static const WCHAR wszTarget[] = {
1289 'T','a','r','g','e','t',0 };
1290 static const WCHAR wszAttributes[] = {
1291 'A','t','t','r','i','b','u','t','e','s',0 };
1292 static const WCHAR wszResolveLinkFlags[] = {
1293 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1294 static const WCHAR wszTargetKnownFolder[] = {
1295 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1296 static const WCHAR wszCLSID[] = {
1297 'C','L','S','I','D',0 };
1299 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1300 ok(V_VT(pVar) == VT_I4, "Wrong variant type for 'TargetSpecialFolder' property!\n");
1301 return E_INVALIDARG;
1304 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1306 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1307 return E_INVALIDARG;
1310 if (!lstrcmpW(pszPropName, wszTarget)) {
1311 WCHAR wszPath[MAX_PATH];
1312 BOOL result;
1314 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'Target' property!\n");
1315 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1317 result = SHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1318 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1319 if (!result) return E_INVALIDARG;
1321 V_BSTR(pVar) = SysAllocString(wszPath);
1322 return S_OK;
1325 if (!lstrcmpW(pszPropName, wszAttributes)) {
1326 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1327 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1328 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1329 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1330 return S_OK;
1333 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1334 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1335 /* TODO */
1336 return E_INVALIDARG;
1339 if (!lstrcmpW(pszPropName, wszCLSID)) {
1340 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1341 /* TODO */
1342 return E_INVALIDARG;
1345 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1346 return E_INVALIDARG;
1349 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1350 VARIANT *pVar)
1352 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1353 return E_NOTIMPL;
1356 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1357 InitPropertyBag_IPropertyBag_QueryInterface,
1358 InitPropertyBag_IPropertyBag_AddRef,
1359 InitPropertyBag_IPropertyBag_Release,
1360 InitPropertyBag_IPropertyBag_Read,
1361 InitPropertyBag_IPropertyBag_Write
1364 static struct IPropertyBag InitPropertyBag = {
1365 &InitPropertyBag_IPropertyBagVtbl
1368 static void test_FolderShortcut(void) {
1369 IPersistPropertyBag *pPersistPropertyBag;
1370 IShellFolder *pShellFolder, *pDesktopFolder;
1371 IPersistFolder3 *pPersistFolder3;
1372 HRESULT hr;
1373 STRRET strret;
1374 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1375 BOOL result;
1376 CLSID clsid;
1377 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1378 HKEY hShellExtKey;
1379 WCHAR wszWineTestFolder[] = {
1380 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1381 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1382 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1383 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1384 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1385 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1386 'N','a','m','e','S','p','a','c','e','\\',
1387 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1388 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1390 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1391 static const GUID CLSID_UnixDosFolder =
1392 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1394 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1395 * via their IPersistPropertyBag interface. And that the target folder
1396 * is taken from the IPropertyBag's 'Target' property.
1398 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1399 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1400 if (hr == REGDB_E_CLASSNOTREG) {
1401 win_skip("CLSID_FolderShortcut is not implemented\n");
1402 return;
1404 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1405 if (hr != S_OK) return;
1407 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1408 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1409 if (hr != S_OK) {
1410 IPersistPropertyBag_Release(pPersistPropertyBag);
1411 return;
1414 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1415 (LPVOID*)&pShellFolder);
1416 IPersistPropertyBag_Release(pPersistPropertyBag);
1417 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1418 if (hr != S_OK) return;
1420 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1421 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* win10 */,
1422 "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1423 if (hr != S_OK) {
1424 IShellFolder_Release(pShellFolder);
1425 return;
1428 result = SHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1429 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1430 if (!result) return;
1432 StrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1433 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1435 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1436 IShellFolder_Release(pShellFolder);
1437 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1438 if (hr != S_OK) return;
1440 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1441 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1442 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1444 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1445 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1446 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1448 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1449 * shell namespace. The target folder, read from the property bag above, remains untouched.
1450 * The following tests show this: The itemidlist for some imaginary shellfolder object
1451 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1452 * itemidlist, but GetDisplayNameOf still returns the path from above.
1454 hr = SHGetDesktopFolder(&pDesktopFolder);
1455 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1456 if (hr != S_OK) return;
1458 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1459 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1460 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1461 RegCloseKey(hShellExtKey);
1462 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1463 &pidlWineTestFolder, NULL);
1464 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1465 IShellFolder_Release(pDesktopFolder);
1466 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1467 if (hr != S_OK) return;
1469 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1470 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1471 if (hr != S_OK) {
1472 IPersistFolder3_Release(pPersistFolder3);
1473 ILFree(pidlWineTestFolder);
1474 return;
1477 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1478 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1479 ok(ILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1480 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1481 ILFree(pidlCurrentFolder);
1482 ILFree(pidlWineTestFolder);
1484 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1485 IPersistFolder3_Release(pPersistFolder3);
1486 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1487 if (hr != S_OK) return;
1489 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1490 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1491 if (hr != S_OK) {
1492 IShellFolder_Release(pShellFolder);
1493 return;
1496 StrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1497 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1499 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1500 * but ShellFSFolders. */
1501 myPathAddBackslashW(wszDesktopPath);
1502 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1503 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1504 IShellFolder_Release(pShellFolder);
1505 return;
1508 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1509 &pidlSubFolder, NULL);
1510 RemoveDirectoryW(wszDesktopPath);
1511 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1512 if (hr != S_OK) {
1513 IShellFolder_Release(pShellFolder);
1514 return;
1517 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1518 (LPVOID*)&pPersistFolder3);
1519 IShellFolder_Release(pShellFolder);
1520 ILFree(pidlSubFolder);
1521 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1522 if (hr != S_OK)
1523 return;
1525 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1526 * a little bit and also allow CLSID_UnixDosFolder. */
1527 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1528 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1529 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1530 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1532 IPersistFolder3_Release(pPersistFolder3);
1535 #include "pshpack1.h"
1536 struct FileStructA {
1537 BYTE type;
1538 BYTE dummy;
1539 DWORD dwFileSize;
1540 WORD uFileDate; /* In our current implementation this is */
1541 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1542 WORD uFileAttribs;
1543 CHAR szName[1];
1546 struct FileStructW {
1547 WORD cbLen; /* Length of this element. */
1548 BYTE abFooBar1[6]; /* Beyond any recognition. */
1549 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1550 WORD uTime; /* (this is currently speculation) */
1551 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1552 WORD uTime2; /* (this is currently speculation) */
1553 BYTE abFooBar2[4]; /* Beyond any recognition. */
1554 WCHAR wszName[1]; /* The long filename in unicode. */
1555 /* Just for documentation: Right after the unicode string: */
1556 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1557 * SHITEMID->cb == uOffset + cbLen */
1559 #include "poppack.h"
1561 static void test_ITEMIDLIST_format(void) {
1562 WCHAR wszPersonal[MAX_PATH];
1563 LPSHELLFOLDER psfDesktop, psfPersonal;
1564 LPITEMIDLIST pidlPersonal, pidlFile;
1565 HANDLE hFile;
1566 HRESULT hr;
1567 BOOL bResult;
1568 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1569 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1570 int i;
1572 bResult = SHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1573 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1574 if (!bResult) return;
1576 SetLastError(0xdeadbeef);
1577 bResult = SetCurrentDirectoryW(wszPersonal);
1578 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1579 win_skip("Most W-calls are not implemented\n");
1580 return;
1582 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1583 if (!bResult) return;
1585 hr = SHGetDesktopFolder(&psfDesktop);
1586 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1587 if (hr != S_OK) return;
1589 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1590 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1591 if (hr != S_OK) {
1592 IShellFolder_Release(psfDesktop);
1593 return;
1596 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1597 (LPVOID*)&psfPersonal);
1598 IShellFolder_Release(psfDesktop);
1599 ILFree(pidlPersonal);
1600 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1601 if (hr != S_OK) return;
1603 for (i=0; i<3; i++) {
1604 CHAR szFile[MAX_PATH];
1605 struct FileStructA *pFileStructA;
1606 WORD cbOffset;
1608 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1610 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1611 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1612 if (hFile == INVALID_HANDLE_VALUE) {
1613 IShellFolder_Release(psfPersonal);
1614 return;
1616 CloseHandle(hFile);
1618 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1619 DeleteFileW(wszFile[i]);
1620 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1621 if (hr != S_OK) {
1622 IShellFolder_Release(psfPersonal);
1623 return;
1626 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1627 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1628 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1629 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1631 if (i < 2) /* First two file names are already in valid 8.3 format */
1632 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1633 else
1634 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1635 * can't implement this correctly, since unix filesystems don't support
1636 * this nasty short/long filename stuff. So we'll probably stay with our
1637 * current habit of storing the long filename here, which seems to work
1638 * just fine. */
1639 todo_wine
1640 ok(pidlFile->mkid.abID[18] == '~', "Should be derived 8.3 name!\n");
1642 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1643 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0',
1644 "Alignment byte, where there shouldn't be!\n");
1646 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1647 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1648 "There should be an alignment byte, but isn't!\n");
1650 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1651 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1652 ok ((cbOffset >= sizeof(struct FileStructA) &&
1653 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)),
1654 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1656 if (cbOffset >= sizeof(struct FileStructA) &&
1657 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1659 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1660 WCHAR *name = pFileStructW->wszName;
1662 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1663 "FileStructW's offset and length should add up to the PIDL's length!\n");
1665 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1666 /* Since we just created the file, time of creation,
1667 * time of last access and time of last write access just be the same.
1668 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1669 * after the first run. I do remember something with NTFS keeping the creation time
1670 * if a file is deleted and then created again within a couple of seconds or so.
1671 * Might be the reason. */
1672 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1673 pFileStructA->uFileTime == pFileStructW->uTime,
1674 "Last write time should match creation time!\n");
1676 /* On FAT filesystems the last access time is midnight
1677 local time, so the values of uDate2 and uTime2 will
1678 depend on the local timezone. If the times are exactly
1679 equal then the dates should be identical for both FAT
1680 and NTFS as no timezone is more than 1 day away from UTC.
1682 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1684 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1685 "Last write date and time should match last access date and time!\n");
1687 else
1689 /* Filesystem may be FAT. Check date within 1 day
1690 and seconds are zero. */
1691 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1692 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1693 "Last access time on FAT filesystems should have zero seconds.\n");
1694 /* TODO: Perform check for date being within one day.*/
1697 ok (!lstrcmpW(wszFile[i], name) ||
1698 !lstrcmpW(wszFile[i], name + 9) || /* Vista */
1699 !lstrcmpW(wszFile[i], name + 11) || /* Win7 */
1700 !lstrcmpW(wszFile[i], name + 13), /* Win8 */
1701 "The filename should be stored in unicode at this position!\n");
1705 ILFree(pidlFile);
1708 IShellFolder_Release(psfPersonal);
1711 static void test_SHGetFolderPathA(void)
1713 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1714 BOOL is_wow64;
1715 char path[MAX_PATH];
1716 char path_x86[MAX_PATH];
1717 char path_key[MAX_PATH];
1718 HRESULT hr;
1719 HKEY key;
1721 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1723 hr = SHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1724 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1725 hr = SHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1726 if (hr == E_FAIL)
1728 win_skip( "Program Files (x86) not supported\n" );
1729 return;
1731 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1732 if (is_win64)
1734 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1735 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1736 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1738 else
1740 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1741 if (is_wow64)
1742 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1743 else
1744 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1746 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1748 DWORD type, count = sizeof(path_x86);
1749 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1751 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1752 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1754 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1755 RegCloseKey( key );
1758 hr = SHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1759 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1760 hr = SHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1761 if (hr == E_FAIL)
1763 win_skip( "Common Files (x86) not supported\n" );
1764 return;
1766 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1767 if (is_win64)
1769 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1770 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1771 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1773 else
1775 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1776 if (is_wow64)
1777 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1778 else
1779 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1781 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1783 DWORD type, count = sizeof(path_x86);
1784 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1786 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1787 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1789 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1793 static void test_SHGetFolderPathAndSubDirA(void)
1795 HRESULT ret;
1796 BOOL delret;
1797 DWORD dwret;
1798 int i;
1799 static const char wine[] = "wine";
1800 static const char winetemp[] = "wine\\temp";
1801 static char appdata[MAX_PATH];
1802 static char testpath[MAX_PATH];
1803 static char toolongpath[MAX_PATH+1];
1805 if(FAILED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1807 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1808 return;
1811 sprintf(testpath, "%s\\%s", appdata, winetemp);
1812 delret = RemoveDirectoryA(testpath);
1813 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1814 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1815 return;
1818 sprintf(testpath, "%s\\%s", appdata, wine);
1819 delret = RemoveDirectoryA(testpath);
1820 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1821 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1822 return;
1825 /* test invalid second parameter */
1826 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1827 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1829 /* test fourth parameter */
1830 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1831 switch(ret) {
1832 case S_OK: /* winvista */
1833 ok(!strncmp(appdata, testpath, strlen(appdata)),
1834 "expected %s to start with %s\n", testpath, appdata);
1835 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1836 "expected %s to end with %s\n", testpath, winetemp);
1837 break;
1838 case E_INVALIDARG: /* winxp, win2k3 */
1839 break;
1840 default:
1841 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
1844 /* test fifth parameter */
1845 testpath[0] = '\0';
1846 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1847 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1848 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1850 testpath[0] = '\0';
1851 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1852 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1853 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1855 testpath[0] = '\0';
1856 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1857 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1858 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1860 for(i=0; i< MAX_PATH; i++)
1861 toolongpath[i] = '0' + i % 10;
1862 toolongpath[MAX_PATH] = '\0';
1863 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1864 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1865 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1867 testpath[0] = '\0';
1868 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1869 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1871 /* test a not existing path */
1872 testpath[0] = '\0';
1873 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1874 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1875 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1877 /* create a directory inside a not existing directory */
1878 testpath[0] = '\0';
1879 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1880 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1881 ok(!strncmp(appdata, testpath, strlen(appdata)),
1882 "expected %s to start with %s\n", testpath, appdata);
1883 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1884 "expected %s to end with %s\n", testpath, winetemp);
1885 dwret = GetFileAttributesA(testpath);
1886 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1888 /* cleanup */
1889 sprintf(testpath, "%s\\%s", appdata, winetemp);
1890 RemoveDirectoryA(testpath);
1891 sprintf(testpath, "%s\\%s", appdata, wine);
1892 RemoveDirectoryA(testpath);
1895 static void test_LocalizedNames(void)
1897 static char cCurrDirA[MAX_PATH];
1898 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1899 IShellFolder *IDesktopFolder, *testIShellFolder;
1900 ITEMIDLIST *newPIDL;
1901 int len;
1902 HRESULT hr;
1903 static char resourcefile[MAX_PATH];
1904 DWORD res;
1905 HANDLE file;
1906 STRRET strret;
1907 BOOL ret;
1909 static const char desktopini_contents1[] =
1910 "[.ShellClassInfo]\r\n"
1911 "LocalizedResourceName=@";
1912 static const char desktopini_contents2[] =
1913 ",-1\r\n";
1914 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1915 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1917 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1918 CreateDirectoryA(".\\testfolder", NULL);
1920 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1922 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1924 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1925 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1926 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1927 ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1928 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1929 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
1930 ok(ret, "WriteFile failed %i\n", GetLastError());
1931 CloseHandle(file);
1933 /* get IShellFolder for parent */
1934 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1935 len = lstrlenA(cCurrDirA);
1937 if (len == 0) {
1938 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1939 goto cleanup;
1941 if(cCurrDirA[len-1] == '\\')
1942 cCurrDirA[len-1] = 0;
1944 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1946 hr = SHGetDesktopFolder(&IDesktopFolder);
1947 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1949 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1950 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1952 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1953 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1955 IMalloc_Free(ppM, newPIDL);
1957 /* windows reads the display name from the resource */
1958 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1959 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1961 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1962 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1964 hr = StrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1965 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1966 todo_wine
1967 ok (!lstrcmpiW(tempbufW, folderdisplayW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1969 /* editing name is also read from the resource */
1970 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1971 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1973 hr = StrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1974 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1975 todo_wine
1976 ok (!lstrcmpiW(tempbufW, folderdisplayW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1978 /* parsing name is unchanged */
1979 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1980 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1982 hr = StrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1983 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1984 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1986 IShellFolder_Release(IDesktopFolder);
1987 IShellFolder_Release(testIShellFolder);
1989 IMalloc_Free(ppM, newPIDL);
1991 cleanup:
1992 DeleteFileA(".\\testfolder\\desktop.ini");
1993 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1994 RemoveDirectoryA(".\\testfolder");
1997 static void test_SHCreateShellItem(void)
1999 IShellItem *shellitem, *shellitem2;
2000 IPersistIDList *persistidl;
2001 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2002 HRESULT ret;
2003 char curdirA[MAX_PATH];
2004 WCHAR curdirW[MAX_PATH];
2005 WCHAR fnbufW[MAX_PATH];
2006 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2007 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2009 GetCurrentDirectoryA(MAX_PATH, curdirA);
2011 if (!pSHCreateShellItem)
2013 win_skip("SHCreateShellItem isn't available\n");
2014 return;
2017 if (!curdirA[0])
2019 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2020 return;
2023 ret = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2024 ok(ret == S_OK, "Got 0x%08x\n", ret);
2026 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2028 ret = SHGetDesktopFolder(&desktopfolder);
2029 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2031 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2032 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2034 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2035 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2037 CreateTestFile(".\\testfile");
2039 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2040 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2042 pidl_abstestfile = ILCombine(pidl_cwd, pidl_testfile);
2044 shellitem = (void*)0xdeadbeef;
2045 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2046 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2047 ok(shellitem == 0, "Got %p\n", shellitem);
2049 if (0) /* crashes on Windows XP */
2051 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2052 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2053 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2054 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2057 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2058 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2059 if (SUCCEEDED(ret))
2061 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2062 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2063 if (SUCCEEDED(ret))
2065 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2066 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2067 if (SUCCEEDED(ret))
2069 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2070 ILFree(pidl_test);
2072 IPersistIDList_Release(persistidl);
2074 IShellItem_Release(shellitem);
2077 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2078 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2079 if (SUCCEEDED(ret))
2081 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2082 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2083 if (SUCCEEDED(ret))
2085 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2086 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2087 if (SUCCEEDED(ret))
2089 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2090 ILFree(pidl_test);
2092 IPersistIDList_Release(persistidl);
2095 ret = IShellItem_GetParent(shellitem, &shellitem2);
2096 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2097 if (SUCCEEDED(ret))
2099 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2100 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2101 if (SUCCEEDED(ret))
2103 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2104 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2105 if (SUCCEEDED(ret))
2107 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2108 ILFree(pidl_test);
2110 IPersistIDList_Release(persistidl);
2112 IShellItem_Release(shellitem2);
2115 IShellItem_Release(shellitem);
2118 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2119 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2120 if (SUCCEEDED(ret))
2122 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2123 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2124 if (SUCCEEDED(ret))
2126 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2127 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2128 if (SUCCEEDED(ret))
2130 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2131 ILFree(pidl_test);
2133 IPersistIDList_Release(persistidl);
2135 IShellItem_Release(shellitem);
2138 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2139 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2140 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2141 if (SUCCEEDED(ret))
2143 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2144 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2145 if (SUCCEEDED(ret))
2147 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2148 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2149 if (SUCCEEDED(ret))
2151 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2152 ILFree(pidl_test);
2154 IPersistIDList_Release(persistidl);
2156 IShellItem_Release(shellitem);
2159 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2160 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2161 if (SUCCEEDED(ret))
2163 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2164 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2165 if (SUCCEEDED(ret))
2167 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2168 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2169 if (SUCCEEDED(ret))
2171 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2172 ILFree(pidl_test);
2174 IPersistIDList_Release(persistidl);
2177 IShellItem_Release(shellitem);
2180 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2181 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2182 if (SUCCEEDED(ret))
2184 ret = IShellItem_GetParent(shellitem, &shellitem2);
2185 ok(FAILED(ret), "Got 0x%08x\n", ret);
2186 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2187 IShellItem_Release(shellitem);
2190 /* SHCreateItemFromParsingName */
2191 if(pSHCreateItemFromParsingName)
2193 if(0)
2195 /* Crashes under windows 7 */
2196 pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2199 shellitem = (void*)0xdeadbeef;
2200 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2201 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2202 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2204 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2205 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2206 "SHCreateItemFromParsingName returned %x\n", ret);
2207 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2209 lstrcpyW(fnbufW, curdirW);
2210 myPathAddBackslashW(fnbufW);
2211 lstrcatW(fnbufW, testfileW);
2213 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2214 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2215 if(SUCCEEDED(ret))
2217 LPWSTR tmp_fname;
2218 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2219 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2220 if(SUCCEEDED(ret))
2222 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2223 CoTaskMemFree(tmp_fname);
2225 IShellItem_Release(shellitem);
2228 else
2229 win_skip("No SHCreateItemFromParsingName\n");
2232 /* SHCreateItemFromIDList */
2233 if(pSHCreateItemFromIDList)
2235 if(0)
2237 /* Crashes under win7 */
2238 pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2241 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2242 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2244 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2245 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2246 if (SUCCEEDED(ret))
2248 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2249 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2250 if (SUCCEEDED(ret))
2252 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2253 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2254 if (SUCCEEDED(ret))
2256 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2257 ILFree(pidl_test);
2259 IPersistIDList_Release(persistidl);
2261 IShellItem_Release(shellitem);
2264 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2265 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2266 if (SUCCEEDED(ret))
2268 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2269 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2270 if (SUCCEEDED(ret))
2272 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2273 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2274 if (SUCCEEDED(ret))
2276 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2277 ILFree(pidl_test);
2279 IPersistIDList_Release(persistidl);
2281 IShellItem_Release(shellitem);
2284 else
2285 win_skip("No SHCreateItemFromIDList\n");
2287 /* SHCreateItemFromRelativeName */
2288 if(pSHCreateItemFromRelativeName && pSHGetKnownFolderPath)
2290 IShellItem *shellitem_desktop = NULL;
2291 WCHAR *desktop_path, *displayname;
2292 WCHAR testfile_path[MAX_PATH] = {0};
2293 HANDLE file;
2294 LPITEMIDLIST pidl_desktop_testfile = NULL;
2295 int order;
2297 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem_desktop);
2298 ok(ret == S_OK, "SHCreateShellItem failed: 0x%08x.\n", ret);
2300 shellitem = (void*)0xdeadbeef;
2301 ret = pSHCreateItemFromRelativeName(shellitem_desktop, NULL, NULL, &IID_IShellItem,
2302 (void**)&shellitem);
2303 ok(ret == E_INVALIDARG, "Expected 0x%08x but SHCreateItemFromRelativeName return: 0x%08x.\n",
2304 E_INVALIDARG, ret);
2305 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2307 /* Test with a non-existent file */
2308 shellitem = (void*)0xdeadbeef;
2309 ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2310 (void**)&shellitem);
2311 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2312 "Expected 0x%08x but SHCreateItemFromRelativeName return: 0x%08x.\n",
2313 HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), ret);
2314 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2316 /* Create a file for testing in desktop folder */
2317 pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &desktop_path);
2318 lstrcatW(testfile_path, desktop_path);
2319 myPathAddBackslashW(testfile_path);
2320 lstrcatW(testfile_path, testfileW);
2321 file = CreateFileW(testfile_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
2322 ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: 0x%08x.\n", GetLastError());
2323 CloseHandle(file);
2325 shellitem = (void*)0xdeadbeef;
2326 ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2327 (void**)&shellitem);
2328 ok(ret == S_OK, "SHCreateItemFromRelativeName failed: 0x%08x.\n", ret);
2329 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2330 if(SUCCEEDED(ret))
2332 ret = IShellItem_GetDisplayName(shellitem, 0, &displayname);
2333 ok(ret == S_OK, "IShellItem_GetDisplayName failed: 0x%08x.\n", ret);
2334 ok(!lstrcmpW(displayname, testfileW), "got wrong display name: %s.\n", wine_dbgstr_w(displayname));
2335 CoTaskMemFree(displayname);
2337 shellitem2 = (void*)0xdeadbeef;
2338 ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2339 (void**)&shellitem2);
2340 ok(ret == S_OK, "SHCreateItemFromRelativeName failed: 0x%08x.\n", ret);
2341 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2342 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2343 ok(!order, "order got wrong value: %d.\n", order);
2344 IShellItem_Release(shellitem2);
2346 shellitem2 = (void*)0xdeadbeef;
2347 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, testfileW, NULL,
2348 &pidl_desktop_testfile, NULL);
2349 ok(ret == S_OK, "ParseDisplayName failed 0x%08x.\n", ret);
2350 ret = pSHCreateItemFromIDList(pidl_desktop_testfile, &IID_IShellItem, (void**)&shellitem2);
2351 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2352 ok(ret == S_OK, "IShellItem_Compare fail: 0x%08x.\n", ret);
2353 ok(!order, "order got wrong value: %d.\n", order);
2354 ILFree(pidl_desktop_testfile);
2355 IShellItem_Release(shellitem2);
2357 IShellItem_Release(shellitem);
2360 DeleteFileW(testfile_path);
2361 CoTaskMemFree(desktop_path);
2362 IShellItem_Release(shellitem_desktop);
2364 else
2365 win_skip("No SHCreateItemFromRelativeName or SHGetKnownFolderPath\n");
2367 /* SHCreateItemInKnownFolder */
2368 if(pSHCreateItemInKnownFolder && pSHGetKnownFolderPath)
2370 WCHAR *desktop_path;
2371 WCHAR testfile_path[MAX_PATH] = {0};
2372 HANDLE file;
2373 WCHAR *displayname = NULL;
2374 int order;
2375 LPITEMIDLIST pidl_desktop_testfile = NULL;
2377 shellitem = (void*)0xdeadbeef;
2378 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, NULL, &IID_IShellItem,
2379 (void**)&shellitem);
2380 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2381 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2382 if(SUCCEEDED(ret))
2384 shellitem2 = (void*)0xdeadbeef;
2385 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem2);
2386 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2387 if(SUCCEEDED(ret))
2389 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2390 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2391 ok(!order, "order got wrong value: %d.\n", order);
2392 IShellItem_Release(shellitem2);
2394 IShellItem_Release(shellitem);
2397 /* Test with a non-existent file */
2398 shellitem = (void*)0xdeadbeef;
2399 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2400 (void**)&shellitem);
2401 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2402 "Expected 0x%08x but SHCreateItemInKnownFolder return: 0x%08x.\n",
2403 HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), ret);
2404 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2406 pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &desktop_path);
2407 lstrcatW(testfile_path, desktop_path);
2408 myPathAddBackslashW(testfile_path);
2409 lstrcatW(testfile_path, testfileW);
2410 file = CreateFileW(testfile_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
2411 ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: 0x%08x.\n", GetLastError());
2412 CloseHandle(file);
2414 shellitem = (void*)0xdeadbeef;
2415 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2416 (void**)&shellitem);
2417 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2418 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2419 if(SUCCEEDED(ret))
2421 ret = IShellItem_GetDisplayName(shellitem, 0, &displayname);
2422 ok(ret == S_OK, "IShellItem_GetDisplayName failed: 0x%08x.\n", ret);
2423 ok(!lstrcmpW(displayname, testfileW), "got wrong display name: %s.\n",
2424 wine_dbgstr_w(displayname));
2425 CoTaskMemFree(displayname);
2427 shellitem2 = (void*)0xdeadbeef;
2428 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2429 (void**)&shellitem2);
2430 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2431 ok(shellitem2 != NULL, "shellitem was %p.\n", shellitem);
2432 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2433 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2434 ok(!order, "order got wrong value: %d.\n", order);
2435 IShellItem_Release(shellitem2);
2437 shellitem2 = (void*)0xdeadbeef;
2438 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, testfileW, NULL,
2439 &pidl_desktop_testfile, NULL);
2440 ok(SUCCEEDED(ret), "ParseDisplayName returned %x.\n", ret);
2441 ret = pSHCreateItemFromIDList(pidl_desktop_testfile, &IID_IShellItem, (void**)&shellitem2);
2442 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2443 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2444 ok(!order, "order got wrong value: %d.\n", order);
2445 ILFree(pidl_desktop_testfile);
2446 IShellItem_Release(shellitem2);
2448 IShellItem_Release(shellitem);
2451 shellitem = (void*)0xdeadbeef;
2452 ret = pSHCreateItemInKnownFolder(&FOLDERID_Documents, 0, NULL, &IID_IShellItem,
2453 (void**)&shellitem);
2454 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2455 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2456 if(SUCCEEDED(ret))
2458 shellitem2 = (void*)0xdeadbeef;
2459 ret = pSHCreateItemInKnownFolder(&FOLDERID_Documents, 0, NULL, &IID_IShellItem,
2460 (void**)&shellitem2);
2461 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2462 ok(shellitem2 != NULL, "shellitem was %p.\n", shellitem);
2463 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2464 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2465 ok(!order, "order got wrong value: %d.\n", order);
2466 IShellItem_Release(shellitem2);
2468 IShellItem_Release(shellitem);
2470 DeleteFileW(testfile_path);
2471 CoTaskMemFree(desktop_path);
2473 else
2474 win_skip("No SHCreateItemInKnownFolder or SHGetKnownFolderPath\n");
2476 DeleteFileA(".\\testfile");
2477 ILFree(pidl_abstestfile);
2478 ILFree(pidl_testfile);
2479 ILFree(pidl_desktop);
2480 ILFree(pidl_cwd);
2481 IShellFolder_Release(currentfolder);
2482 IShellFolder_Release(desktopfolder);
2485 static void test_SHGetNameFromIDList(void)
2487 IShellItem *shellitem;
2488 LPITEMIDLIST pidl;
2489 LPWSTR name_string;
2490 HRESULT hres;
2491 UINT i;
2492 static const DWORD flags[] = {
2493 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2494 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2495 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2496 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2498 if(!pSHGetNameFromIDList)
2500 win_skip("SHGetNameFromIDList missing.\n");
2501 return;
2504 /* This should be available on any platform that passed the above test. */
2505 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2507 if(0)
2509 /* Crashes under win7 */
2510 pSHGetNameFromIDList(NULL, 0, NULL);
2513 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2514 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2516 /* Test the desktop */
2517 hres = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2518 ok(hres == S_OK, "Got 0x%08x\n", hres);
2519 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2520 ok(hres == S_OK, "Got 0x%08x\n", hres);
2521 if(SUCCEEDED(hres))
2523 WCHAR *nameSI, *nameSH;
2524 WCHAR buf[MAX_PATH];
2525 HRESULT hrSI, hrSH, hrSF;
2526 STRRET strret;
2527 IShellFolder *psf;
2528 BOOL res;
2530 SHGetDesktopFolder(&psf);
2531 for(i = 0; flags[i] != -1234; i++)
2533 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2534 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2535 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2536 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2537 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2538 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2540 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2541 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2543 if(SUCCEEDED(hrSF))
2545 StrRetToBufW(&strret, NULL, buf, MAX_PATH);
2546 if(SUCCEEDED(hrSI))
2547 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2548 if(SUCCEEDED(hrSF))
2549 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2551 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2552 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2554 IShellFolder_Release(psf);
2556 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2557 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2558 res = SHGetPathFromIDListW(pidl, buf);
2559 ok(res == TRUE, "Got %d\n", res);
2560 if(SUCCEEDED(hrSI) && res)
2561 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2562 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2564 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2565 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2566 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2568 IShellItem_Release(shellitem);
2570 ILFree(pidl);
2572 /* Test the control panel */
2573 hres = SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2574 ok(hres == S_OK, "Got 0x%08x\n", hres);
2575 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2576 ok(hres == S_OK, "Got 0x%08x\n", hres);
2577 if(SUCCEEDED(hres))
2579 WCHAR *nameSI, *nameSH;
2580 WCHAR buf[MAX_PATH];
2581 HRESULT hrSI, hrSH, hrSF;
2582 STRRET strret;
2583 IShellFolder *psf;
2584 BOOL res;
2586 SHGetDesktopFolder(&psf);
2587 for(i = 0; flags[i] != -1234; i++)
2589 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2590 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2591 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2592 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2593 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2594 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2596 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2597 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2599 if(SUCCEEDED(hrSF))
2601 StrRetToBufW(&strret, NULL, buf, MAX_PATH);
2602 if(SUCCEEDED(hrSI))
2603 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2604 if(SUCCEEDED(hrSF))
2605 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2607 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2608 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2610 IShellFolder_Release(psf);
2612 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2613 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2614 res = SHGetPathFromIDListW(pidl, buf);
2615 ok(res == FALSE, "Got %d\n", res);
2616 if(SUCCEEDED(hrSI) && res)
2617 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2618 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2620 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2621 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2622 "Got 0x%08x\n", hres);
2623 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2625 IShellItem_Release(shellitem);
2627 ILFree(pidl);
2630 static void test_SHGetItemFromDataObject(void)
2632 IShellFolder *psfdesktop;
2633 IShellItem *psi;
2634 IShellView *psv;
2635 HRESULT hres;
2637 if(!pSHGetItemFromDataObject)
2639 win_skip("No SHGetItemFromDataObject.\n");
2640 return;
2643 if(0)
2645 /* Crashes under win7 */
2646 pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2649 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2650 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2652 SHGetDesktopFolder(&psfdesktop);
2654 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2655 ok(hres == S_OK, "got 0x%08x\n", hres);
2656 if(SUCCEEDED(hres))
2658 IEnumIDList *peidl;
2659 IDataObject *pdo;
2660 SHCONTF enum_flags;
2662 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2663 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2664 ok(hres == S_OK, "got 0x%08x\n", hres);
2665 if(SUCCEEDED(hres))
2667 LPITEMIDLIST apidl[5];
2668 UINT count = 0, i;
2670 for(count = 0; count < 5; count++)
2671 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2672 break;
2674 if(count)
2676 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2677 &IID_IDataObject, NULL, (void**)&pdo);
2678 ok(hres == S_OK, "got 0x%08x\n", hres);
2679 if(SUCCEEDED(hres))
2681 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2682 ok(hres == S_OK, "got 0x%08x\n", hres);
2683 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2684 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2685 ok(hres == S_OK, "got 0x%08x\n", hres);
2686 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2687 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2688 ok(hres == S_OK, "got 0x%08x\n", hres);
2689 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2690 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2691 ok(hres == S_OK, "got 0x%08x\n", hres);
2692 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2693 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2694 ok(hres == S_OK, "got 0x%08x\n", hres);
2695 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2697 IDataObject_Release(pdo);
2700 else
2701 skip("No file(s) found - skipping single-file test.\n");
2703 if(count > 1)
2705 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2706 &IID_IDataObject, NULL, (void**)&pdo);
2707 ok(hres == S_OK, "got 0x%08x\n", hres);
2708 if(SUCCEEDED(hres))
2710 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2711 ok(hres == S_OK, "got 0x%08x\n", hres);
2712 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2713 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2714 ok(hres == S_OK, "got 0x%08x\n", hres);
2715 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2716 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2717 ok(hres == S_OK, "got 0x%08x\n", hres);
2718 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2719 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2720 ok(hres == S_OK, "got 0x%08x\n", hres);
2721 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2722 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2723 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2724 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2725 IDataObject_Release(pdo);
2728 else
2729 skip("zero or one file found - skipping multi-file test.\n");
2731 for(i = 0; i < count; i++)
2732 ILFree(apidl[i]);
2734 IEnumIDList_Release(peidl);
2737 IShellView_Release(psv);
2740 IShellFolder_Release(psfdesktop);
2743 static void test_ShellItemCompare(void)
2745 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2746 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2747 IShellFolder *psf_desktop, *psf_current;
2748 LPITEMIDLIST pidl_cwd;
2749 WCHAR curdirW[MAX_PATH];
2750 BOOL failed;
2751 HRESULT hr;
2752 static const WCHAR filesW[][9] = {
2753 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2754 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2755 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2756 int order;
2757 UINT i;
2759 if(!pSHCreateShellItem)
2761 win_skip("SHCreateShellItem missing.\n");
2762 return;
2765 GetCurrentDirectoryW(MAX_PATH, curdirW);
2766 if (!curdirW[0])
2768 skip("Failed to get current directory, skipping.\n");
2769 return;
2772 CreateDirectoryA(".\\a", NULL);
2773 CreateDirectoryA(".\\b", NULL);
2774 CreateDirectoryA(".\\c", NULL);
2775 CreateTestFile(".\\a\\a");
2776 CreateTestFile(".\\a\\b");
2777 CreateTestFile(".\\a\\c");
2778 CreateTestFile(".\\b\\a");
2779 CreateTestFile(".\\b\\b");
2780 CreateTestFile(".\\b\\c");
2781 CreateTestFile(".\\c\\a");
2782 CreateTestFile(".\\c\\b");
2783 CreateTestFile(".\\c\\c");
2785 SHGetDesktopFolder(&psf_desktop);
2786 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2787 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2788 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2789 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2790 IShellFolder_Release(psf_desktop);
2791 ILFree(pidl_cwd);
2793 /* Generate ShellItems for the files */
2794 memset(&psi, 0, sizeof(psi));
2795 failed = FALSE;
2796 for(i = 0; i < 9; i++)
2798 LPITEMIDLIST pidl_testfile = NULL;
2800 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2801 NULL, &pidl_testfile, NULL);
2802 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2803 if(SUCCEEDED(hr))
2805 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2806 ok(hr == S_OK, "Got 0x%08x\n", hr);
2807 ILFree(pidl_testfile);
2809 if(FAILED(hr)) failed = TRUE;
2811 if(failed)
2813 skip("Failed to create all shellitems.\n");
2814 goto cleanup;
2817 /* Generate ShellItems for the folders */
2818 hr = IShellItem_GetParent(psi[0], &psi_a);
2819 ok(hr == S_OK, "Got 0x%08x\n", hr);
2820 if(FAILED(hr)) failed = TRUE;
2821 hr = IShellItem_GetParent(psi[3], &psi_b);
2822 ok(hr == S_OK, "Got 0x%08x\n", hr);
2823 if(FAILED(hr)) failed = TRUE;
2824 hr = IShellItem_GetParent(psi[6], &psi_c);
2825 ok(hr == S_OK, "Got 0x%08x\n", hr);
2826 if(FAILED(hr)) failed = TRUE;
2828 if(failed)
2830 skip("Failed to create shellitems.\n");
2831 goto cleanup;
2834 if(0)
2836 /* Crashes on native (win7, winxp) */
2837 IShellItem_Compare(psi_a, NULL, 0, NULL);
2838 IShellItem_Compare(psi_a, psi_b, 0, NULL);
2839 IShellItem_Compare(psi_a, NULL, 0, &order);
2842 /* Basics */
2843 for(i = 0; i < 9; i++)
2845 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2846 ok(hr == S_OK, "Got 0x%08x\n", hr);
2847 ok(order == 0, "Got order %d\n", order);
2848 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2849 ok(hr == S_OK, "Got 0x%08x\n", hr);
2850 ok(order == 0, "Got order %d\n", order);
2851 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2852 ok(hr == S_OK, "Got 0x%08x\n", hr);
2853 ok(order == 0, "Got order %d\n", order);
2856 /* Order */
2857 /* a\b:a\a , a\b:a\c, a\b:a\b */
2858 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2859 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2860 ok(order == 1, "Got order %d\n", order);
2861 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2862 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2863 ok(order == -1, "Got order %d\n", order);
2864 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2865 ok(hr == S_OK, "Got 0x%08x\n", hr);
2866 ok(order == 0, "Got order %d\n", order);
2868 /* b\b:a\b, b\b:c\b, b\b:c\b */
2869 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2870 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2871 ok(order == 1, "Got order %d\n", order);
2872 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2873 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2874 ok(order == -1, "Got order %d\n", order);
2875 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2876 ok(hr == S_OK, "Got 0x%08x\n", hr);
2877 ok(order == 0, "Got order %d\n", order);
2879 /* b:a\a, b:a\c, b:a\b */
2880 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2881 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2882 todo_wine ok(order == 1, "Got order %d\n", order);
2883 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2884 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2885 todo_wine ok(order == 1, "Got order %d\n", order);
2886 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2887 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2888 todo_wine ok(order == 1, "Got order %d\n", order);
2890 /* b:c\a, b:c\c, b:c\b */
2891 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2892 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2893 ok(order == -1, "Got order %d\n", order);
2894 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2895 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2896 ok(order == -1, "Got order %d\n", order);
2897 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2898 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2899 ok(order == -1, "Got order %d\n", order);
2901 /* a\b:a\a , a\b:a\c, a\b:a\b */
2902 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2903 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2904 ok(order == 1, "Got order %d\n", order);
2905 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2906 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2907 ok(order == -1, "Got order %d\n", order);
2908 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2909 ok(hr == S_OK, "Got 0x%08x\n", hr);
2910 ok(order == 0, "Got order %d\n", order);
2912 /* b\b:a\b, b\b:c\b, b\b:c\b */
2913 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2914 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2915 ok(order == 1, "Got order %d\n", order);
2916 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2917 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2918 ok(order == -1, "Got order %d\n", order);
2919 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2920 ok(hr == S_OK, "Got 0x%08x\n", hr);
2921 ok(order == 0, "Got order %d\n", order);
2923 /* b:a\a, b:a\c, b:a\b */
2924 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2925 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2926 todo_wine ok(order == 1, "Got order %d\n", order);
2927 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2928 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2929 todo_wine ok(order == 1, "Got order %d\n", order);
2930 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2931 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2932 todo_wine ok(order == 1, "Got order %d\n", order);
2934 /* b:c\a, b:c\c, b:c\b */
2935 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2936 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2937 ok(order == -1, "Got order %d\n", order);
2938 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2939 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2940 ok(order == -1, "Got order %d\n", order);
2941 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2942 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2943 ok(order == -1, "Got order %d\n", order);
2945 cleanup:
2946 IShellFolder_Release(psf_current);
2948 DeleteFileA(".\\a\\a");
2949 DeleteFileA(".\\a\\b");
2950 DeleteFileA(".\\a\\c");
2951 DeleteFileA(".\\b\\a");
2952 DeleteFileA(".\\b\\b");
2953 DeleteFileA(".\\b\\c");
2954 DeleteFileA(".\\c\\a");
2955 DeleteFileA(".\\c\\b");
2956 DeleteFileA(".\\c\\c");
2957 RemoveDirectoryA(".\\a");
2958 RemoveDirectoryA(".\\b");
2959 RemoveDirectoryA(".\\c");
2961 if(psi_a) IShellItem_Release(psi_a);
2962 if(psi_b) IShellItem_Release(psi_b);
2963 if(psi_c) IShellItem_Release(psi_c);
2965 for(i = 0; i < 9; i++)
2966 if(psi[i]) IShellItem_Release(psi[i]);
2969 /**************************************************************/
2970 /* IUnknown implementation for counting QueryInterface calls. */
2971 typedef struct {
2972 IUnknown IUnknown_iface;
2973 struct if_count {
2974 REFIID id;
2975 LONG count;
2976 } *ifaces;
2977 LONG unknown;
2978 } IUnknownImpl;
2980 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
2982 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
2985 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2987 IUnknownImpl *This = impl_from_IUnknown(iunk);
2988 UINT i;
2989 BOOL found = FALSE;
2990 for(i = 0; This->ifaces[i].id != NULL; i++)
2992 if(IsEqualIID(This->ifaces[i].id, riid))
2994 This->ifaces[i].count++;
2995 found = TRUE;
2996 break;
2999 if(!found)
3000 This->unknown++;
3001 return E_NOINTERFACE;
3004 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
3006 return 2;
3009 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3011 return 1;
3014 static const IUnknownVtbl vt_IUnknown = {
3015 unk_fnQueryInterface,
3016 unk_fnAddRef,
3017 unk_fnRelease
3020 static void test_SHGetIDListFromObject(void)
3022 IUnknownImpl *punkimpl;
3023 IShellFolder *psfdesktop;
3024 IShellView *psv;
3025 LPITEMIDLIST pidl, pidl_desktop;
3026 HRESULT hres;
3027 UINT i;
3028 struct if_count ifaces[] =
3029 { {&IID_IPersistIDList, 0},
3030 {&IID_IPersistFolder2, 0},
3031 {&IID_IDataObject, 0},
3032 {&IID_IParentAndItem, 0},
3033 {&IID_IFolderView, 0},
3034 {NULL, 0} };
3036 if(!pSHGetIDListFromObject)
3038 win_skip("SHGetIDListFromObject missing.\n");
3039 return;
3042 if(0)
3044 /* Crashes native */
3045 pSHGetIDListFromObject(NULL, NULL);
3046 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3049 hres = pSHGetIDListFromObject(NULL, &pidl);
3050 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3052 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3053 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3054 punkimpl->ifaces = ifaces;
3055 punkimpl->unknown = 0;
3057 hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3058 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3059 ok(ifaces[0].count, "interface not requested.\n");
3060 ok(ifaces[1].count, "interface not requested.\n");
3061 ok(ifaces[2].count, "interface not requested.\n");
3062 todo_wine
3063 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3064 "interface not requested.\n");
3065 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3066 "interface not requested.\n");
3068 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3069 HeapFree(GetProcessHeap(), 0, punkimpl);
3071 pidl_desktop = NULL;
3072 SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3073 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3075 SHGetDesktopFolder(&psfdesktop);
3077 /* Test IShellItem */
3078 if(pSHCreateShellItem)
3080 IShellItem *shellitem;
3081 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3082 ok(hres == S_OK, "got 0x%08x\n", hres);
3083 if(SUCCEEDED(hres))
3085 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3086 ok(hres == S_OK, "got 0x%08x\n", hres);
3087 if(SUCCEEDED(hres))
3089 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3090 ILFree(pidl);
3092 IShellItem_Release(shellitem);
3095 else
3096 skip("no SHCreateShellItem.\n");
3098 /* Test IShellFolder */
3099 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3100 ok(hres == S_OK, "got 0x%08x\n", hres);
3101 if(SUCCEEDED(hres))
3103 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3104 ILFree(pidl);
3107 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3108 ok(hres == S_OK, "got 0x%08x\n", hres);
3109 if(SUCCEEDED(hres))
3111 IEnumIDList *peidl;
3112 IDataObject *pdo;
3113 SHCONTF enum_flags;
3115 /* Test IFolderView */
3116 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3117 ok(hres == S_OK, "got 0x%08x\n", hres);
3118 if(SUCCEEDED(hres))
3120 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3121 ILFree(pidl);
3124 /* Test IDataObject */
3125 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3126 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3127 ok(hres == S_OK, "got 0x%08x\n", hres);
3128 if(SUCCEEDED(hres))
3130 LPITEMIDLIST apidl[5];
3131 UINT count = 0;
3132 for(count = 0; count < 5; count++)
3133 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3134 break;
3136 if(count)
3138 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3139 &IID_IDataObject, NULL, (void**)&pdo);
3140 ok(hres == S_OK, "got 0x%08x\n", hres);
3141 if(SUCCEEDED(hres))
3143 pidl = (void*)0xDEADBEEF;
3144 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3145 ok(hres == S_OK, "got 0x%08x\n", hres);
3146 ok(pidl != NULL, "pidl is NULL.\n");
3147 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3148 ILFree(pidl);
3150 IDataObject_Release(pdo);
3153 else
3154 skip("No files found - skipping single-file test.\n");
3156 if(count > 1)
3158 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3159 &IID_IDataObject, NULL, (void**)&pdo);
3160 ok(hres == S_OK, "got 0x%08x\n", hres);
3161 if(SUCCEEDED(hres))
3163 pidl = (void*)0xDEADBEEF;
3164 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3165 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3166 "got 0x%08x\n", hres);
3167 ok(pidl == NULL, "pidl is not NULL.\n");
3169 IDataObject_Release(pdo);
3172 else
3173 skip("zero or one file found - skipping multi-file test.\n");
3175 for(i = 0; i < count; i++)
3176 ILFree(apidl[i]);
3178 IEnumIDList_Release(peidl);
3181 IShellView_Release(psv);
3184 IShellFolder_Release(psfdesktop);
3185 ILFree(pidl_desktop);
3188 static void test_SHGetItemFromObject(void)
3190 IUnknownImpl *punkimpl;
3191 IShellFolder *psfdesktop;
3192 LPITEMIDLIST pidl;
3193 IShellItem *psi;
3194 IUnknown *punk;
3195 HRESULT hres;
3196 struct if_count ifaces[] =
3197 { {&IID_IPersistIDList, 0},
3198 {&IID_IPersistFolder2, 0},
3199 {&IID_IDataObject, 0},
3200 {&IID_IParentAndItem, 0},
3201 {&IID_IFolderView, 0},
3202 {NULL, 0} };
3204 if(!pSHGetItemFromObject)
3206 skip("No SHGetItemFromObject.\n");
3207 return;
3210 SHGetDesktopFolder(&psfdesktop);
3212 if(0)
3214 /* Crashes with Windows 7 */
3215 pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3216 pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3217 pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3220 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3221 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3223 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3224 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3225 punkimpl->ifaces = ifaces;
3226 punkimpl->unknown = 0;
3228 /* The same as SHGetIDListFromObject */
3229 hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3230 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3231 ok(ifaces[0].count, "interface not requested.\n");
3232 ok(ifaces[1].count, "interface not requested.\n");
3233 ok(ifaces[2].count, "interface not requested.\n");
3234 todo_wine
3235 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3236 "interface not requested.\n");
3237 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3238 "interface not requested.\n");
3240 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3241 HeapFree(GetProcessHeap(), 0, punkimpl);
3243 /* Test IShellItem */
3244 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3245 ok(hres == S_OK, "Got 0x%08x\n", hres);
3246 if(SUCCEEDED(hres))
3248 IShellItem *psi2;
3249 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3250 ok(hres == S_OK, "Got 0x%08x\n", hres);
3251 if(SUCCEEDED(hres))
3253 todo_wine
3254 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3255 IShellItem_Release(psi2);
3257 IShellItem_Release(psi);
3260 IShellFolder_Release(psfdesktop);
3263 static void test_SHCreateShellItemArray(void)
3265 IShellFolder *pdesktopsf, *psf;
3266 IShellItemArray *psia;
3267 IEnumIDList *peidl;
3268 HRESULT hr;
3269 WCHAR cTestDirW[MAX_PATH];
3270 LPITEMIDLIST pidl_testdir, pidl;
3271 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3273 if(!pSHCreateShellItemArray) {
3274 skip("No pSHCreateShellItemArray!\n");
3275 return;
3278 if(0)
3280 /* Crashes under native */
3281 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3282 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3283 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3284 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3287 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3288 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3290 SHGetDesktopFolder(&pdesktopsf);
3291 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3292 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3294 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3295 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3297 SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3298 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3299 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3300 ILFree(pidl);
3302 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3303 myPathAddBackslashW(cTestDirW);
3304 lstrcatW(cTestDirW, testdirW);
3306 CreateFilesFolders();
3308 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3309 ok(hr == S_OK, "got 0x%08x\n", hr);
3310 if(SUCCEEDED(hr))
3312 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3313 (void**)&psf);
3314 ok(hr == S_OK, "Got 0x%08x\n", hr);
3316 IShellFolder_Release(pdesktopsf);
3318 if(FAILED(hr))
3320 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3321 ILFree(pidl_testdir);
3322 Cleanup();
3323 return;
3326 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3327 ok(hr == S_OK, "Got %08x\n", hr);
3328 if(SUCCEEDED(hr))
3330 LPITEMIDLIST apidl[5];
3331 UINT done, numitems, i;
3333 for(done = 0; done < 5; done++)
3334 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3335 break;
3336 ok(done == 5, "Got %d pidls\n", done);
3337 IEnumIDList_Release(peidl);
3339 /* Create a ShellItemArray */
3340 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3341 ok(hr == S_OK, "Got 0x%08x\n", hr);
3342 if(SUCCEEDED(hr))
3344 IShellItem *psi;
3346 if(0)
3348 /* Crashes in Windows 7 */
3349 IShellItemArray_GetCount(psia, NULL);
3352 IShellItemArray_GetCount(psia, &numitems);
3353 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3355 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3356 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3358 /* Compare all the items */
3359 for(i = 0; i < numitems; i++)
3361 LPITEMIDLIST pidl_abs;
3362 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3364 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3365 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3366 if(SUCCEEDED(hr))
3368 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3369 ok(hr == S_OK, "Got 0x%08x\n", hr);
3370 if(SUCCEEDED(hr))
3372 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3373 ILFree(pidl);
3375 IShellItem_Release(psi);
3377 ILFree(pidl_abs);
3379 for(i = 0; i < done; i++)
3380 ILFree(apidl[i]);
3381 IShellItemArray_Release(psia);
3385 /* SHCreateShellItemArrayFromShellItem */
3386 if(pSHCreateShellItemArrayFromShellItem)
3388 IShellItem *psi;
3390 if(0)
3392 /* Crashes under Windows 7 */
3393 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3394 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3395 pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3398 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3399 ok(hr == S_OK, "Got 0x%08x\n", hr);
3400 if(SUCCEEDED(hr))
3402 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3403 ok(hr == S_OK, "Got 0x%08x\n", hr);
3404 if(SUCCEEDED(hr))
3406 IShellItem *psi2;
3407 UINT count;
3408 hr = IShellItemArray_GetCount(psia, &count);
3409 ok(hr == S_OK, "Got 0x%08x\n", hr);
3410 ok(count == 1, "Got count %d\n", count);
3411 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3412 ok(hr == S_OK, "Got 0x%08x\n", hr);
3413 todo_wine
3414 ok(psi != psi2, "ShellItems are of the same instance.\n");
3415 if(SUCCEEDED(hr))
3417 LPITEMIDLIST pidl1, pidl2;
3418 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3419 ok(hr == S_OK, "Got 0x%08x\n", hr);
3420 ok(pidl1 != NULL, "pidl1 was null.\n");
3421 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3422 ok(hr == S_OK, "Got 0x%08x\n", hr);
3423 ok(pidl2 != NULL, "pidl2 was null.\n");
3424 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3425 ILFree(pidl1);
3426 ILFree(pidl2);
3427 IShellItem_Release(psi2);
3429 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3430 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3431 IShellItemArray_Release(psia);
3433 IShellItem_Release(psi);
3436 else
3437 skip("No SHCreateShellItemArrayFromShellItem.\n");
3439 if(pSHCreateShellItemArrayFromDataObject)
3441 IShellView *psv;
3443 if(0)
3445 /* Crashes under Windows 7 */
3446 pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3448 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3449 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3451 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3452 ok(hr == S_OK, "got 0x%08x\n", hr);
3453 if(SUCCEEDED(hr))
3455 IEnumIDList *peidl;
3456 IDataObject *pdo;
3457 SHCONTF enum_flags;
3459 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3460 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3461 ok(hr == S_OK, "got 0x%08x\n", hr);
3462 if(SUCCEEDED(hr))
3464 LPITEMIDLIST apidl[5];
3465 UINT count, i;
3467 for(count = 0; count < 5; count++)
3468 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3469 break;
3470 ok(count == 5, "Got %d\n", count);
3472 if(count)
3474 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3475 &IID_IDataObject, NULL, (void**)&pdo);
3476 ok(hr == S_OK, "Got 0x%08x\n", hr);
3477 if(SUCCEEDED(hr))
3479 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3480 (void**)&psia);
3481 ok(hr == S_OK, "Got 0x%08x\n", hr);
3482 if(SUCCEEDED(hr))
3484 UINT count_sia, i;
3485 hr = IShellItemArray_GetCount(psia, &count_sia);
3486 ok(hr == S_OK, "Got 0x%08x\n", hr);
3487 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3488 for(i = 0; i < count_sia; i++)
3490 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3491 IShellItem *psi;
3492 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3493 ok(hr == S_OK, "Got 0x%08x\n", hr);
3494 if(SUCCEEDED(hr))
3496 LPITEMIDLIST pidl;
3497 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3498 ok(hr == S_OK, "Got 0x%08x\n", hr);
3499 ok(pidl != NULL, "pidl as NULL.\n");
3500 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3501 ILFree(pidl);
3502 IShellItem_Release(psi);
3504 ILFree(pidl_abs);
3507 IShellItemArray_Release(psia);
3510 IDataObject_Release(pdo);
3512 for(i = 0; i < count; i++)
3513 ILFree(apidl[i]);
3515 else
3516 skip("No files found - skipping test.\n");
3518 IEnumIDList_Release(peidl);
3520 IShellView_Release(psv);
3523 else
3524 skip("No SHCreateShellItemArrayFromDataObject.\n");
3526 if(pSHCreateShellItemArrayFromIDLists)
3528 WCHAR test1W[] = {'t','e','s','t','1','.','t','x','t',0};
3529 WCHAR test1pathW[MAX_PATH];
3530 LPITEMIDLIST pidltest1;
3531 LPCITEMIDLIST pidl_array[2];
3533 if(0)
3535 /* Crashes */
3536 hr = pSHCreateShellItemArrayFromIDLists(0, NULL, NULL);
3539 psia = (void*)0xdeadbeef;
3540 hr = pSHCreateShellItemArrayFromIDLists(0, NULL, &psia);
3541 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3542 ok(psia == NULL, "Got %p\n", psia);
3544 psia = (void*)0xdeadbeef;
3545 hr = pSHCreateShellItemArrayFromIDLists(0, pidl_array, &psia);
3546 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3547 ok(psia == NULL, "Got %p\n", psia);
3549 psia = (void*)0xdeadbeef;
3550 pidl_array[0] = NULL;
3551 hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3552 todo_wine ok(hr == E_OUTOFMEMORY, "Got 0x%08x\n", hr);
3553 ok(psia == NULL, "Got %p\n", psia);
3555 psia = (void*)0xdeadbeef;
3556 pidl_array[0] = pidl_testdir;
3557 pidl_array[1] = NULL;
3558 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3559 todo_wine ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Vista */, "Got 0x%08x\n", hr);
3560 todo_wine ok(psia != NULL || broken(psia == NULL) /* Vista */, "Got %p\n", psia);
3561 if(SUCCEEDED(hr))
3563 IShellItem *psi;
3564 UINT count = 0;
3566 hr = IShellItemArray_GetCount(psia, &count);
3567 ok(hr == S_OK, "Got 0x%08x\n", hr);
3568 ok(count == 2, "Got %d\n", count);
3570 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3571 ok(hr == S_OK, "Got 0x%08x\n", hr);
3572 if(SUCCEEDED(hr))
3574 LPWSTR path;
3575 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3576 ok(hr == S_OK, "Got 0x%08x\n", hr);
3577 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3578 if(SUCCEEDED(hr))
3579 CoTaskMemFree(path);
3581 IShellItem_Release(psi);
3584 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3585 ok(hr == S_OK, "Got 0x%08x\n", hr);
3586 if(SUCCEEDED(hr))
3588 LPWSTR path;
3589 WCHAR desktoppath[MAX_PATH];
3590 BOOL result;
3592 result = SHGetSpecialFolderPathW(NULL, desktoppath, CSIDL_DESKTOPDIRECTORY, FALSE);
3593 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
3595 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3596 ok(hr == S_OK, "Got 0x%08x\n", hr);
3597 ok(!lstrcmpW(path, desktoppath), "Got %s\n", wine_dbgstr_w(path));
3598 if(SUCCEEDED(hr))
3599 CoTaskMemFree(path);
3601 IShellItem_Release(psi);
3605 IShellItemArray_Release(psia);
3609 /* Single pidl */
3610 psia = (void*)0xdeadbeef;
3611 pidl_array[0] = pidl_testdir;
3612 hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3613 ok(hr == S_OK, "Got 0x%08x\n", hr);
3614 if(SUCCEEDED(hr))
3616 IShellItem *psi;
3617 UINT count = 0;
3619 hr = IShellItemArray_GetCount(psia, &count);
3620 ok(hr == S_OK, "Got 0x%08x\n", hr);
3621 ok(count == 1, "Got %d\n", count);
3623 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3624 ok(hr == S_OK, "Got 0x%08x\n", hr);
3625 if(SUCCEEDED(hr))
3627 LPWSTR path;
3628 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3629 ok(hr == S_OK, "Got 0x%08x\n", hr);
3630 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3631 if(SUCCEEDED(hr))
3632 CoTaskMemFree(path);
3634 IShellItem_Release(psi);
3637 IShellItemArray_Release(psia);
3641 lstrcpyW(test1pathW, cTestDirW);
3642 myPathAddBackslashW(test1pathW);
3643 lstrcatW(test1pathW, test1W);
3645 SHGetDesktopFolder(&pdesktopsf);
3647 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, test1pathW, NULL, &pidltest1, NULL);
3648 ok(hr == S_OK, "Got 0x%08x\n", hr);
3649 if(SUCCEEDED(hr))
3651 psia = (void*)0xdeadbeef;
3652 pidl_array[0] = pidl_testdir;
3653 pidl_array[1] = pidltest1;
3654 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3655 ok(hr == S_OK, "Got 0x%08x\n", hr);
3656 if(SUCCEEDED(hr))
3658 IShellItem *psi;
3659 UINT count = 0;
3661 hr = IShellItemArray_GetCount(psia, &count);
3662 ok(hr == S_OK, "Got 0x%08x\n", hr);
3663 ok(count == 2, "Got %d\n", count);
3665 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3666 ok(hr == S_OK, "Got 0x%08x\n", hr);
3667 if(SUCCEEDED(hr))
3669 LPWSTR path;
3670 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3671 ok(hr == S_OK, "Got 0x%08x\n", hr);
3672 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3673 if(SUCCEEDED(hr))
3674 CoTaskMemFree(path);
3676 IShellItem_Release(psi);
3679 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3680 ok(hr == S_OK, "Got 0x%08x\n", hr);
3681 if(SUCCEEDED(hr))
3683 LPWSTR path;
3684 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3685 ok(hr == S_OK, "Got 0x%08x\n", hr);
3686 ok(!lstrcmpW(path, test1pathW), "Got %s\n", wine_dbgstr_w(path));
3687 if(SUCCEEDED(hr))
3688 CoTaskMemFree(path);
3690 IShellItem_Release(psi);
3694 IShellItemArray_Release(psia);
3697 ILFree(pidltest1);
3700 IShellFolder_Release(pdesktopsf);
3702 else
3703 skip("No SHCreateShellItemArrayFromIDLists.\n");
3705 IShellFolder_Release(psf);
3706 ILFree(pidl_testdir);
3707 Cleanup();
3710 static void test_ShellItemArrayEnumItems(void)
3712 IShellFolder *pdesktopsf, *psf;
3713 IEnumIDList *peidl;
3714 WCHAR cTestDirW[MAX_PATH];
3715 HRESULT hr;
3716 LPITEMIDLIST pidl_testdir;
3717 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3719 if(!pSHCreateShellItemArray)
3721 win_skip("No SHCreateShellItemArray, skipping test...\n");
3722 return;
3725 CreateFilesFolders();
3727 SHGetDesktopFolder(&pdesktopsf);
3729 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3730 myPathAddBackslashW(cTestDirW);
3731 lstrcatW(cTestDirW, testdirW);
3733 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3734 ok(hr == S_OK, "got 0x%08x\n", hr);
3735 if(SUCCEEDED(hr))
3737 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3738 (void**)&psf);
3739 ok(hr == S_OK, "Got 0x%08x\n", hr);
3740 ILFree(pidl_testdir);
3742 IShellFolder_Release(pdesktopsf);
3743 if (FAILED(hr)) return;
3745 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3746 ok(hr == S_OK, "Got %08x\n", hr);
3747 if(SUCCEEDED(hr))
3749 IShellItemArray *psia;
3750 LPITEMIDLIST apidl[5];
3751 UINT done, numitems, i;
3753 for(done = 0; done < 5; done++)
3754 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3755 break;
3756 ok(done == 5, "Got %d pidls\n", done);
3757 IEnumIDList_Release(peidl);
3759 /* Create a ShellItemArray */
3760 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3761 ok(hr == S_OK, "Got 0x%08x\n", hr);
3762 if(SUCCEEDED(hr))
3764 IEnumShellItems *iesi;
3765 IShellItem *my_array[10];
3766 ULONG fetched;
3768 IShellItemArray_GetCount(psia, &numitems);
3769 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3771 iesi = NULL;
3772 hr = IShellItemArray_EnumItems(psia, &iesi);
3773 ok(hr == S_OK, "Got 0x%08x\n", hr);
3774 ok(iesi != NULL, "Got NULL\n");
3775 if(SUCCEEDED(hr))
3777 IEnumShellItems *iesi2;
3779 /* This should fail according to the documentation and Win7+ */
3780 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3781 hr = IEnumShellItems_Next(iesi, 2, my_array, NULL);
3782 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
3783 for(i = 0; i < 2; i++)
3785 ok(my_array[i] == (void*)0xdeadbeef ||
3786 broken(my_array[i] != (void*)0xdeadbeef && my_array[i] != NULL), /* Vista */
3787 "Got %p (%d)\n", my_array[i], i);
3789 if(my_array[i] != (void*)0xdeadbeef)
3790 IShellItem_Release(my_array[i]);
3792 ok(my_array[2] == (void*)0xdeadbeef, "Got %p\n", my_array[2]);
3794 IEnumShellItems_Reset(iesi);
3795 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3796 hr = IEnumShellItems_Next(iesi, 1, my_array, NULL);
3797 ok(hr == S_OK, "Got 0x%08x\n", hr);
3798 ok(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef, "Got %p\n", my_array[0]);
3799 if(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef)
3800 IShellItem_Release(my_array[0]);
3801 ok(my_array[1] == (void*)0xdeadbeef, "Got %p\n", my_array[1]);
3803 IEnumShellItems_Reset(iesi);
3804 fetched = 0;
3805 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3806 hr = IEnumShellItems_Next(iesi, numitems, my_array, &fetched);
3807 ok(hr == S_OK, "Got 0x%08x\n", hr);
3808 ok(fetched == numitems, "Got %d\n", fetched);
3809 for(i = 0;i < numitems; i++)
3811 ok(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef,
3812 "Got %p at %d\n", my_array[i], i);
3814 if(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef)
3815 IShellItem_Release(my_array[i]);
3817 ok(my_array[i] == (void*)0xdeadbeef, "Got %p\n", my_array[i]);
3819 /* Compare all the items */
3820 IEnumShellItems_Reset(iesi);
3821 for(i = 0; i < numitems; i++)
3823 IShellItem *psi;
3824 int order;
3826 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3827 ok(hr == S_OK, "Got 0x%08x\n", hr);
3828 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
3829 ok(hr == S_OK, "Got 0x%08x\n", hr);
3830 ok(fetched == 1, "Got %d\n", fetched);
3832 hr = IShellItem_Compare(psi, my_array[0], 0, &order);
3833 ok(hr == S_OK, "Got 0x%08x\n", hr);
3834 ok(order == 0, "Got %d\n", order);
3836 IShellItem_Release(psi);
3837 IShellItem_Release(my_array[0]);
3840 my_array[0] = (void*)0xdeadbeef;
3841 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
3842 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3843 ok(fetched == 0, "Got %d\n", fetched);
3844 ok(my_array[0] == (void*)0xdeadbeef, "Got %p\n", my_array[0]);
3846 /* Cloning not implemented anywhere */
3847 iesi2 = (void*)0xdeadbeef;
3848 hr = IEnumShellItems_Clone(iesi, &iesi2);
3849 ok(hr == E_NOTIMPL, "Got 0x%08x\n", hr);
3850 ok(iesi2 == NULL || broken(iesi2 == (void*)0xdeadbeef) /* Vista */, "Got %p\n", iesi2);
3852 IEnumShellItems_Release(iesi);
3855 IShellItemArray_Release(psia);
3858 for(i = 0; i < done; i++)
3859 ILFree(apidl[i]);
3864 static void test_ShellItemBindToHandler(void)
3866 IShellItem *psi;
3867 LPITEMIDLIST pidl_desktop;
3868 HRESULT hr;
3870 if(!pSHCreateShellItem)
3872 skip("SHCreateShellItem missing.\n");
3873 return;
3876 hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3877 ok(hr == S_OK, "Got 0x%08x\n", hr);
3878 if(SUCCEEDED(hr))
3880 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3881 ok(hr == S_OK, "Got 0x%08x\n", hr);
3883 if(SUCCEEDED(hr))
3885 IPersistFolder2 *ppf2;
3886 IUnknown *punk;
3888 if(0)
3890 /* Crashes under Windows 7 */
3891 IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3892 IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3894 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3895 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3897 /* BHID_SFObject */
3898 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3899 ok(hr == S_OK, "Got 0x%08x\n", hr);
3900 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3901 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3902 ok(hr == S_OK, "Got 0x%08x\n", hr);
3903 if(SUCCEEDED(hr))
3905 LPITEMIDLIST pidl_tmp;
3906 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3907 ok(hr == S_OK, "Got 0x%08x\n", hr);
3908 if(SUCCEEDED(hr))
3910 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3911 ILFree(pidl_tmp);
3913 IPersistFolder2_Release(ppf2);
3916 /* BHID_SFUIObject */
3917 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3918 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3919 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3920 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3921 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3922 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3924 /* BHID_DataObject */
3925 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3926 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3927 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3929 todo_wine
3931 /* BHID_SFViewObject */
3932 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3933 ok(hr == S_OK, "Got 0x%08x\n", hr);
3934 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3935 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3936 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3937 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3939 /* BHID_Storage */
3940 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3941 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3942 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3943 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3944 ok(hr == S_OK, "Got 0x%08x\n", hr);
3945 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3947 /* BHID_Stream */
3948 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3949 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3950 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3951 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3952 ok(hr == S_OK, "Got 0x%08x\n", hr);
3953 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3955 /* BHID_StorageEnum */
3956 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3957 ok(hr == S_OK, "Got 0x%08x\n", hr);
3958 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3960 /* BHID_Transfer
3961 ITransferSource and ITransferDestination are accessible starting from Vista, IUnknown is
3962 supported starting from Win8. */
3963 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferSource, (void**)&punk);
3964 ok(hr == S_OK || broken(FAILED(hr)) /* pre-Vista */, "Got 0x%08x\n", hr);
3965 if(SUCCEEDED(hr))
3967 IUnknown_Release(punk);
3969 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferDestination, (void**)&punk);
3970 ok(hr == S_OK, "Got 0x%08x\n", hr);
3971 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3973 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3974 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Win8 */, "Got 0x%08x\n", hr);
3975 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3978 /* BHID_EnumItems */
3979 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3980 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3981 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3983 /* BHID_Filter */
3984 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3985 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3986 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3988 /* BHID_LinkTargetItem */
3989 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3990 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3991 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3992 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3993 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3994 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3996 /* BHID_PropertyStore */
3997 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3998 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3999 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4000 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
4001 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4002 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4004 /* BHID_ThumbnailHandler */
4005 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
4006 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4007 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4009 /* BHID_AssociationArray */
4010 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
4011 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4012 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4014 /* BHID_EnumAssocHandlers */
4015 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
4016 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
4017 if(SUCCEEDED(hr)) IUnknown_Release(punk);
4020 IShellItem_Release(psi);
4022 else
4023 skip("Failed to create ShellItem.\n");
4025 ILFree(pidl_desktop);
4028 static void test_ShellItemGetAttributes(void)
4030 IShellItem *psi, *psi_folder1, *psi_file1;
4031 IShellFolder *pdesktopsf;
4032 LPITEMIDLIST pidl_desktop, pidl;
4033 SFGAOF sfgao;
4034 HRESULT hr;
4035 WCHAR curdirW[MAX_PATH];
4036 WCHAR buf[MAX_PATH];
4037 static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4038 static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4040 if(!pSHCreateShellItem)
4042 skip("SHCreateShellItem missing.\n");
4043 return;
4046 hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
4047 ok(hr == S_OK, "Got 0x%08x\n", hr);
4048 if(SUCCEEDED(hr))
4050 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
4051 ok(hr == S_OK, "Got 0x%08x\n", hr);
4052 ILFree(pidl_desktop);
4054 if(FAILED(hr))
4056 skip("Skipping tests.\n");
4057 return;
4060 if(0)
4062 /* Crashes on native (Win 7) */
4063 IShellItem_GetAttributes(psi, 0, NULL);
4066 /* Test GetAttributes on the desktop folder. */
4067 sfgao = 0xdeadbeef;
4068 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
4069 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
4070 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
4072 IShellItem_Release(psi);
4074 CreateFilesFolders();
4076 SHGetDesktopFolder(&pdesktopsf);
4078 GetCurrentDirectoryW(MAX_PATH, curdirW);
4079 myPathAddBackslashW(curdirW);
4081 lstrcpyW(buf, curdirW);
4082 lstrcatW(buf, testdir1W);
4083 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4084 ok(hr == S_OK, "got 0x%08x\n", hr);
4085 hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_folder1);
4086 ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4087 ILFree(pidl);
4089 lstrcpyW(buf, curdirW);
4090 lstrcatW(buf, testfile1W);
4091 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4092 ok(hr == S_OK, "got 0x%08x\n", hr);
4093 hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_file1);
4094 ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4095 ILFree(pidl);
4097 IShellFolder_Release(pdesktopsf);
4099 sfgao = 0xdeadbeef;
4100 hr = IShellItem_GetAttributes(psi_folder1, 0, &sfgao);
4101 ok(hr == S_OK, "Got 0x%08x\n", hr);
4102 ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4104 sfgao = 0xdeadbeef;
4105 hr = IShellItem_GetAttributes(psi_folder1, SFGAO_FOLDER, &sfgao);
4106 ok(hr == S_OK, "Got 0x%08x\n", hr);
4107 ok(sfgao == SFGAO_FOLDER, "Got 0x%08x\n", sfgao);
4109 sfgao = 0xdeadbeef;
4110 hr = IShellItem_GetAttributes(psi_file1, SFGAO_FOLDER, &sfgao);
4111 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
4112 ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4114 IShellItem_Release(psi_folder1);
4115 IShellItem_Release(psi_file1);
4117 Cleanup();
4120 static void test_ShellItemArrayGetAttributes(void)
4122 IShellItemArray *psia_files, *psia_folders1, *psia_folders2, *psia_all;
4123 IShellFolder *pdesktopsf;
4124 LPCITEMIDLIST pidl_array[5];
4125 SFGAOF attr;
4126 HRESULT hr;
4127 WCHAR curdirW[MAX_PATH];
4128 WCHAR buf[MAX_PATH];
4129 UINT i;
4130 static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4131 static const WCHAR testdir2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','2',0};
4132 static const WCHAR testdir3W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','3',0};
4133 static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4134 static const WCHAR testfile2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','2','.','t','x','t',0};
4135 static const WCHAR *testfilesW[5] = { testdir1W, testdir2W, testdir3W, testfile1W, testfile2W };
4137 if(!pSHCreateShellItemArrayFromShellItem)
4139 win_skip("No SHCreateShellItemArrayFromShellItem, skipping test...\n");
4140 return;
4143 CreateFilesFolders();
4144 CreateDirectoryA(".\\testdir\\testdir3", NULL);
4146 SHGetDesktopFolder(&pdesktopsf);
4148 GetCurrentDirectoryW(MAX_PATH, curdirW);
4149 myPathAddBackslashW(curdirW);
4151 for(i = 0; i < 5; i++)
4153 lstrcpyW(buf, curdirW);
4154 lstrcatW(buf, testfilesW[i]);
4155 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, (LPITEMIDLIST*)&pidl_array[i], NULL);
4156 ok(hr == S_OK, "got 0x%08x\n", hr);
4158 IShellFolder_Release(pdesktopsf);
4160 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia_folders1);
4161 ok(hr == S_OK, "got 0x%08x\n", hr);
4162 hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[1], &psia_folders2);
4163 ok(hr == S_OK, "got 0x%08x\n", hr);
4164 hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[3], &psia_files);
4165 ok(hr == S_OK, "got 0x%08x\n", hr);
4166 hr = pSHCreateShellItemArrayFromIDLists(4, &pidl_array[1], &psia_all); /* All except the first */
4167 ok(hr == S_OK, "got 0x%08x\n", hr);
4169 for(i = 0; i < 5; i++)
4170 ILFree((LPITEMIDLIST)pidl_array[i]);
4172 /* [testfolder/, testfolder/testfolder2] seems to break in Vista */
4173 attr = 0xdeadbeef;
4174 hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4175 ok(hr == S_OK || broken(hr == E_UNEXPECTED) /* Vista */, "Got 0x%08x\n", hr);
4176 ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4177 attr = 0xdeadbeef;
4178 hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4179 ok(hr == S_OK || broken(hr == E_UNEXPECTED) /* Vista */, "Got 0x%08x\n", hr);
4180 ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4182 /* [testfolder/testfolder2, testfolder/testfolder3] works */
4183 attr = 0xdeadbeef;
4184 hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4185 ok(hr == S_OK, "Got 0x%08x\n", hr);
4186 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4187 attr = 0xdeadbeef;
4188 hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4189 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4190 ok(attr == 0, "Got 0x%08x\n", attr);
4191 attr = 0xdeadbeef;
4192 hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4193 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4194 ok(attr == 0, "Got 0x%08x\n", attr);
4195 attr = 0xdeadbeef;
4196 hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4197 ok(hr == S_OK, "Got 0x%08x\n", hr);
4198 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4199 attr = 0xdeadbeef;
4200 hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4201 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4202 ok(attr == 0, "Got 0x%08x\n", attr);
4203 attr = 0xdeadbeef;
4204 hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4205 ok(hr == S_OK, "Got 0x%08x\n", hr);
4206 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4208 IShellItemArray_Release(psia_folders1);
4209 IShellItemArray_Release(psia_folders2);
4210 IShellItemArray_Release(psia_files);
4211 IShellItemArray_Release(psia_all);
4213 RemoveDirectoryA(".\\testdir\\testdir3");
4214 Cleanup();
4217 static void test_SHParseDisplayName(void)
4219 LPITEMIDLIST pidl1, pidl2;
4220 IShellFolder *desktop;
4221 WCHAR dirW[MAX_PATH];
4222 WCHAR nameW[10];
4223 HRESULT hr;
4224 BOOL ret, is_wow64;
4226 if (0)
4228 /* crashes on native */
4229 SHParseDisplayName(NULL, NULL, NULL, 0, NULL);
4230 nameW[0] = 0;
4231 SHParseDisplayName(nameW, NULL, NULL, 0, NULL);
4234 pidl1 = (LPITEMIDLIST)0xdeadbeef;
4235 hr = SHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
4236 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
4237 hr == E_INVALIDARG, "failed %08x\n", hr);
4238 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
4240 /* dummy name */
4241 nameW[0] = 0;
4242 hr = SHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
4243 ok(hr == S_OK, "failed %08x\n", hr);
4244 hr = SHGetDesktopFolder(&desktop);
4245 ok(hr == S_OK, "failed %08x\n", hr);
4246 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
4247 ok(hr == S_OK, "failed %08x\n", hr);
4248 ret = ILIsEqual(pidl1, pidl2);
4249 ok(ret == TRUE, "expected equal idls\n");
4250 ILFree(pidl1);
4251 ILFree(pidl2);
4253 /* with path */
4254 GetWindowsDirectoryW( dirW, MAX_PATH );
4256 hr = SHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4257 ok(hr == S_OK, "failed %08x\n", hr);
4258 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
4259 ok(hr == S_OK, "failed %08x\n", hr);
4261 ret = ILIsEqual(pidl1, pidl2);
4262 ok(ret == TRUE, "expected equal idls\n");
4263 ILFree(pidl1);
4264 ILFree(pidl2);
4266 /* system32 is not redirected to syswow64 on WOW64 */
4267 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
4268 if (is_wow64)
4270 UINT len;
4271 *dirW = 0;
4272 len = GetSystemDirectoryW(dirW, MAX_PATH);
4273 ok(len > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
4274 hr = SHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4275 ok(hr == S_OK, "failed %08x\n", hr);
4276 *dirW = 0;
4277 len = GetSystemWow64DirectoryW(dirW, MAX_PATH);
4278 ok(len > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
4279 hr = SHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
4280 ok(hr == S_OK, "failed %08x\n", hr);
4281 ret = ILIsEqual(pidl1, pidl2);
4282 ok(ret == FALSE, "expected different idls\n");
4283 ILFree(pidl1);
4284 ILFree(pidl2);
4287 IShellFolder_Release(desktop);
4290 static void test_desktop_IPersist(void)
4292 IShellFolder *desktop;
4293 IPersist *persist;
4294 IPersistFolder2 *ppf2;
4295 CLSID clsid;
4296 HRESULT hr;
4298 hr = SHGetDesktopFolder(&desktop);
4299 ok(hr == S_OK, "failed %08x\n", hr);
4301 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
4302 ok(hr == S_OK, "failed %08x\n", hr);
4304 if (hr == S_OK)
4306 if (0)
4308 /* crashes on native */
4309 IPersist_GetClassID(persist, NULL);
4311 memset(&clsid, 0, sizeof(clsid));
4312 hr = IPersist_GetClassID(persist, &clsid);
4313 ok(hr == S_OK, "failed %08x\n", hr);
4314 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
4315 IPersist_Release(persist);
4318 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
4319 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
4320 if(SUCCEEDED(hr))
4322 IPersistFolder *ppf;
4323 LPITEMIDLIST pidl;
4324 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
4325 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
4326 if(SUCCEEDED(hr))
4327 IPersistFolder_Release(ppf);
4329 todo_wine {
4330 hr = IPersistFolder2_Initialize(ppf2, NULL);
4331 ok(hr == S_OK, "got %08x\n", hr);
4334 pidl = NULL;
4335 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
4336 ok(hr == S_OK, "got %08x\n", hr);
4337 ok(pidl != NULL, "pidl was NULL.\n");
4338 if(SUCCEEDED(hr)) ILFree(pidl);
4340 IPersistFolder2_Release(ppf2);
4343 IShellFolder_Release(desktop);
4346 static void test_GetUIObject(void)
4348 IShellFolder *psf_desktop;
4349 IContextMenu *pcm;
4350 LPITEMIDLIST pidl;
4351 HRESULT hr;
4352 WCHAR path[MAX_PATH];
4353 const WCHAR filename[] =
4354 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4356 GetCurrentDirectoryW(MAX_PATH, path);
4357 if (!path[0])
4359 skip("GetCurrentDirectoryW returned an empty string.\n");
4360 return;
4362 lstrcatW(path, filename);
4363 SHGetDesktopFolder(&psf_desktop);
4365 CreateFilesFolders();
4367 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
4368 ok(hr == S_OK, "Got 0x%08x\n", hr);
4369 if(SUCCEEDED(hr))
4371 IShellFolder *psf;
4372 LPCITEMIDLIST pidl_child;
4373 hr = SHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
4374 ok(hr == S_OK, "Got 0x%08x\n", hr);
4375 if(SUCCEEDED(hr))
4377 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, &pidl_child, &IID_IContextMenu, NULL,
4378 (void**)&pcm);
4379 ok(hr == S_OK, "Got 0x%08x\n", hr);
4380 if(SUCCEEDED(hr))
4382 const int baseItem = 0x40;
4383 HMENU hmenu = CreatePopupMenu();
4384 INT max_id, max_id_check;
4385 UINT count, i;
4386 const int id_upper_limit = 32767;
4387 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, baseItem, id_upper_limit, CMF_NORMAL);
4388 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
4389 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
4390 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
4391 count = GetMenuItemCount(hmenu);
4392 ok(count, "Got %d\n", count);
4394 max_id_check = 0;
4395 for(i = 0; i < count; i++)
4397 MENUITEMINFOA mii;
4398 INT res;
4399 char buf[255], buf2[255];
4400 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
4401 mii.cbSize = sizeof(MENUITEMINFOA);
4402 mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
4403 mii.dwTypeData = buf2;
4404 mii.cch = sizeof(buf2);
4406 SetLastError(0);
4407 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
4408 ok(res, "Failed (last error: %d).\n", GetLastError());
4410 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
4411 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
4412 if(!(mii.fType & MFT_SEPARATOR))
4414 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
4415 hr = IContextMenu_GetCommandString(pcm, mii.wID - baseItem, GCS_VERBA, 0, buf, sizeof(buf));
4416 ok(SUCCEEDED(hr) || hr == E_NOTIMPL, "for id 0x%x got 0x%08x (menustr: %s)\n", mii.wID - baseItem, hr, mii.dwTypeData);
4417 if (SUCCEEDED(hr))
4418 trace("for id 0x%x got string %s (menu string: %s)\n", mii.wID - baseItem, buf, mii.dwTypeData);
4419 else if (hr == E_NOTIMPL)
4420 trace("for id 0x%x got E_NOTIMPL (menu string: %s)\n", mii.wID - baseItem, mii.dwTypeData);
4423 max_id_check -= baseItem;
4424 ok((max_id_check == max_id) ||
4425 (max_id_check == max_id-1) || /* Win 7 */
4426 (max_id_check == max_id-2), /* Win 8 */
4427 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
4429 if(count)
4431 CMINVOKECOMMANDINFO cmi;
4432 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
4433 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
4435 /* Attempt to execute a nonexistent command */
4436 cmi.lpVerb = MAKEINTRESOURCEA(9999);
4437 hr = IContextMenu_InvokeCommand(pcm, &cmi);
4438 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
4440 cmi.lpVerb = "foobar_wine_test";
4441 hr = IContextMenu_InvokeCommand(pcm, &cmi);
4442 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
4443 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
4444 "Got 0x%08x\n", hr);
4447 DestroyMenu(hmenu);
4448 IContextMenu_Release(pcm);
4450 IShellFolder_Release(psf);
4452 ILFree(pidl);
4455 IShellFolder_Release(psf_desktop);
4456 Cleanup();
4459 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
4460 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
4462 LPCITEMIDLIST child;
4463 IShellFolder *parent;
4464 STRRET filename;
4465 HRESULT hr;
4467 if(path){
4468 if(!pidl){
4469 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
4470 return;
4473 hr = SHBindToParent(pidl, &IID_IShellFolder, (void **)&parent, &child);
4474 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
4475 if(FAILED(hr))
4476 return;
4478 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
4479 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
4480 if(FAILED(hr)){
4481 IShellFolder_Release(parent);
4482 return;
4485 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
4486 "Got unexpected string type: %d\n", filename.uType);
4487 if(filename.uType == STRRET_WSTR){
4488 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
4489 "didn't get expected path (%s), instead: %s\n",
4490 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
4491 SHFree(U(filename).pOleStr);
4492 }else if(filename.uType == STRRET_CSTR){
4493 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
4494 "didn't get expected path (%s), instead: %s\n",
4495 wine_dbgstr_w(path), U(filename).cStr);
4498 IShellFolder_Release(parent);
4499 }else
4500 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4503 static void test_SHSimpleIDListFromPath(void)
4505 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4506 const CHAR adirA[] = "C:\\sidlfpdir";
4507 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4509 LPITEMIDLIST pidl = NULL;
4511 br = CreateDirectoryA(adirA, NULL);
4512 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4514 if(is_unicode)
4515 pidl = SHSimpleIDListFromPath(adirW);
4516 else
4517 pidl = SHSimpleIDListFromPath((const WCHAR *)adirA);
4518 verify_pidl(pidl, adirW);
4519 ILFree(pidl);
4521 br = RemoveDirectoryA(adirA);
4522 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4524 if(is_unicode)
4525 pidl = SHSimpleIDListFromPath(adirW);
4526 else
4527 pidl = SHSimpleIDListFromPath((const WCHAR *)adirA);
4528 verify_pidl(pidl, adirW);
4529 ILFree(pidl);
4532 /* IFileSystemBindData impl */
4533 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4534 REFIID riid, void **ppv)
4536 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4537 IsEqualIID(riid, &IID_IUnknown)){
4538 *ppv = fsbd;
4539 return S_OK;
4541 return E_NOINTERFACE;
4544 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4546 return 2;
4549 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4551 return 1;
4554 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4555 const WIN32_FIND_DATAW *pfd)
4557 ok(0, "SetFindData called\n");
4558 return E_NOTIMPL;
4561 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4562 WIN32_FIND_DATAW *pfd)
4564 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4565 return S_OK;
4568 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4569 WIN32_FIND_DATAW *pfd)
4571 memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4572 return S_OK;
4575 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4576 WIN32_FIND_DATAW *pfd)
4578 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4579 *pfd->cFileName = 'a';
4580 *pfd->cAlternateFileName = 'a';
4581 return S_OK;
4584 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4585 WIN32_FIND_DATAW *pfd)
4587 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4588 HANDLE handle = FindFirstFileW(adirW, pfd);
4589 FindClose(handle);
4590 return S_OK;
4593 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4594 WIN32_FIND_DATAW *pfd)
4596 return E_FAIL;
4599 static IFileSystemBindDataVtbl fsbdVtbl = {
4600 fsbd_QueryInterface,
4601 fsbd_AddRef,
4602 fsbd_Release,
4603 fsbd_SetFindData,
4604 NULL
4607 static IFileSystemBindData fsbd = { &fsbdVtbl };
4609 static void test_ParseDisplayNamePBC(void)
4611 WCHAR wFileSystemBindData[] =
4612 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4613 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4614 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4615 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4616 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4618 IShellFolder *psf;
4619 IBindCtx *pbc;
4620 HRESULT hres;
4621 ITEMIDLIST *pidl;
4623 /* Check if we support WCHAR functions */
4624 SetLastError(0xdeadbeef);
4625 lstrcmpiW(adirW, adirW);
4626 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4627 win_skip("Most W-calls are not implemented\n");
4628 return;
4631 hres = SHGetDesktopFolder(&psf);
4632 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4633 if(FAILED(hres)){
4634 win_skip("Failed to get IShellFolder, can't run tests\n");
4635 return;
4638 /* fails on unknown dir with no IBindCtx */
4639 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4640 ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4641 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4642 ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4643 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4644 ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4646 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4647 hres = CreateBindCtx(0, &pbc);
4648 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4650 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4651 ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4652 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4653 ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4654 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4655 ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4657 /* unknown dir with IBindCtx with IFileSystemBindData */
4658 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4659 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4661 /* return E_FAIL from GetFindData */
4662 pidl = (ITEMIDLIST*)0xdeadbeef;
4663 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4664 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4665 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4666 if(SUCCEEDED(hres)){
4667 verify_pidl(pidl, adirW);
4668 ILFree(pidl);
4671 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4672 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4673 if(SUCCEEDED(hres)){
4674 verify_pidl(pidl, afileW);
4675 ILFree(pidl);
4678 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4679 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4680 if(SUCCEEDED(hres)){
4681 verify_pidl(pidl, afile2W);
4682 ILFree(pidl);
4685 /* set FIND_DATA struct to NULLs */
4686 pidl = (ITEMIDLIST*)0xdeadbeef;
4687 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4688 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4689 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4690 if(SUCCEEDED(hres)){
4691 verify_pidl(pidl, adirW);
4692 ILFree(pidl);
4695 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4696 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4697 if(SUCCEEDED(hres)){
4698 verify_pidl(pidl, afileW);
4699 ILFree(pidl);
4702 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4703 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4704 if(SUCCEEDED(hres)){
4705 verify_pidl(pidl, afile2W);
4706 ILFree(pidl);
4709 /* set FIND_DATA struct to junk */
4710 pidl = (ITEMIDLIST*)0xdeadbeef;
4711 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4712 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4713 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4714 if(SUCCEEDED(hres)){
4715 verify_pidl(pidl, adirW);
4716 ILFree(pidl);
4719 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4720 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4721 if(SUCCEEDED(hres)){
4722 verify_pidl(pidl, afileW);
4723 ILFree(pidl);
4726 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4727 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4728 if(SUCCEEDED(hres)){
4729 verify_pidl(pidl, afile2W);
4730 ILFree(pidl);
4733 /* set FIND_DATA struct to invalid data */
4734 pidl = (ITEMIDLIST*)0xdeadbeef;
4735 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4736 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4737 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4738 if(SUCCEEDED(hres)){
4739 verify_pidl(pidl, adirW);
4740 ILFree(pidl);
4743 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4744 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4745 if(SUCCEEDED(hres)){
4746 verify_pidl(pidl, afileW);
4747 ILFree(pidl);
4750 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4751 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4752 if(SUCCEEDED(hres)){
4753 verify_pidl(pidl, afile2W);
4754 ILFree(pidl);
4757 /* set FIND_DATA struct to valid data */
4758 pidl = (ITEMIDLIST*)0xdeadbeef;
4759 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4760 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4761 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4762 if(SUCCEEDED(hres)){
4763 verify_pidl(pidl, adirW);
4764 ILFree(pidl);
4767 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4768 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4769 if(SUCCEEDED(hres)){
4770 verify_pidl(pidl, afileW);
4771 ILFree(pidl);
4774 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4775 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4776 if(SUCCEEDED(hres)){
4777 verify_pidl(pidl, afile2W);
4778 ILFree(pidl);
4781 IBindCtx_Release(pbc);
4782 IShellFolder_Release(psf);
4785 static const CHAR testwindow_class[] = "testwindow";
4786 #define WM_USER_NOTIFY (WM_APP+1)
4788 struct ChNotifyTest {
4789 const char id[256];
4790 const UINT notify_count;
4791 UINT missing_events;
4792 UINT signal;
4793 const char path_1[256];
4794 const char path_2[256];
4795 } chnotify_tests[] = {
4796 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4797 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4798 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4801 struct ChNotifyTest *exp_data;
4802 BOOL test_new_delivery_flag;
4804 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4806 LONG signal = (LONG)lparam;
4808 switch(msg){
4809 case WM_USER_NOTIFY:
4810 if(exp_data->missing_events > 0) {
4811 WCHAR *path1, *path2;
4812 LPITEMIDLIST *pidls = (LPITEMIDLIST*)wparam;
4813 HANDLE hLock = NULL;
4815 if(test_new_delivery_flag) {
4816 hLock = SHChangeNotification_Lock((HANDLE)wparam, lparam, &pidls, &signal);
4817 ok(hLock != NULL, "SHChangeNotification_Lock returned NULL\n");
4820 ok(exp_data->signal == signal,
4821 "%s: expected notification type %x, got: %x\n",
4822 exp_data->id, exp_data->signal, signal);
4824 trace("verifying pidls for: %s\n", exp_data->id);
4825 path1 = make_wstr(exp_data->path_1);
4826 path2 = make_wstr(exp_data->path_2);
4827 verify_pidl(pidls[0], path1);
4828 verify_pidl(pidls[1], path2);
4829 HeapFree(GetProcessHeap(), 0, path1);
4830 HeapFree(GetProcessHeap(), 0, path2);
4832 exp_data->missing_events--;
4834 if(test_new_delivery_flag)
4835 SHChangeNotification_Unlock(hLock);
4836 }else
4837 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4838 return 0;
4840 return DefWindowProcA(hwnd, msg, wparam, lparam);
4843 static void register_testwindow_class(void)
4845 WNDCLASSEXA cls;
4846 ATOM ret;
4848 ZeroMemory(&cls, sizeof(cls));
4849 cls.cbSize = sizeof(cls);
4850 cls.style = 0;
4851 cls.lpfnWndProc = testwindow_wndproc;
4852 cls.hInstance = GetModuleHandleA(NULL);
4853 cls.lpszClassName = testwindow_class;
4855 SetLastError(0);
4856 ret = RegisterClassExA(&cls);
4857 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4860 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4861 * have to poll repeatedly for the message to appear */
4862 static void do_events(void)
4864 int c = 0;
4865 while (exp_data->missing_events && (c++ < 10)){
4866 MSG msg;
4867 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4868 TranslateMessage(&msg);
4869 DispatchMessageA(&msg);
4871 if(exp_data->missing_events)
4872 Sleep(500);
4874 trace("%s: took %d tries\n", exp_data->id, c);
4877 static void test_SHChangeNotify(BOOL test_new_delivery)
4879 HWND wnd;
4880 ULONG notifyID, i;
4881 HRESULT hr;
4882 BOOL br, has_unicode;
4883 SHChangeNotifyEntry entries[1];
4884 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4885 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4887 trace("SHChangeNotify tests (%x)\n", test_new_delivery);
4889 CreateDirectoryW(NULL, NULL);
4890 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4892 test_new_delivery_flag = test_new_delivery;
4893 if(!test_new_delivery)
4894 register_testwindow_class();
4896 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4897 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4898 NULL, NULL, GetModuleHandleA(NULL), 0);
4899 ok(wnd != NULL, "Failed to make a window\n");
4901 br = CreateDirectoryA(root_dirA, NULL);
4902 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4904 entries[0].pidl = NULL;
4905 if(has_unicode)
4906 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4907 else
4908 hr = SHILCreateFromPath((const void *)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4909 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4910 entries[0].fRecursive = TRUE;
4912 notifyID = SHChangeNotifyRegister(wnd, !test_new_delivery ? SHCNRF_ShellLevel : SHCNRF_ShellLevel|SHCNRF_NewDelivery,
4913 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4914 ok(notifyID != 0, "Failed to register a window for change notifications\n");
4916 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
4917 exp_data = chnotify_tests + i;
4919 exp_data->missing_events = exp_data->notify_count;
4920 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4921 exp_data->path_1[0] ? exp_data->path_1 : NULL,
4922 exp_data->path_2[0] ? exp_data->path_2 : NULL);
4923 do_events();
4924 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4926 if(has_unicode){
4927 WCHAR *path1, *path2;
4929 path1 = make_wstr(exp_data->path_1);
4930 path2 = make_wstr(exp_data->path_2);
4932 exp_data->missing_events = exp_data->notify_count;
4933 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
4934 do_events();
4935 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4937 HeapFree(GetProcessHeap(), 0, path1);
4938 HeapFree(GetProcessHeap(), 0, path2);
4942 SHChangeNotifyDeregister(notifyID);
4943 DestroyWindow(wnd);
4945 ILFree((LPITEMIDLIST)entries[0].pidl);
4946 br = RemoveDirectoryA(root_dirA);
4947 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4950 static void test_SHCreateDefaultContextMenu(void)
4952 HKEY keys[16];
4953 WCHAR path[MAX_PATH];
4954 IShellFolder *desktop,*folder;
4955 IPersistFolder2 *persist;
4956 IContextMenu *cmenu;
4957 LONG status;
4958 LPITEMIDLIST pidlFolder, pidl_child, pidl;
4959 DEFCONTEXTMENU cminfo;
4960 HRESULT hr;
4961 UINT i;
4962 const WCHAR filename[] =
4963 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4964 if(!pSHCreateDefaultContextMenu)
4966 win_skip("SHCreateDefaultContextMenu missing.\n");
4967 return;
4970 GetCurrentDirectoryW(MAX_PATH, path);
4971 if (!path[0])
4973 skip("GetCurrentDirectoryW returned an empty string.\n");
4974 return;
4976 lstrcatW(path, filename);
4977 SHGetDesktopFolder(&desktop);
4979 CreateFilesFolders();
4981 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &pidl, 0);
4982 ok(hr == S_OK, "Got 0x%08x\n", hr);
4983 if(SUCCEEDED(hr))
4985 hr = SHBindToParent(pidl, &IID_IShellFolder, (void **)&folder, (const ITEMIDLIST **)&pidl_child);
4986 ok(hr == S_OK, "Got 0x%08x\n", hr);
4988 IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
4989 IPersistFolder2_GetCurFolder(persist,&pidlFolder);
4990 IPersistFolder2_Release(persist);
4991 if(SUCCEEDED(hr))
4994 cminfo.hwnd=NULL;
4995 cminfo.pcmcb=NULL;
4996 cminfo.psf=folder;
4997 cminfo.pidlFolder=NULL;
4998 cminfo.apidl=(LPCITEMIDLIST*)&pidl_child;
4999 cminfo.cidl=1;
5000 cminfo.aKeys=NULL;
5001 cminfo.cKeys=0;
5002 cminfo.punkAssociationInfo=NULL;
5003 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5004 ok(hr==S_OK,"Got 0x%08x\n", hr);
5005 IContextMenu_Release(cmenu);
5006 cminfo.pidlFolder=pidlFolder;
5007 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5008 ok(hr==S_OK,"Got 0x%08x\n", hr);
5009 IContextMenu_Release(cmenu);
5010 status = RegOpenKeyExA(HKEY_CLASSES_ROOT,"*",0,KEY_READ,keys);
5011 if(status==ERROR_SUCCESS){
5012 for(i=1;i<16;i++)
5013 keys[i]=keys[0];
5014 cminfo.aKeys=keys;
5015 cminfo.cKeys=16;
5016 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5017 RegCloseKey(keys[0]);
5018 ok(hr==S_OK,"Got 0x%08x\n", hr);
5019 IContextMenu_Release(cmenu);
5022 ILFree(pidlFolder);
5023 IShellFolder_Release(folder);
5025 IShellFolder_Release(desktop);
5026 ILFree(pidl);
5027 Cleanup();
5030 static void test_DataObject(void)
5032 IShellFolder *desktop;
5033 IDataObject *data_obj;
5034 HRESULT hres;
5035 IEnumIDList *peidl;
5036 LPITEMIDLIST apidl;
5037 FORMATETC fmt;
5038 DWORD cf_shellidlist;
5039 STGMEDIUM medium;
5041 SHGetDesktopFolder(&desktop);
5043 hres = IShellFolder_EnumObjects(desktop, NULL,
5044 SHCONTF_NONFOLDERS|SHCONTF_FOLDERS|SHCONTF_INCLUDEHIDDEN, &peidl);
5045 ok(hres == S_OK, "got %x\n", hres);
5047 if(IEnumIDList_Next(peidl, 1, &apidl, NULL) != S_OK) {
5048 skip("no files on desktop - skipping GetDataObject tests\n");
5049 IEnumIDList_Release(peidl);
5050 IShellFolder_Release(desktop);
5051 return;
5053 IEnumIDList_Release(peidl);
5055 hres = IShellFolder_GetUIObjectOf(desktop, NULL, 1, (LPCITEMIDLIST*)&apidl,
5056 &IID_IDataObject, NULL, (void**)&data_obj);
5057 ok(hres == S_OK, "got %x\n", hres);
5058 ILFree(apidl);
5059 IShellFolder_Release(desktop);
5061 cf_shellidlist = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
5062 fmt.cfFormat = cf_shellidlist;
5063 fmt.ptd = NULL;
5064 fmt.dwAspect = DVASPECT_CONTENT;
5065 fmt.lindex = -1;
5066 fmt.tymed = TYMED_HGLOBAL;
5067 hres = IDataObject_QueryGetData(data_obj, &fmt);
5068 ok(hres == S_OK, "got %x\n", hres);
5070 fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5071 hres = IDataObject_QueryGetData(data_obj, &fmt);
5072 ok(hres == S_OK, "got %x\n", hres);
5074 fmt.tymed = TYMED_ISTREAM;
5075 hres = IDataObject_QueryGetData(data_obj, &fmt);
5076 todo_wine ok(hres == S_FALSE, "got %x\n", hres);
5078 fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5079 hres = IDataObject_GetData(data_obj, &fmt, &medium);
5080 ok(hres == S_OK, "got %x\n", hres);
5081 ok(medium.tymed == TYMED_HGLOBAL, "medium.tymed = %x\n", medium.tymed);
5082 ReleaseStgMedium(&medium);
5084 IDataObject_Release(data_obj);
5087 static void test_GetDefaultColumn(void)
5089 static const CLSID *folders[] =
5091 &CLSID_MyComputer,
5092 &CLSID_MyDocuments,
5093 &CLSID_ControlPanel,
5094 &CLSID_NetworkPlaces,
5095 &CLSID_Printers,
5096 &CLSID_RecycleBin,
5097 &CLSID_ShellDesktop,
5099 HRESULT hr;
5100 int i;
5102 CoInitialize(NULL);
5104 for (i = 0; i < sizeof(folders)/sizeof(folders[0]); i++)
5106 IShellFolder2 *folder;
5107 ULONG sort, display;
5109 hr = CoCreateInstance(folders[i], NULL, CLSCTX_INPROC_SERVER, &IID_IShellFolder2, (void **)&folder);
5110 if (hr != S_OK)
5112 win_skip("Failed to create folder %s, hr %#x.\n", wine_dbgstr_guid(folders[i]), hr);
5113 continue;
5116 hr = IShellFolder2_GetDefaultColumn(folder, 0, NULL, NULL);
5117 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5119 sort = display = 123;
5120 hr = IShellFolder2_GetDefaultColumn(folder, 0, &sort, &display);
5121 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5122 ok(sort == 123 && display == 123, "Unexpected default column.\n");
5124 display = 123;
5125 hr = IShellFolder2_GetDefaultColumn(folder, 0, NULL, &display);
5126 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5127 ok(display == 123, "Unexpected default column.\n");
5129 sort = 123;
5130 hr = IShellFolder2_GetDefaultColumn(folder, 0, &sort, NULL);
5131 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5132 ok(sort == 123, "Unexpected default column.\n");
5135 CoUninitialize();
5138 static void test_GetDefaultSearchGUID(void)
5140 static const CLSID *folders[] =
5142 &CLSID_MyComputer,
5143 &CLSID_MyDocuments,
5144 &CLSID_ControlPanel,
5145 &CLSID_NetworkPlaces,
5146 &CLSID_Printers,
5147 &CLSID_RecycleBin,
5148 &CLSID_ShellDesktop,
5150 HRESULT hr;
5151 int i;
5153 CoInitialize(NULL);
5155 for (i = 0; i < sizeof(folders)/sizeof(folders[0]); i++)
5157 IShellFolder2 *folder;
5158 GUID guid;
5160 hr = CoCreateInstance(folders[i], NULL, CLSCTX_INPROC_SERVER, &IID_IShellFolder2, (void **)&folder);
5161 if (hr != S_OK)
5163 win_skip("Failed to create folder %s, hr %#x.\n", wine_dbgstr_guid(folders[i]), hr);
5164 continue;
5167 if (0)
5169 /* crashes on XP */
5170 hr = IShellFolder2_GetDefaultSearchGUID(folder, NULL);
5171 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5174 memcpy(&guid, &CLSID_MyComputer, sizeof(guid));
5175 hr = IShellFolder2_GetDefaultSearchGUID(folder, &guid);
5176 ok(hr == E_NOTIMPL || broken(hr == S_OK) /* Method was last supported on XP */, "Unexpected hr %#x.\n", hr);
5177 if (hr == E_NOTIMPL)
5178 ok(IsEqualGUID(&guid, &CLSID_MyComputer), "Unexpected guid %s.\n", wine_dbgstr_guid(&guid));
5180 IShellFolder2_Release(folder);
5183 CoUninitialize();
5186 START_TEST(shlfolder)
5188 init_function_pointers();
5189 /* if OleInitialize doesn't get called, ParseDisplayName returns
5190 CO_E_NOTINITIALIZED for malformed directory names */
5191 OleInitialize(NULL);
5193 test_ParseDisplayName();
5194 test_SHParseDisplayName();
5195 test_BindToObject();
5196 test_EnumObjects_and_CompareIDs();
5197 test_GetDisplayName();
5198 test_GetAttributesOf();
5199 test_SHGetPathFromIDList();
5200 test_CallForAttributes();
5201 test_FolderShortcut();
5202 test_ITEMIDLIST_format();
5203 test_SHGetFolderPathA();
5204 test_SHGetFolderPathAndSubDirA();
5205 test_LocalizedNames();
5206 test_SHCreateShellItem();
5207 test_SHCreateShellItemArray();
5208 test_ShellItemArrayEnumItems();
5209 test_desktop_IPersist();
5210 test_GetUIObject();
5211 test_SHSimpleIDListFromPath();
5212 test_ParseDisplayNamePBC();
5213 test_SHGetNameFromIDList();
5214 test_SHGetItemFromDataObject();
5215 test_SHGetIDListFromObject();
5216 test_SHGetItemFromObject();
5217 test_ShellItemCompare();
5218 test_SHChangeNotify(FALSE);
5219 test_SHChangeNotify(TRUE);
5220 test_ShellItemBindToHandler();
5221 test_ShellItemGetAttributes();
5222 test_ShellItemArrayGetAttributes();
5223 test_SHCreateDefaultContextMenu();
5224 test_DataObject();
5225 test_GetDefaultColumn();
5226 test_GetDefaultSearchGUID();
5228 OleUninitialize();