amstream: Implement AMAudioStream::NewSegment.
[wine/zf.git] / dlls / shell32 / tests / shlfolder.c
blobe724448c7a082f570f20d2ec53052d272890ccdc
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/heap.h"
41 #include "wine/test.h"
43 #include <initguid.h>
44 DEFINE_GUID(IID_IParentAndItem, 0xB3A4B685, 0xB685, 0x4805, 0x99,0xD9, 0x5D,0xEA,0xD2,0x87,0x32,0x36);
45 DEFINE_GUID(CLSID_ShellDocObjView, 0xe7e4bc40, 0xe76a, 0x11ce, 0xa9,0xbb, 0x00,0xaa,0x00,0x4a,0xe8,0x37);
47 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
48 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
49 static HRESULT (WINAPI *pSHCreateItemFromRelativeName)(IShellItem*,PCWSTR,IBindCtx*,REFIID,void**);
50 static HRESULT (WINAPI *pSHCreateItemInKnownFolder)(REFKNOWNFOLDERID,DWORD,PCWSTR,REFIID,void **);
51 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
52 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
53 static HRESULT (WINAPI *pSHCreateShellItemArrayFromIDLists)(UINT, PCIDLIST_ABSOLUTE*, IShellItemArray**);
54 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
55 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
56 static HRESULT (WINAPI *pSHGetKnownFolderPath)(REFKNOWNFOLDERID,DWORD,HANDLE,PWSTR*);
57 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
58 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
59 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
60 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
61 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
62 static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
63 static BOOL (WINAPI *pSHGetPathFromIDListEx)(PCIDLIST_ABSOLUTE,WCHAR*,DWORD,GPFIDL_FLAGS);
64 static HRESULT (WINAPI *pSHGetSetFolderCustomSettings)(LPSHFOLDERCUSTOMSETTINGS,PCWSTR,DWORD);
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 = heap_alloc(len * sizeof(WCHAR));
79 if(!ret)
80 return NULL;
82 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
83 return ret;
86 static void init_function_pointers(void)
88 HMODULE hmod;
89 void *ptr;
91 hmod = GetModuleHandleA("shell32.dll");
93 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
94 MAKEFUNC(SHCreateItemFromIDList);
95 MAKEFUNC(SHCreateItemFromParsingName);
96 MAKEFUNC(SHCreateItemFromRelativeName);
97 MAKEFUNC(SHCreateItemInKnownFolder);
98 MAKEFUNC(SHCreateShellItem);
99 MAKEFUNC(SHCreateShellItemArray);
100 MAKEFUNC(SHCreateShellItemArrayFromIDLists);
101 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
102 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
103 MAKEFUNC(SHGetKnownFolderPath);
104 MAKEFUNC(SHGetNameFromIDList);
105 MAKEFUNC(SHGetItemFromDataObject);
106 MAKEFUNC(SHGetIDListFromObject);
107 MAKEFUNC(SHGetItemFromObject);
108 MAKEFUNC(SHCreateDefaultContextMenu);
109 MAKEFUNC(SHGetPathFromIDListEx);
110 MAKEFUNC(SHGetSetFolderCustomSettings);
111 #undef MAKEFUNC
113 /* test named exports */
114 ptr = GetProcAddress(hmod, "ILFree");
115 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
116 if (ptr)
118 #define TESTNAMED(f) \
119 ptr = (void*)GetProcAddress(hmod, #f); \
120 ok(ptr != 0, "expected named export for " #f "\n");
122 TESTNAMED(ILAppendID);
123 TESTNAMED(ILClone);
124 TESTNAMED(ILCloneFirst);
125 TESTNAMED(ILCombine);
126 TESTNAMED(ILCreateFromPath);
127 TESTNAMED(ILCreateFromPathA);
128 TESTNAMED(ILCreateFromPathW);
129 TESTNAMED(ILFindChild);
130 TESTNAMED(ILFindLastID);
131 TESTNAMED(ILGetNext);
132 TESTNAMED(ILGetSize);
133 TESTNAMED(ILIsEqual);
134 TESTNAMED(ILIsParent);
135 TESTNAMED(ILRemoveLastID);
136 TESTNAMED(ILSaveToStream);
137 #undef TESTNAMED
140 hmod = GetModuleHandleA("kernel32.dll");
141 pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
144 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
145 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
147 size_t iLen;
149 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
150 return NULL;
152 if (iLen)
154 lpszPath += iLen;
155 if (lpszPath[-1] != '\\')
157 *lpszPath++ = '\\';
158 *lpszPath = '\0';
161 return lpszPath;
164 static struct
166 WCHAR path[MAX_PATH];
167 HRESULT hr;
168 int todo;
169 } parse_tests[] = {
170 {{'c',':','\\',0}, S_OK},
171 {{'c',':','\\','\\',0}, E_INVALIDARG, 1},
172 {{'c',':','\\','f','a','k','e',0}, 0x80070002}, /* ERROR_FILE_NOT_FOUND */
173 {{'c',':','f','a','k','e',0}, E_INVALIDARG, 1},
174 {{'c',':','/',0}, E_INVALIDARG, 1},
175 {{'c',':','\\','w','i','n','d','o','w','s',0}, S_OK},
176 {{'c',':','\\','w','i','n','d','o','w','s','\\',0}, S_OK},
177 {{'c',':','\\','w','i','n','d','o','w','s','\\','.',0}, E_INVALIDARG, 1},
178 {{'c',':','\\','w','i','n','d','o','w','s','\\','.','.',0}, E_INVALIDARG, 1},
179 {{'.',0}, E_INVALIDARG, 1},
180 {{'.','.',0}, E_INVALIDARG, 1},
181 {{'t','e','s','t',0}, 0x80070002},
182 {{'t','e','s','t','\\',0}, 0x80070002},
183 {{'s','u','b','\\','d','i','r',0}, 0x80070002},
184 {{'s','u','b','/','d','i','r',0}, E_INVALIDARG, 1},
185 {{'h','t','t','p',':',0}, S_OK, 1},
186 {{'h','t','t','p',':','t','e','s','t',0}, S_OK, 1},
187 {{'h','t','t','p',':','\\','t','e','s','t',0}, S_OK, 1},
188 {{'x','x',':',0}, S_OK, 1},
191 static void test_ParseDisplayName(void)
193 static WCHAR testdirW[] = {'p','a','r','s','e','t','e','s','t',0};
194 static WCHAR backslashW[] = {'\\',0};
195 WCHAR buffer[MAX_PATH], buffer2[MAX_PATH];
196 IShellFolder *desktop;
197 ITEMIDLIST *pidl;
198 HRESULT hr;
199 BOOL bRes;
200 int i;
202 hr = SHGetDesktopFolder(&desktop);
203 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
205 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, NULL, NULL, &pidl, NULL);
206 ok(hr == E_INVALIDARG, "got %#x\n", hr);
208 for (i = 0; i < ARRAY_SIZE(parse_tests); i++)
210 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, parse_tests[i].path, NULL, &pidl, NULL);
211 todo_wine_if(parse_tests[i].todo)
212 ok(hr == parse_tests[i].hr, "%s: expected %#x, got %#x\n",
213 wine_dbgstr_w(parse_tests[i].path), parse_tests[i].hr, hr);
214 if (SUCCEEDED(hr))
215 CoTaskMemFree(pidl);
218 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
219 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
220 * out it doesn't. The magic seems to happen in the file dialogs, then. */
222 bRes = SHGetSpecialFolderPathW(NULL, buffer, CSIDL_PERSONAL, FALSE);
223 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
225 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, buffer, NULL, &pidl, 0);
226 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
228 ok(ILFindLastID(pidl)->mkid.abID[0] == 0x31,
229 "Last pidl should be of type PT_FOLDER, but is: %02x\n",
230 ILFindLastID(pidl)->mkid.abID[0]);
231 CoTaskMemFree(pidl);
233 /* Relative paths are interpreted relative to the desktop. */
234 GetTempPathW(ARRAY_SIZE(buffer), buffer);
235 GetLongPathNameW(buffer, buffer, ARRAY_SIZE(buffer));
236 SetCurrentDirectoryW(buffer);
237 CreateDirectoryW(testdirW, NULL);
239 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, testdirW, NULL, &pidl, NULL);
240 ok(hr == 0x80070002, "got %#x\n", hr);
242 RemoveDirectoryW(testdirW);
244 hr = SHGetSpecialFolderPathW(NULL, buffer, CSIDL_DESKTOP, FALSE);
245 ok(hr == S_FALSE, "got %#x\n", hr);
246 SetCurrentDirectoryW(buffer);
247 CreateDirectoryW(testdirW, NULL);
249 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, testdirW, NULL, &pidl, NULL);
250 ok(hr == S_OK, "got %#x\n", hr);
252 ok(SHGetPathFromIDListW(pidl, buffer2), "SHGetPathFromIDList failed\n");
253 lstrcatW(buffer, backslashW);
254 lstrcatW(buffer, testdirW);
255 ok(!lstrcmpW(buffer, buffer2), "expected %s, got %s\n", wine_dbgstr_w(buffer), wine_dbgstr_w(buffer2));
257 RemoveDirectoryW(testdirW);
258 CoTaskMemFree(pidl);
260 IShellFolder_Release(desktop);
263 /* creates a file with the specified name for tests */
264 static void CreateTestFile(const CHAR *name)
266 HANDLE file;
267 DWORD written;
269 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
270 if (file != INVALID_HANDLE_VALUE)
272 WriteFile(file, name, strlen(name), &written, NULL);
273 WriteFile(file, "\n", strlen("\n"), &written, NULL);
274 CloseHandle(file);
279 /* initializes the tests */
280 static void CreateFilesFolders(void)
282 CreateDirectoryA(".\\testdir", NULL);
283 CreateDirectoryA(".\\testdir\\test.txt", NULL);
284 CreateTestFile (".\\testdir\\test1.txt ");
285 CreateTestFile (".\\testdir\\test2.txt ");
286 CreateTestFile (".\\testdir\\test3.txt ");
287 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
288 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
291 /* cleans after tests */
292 static void Cleanup(void)
294 DeleteFileA(".\\testdir\\test1.txt");
295 DeleteFileA(".\\testdir\\test2.txt");
296 DeleteFileA(".\\testdir\\test3.txt");
297 RemoveDirectoryA(".\\testdir\\test.txt");
298 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
299 RemoveDirectoryA(".\\testdir\\testdir2");
300 RemoveDirectoryA(".\\testdir");
304 /* perform test */
305 static void test_EnumObjects(IShellFolder *iFolder)
307 IEnumIDList *iEnumList;
308 LPITEMIDLIST newPIDL, idlArr[10];
309 ULONG NumPIDLs;
310 int i=0, j;
311 HRESULT hr;
313 static const WORD iResults [5][5] =
315 { 0,-1,-1,-1,-1},
316 { 1, 0,-1,-1,-1},
317 { 1, 1, 0,-1,-1},
318 { 1, 1, 1, 0,-1},
319 { 1, 1, 1, 1, 0}
322 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
323 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
324 static const ULONG attrs[5] =
326 SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
327 SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
328 SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY | SFGAO_FILESYSTEM,
329 SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY | SFGAO_FILESYSTEM,
330 SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY | SFGAO_FILESYSTEM,
332 static const ULONG full_attrs[5] =
334 SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
335 SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
336 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
337 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
338 SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
341 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
342 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
344 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
345 * the filesystem shellfolders return S_OK even if less than 'celt' items are
346 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
347 * only ever returns a single entry per call. */
348 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
349 i += NumPIDLs;
350 ok (i == 5, "i: %d\n", i);
352 hr = IEnumIDList_Release(iEnumList);
353 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
355 /* Sort them first in case of wrong order from system */
356 for (i=0;i<5;i++) for (j=0;j<5;j++)
357 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
359 newPIDL = idlArr[i];
360 idlArr[i] = idlArr[j];
361 idlArr[j] = newPIDL;
364 for (i=0;i<5;i++) for (j=0;j<5;j++)
366 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
367 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
370 for (i = 0; i < ARRAY_SIZE(attrs); ++i)
372 SFGAOF flags;
374 flags = SFGAO_CANCOPY;
375 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
376 flags &= SFGAO_testfor;
377 ok(hr == S_OK, "Failed to get item attributes, hr %#x.\n", hr);
378 ok((flags & attrs[i]) == attrs[i], "%i: unexpected attributes got %#x, expected %#x.\n", i, flags, attrs[i]);
380 flags = SFGAO_testfor;
381 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
382 flags &= SFGAO_testfor;
383 ok(hr == S_OK, "Failed to get item attributes, hr %#x.\n", hr);
384 ok(flags == (attrs[i] | SFGAO_CAPABILITYMASK), "%i: unexpected attributes got %#x, expected %#x.\n",
385 i, flags, attrs[i]);
387 flags = ~0u;
388 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
389 ok(hr == S_OK, "Failed to get item attributes, hr %#x.\n", hr);
390 ok((flags & ~(SFGAO_HASSUBFOLDER|SFGAO_COMPRESSED)) == full_attrs[i], "%d: unexpected attributes %#x, expected %#x\n",
391 i, flags, full_attrs[i]);
394 for (i=0;i<5;i++)
395 ILFree(idlArr[i]);
398 static void test_BindToObject(void)
400 HRESULT hr;
401 UINT cChars;
402 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
403 SHITEMID emptyitem = { 0, { 0 } };
404 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
405 WCHAR wszSystemDir[MAX_PATH];
406 char szSystemDir[MAX_PATH];
407 char buf[MAX_PATH];
408 WCHAR path[MAX_PATH];
409 CHAR pathA[MAX_PATH];
410 HANDLE hfile;
411 WCHAR wszMyComputer[] = {
412 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
413 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
414 static const CHAR filename_html[] = "winetest.html";
415 static const CHAR filename_txt[] = "winetest.txt";
416 static const CHAR filename_foo[] = "winetest.foo";
418 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
419 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
421 hr = SHGetDesktopFolder(&psfDesktop);
422 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
423 if (hr != S_OK) return;
425 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
426 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
428 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
429 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
431 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
432 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
433 if (hr != S_OK) {
434 IShellFolder_Release(psfDesktop);
435 return;
438 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
439 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
440 IShellFolder_Release(psfDesktop);
441 ILFree(pidlMyComputer);
442 if (hr != S_OK) return;
444 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
445 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
447 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
448 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
450 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
451 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
452 if (cChars == 0 || cChars >= MAX_PATH) {
453 IShellFolder_Release(psfMyComputer);
454 return;
456 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
458 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
459 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
460 if (hr != S_OK) {
461 IShellFolder_Release(psfMyComputer);
462 return;
465 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
466 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
467 IShellFolder_Release(psfMyComputer);
468 ILFree(pidlSystemDir);
469 if (hr != S_OK) return;
471 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
472 ok (hr == E_INVALIDARG,
473 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
475 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
476 ok (hr == E_INVALIDARG,
477 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
479 IShellFolder_Release(psfSystemDir);
481 cChars = GetCurrentDirectoryA(MAX_PATH, buf);
482 if(!cChars)
484 skip("Failed to get current directory, skipping tests.\n");
485 return;
487 if(buf[cChars-1] != '\\') lstrcatA(buf, "\\");
489 SHGetDesktopFolder(&psfDesktop);
491 /* Attempt BindToObject on files. */
493 /* .html */
494 lstrcpyA(pathA, buf);
495 lstrcatA(pathA, filename_html);
496 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
497 if(hfile != INVALID_HANDLE_VALUE)
499 CloseHandle(hfile);
500 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
501 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
502 ok(hr == S_OK, "Got 0x%08x\n", hr);
503 if(SUCCEEDED(hr))
505 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
506 ok(hr == S_OK ||
507 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
508 "Got 0x%08x\n", hr);
509 if(SUCCEEDED(hr))
511 IPersist *pp;
512 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
513 ok(hr == S_OK, "Got 0x%08x\n", hr);
514 if(SUCCEEDED(hr))
516 CLSID id;
517 hr = IPersist_GetClassID(pp, &id);
518 ok(hr == S_OK, "Got 0x%08x\n", hr);
519 ok(IsEqualIID(&id, &CLSID_ShellDocObjView), "Unexpected classid %s\n", wine_dbgstr_guid(&id));
520 IPersist_Release(pp);
523 IShellFolder_Release(psfChild);
525 ILFree(pidl);
527 DeleteFileA(pathA);
529 else
530 win_skip("Failed to create .html testfile.\n");
532 /* .txt */
533 lstrcpyA(pathA, buf);
534 lstrcatA(pathA, filename_txt);
535 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
536 if(hfile != INVALID_HANDLE_VALUE)
538 CloseHandle(hfile);
539 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
540 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
541 ok(hr == S_OK, "Got 0x%08x\n", hr);
542 if(SUCCEEDED(hr))
544 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
545 ok(hr == E_FAIL || /* Vista+ */
546 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
547 "Got 0x%08x\n", hr);
548 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
549 ILFree(pidl);
551 DeleteFileA(pathA);
553 else
554 win_skip("Failed to create .txt testfile.\n");
556 /* .foo */
557 lstrcpyA(pathA, buf);
558 lstrcatA(pathA, filename_foo);
559 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
560 if(hfile != INVALID_HANDLE_VALUE)
562 CloseHandle(hfile);
563 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
564 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
565 ok(hr == S_OK, "Got 0x%08x\n", hr);
566 if(SUCCEEDED(hr))
568 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
569 ok(hr == E_FAIL || /* Vista+ */
570 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
571 "Got 0x%08x\n", hr);
572 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
573 ILFree(pidl);
575 DeleteFileA(pathA);
577 else
578 win_skip("Failed to create .foo testfile.\n");
580 /* And on the desktop */
581 SHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
582 lstrcatA(pathA, "\\");
583 lstrcatA(pathA, filename_html);
584 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
586 CloseHandle(hfile);
587 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
588 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
589 ok(hr == S_OK, "Got 0x%08x\n", hr);
591 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void **)&psfChild);
592 ok(hr == S_OK ||
593 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
594 "Got 0x%08x\n", hr);
595 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
596 ILFree(pidl);
597 if(!DeleteFileA(pathA))
598 trace("Failed to delete: %d\n", GetLastError());
600 SHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
601 lstrcatA(pathA, "\\");
602 lstrcatA(pathA, filename_foo);
603 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
605 CloseHandle(hfile);
606 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
607 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
608 ok(hr == S_OK, "Got 0x%08x\n", hr);
610 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void **)&psfChild);
611 ok(hr == E_FAIL || /* Vista+ */
612 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
613 "Got 0x%08x\n", hr);
614 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
615 ILFree(pidl);
616 DeleteFileA(pathA);
618 IShellFolder_Release(psfDesktop);
621 static void test_GetDisplayName(void)
623 BOOL result;
624 HRESULT hr;
625 HANDLE hTestFile;
626 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
627 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
628 DWORD attr;
629 STRRET strret;
630 LPSHELLFOLDER psfDesktop, psfPersonal;
631 IUnknown *psfFile;
632 SHITEMID emptyitem = { 0, { 0 } };
633 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
634 LPCITEMIDLIST pidlLast;
635 static const CHAR szFileName[] = "winetest.foo";
636 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
637 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
639 /* It's ok to use this fixed path. Call will fail anyway. */
640 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
641 LPITEMIDLIST pidlNew;
643 /* I'm trying to figure if there is a functional difference between calling
644 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
645 * binding to the shellfolder. One thing I thought of was that perhaps
646 * SHGetPathFromIDListW would be able to get the path to a file, which does
647 * not exist anymore, while the other method wouldn't. It turns out there's
648 * no functional difference in this respect.
651 /* First creating a directory in MyDocuments and a file in this directory. */
652 result = SHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
653 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
654 if (!result) return;
656 /* Use ANSI file functions so this works on Windows 9x */
657 lstrcatA(szTestDir, "\\winetest");
658 CreateDirectoryA(szTestDir, NULL);
659 attr=GetFileAttributesA(szTestDir);
660 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
662 ok(0, "unable to create the '%s' directory\n", szTestDir);
663 return;
666 lstrcpyA(szTestFile, szTestDir);
667 lstrcatA(szTestFile, "\\");
668 lstrcatA(szTestFile, szFileName);
669 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
670 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
671 if (hTestFile == INVALID_HANDLE_VALUE) return;
672 CloseHandle(hTestFile);
674 /* Getting an itemidlist for the file. */
675 hr = SHGetDesktopFolder(&psfDesktop);
676 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
677 if (hr != S_OK) return;
679 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
681 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
682 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
683 if (hr != S_OK) {
684 IShellFolder_Release(psfDesktop);
685 return;
688 pidlLast = ILFindLastID(pidlTestFile);
689 ok(pidlLast->mkid.cb >= 76, "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
690 if (pidlLast->mkid.cb >= 28) {
691 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
692 "Filename should be stored as ansi-string at this position!\n");
694 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
695 if (pidlLast->mkid.cb >= 76) {
696 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
697 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
698 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)) || /* Win7 */
699 (pidlLast->mkid.cb >= 102 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[72], wszFileName)), /* Win8 */
700 "Filename should be stored as wchar-string at this position!\n");
703 /* It seems as if we cannot bind to regular files on windows, but only directories.
705 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
706 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
707 hr == E_NOTIMPL, /* Vista */
708 "hr = %08x\n", hr);
709 if (hr == S_OK) {
710 IUnknown_Release(psfFile);
713 /* Some tests for IShellFolder::SetNameOf */
714 hr = SHBindToParent(pidlTestFile, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
715 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
717 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
718 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
719 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
721 ok (((ITEMIDLIST *)((BYTE *)pidlNew + pidlNew->mkid.cb))->mkid.cb == 0,
722 "pidl returned from SetNameOf should be simple!\n");
724 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
725 * is implemented on top of SHFileOperation in WinXP. */
726 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename, SHGDN_FORPARSING, NULL);
727 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
729 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
730 * SHGDN flags specify an absolute path. */
731 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
732 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
734 ILFree(pidlNew);
735 IShellFolder_Release(psfPersonal);
737 /* Deleting the file and the directory */
738 DeleteFileA(szTestFile);
739 RemoveDirectoryA(szTestDir);
741 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
742 result = SHGetPathFromIDListW(pidlTestFile, wszTestFile2);
743 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
744 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
746 /* SHBindToParent fails, if called with a NULL PIDL. */
747 hr = SHBindToParent(NULL, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
748 ok (hr == E_INVALIDARG || broken(hr == E_OUTOFMEMORY) /* XP */,
749 "SHBindToParent(NULL) should fail! hr = %08x\n", hr);
751 /* But it succeeds with an empty PIDL. */
752 hr = SHBindToParent(pidlEmpty, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
753 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
754 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
755 if (hr == S_OK)
756 IShellFolder_Release(psfPersonal);
758 /* Binding to the folder and querying the display name of the file also works. */
759 hr = SHBindToParent(pidlTestFile, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
760 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
761 if (hr != S_OK) {
762 IShellFolder_Release(psfDesktop);
763 return;
766 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
767 * pidlTestFile (In accordance with MSDN). */
768 ok (ILFindLastID(pidlTestFile) == pidlLast,
769 "SHBindToParent doesn't return the last id of the pidl param!\n");
771 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
772 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
773 if (hr != S_OK) {
774 IShellFolder_Release(psfDesktop);
775 IShellFolder_Release(psfPersonal);
776 return;
779 hr = StrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
780 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
781 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
783 ILFree(pidlTestFile);
784 IShellFolder_Release(psfDesktop);
785 IShellFolder_Release(psfPersonal);
788 static void test_CallForAttributes(void)
790 HKEY hKey;
791 LONG lResult;
792 HRESULT hr;
793 DWORD dwSize;
794 LPSHELLFOLDER psfDesktop;
795 LPITEMIDLIST pidlMyDocuments;
796 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
797 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
798 static const WCHAR wszCallForAttributes[] = {
799 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
800 static const WCHAR wszMyDocumentsKey[] = {
801 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
802 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
803 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
804 WCHAR wszMyDocuments[] = {
805 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
806 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
808 /* For the root of a namespace extension, the attributes are not queried by binding
809 * to the object and calling GetAttributesOf. Instead, the attributes are read from
810 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
812 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
813 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
814 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
815 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
817 hr = SHGetDesktopFolder(&psfDesktop);
818 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
819 if (hr != S_OK) return;
821 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
822 &pidlMyDocuments, NULL);
823 ok (hr == S_OK,
824 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
825 if (hr != S_OK) {
826 IShellFolder_Release(psfDesktop);
827 return;
830 dwAttributes = 0xffffffff;
831 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
832 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
833 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
835 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
836 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
837 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
838 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
840 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
841 * key. So the test will return at this point, if run on wine.
843 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
844 ok (lResult == ERROR_SUCCESS ||
845 lResult == ERROR_ACCESS_DENIED,
846 "RegOpenKeyEx failed! result: %08x\n", lResult);
847 if (lResult != ERROR_SUCCESS) {
848 if (lResult == ERROR_ACCESS_DENIED)
849 skip("Not enough rights to open the registry key\n");
850 ILFree(pidlMyDocuments);
851 IShellFolder_Release(psfDesktop);
852 return;
855 /* Query MyDocuments' Attributes value, to be able to restore it later. */
856 dwSize = sizeof(DWORD);
857 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
858 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
859 if (lResult != ERROR_SUCCESS) {
860 RegCloseKey(hKey);
861 ILFree(pidlMyDocuments);
862 IShellFolder_Release(psfDesktop);
863 return;
866 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
867 dwSize = sizeof(DWORD);
868 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
869 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
870 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
871 if (lResult != ERROR_SUCCESS) {
872 RegCloseKey(hKey);
873 ILFree(pidlMyDocuments);
874 IShellFolder_Release(psfDesktop);
875 return;
878 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
879 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
880 * SFGAO_FILESYSTEM attributes. */
881 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
882 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
883 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
884 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
885 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
887 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
888 * GetAttributesOf. It seems that once there is a single attribute queried, for which
889 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
890 * the flags in Attributes are ignored.
892 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
893 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
894 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
895 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
896 if (hr == S_OK)
897 ok (dwAttributes == SFGAO_FILESYSTEM,
898 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
899 dwAttributes);
901 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
902 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
903 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
904 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
905 RegCloseKey(hKey);
906 ILFree(pidlMyDocuments);
907 IShellFolder_Release(psfDesktop);
910 static void test_GetAttributesOf(void)
912 HRESULT hr;
913 LPSHELLFOLDER psfDesktop, psfMyComputer;
914 SHITEMID emptyitem = { 0, { 0 } };
915 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
916 LPITEMIDLIST pidlMyComputer;
917 DWORD dwFlags;
918 static const DWORD desktopFlags = SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
919 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER;
920 static const DWORD myComputerFlags = SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET |
921 SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
922 WCHAR wszMyComputer[] = {
923 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
924 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
925 char cCurrDirA [MAX_PATH] = {0};
926 WCHAR cCurrDirW [MAX_PATH];
927 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
928 IShellFolder *IDesktopFolder, *testIShellFolder;
929 ITEMIDLIST *newPIDL;
930 int len;
932 hr = SHGetDesktopFolder(&psfDesktop);
933 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
934 if (hr != S_OK) return;
936 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
937 dwFlags = 0xffffffff;
938 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
939 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
940 ok (dwFlags == desktopFlags, "Wrong Desktop attributes: %08x\n", dwFlags);
942 /* .. or with no itemidlist at all. */
943 dwFlags = 0xffffffff;
944 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
945 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
946 ok (dwFlags == desktopFlags, "Wrong Desktop attributes: %08x\n", dwFlags);
948 /* Testing the attributes of the MyComputer shellfolder */
949 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
950 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
951 if (hr != S_OK) {
952 IShellFolder_Release(psfDesktop);
953 return;
956 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
957 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
959 dwFlags = 0xffffffff;
960 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
961 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
962 todo_wine
963 ok (dwFlags == (myComputerFlags | SFGAO_CANLINK), "Wrong MyComputer attributes: %08x\n", dwFlags);
965 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
966 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
967 IShellFolder_Release(psfDesktop);
968 ILFree(pidlMyComputer);
969 if (hr != S_OK) return;
971 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
972 todo_wine
973 ok (hr == E_INVALIDARG, "MyComputer->GetAttributesOf(empty pidl) should fail! hr = %08x\n", hr);
975 dwFlags = 0xffffffff;
976 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
977 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
978 todo_wine
979 ok (dwFlags == myComputerFlags, "Wrong MyComputer attributes: %08x\n", dwFlags);
981 IShellFolder_Release(psfMyComputer);
983 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
984 len = lstrlenA(cCurrDirA);
986 if (len == 0) {
987 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
988 return;
990 if (len > 3 && cCurrDirA[len-1] == '\\')
991 cCurrDirA[len-1] = 0;
993 /* create test directory */
994 CreateFilesFolders();
996 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
998 hr = SHGetDesktopFolder(&IDesktopFolder);
999 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1001 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1002 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1004 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1005 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1007 ILFree(newPIDL);
1009 /* get relative PIDL */
1010 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1011 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1013 /* test the shell attributes of the test directory using the relative PIDL */
1014 dwFlags = SFGAO_FOLDER;
1015 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1016 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1017 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1019 /* free memory */
1020 ILFree(newPIDL);
1022 /* append testdirectory name to path */
1023 if (cCurrDirA[len-1] == '\\')
1024 cCurrDirA[len-1] = 0;
1025 lstrcatA(cCurrDirA, "\\testdir");
1026 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1028 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1029 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1031 /* test the shell attributes of the test directory using the absolute PIDL */
1032 dwFlags = SFGAO_FOLDER;
1033 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1034 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1035 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1037 /* free memory */
1038 ILFree(newPIDL);
1040 IShellFolder_Release(testIShellFolder);
1042 Cleanup();
1044 IShellFolder_Release(IDesktopFolder);
1047 static void test_SHGetPathFromIDList(void)
1049 SHITEMID emptyitem = { 0, { 0 } };
1050 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1051 LPITEMIDLIST pidlMyComputer;
1052 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1053 BOOL result;
1054 HRESULT hr;
1055 LPSHELLFOLDER psfDesktop;
1056 WCHAR wszMyComputer[] = {
1057 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1058 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1059 WCHAR wszFileName[MAX_PATH];
1060 LPITEMIDLIST pidlTestFile;
1061 HANDLE hTestFile;
1062 STRRET strret;
1063 static WCHAR wszTestFile[] = {
1064 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1065 LPITEMIDLIST pidlPrograms;
1067 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1068 wszPath[0] = 'a';
1069 wszPath[1] = '\0';
1070 result = SHGetPathFromIDListW(NULL, wszPath);
1071 ok(!result, "Expected failure\n");
1072 ok(!wszPath[0], "Expected empty string\n");
1074 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1075 result = SHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1076 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1077 if (!result) return;
1079 result = SHGetPathFromIDListW(pidlEmpty, wszPath);
1080 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1081 if (!result) return;
1082 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1084 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1085 hr = SHGetDesktopFolder(&psfDesktop);
1086 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1087 if (hr != S_OK) return;
1089 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1090 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1091 if (hr != S_OK) {
1092 IShellFolder_Release(psfDesktop);
1093 return;
1096 SetLastError(0xdeadbeef);
1097 wszPath[0] = 'a';
1098 wszPath[1] = '\0';
1099 result = SHGetPathFromIDListW(pidlMyComputer, wszPath);
1100 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1101 ok (GetLastError()==0xdeadbeef ||
1102 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1103 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1104 ok (!wszPath[0], "Expected empty path\n");
1105 if (result) {
1106 IShellFolder_Release(psfDesktop);
1107 return;
1110 ILFree(pidlMyComputer);
1112 result = SHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1113 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1114 if (!result) {
1115 IShellFolder_Release(psfDesktop);
1116 return;
1118 myPathAddBackslashW(wszFileName);
1119 lstrcatW(wszFileName, wszTestFile);
1120 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1121 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1122 if (hTestFile == INVALID_HANDLE_VALUE) {
1123 IShellFolder_Release(psfDesktop);
1124 return;
1126 CloseHandle(hTestFile);
1128 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1129 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1130 if (hr != S_OK) {
1131 IShellFolder_Release(psfDesktop);
1132 DeleteFileW(wszFileName);
1133 ILFree(pidlTestFile);
1134 return;
1137 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1138 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1139 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1140 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1141 IShellFolder_Release(psfDesktop);
1142 DeleteFileW(wszFileName);
1143 if (hr != S_OK) {
1144 ILFree(pidlTestFile);
1145 return;
1147 StrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1148 ok(0 == lstrcmpW(wszFileName, wszPath),
1149 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1150 "returned incorrect path for file placed on desktop\n");
1152 result = SHGetPathFromIDListW(pidlTestFile, wszPath);
1153 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1154 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1156 if (pSHGetPathFromIDListEx)
1158 result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1159 ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1160 ok(!lstrcmpiW(wszDesktop, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1161 wine_dbgstr_w(wszPath), wine_dbgstr_w(wszDesktop));
1163 result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1164 ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1165 ok(!lstrcmpiW(wszFileName, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1166 wine_dbgstr_w(wszPath), wine_dbgstr_w(wszFileName));
1168 SetLastError(0xdeadbeef);
1169 memset(wszPath, 0x55, sizeof(wszPath));
1170 result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, 5, SFGAO_FILESYSTEM);
1171 ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1173 SetLastError(0xdeadbeef);
1174 memset(wszPath, 0x55, sizeof(wszPath));
1175 result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, 5, SFGAO_FILESYSTEM);
1176 ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1178 else
1179 win_skip("SHGetPathFromIDListEx not available\n");
1181 ILFree(pidlTestFile);
1183 /* Test if we can get the path from the start menu "program files" PIDL. */
1184 hr = SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1185 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1187 SetLastError(0xdeadbeef);
1188 result = SHGetPathFromIDListW(pidlPrograms, wszPath);
1189 ILFree(pidlPrograms);
1190 ok(result, "SHGetPathFromIDListW failed\n");
1193 static void test_EnumObjects_and_CompareIDs(void)
1195 ITEMIDLIST *newPIDL;
1196 IShellFolder *IDesktopFolder, *testIShellFolder;
1197 char cCurrDirA [MAX_PATH] = {0};
1198 static const CHAR cTestDirA[] = "\\testdir";
1199 WCHAR cTestDirW[MAX_PATH];
1200 int len;
1201 HRESULT hr;
1203 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1204 len = lstrlenA(cCurrDirA);
1206 if(len == 0) {
1207 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1208 return;
1210 if(cCurrDirA[len-1] == '\\')
1211 cCurrDirA[len-1] = 0;
1213 lstrcatA(cCurrDirA, cTestDirA);
1214 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1216 hr = SHGetDesktopFolder(&IDesktopFolder);
1217 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1219 CreateFilesFolders();
1221 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1222 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1224 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1225 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1227 test_EnumObjects(testIShellFolder);
1229 IShellFolder_Release(testIShellFolder);
1231 Cleanup();
1233 ILFree(newPIDL);
1235 IShellFolder_Release(IDesktopFolder);
1238 /* A simple implementation of an IPropertyBag, which returns fixed values for
1239 * 'Target' and 'Attributes' properties.
1241 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1242 void **ppvObject)
1244 if (!ppvObject)
1245 return E_INVALIDARG;
1247 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1248 *ppvObject = iface;
1249 } else {
1250 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1251 return E_NOINTERFACE;
1254 IPropertyBag_AddRef(iface);
1255 return S_OK;
1258 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1259 return 2;
1262 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1263 return 1;
1266 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1267 VARIANT *pVar, IErrorLog *pErrorLog)
1269 static const WCHAR wszTargetSpecialFolder[] = {
1270 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1271 static const WCHAR wszTarget[] = {
1272 'T','a','r','g','e','t',0 };
1273 static const WCHAR wszAttributes[] = {
1274 'A','t','t','r','i','b','u','t','e','s',0 };
1275 static const WCHAR wszResolveLinkFlags[] = {
1276 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1277 static const WCHAR wszTargetKnownFolder[] = {
1278 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1279 static const WCHAR wszCLSID[] = {
1280 'C','L','S','I','D',0 };
1282 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1283 ok(V_VT(pVar) == VT_I4, "Wrong variant type for 'TargetSpecialFolder' property!\n");
1284 return E_INVALIDARG;
1287 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1289 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1290 return E_INVALIDARG;
1293 if (!lstrcmpW(pszPropName, wszTarget)) {
1294 WCHAR wszPath[MAX_PATH];
1295 BOOL result;
1297 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'Target' property!\n");
1298 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1300 result = SHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1301 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1302 if (!result) return E_INVALIDARG;
1304 V_BSTR(pVar) = SysAllocString(wszPath);
1305 return S_OK;
1308 if (!lstrcmpW(pszPropName, wszAttributes)) {
1309 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1310 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1311 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1312 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1313 return S_OK;
1316 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1317 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1318 /* TODO */
1319 return E_INVALIDARG;
1322 if (!lstrcmpW(pszPropName, wszCLSID)) {
1323 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1324 /* TODO */
1325 return E_INVALIDARG;
1328 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1329 return E_INVALIDARG;
1332 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1333 VARIANT *pVar)
1335 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1336 return E_NOTIMPL;
1339 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1340 InitPropertyBag_IPropertyBag_QueryInterface,
1341 InitPropertyBag_IPropertyBag_AddRef,
1342 InitPropertyBag_IPropertyBag_Release,
1343 InitPropertyBag_IPropertyBag_Read,
1344 InitPropertyBag_IPropertyBag_Write
1347 static struct IPropertyBag InitPropertyBag = {
1348 &InitPropertyBag_IPropertyBagVtbl
1351 static void test_FolderShortcut(void) {
1352 IPersistPropertyBag *pPersistPropertyBag;
1353 IShellFolder *pShellFolder, *pDesktopFolder;
1354 IPersistFolder3 *pPersistFolder3;
1355 HRESULT hr;
1356 STRRET strret;
1357 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1358 BOOL result;
1359 CLSID clsid;
1360 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1361 HKEY hShellExtKey;
1362 WCHAR wszWineTestFolder[] = {
1363 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1364 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1365 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1366 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1367 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1368 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1369 'N','a','m','e','S','p','a','c','e','\\',
1370 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1371 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1373 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1374 static const GUID CLSID_UnixDosFolder =
1375 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1377 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1378 * via their IPersistPropertyBag interface. And that the target folder
1379 * is taken from the IPropertyBag's 'Target' property.
1381 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1382 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1383 if (hr == REGDB_E_CLASSNOTREG) {
1384 win_skip("CLSID_FolderShortcut is not implemented\n");
1385 return;
1387 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1388 if (hr != S_OK) return;
1390 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1391 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1392 if (hr != S_OK) {
1393 IPersistPropertyBag_Release(pPersistPropertyBag);
1394 return;
1397 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1398 (LPVOID*)&pShellFolder);
1399 IPersistPropertyBag_Release(pPersistPropertyBag);
1400 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1401 if (hr != S_OK) return;
1403 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1404 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* win10 */,
1405 "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1406 if (hr != S_OK) {
1407 IShellFolder_Release(pShellFolder);
1408 return;
1411 result = SHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1412 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1413 if (!result) return;
1415 StrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1416 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1418 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1419 IShellFolder_Release(pShellFolder);
1420 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1421 if (hr != S_OK) return;
1423 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1424 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1425 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1427 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1428 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1429 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1431 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1432 * shell namespace. The target folder, read from the property bag above, remains untouched.
1433 * The following tests show this: The itemidlist for some imaginary shellfolder object
1434 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1435 * itemidlist, but GetDisplayNameOf still returns the path from above.
1437 hr = SHGetDesktopFolder(&pDesktopFolder);
1438 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1439 if (hr != S_OK) return;
1441 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1442 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1443 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1444 RegCloseKey(hShellExtKey);
1445 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1446 &pidlWineTestFolder, NULL);
1447 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1448 IShellFolder_Release(pDesktopFolder);
1449 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1450 if (hr != S_OK) return;
1452 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1453 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1454 if (hr != S_OK) {
1455 IPersistFolder3_Release(pPersistFolder3);
1456 ILFree(pidlWineTestFolder);
1457 return;
1460 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1461 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1462 ok(ILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1463 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1464 ILFree(pidlCurrentFolder);
1465 ILFree(pidlWineTestFolder);
1467 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1468 IPersistFolder3_Release(pPersistFolder3);
1469 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1470 if (hr != S_OK) return;
1472 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1473 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1474 if (hr != S_OK) {
1475 IShellFolder_Release(pShellFolder);
1476 return;
1479 StrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1480 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1482 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1483 * but ShellFSFolders. */
1484 myPathAddBackslashW(wszDesktopPath);
1485 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1486 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1487 IShellFolder_Release(pShellFolder);
1488 return;
1491 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1492 &pidlSubFolder, NULL);
1493 RemoveDirectoryW(wszDesktopPath);
1494 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1495 if (hr != S_OK) {
1496 IShellFolder_Release(pShellFolder);
1497 return;
1500 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1501 (LPVOID*)&pPersistFolder3);
1502 IShellFolder_Release(pShellFolder);
1503 ILFree(pidlSubFolder);
1504 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1505 if (hr != S_OK)
1506 return;
1508 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1509 * a little bit and also allow CLSID_UnixDosFolder. */
1510 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1511 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1512 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1513 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1515 IPersistFolder3_Release(pPersistFolder3);
1518 #include "pshpack1.h"
1519 struct FileStructA {
1520 BYTE type;
1521 BYTE dummy;
1522 DWORD dwFileSize;
1523 WORD uFileDate; /* In our current implementation this is */
1524 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1525 WORD uFileAttribs;
1526 CHAR szName[1];
1529 struct FileStructW {
1530 WORD cbLen; /* Length of this element. */
1531 BYTE abFooBar1[6]; /* Beyond any recognition. */
1532 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1533 WORD uTime; /* (this is currently speculation) */
1534 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1535 WORD uTime2; /* (this is currently speculation) */
1536 BYTE abFooBar2[4]; /* Beyond any recognition. */
1537 WCHAR wszName[1]; /* The long filename in unicode. */
1538 /* Just for documentation: Right after the unicode string: */
1539 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1540 * SHITEMID->cb == uOffset + cbLen */
1542 #include "poppack.h"
1544 static void test_ITEMIDLIST_format(void) {
1545 WCHAR wszPersonal[MAX_PATH];
1546 LPSHELLFOLDER psfDesktop, psfPersonal;
1547 LPITEMIDLIST pidlPersonal, pidlFile;
1548 HANDLE hFile;
1549 HRESULT hr;
1550 BOOL bResult;
1551 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1552 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1553 int i;
1555 bResult = SHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1556 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1557 if (!bResult) return;
1559 SetLastError(0xdeadbeef);
1560 bResult = SetCurrentDirectoryW(wszPersonal);
1561 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1562 win_skip("Most W-calls are not implemented\n");
1563 return;
1565 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1566 if (!bResult) return;
1568 hr = SHGetDesktopFolder(&psfDesktop);
1569 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1570 if (hr != S_OK) return;
1572 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1573 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1574 if (hr != S_OK) {
1575 IShellFolder_Release(psfDesktop);
1576 return;
1579 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1580 (LPVOID*)&psfPersonal);
1581 IShellFolder_Release(psfDesktop);
1582 ILFree(pidlPersonal);
1583 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1584 if (hr != S_OK) return;
1586 for (i=0; i<3; i++) {
1587 CHAR szFile[MAX_PATH];
1588 struct FileStructA *pFileStructA;
1589 WORD cbOffset;
1591 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1593 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1594 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1595 if (hFile == INVALID_HANDLE_VALUE) {
1596 IShellFolder_Release(psfPersonal);
1597 return;
1599 CloseHandle(hFile);
1601 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1602 DeleteFileW(wszFile[i]);
1603 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1604 if (hr != S_OK) {
1605 IShellFolder_Release(psfPersonal);
1606 return;
1609 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1610 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1611 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1612 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1614 if (i < 2) /* First two file names are already in valid 8.3 format */
1615 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1616 else
1617 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1618 * can't implement this correctly, since unix filesystems don't support
1619 * this nasty short/long filename stuff. So we'll probably stay with our
1620 * current habit of storing the long filename here, which seems to work
1621 * just fine. */
1622 todo_wine
1623 ok(pidlFile->mkid.abID[18] == '~', "Should be derived 8.3 name!\n");
1625 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1626 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0',
1627 "Alignment byte, where there shouldn't be!\n");
1629 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1630 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1631 "There should be an alignment byte, but isn't!\n");
1633 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1634 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1635 ok ((cbOffset >= sizeof(struct FileStructA) &&
1636 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)),
1637 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1639 if (cbOffset >= sizeof(struct FileStructA) &&
1640 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1642 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1643 WCHAR *name = pFileStructW->wszName;
1645 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1646 "FileStructW's offset and length should add up to the PIDL's length!\n");
1648 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1649 /* Since we just created the file, time of creation,
1650 * time of last access and time of last write access just be the same.
1651 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1652 * after the first run. I do remember something with NTFS keeping the creation time
1653 * if a file is deleted and then created again within a couple of seconds or so.
1654 * Might be the reason. */
1655 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1656 pFileStructA->uFileTime == pFileStructW->uTime,
1657 "Last write time should match creation time!\n");
1659 /* On FAT filesystems the last access time is midnight
1660 local time, so the values of uDate2 and uTime2 will
1661 depend on the local timezone. If the times are exactly
1662 equal then the dates should be identical for both FAT
1663 and NTFS as no timezone is more than 1 day away from UTC.
1665 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1667 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1668 "Last write date and time should match last access date and time!\n");
1670 else
1672 /* Filesystem may be FAT. Check date within 1 day
1673 and seconds are zero. */
1674 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1675 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1676 "Last access time on FAT filesystems should have zero seconds.\n");
1677 /* TODO: Perform check for date being within one day.*/
1680 ok (!lstrcmpW(wszFile[i], name) ||
1681 !lstrcmpW(wszFile[i], name + 9) || /* Vista */
1682 !lstrcmpW(wszFile[i], name + 11) || /* Win7 */
1683 !lstrcmpW(wszFile[i], name + 13), /* Win8 */
1684 "The filename should be stored in unicode at this position!\n");
1688 ILFree(pidlFile);
1691 IShellFolder_Release(psfPersonal);
1694 static void test_SHGetFolderPathA(void)
1696 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1697 BOOL is_wow64;
1698 char path[MAX_PATH];
1699 char path_x86[MAX_PATH];
1700 char path_key[MAX_PATH];
1701 HRESULT hr;
1702 HKEY key;
1704 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1706 hr = SHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1707 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1708 hr = SHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1709 if (hr == E_FAIL)
1711 win_skip( "Program Files (x86) not supported\n" );
1712 return;
1714 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1715 if (is_win64)
1717 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1718 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1719 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1721 else
1723 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1724 if (is_wow64)
1725 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1726 else
1727 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1729 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1731 DWORD type, count = sizeof(path_x86);
1732 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1734 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1735 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1737 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1738 RegCloseKey( key );
1741 hr = SHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1742 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1743 hr = SHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1744 if (hr == E_FAIL)
1746 win_skip( "Common Files (x86) not supported\n" );
1747 return;
1749 ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1750 if (is_win64)
1752 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1753 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1754 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1756 else
1758 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1759 if (is_wow64)
1760 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1761 else
1762 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1764 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1766 DWORD type, count = sizeof(path_x86);
1767 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1769 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1770 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1772 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1776 static void test_SHGetFolderPathAndSubDirA(void)
1778 HRESULT ret;
1779 BOOL delret;
1780 DWORD dwret;
1781 int i;
1782 static const char wine[] = "wine";
1783 static const char winetemp[] = "wine\\temp";
1784 static char appdata[MAX_PATH];
1785 static char testpath[2 * MAX_PATH];
1786 static char toolongpath[MAX_PATH+1];
1788 if(FAILED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1790 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1791 return;
1794 sprintf(testpath, "%s\\%s", appdata, winetemp);
1795 delret = RemoveDirectoryA(testpath);
1796 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1797 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1798 return;
1801 sprintf(testpath, "%s\\%s", appdata, wine);
1802 delret = RemoveDirectoryA(testpath);
1803 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1804 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1805 return;
1808 /* test invalid second parameter */
1809 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1810 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1812 /* test fourth parameter */
1813 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1814 switch(ret) {
1815 case S_OK: /* winvista */
1816 ok(!strncmp(appdata, testpath, strlen(appdata)),
1817 "expected %s to start with %s\n", testpath, appdata);
1818 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1819 "expected %s to end with %s\n", testpath, winetemp);
1820 break;
1821 case E_INVALIDARG: /* winxp, win2k3 */
1822 break;
1823 default:
1824 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
1827 /* test fifth parameter */
1828 testpath[0] = '\0';
1829 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1830 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1831 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1833 testpath[0] = '\0';
1834 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1835 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1836 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1838 testpath[0] = '\0';
1839 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1840 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1841 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1843 for(i=0; i< MAX_PATH; i++)
1844 toolongpath[i] = '0' + i % 10;
1845 toolongpath[MAX_PATH] = '\0';
1846 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1847 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1848 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1850 testpath[0] = '\0';
1851 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1852 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1854 /* test a not existing path */
1855 testpath[0] = '\0';
1856 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1857 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1858 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1860 /* create a directory inside a not existing directory */
1861 testpath[0] = '\0';
1862 ret = SHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1863 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1864 ok(!strncmp(appdata, testpath, strlen(appdata)),
1865 "expected %s to start with %s\n", testpath, appdata);
1866 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1867 "expected %s to end with %s\n", testpath, winetemp);
1868 dwret = GetFileAttributesA(testpath);
1869 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1871 /* cleanup */
1872 sprintf(testpath, "%s\\%s", appdata, winetemp);
1873 RemoveDirectoryA(testpath);
1874 sprintf(testpath, "%s\\%s", appdata, wine);
1875 RemoveDirectoryA(testpath);
1878 static void test_LocalizedNames(void)
1880 static char cCurrDirA[MAX_PATH];
1881 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1882 IShellFolder *IDesktopFolder, *testIShellFolder;
1883 ITEMIDLIST *newPIDL;
1884 int len;
1885 HRESULT hr;
1886 static char resourcefile[MAX_PATH];
1887 DWORD res;
1888 HANDLE file;
1889 STRRET strret;
1890 BOOL ret;
1892 static const char desktopini_contents1[] =
1893 "[.ShellClassInfo]\r\n"
1894 "LocalizedResourceName=@";
1895 static const char desktopini_contents2[] =
1896 ",-1\r\n";
1897 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1898 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1900 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1901 CreateDirectoryA(".\\testfolder", NULL);
1903 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1905 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1907 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1908 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1909 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1910 ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1911 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1912 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
1913 ok(ret, "WriteFile failed %i\n", GetLastError());
1914 CloseHandle(file);
1916 /* get IShellFolder for parent */
1917 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1918 len = lstrlenA(cCurrDirA);
1920 if (len == 0) {
1921 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1922 goto cleanup;
1924 if(cCurrDirA[len-1] == '\\')
1925 cCurrDirA[len-1] = 0;
1927 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1929 hr = SHGetDesktopFolder(&IDesktopFolder);
1930 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1932 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1933 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1935 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1936 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1938 ILFree(newPIDL);
1940 /* windows reads the display name from the resource */
1941 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1942 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1944 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1945 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1947 hr = StrRetToBufW(&strret, newPIDL, tempbufW, ARRAY_SIZE(tempbufW));
1948 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1949 todo_wine
1950 ok (!lstrcmpiW(tempbufW, folderdisplayW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1952 /* editing name is also read from the resource */
1953 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1954 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1956 hr = StrRetToBufW(&strret, newPIDL, tempbufW, ARRAY_SIZE(tempbufW));
1957 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1958 todo_wine
1959 ok (!lstrcmpiW(tempbufW, folderdisplayW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1961 /* parsing name is unchanged */
1962 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1963 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1965 hr = StrRetToBufW(&strret, newPIDL, tempbufW, ARRAY_SIZE(tempbufW));
1966 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1967 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1969 IShellFolder_Release(IDesktopFolder);
1970 IShellFolder_Release(testIShellFolder);
1972 ILFree(newPIDL);
1974 cleanup:
1975 DeleteFileA(".\\testfolder\\desktop.ini");
1976 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1977 RemoveDirectoryA(".\\testfolder");
1980 static void test_SHCreateShellItem(void)
1982 IShellItem *shellitem, *shellitem2;
1983 IPersistIDList *persistidl;
1984 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
1985 HRESULT ret;
1986 char curdirA[MAX_PATH];
1987 WCHAR curdirW[MAX_PATH];
1988 WCHAR fnbufW[MAX_PATH];
1989 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
1990 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
1992 GetCurrentDirectoryA(MAX_PATH, curdirA);
1994 if (!pSHCreateShellItem)
1996 win_skip("SHCreateShellItem isn't available\n");
1997 return;
2000 if (!curdirA[0])
2002 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2003 return;
2006 ret = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2007 ok(ret == S_OK, "Got 0x%08x\n", ret);
2009 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2011 ret = SHGetDesktopFolder(&desktopfolder);
2012 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2014 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2015 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2017 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2018 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2020 CreateTestFile(".\\testfile");
2022 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2023 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2025 pidl_abstestfile = ILCombine(pidl_cwd, pidl_testfile);
2027 shellitem = (void*)0xdeadbeef;
2028 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2029 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2030 ok(shellitem == 0, "Got %p\n", shellitem);
2032 if (0) /* crashes on Windows XP */
2034 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2035 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2036 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2037 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2040 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2041 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2042 if (SUCCEEDED(ret))
2044 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2045 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2046 if (SUCCEEDED(ret))
2048 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2049 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2050 if (SUCCEEDED(ret))
2052 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2053 ILFree(pidl_test);
2055 IPersistIDList_Release(persistidl);
2057 IShellItem_Release(shellitem);
2060 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2061 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2062 if (SUCCEEDED(ret))
2064 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2065 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2066 if (SUCCEEDED(ret))
2068 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2069 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2070 if (SUCCEEDED(ret))
2072 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2073 ILFree(pidl_test);
2075 IPersistIDList_Release(persistidl);
2078 ret = IShellItem_GetParent(shellitem, &shellitem2);
2079 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2080 if (SUCCEEDED(ret))
2082 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2083 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2084 if (SUCCEEDED(ret))
2086 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2087 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2088 if (SUCCEEDED(ret))
2090 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2091 ILFree(pidl_test);
2093 IPersistIDList_Release(persistidl);
2095 IShellItem_Release(shellitem2);
2098 IShellItem_Release(shellitem);
2101 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2102 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2103 if (SUCCEEDED(ret))
2105 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2106 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2107 if (SUCCEEDED(ret))
2109 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2110 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2111 if (SUCCEEDED(ret))
2113 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2114 ILFree(pidl_test);
2116 IPersistIDList_Release(persistidl);
2118 IShellItem_Release(shellitem);
2121 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2122 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2123 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2124 if (SUCCEEDED(ret))
2126 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2127 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2128 if (SUCCEEDED(ret))
2130 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2131 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2132 if (SUCCEEDED(ret))
2134 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2135 ILFree(pidl_test);
2137 IPersistIDList_Release(persistidl);
2139 IShellItem_Release(shellitem);
2142 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2143 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2144 if (SUCCEEDED(ret))
2146 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2147 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2148 if (SUCCEEDED(ret))
2150 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2151 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2152 if (SUCCEEDED(ret))
2154 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2155 ILFree(pidl_test);
2157 IPersistIDList_Release(persistidl);
2160 IShellItem_Release(shellitem);
2163 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2164 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2165 if (SUCCEEDED(ret))
2167 ret = IShellItem_GetParent(shellitem, &shellitem2);
2168 ok(FAILED(ret), "Got 0x%08x\n", ret);
2169 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2170 IShellItem_Release(shellitem);
2173 /* SHCreateItemFromParsingName */
2174 if(pSHCreateItemFromParsingName)
2176 if(0)
2178 /* Crashes under windows 7 */
2179 pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2182 shellitem = (void*)0xdeadbeef;
2183 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2184 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2185 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2187 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2188 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2189 "SHCreateItemFromParsingName returned %x\n", ret);
2190 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2192 lstrcpyW(fnbufW, curdirW);
2193 myPathAddBackslashW(fnbufW);
2194 lstrcatW(fnbufW, testfileW);
2196 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2197 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2198 if(SUCCEEDED(ret))
2200 LPWSTR tmp_fname;
2201 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2202 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2203 if(SUCCEEDED(ret))
2205 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2206 CoTaskMemFree(tmp_fname);
2208 IShellItem_Release(shellitem);
2211 else
2212 win_skip("No SHCreateItemFromParsingName\n");
2215 /* SHCreateItemFromIDList */
2216 if(pSHCreateItemFromIDList)
2218 if(0)
2220 /* Crashes under win7 */
2221 pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2224 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2225 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2227 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2228 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2229 if (SUCCEEDED(ret))
2231 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2232 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2233 if (SUCCEEDED(ret))
2235 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2236 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2237 if (SUCCEEDED(ret))
2239 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2240 ILFree(pidl_test);
2242 IPersistIDList_Release(persistidl);
2244 IShellItem_Release(shellitem);
2247 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2248 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2249 if (SUCCEEDED(ret))
2251 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2252 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2253 if (SUCCEEDED(ret))
2255 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2256 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2257 if (SUCCEEDED(ret))
2259 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2260 ILFree(pidl_test);
2262 IPersistIDList_Release(persistidl);
2264 IShellItem_Release(shellitem);
2267 else
2268 win_skip("No SHCreateItemFromIDList\n");
2270 /* SHCreateItemFromRelativeName */
2271 if(pSHCreateItemFromRelativeName && pSHGetKnownFolderPath)
2273 IShellItem *shellitem_desktop = NULL;
2274 WCHAR *desktop_path, *displayname;
2275 WCHAR testfile_path[MAX_PATH] = {0};
2276 HANDLE file;
2277 LPITEMIDLIST pidl_desktop_testfile = NULL;
2278 int order;
2280 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem_desktop);
2281 ok(ret == S_OK, "SHCreateShellItem failed: 0x%08x.\n", ret);
2283 shellitem = (void*)0xdeadbeef;
2284 ret = pSHCreateItemFromRelativeName(shellitem_desktop, NULL, NULL, &IID_IShellItem,
2285 (void**)&shellitem);
2286 ok(ret == E_INVALIDARG, "Expected 0x%08x but SHCreateItemFromRelativeName return: 0x%08x.\n",
2287 E_INVALIDARG, ret);
2288 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2290 /* Test with a non-existent file */
2291 shellitem = (void*)0xdeadbeef;
2292 ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2293 (void**)&shellitem);
2294 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2295 "Expected 0x%08x but SHCreateItemFromRelativeName return: 0x%08x.\n",
2296 HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), ret);
2297 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2299 /* Create a file for testing in desktop folder */
2300 pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &desktop_path);
2301 lstrcatW(testfile_path, desktop_path);
2302 myPathAddBackslashW(testfile_path);
2303 lstrcatW(testfile_path, testfileW);
2304 file = CreateFileW(testfile_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
2305 ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: 0x%08x.\n", GetLastError());
2306 CloseHandle(file);
2308 shellitem = (void*)0xdeadbeef;
2309 ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2310 (void**)&shellitem);
2311 ok(ret == S_OK, "SHCreateItemFromRelativeName failed: 0x%08x.\n", ret);
2312 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2313 if(SUCCEEDED(ret))
2315 ret = IShellItem_GetDisplayName(shellitem, 0, &displayname);
2316 ok(ret == S_OK, "IShellItem_GetDisplayName failed: 0x%08x.\n", ret);
2317 ok(!lstrcmpW(displayname, testfileW), "got wrong display name: %s.\n", wine_dbgstr_w(displayname));
2318 CoTaskMemFree(displayname);
2320 shellitem2 = (void*)0xdeadbeef;
2321 ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2322 (void**)&shellitem2);
2323 ok(ret == S_OK, "SHCreateItemFromRelativeName failed: 0x%08x.\n", ret);
2324 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2325 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2326 ok(!order, "order got wrong value: %d.\n", order);
2327 IShellItem_Release(shellitem2);
2329 shellitem2 = (void*)0xdeadbeef;
2330 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, testfileW, NULL,
2331 &pidl_desktop_testfile, NULL);
2332 ok(ret == S_OK, "ParseDisplayName failed 0x%08x.\n", ret);
2333 ret = pSHCreateItemFromIDList(pidl_desktop_testfile, &IID_IShellItem, (void**)&shellitem2);
2334 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2335 ok(ret == S_OK, "IShellItem_Compare fail: 0x%08x.\n", ret);
2336 ok(!order, "order got wrong value: %d.\n", order);
2337 ILFree(pidl_desktop_testfile);
2338 IShellItem_Release(shellitem2);
2340 IShellItem_Release(shellitem);
2343 DeleteFileW(testfile_path);
2344 CoTaskMemFree(desktop_path);
2345 IShellItem_Release(shellitem_desktop);
2347 else
2348 win_skip("No SHCreateItemFromRelativeName or SHGetKnownFolderPath\n");
2350 /* SHCreateItemInKnownFolder */
2351 if(pSHCreateItemInKnownFolder && pSHGetKnownFolderPath)
2353 WCHAR *desktop_path;
2354 WCHAR testfile_path[MAX_PATH] = {0};
2355 HANDLE file;
2356 WCHAR *displayname = NULL;
2357 int order;
2358 LPITEMIDLIST pidl_desktop_testfile = NULL;
2360 shellitem = (void*)0xdeadbeef;
2361 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, NULL, &IID_IShellItem,
2362 (void**)&shellitem);
2363 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2364 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2365 if(SUCCEEDED(ret))
2367 shellitem2 = (void*)0xdeadbeef;
2368 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem2);
2369 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2370 if(SUCCEEDED(ret))
2372 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2373 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2374 ok(!order, "order got wrong value: %d.\n", order);
2375 IShellItem_Release(shellitem2);
2377 IShellItem_Release(shellitem);
2380 /* Test with a non-existent file */
2381 shellitem = (void*)0xdeadbeef;
2382 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2383 (void**)&shellitem);
2384 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2385 "Expected 0x%08x but SHCreateItemInKnownFolder return: 0x%08x.\n",
2386 HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), ret);
2387 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2389 pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &desktop_path);
2390 lstrcatW(testfile_path, desktop_path);
2391 myPathAddBackslashW(testfile_path);
2392 lstrcatW(testfile_path, testfileW);
2393 file = CreateFileW(testfile_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
2394 ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: 0x%08x.\n", GetLastError());
2395 CloseHandle(file);
2397 shellitem = (void*)0xdeadbeef;
2398 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2399 (void**)&shellitem);
2400 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2401 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2402 if(SUCCEEDED(ret))
2404 ret = IShellItem_GetDisplayName(shellitem, 0, &displayname);
2405 ok(ret == S_OK, "IShellItem_GetDisplayName failed: 0x%08x.\n", ret);
2406 ok(!lstrcmpW(displayname, testfileW), "got wrong display name: %s.\n",
2407 wine_dbgstr_w(displayname));
2408 CoTaskMemFree(displayname);
2410 shellitem2 = (void*)0xdeadbeef;
2411 ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2412 (void**)&shellitem2);
2413 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2414 ok(shellitem2 != NULL, "shellitem was %p.\n", shellitem);
2415 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2416 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2417 ok(!order, "order got wrong value: %d.\n", order);
2418 IShellItem_Release(shellitem2);
2420 shellitem2 = (void*)0xdeadbeef;
2421 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, testfileW, NULL,
2422 &pidl_desktop_testfile, NULL);
2423 ok(SUCCEEDED(ret), "ParseDisplayName returned %x.\n", ret);
2424 ret = pSHCreateItemFromIDList(pidl_desktop_testfile, &IID_IShellItem, (void**)&shellitem2);
2425 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2426 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2427 ok(!order, "order got wrong value: %d.\n", order);
2428 ILFree(pidl_desktop_testfile);
2429 IShellItem_Release(shellitem2);
2431 IShellItem_Release(shellitem);
2434 shellitem = (void*)0xdeadbeef;
2435 ret = pSHCreateItemInKnownFolder(&FOLDERID_Documents, 0, NULL, &IID_IShellItem,
2436 (void**)&shellitem);
2437 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2438 ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2439 if(SUCCEEDED(ret))
2441 shellitem2 = (void*)0xdeadbeef;
2442 ret = pSHCreateItemInKnownFolder(&FOLDERID_Documents, 0, NULL, &IID_IShellItem,
2443 (void**)&shellitem2);
2444 ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2445 ok(shellitem2 != NULL, "shellitem was %p.\n", shellitem);
2446 ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2447 ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2448 ok(!order, "order got wrong value: %d.\n", order);
2449 IShellItem_Release(shellitem2);
2451 IShellItem_Release(shellitem);
2453 DeleteFileW(testfile_path);
2454 CoTaskMemFree(desktop_path);
2456 else
2457 win_skip("No SHCreateItemInKnownFolder or SHGetKnownFolderPath\n");
2459 DeleteFileA(".\\testfile");
2460 ILFree(pidl_abstestfile);
2461 ILFree(pidl_testfile);
2462 ILFree(pidl_desktop);
2463 ILFree(pidl_cwd);
2464 IShellFolder_Release(currentfolder);
2465 IShellFolder_Release(desktopfolder);
2468 static void test_SHGetNameFromIDList(void)
2470 IShellItem *shellitem;
2471 LPITEMIDLIST pidl;
2472 LPWSTR name_string;
2473 HRESULT hres;
2474 UINT i;
2475 static const DWORD flags[] = {
2476 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2477 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2478 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2479 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2481 if(!pSHGetNameFromIDList)
2483 win_skip("SHGetNameFromIDList missing.\n");
2484 return;
2487 /* This should be available on any platform that passed the above test. */
2488 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2490 if(0)
2492 /* Crashes under win7 */
2493 pSHGetNameFromIDList(NULL, 0, NULL);
2496 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2497 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2499 /* Test the desktop */
2500 hres = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2501 ok(hres == S_OK, "Got 0x%08x\n", hres);
2502 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2503 ok(hres == S_OK, "Got 0x%08x\n", hres);
2504 if(SUCCEEDED(hres))
2506 WCHAR *nameSI, *nameSH;
2507 WCHAR buf[MAX_PATH];
2508 HRESULT hrSI, hrSH, hrSF;
2509 STRRET strret;
2510 IShellFolder *psf;
2511 BOOL res;
2513 SHGetDesktopFolder(&psf);
2514 for(i = 0; flags[i] != -1234; i++)
2516 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2517 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2518 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2519 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2520 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2521 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2523 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2524 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2526 if(SUCCEEDED(hrSF))
2528 StrRetToBufW(&strret, NULL, buf, MAX_PATH);
2529 if(SUCCEEDED(hrSI))
2530 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2531 if(SUCCEEDED(hrSF))
2532 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2534 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2535 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2537 IShellFolder_Release(psf);
2539 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2540 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2541 res = SHGetPathFromIDListW(pidl, buf);
2542 ok(res == TRUE, "Got %d\n", res);
2543 if(SUCCEEDED(hrSI) && res)
2544 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2545 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2547 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2548 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2549 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2551 IShellItem_Release(shellitem);
2553 ILFree(pidl);
2555 /* Test the control panel */
2556 hres = SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2557 ok(hres == S_OK, "Got 0x%08x\n", hres);
2558 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2559 ok(hres == S_OK, "Got 0x%08x\n", hres);
2560 if(SUCCEEDED(hres))
2562 WCHAR *nameSI, *nameSH;
2563 WCHAR buf[MAX_PATH];
2564 HRESULT hrSI, hrSH, hrSF;
2565 STRRET strret;
2566 IShellFolder *psf;
2567 BOOL res;
2569 SHGetDesktopFolder(&psf);
2570 for(i = 0; flags[i] != -1234; i++)
2572 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2573 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2574 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2575 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2576 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2577 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2579 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2580 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2582 if(SUCCEEDED(hrSF))
2584 StrRetToBufW(&strret, NULL, buf, MAX_PATH);
2585 if(SUCCEEDED(hrSI))
2586 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2587 if(SUCCEEDED(hrSF))
2588 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2590 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2591 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2593 IShellFolder_Release(psf);
2595 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2596 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2597 res = SHGetPathFromIDListW(pidl, buf);
2598 ok(res == FALSE, "Got %d\n", res);
2599 if(SUCCEEDED(hrSI) && res)
2600 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2601 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2603 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2604 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2605 "Got 0x%08x\n", hres);
2606 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2608 IShellItem_Release(shellitem);
2610 ILFree(pidl);
2613 static void test_SHGetItemFromDataObject(void)
2615 IShellFolder *psfdesktop;
2616 IShellItem *psi;
2617 IShellView *psv;
2618 HRESULT hres;
2620 if(!pSHGetItemFromDataObject)
2622 win_skip("No SHGetItemFromDataObject.\n");
2623 return;
2626 if(0)
2628 /* Crashes under win7 */
2629 pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2632 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2633 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2635 SHGetDesktopFolder(&psfdesktop);
2637 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2638 ok(hres == S_OK, "got 0x%08x\n", hres);
2639 if(SUCCEEDED(hres))
2641 IEnumIDList *peidl;
2642 IDataObject *pdo;
2643 SHCONTF enum_flags;
2645 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2646 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2647 ok(hres == S_OK, "got 0x%08x\n", hres);
2648 if(SUCCEEDED(hres))
2650 LPITEMIDLIST apidl[5];
2651 UINT count = 0, i;
2653 for(count = 0; count < 5; count++)
2654 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2655 break;
2657 if(count)
2659 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2660 &IID_IDataObject, NULL, (void**)&pdo);
2661 ok(hres == S_OK, "got 0x%08x\n", hres);
2662 if(SUCCEEDED(hres))
2664 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2665 ok(hres == S_OK, "got 0x%08x\n", hres);
2666 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2667 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2668 ok(hres == S_OK, "got 0x%08x\n", hres);
2669 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2670 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2671 ok(hres == S_OK, "got 0x%08x\n", hres);
2672 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2673 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2674 ok(hres == S_OK, "got 0x%08x\n", hres);
2675 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2676 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2677 ok(hres == S_OK, "got 0x%08x\n", hres);
2678 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2680 IDataObject_Release(pdo);
2683 else
2684 skip("No file(s) found - skipping single-file test.\n");
2686 if(count > 1)
2688 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2689 &IID_IDataObject, NULL, (void**)&pdo);
2690 ok(hres == S_OK, "got 0x%08x\n", hres);
2691 if(SUCCEEDED(hres))
2693 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2694 ok(hres == S_OK, "got 0x%08x\n", hres);
2695 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2696 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2697 ok(hres == S_OK, "got 0x%08x\n", hres);
2698 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2699 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2700 ok(hres == S_OK, "got 0x%08x\n", hres);
2701 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2702 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2703 ok(hres == S_OK, "got 0x%08x\n", hres);
2704 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2705 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2706 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2707 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2708 IDataObject_Release(pdo);
2711 else
2712 skip("zero or one file found - skipping multi-file test.\n");
2714 for(i = 0; i < count; i++)
2715 ILFree(apidl[i]);
2717 IEnumIDList_Release(peidl);
2720 IShellView_Release(psv);
2723 IShellFolder_Release(psfdesktop);
2726 static void test_ShellItemCompare(void)
2728 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2729 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2730 IShellFolder *psf_desktop, *psf_current;
2731 LPITEMIDLIST pidl_cwd;
2732 WCHAR curdirW[MAX_PATH];
2733 BOOL failed;
2734 HRESULT hr;
2735 static const WCHAR filesW[][9] = {
2736 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2737 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2738 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2739 int order;
2740 UINT i;
2742 if(!pSHCreateShellItem)
2744 win_skip("SHCreateShellItem missing.\n");
2745 return;
2748 GetCurrentDirectoryW(MAX_PATH, curdirW);
2749 if (!curdirW[0])
2751 skip("Failed to get current directory, skipping.\n");
2752 return;
2755 CreateDirectoryA(".\\a", NULL);
2756 CreateDirectoryA(".\\b", NULL);
2757 CreateDirectoryA(".\\c", NULL);
2758 CreateTestFile(".\\a\\a");
2759 CreateTestFile(".\\a\\b");
2760 CreateTestFile(".\\a\\c");
2761 CreateTestFile(".\\b\\a");
2762 CreateTestFile(".\\b\\b");
2763 CreateTestFile(".\\b\\c");
2764 CreateTestFile(".\\c\\a");
2765 CreateTestFile(".\\c\\b");
2766 CreateTestFile(".\\c\\c");
2768 SHGetDesktopFolder(&psf_desktop);
2769 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2770 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2771 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2772 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2773 IShellFolder_Release(psf_desktop);
2774 ILFree(pidl_cwd);
2776 /* Generate ShellItems for the files */
2777 memset(&psi, 0, sizeof(psi));
2778 failed = FALSE;
2779 for(i = 0; i < 9; i++)
2781 LPITEMIDLIST pidl_testfile = NULL;
2783 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2784 NULL, &pidl_testfile, NULL);
2785 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2786 if(SUCCEEDED(hr))
2788 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2789 ok(hr == S_OK, "Got 0x%08x\n", hr);
2790 ILFree(pidl_testfile);
2792 if(FAILED(hr)) failed = TRUE;
2794 if(failed)
2796 skip("Failed to create all shellitems.\n");
2797 goto cleanup;
2800 /* Generate ShellItems for the folders */
2801 hr = IShellItem_GetParent(psi[0], &psi_a);
2802 ok(hr == S_OK, "Got 0x%08x\n", hr);
2803 if(FAILED(hr)) failed = TRUE;
2804 hr = IShellItem_GetParent(psi[3], &psi_b);
2805 ok(hr == S_OK, "Got 0x%08x\n", hr);
2806 if(FAILED(hr)) failed = TRUE;
2807 hr = IShellItem_GetParent(psi[6], &psi_c);
2808 ok(hr == S_OK, "Got 0x%08x\n", hr);
2809 if(FAILED(hr)) failed = TRUE;
2811 if(failed)
2813 skip("Failed to create shellitems.\n");
2814 goto cleanup;
2817 if(0)
2819 /* Crashes on native (win7, winxp) */
2820 IShellItem_Compare(psi_a, NULL, 0, NULL);
2821 IShellItem_Compare(psi_a, psi_b, 0, NULL);
2822 IShellItem_Compare(psi_a, NULL, 0, &order);
2825 /* Basics */
2826 for(i = 0; i < 9; i++)
2828 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2829 ok(hr == S_OK, "Got 0x%08x\n", hr);
2830 ok(order == 0, "Got order %d\n", order);
2831 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2832 ok(hr == S_OK, "Got 0x%08x\n", hr);
2833 ok(order == 0, "Got order %d\n", order);
2834 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2835 ok(hr == S_OK, "Got 0x%08x\n", hr);
2836 ok(order == 0, "Got order %d\n", order);
2839 /* Order */
2840 /* a\b:a\a , a\b:a\c, a\b:a\b */
2841 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2842 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2843 ok(order == 1, "Got order %d\n", order);
2844 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2845 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2846 ok(order == -1, "Got order %d\n", order);
2847 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2848 ok(hr == S_OK, "Got 0x%08x\n", hr);
2849 ok(order == 0, "Got order %d\n", order);
2851 /* b\b:a\b, b\b:c\b, b\b:c\b */
2852 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2853 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2854 ok(order == 1, "Got order %d\n", order);
2855 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2856 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2857 ok(order == -1, "Got order %d\n", order);
2858 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2859 ok(hr == S_OK, "Got 0x%08x\n", hr);
2860 ok(order == 0, "Got order %d\n", order);
2862 /* b:a\a, b:a\c, b:a\b */
2863 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2864 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2865 todo_wine ok(order == 1, "Got order %d\n", order);
2866 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2867 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2868 todo_wine ok(order == 1, "Got order %d\n", order);
2869 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2870 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2871 todo_wine ok(order == 1, "Got order %d\n", order);
2873 /* b:c\a, b:c\c, b:c\b */
2874 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2875 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2876 ok(order == -1, "Got order %d\n", order);
2877 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2878 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2879 ok(order == -1, "Got order %d\n", order);
2880 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2881 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2882 ok(order == -1, "Got order %d\n", order);
2884 /* a\b:a\a , a\b:a\c, a\b:a\b */
2885 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2886 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2887 ok(order == 1, "Got order %d\n", order);
2888 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2889 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2890 ok(order == -1, "Got order %d\n", order);
2891 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2892 ok(hr == S_OK, "Got 0x%08x\n", hr);
2893 ok(order == 0, "Got order %d\n", order);
2895 /* b\b:a\b, b\b:c\b, b\b:c\b */
2896 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2897 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2898 ok(order == 1, "Got order %d\n", order);
2899 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2900 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2901 ok(order == -1, "Got order %d\n", order);
2902 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2903 ok(hr == S_OK, "Got 0x%08x\n", hr);
2904 ok(order == 0, "Got order %d\n", order);
2906 /* b:a\a, b:a\c, b:a\b */
2907 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2908 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2909 todo_wine ok(order == 1, "Got order %d\n", order);
2910 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2911 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2912 todo_wine ok(order == 1, "Got order %d\n", order);
2913 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2914 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2915 todo_wine ok(order == 1, "Got order %d\n", order);
2917 /* b:c\a, b:c\c, b:c\b */
2918 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2919 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2920 ok(order == -1, "Got order %d\n", order);
2921 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2922 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2923 ok(order == -1, "Got order %d\n", order);
2924 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2925 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2926 ok(order == -1, "Got order %d\n", order);
2928 cleanup:
2929 IShellFolder_Release(psf_current);
2931 DeleteFileA(".\\a\\a");
2932 DeleteFileA(".\\a\\b");
2933 DeleteFileA(".\\a\\c");
2934 DeleteFileA(".\\b\\a");
2935 DeleteFileA(".\\b\\b");
2936 DeleteFileA(".\\b\\c");
2937 DeleteFileA(".\\c\\a");
2938 DeleteFileA(".\\c\\b");
2939 DeleteFileA(".\\c\\c");
2940 RemoveDirectoryA(".\\a");
2941 RemoveDirectoryA(".\\b");
2942 RemoveDirectoryA(".\\c");
2944 if(psi_a) IShellItem_Release(psi_a);
2945 if(psi_b) IShellItem_Release(psi_b);
2946 if(psi_c) IShellItem_Release(psi_c);
2948 for(i = 0; i < 9; i++)
2949 if(psi[i]) IShellItem_Release(psi[i]);
2952 /**************************************************************/
2953 /* IUnknown implementation for counting QueryInterface calls. */
2954 typedef struct {
2955 IUnknown IUnknown_iface;
2956 struct if_count {
2957 REFIID id;
2958 LONG count;
2959 } *ifaces;
2960 LONG unknown;
2961 } IUnknownImpl;
2963 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
2965 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
2968 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2970 IUnknownImpl *This = impl_from_IUnknown(iunk);
2971 UINT i;
2972 BOOL found = FALSE;
2973 for(i = 0; This->ifaces[i].id != NULL; i++)
2975 if(IsEqualIID(This->ifaces[i].id, riid))
2977 This->ifaces[i].count++;
2978 found = TRUE;
2979 break;
2982 if(!found)
2983 This->unknown++;
2984 return E_NOINTERFACE;
2987 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
2989 return 2;
2992 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
2994 return 1;
2997 static const IUnknownVtbl vt_IUnknown = {
2998 unk_fnQueryInterface,
2999 unk_fnAddRef,
3000 unk_fnRelease
3003 static void test_SHGetIDListFromObject(void)
3005 IUnknownImpl *punkimpl;
3006 IShellFolder *psfdesktop;
3007 IShellView *psv;
3008 LPITEMIDLIST pidl, pidl_desktop;
3009 HRESULT hres;
3010 UINT i;
3011 struct if_count ifaces[] =
3012 { {&IID_IPersistIDList, 0},
3013 {&IID_IPersistFolder2, 0},
3014 {&IID_IDataObject, 0},
3015 {&IID_IParentAndItem, 0},
3016 {&IID_IFolderView, 0},
3017 {NULL, 0} };
3019 if(!pSHGetIDListFromObject)
3021 win_skip("SHGetIDListFromObject missing.\n");
3022 return;
3025 if(0)
3027 /* Crashes native */
3028 pSHGetIDListFromObject(NULL, NULL);
3029 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3032 hres = pSHGetIDListFromObject(NULL, &pidl);
3033 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3035 punkimpl = heap_alloc(sizeof(*punkimpl));
3036 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3037 punkimpl->ifaces = ifaces;
3038 punkimpl->unknown = 0;
3040 hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3041 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3042 ok(ifaces[0].count, "interface not requested.\n");
3043 ok(ifaces[1].count, "interface not requested.\n");
3044 ok(ifaces[2].count, "interface not requested.\n");
3045 todo_wine
3046 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3047 "interface not requested.\n");
3048 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3049 "interface not requested.\n");
3051 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3052 heap_free(punkimpl);
3054 pidl_desktop = NULL;
3055 SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3056 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3058 SHGetDesktopFolder(&psfdesktop);
3060 /* Test IShellItem */
3061 if(pSHCreateShellItem)
3063 IShellItem *shellitem;
3064 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3065 ok(hres == S_OK, "got 0x%08x\n", hres);
3066 if(SUCCEEDED(hres))
3068 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3069 ok(hres == S_OK, "got 0x%08x\n", hres);
3070 if(SUCCEEDED(hres))
3072 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3073 ILFree(pidl);
3075 IShellItem_Release(shellitem);
3078 else
3079 skip("no SHCreateShellItem.\n");
3081 /* Test IShellFolder */
3082 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3083 ok(hres == S_OK, "got 0x%08x\n", hres);
3084 if(SUCCEEDED(hres))
3086 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3087 ILFree(pidl);
3090 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3091 ok(hres == S_OK, "got 0x%08x\n", hres);
3092 if(SUCCEEDED(hres))
3094 IEnumIDList *peidl;
3095 IDataObject *pdo;
3096 SHCONTF enum_flags;
3098 /* Test IFolderView */
3099 hres = pSHGetIDListFromObject((IUnknown*)psv, &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 /* Test IDataObject */
3108 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3109 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3110 ok(hres == S_OK, "got 0x%08x\n", hres);
3111 if(SUCCEEDED(hres))
3113 LPITEMIDLIST apidl[5];
3114 UINT count = 0;
3115 for(count = 0; count < 5; count++)
3116 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3117 break;
3119 if(count)
3121 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3122 &IID_IDataObject, NULL, (void**)&pdo);
3123 ok(hres == S_OK, "got 0x%08x\n", hres);
3124 if(SUCCEEDED(hres))
3126 pidl = (void*)0xDEADBEEF;
3127 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3128 ok(hres == S_OK, "got 0x%08x\n", hres);
3129 ok(pidl != NULL, "pidl is NULL.\n");
3130 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3131 ILFree(pidl);
3133 IDataObject_Release(pdo);
3136 else
3137 skip("No files found - skipping single-file test.\n");
3139 if(count > 1)
3141 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3142 &IID_IDataObject, NULL, (void**)&pdo);
3143 ok(hres == S_OK, "got 0x%08x\n", hres);
3144 if(SUCCEEDED(hres))
3146 pidl = (void*)0xDEADBEEF;
3147 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3148 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3149 "got 0x%08x\n", hres);
3150 ok(pidl == NULL, "pidl is not NULL.\n");
3152 IDataObject_Release(pdo);
3155 else
3156 skip("zero or one file found - skipping multi-file test.\n");
3158 for(i = 0; i < count; i++)
3159 ILFree(apidl[i]);
3161 IEnumIDList_Release(peidl);
3164 IShellView_Release(psv);
3167 IShellFolder_Release(psfdesktop);
3168 ILFree(pidl_desktop);
3171 static void test_SHGetItemFromObject(void)
3173 IUnknownImpl *punkimpl;
3174 IShellFolder *psfdesktop;
3175 LPITEMIDLIST pidl;
3176 IShellItem *psi;
3177 IUnknown *punk;
3178 HRESULT hres;
3179 struct if_count ifaces[] =
3180 { {&IID_IPersistIDList, 0},
3181 {&IID_IPersistFolder2, 0},
3182 {&IID_IDataObject, 0},
3183 {&IID_IParentAndItem, 0},
3184 {&IID_IFolderView, 0},
3185 {NULL, 0} };
3187 if(!pSHGetItemFromObject)
3189 skip("No SHGetItemFromObject.\n");
3190 return;
3193 SHGetDesktopFolder(&psfdesktop);
3195 if(0)
3197 /* Crashes with Windows 7 */
3198 pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3199 pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3200 pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3203 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3204 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3206 punkimpl = heap_alloc(sizeof(*punkimpl));
3207 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3208 punkimpl->ifaces = ifaces;
3209 punkimpl->unknown = 0;
3211 /* The same as SHGetIDListFromObject */
3212 hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3213 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3214 ok(ifaces[0].count, "interface not requested.\n");
3215 ok(ifaces[1].count, "interface not requested.\n");
3216 ok(ifaces[2].count, "interface not requested.\n");
3217 todo_wine
3218 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3219 "interface not requested.\n");
3220 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3221 "interface not requested.\n");
3223 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3224 heap_free(punkimpl);
3226 /* Test IShellItem */
3227 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3228 ok(hres == S_OK, "Got 0x%08x\n", hres);
3229 if(SUCCEEDED(hres))
3231 IShellItem *psi2;
3232 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3233 ok(hres == S_OK, "Got 0x%08x\n", hres);
3234 if(SUCCEEDED(hres))
3236 todo_wine
3237 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3238 IShellItem_Release(psi2);
3240 IShellItem_Release(psi);
3243 IShellFolder_Release(psfdesktop);
3246 static void test_SHCreateShellItemArray(void)
3248 IShellFolder *pdesktopsf, *psf;
3249 IShellItemArray *psia;
3250 IEnumIDList *peidl;
3251 HRESULT hr;
3252 WCHAR cTestDirW[MAX_PATH];
3253 LPITEMIDLIST pidl_testdir, pidl;
3254 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3256 if(!pSHCreateShellItemArray) {
3257 skip("No pSHCreateShellItemArray!\n");
3258 return;
3261 if(0)
3263 /* Crashes under native */
3264 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3265 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3266 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3267 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3270 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3271 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3273 SHGetDesktopFolder(&pdesktopsf);
3274 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3275 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3277 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3278 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3280 SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3281 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3282 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3283 ILFree(pidl);
3285 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3286 myPathAddBackslashW(cTestDirW);
3287 lstrcatW(cTestDirW, testdirW);
3289 CreateFilesFolders();
3291 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3292 ok(hr == S_OK, "got 0x%08x\n", hr);
3293 if(SUCCEEDED(hr))
3295 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3296 (void**)&psf);
3297 ok(hr == S_OK, "Got 0x%08x\n", hr);
3299 IShellFolder_Release(pdesktopsf);
3301 if(FAILED(hr))
3303 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3304 ILFree(pidl_testdir);
3305 Cleanup();
3306 return;
3309 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3310 ok(hr == S_OK, "Got %08x\n", hr);
3311 if(SUCCEEDED(hr))
3313 LPITEMIDLIST apidl[5];
3314 UINT done, numitems, i;
3316 for(done = 0; done < 5; done++)
3317 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3318 break;
3319 ok(done == 5, "Got %d pidls\n", done);
3320 IEnumIDList_Release(peidl);
3322 /* Create a ShellItemArray */
3323 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3324 ok(hr == S_OK, "Got 0x%08x\n", hr);
3325 if(SUCCEEDED(hr))
3327 IShellItem *psi;
3329 if(0)
3331 /* Crashes in Windows 7 */
3332 IShellItemArray_GetCount(psia, NULL);
3335 IShellItemArray_GetCount(psia, &numitems);
3336 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3338 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3339 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3341 /* Compare all the items */
3342 for(i = 0; i < numitems; i++)
3344 LPITEMIDLIST pidl_abs;
3345 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3347 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3348 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3349 if(SUCCEEDED(hr))
3351 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3352 ok(hr == S_OK, "Got 0x%08x\n", hr);
3353 if(SUCCEEDED(hr))
3355 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3356 ILFree(pidl);
3358 IShellItem_Release(psi);
3360 ILFree(pidl_abs);
3362 for(i = 0; i < done; i++)
3363 ILFree(apidl[i]);
3364 IShellItemArray_Release(psia);
3368 /* SHCreateShellItemArrayFromShellItem */
3369 if(pSHCreateShellItemArrayFromShellItem)
3371 IShellItem *psi;
3373 if(0)
3375 /* Crashes under Windows 7 */
3376 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3377 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3378 pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3381 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3382 ok(hr == S_OK, "Got 0x%08x\n", hr);
3383 if(SUCCEEDED(hr))
3385 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3386 ok(hr == S_OK, "Got 0x%08x\n", hr);
3387 if(SUCCEEDED(hr))
3389 IShellItem *psi2;
3390 UINT count;
3391 hr = IShellItemArray_GetCount(psia, &count);
3392 ok(hr == S_OK, "Got 0x%08x\n", hr);
3393 ok(count == 1, "Got count %d\n", count);
3394 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3395 ok(hr == S_OK, "Got 0x%08x\n", hr);
3396 todo_wine
3397 ok(psi != psi2, "ShellItems are of the same instance.\n");
3398 if(SUCCEEDED(hr))
3400 LPITEMIDLIST pidl1, pidl2;
3401 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3402 ok(hr == S_OK, "Got 0x%08x\n", hr);
3403 ok(pidl1 != NULL, "pidl1 was null.\n");
3404 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3405 ok(hr == S_OK, "Got 0x%08x\n", hr);
3406 ok(pidl2 != NULL, "pidl2 was null.\n");
3407 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3408 ILFree(pidl1);
3409 ILFree(pidl2);
3410 IShellItem_Release(psi2);
3412 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3413 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3414 IShellItemArray_Release(psia);
3416 IShellItem_Release(psi);
3419 else
3420 skip("No SHCreateShellItemArrayFromShellItem.\n");
3422 if(pSHCreateShellItemArrayFromDataObject)
3424 IShellView *psv;
3426 if(0)
3428 /* Crashes under Windows 7 */
3429 pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3431 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3432 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3434 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3435 ok(hr == S_OK, "got 0x%08x\n", hr);
3436 if(SUCCEEDED(hr))
3438 IEnumIDList *peidl;
3439 IDataObject *pdo;
3440 SHCONTF enum_flags;
3442 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3443 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3444 ok(hr == S_OK, "got 0x%08x\n", hr);
3445 if(SUCCEEDED(hr))
3447 LPITEMIDLIST apidl[5];
3448 UINT count, i;
3450 for(count = 0; count < 5; count++)
3451 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3452 break;
3453 ok(count == 5, "Got %d\n", count);
3455 if(count)
3457 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3458 &IID_IDataObject, NULL, (void**)&pdo);
3459 ok(hr == S_OK, "Got 0x%08x\n", hr);
3460 if(SUCCEEDED(hr))
3462 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3463 (void**)&psia);
3464 ok(hr == S_OK, "Got 0x%08x\n", hr);
3465 if(SUCCEEDED(hr))
3467 UINT count_sia, i;
3468 hr = IShellItemArray_GetCount(psia, &count_sia);
3469 ok(hr == S_OK, "Got 0x%08x\n", hr);
3470 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3471 for(i = 0; i < count_sia; i++)
3473 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3474 IShellItem *psi;
3475 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3476 ok(hr == S_OK, "Got 0x%08x\n", hr);
3477 if(SUCCEEDED(hr))
3479 LPITEMIDLIST pidl;
3480 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3481 ok(hr == S_OK, "Got 0x%08x\n", hr);
3482 ok(pidl != NULL, "pidl as NULL.\n");
3483 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3484 ILFree(pidl);
3485 IShellItem_Release(psi);
3487 ILFree(pidl_abs);
3490 IShellItemArray_Release(psia);
3493 IDataObject_Release(pdo);
3495 for(i = 0; i < count; i++)
3496 ILFree(apidl[i]);
3498 else
3499 skip("No files found - skipping test.\n");
3501 IEnumIDList_Release(peidl);
3503 IShellView_Release(psv);
3506 else
3507 skip("No SHCreateShellItemArrayFromDataObject.\n");
3509 if(pSHCreateShellItemArrayFromIDLists)
3511 WCHAR test1W[] = {'t','e','s','t','1','.','t','x','t',0};
3512 WCHAR test1pathW[MAX_PATH];
3513 LPITEMIDLIST pidltest1;
3514 LPCITEMIDLIST pidl_array[2];
3516 if(0)
3518 /* Crashes */
3519 hr = pSHCreateShellItemArrayFromIDLists(0, NULL, NULL);
3522 psia = (void*)0xdeadbeef;
3523 hr = pSHCreateShellItemArrayFromIDLists(0, NULL, &psia);
3524 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3525 ok(psia == NULL, "Got %p\n", psia);
3527 psia = (void*)0xdeadbeef;
3528 hr = pSHCreateShellItemArrayFromIDLists(0, pidl_array, &psia);
3529 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3530 ok(psia == NULL, "Got %p\n", psia);
3532 psia = (void*)0xdeadbeef;
3533 pidl_array[0] = NULL;
3534 hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3535 todo_wine ok(hr == E_OUTOFMEMORY, "Got 0x%08x\n", hr);
3536 ok(psia == NULL, "Got %p\n", psia);
3538 psia = (void*)0xdeadbeef;
3539 pidl_array[0] = pidl_testdir;
3540 pidl_array[1] = NULL;
3541 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3542 todo_wine ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Vista */, "Got 0x%08x\n", hr);
3543 todo_wine ok(psia != NULL || broken(psia == NULL) /* Vista */, "Got %p\n", psia);
3544 if(SUCCEEDED(hr))
3546 IShellItem *psi;
3547 UINT count = 0;
3549 hr = IShellItemArray_GetCount(psia, &count);
3550 ok(hr == S_OK, "Got 0x%08x\n", hr);
3551 ok(count == 2, "Got %d\n", count);
3553 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3554 ok(hr == S_OK, "Got 0x%08x\n", hr);
3555 if(SUCCEEDED(hr))
3557 LPWSTR path;
3558 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3559 ok(hr == S_OK, "Got 0x%08x\n", hr);
3560 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3561 if(SUCCEEDED(hr))
3562 CoTaskMemFree(path);
3564 IShellItem_Release(psi);
3567 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3568 ok(hr == S_OK, "Got 0x%08x\n", hr);
3569 if(SUCCEEDED(hr))
3571 LPWSTR path;
3572 WCHAR desktoppath[MAX_PATH];
3573 BOOL result;
3575 result = SHGetSpecialFolderPathW(NULL, desktoppath, CSIDL_DESKTOPDIRECTORY, FALSE);
3576 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
3578 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3579 ok(hr == S_OK, "Got 0x%08x\n", hr);
3580 ok(!lstrcmpW(path, desktoppath), "Got %s\n", wine_dbgstr_w(path));
3581 if(SUCCEEDED(hr))
3582 CoTaskMemFree(path);
3584 IShellItem_Release(psi);
3588 IShellItemArray_Release(psia);
3592 /* Single pidl */
3593 psia = (void*)0xdeadbeef;
3594 pidl_array[0] = pidl_testdir;
3595 hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3596 ok(hr == S_OK, "Got 0x%08x\n", hr);
3597 if(SUCCEEDED(hr))
3599 IShellItem *psi;
3600 UINT count = 0;
3602 hr = IShellItemArray_GetCount(psia, &count);
3603 ok(hr == S_OK, "Got 0x%08x\n", hr);
3604 ok(count == 1, "Got %d\n", count);
3606 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3607 ok(hr == S_OK, "Got 0x%08x\n", hr);
3608 if(SUCCEEDED(hr))
3610 LPWSTR path;
3611 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3612 ok(hr == S_OK, "Got 0x%08x\n", hr);
3613 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3614 if(SUCCEEDED(hr))
3615 CoTaskMemFree(path);
3617 IShellItem_Release(psi);
3620 IShellItemArray_Release(psia);
3624 lstrcpyW(test1pathW, cTestDirW);
3625 myPathAddBackslashW(test1pathW);
3626 lstrcatW(test1pathW, test1W);
3628 SHGetDesktopFolder(&pdesktopsf);
3630 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, test1pathW, NULL, &pidltest1, NULL);
3631 ok(hr == S_OK, "Got 0x%08x\n", hr);
3632 if(SUCCEEDED(hr))
3634 psia = (void*)0xdeadbeef;
3635 pidl_array[0] = pidl_testdir;
3636 pidl_array[1] = pidltest1;
3637 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3638 ok(hr == S_OK, "Got 0x%08x\n", hr);
3639 if(SUCCEEDED(hr))
3641 IShellItem *psi;
3642 UINT count = 0;
3644 hr = IShellItemArray_GetCount(psia, &count);
3645 ok(hr == S_OK, "Got 0x%08x\n", hr);
3646 ok(count == 2, "Got %d\n", count);
3648 hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3649 ok(hr == S_OK, "Got 0x%08x\n", hr);
3650 if(SUCCEEDED(hr))
3652 LPWSTR path;
3653 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3654 ok(hr == S_OK, "Got 0x%08x\n", hr);
3655 ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3656 if(SUCCEEDED(hr))
3657 CoTaskMemFree(path);
3659 IShellItem_Release(psi);
3662 hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3663 ok(hr == S_OK, "Got 0x%08x\n", hr);
3664 if(SUCCEEDED(hr))
3666 LPWSTR path;
3667 hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3668 ok(hr == S_OK, "Got 0x%08x\n", hr);
3669 ok(!lstrcmpW(path, test1pathW), "Got %s\n", wine_dbgstr_w(path));
3670 if(SUCCEEDED(hr))
3671 CoTaskMemFree(path);
3673 IShellItem_Release(psi);
3677 IShellItemArray_Release(psia);
3680 ILFree(pidltest1);
3683 IShellFolder_Release(pdesktopsf);
3685 else
3686 skip("No SHCreateShellItemArrayFromIDLists.\n");
3688 IShellFolder_Release(psf);
3689 ILFree(pidl_testdir);
3690 Cleanup();
3693 static void test_ShellItemArrayEnumItems(void)
3695 IShellFolder *pdesktopsf, *psf;
3696 IEnumIDList *peidl;
3697 WCHAR cTestDirW[MAX_PATH];
3698 HRESULT hr;
3699 LPITEMIDLIST pidl_testdir;
3700 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3702 if(!pSHCreateShellItemArray)
3704 win_skip("No SHCreateShellItemArray, skipping test...\n");
3705 return;
3708 CreateFilesFolders();
3710 SHGetDesktopFolder(&pdesktopsf);
3712 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3713 myPathAddBackslashW(cTestDirW);
3714 lstrcatW(cTestDirW, testdirW);
3716 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3717 ok(hr == S_OK, "got 0x%08x\n", hr);
3718 if(SUCCEEDED(hr))
3720 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3721 (void**)&psf);
3722 ok(hr == S_OK, "Got 0x%08x\n", hr);
3723 ILFree(pidl_testdir);
3725 IShellFolder_Release(pdesktopsf);
3726 if (FAILED(hr)) return;
3728 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3729 ok(hr == S_OK, "Got %08x\n", hr);
3730 if(SUCCEEDED(hr))
3732 IShellItemArray *psia;
3733 LPITEMIDLIST apidl[5];
3734 UINT done, numitems, i;
3736 for(done = 0; done < 5; done++)
3737 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3738 break;
3739 ok(done == 5, "Got %d pidls\n", done);
3740 IEnumIDList_Release(peidl);
3742 /* Create a ShellItemArray */
3743 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3744 ok(hr == S_OK, "Got 0x%08x\n", hr);
3745 if(SUCCEEDED(hr))
3747 IEnumShellItems *iesi;
3748 IShellItem *my_array[10];
3749 ULONG fetched;
3751 IShellItemArray_GetCount(psia, &numitems);
3752 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3754 iesi = NULL;
3755 hr = IShellItemArray_EnumItems(psia, &iesi);
3756 ok(hr == S_OK, "Got 0x%08x\n", hr);
3757 ok(iesi != NULL, "Got NULL\n");
3758 if(SUCCEEDED(hr))
3760 IEnumShellItems *iesi2;
3762 /* This should fail according to the documentation and Win7+ */
3763 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3764 hr = IEnumShellItems_Next(iesi, 2, my_array, NULL);
3765 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
3766 for(i = 0; i < 2; i++)
3768 ok(my_array[i] == (void*)0xdeadbeef ||
3769 broken(my_array[i] != (void*)0xdeadbeef && my_array[i] != NULL), /* Vista */
3770 "Got %p (%d)\n", my_array[i], i);
3772 if(my_array[i] != (void*)0xdeadbeef)
3773 IShellItem_Release(my_array[i]);
3775 ok(my_array[2] == (void*)0xdeadbeef, "Got %p\n", my_array[2]);
3777 IEnumShellItems_Reset(iesi);
3778 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3779 hr = IEnumShellItems_Next(iesi, 1, my_array, NULL);
3780 ok(hr == S_OK, "Got 0x%08x\n", hr);
3781 ok(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef, "Got %p\n", my_array[0]);
3782 if(my_array[0] != NULL && my_array[0] != (void*)0xdeadbeef)
3783 IShellItem_Release(my_array[0]);
3784 ok(my_array[1] == (void*)0xdeadbeef, "Got %p\n", my_array[1]);
3786 IEnumShellItems_Reset(iesi);
3787 fetched = 0;
3788 for(i = 0; i < 10; i++) my_array[i] = (void*)0xdeadbeef;
3789 hr = IEnumShellItems_Next(iesi, numitems, my_array, &fetched);
3790 ok(hr == S_OK, "Got 0x%08x\n", hr);
3791 ok(fetched == numitems, "Got %d\n", fetched);
3792 for(i = 0;i < numitems; i++)
3794 ok(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef,
3795 "Got %p at %d\n", my_array[i], i);
3797 if(my_array[i] != NULL && my_array[i] != (void*)0xdeadbeef)
3798 IShellItem_Release(my_array[i]);
3800 ok(my_array[i] == (void*)0xdeadbeef, "Got %p\n", my_array[i]);
3802 /* Compare all the items */
3803 IEnumShellItems_Reset(iesi);
3804 for(i = 0; i < numitems; i++)
3806 IShellItem *psi;
3807 int order;
3809 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3810 ok(hr == S_OK, "Got 0x%08x\n", hr);
3811 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
3812 ok(hr == S_OK, "Got 0x%08x\n", hr);
3813 ok(fetched == 1, "Got %d\n", fetched);
3815 hr = IShellItem_Compare(psi, my_array[0], 0, &order);
3816 ok(hr == S_OK, "Got 0x%08x\n", hr);
3817 ok(order == 0, "Got %d\n", order);
3819 IShellItem_Release(psi);
3820 IShellItem_Release(my_array[0]);
3823 my_array[0] = (void*)0xdeadbeef;
3824 hr = IEnumShellItems_Next(iesi, 1, my_array, &fetched);
3825 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
3826 ok(fetched == 0, "Got %d\n", fetched);
3827 ok(my_array[0] == (void*)0xdeadbeef, "Got %p\n", my_array[0]);
3829 /* Cloning not implemented anywhere */
3830 iesi2 = (void*)0xdeadbeef;
3831 hr = IEnumShellItems_Clone(iesi, &iesi2);
3832 ok(hr == E_NOTIMPL, "Got 0x%08x\n", hr);
3833 ok(iesi2 == NULL || broken(iesi2 == (void*)0xdeadbeef) /* Vista */, "Got %p\n", iesi2);
3835 IEnumShellItems_Release(iesi);
3838 IShellItemArray_Release(psia);
3841 for(i = 0; i < done; i++)
3842 ILFree(apidl[i]);
3845 IShellFolder_Release(psf);
3849 static void test_ShellItemBindToHandler(void)
3851 IShellItem *psi;
3852 LPITEMIDLIST pidl_desktop;
3853 HRESULT hr;
3855 if(!pSHCreateShellItem)
3857 skip("SHCreateShellItem missing.\n");
3858 return;
3861 hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3862 ok(hr == S_OK, "Got 0x%08x\n", hr);
3863 if(SUCCEEDED(hr))
3865 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3866 ok(hr == S_OK, "Got 0x%08x\n", hr);
3868 if(SUCCEEDED(hr))
3870 IPersistFolder2 *ppf2;
3871 IUnknown *punk;
3873 if(0)
3875 /* Crashes under Windows 7 */
3876 IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3877 IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3879 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3880 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3882 /* BHID_SFObject */
3883 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3884 ok(hr == S_OK, "Got 0x%08x\n", hr);
3885 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3886 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3887 ok(hr == S_OK, "Got 0x%08x\n", hr);
3888 if(SUCCEEDED(hr))
3890 LPITEMIDLIST pidl_tmp;
3891 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3892 ok(hr == S_OK, "Got 0x%08x\n", hr);
3893 if(SUCCEEDED(hr))
3895 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3896 ILFree(pidl_tmp);
3898 IPersistFolder2_Release(ppf2);
3901 /* BHID_SFUIObject */
3902 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3903 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3904 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3905 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3906 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3907 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3909 /* BHID_DataObject */
3910 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3911 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3912 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3914 todo_wine
3916 /* BHID_SFViewObject */
3917 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3918 ok(hr == S_OK, "Got 0x%08x\n", hr);
3919 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3920 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3921 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3922 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3924 /* BHID_Storage */
3925 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3926 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3927 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3928 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3929 ok(hr == S_OK, "Got 0x%08x\n", hr);
3930 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3932 /* BHID_Stream */
3933 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3934 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3935 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3936 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3937 ok(hr == S_OK, "Got 0x%08x\n", hr);
3938 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3940 /* BHID_StorageEnum */
3941 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3942 ok(hr == S_OK, "Got 0x%08x\n", hr);
3943 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3945 /* BHID_Transfer
3946 ITransferSource and ITransferDestination are accessible starting from Vista, IUnknown is
3947 supported starting from Win8. */
3948 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferSource, (void**)&punk);
3949 ok(hr == S_OK || broken(FAILED(hr)) /* pre-Vista */, "Got 0x%08x\n", hr);
3950 if(SUCCEEDED(hr))
3952 IUnknown_Release(punk);
3954 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_ITransferDestination, (void**)&punk);
3955 ok(hr == S_OK, "Got 0x%08x\n", hr);
3956 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3958 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3959 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Win8 */, "Got 0x%08x\n", hr);
3960 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3963 /* BHID_EnumItems */
3964 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3965 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3966 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3968 /* BHID_Filter */
3969 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3970 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3971 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3973 /* BHID_LinkTargetItem */
3974 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3975 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3976 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3977 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3978 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3979 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3981 /* BHID_PropertyStore */
3982 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3983 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3984 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3985 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3986 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3987 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3989 /* BHID_ThumbnailHandler */
3990 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3991 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3992 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3994 /* BHID_AssociationArray */
3995 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3996 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3997 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3999 /* BHID_EnumAssocHandlers */
4000 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (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);
4005 IShellItem_Release(psi);
4007 else
4008 skip("Failed to create ShellItem.\n");
4010 ILFree(pidl_desktop);
4013 static void test_ShellItemGetAttributes(void)
4015 IShellItem *psi, *psi_folder1, *psi_file1;
4016 IShellFolder *pdesktopsf;
4017 LPITEMIDLIST pidl_desktop, pidl;
4018 SFGAOF sfgao;
4019 HRESULT hr;
4020 WCHAR curdirW[MAX_PATH];
4021 WCHAR buf[MAX_PATH];
4022 static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4023 static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4025 if(!pSHCreateShellItem)
4027 skip("SHCreateShellItem missing.\n");
4028 return;
4031 hr = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
4032 ok(hr == S_OK, "Got 0x%08x\n", hr);
4033 if(SUCCEEDED(hr))
4035 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
4036 ok(hr == S_OK, "Got 0x%08x\n", hr);
4037 ILFree(pidl_desktop);
4039 if(FAILED(hr))
4041 skip("Skipping tests.\n");
4042 return;
4045 if(0)
4047 /* Crashes on native (Win 7) */
4048 IShellItem_GetAttributes(psi, 0, NULL);
4051 /* Test GetAttributes on the desktop folder. */
4052 sfgao = 0xdeadbeef;
4053 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
4054 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
4055 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
4057 IShellItem_Release(psi);
4059 CreateFilesFolders();
4061 SHGetDesktopFolder(&pdesktopsf);
4063 GetCurrentDirectoryW(MAX_PATH, curdirW);
4064 myPathAddBackslashW(curdirW);
4066 lstrcpyW(buf, curdirW);
4067 lstrcatW(buf, testdir1W);
4068 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4069 ok(hr == S_OK, "got 0x%08x\n", hr);
4070 hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_folder1);
4071 ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4072 ILFree(pidl);
4074 lstrcpyW(buf, curdirW);
4075 lstrcatW(buf, testfile1W);
4076 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, &pidl, NULL);
4077 ok(hr == S_OK, "got 0x%08x\n", hr);
4078 hr = pSHCreateShellItem(NULL, NULL, pidl, &psi_file1);
4079 ok(hr == S_OK, "Got 0x%08x\n", sfgao);
4080 ILFree(pidl);
4082 IShellFolder_Release(pdesktopsf);
4084 sfgao = 0xdeadbeef;
4085 hr = IShellItem_GetAttributes(psi_folder1, 0, &sfgao);
4086 ok(hr == S_OK, "Got 0x%08x\n", hr);
4087 ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4089 sfgao = 0xdeadbeef;
4090 hr = IShellItem_GetAttributes(psi_folder1, SFGAO_FOLDER, &sfgao);
4091 ok(hr == S_OK, "Got 0x%08x\n", hr);
4092 ok(sfgao == SFGAO_FOLDER, "Got 0x%08x\n", sfgao);
4094 sfgao = 0xdeadbeef;
4095 hr = IShellItem_GetAttributes(psi_file1, SFGAO_FOLDER, &sfgao);
4096 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
4097 ok(sfgao == 0, "Got 0x%08x\n", sfgao);
4099 IShellItem_Release(psi_folder1);
4100 IShellItem_Release(psi_file1);
4102 Cleanup();
4105 static void test_ShellItemArrayGetAttributes(void)
4107 IShellItemArray *psia_files, *psia_folders1, *psia_folders2, *psia_all;
4108 IShellFolder *pdesktopsf;
4109 LPCITEMIDLIST pidl_array[5];
4110 SFGAOF attr;
4111 HRESULT hr;
4112 WCHAR curdirW[MAX_PATH];
4113 WCHAR buf[MAX_PATH];
4114 UINT i;
4115 static const WCHAR testdir1W[] = {'t','e','s','t','d','i','r',0};
4116 static const WCHAR testdir2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','2',0};
4117 static const WCHAR testdir3W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','d','i','r','3',0};
4118 static const WCHAR testfile1W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4119 static const WCHAR testfile2W[] = {'t','e','s','t','d','i','r','\\','t','e','s','t','2','.','t','x','t',0};
4120 static const WCHAR *testfilesW[5] = { testdir1W, testdir2W, testdir3W, testfile1W, testfile2W };
4122 if(!pSHCreateShellItemArrayFromShellItem)
4124 win_skip("No SHCreateShellItemArrayFromShellItem, skipping test...\n");
4125 return;
4128 CreateFilesFolders();
4129 CreateDirectoryA(".\\testdir\\testdir3", NULL);
4131 SHGetDesktopFolder(&pdesktopsf);
4133 GetCurrentDirectoryW(MAX_PATH, curdirW);
4134 myPathAddBackslashW(curdirW);
4136 for(i = 0; i < 5; i++)
4138 lstrcpyW(buf, curdirW);
4139 lstrcatW(buf, testfilesW[i]);
4140 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, buf, NULL, (LPITEMIDLIST*)&pidl_array[i], NULL);
4141 ok(hr == S_OK, "got 0x%08x\n", hr);
4143 IShellFolder_Release(pdesktopsf);
4145 hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia_folders1);
4146 ok(hr == S_OK, "got 0x%08x\n", hr);
4147 hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[1], &psia_folders2);
4148 ok(hr == S_OK, "got 0x%08x\n", hr);
4149 hr = pSHCreateShellItemArrayFromIDLists(2, &pidl_array[3], &psia_files);
4150 ok(hr == S_OK, "got 0x%08x\n", hr);
4151 hr = pSHCreateShellItemArrayFromIDLists(4, &pidl_array[1], &psia_all); /* All except the first */
4152 ok(hr == S_OK, "got 0x%08x\n", hr);
4154 for(i = 0; i < 5; i++)
4155 ILFree((LPITEMIDLIST)pidl_array[i]);
4157 /* [testfolder/, testfolder/testfolder2] seems to break in Vista */
4158 attr = 0xdeadbeef;
4159 hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4160 ok(hr == S_OK || broken(hr == E_UNEXPECTED) /* Vista */, "Got 0x%08x\n", hr);
4161 ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4162 attr = 0xdeadbeef;
4163 hr = IShellItemArray_GetAttributes(psia_folders1, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4164 ok(hr == S_OK || broken(hr == E_UNEXPECTED) /* Vista */, "Got 0x%08x\n", hr);
4165 ok(attr == SFGAO_FOLDER || broken(attr == 0) /* Vista */, "Got 0x%08x\n", attr);
4167 /* [testfolder/testfolder2, testfolder/testfolder3] works */
4168 attr = 0xdeadbeef;
4169 hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4170 ok(hr == S_OK, "Got 0x%08x\n", hr);
4171 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4172 attr = 0xdeadbeef;
4173 hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4174 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4175 ok(attr == 0, "Got 0x%08x\n", attr);
4176 attr = 0xdeadbeef;
4177 hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_AND, SFGAO_FOLDER, &attr);
4178 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4179 ok(attr == 0, "Got 0x%08x\n", attr);
4180 attr = 0xdeadbeef;
4181 hr = IShellItemArray_GetAttributes(psia_folders2, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4182 ok(hr == S_OK, "Got 0x%08x\n", hr);
4183 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4184 attr = 0xdeadbeef;
4185 hr = IShellItemArray_GetAttributes(psia_files, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4186 ok(hr == S_FALSE || broken(hr == S_OK) /* Vista */, "Got 0x%08x\n", hr);
4187 ok(attr == 0, "Got 0x%08x\n", attr);
4188 attr = 0xdeadbeef;
4189 hr = IShellItemArray_GetAttributes(psia_all, SIATTRIBFLAGS_OR, SFGAO_FOLDER, &attr);
4190 ok(hr == S_OK, "Got 0x%08x\n", hr);
4191 ok(attr == SFGAO_FOLDER, "Got 0x%08x\n", attr);
4193 IShellItemArray_Release(psia_folders1);
4194 IShellItemArray_Release(psia_folders2);
4195 IShellItemArray_Release(psia_files);
4196 IShellItemArray_Release(psia_all);
4198 RemoveDirectoryA(".\\testdir\\testdir3");
4199 Cleanup();
4202 static void test_SHParseDisplayName(void)
4204 LPITEMIDLIST pidl1, pidl2;
4205 IShellFolder *desktop;
4206 WCHAR dirW[MAX_PATH];
4207 WCHAR nameW[10];
4208 HRESULT hr;
4209 BOOL ret, is_wow64;
4211 if (0)
4213 /* crashes on native */
4214 SHParseDisplayName(NULL, NULL, NULL, 0, NULL);
4215 nameW[0] = 0;
4216 SHParseDisplayName(nameW, NULL, NULL, 0, NULL);
4219 pidl1 = (LPITEMIDLIST)0xdeadbeef;
4220 hr = SHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
4221 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
4222 hr == E_INVALIDARG, "failed %08x\n", hr);
4223 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
4225 /* dummy name */
4226 nameW[0] = 0;
4227 hr = SHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
4228 ok(hr == S_OK, "failed %08x\n", hr);
4229 hr = SHGetDesktopFolder(&desktop);
4230 ok(hr == S_OK, "failed %08x\n", hr);
4231 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
4232 ok(hr == S_OK, "failed %08x\n", hr);
4233 ret = ILIsEqual(pidl1, pidl2);
4234 ok(ret == TRUE, "expected equal idls\n");
4235 ILFree(pidl1);
4236 ILFree(pidl2);
4238 /* with path */
4239 GetWindowsDirectoryW( dirW, MAX_PATH );
4241 hr = SHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4242 ok(hr == S_OK, "failed %08x\n", hr);
4243 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
4244 ok(hr == S_OK, "failed %08x\n", hr);
4246 ret = ILIsEqual(pidl1, pidl2);
4247 ok(ret == TRUE, "expected equal idls\n");
4248 ILFree(pidl1);
4249 ILFree(pidl2);
4251 /* system32 is not redirected to syswow64 on WOW64 */
4252 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
4253 if (is_wow64)
4255 UINT len;
4256 *dirW = 0;
4257 len = GetSystemDirectoryW(dirW, MAX_PATH);
4258 ok(len > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
4259 hr = SHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
4260 ok(hr == S_OK, "failed %08x\n", hr);
4261 *dirW = 0;
4262 len = GetSystemWow64DirectoryW(dirW, MAX_PATH);
4263 ok(len > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
4264 hr = SHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
4265 ok(hr == S_OK, "failed %08x\n", hr);
4266 ret = ILIsEqual(pidl1, pidl2);
4267 ok(ret == FALSE, "expected different idls\n");
4268 ILFree(pidl1);
4269 ILFree(pidl2);
4272 IShellFolder_Release(desktop);
4275 static void test_desktop_IPersist(void)
4277 IShellFolder *desktop;
4278 IPersist *persist;
4279 IPersistFolder2 *ppf2;
4280 CLSID clsid;
4281 HRESULT hr;
4283 hr = SHGetDesktopFolder(&desktop);
4284 ok(hr == S_OK, "failed %08x\n", hr);
4286 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
4287 ok(hr == S_OK, "failed %08x\n", hr);
4289 if (hr == S_OK)
4291 if (0)
4293 /* crashes on native */
4294 IPersist_GetClassID(persist, NULL);
4296 memset(&clsid, 0, sizeof(clsid));
4297 hr = IPersist_GetClassID(persist, &clsid);
4298 ok(hr == S_OK, "failed %08x\n", hr);
4299 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
4300 IPersist_Release(persist);
4303 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
4304 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
4305 if(SUCCEEDED(hr))
4307 IPersistFolder *ppf;
4308 LPITEMIDLIST pidl;
4309 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
4310 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
4311 if(SUCCEEDED(hr))
4312 IPersistFolder_Release(ppf);
4314 todo_wine {
4315 hr = IPersistFolder2_Initialize(ppf2, NULL);
4316 ok(hr == S_OK, "got %08x\n", hr);
4319 pidl = NULL;
4320 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
4321 ok(hr == S_OK, "got %08x\n", hr);
4322 ok(pidl != NULL, "pidl was NULL.\n");
4323 if(SUCCEEDED(hr)) ILFree(pidl);
4325 IPersistFolder2_Release(ppf2);
4328 IShellFolder_Release(desktop);
4331 static void test_contextmenu_qi(IContextMenu *menu, BOOL todo)
4333 IUnknown *unk;
4334 HRESULT hr;
4336 hr = IContextMenu_QueryInterface(menu, &IID_IShellExtInit, (void **)&unk);
4337 todo_wine_if(todo)
4338 ok(hr == S_OK, "Failed to get IShellExtInit, hr %#x.\n", hr);
4339 if (hr == S_OK)
4340 IUnknown_Release(unk);
4342 hr = IContextMenu_QueryInterface(menu, &IID_IObjectWithSite, (void **)&unk);
4343 todo_wine_if(todo)
4344 ok(hr == S_OK, "Failed to get IShellExtInit, hr %#x.\n", hr);
4345 if (hr == S_OK)
4346 IUnknown_Release(unk);
4349 static void test_contextmenu(IContextMenu *menu, BOOL background)
4351 HMENU hmenu = CreatePopupMenu();
4352 UINT count, i, max_id;
4353 HRESULT hr;
4355 test_contextmenu_qi(menu, FALSE);
4357 hr = IContextMenu_QueryContextMenu(menu, hmenu, 0, 64, 32767, CMF_NORMAL);
4358 ok(SUCCEEDED(hr), "Failed to query the menu, hr %#x.\n", hr);
4360 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
4361 ok(max_id <= 32767, "Got %d\n", max_id);
4362 count = GetMenuItemCount(hmenu);
4363 ok(count, "Got %d\n", count);
4365 for (i = 0; i < count; i++)
4367 MENUITEMINFOA mii;
4368 INT res;
4369 char buf[255], buf2[255];
4370 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
4371 mii.cbSize = sizeof(MENUITEMINFOA);
4372 mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
4373 mii.dwTypeData = buf2;
4374 mii.cch = sizeof(buf2);
4376 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
4377 ok(res, "Failed to get menu item info, error %d.\n", GetLastError());
4379 if (!(mii.fType & MFT_SEPARATOR))
4381 ok(mii.wID >= 64 && mii.wID <= 64 + max_id,
4382 "Expected between 64 and %d, got %d.\n", 64 + max_id, mii.wID);
4383 hr = IContextMenu_GetCommandString(menu, mii.wID - 64, GCS_VERBA, 0, buf, sizeof(buf));
4384 todo_wine_if(background)
4385 ok(hr == S_OK || hr == E_NOTIMPL || hr == E_INVALIDARG,
4386 "Got unexpected hr %#x for ID %d, string %s.\n", hr, mii.wID, debugstr_a(mii.dwTypeData));
4387 if (hr == S_OK)
4388 trace("Got ID %d, verb %s, string %s.\n", mii.wID, debugstr_a(buf), debugstr_a(mii.dwTypeData));
4389 else
4390 trace("Got ID %d, hr %#x, string %s.\n", mii.wID, hr, debugstr_a(mii.dwTypeData));
4394 if (count)
4396 CMINVOKECOMMANDINFO cmi;
4398 memset(&cmi, 0, sizeof(CMINVOKECOMMANDINFO));
4399 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
4401 /* Attempt to execute a nonexistent command */
4402 cmi.lpVerb = MAKEINTRESOURCEA(9999);
4403 hr = IContextMenu_InvokeCommand(menu, &cmi);
4404 todo_wine_if(background)
4405 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
4407 cmi.lpVerb = "foobar_wine_test";
4408 hr = IContextMenu_InvokeCommand(menu, &cmi);
4409 todo_wine_if(background)
4410 ok((hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
4411 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
4412 "Unexpected hr %#x.\n", hr);
4415 DestroyMenu(hmenu);
4418 static void test_GetUIObject(void)
4420 IShellFolder *psf_desktop;
4421 IContextMenu *pcm;
4422 LPITEMIDLIST pidl;
4423 HRESULT hr;
4424 WCHAR path[MAX_PATH];
4425 const WCHAR filename[] =
4426 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4427 LPCITEMIDLIST pidl_child;
4428 IShellFolder *psf;
4430 GetCurrentDirectoryW(MAX_PATH, path);
4431 if (!path[0])
4433 skip("GetCurrentDirectoryW returned an empty string.\n");
4434 return;
4436 lstrcatW(path, filename);
4437 SHGetDesktopFolder(&psf_desktop);
4439 CreateFilesFolders();
4441 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
4442 ok(hr == S_OK, "Got 0x%08x\n", hr);
4444 hr = SHBindToParent(pidl, &IID_IShellFolder, (void **)&psf, &pidl_child);
4445 ok(hr == S_OK, "Failed to bind to folder, hr %#x.\n", hr);
4447 /* Item menu */
4448 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, &pidl_child, &IID_IContextMenu, NULL, (void **)&pcm);
4449 ok(hr == S_OK, "GetUIObjectOf() failed, hr %#x.\n", hr);
4450 test_contextmenu(pcm, FALSE);
4451 IContextMenu_Release(pcm);
4453 /* Background menu */
4454 hr = IShellFolder_GetUIObjectOf(psf_desktop, NULL, 0, NULL, &IID_IContextMenu, NULL, (void **)&pcm);
4455 ok(hr == S_OK, "GetUIObjectOf() failed, hr %#x.\n", hr);
4456 test_contextmenu(pcm, TRUE);
4457 IContextMenu_Release(pcm);
4459 IShellFolder_Release(psf);
4460 ILFree(pidl);
4462 IShellFolder_Release(psf_desktop);
4463 Cleanup();
4466 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
4467 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
4469 LPCITEMIDLIST child;
4470 IShellFolder *parent;
4471 STRRET filename;
4472 HRESULT hr;
4474 if(path){
4475 if(!pidl){
4476 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
4477 return;
4480 hr = SHBindToParent(pidl, &IID_IShellFolder, (void **)&parent, &child);
4481 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
4482 if(FAILED(hr))
4483 return;
4485 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
4486 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
4487 if(FAILED(hr)){
4488 IShellFolder_Release(parent);
4489 return;
4492 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
4493 "Got unexpected string type: %d\n", filename.uType);
4494 if(filename.uType == STRRET_WSTR){
4495 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
4496 "didn't get expected path (%s), instead: %s\n",
4497 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
4498 SHFree(U(filename).pOleStr);
4500 else if(filename.uType == STRRET_CSTR)
4502 WCHAR *strW = make_wstr(U(filename).cStr);
4503 ok_(__FILE__,l)(!lstrcmpW(path, strW), "didn't get expected path (%s), instead: %s\n",
4504 wine_dbgstr_w(path), U(filename).cStr);
4505 heap_free(strW);
4508 IShellFolder_Release(parent);
4509 }else
4510 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4513 static void test_SHSimpleIDListFromPath(void)
4515 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4516 const CHAR adirA[] = "C:\\sidlfpdir";
4517 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4519 LPITEMIDLIST pidl = NULL;
4521 br = CreateDirectoryA(adirA, NULL);
4522 ok(br == TRUE, "CreateDirectory 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);
4531 br = RemoveDirectoryA(adirA);
4532 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4534 if(is_unicode)
4535 pidl = SHSimpleIDListFromPath(adirW);
4536 else
4537 pidl = SHSimpleIDListFromPath((const WCHAR *)adirA);
4538 verify_pidl(pidl, adirW);
4539 ILFree(pidl);
4542 /* IFileSystemBindData impl */
4543 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4544 REFIID riid, void **ppv)
4546 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4547 IsEqualIID(riid, &IID_IUnknown)){
4548 *ppv = fsbd;
4549 return S_OK;
4551 return E_NOINTERFACE;
4554 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4556 return 2;
4559 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4561 return 1;
4564 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4565 const WIN32_FIND_DATAW *pfd)
4567 ok(0, "SetFindData called\n");
4568 return E_NOTIMPL;
4571 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4572 WIN32_FIND_DATAW *pfd)
4574 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4575 return S_OK;
4578 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4579 WIN32_FIND_DATAW *pfd)
4581 memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4582 return S_OK;
4585 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4586 WIN32_FIND_DATAW *pfd)
4588 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4589 *pfd->cFileName = 'a';
4590 *pfd->cAlternateFileName = 'a';
4591 return S_OK;
4594 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4595 WIN32_FIND_DATAW *pfd)
4597 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4598 HANDLE handle = FindFirstFileW(adirW, pfd);
4599 FindClose(handle);
4600 return S_OK;
4603 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4604 WIN32_FIND_DATAW *pfd)
4606 return E_FAIL;
4609 static IFileSystemBindDataVtbl fsbdVtbl = {
4610 fsbd_QueryInterface,
4611 fsbd_AddRef,
4612 fsbd_Release,
4613 fsbd_SetFindData,
4614 NULL
4617 static IFileSystemBindData fsbd = { &fsbdVtbl };
4619 static void test_ParseDisplayNamePBC(void)
4621 WCHAR wFileSystemBindData[] =
4622 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4623 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4624 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4625 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4626 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4628 IShellFolder *psf;
4629 IBindCtx *pbc;
4630 HRESULT hres;
4631 ITEMIDLIST *pidl;
4633 /* Check if we support WCHAR functions */
4634 SetLastError(0xdeadbeef);
4635 lstrcmpiW(adirW, adirW);
4636 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4637 win_skip("Most W-calls are not implemented\n");
4638 return;
4641 hres = SHGetDesktopFolder(&psf);
4642 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4643 if(FAILED(hres)){
4644 win_skip("Failed to get IShellFolder, can't run tests\n");
4645 return;
4648 /* fails on unknown dir with no IBindCtx */
4649 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4650 ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4651 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4652 ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4653 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4654 ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4656 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4657 hres = CreateBindCtx(0, &pbc);
4658 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4660 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4661 ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4662 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4663 ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4664 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4665 ok(hres == exp_err, "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4667 /* unknown dir with IBindCtx with IFileSystemBindData */
4668 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4669 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4671 /* return E_FAIL from GetFindData */
4672 pidl = (ITEMIDLIST*)0xdeadbeef;
4673 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4674 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4675 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4676 if(SUCCEEDED(hres)){
4677 verify_pidl(pidl, adirW);
4678 ILFree(pidl);
4681 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4682 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4683 if(SUCCEEDED(hres)){
4684 verify_pidl(pidl, afileW);
4685 ILFree(pidl);
4688 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4689 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4690 if(SUCCEEDED(hres)){
4691 verify_pidl(pidl, afile2W);
4692 ILFree(pidl);
4695 /* set FIND_DATA struct to NULLs */
4696 pidl = (ITEMIDLIST*)0xdeadbeef;
4697 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4698 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4699 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4700 if(SUCCEEDED(hres)){
4701 verify_pidl(pidl, adirW);
4702 ILFree(pidl);
4705 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4706 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4707 if(SUCCEEDED(hres)){
4708 verify_pidl(pidl, afileW);
4709 ILFree(pidl);
4712 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4713 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4714 if(SUCCEEDED(hres)){
4715 verify_pidl(pidl, afile2W);
4716 ILFree(pidl);
4719 /* set FIND_DATA struct to junk */
4720 pidl = (ITEMIDLIST*)0xdeadbeef;
4721 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4722 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4723 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4724 if(SUCCEEDED(hres)){
4725 verify_pidl(pidl, adirW);
4726 ILFree(pidl);
4729 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4730 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4731 if(SUCCEEDED(hres)){
4732 verify_pidl(pidl, afileW);
4733 ILFree(pidl);
4736 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4737 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4738 if(SUCCEEDED(hres)){
4739 verify_pidl(pidl, afile2W);
4740 ILFree(pidl);
4743 /* set FIND_DATA struct to invalid data */
4744 pidl = (ITEMIDLIST*)0xdeadbeef;
4745 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4746 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4747 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4748 if(SUCCEEDED(hres)){
4749 verify_pidl(pidl, adirW);
4750 ILFree(pidl);
4753 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4754 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4755 if(SUCCEEDED(hres)){
4756 verify_pidl(pidl, afileW);
4757 ILFree(pidl);
4760 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4761 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4762 if(SUCCEEDED(hres)){
4763 verify_pidl(pidl, afile2W);
4764 ILFree(pidl);
4767 /* set FIND_DATA struct to valid data */
4768 pidl = (ITEMIDLIST*)0xdeadbeef;
4769 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4770 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4771 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4772 if(SUCCEEDED(hres)){
4773 verify_pidl(pidl, adirW);
4774 ILFree(pidl);
4777 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4778 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4779 if(SUCCEEDED(hres)){
4780 verify_pidl(pidl, afileW);
4781 ILFree(pidl);
4784 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4785 ok(hres == S_OK, "ParseDisplayName failed: 0x%08x\n", hres);
4786 if(SUCCEEDED(hres)){
4787 verify_pidl(pidl, afile2W);
4788 ILFree(pidl);
4791 IBindCtx_Release(pbc);
4792 IShellFolder_Release(psf);
4795 static const CHAR testwindow_class[] = "testwindow";
4796 #define WM_USER_NOTIFY (WM_APP+1)
4798 struct ChNotifyTest {
4799 const char id[256];
4800 const UINT notify_count;
4801 UINT missing_events;
4802 UINT signal;
4803 const char path_1[256];
4804 const char path_2[256];
4805 } chnotify_tests[] = {
4806 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4807 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4808 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4811 struct ChNotifyTest *exp_data;
4812 BOOL test_new_delivery_flag;
4814 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4816 LONG signal = (LONG)lparam;
4818 switch(msg){
4819 case WM_USER_NOTIFY:
4820 if(exp_data->missing_events > 0) {
4821 WCHAR *path1, *path2;
4822 LPITEMIDLIST *pidls = (LPITEMIDLIST*)wparam;
4823 HANDLE hLock = NULL;
4825 if(test_new_delivery_flag) {
4826 hLock = SHChangeNotification_Lock((HANDLE)wparam, lparam, &pidls, &signal);
4827 ok(hLock != NULL, "SHChangeNotification_Lock returned NULL\n");
4830 ok(exp_data->signal == signal,
4831 "%s: expected notification type %x, got: %x\n",
4832 exp_data->id, exp_data->signal, signal);
4834 trace("verifying pidls for: %s\n", exp_data->id);
4835 path1 = make_wstr(exp_data->path_1);
4836 path2 = make_wstr(exp_data->path_2);
4837 verify_pidl(pidls[0], path1);
4838 verify_pidl(pidls[1], path2);
4839 heap_free(path1);
4840 heap_free(path2);
4842 exp_data->missing_events--;
4844 if(test_new_delivery_flag)
4845 SHChangeNotification_Unlock(hLock);
4846 }else
4847 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4848 return 0;
4850 return DefWindowProcA(hwnd, msg, wparam, lparam);
4853 static void register_testwindow_class(void)
4855 WNDCLASSEXA cls;
4856 ATOM ret;
4858 ZeroMemory(&cls, sizeof(cls));
4859 cls.cbSize = sizeof(cls);
4860 cls.style = 0;
4861 cls.lpfnWndProc = testwindow_wndproc;
4862 cls.hInstance = GetModuleHandleA(NULL);
4863 cls.lpszClassName = testwindow_class;
4865 SetLastError(0);
4866 ret = RegisterClassExA(&cls);
4867 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4870 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4871 * have to poll repeatedly for the message to appear */
4872 static void do_events(void)
4874 int c = 0;
4875 while (exp_data->missing_events && (c++ < 10)){
4876 MSG msg;
4877 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4878 TranslateMessage(&msg);
4879 DispatchMessageA(&msg);
4881 if(exp_data->missing_events)
4882 Sleep(500);
4884 trace("%s: took %d tries\n", exp_data->id, c);
4887 static void test_SHChangeNotify(BOOL test_new_delivery)
4889 HWND wnd;
4890 ULONG notifyID, i;
4891 HRESULT hr;
4892 BOOL br, has_unicode;
4893 SHChangeNotifyEntry entries[1];
4894 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4895 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4897 trace("SHChangeNotify tests (%x)\n", test_new_delivery);
4899 CreateDirectoryW(NULL, NULL);
4900 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4902 test_new_delivery_flag = test_new_delivery;
4903 if(!test_new_delivery)
4904 register_testwindow_class();
4906 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4907 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4908 NULL, NULL, GetModuleHandleA(NULL), 0);
4909 ok(wnd != NULL, "Failed to make a window\n");
4911 br = CreateDirectoryA(root_dirA, NULL);
4912 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4914 entries[0].pidl = NULL;
4915 if(has_unicode)
4916 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4917 else
4918 hr = SHILCreateFromPath((const void *)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4919 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4920 entries[0].fRecursive = TRUE;
4922 notifyID = SHChangeNotifyRegister(wnd, !test_new_delivery ? SHCNRF_ShellLevel : SHCNRF_ShellLevel|SHCNRF_NewDelivery,
4923 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4924 ok(notifyID != 0, "Failed to register a window for change notifications\n");
4926 for (i = 0; i < ARRAY_SIZE(chnotify_tests); ++i)
4928 exp_data = chnotify_tests + i;
4930 exp_data->missing_events = exp_data->notify_count;
4931 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4932 exp_data->path_1[0] ? exp_data->path_1 : NULL,
4933 exp_data->path_2[0] ? exp_data->path_2 : NULL);
4934 do_events();
4935 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4937 if(has_unicode){
4938 WCHAR *path1, *path2;
4940 path1 = make_wstr(exp_data->path_1);
4941 path2 = make_wstr(exp_data->path_2);
4943 exp_data->missing_events = exp_data->notify_count;
4944 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
4945 do_events();
4946 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4948 heap_free(path1);
4949 heap_free(path2);
4953 SHChangeNotifyDeregister(notifyID);
4954 DestroyWindow(wnd);
4956 ILFree((LPITEMIDLIST)entries[0].pidl);
4957 br = RemoveDirectoryA(root_dirA);
4958 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4961 static void test_SHCreateDefaultContextMenu(void)
4963 HKEY keys[16];
4964 WCHAR path[MAX_PATH];
4965 IShellFolder *desktop,*folder;
4966 IPersistFolder2 *persist;
4967 IContextMenu *cmenu;
4968 LONG status;
4969 LPITEMIDLIST pidlFolder, pidl_child, pidl;
4970 DEFCONTEXTMENU cminfo;
4971 HRESULT hr;
4972 UINT i;
4973 const WCHAR filename[] =
4974 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4975 if(!pSHCreateDefaultContextMenu)
4977 win_skip("SHCreateDefaultContextMenu missing.\n");
4978 return;
4981 GetCurrentDirectoryW(MAX_PATH, path);
4982 if (!path[0])
4984 skip("GetCurrentDirectoryW returned an empty string.\n");
4985 return;
4987 lstrcatW(path, filename);
4988 SHGetDesktopFolder(&desktop);
4990 CreateFilesFolders();
4992 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &pidl, 0);
4993 ok(hr == S_OK, "Got 0x%08x\n", hr);
4994 if(SUCCEEDED(hr))
4996 hr = SHBindToParent(pidl, &IID_IShellFolder, (void **)&folder, (const ITEMIDLIST **)&pidl_child);
4997 ok(hr == S_OK, "Got 0x%08x\n", hr);
4999 IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
5000 IPersistFolder2_GetCurFolder(persist,&pidlFolder);
5001 IPersistFolder2_Release(persist);
5002 if(SUCCEEDED(hr))
5004 cminfo.hwnd=NULL;
5005 cminfo.pcmcb=NULL;
5006 cminfo.psf=folder;
5007 cminfo.pidlFolder=NULL;
5008 cminfo.apidl=(LPCITEMIDLIST*)&pidl_child;
5009 cminfo.cidl=1;
5010 cminfo.aKeys=NULL;
5011 cminfo.cKeys=0;
5012 cminfo.punkAssociationInfo=NULL;
5014 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5015 ok(hr==S_OK,"Got 0x%08x\n", hr);
5016 test_contextmenu_qi(cmenu, TRUE);
5017 IContextMenu_Release(cmenu);
5019 cminfo.pidlFolder=pidlFolder;
5020 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5021 ok(hr==S_OK,"Got 0x%08x\n", hr);
5022 test_contextmenu_qi(cmenu, TRUE);
5023 IContextMenu_Release(cmenu);
5025 status = RegOpenKeyExA(HKEY_CLASSES_ROOT,"*",0,KEY_READ,keys);
5026 if(status==ERROR_SUCCESS){
5027 for(i=1;i<16;i++)
5028 keys[i]=keys[0];
5029 cminfo.aKeys=keys;
5030 cminfo.cKeys=16;
5031 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
5032 RegCloseKey(keys[0]);
5033 ok(hr==S_OK,"Got 0x%08x\n", hr);
5034 IContextMenu_Release(cmenu);
5037 ILFree(pidlFolder);
5038 IShellFolder_Release(folder);
5040 IShellFolder_Release(desktop);
5041 ILFree(pidl);
5042 Cleanup();
5045 static void test_DataObject(void)
5047 IShellFolder *desktop;
5048 IDataObject *data_obj;
5049 HRESULT hres;
5050 IEnumIDList *peidl;
5051 LPITEMIDLIST apidl;
5052 FORMATETC fmt;
5053 DWORD cf_shellidlist;
5054 STGMEDIUM medium;
5056 SHGetDesktopFolder(&desktop);
5058 hres = IShellFolder_EnumObjects(desktop, NULL,
5059 SHCONTF_NONFOLDERS|SHCONTF_FOLDERS|SHCONTF_INCLUDEHIDDEN, &peidl);
5060 ok(hres == S_OK, "got %x\n", hres);
5062 if(IEnumIDList_Next(peidl, 1, &apidl, NULL) != S_OK) {
5063 skip("no files on desktop - skipping GetDataObject tests\n");
5064 IEnumIDList_Release(peidl);
5065 IShellFolder_Release(desktop);
5066 return;
5068 IEnumIDList_Release(peidl);
5070 hres = IShellFolder_GetUIObjectOf(desktop, NULL, 1, (LPCITEMIDLIST*)&apidl,
5071 &IID_IDataObject, NULL, (void**)&data_obj);
5072 ok(hres == S_OK, "got %x\n", hres);
5073 ILFree(apidl);
5074 IShellFolder_Release(desktop);
5076 cf_shellidlist = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
5077 fmt.cfFormat = cf_shellidlist;
5078 fmt.ptd = NULL;
5079 fmt.dwAspect = DVASPECT_CONTENT;
5080 fmt.lindex = -1;
5081 fmt.tymed = TYMED_HGLOBAL;
5082 hres = IDataObject_QueryGetData(data_obj, &fmt);
5083 ok(hres == S_OK, "got %x\n", hres);
5085 fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5086 hres = IDataObject_QueryGetData(data_obj, &fmt);
5087 ok(hres == S_OK, "got %x\n", hres);
5089 fmt.tymed = TYMED_ISTREAM;
5090 hres = IDataObject_QueryGetData(data_obj, &fmt);
5091 todo_wine ok(hres == S_FALSE, "got %x\n", hres);
5093 fmt.tymed = TYMED_HGLOBAL | TYMED_ISTREAM;
5094 hres = IDataObject_GetData(data_obj, &fmt, &medium);
5095 ok(hres == S_OK, "got %x\n", hres);
5096 ok(medium.tymed == TYMED_HGLOBAL, "medium.tymed = %x\n", medium.tymed);
5097 ReleaseStgMedium(&medium);
5099 IDataObject_Release(data_obj);
5102 static void test_GetDefaultColumn(void)
5104 static const CLSID *folders[] =
5106 &CLSID_MyComputer,
5107 &CLSID_MyDocuments,
5108 &CLSID_ControlPanel,
5109 &CLSID_NetworkPlaces,
5110 &CLSID_Printers,
5111 &CLSID_RecycleBin,
5112 &CLSID_ShellDesktop,
5114 HRESULT hr;
5115 int i;
5117 CoInitialize(NULL);
5119 for (i = 0; i < ARRAY_SIZE(folders); i++)
5121 IShellFolder2 *folder;
5122 ULONG sort, display;
5124 hr = CoCreateInstance(folders[i], NULL, CLSCTX_INPROC_SERVER, &IID_IShellFolder2, (void **)&folder);
5125 if (hr != S_OK)
5127 win_skip("Failed to create folder %s, hr %#x.\n", wine_dbgstr_guid(folders[i]), hr);
5128 continue;
5131 hr = IShellFolder2_GetDefaultColumn(folder, 0, NULL, NULL);
5132 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5134 sort = display = 123;
5135 hr = IShellFolder2_GetDefaultColumn(folder, 0, &sort, &display);
5136 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5137 ok(sort == 123 && display == 123, "Unexpected default column.\n");
5139 display = 123;
5140 hr = IShellFolder2_GetDefaultColumn(folder, 0, NULL, &display);
5141 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5142 ok(display == 123, "Unexpected default column.\n");
5144 sort = 123;
5145 hr = IShellFolder2_GetDefaultColumn(folder, 0, &sort, NULL);
5146 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5147 ok(sort == 123, "Unexpected default column.\n");
5149 IShellFolder2_Release(folder);
5152 CoUninitialize();
5155 static void test_GetDefaultSearchGUID(void)
5157 static const CLSID *folders[] =
5159 &CLSID_MyComputer,
5160 &CLSID_MyDocuments,
5161 &CLSID_ControlPanel,
5162 &CLSID_NetworkPlaces,
5163 &CLSID_Printers,
5164 &CLSID_RecycleBin,
5165 &CLSID_ShellDesktop,
5167 HRESULT hr;
5168 int i;
5170 CoInitialize(NULL);
5172 for (i = 0; i < ARRAY_SIZE(folders); i++)
5174 IShellFolder2 *folder;
5175 GUID guid;
5177 hr = CoCreateInstance(folders[i], NULL, CLSCTX_INPROC_SERVER, &IID_IShellFolder2, (void **)&folder);
5178 if (hr != S_OK)
5180 win_skip("Failed to create folder %s, hr %#x.\n", wine_dbgstr_guid(folders[i]), hr);
5181 continue;
5184 if (0)
5186 /* crashes on XP */
5187 hr = IShellFolder2_GetDefaultSearchGUID(folder, NULL);
5188 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
5191 memcpy(&guid, &CLSID_MyComputer, sizeof(guid));
5192 hr = IShellFolder2_GetDefaultSearchGUID(folder, &guid);
5193 ok(hr == E_NOTIMPL || broken(hr == S_OK) /* Method was last supported on XP */, "Unexpected hr %#x.\n", hr);
5194 if (hr == E_NOTIMPL)
5195 ok(IsEqualGUID(&guid, &CLSID_MyComputer), "Unexpected guid %s.\n", wine_dbgstr_guid(&guid));
5197 IShellFolder2_Release(folder);
5200 CoUninitialize();
5203 static void test_SHLimitInputEdit(void)
5205 IShellFolder *desktop;
5206 HRESULT hr;
5207 HWND hwnd;
5209 hr = SHGetDesktopFolder(&desktop);
5210 ok(hr == S_OK, "Failed to get desktop folder, hr %#x.\n", hr);
5212 hr = SHLimitInputEdit(NULL, desktop);
5213 todo_wine
5214 ok(hr == E_FAIL, "Unexpected hr %#x.\n", hr);
5216 hwnd = CreateWindowA("EDIT", NULL, WS_VISIBLE, 0, 0, 100, 30, NULL, NULL, NULL, NULL);
5217 ok(hwnd != NULL, "Failed to create Edit control.\n");
5219 hr = SHLimitInputEdit(hwnd, desktop);
5220 todo_wine
5221 ok(hr == S_OK, "Failed to set input limits, hr %#x.\n", hr);
5223 hr = SHLimitInputEdit(hwnd, desktop);
5224 todo_wine
5225 ok(hr == S_OK, "Failed to set input limits, hr %#x.\n", hr);
5227 DestroyWindow(hwnd);
5228 IShellFolder_Release(desktop);
5231 static void test_SHGetSetFolderCustomSettings(void)
5233 HRESULT hr;
5234 SHFOLDERCUSTOMSETTINGS fcs;
5235 WCHAR pathW[MAX_PATH];
5236 WCHAR bufferW[MAX_PATH];
5237 WCHAR iconpathW[MAX_PATH];
5238 static const WCHAR somedirW[] = {'s','o','m','e','_','d','i','r',0};
5239 static const WCHAR iconW[] = {'\\','s','o','m','e','_','i','c','o','n','.','i','c','o',0};
5240 static const WCHAR desktop_iniW[] = {'\\','D','e','s','k','t','o','p','.','i','n','i',0};
5242 if (!pSHGetSetFolderCustomSettings)
5244 win_skip("SHGetSetFolderCustomSetting is not available.\n");
5245 return;
5248 GetTempPathW(MAX_PATH, pathW);
5249 lstrcatW(pathW, somedirW);
5250 CreateDirectoryW(pathW, NULL);
5252 lstrcpyW(iconpathW, pathW);
5253 lstrcatW(iconpathW, iconW);
5255 memset(&fcs, 0, sizeof(fcs));
5256 fcs.dwSize = sizeof(fcs);
5257 fcs.dwMask = FCSM_ICONFILE;
5258 fcs.pszIconFile = iconpathW;
5260 hr = pSHGetSetFolderCustomSettings(&fcs, pathW, FCS_FORCEWRITE); /*creates and writes to a Desktop.ini*/
5261 ok(hr == S_OK, "Expected S_OK, got %#x\n", hr);
5263 memset(&fcs, 0, sizeof(fcs));
5264 fcs.dwSize = sizeof(fcs);
5265 fcs.dwMask = FCSM_ICONFILE;
5266 fcs.cchIconFile = MAX_PATH;
5267 fcs.pszIconFile = bufferW;
5268 bufferW[0] = 0;
5270 hr = pSHGetSetFolderCustomSettings(&fcs, pathW, FCS_READ);
5271 todo_wine ok(hr == S_OK, "Expected S_OK, got %#x\n", hr);
5272 todo_wine ok(!lstrcmpiW(iconpathW, fcs.pszIconFile), "Expected %s, got %s\n", wine_dbgstr_w(iconpathW), wine_dbgstr_w(fcs.pszIconFile));
5274 hr = pSHGetSetFolderCustomSettings(&fcs, NULL, FCS_READ);
5275 ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
5277 lstrcpyW(bufferW, pathW);
5278 lstrcatW(bufferW, desktop_iniW);
5279 DeleteFileW(bufferW);
5280 RemoveDirectoryW(pathW);
5283 START_TEST(shlfolder)
5285 init_function_pointers();
5286 /* if OleInitialize doesn't get called, ParseDisplayName returns
5287 CO_E_NOTINITIALIZED for malformed directory names */
5288 OleInitialize(NULL);
5290 test_ParseDisplayName();
5291 test_SHParseDisplayName();
5292 test_BindToObject();
5293 test_EnumObjects_and_CompareIDs();
5294 test_GetDisplayName();
5295 test_GetAttributesOf();
5296 test_SHGetPathFromIDList();
5297 test_CallForAttributes();
5298 test_FolderShortcut();
5299 test_ITEMIDLIST_format();
5300 test_SHGetFolderPathA();
5301 test_SHGetFolderPathAndSubDirA();
5302 test_LocalizedNames();
5303 test_SHCreateShellItem();
5304 test_SHCreateShellItemArray();
5305 test_ShellItemArrayEnumItems();
5306 test_desktop_IPersist();
5307 test_GetUIObject();
5308 test_SHSimpleIDListFromPath();
5309 test_ParseDisplayNamePBC();
5310 test_SHGetNameFromIDList();
5311 test_SHGetItemFromDataObject();
5312 test_SHGetIDListFromObject();
5313 test_SHGetItemFromObject();
5314 test_ShellItemCompare();
5315 test_SHChangeNotify(FALSE);
5316 test_SHChangeNotify(TRUE);
5317 test_ShellItemBindToHandler();
5318 test_ShellItemGetAttributes();
5319 test_ShellItemArrayGetAttributes();
5320 test_SHCreateDefaultContextMenu();
5321 test_DataObject();
5322 test_GetDefaultColumn();
5323 test_GetDefaultSearchGUID();
5324 test_SHLimitInputEdit();
5325 test_SHGetSetFolderCustomSettings();
5327 OleUninitialize();