jscript: Removed unused do_*_tag_format arguments.
[wine/multimedia.git] / dlls / shell32 / tests / shlfolder.c
blobbee6cb5a13af5bfcbf352aca49fc3fa2cf31f3ed
1 /*
2 * Unit test of the IShellFolder functions.
4 * Copyright 2004 Vitaliy Margolen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdio.h>
24 #define COBJMACROS
25 #define CONST_VTABLE
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wtypes.h"
30 #include "shellapi.h"
33 #include "shlguid.h"
34 #include "shlobj.h"
35 #include "shobjidl.h"
36 #include "shlwapi.h"
37 #include "ocidl.h"
38 #include "oleauto.h"
40 #include "wine/test.h"
42 #include <initguid.h>
43 DEFINE_GUID(IID_IParentAndItem, 0xB3A4B685, 0xB685, 0x4805, 0x99,0xD9, 0x5D,0xEA,0xD2,0x87,0x32,0x36);
44 DEFINE_GUID(CLSID_ShellDocObjView, 0xe7e4bc40, 0xe76a, 0x11ce, 0xa9,0xbb, 0x00,0xaa,0x00,0x4a,0xe8,0x37);
46 static IMalloc *ppM;
48 static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
49 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
50 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
51 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
52 static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
53 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
54 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
55 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
56 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
57 static void (WINAPI *pILFree)(LPITEMIDLIST);
58 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
59 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
60 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
61 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
62 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
63 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
64 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
65 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
66 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
67 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
68 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
69 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
70 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
71 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
72 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
73 static UINT (WINAPI *pGetSystemWow64DirectoryW)(LPWSTR, UINT);
74 static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
76 static WCHAR *make_wstr(const char *str)
78 WCHAR *ret;
79 int len;
81 if(!str || strlen(str) == 0)
82 return NULL;
84 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
85 if(!len || len < 0)
86 return NULL;
88 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
89 if(!ret)
90 return NULL;
92 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
93 return ret;
96 static int strcmp_wa(LPCWSTR strw, const char *stra)
98 CHAR buf[512];
99 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
100 return lstrcmpA(stra, buf);
103 static void init_function_pointers(void)
105 HMODULE hmod;
106 HRESULT hr;
107 void *ptr;
109 hmod = GetModuleHandleA("shell32.dll");
111 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
112 MAKEFUNC(SHBindToParent);
113 MAKEFUNC(SHCreateItemFromIDList);
114 MAKEFUNC(SHCreateItemFromParsingName);
115 MAKEFUNC(SHCreateShellItem);
116 MAKEFUNC(SHCreateShellItemArray);
117 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
118 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
119 MAKEFUNC(SHGetFolderPathA);
120 MAKEFUNC(SHGetFolderPathAndSubDirA);
121 MAKEFUNC(SHGetPathFromIDListW);
122 MAKEFUNC(SHGetSpecialFolderPathA);
123 MAKEFUNC(SHGetSpecialFolderPathW);
124 MAKEFUNC(SHGetSpecialFolderLocation);
125 MAKEFUNC(SHParseDisplayName);
126 MAKEFUNC(SHGetNameFromIDList);
127 MAKEFUNC(SHGetItemFromDataObject);
128 MAKEFUNC(SHGetIDListFromObject);
129 MAKEFUNC(SHGetItemFromObject);
130 MAKEFUNC(SHCreateDefaultContextMenu);
131 #undef MAKEFUNC
133 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
134 MAKEFUNC_ORD(ILFindLastID, 16);
135 MAKEFUNC_ORD(ILIsEqual, 21);
136 MAKEFUNC_ORD(ILCombine, 25);
137 MAKEFUNC_ORD(ILFree, 155);
138 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
139 #undef MAKEFUNC_ORD
141 /* test named exports */
142 ptr = GetProcAddress(hmod, "ILFree");
143 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
144 if (ptr)
146 #define TESTNAMED(f) \
147 ptr = (void*)GetProcAddress(hmod, #f); \
148 ok(ptr != 0, "expected named export for " #f "\n");
150 TESTNAMED(ILAppendID);
151 TESTNAMED(ILClone);
152 TESTNAMED(ILCloneFirst);
153 TESTNAMED(ILCombine);
154 TESTNAMED(ILCreateFromPath);
155 TESTNAMED(ILCreateFromPathA);
156 TESTNAMED(ILCreateFromPathW);
157 TESTNAMED(ILFindChild);
158 TESTNAMED(ILFindLastID);
159 TESTNAMED(ILGetNext);
160 TESTNAMED(ILGetSize);
161 TESTNAMED(ILIsEqual);
162 TESTNAMED(ILIsParent);
163 TESTNAMED(ILRemoveLastID);
164 TESTNAMED(ILSaveToStream);
165 #undef TESTNAMED
168 hmod = GetModuleHandleA("shlwapi.dll");
169 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
171 hmod = GetModuleHandleA("kernel32.dll");
172 pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
173 pGetSystemWow64DirectoryW = (void*)GetProcAddress(hmod, "GetSystemWow64DirectoryW");
175 hr = SHGetMalloc(&ppM);
176 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
179 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
180 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
182 size_t iLen;
184 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
185 return NULL;
187 if (iLen)
189 lpszPath += iLen;
190 if (lpszPath[-1] != '\\')
192 *lpszPath++ = '\\';
193 *lpszPath = '\0';
196 return lpszPath;
199 static void test_ParseDisplayName(void)
201 HRESULT hr;
202 IShellFolder *IDesktopFolder;
203 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
204 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
205 static const char *cInetTestA = "http:\\yyy";
206 static const char *cInetTest2A = "xx:yyy";
207 DWORD res;
208 WCHAR cTestDirW [MAX_PATH] = {0};
209 ITEMIDLIST *newPIDL;
210 BOOL bRes;
212 hr = SHGetDesktopFolder(&IDesktopFolder);
213 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
214 if(hr != S_OK) return;
216 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
217 if (pSHCreateShellItem)
219 /* null name and pidl */
220 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
221 NULL, NULL, NULL, NULL, NULL, 0);
222 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
224 /* null name */
225 newPIDL = (ITEMIDLIST*)0xdeadbeef;
226 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
227 NULL, NULL, NULL, NULL, &newPIDL, 0);
228 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
229 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
231 else
232 win_skip("Tests would crash on W2K and below\n");
234 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
235 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
236 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
237 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
238 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
239 if (hr == S_OK)
241 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
242 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
243 IMalloc_Free(ppM, newPIDL);
246 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
247 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
248 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
249 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
250 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
251 if (hr == S_OK)
253 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
254 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
255 IMalloc_Free(ppM, newPIDL);
258 res = GetFileAttributesA(cNonExistDir1A);
259 if(res != INVALID_FILE_ATTRIBUTES)
261 skip("Test directory unexpectedly exists\n");
262 goto finished;
265 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
266 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
267 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
268 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
269 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
271 res = GetFileAttributesA(cNonExistDir2A);
272 if(res != INVALID_FILE_ATTRIBUTES)
274 skip("Test directory unexpectedly exists\n");
275 goto finished;
278 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
279 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
280 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
281 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
282 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
284 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
285 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
286 * out it doesn't. The magic seems to happen in the file dialogs, then. */
287 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
289 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
290 goto finished;
293 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
294 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
295 if (!bRes) goto finished;
297 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
298 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
299 if (hr != S_OK) goto finished;
301 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
302 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
303 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
304 pILFindLastID(newPIDL)->mkid.abID[0]);
305 IMalloc_Free(ppM, newPIDL);
307 finished:
308 IShellFolder_Release(IDesktopFolder);
311 /* creates a file with the specified name for tests */
312 static void CreateTestFile(const CHAR *name)
314 HANDLE file;
315 DWORD written;
317 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
318 if (file != INVALID_HANDLE_VALUE)
320 WriteFile(file, name, strlen(name), &written, NULL);
321 WriteFile(file, "\n", strlen("\n"), &written, NULL);
322 CloseHandle(file);
327 /* initializes the tests */
328 static void CreateFilesFolders(void)
330 CreateDirectoryA(".\\testdir", NULL);
331 CreateDirectoryA(".\\testdir\\test.txt", NULL);
332 CreateTestFile (".\\testdir\\test1.txt ");
333 CreateTestFile (".\\testdir\\test2.txt ");
334 CreateTestFile (".\\testdir\\test3.txt ");
335 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
336 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
339 /* cleans after tests */
340 static void Cleanup(void)
342 DeleteFileA(".\\testdir\\test1.txt");
343 DeleteFileA(".\\testdir\\test2.txt");
344 DeleteFileA(".\\testdir\\test3.txt");
345 RemoveDirectoryA(".\\testdir\\test.txt");
346 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
347 RemoveDirectoryA(".\\testdir\\testdir2");
348 RemoveDirectoryA(".\\testdir");
352 /* perform test */
353 static void test_EnumObjects(IShellFolder *iFolder)
355 IEnumIDList *iEnumList;
356 LPITEMIDLIST newPIDL, idlArr[10];
357 ULONG NumPIDLs;
358 int i=0, j;
359 HRESULT hr;
361 static const WORD iResults [5][5] =
363 { 0,-1,-1,-1,-1},
364 { 1, 0,-1,-1,-1},
365 { 1, 1, 0,-1,-1},
366 { 1, 1, 1, 0,-1},
367 { 1, 1, 1, 1, 0}
370 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
371 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
372 static const ULONG attrs[5] =
374 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
375 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
376 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
377 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
378 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
381 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
382 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
384 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
385 * the filesystem shellfolders return S_OK even if less than 'celt' items are
386 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
387 * only ever returns a single entry per call. */
388 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
389 i += NumPIDLs;
390 ok (i == 5, "i: %d\n", i);
392 hr = IEnumIDList_Release(iEnumList);
393 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
395 /* Sort them first in case of wrong order from system */
396 for (i=0;i<5;i++) for (j=0;j<5;j++)
397 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
399 newPIDL = idlArr[i];
400 idlArr[i] = idlArr[j];
401 idlArr[j] = newPIDL;
404 for (i=0;i<5;i++) for (j=0;j<5;j++)
406 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
407 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
411 for (i = 0; i < 5; i++)
413 SFGAOF flags;
414 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
415 /* Native returns all flags no matter what we ask for */
416 flags = SFGAO_CANCOPY;
417 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
418 flags &= SFGAO_testfor;
419 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
420 ok(flags == (attrs[i]) ||
421 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
422 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
423 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
425 flags = SFGAO_testfor;
426 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
427 flags &= SFGAO_testfor;
428 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
429 ok(flags == attrs[i] ||
430 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
431 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
434 for (i=0;i<5;i++)
435 IMalloc_Free(ppM, idlArr[i]);
438 static void test_BindToObject(void)
440 HRESULT hr;
441 UINT cChars;
442 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
443 SHITEMID emptyitem = { 0, { 0 } };
444 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
445 WCHAR wszSystemDir[MAX_PATH];
446 char szSystemDir[MAX_PATH];
447 char buf[MAX_PATH];
448 WCHAR path[MAX_PATH];
449 CHAR pathA[MAX_PATH];
450 HANDLE hfile;
451 WCHAR wszMyComputer[] = {
452 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
453 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
454 static const CHAR filename_html[] = "winetest.html";
455 static const CHAR filename_txt[] = "winetest.txt";
456 static const CHAR filename_foo[] = "winetest.foo";
458 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
459 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
461 hr = SHGetDesktopFolder(&psfDesktop);
462 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
463 if (hr != S_OK) return;
465 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
466 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
468 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
469 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
471 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
472 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
473 if (hr != S_OK) {
474 IShellFolder_Release(psfDesktop);
475 return;
478 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
479 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
480 IShellFolder_Release(psfDesktop);
481 IMalloc_Free(ppM, pidlMyComputer);
482 if (hr != S_OK) return;
484 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
485 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
487 if (0)
489 /* this call segfaults on 98SE */
490 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
491 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
494 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
495 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
496 if (cChars == 0 || cChars >= MAX_PATH) {
497 IShellFolder_Release(psfMyComputer);
498 return;
500 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
502 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
503 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
504 if (hr != S_OK) {
505 IShellFolder_Release(psfMyComputer);
506 return;
509 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
510 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
511 IShellFolder_Release(psfMyComputer);
512 IMalloc_Free(ppM, pidlSystemDir);
513 if (hr != S_OK) return;
515 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
516 ok (hr == E_INVALIDARG,
517 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
519 if (0)
521 /* this call segfaults on 98SE */
522 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
523 ok (hr == E_INVALIDARG,
524 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
527 IShellFolder_Release(psfSystemDir);
529 GetCurrentDirectoryA(MAX_PATH, buf);
530 if(!lstrlenA(buf))
532 skip("Failed to get current directory, skipping tests.\n");
533 return;
536 SHGetDesktopFolder(&psfDesktop);
538 /* Attempt BindToObject on files. */
540 /* .html */
541 lstrcpyA(pathA, buf);
542 lstrcatA(pathA, "\\");
543 lstrcatA(pathA, filename_html);
544 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
545 if(hfile != INVALID_HANDLE_VALUE)
547 CloseHandle(hfile);
548 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
549 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
550 ok(hr == S_OK, "Got 0x%08x\n", hr);
551 if(SUCCEEDED(hr))
553 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
554 ok(hr == S_OK ||
555 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
556 "Got 0x%08x\n", hr);
557 if(SUCCEEDED(hr))
559 IPersist *pp;
560 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
561 ok(hr == S_OK ||
562 broken(hr == E_NOINTERFACE), /* Win9x, NT4, W2K */
563 "Got 0x%08x\n", hr);
564 if(SUCCEEDED(hr))
566 CLSID id;
567 hr = IPersist_GetClassID(pp, &id);
568 ok(hr == S_OK, "Got 0x%08x\n", hr);
569 ok(IsEqualIID(&id, &CLSID_ShellDocObjView), "Unexpected classid\n");
570 IPersist_Release(pp);
573 IShellFolder_Release(psfChild);
575 pILFree(pidl);
577 DeleteFileA(pathA);
579 else
580 win_skip("Failed to create .html testfile.\n");
582 /* .txt */
583 lstrcpyA(pathA, buf);
584 lstrcatA(pathA, "\\");
585 lstrcatA(pathA, filename_txt);
586 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
587 if(hfile != INVALID_HANDLE_VALUE)
589 CloseHandle(hfile);
590 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
591 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
592 ok(hr == S_OK, "Got 0x%08x\n", hr);
593 if(SUCCEEDED(hr))
595 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
596 ok(hr == E_FAIL || /* Vista+ */
597 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
598 broken(hr == S_OK), /* Win9x, NT4, W2K */
599 "Got 0x%08x\n", hr);
600 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
601 pILFree(pidl);
603 DeleteFileA(pathA);
605 else
606 win_skip("Failed to create .txt testfile.\n");
608 /* .foo */
609 lstrcpyA(pathA, buf);
610 lstrcatA(pathA, "\\");
611 lstrcatA(pathA, filename_foo);
612 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
613 if(hfile != INVALID_HANDLE_VALUE)
615 CloseHandle(hfile);
616 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
617 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
618 ok(hr == S_OK, "Got 0x%08x\n", hr);
619 if(SUCCEEDED(hr))
621 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
622 ok(hr == E_FAIL || /* Vista+ */
623 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
624 broken(hr == S_OK), /* Win9x, NT4, W2K */
625 "Got 0x%08x\n", hr);
626 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
627 pILFree(pidl);
629 DeleteFileA(pathA);
631 else
632 win_skip("Failed to create .foo testfile.\n");
634 /* And on the desktop */
635 if(pSHGetSpecialFolderPathA)
637 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
638 lstrcatA(pathA, "\\");
639 lstrcatA(pathA, filename_html);
640 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
641 if(hfile != INVALID_HANDLE_VALUE)
643 CloseHandle(hfile);
644 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
645 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
646 ok(hr == S_OK, "Got 0x%08x\n", hr);
647 if(SUCCEEDED(hr))
649 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
650 ok(hr == S_OK ||
651 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
652 "Got 0x%08x\n", hr);
653 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
654 pILFree(pidl);
656 if(!DeleteFileA(pathA))
657 trace("Failed to delete: %d\n", GetLastError());
660 else
661 win_skip("Failed to create .html testfile.\n");
663 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
664 lstrcatA(pathA, "\\");
665 lstrcatA(pathA, filename_foo);
666 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
667 if(hfile != INVALID_HANDLE_VALUE)
669 CloseHandle(hfile);
670 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
671 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
672 ok(hr == S_OK, "Got 0x%08x\n", hr);
673 if(SUCCEEDED(hr))
675 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
676 ok(hr == E_FAIL || /* Vista+ */
677 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
678 broken(hr == S_OK), /* Win9x, NT4, W2K */
679 "Got 0x%08x\n", hr);
680 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
681 pILFree(pidl);
683 DeleteFileA(pathA);
685 else
686 win_skip("Failed to create .foo testfile.\n");
689 IShellFolder_Release(psfDesktop);
692 static void test_GetDisplayName(void)
694 BOOL result;
695 HRESULT hr;
696 HANDLE hTestFile;
697 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
698 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
699 DWORD attr;
700 STRRET strret;
701 LPSHELLFOLDER psfDesktop, psfPersonal;
702 IUnknown *psfFile;
703 SHITEMID emptyitem = { 0, { 0 } };
704 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
705 LPCITEMIDLIST pidlLast;
706 static const CHAR szFileName[] = "winetest.foo";
707 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
708 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
710 /* I'm trying to figure if there is a functional difference between calling
711 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
712 * binding to the shellfolder. One thing I thought of was that perhaps
713 * SHGetPathFromIDListW would be able to get the path to a file, which does
714 * not exist anymore, while the other method wouldn't. It turns out there's
715 * no functional difference in this respect.
718 if(!pSHGetSpecialFolderPathA) {
719 win_skip("SHGetSpecialFolderPathA is not available\n");
720 return;
723 /* First creating a directory in MyDocuments and a file in this directory. */
724 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
725 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
726 if (!result) return;
728 /* Use ANSI file functions so this works on Windows 9x */
729 lstrcatA(szTestDir, "\\winetest");
730 CreateDirectoryA(szTestDir, NULL);
731 attr=GetFileAttributesA(szTestDir);
732 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
734 ok(0, "unable to create the '%s' directory\n", szTestDir);
735 return;
738 lstrcpyA(szTestFile, szTestDir);
739 lstrcatA(szTestFile, "\\");
740 lstrcatA(szTestFile, szFileName);
741 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
742 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
743 if (hTestFile == INVALID_HANDLE_VALUE) return;
744 CloseHandle(hTestFile);
746 /* Getting an itemidlist for the file. */
747 hr = SHGetDesktopFolder(&psfDesktop);
748 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
749 if (hr != S_OK) return;
751 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
753 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
754 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
755 if (hr != S_OK) {
756 IShellFolder_Release(psfDesktop);
757 return;
760 pidlLast = pILFindLastID(pidlTestFile);
761 ok(pidlLast->mkid.cb >=76 ||
762 broken(pidlLast->mkid.cb == 28) || /* W2K */
763 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
764 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
765 if (pidlLast->mkid.cb >= 28) {
766 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
767 "Filename should be stored as ansi-string at this position!\n");
769 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
770 if (pidlLast->mkid.cb >= 76) {
771 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
772 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
773 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
774 "Filename should be stored as wchar-string at this position!\n");
777 /* It seems as if we cannot bind to regular files on windows, but only directories.
779 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
780 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
781 hr == E_NOTIMPL || /* Vista */
782 broken(hr == S_OK), /* Win9x, W2K */
783 "hr = %08x\n", hr);
784 if (hr == S_OK) {
785 IShellFolder_Release(psfFile);
788 if (!pSHBindToParent)
790 win_skip("SHBindToParent is missing\n");
791 DeleteFileA(szTestFile);
792 RemoveDirectoryA(szTestDir);
793 return;
796 /* Some tests for IShellFolder::SetNameOf */
797 if (pSHGetFolderPathAndSubDirA)
799 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
800 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
801 if (hr == S_OK) {
802 /* It's ok to use this fixed path. Call will fail anyway. */
803 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
804 LPITEMIDLIST pidlNew;
806 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
807 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
808 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
809 if (hr == S_OK)
811 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
812 "pidl returned from SetNameOf should be simple!\n");
814 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
815 * is implemented on top of SHFileOperation in WinXP. */
816 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
817 SHGDN_FORPARSING, NULL);
818 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
820 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
821 * SHGDN flags specify an absolute path. */
822 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
823 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
825 pILFree(pidlNew);
828 IShellFolder_Release(psfPersonal);
831 else
832 win_skip("Avoid needs of interaction on Win2k\n");
834 /* Deleting the file and the directory */
835 DeleteFileA(szTestFile);
836 RemoveDirectoryA(szTestDir);
838 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
839 if (pSHGetPathFromIDListW)
841 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
842 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
843 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
846 /* SHBindToParent fails, if called with a NULL PIDL. */
847 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
848 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
850 /* But it succeeds with an empty PIDL. */
851 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
852 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
853 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
854 if (hr == S_OK)
855 IShellFolder_Release(psfPersonal);
857 /* Binding to the folder and querying the display name of the file also works. */
858 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
859 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
860 if (hr != S_OK) {
861 IShellFolder_Release(psfDesktop);
862 return;
865 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
866 * pidlTestFile (In accordance with MSDN). */
867 ok (pILFindLastID(pidlTestFile) == pidlLast,
868 "SHBindToParent doesn't return the last id of the pidl param!\n");
870 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
871 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
872 if (hr != S_OK) {
873 IShellFolder_Release(psfDesktop);
874 IShellFolder_Release(psfPersonal);
875 return;
878 if (pStrRetToBufW)
880 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
881 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
882 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
885 ILFree(pidlTestFile);
886 IShellFolder_Release(psfDesktop);
887 IShellFolder_Release(psfPersonal);
890 static void test_CallForAttributes(void)
892 HKEY hKey;
893 LONG lResult;
894 HRESULT hr;
895 DWORD dwSize;
896 LPSHELLFOLDER psfDesktop;
897 LPITEMIDLIST pidlMyDocuments;
898 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
899 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
900 static const WCHAR wszCallForAttributes[] = {
901 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
902 static const WCHAR wszMyDocumentsKey[] = {
903 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
904 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
905 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
906 WCHAR wszMyDocuments[] = {
907 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
908 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
910 /* For the root of a namespace extension, the attributes are not queried by binding
911 * to the object and calling GetAttributesOf. Instead, the attributes are read from
912 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
914 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
915 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
916 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
917 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
919 hr = SHGetDesktopFolder(&psfDesktop);
920 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
921 if (hr != S_OK) return;
923 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
924 &pidlMyDocuments, NULL);
925 ok (hr == S_OK ||
926 broken(hr == E_INVALIDARG), /* Win95, NT4 */
927 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
928 if (hr != S_OK) {
929 IShellFolder_Release(psfDesktop);
930 return;
933 dwAttributes = 0xffffffff;
934 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
935 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
936 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
938 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
939 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
940 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
941 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
943 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
944 * key. So the test will return at this point, if run on wine.
946 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
947 ok (lResult == ERROR_SUCCESS ||
948 lResult == ERROR_ACCESS_DENIED,
949 "RegOpenKeyEx failed! result: %08x\n", lResult);
950 if (lResult != ERROR_SUCCESS) {
951 if (lResult == ERROR_ACCESS_DENIED)
952 skip("Not enough rights to open the registry key\n");
953 IMalloc_Free(ppM, pidlMyDocuments);
954 IShellFolder_Release(psfDesktop);
955 return;
958 /* Query MyDocuments' Attributes value, to be able to restore it later. */
959 dwSize = sizeof(DWORD);
960 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
961 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
962 if (lResult != ERROR_SUCCESS) {
963 RegCloseKey(hKey);
964 IMalloc_Free(ppM, pidlMyDocuments);
965 IShellFolder_Release(psfDesktop);
966 return;
969 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
970 dwSize = sizeof(DWORD);
971 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
972 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
973 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
974 if (lResult != ERROR_SUCCESS) {
975 RegCloseKey(hKey);
976 IMalloc_Free(ppM, pidlMyDocuments);
977 IShellFolder_Release(psfDesktop);
978 return;
981 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
982 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
983 * SFGAO_FILESYSTEM attributes. */
984 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
985 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
986 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
987 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
988 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
990 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
991 * GetAttributesOf. It seems that once there is a single attribute queried, for which
992 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
993 * the flags in Attributes are ignored.
995 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
996 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
997 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
998 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
999 if (hr == S_OK)
1000 ok (dwAttributes == SFGAO_FILESYSTEM,
1001 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
1002 dwAttributes);
1004 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
1005 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
1006 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1007 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
1008 RegCloseKey(hKey);
1009 IMalloc_Free(ppM, pidlMyDocuments);
1010 IShellFolder_Release(psfDesktop);
1013 static void test_GetAttributesOf(void)
1015 HRESULT hr;
1016 LPSHELLFOLDER psfDesktop, psfMyComputer;
1017 SHITEMID emptyitem = { 0, { 0 } };
1018 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1019 LPITEMIDLIST pidlMyComputer;
1020 DWORD dwFlags;
1021 static const DWORD desktopFlags[] = {
1022 /* WinXP */
1023 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
1024 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1025 /* Win2k */
1026 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
1027 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1028 /* WinMe, Win9x, WinNT*/
1029 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
1030 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1032 static const DWORD myComputerFlags[] = {
1033 /* WinXP */
1034 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
1035 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1036 /* Win2k */
1037 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
1038 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1039 /* WinMe, Win9x, WinNT */
1040 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1041 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1042 /* Win95, WinNT when queried directly */
1043 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1044 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1046 WCHAR wszMyComputer[] = {
1047 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1048 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1049 char cCurrDirA [MAX_PATH] = {0};
1050 WCHAR cCurrDirW [MAX_PATH];
1051 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
1052 IShellFolder *IDesktopFolder, *testIShellFolder;
1053 ITEMIDLIST *newPIDL;
1054 int len, i;
1055 BOOL foundFlagsMatch;
1057 hr = SHGetDesktopFolder(&psfDesktop);
1058 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1059 if (hr != S_OK) return;
1061 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
1062 dwFlags = 0xffffffff;
1063 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
1064 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
1065 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1066 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1068 if (desktopFlags[i] == dwFlags)
1069 foundFlagsMatch = TRUE;
1071 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1073 /* .. or with no itemidlist at all. */
1074 dwFlags = 0xffffffff;
1075 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
1076 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1077 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1078 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1080 if (desktopFlags[i] == dwFlags)
1081 foundFlagsMatch = TRUE;
1083 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1085 /* Testing the attributes of the MyComputer shellfolder */
1086 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1087 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1088 if (hr != S_OK) {
1089 IShellFolder_Release(psfDesktop);
1090 return;
1093 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
1094 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
1096 dwFlags = 0xffffffff;
1097 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
1098 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
1099 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1100 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1102 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
1103 foundFlagsMatch = TRUE;
1105 todo_wine
1106 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1108 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
1109 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
1110 IShellFolder_Release(psfDesktop);
1111 IMalloc_Free(ppM, pidlMyComputer);
1112 if (hr != S_OK) return;
1114 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
1115 todo_wine
1116 ok (hr == E_INVALIDARG ||
1117 broken(hr == S_OK), /* W2K and earlier */
1118 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
1120 dwFlags = 0xffffffff;
1121 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
1122 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1123 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1124 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1126 if (myComputerFlags[i] == dwFlags)
1127 foundFlagsMatch = TRUE;
1129 todo_wine
1130 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1132 IShellFolder_Release(psfMyComputer);
1134 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1135 len = lstrlenA(cCurrDirA);
1137 if (len == 0) {
1138 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1139 return;
1141 if (len > 3 && cCurrDirA[len-1] == '\\')
1142 cCurrDirA[len-1] = 0;
1144 /* create test directory */
1145 CreateFilesFolders();
1147 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1149 hr = SHGetDesktopFolder(&IDesktopFolder);
1150 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1152 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1153 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1155 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1156 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1158 IMalloc_Free(ppM, newPIDL);
1160 /* get relative PIDL */
1161 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1162 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1164 /* test the shell attributes of the test directory using the relative PIDL */
1165 dwFlags = SFGAO_FOLDER;
1166 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1167 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1168 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1170 /* free memory */
1171 IMalloc_Free(ppM, newPIDL);
1173 /* append testdirectory name to path */
1174 if (cCurrDirA[len-1] == '\\')
1175 cCurrDirA[len-1] = 0;
1176 lstrcatA(cCurrDirA, "\\testdir");
1177 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1179 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1180 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1182 /* test the shell attributes of the test directory using the absolute PIDL */
1183 dwFlags = SFGAO_FOLDER;
1184 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1185 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1186 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1188 /* free memory */
1189 IMalloc_Free(ppM, newPIDL);
1191 IShellFolder_Release(testIShellFolder);
1193 Cleanup();
1195 IShellFolder_Release(IDesktopFolder);
1198 static void test_SHGetPathFromIDList(void)
1200 SHITEMID emptyitem = { 0, { 0 } };
1201 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1202 LPITEMIDLIST pidlMyComputer;
1203 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1204 BOOL result;
1205 HRESULT hr;
1206 LPSHELLFOLDER psfDesktop;
1207 WCHAR wszMyComputer[] = {
1208 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1209 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1210 WCHAR wszFileName[MAX_PATH];
1211 LPITEMIDLIST pidlTestFile;
1212 HANDLE hTestFile;
1213 STRRET strret;
1214 static WCHAR wszTestFile[] = {
1215 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1216 LPITEMIDLIST pidlPrograms;
1218 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1220 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1221 return;
1224 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1225 wszPath[0] = 'a';
1226 wszPath[1] = '\0';
1227 result = pSHGetPathFromIDListW(NULL, wszPath);
1228 ok(!result, "Expected failure\n");
1229 ok(!wszPath[0], "Expected empty string\n");
1231 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1232 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1233 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1234 if (!result) return;
1236 /* Check if we are on Win9x */
1237 SetLastError(0xdeadbeef);
1238 lstrcmpiW(wszDesktop, wszDesktop);
1239 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1241 win_skip("Most W-calls are not implemented\n");
1242 return;
1245 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1246 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1247 if (!result) return;
1248 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1250 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1251 hr = SHGetDesktopFolder(&psfDesktop);
1252 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1253 if (hr != S_OK) return;
1255 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1256 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1257 if (hr != S_OK) {
1258 IShellFolder_Release(psfDesktop);
1259 return;
1262 SetLastError(0xdeadbeef);
1263 wszPath[0] = 'a';
1264 wszPath[1] = '\0';
1265 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1266 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1267 ok (GetLastError()==0xdeadbeef ||
1268 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1269 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1270 ok (!wszPath[0], "Expected empty path\n");
1271 if (result) {
1272 IShellFolder_Release(psfDesktop);
1273 return;
1276 IMalloc_Free(ppM, pidlMyComputer);
1278 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1279 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1280 if (!result) {
1281 IShellFolder_Release(psfDesktop);
1282 return;
1284 myPathAddBackslashW(wszFileName);
1285 lstrcatW(wszFileName, wszTestFile);
1286 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1287 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1288 if (hTestFile == INVALID_HANDLE_VALUE) {
1289 IShellFolder_Release(psfDesktop);
1290 return;
1292 CloseHandle(hTestFile);
1294 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1295 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1296 if (hr != S_OK) {
1297 IShellFolder_Release(psfDesktop);
1298 DeleteFileW(wszFileName);
1299 IMalloc_Free(ppM, pidlTestFile);
1300 return;
1303 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1304 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1305 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1306 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1307 IShellFolder_Release(psfDesktop);
1308 DeleteFileW(wszFileName);
1309 if (hr != S_OK) {
1310 IMalloc_Free(ppM, pidlTestFile);
1311 return;
1313 if (pStrRetToBufW)
1315 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1316 ok(0 == lstrcmpW(wszFileName, wszPath),
1317 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1318 "returned incorrect path for file placed on desktop\n");
1321 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1322 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1323 IMalloc_Free(ppM, pidlTestFile);
1324 if (!result) return;
1325 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1328 /* Test if we can get the path from the start menu "program files" PIDL. */
1329 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1330 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1332 SetLastError(0xdeadbeef);
1333 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1334 IMalloc_Free(ppM, pidlPrograms);
1335 ok(result, "SHGetPathFromIDListW failed\n");
1338 static void test_EnumObjects_and_CompareIDs(void)
1340 ITEMIDLIST *newPIDL;
1341 IShellFolder *IDesktopFolder, *testIShellFolder;
1342 char cCurrDirA [MAX_PATH] = {0};
1343 static const CHAR cTestDirA[] = "\\testdir";
1344 WCHAR cTestDirW[MAX_PATH];
1345 int len;
1346 HRESULT hr;
1348 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1349 len = lstrlenA(cCurrDirA);
1351 if(len == 0) {
1352 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1353 return;
1355 if(cCurrDirA[len-1] == '\\')
1356 cCurrDirA[len-1] = 0;
1358 lstrcatA(cCurrDirA, cTestDirA);
1359 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1361 hr = SHGetDesktopFolder(&IDesktopFolder);
1362 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1364 CreateFilesFolders();
1366 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1367 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1369 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1370 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1372 test_EnumObjects(testIShellFolder);
1374 IShellFolder_Release(testIShellFolder);
1376 Cleanup();
1378 IMalloc_Free(ppM, newPIDL);
1380 IShellFolder_Release(IDesktopFolder);
1383 /* A simple implementation of an IPropertyBag, which returns fixed values for
1384 * 'Target' and 'Attributes' properties.
1386 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1387 void **ppvObject)
1389 if (!ppvObject)
1390 return E_INVALIDARG;
1392 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1393 *ppvObject = iface;
1394 } else {
1395 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1396 return E_NOINTERFACE;
1399 IPropertyBag_AddRef(iface);
1400 return S_OK;
1403 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1404 return 2;
1407 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1408 return 1;
1411 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1412 VARIANT *pVar, IErrorLog *pErrorLog)
1414 static const WCHAR wszTargetSpecialFolder[] = {
1415 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1416 static const WCHAR wszTarget[] = {
1417 'T','a','r','g','e','t',0 };
1418 static const WCHAR wszAttributes[] = {
1419 'A','t','t','r','i','b','u','t','e','s',0 };
1420 static const WCHAR wszResolveLinkFlags[] = {
1421 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1422 static const WCHAR wszTargetKnownFolder[] = {
1423 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1424 static const WCHAR wszCLSID[] = {
1425 'C','L','S','I','D',0 };
1427 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1428 ok(V_VT(pVar) == VT_I4 ||
1429 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1430 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1431 return E_INVALIDARG;
1434 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1436 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1437 return E_INVALIDARG;
1440 if (!lstrcmpW(pszPropName, wszTarget)) {
1441 WCHAR wszPath[MAX_PATH];
1442 BOOL result;
1444 ok(V_VT(pVar) == VT_BSTR ||
1445 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1446 "Wrong variant type for 'Target' property!\n");
1447 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1449 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1450 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1451 if (!result) return E_INVALIDARG;
1453 V_BSTR(pVar) = SysAllocString(wszPath);
1454 return S_OK;
1457 if (!lstrcmpW(pszPropName, wszAttributes)) {
1458 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1459 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1460 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1461 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1462 return S_OK;
1465 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1466 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1467 /* TODO */
1468 return E_INVALIDARG;
1471 if (!lstrcmpW(pszPropName, wszCLSID)) {
1472 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1473 /* TODO */
1474 return E_INVALIDARG;
1477 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1478 return E_INVALIDARG;
1481 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1482 VARIANT *pVar)
1484 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1485 return E_NOTIMPL;
1488 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1489 InitPropertyBag_IPropertyBag_QueryInterface,
1490 InitPropertyBag_IPropertyBag_AddRef,
1491 InitPropertyBag_IPropertyBag_Release,
1492 InitPropertyBag_IPropertyBag_Read,
1493 InitPropertyBag_IPropertyBag_Write
1496 static struct IPropertyBag InitPropertyBag = {
1497 &InitPropertyBag_IPropertyBagVtbl
1500 static void test_FolderShortcut(void) {
1501 IPersistPropertyBag *pPersistPropertyBag;
1502 IShellFolder *pShellFolder, *pDesktopFolder;
1503 IPersistFolder3 *pPersistFolder3;
1504 HRESULT hr;
1505 STRRET strret;
1506 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1507 BOOL result;
1508 CLSID clsid;
1509 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1510 HKEY hShellExtKey;
1511 WCHAR wszWineTestFolder[] = {
1512 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1513 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1514 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1515 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1516 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1517 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1518 'N','a','m','e','S','p','a','c','e','\\',
1519 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1520 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1522 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1523 static const GUID CLSID_UnixDosFolder =
1524 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1526 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1527 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1528 return;
1531 if (!pSHGetFolderPathAndSubDirA)
1533 win_skip("FolderShortcut test doesn't work on Win2k\n");
1534 return;
1537 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1538 * via their IPersistPropertyBag interface. And that the target folder
1539 * is taken from the IPropertyBag's 'Target' property.
1541 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1542 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1543 if (hr == REGDB_E_CLASSNOTREG) {
1544 win_skip("CLSID_FolderShortcut is not implemented\n");
1545 return;
1547 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1548 if (hr != S_OK) return;
1550 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1551 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1552 if (hr != S_OK) {
1553 IPersistPropertyBag_Release(pPersistPropertyBag);
1554 return;
1557 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1558 (LPVOID*)&pShellFolder);
1559 IPersistPropertyBag_Release(pPersistPropertyBag);
1560 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1561 if (hr != S_OK) return;
1563 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1564 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1565 if (hr != S_OK) {
1566 IShellFolder_Release(pShellFolder);
1567 return;
1570 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1571 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1572 if (!result) return;
1574 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1575 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1577 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1578 IShellFolder_Release(pShellFolder);
1579 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1580 if (hr != S_OK) return;
1582 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1583 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1584 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1586 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1587 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1588 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1590 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1591 * shell namespace. The target folder, read from the property bag above, remains untouched.
1592 * The following tests show this: The itemidlist for some imaginary shellfolder object
1593 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1594 * itemidlist, but GetDisplayNameOf still returns the path from above.
1596 hr = SHGetDesktopFolder(&pDesktopFolder);
1597 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1598 if (hr != S_OK) return;
1600 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1601 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1602 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1603 RegCloseKey(hShellExtKey);
1604 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1605 &pidlWineTestFolder, NULL);
1606 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1607 IShellFolder_Release(pDesktopFolder);
1608 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1609 if (hr != S_OK) return;
1611 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1612 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1613 if (hr != S_OK) {
1614 IPersistFolder3_Release(pPersistFolder3);
1615 pILFree(pidlWineTestFolder);
1616 return;
1619 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1620 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1621 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1622 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1623 pILFree(pidlCurrentFolder);
1624 pILFree(pidlWineTestFolder);
1626 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1627 IPersistFolder3_Release(pPersistFolder3);
1628 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1629 if (hr != S_OK) return;
1631 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1632 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1633 if (hr != S_OK) {
1634 IShellFolder_Release(pShellFolder);
1635 return;
1638 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1639 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1641 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1642 * but ShellFSFolders. */
1643 myPathAddBackslashW(wszDesktopPath);
1644 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1645 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1646 IShellFolder_Release(pShellFolder);
1647 return;
1650 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1651 &pidlSubFolder, NULL);
1652 RemoveDirectoryW(wszDesktopPath);
1653 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1654 if (hr != S_OK) {
1655 IShellFolder_Release(pShellFolder);
1656 return;
1659 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1660 (LPVOID*)&pPersistFolder3);
1661 IShellFolder_Release(pShellFolder);
1662 pILFree(pidlSubFolder);
1663 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1664 if (hr != S_OK)
1665 return;
1667 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1668 * a little bit and also allow CLSID_UnixDosFolder. */
1669 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1670 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1671 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1672 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1674 IPersistFolder3_Release(pPersistFolder3);
1677 #include "pshpack1.h"
1678 struct FileStructA {
1679 BYTE type;
1680 BYTE dummy;
1681 DWORD dwFileSize;
1682 WORD uFileDate; /* In our current implementation this is */
1683 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1684 WORD uFileAttribs;
1685 CHAR szName[1];
1688 struct FileStructW {
1689 WORD cbLen; /* Length of this element. */
1690 BYTE abFooBar1[6]; /* Beyond any recognition. */
1691 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1692 WORD uTime; /* (this is currently speculation) */
1693 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1694 WORD uTime2; /* (this is currently speculation) */
1695 BYTE abFooBar2[4]; /* Beyond any recognition. */
1696 WCHAR wszName[1]; /* The long filename in unicode. */
1697 /* Just for documentation: Right after the unicode string: */
1698 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1699 * SHITEMID->cb == uOffset + cbLen */
1701 #include "poppack.h"
1703 static void test_ITEMIDLIST_format(void) {
1704 WCHAR wszPersonal[MAX_PATH];
1705 LPSHELLFOLDER psfDesktop, psfPersonal;
1706 LPITEMIDLIST pidlPersonal, pidlFile;
1707 HANDLE hFile;
1708 HRESULT hr;
1709 BOOL bResult;
1710 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1711 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1712 int i;
1714 if (!pSHGetSpecialFolderPathW) return;
1716 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1717 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1718 if (!bResult) return;
1720 SetLastError(0xdeadbeef);
1721 bResult = SetCurrentDirectoryW(wszPersonal);
1722 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1723 win_skip("Most W-calls are not implemented\n");
1724 return;
1726 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1727 if (!bResult) return;
1729 hr = SHGetDesktopFolder(&psfDesktop);
1730 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1731 if (hr != S_OK) return;
1733 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1734 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1735 if (hr != S_OK) {
1736 IShellFolder_Release(psfDesktop);
1737 return;
1740 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1741 (LPVOID*)&psfPersonal);
1742 IShellFolder_Release(psfDesktop);
1743 pILFree(pidlPersonal);
1744 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1745 if (hr != S_OK) return;
1747 for (i=0; i<3; i++) {
1748 CHAR szFile[MAX_PATH];
1749 struct FileStructA *pFileStructA;
1750 WORD cbOffset;
1752 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1754 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1755 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1756 if (hFile == INVALID_HANDLE_VALUE) {
1757 IShellFolder_Release(psfPersonal);
1758 return;
1760 CloseHandle(hFile);
1762 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1763 DeleteFileW(wszFile[i]);
1764 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1765 if (hr != S_OK) {
1766 IShellFolder_Release(psfPersonal);
1767 return;
1770 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1771 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1772 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1773 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1775 if (i < 2) /* First two file names are already in valid 8.3 format */
1776 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1777 else
1778 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1779 * can't implement this correctly, since unix filesystems don't support
1780 * this nasty short/long filename stuff. So we'll probably stay with our
1781 * current habit of storing the long filename here, which seems to work
1782 * just fine. */
1783 todo_wine
1784 ok(pidlFile->mkid.abID[18] == '~' ||
1785 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1786 "Should be derived 8.3 name!\n");
1788 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1789 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1790 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1791 "Alignment byte, where there shouldn't be!\n");
1793 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1794 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1795 "There should be an alignment byte, but isn't!\n");
1797 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1798 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1799 ok ((cbOffset >= sizeof(struct FileStructA) &&
1800 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1801 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1802 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1803 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1805 if (cbOffset >= sizeof(struct FileStructA) &&
1806 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1808 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1809 WCHAR *name = pFileStructW->wszName;
1811 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1812 "FileStructW's offset and length should add up to the PIDL's length!\n");
1814 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1815 /* Since we just created the file, time of creation,
1816 * time of last access and time of last write access just be the same.
1817 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1818 * after the first run. I do remember something with NTFS keeping the creation time
1819 * if a file is deleted and then created again within a couple of seconds or so.
1820 * Might be the reason. */
1821 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1822 pFileStructA->uFileTime == pFileStructW->uTime,
1823 "Last write time should match creation time!\n");
1825 /* On FAT filesystems the last access time is midnight
1826 local time, so the values of uDate2 and uTime2 will
1827 depend on the local timezone. If the times are exactly
1828 equal then the dates should be identical for both FAT
1829 and NTFS as no timezone is more than 1 day away from UTC.
1831 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1833 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1834 "Last write date and time should match last access date and time!\n");
1836 else
1838 /* Filesystem may be FAT. Check date within 1 day
1839 and seconds are zero. */
1840 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1841 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1842 "Last access time on FAT filesystems should have zero seconds.\n");
1843 /* TODO: Perform check for date being within one day.*/
1846 ok (!lstrcmpW(wszFile[i], name) ||
1847 !lstrcmpW(wszFile[i], name + 9) || /* Vista */
1848 !lstrcmpW(wszFile[i], name + 11), /* Win7 */
1849 "The filename should be stored in unicode at this position!\n");
1853 pILFree(pidlFile);
1856 IShellFolder_Release(psfPersonal);
1859 static void test_SHGetFolderPathA(void)
1861 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1862 BOOL is_wow64;
1863 char path[MAX_PATH];
1864 char path_x86[MAX_PATH];
1865 char path_key[MAX_PATH];
1866 HRESULT hr;
1867 HKEY key;
1869 if (!pSHGetFolderPathA)
1871 win_skip("SHGetFolderPathA not present\n");
1872 return;
1874 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1876 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1877 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1878 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1879 if (hr == E_FAIL)
1881 win_skip( "Program Files (x86) not supported\n" );
1882 return;
1884 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1885 if (is_win64)
1887 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1888 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1889 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1891 else
1893 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1894 if (is_wow64)
1895 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1896 else
1897 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1899 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1901 DWORD type, count = sizeof(path_x86);
1902 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1904 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1905 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1907 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1908 RegCloseKey( key );
1911 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1912 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1913 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1914 if (hr == E_FAIL)
1916 win_skip( "Common Files (x86) not supported\n" );
1917 return;
1919 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1920 if (is_win64)
1922 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1923 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1924 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1926 else
1928 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1929 if (is_wow64)
1930 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1931 else
1932 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1934 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1936 DWORD type, count = sizeof(path_x86);
1937 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1939 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1940 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1942 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1946 static void test_SHGetFolderPathAndSubDirA(void)
1948 HRESULT ret;
1949 BOOL delret;
1950 DWORD dwret;
1951 int i;
1952 static char wine[] = "wine";
1953 static char winetemp[] = "wine\\temp";
1954 static char appdata[MAX_PATH];
1955 static char testpath[MAX_PATH];
1956 static char toolongpath[MAX_PATH+1];
1958 if(!pSHGetFolderPathAndSubDirA)
1960 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1961 return;
1964 if(!pSHGetFolderPathA) {
1965 win_skip("SHGetFolderPathA not present!\n");
1966 return;
1968 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1970 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1971 return;
1974 sprintf(testpath, "%s\\%s", appdata, winetemp);
1975 delret = RemoveDirectoryA(testpath);
1976 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1977 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1978 return;
1981 sprintf(testpath, "%s\\%s", appdata, wine);
1982 delret = RemoveDirectoryA(testpath);
1983 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1984 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1985 return;
1988 /* test invalid second parameter */
1989 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1990 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1992 /* test fourth parameter */
1993 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1994 switch(ret) {
1995 case S_OK: /* winvista */
1996 ok(!strncmp(appdata, testpath, strlen(appdata)),
1997 "expected %s to start with %s\n", testpath, appdata);
1998 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1999 "expected %s to end with %s\n", testpath, winetemp);
2000 break;
2001 case E_INVALIDARG: /* winxp, win2k3 */
2002 break;
2003 default:
2004 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
2007 /* test fifth parameter */
2008 testpath[0] = '\0';
2009 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
2010 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2011 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2013 testpath[0] = '\0';
2014 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
2015 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2016 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2018 testpath[0] = '\0';
2019 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
2020 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2021 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2023 for(i=0; i< MAX_PATH; i++)
2024 toolongpath[i] = '0' + i % 10;
2025 toolongpath[MAX_PATH] = '\0';
2026 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2027 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2028 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2030 testpath[0] = '\0';
2031 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2032 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2034 /* test a not existing path */
2035 testpath[0] = '\0';
2036 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2037 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2038 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2040 /* create a directory inside a not existing directory */
2041 testpath[0] = '\0';
2042 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2043 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2044 ok(!strncmp(appdata, testpath, strlen(appdata)),
2045 "expected %s to start with %s\n", testpath, appdata);
2046 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2047 "expected %s to end with %s\n", testpath, winetemp);
2048 dwret = GetFileAttributes(testpath);
2049 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2051 /* cleanup */
2052 sprintf(testpath, "%s\\%s", appdata, winetemp);
2053 RemoveDirectoryA(testpath);
2054 sprintf(testpath, "%s\\%s", appdata, wine);
2055 RemoveDirectoryA(testpath);
2058 static void test_LocalizedNames(void)
2060 static char cCurrDirA[MAX_PATH];
2061 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2062 IShellFolder *IDesktopFolder, *testIShellFolder;
2063 ITEMIDLIST *newPIDL;
2064 int len;
2065 HRESULT hr;
2066 static char resourcefile[MAX_PATH];
2067 DWORD res;
2068 HANDLE file;
2069 STRRET strret;
2070 BOOL ret;
2072 static const char desktopini_contents1[] =
2073 "[.ShellClassInfo]\r\n"
2074 "LocalizedResourceName=@";
2075 static const char desktopini_contents2[] =
2076 ",-1\r\n";
2077 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2078 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2080 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2081 CreateDirectoryA(".\\testfolder", NULL);
2083 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2085 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2087 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2088 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2089 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2090 ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2091 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2092 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
2093 ok(ret, "WriteFile failed %i\n", GetLastError());
2094 CloseHandle(file);
2096 /* get IShellFolder for parent */
2097 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2098 len = lstrlenA(cCurrDirA);
2100 if (len == 0) {
2101 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2102 goto cleanup;
2104 if(cCurrDirA[len-1] == '\\')
2105 cCurrDirA[len-1] = 0;
2107 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2109 hr = SHGetDesktopFolder(&IDesktopFolder);
2110 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2112 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2113 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2115 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2116 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2118 IMalloc_Free(ppM, newPIDL);
2120 /* windows reads the display name from the resource */
2121 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2122 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2124 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2125 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2127 if (hr == S_OK && pStrRetToBufW)
2129 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2130 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2131 todo_wine
2132 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2133 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2134 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2137 /* editing name is also read from the resource */
2138 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2139 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2141 if (hr == S_OK && pStrRetToBufW)
2143 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2144 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2145 todo_wine
2146 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2147 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2148 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2151 /* parsing name is unchanged */
2152 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2153 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2155 if (hr == S_OK && pStrRetToBufW)
2157 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2158 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2159 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2162 IShellFolder_Release(IDesktopFolder);
2163 IShellFolder_Release(testIShellFolder);
2165 IMalloc_Free(ppM, newPIDL);
2167 cleanup:
2168 DeleteFileA(".\\testfolder\\desktop.ini");
2169 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2170 RemoveDirectoryA(".\\testfolder");
2173 static void test_SHCreateShellItem(void)
2175 IShellItem *shellitem, *shellitem2;
2176 IPersistIDList *persistidl;
2177 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2178 HRESULT ret;
2179 char curdirA[MAX_PATH];
2180 WCHAR curdirW[MAX_PATH];
2181 WCHAR fnbufW[MAX_PATH];
2182 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2183 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2185 GetCurrentDirectoryA(MAX_PATH, curdirA);
2187 if (!pSHCreateShellItem)
2189 win_skip("SHCreateShellItem isn't available\n");
2190 return;
2193 if (!lstrlenA(curdirA))
2195 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2196 return;
2199 if(pSHGetSpecialFolderLocation)
2201 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2202 ok(ret == S_OK, "Got 0x%08x\n", ret);
2204 else
2206 win_skip("pSHGetSpecialFolderLocation missing.\n");
2207 pidl_desktop = NULL;
2210 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2212 ret = SHGetDesktopFolder(&desktopfolder);
2213 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2215 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2216 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2218 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2219 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2221 CreateTestFile(".\\testfile");
2223 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2224 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2226 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2228 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2229 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2231 if (0) /* crashes on Windows XP */
2233 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2234 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2235 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2236 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2239 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2240 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2241 if (SUCCEEDED(ret))
2243 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2244 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2245 if (SUCCEEDED(ret))
2247 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2248 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2249 if (SUCCEEDED(ret))
2251 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2252 pILFree(pidl_test);
2254 IPersistIDList_Release(persistidl);
2256 IShellItem_Release(shellitem);
2259 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2260 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2261 if (SUCCEEDED(ret))
2263 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2264 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2265 if (SUCCEEDED(ret))
2267 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2268 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2269 if (SUCCEEDED(ret))
2271 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2272 pILFree(pidl_test);
2274 IPersistIDList_Release(persistidl);
2277 ret = IShellItem_GetParent(shellitem, &shellitem2);
2278 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2279 if (SUCCEEDED(ret))
2281 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2282 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2283 if (SUCCEEDED(ret))
2285 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2286 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2287 if (SUCCEEDED(ret))
2289 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2290 pILFree(pidl_test);
2292 IPersistIDList_Release(persistidl);
2294 IShellItem_Release(shellitem2);
2297 IShellItem_Release(shellitem);
2300 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2301 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2302 if (SUCCEEDED(ret))
2304 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2305 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2306 if (SUCCEEDED(ret))
2308 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2309 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2310 if (SUCCEEDED(ret))
2312 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2313 pILFree(pidl_test);
2315 IPersistIDList_Release(persistidl);
2317 IShellItem_Release(shellitem);
2320 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2321 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2322 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2323 if (SUCCEEDED(ret))
2325 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2326 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2327 if (SUCCEEDED(ret))
2329 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2330 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2331 if (SUCCEEDED(ret))
2333 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2334 pILFree(pidl_test);
2336 IPersistIDList_Release(persistidl);
2338 IShellItem_Release(shellitem);
2341 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2342 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2343 if (SUCCEEDED(ret))
2345 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2346 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2347 if (SUCCEEDED(ret))
2349 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2350 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2351 if (SUCCEEDED(ret))
2353 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2354 pILFree(pidl_test);
2356 IPersistIDList_Release(persistidl);
2359 IShellItem_Release(shellitem);
2362 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2363 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2364 if (SUCCEEDED(ret))
2366 ret = IShellItem_GetParent(shellitem, &shellitem2);
2367 ok(FAILED(ret), "Got 0x%08x\n", ret);
2368 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2369 IShellItem_Release(shellitem);
2372 /* SHCreateItemFromParsingName */
2373 if(pSHCreateItemFromParsingName)
2375 if(0)
2377 /* Crashes under windows 7 */
2378 pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2381 shellitem = (void*)0xdeadbeef;
2382 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2383 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2384 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2386 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2387 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2388 "SHCreateItemFromParsingName returned %x\n", ret);
2389 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2391 lstrcpyW(fnbufW, curdirW);
2392 myPathAddBackslashW(fnbufW);
2393 lstrcatW(fnbufW, testfileW);
2395 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2396 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2397 if(SUCCEEDED(ret))
2399 LPWSTR tmp_fname;
2400 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2401 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2402 if(SUCCEEDED(ret))
2404 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2405 CoTaskMemFree(tmp_fname);
2407 IShellItem_Release(shellitem);
2410 else
2411 win_skip("No SHCreateItemFromParsingName\n");
2414 /* SHCreateItemFromIDList */
2415 if(pSHCreateItemFromIDList)
2417 if(0)
2419 /* Crashes under win7 */
2420 pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2423 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2424 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2426 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2427 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2428 if (SUCCEEDED(ret))
2430 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2431 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2432 if (SUCCEEDED(ret))
2434 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2435 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2436 if (SUCCEEDED(ret))
2438 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2439 pILFree(pidl_test);
2441 IPersistIDList_Release(persistidl);
2443 IShellItem_Release(shellitem);
2446 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2447 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2448 if (SUCCEEDED(ret))
2450 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2451 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2452 if (SUCCEEDED(ret))
2454 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2455 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2456 if (SUCCEEDED(ret))
2458 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2459 pILFree(pidl_test);
2461 IPersistIDList_Release(persistidl);
2463 IShellItem_Release(shellitem);
2466 else
2467 win_skip("No SHCreateItemFromIDList\n");
2469 DeleteFileA(".\\testfile");
2470 pILFree(pidl_abstestfile);
2471 pILFree(pidl_testfile);
2472 pILFree(pidl_desktop);
2473 pILFree(pidl_cwd);
2474 IShellFolder_Release(currentfolder);
2475 IShellFolder_Release(desktopfolder);
2478 static void test_SHGetNameFromIDList(void)
2480 IShellItem *shellitem;
2481 LPITEMIDLIST pidl;
2482 LPWSTR name_string;
2483 HRESULT hres;
2484 UINT i;
2485 static const DWORD flags[] = {
2486 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2487 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2488 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2489 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2491 if(!pSHGetNameFromIDList)
2493 win_skip("SHGetNameFromIDList missing.\n");
2494 return;
2497 /* These should be available on any platform that passed the above test. */
2498 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2499 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2500 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2501 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2503 if(0)
2505 /* Crashes under win7 */
2506 pSHGetNameFromIDList(NULL, 0, NULL);
2509 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2510 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2512 /* Test the desktop */
2513 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2514 ok(hres == S_OK, "Got 0x%08x\n", hres);
2515 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2516 ok(hres == S_OK, "Got 0x%08x\n", hres);
2517 if(SUCCEEDED(hres))
2519 WCHAR *nameSI, *nameSH;
2520 WCHAR buf[MAX_PATH];
2521 HRESULT hrSI, hrSH, hrSF;
2522 STRRET strret;
2523 IShellFolder *psf;
2524 BOOL res;
2526 SHGetDesktopFolder(&psf);
2527 for(i = 0; flags[i] != -1234; i++)
2529 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2530 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2531 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2532 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2533 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2534 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2536 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2537 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2539 if(SUCCEEDED(hrSF))
2541 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2542 if(SUCCEEDED(hrSI))
2543 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2544 if(SUCCEEDED(hrSF))
2545 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2547 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2548 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2550 IShellFolder_Release(psf);
2552 if(pSHGetPathFromIDListW){
2553 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2554 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2555 res = pSHGetPathFromIDListW(pidl, buf);
2556 ok(res == TRUE, "Got %d\n", res);
2557 if(SUCCEEDED(hrSI) && res)
2558 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2559 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2560 }else
2561 win_skip("pSHGetPathFromIDListW not available\n");
2563 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2564 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2565 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2567 IShellItem_Release(shellitem);
2569 pILFree(pidl);
2571 /* Test the control panel */
2572 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2573 ok(hres == S_OK, "Got 0x%08x\n", hres);
2574 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2575 ok(hres == S_OK, "Got 0x%08x\n", hres);
2576 if(SUCCEEDED(hres))
2578 WCHAR *nameSI, *nameSH;
2579 WCHAR buf[MAX_PATH];
2580 HRESULT hrSI, hrSH, hrSF;
2581 STRRET strret;
2582 IShellFolder *psf;
2583 BOOL res;
2585 SHGetDesktopFolder(&psf);
2586 for(i = 0; flags[i] != -1234; i++)
2588 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2589 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2590 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2591 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2592 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2593 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2595 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2596 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2598 if(SUCCEEDED(hrSF))
2600 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2601 if(SUCCEEDED(hrSI))
2602 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2603 if(SUCCEEDED(hrSF))
2604 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2606 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2607 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2609 IShellFolder_Release(psf);
2611 if(pSHGetPathFromIDListW){
2612 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2613 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2614 res = pSHGetPathFromIDListW(pidl, buf);
2615 ok(res == FALSE, "Got %d\n", res);
2616 if(SUCCEEDED(hrSI) && res)
2617 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2618 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2619 }else
2620 win_skip("pSHGetPathFromIDListW not available\n");
2622 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2623 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2624 "Got 0x%08x\n", hres);
2625 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2627 IShellItem_Release(shellitem);
2629 pILFree(pidl);
2632 static void test_SHGetItemFromDataObject(void)
2634 IShellFolder *psfdesktop;
2635 IShellItem *psi;
2636 IShellView *psv;
2637 HRESULT hres;
2639 if(!pSHGetItemFromDataObject)
2641 win_skip("No SHGetItemFromDataObject.\n");
2642 return;
2645 if(0)
2647 /* Crashes under win7 */
2648 pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2651 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2652 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2654 SHGetDesktopFolder(&psfdesktop);
2656 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2657 ok(hres == S_OK, "got 0x%08x\n", hres);
2658 if(SUCCEEDED(hres))
2660 IEnumIDList *peidl;
2661 IDataObject *pdo;
2662 SHCONTF enum_flags;
2664 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2665 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2666 ok(hres == S_OK, "got 0x%08x\n", hres);
2667 if(SUCCEEDED(hres))
2669 LPITEMIDLIST apidl[5];
2670 UINT count = 0, i;
2672 for(count = 0; count < 5; count++)
2673 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2674 break;
2676 if(count)
2678 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2679 &IID_IDataObject, NULL, (void**)&pdo);
2680 ok(hres == S_OK, "got 0x%08x\n", hres);
2681 if(SUCCEEDED(hres))
2683 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2684 ok(hres == S_OK, "got 0x%08x\n", hres);
2685 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2686 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2687 ok(hres == S_OK, "got 0x%08x\n", hres);
2688 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2689 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2690 ok(hres == S_OK, "got 0x%08x\n", hres);
2691 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2692 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2693 ok(hres == S_OK, "got 0x%08x\n", hres);
2694 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2695 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2696 ok(hres == S_OK, "got 0x%08x\n", hres);
2697 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2699 IDataObject_Release(pdo);
2702 else
2703 skip("No file(s) found - skipping single-file test.\n");
2705 if(count > 1)
2707 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2708 &IID_IDataObject, NULL, (void**)&pdo);
2709 ok(hres == S_OK, "got 0x%08x\n", hres);
2710 if(SUCCEEDED(hres))
2712 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2713 ok(hres == S_OK, "got 0x%08x\n", hres);
2714 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2715 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2716 ok(hres == S_OK, "got 0x%08x\n", hres);
2717 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2718 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2719 ok(hres == S_OK, "got 0x%08x\n", hres);
2720 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2721 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2722 ok(hres == S_OK, "got 0x%08x\n", hres);
2723 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2724 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2725 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2726 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2727 IDataObject_Release(pdo);
2730 else
2731 skip("zero or one file found - skipping multi-file test.\n");
2733 for(i = 0; i < count; i++)
2734 pILFree(apidl[i]);
2736 IEnumIDList_Release(peidl);
2739 IShellView_Release(psv);
2742 IShellFolder_Release(psfdesktop);
2745 static void test_ShellItemCompare(void)
2747 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2748 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2749 IShellFolder *psf_desktop, *psf_current;
2750 LPITEMIDLIST pidl_cwd;
2751 WCHAR curdirW[MAX_PATH];
2752 BOOL failed;
2753 HRESULT hr;
2754 static const WCHAR filesW[][9] = {
2755 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2756 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2757 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2758 int order;
2759 UINT i;
2761 if(!pSHCreateShellItem)
2763 win_skip("SHCreateShellItem missing.\n");
2764 return;
2767 GetCurrentDirectoryW(MAX_PATH, curdirW);
2768 if(!lstrlenW(curdirW))
2770 skip("Failed to get current directory, skipping.\n");
2771 return;
2774 CreateDirectoryA(".\\a", NULL);
2775 CreateDirectoryA(".\\b", NULL);
2776 CreateDirectoryA(".\\c", NULL);
2777 CreateTestFile(".\\a\\a");
2778 CreateTestFile(".\\a\\b");
2779 CreateTestFile(".\\a\\c");
2780 CreateTestFile(".\\b\\a");
2781 CreateTestFile(".\\b\\b");
2782 CreateTestFile(".\\b\\c");
2783 CreateTestFile(".\\c\\a");
2784 CreateTestFile(".\\c\\b");
2785 CreateTestFile(".\\c\\c");
2787 SHGetDesktopFolder(&psf_desktop);
2788 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2789 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2790 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2791 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2792 IShellFolder_Release(psf_desktop);
2793 ILFree(pidl_cwd);
2795 /* Generate ShellItems for the files */
2796 memset(&psi, 0, sizeof(psi));
2797 failed = FALSE;
2798 for(i = 0; i < 9; i++)
2800 LPITEMIDLIST pidl_testfile = NULL;
2802 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2803 NULL, &pidl_testfile, NULL);
2804 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2805 if(SUCCEEDED(hr))
2807 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2808 ok(hr == S_OK, "Got 0x%08x\n", hr);
2809 pILFree(pidl_testfile);
2811 if(FAILED(hr)) failed = TRUE;
2813 if(failed)
2815 skip("Failed to create all shellitems.\n");
2816 goto cleanup;
2819 /* Generate ShellItems for the folders */
2820 hr = IShellItem_GetParent(psi[0], &psi_a);
2821 ok(hr == S_OK, "Got 0x%08x\n", hr);
2822 if(FAILED(hr)) failed = TRUE;
2823 hr = IShellItem_GetParent(psi[3], &psi_b);
2824 ok(hr == S_OK, "Got 0x%08x\n", hr);
2825 if(FAILED(hr)) failed = TRUE;
2826 hr = IShellItem_GetParent(psi[6], &psi_c);
2827 ok(hr == S_OK, "Got 0x%08x\n", hr);
2828 if(FAILED(hr)) failed = TRUE;
2830 if(failed)
2832 skip("Failed to create shellitems.\n");
2833 goto cleanup;
2836 if(0)
2838 /* Crashes on native (win7, winxp) */
2839 IShellItem_Compare(psi_a, NULL, 0, NULL);
2840 IShellItem_Compare(psi_a, psi_b, 0, NULL);
2841 IShellItem_Compare(psi_a, NULL, 0, &order);
2844 /* Basics */
2845 for(i = 0; i < 9; i++)
2847 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2848 ok(hr == S_OK, "Got 0x%08x\n", hr);
2849 ok(order == 0, "Got order %d\n", order);
2850 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2851 ok(hr == S_OK, "Got 0x%08x\n", hr);
2852 ok(order == 0, "Got order %d\n", order);
2853 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2854 ok(hr == S_OK, "Got 0x%08x\n", hr);
2855 ok(order == 0, "Got order %d\n", order);
2858 /* Order */
2859 /* a\b:a\a , a\b:a\c, a\b:a\b */
2860 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2861 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2862 ok(order == 1, "Got order %d\n", order);
2863 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2864 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2865 ok(order == -1, "Got order %d\n", order);
2866 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2867 ok(hr == S_OK, "Got 0x%08x\n", hr);
2868 ok(order == 0, "Got order %d\n", order);
2870 /* b\b:a\b, b\b:c\b, b\b:c\b */
2871 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2872 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2873 ok(order == 1, "Got order %d\n", order);
2874 hr = IShellItem_Compare(psi[4], psi[7], 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[4], psi[4], SICHINT_DISPLAY, &order);
2878 ok(hr == S_OK, "Got 0x%08x\n", hr);
2879 ok(order == 0, "Got order %d\n", order);
2881 /* b:a\a, b:a\c, b:a\b */
2882 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2883 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2884 todo_wine ok(order == 1, "Got order %d\n", order);
2885 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2886 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2887 todo_wine ok(order == 1, "Got order %d\n", order);
2888 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2889 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2890 todo_wine ok(order == 1, "Got order %d\n", order);
2892 /* b:c\a, b:c\c, b:c\b */
2893 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2894 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2895 ok(order == -1, "Got order %d\n", order);
2896 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &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_b, psi[7], SICHINT_DISPLAY, &order);
2900 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2901 ok(order == -1, "Got order %d\n", order);
2903 /* a\b:a\a , a\b:a\c, a\b:a\b */
2904 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2905 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2906 ok(order == 1, "Got order %d\n", order);
2907 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2908 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2909 ok(order == -1, "Got order %d\n", order);
2910 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2911 ok(hr == S_OK, "Got 0x%08x\n", hr);
2912 ok(order == 0, "Got order %d\n", order);
2914 /* b\b:a\b, b\b:c\b, b\b:c\b */
2915 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2916 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2917 ok(order == 1, "Got order %d\n", order);
2918 hr = IShellItem_Compare(psi[4], psi[7], 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[4], psi[4], SICHINT_CANONICAL, &order);
2922 ok(hr == S_OK, "Got 0x%08x\n", hr);
2923 ok(order == 0, "Got order %d\n", order);
2925 /* b:a\a, b:a\c, b:a\b */
2926 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2927 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2928 todo_wine ok(order == 1, "Got order %d\n", order);
2929 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2930 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2931 todo_wine ok(order == 1, "Got order %d\n", order);
2932 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2933 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2934 todo_wine ok(order == 1, "Got order %d\n", order);
2936 /* b:c\a, b:c\c, b:c\b */
2937 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2938 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2939 ok(order == -1, "Got order %d\n", order);
2940 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2941 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2942 ok(order == -1, "Got order %d\n", order);
2943 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2944 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2945 ok(order == -1, "Got order %d\n", order);
2947 cleanup:
2948 IShellFolder_Release(psf_current);
2950 DeleteFileA(".\\a\\a");
2951 DeleteFileA(".\\a\\b");
2952 DeleteFileA(".\\a\\c");
2953 DeleteFileA(".\\b\\a");
2954 DeleteFileA(".\\b\\b");
2955 DeleteFileA(".\\b\\c");
2956 DeleteFileA(".\\c\\a");
2957 DeleteFileA(".\\c\\b");
2958 DeleteFileA(".\\c\\c");
2959 RemoveDirectoryA(".\\a");
2960 RemoveDirectoryA(".\\b");
2961 RemoveDirectoryA(".\\c");
2963 if(psi_a) IShellItem_Release(psi_a);
2964 if(psi_b) IShellItem_Release(psi_b);
2965 if(psi_c) IShellItem_Release(psi_c);
2967 for(i = 0; i < 9; i++)
2968 if(psi[i]) IShellItem_Release(psi[i]);
2971 /**************************************************************/
2972 /* IUnknown implementation for counting QueryInterface calls. */
2973 typedef struct {
2974 IUnknown IUnknown_iface;
2975 struct if_count {
2976 REFIID id;
2977 LONG count;
2978 } *ifaces;
2979 LONG unknown;
2980 } IUnknownImpl;
2982 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
2984 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
2987 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2989 IUnknownImpl *This = impl_from_IUnknown(iunk);
2990 UINT i, found;
2991 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2993 if(IsEqualIID(This->ifaces[i].id, riid))
2995 This->ifaces[i].count++;
2996 found = 1;
2997 break;
3000 if(!found)
3001 This->unknown++;
3002 return E_NOINTERFACE;
3005 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
3007 return 2;
3010 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3012 return 1;
3015 static const IUnknownVtbl vt_IUnknown = {
3016 unk_fnQueryInterface,
3017 unk_fnAddRef,
3018 unk_fnRelease
3021 static void test_SHGetIDListFromObject(void)
3023 IUnknownImpl *punkimpl;
3024 IShellFolder *psfdesktop;
3025 IShellView *psv;
3026 LPITEMIDLIST pidl, pidl_desktop;
3027 HRESULT hres;
3028 UINT i;
3029 struct if_count ifaces[] =
3030 { {&IID_IPersistIDList, 0},
3031 {&IID_IPersistFolder2, 0},
3032 {&IID_IDataObject, 0},
3033 {&IID_IParentAndItem, 0},
3034 {&IID_IFolderView, 0},
3035 {NULL, 0} };
3037 if(!pSHGetIDListFromObject)
3039 win_skip("SHGetIDListFromObject missing.\n");
3040 return;
3043 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3045 if(0)
3047 /* Crashes native */
3048 pSHGetIDListFromObject(NULL, NULL);
3049 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3052 hres = pSHGetIDListFromObject(NULL, &pidl);
3053 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3055 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3056 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3057 punkimpl->ifaces = ifaces;
3058 punkimpl->unknown = 0;
3060 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3061 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3062 ok(ifaces[0].count, "interface not requested.\n");
3063 ok(ifaces[1].count, "interface not requested.\n");
3064 ok(ifaces[2].count, "interface not requested.\n");
3065 todo_wine
3066 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3067 "interface not requested.\n");
3068 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3069 "interface not requested.\n");
3071 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3072 HeapFree(GetProcessHeap(), 0, punkimpl);
3074 pidl_desktop = NULL;
3075 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3076 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3078 SHGetDesktopFolder(&psfdesktop);
3080 /* Test IShellItem */
3081 if(pSHCreateShellItem)
3083 IShellItem *shellitem;
3084 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3085 ok(hres == S_OK, "got 0x%08x\n", hres);
3086 if(SUCCEEDED(hres))
3088 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3089 ok(hres == S_OK, "got 0x%08x\n", hres);
3090 if(SUCCEEDED(hres))
3092 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3093 pILFree(pidl);
3095 IShellItem_Release(shellitem);
3098 else
3099 skip("no SHCreateShellItem.\n");
3101 /* Test IShellFolder */
3102 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3103 ok(hres == S_OK, "got 0x%08x\n", hres);
3104 if(SUCCEEDED(hres))
3106 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3107 pILFree(pidl);
3110 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3111 ok(hres == S_OK, "got 0x%08x\n", hres);
3112 if(SUCCEEDED(hres))
3114 IEnumIDList *peidl;
3115 IDataObject *pdo;
3116 SHCONTF enum_flags;
3118 /* Test IFolderView */
3119 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3120 ok(hres == S_OK, "got 0x%08x\n", hres);
3121 if(SUCCEEDED(hres))
3123 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3124 pILFree(pidl);
3127 /* Test IDataObject */
3128 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3129 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3130 ok(hres == S_OK, "got 0x%08x\n", hres);
3131 if(SUCCEEDED(hres))
3133 LPITEMIDLIST apidl[5];
3134 UINT count = 0;
3135 for(count = 0; count < 5; count++)
3136 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3137 break;
3139 if(count)
3141 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (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 == S_OK, "got 0x%08x\n", hres);
3149 ok(pidl != NULL, "pidl is NULL.\n");
3150 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3151 pILFree(pidl);
3153 IDataObject_Release(pdo);
3156 else
3157 skip("No files found - skipping single-file test.\n");
3159 if(count > 1)
3161 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3162 &IID_IDataObject, NULL, (void**)&pdo);
3163 ok(hres == S_OK, "got 0x%08x\n", hres);
3164 if(SUCCEEDED(hres))
3166 pidl = (void*)0xDEADBEEF;
3167 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3168 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3169 "got 0x%08x\n", hres);
3170 ok(pidl == NULL, "pidl is not NULL.\n");
3172 IDataObject_Release(pdo);
3175 else
3176 skip("zero or one file found - skipping multi-file test.\n");
3178 for(i = 0; i < count; i++)
3179 pILFree(apidl[i]);
3181 IEnumIDList_Release(peidl);
3184 IShellView_Release(psv);
3187 IShellFolder_Release(psfdesktop);
3188 pILFree(pidl_desktop);
3191 static void test_SHGetItemFromObject(void)
3193 IUnknownImpl *punkimpl;
3194 IShellFolder *psfdesktop;
3195 LPITEMIDLIST pidl;
3196 IShellItem *psi;
3197 IUnknown *punk;
3198 HRESULT hres;
3199 struct if_count ifaces[] =
3200 { {&IID_IPersistIDList, 0},
3201 {&IID_IPersistFolder2, 0},
3202 {&IID_IDataObject, 0},
3203 {&IID_IParentAndItem, 0},
3204 {&IID_IFolderView, 0},
3205 {NULL, 0} };
3207 if(!pSHGetItemFromObject)
3209 skip("No SHGetItemFromObject.\n");
3210 return;
3213 SHGetDesktopFolder(&psfdesktop);
3215 if(0)
3217 /* Crashes with Windows 7 */
3218 pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3219 pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3220 pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3223 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3224 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3226 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3227 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3228 punkimpl->ifaces = ifaces;
3229 punkimpl->unknown = 0;
3231 /* The same as SHGetIDListFromObject */
3232 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3233 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3234 ok(ifaces[0].count, "interface not requested.\n");
3235 ok(ifaces[1].count, "interface not requested.\n");
3236 ok(ifaces[2].count, "interface not requested.\n");
3237 todo_wine
3238 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3239 "interface not requested.\n");
3240 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3241 "interface not requested.\n");
3243 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3244 HeapFree(GetProcessHeap(), 0, punkimpl);
3246 /* Test IShellItem */
3247 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3248 ok(hres == S_OK, "Got 0x%08x\n", hres);
3249 if(SUCCEEDED(hres))
3251 IShellItem *psi2;
3252 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3253 ok(hres == S_OK, "Got 0x%08x\n", hres);
3254 if(SUCCEEDED(hres))
3256 todo_wine
3257 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3258 IShellItem_Release(psi2);
3260 IShellItem_Release(psi);
3263 IShellFolder_Release(psfdesktop);
3266 static void test_SHCreateShellItemArray(void)
3268 IShellFolder *pdesktopsf, *psf;
3269 IShellItemArray *psia;
3270 IEnumIDList *peidl;
3271 HRESULT hr;
3272 WCHAR cTestDirW[MAX_PATH];
3273 LPITEMIDLIST pidl_testdir, pidl;
3274 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3276 if(!pSHCreateShellItemArray) {
3277 skip("No pSHCreateShellItemArray!\n");
3278 return;
3281 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3283 if(0)
3285 /* Crashes under native */
3286 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3287 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3288 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3289 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3292 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3293 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3295 SHGetDesktopFolder(&pdesktopsf);
3296 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3297 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3299 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3300 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3302 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3303 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3304 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3305 pILFree(pidl);
3307 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3308 myPathAddBackslashW(cTestDirW);
3309 lstrcatW(cTestDirW, testdirW);
3311 CreateFilesFolders();
3313 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3314 ok(hr == S_OK, "got 0x%08x\n", hr);
3315 if(SUCCEEDED(hr))
3317 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3318 (void**)&psf);
3319 ok(hr == S_OK, "Got 0x%08x\n", hr);
3321 IShellFolder_Release(pdesktopsf);
3323 if(FAILED(hr))
3325 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3326 pILFree(pidl_testdir);
3327 Cleanup();
3328 return;
3331 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3332 ok(hr == S_OK, "Got %08x\n", hr);
3333 if(SUCCEEDED(hr))
3335 LPITEMIDLIST apidl[5];
3336 UINT done, numitems, i;
3338 for(done = 0; done < 5; done++)
3339 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3340 break;
3341 ok(done == 5, "Got %d pidls\n", done);
3342 IEnumIDList_Release(peidl);
3344 /* Create a ShellItemArray */
3345 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3346 ok(hr == S_OK, "Got 0x%08x\n", hr);
3347 if(SUCCEEDED(hr))
3349 IShellItem *psi;
3351 if(0)
3353 /* Crashes in Windows 7 */
3354 IShellItemArray_GetCount(psia, NULL);
3357 IShellItemArray_GetCount(psia, &numitems);
3358 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3360 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3361 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3363 /* Compare all the items */
3364 for(i = 0; i < numitems; i++)
3366 LPITEMIDLIST pidl_abs;
3367 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3369 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3370 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3371 if(SUCCEEDED(hr))
3373 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3374 ok(hr == S_OK, "Got 0x%08x\n", hr);
3375 if(SUCCEEDED(hr))
3377 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3378 pILFree(pidl);
3380 IShellItem_Release(psi);
3382 pILFree(pidl_abs);
3384 for(i = 0; i < done; i++)
3385 pILFree(apidl[i]);
3386 IShellItemArray_Release(psia);
3390 /* SHCreateShellItemArrayFromShellItem */
3391 if(pSHCreateShellItemArrayFromShellItem)
3393 IShellItem *psi;
3395 if(0)
3397 /* Crashes under Windows 7 */
3398 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3399 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3400 pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3403 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3404 ok(hr == S_OK, "Got 0x%08x\n", hr);
3405 if(SUCCEEDED(hr))
3407 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3408 ok(hr == S_OK, "Got 0x%08x\n", hr);
3409 if(SUCCEEDED(hr))
3411 IShellItem *psi2;
3412 UINT count;
3413 hr = IShellItemArray_GetCount(psia, &count);
3414 ok(hr == S_OK, "Got 0x%08x\n", hr);
3415 ok(count == 1, "Got count %d\n", count);
3416 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3417 ok(hr == S_OK, "Got 0x%08x\n", hr);
3418 todo_wine
3419 ok(psi != psi2, "ShellItems are of the same instance.\n");
3420 if(SUCCEEDED(hr))
3422 LPITEMIDLIST pidl1, pidl2;
3423 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3424 ok(hr == S_OK, "Got 0x%08x\n", hr);
3425 ok(pidl1 != NULL, "pidl1 was null.\n");
3426 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3427 ok(hr == S_OK, "Got 0x%08x\n", hr);
3428 ok(pidl2 != NULL, "pidl2 was null.\n");
3429 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3430 pILFree(pidl1);
3431 pILFree(pidl2);
3432 IShellItem_Release(psi2);
3434 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3435 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3436 IShellItemArray_Release(psia);
3438 IShellItem_Release(psi);
3441 else
3442 skip("No SHCreateShellItemArrayFromShellItem.\n");
3444 if(pSHCreateShellItemArrayFromDataObject)
3446 IShellView *psv;
3448 if(0)
3450 /* Crashes under Windows 7 */
3451 pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3453 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3454 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3456 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3457 ok(hr == S_OK, "got 0x%08x\n", hr);
3458 if(SUCCEEDED(hr))
3460 IEnumIDList *peidl;
3461 IDataObject *pdo;
3462 SHCONTF enum_flags;
3464 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3465 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3466 ok(hr == S_OK, "got 0x%08x\n", hr);
3467 if(SUCCEEDED(hr))
3469 LPITEMIDLIST apidl[5];
3470 UINT count, i;
3472 for(count = 0; count < 5; count++)
3473 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3474 break;
3475 ok(count == 5, "Got %d\n", count);
3477 if(count)
3479 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3480 &IID_IDataObject, NULL, (void**)&pdo);
3481 ok(hr == S_OK, "Got 0x%08x\n", hr);
3482 if(SUCCEEDED(hr))
3484 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3485 (void**)&psia);
3486 ok(hr == S_OK, "Got 0x%08x\n", hr);
3487 if(SUCCEEDED(hr))
3489 UINT count_sia, i;
3490 hr = IShellItemArray_GetCount(psia, &count_sia);
3491 ok(hr == S_OK, "Got 0x%08x\n", hr);
3492 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3493 for(i = 0; i < count_sia; i++)
3495 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3496 IShellItem *psi;
3497 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3498 ok(hr == S_OK, "Got 0x%08x\n", hr);
3499 if(SUCCEEDED(hr))
3501 LPITEMIDLIST pidl;
3502 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3503 ok(hr == S_OK, "Got 0x%08x\n", hr);
3504 ok(pidl != NULL, "pidl as NULL.\n");
3505 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3506 pILFree(pidl);
3507 IShellItem_Release(psi);
3509 pILFree(pidl_abs);
3512 IShellItemArray_Release(psia);
3515 IDataObject_Release(pdo);
3517 for(i = 0; i < count; i++)
3518 pILFree(apidl[i]);
3520 else
3521 skip("No files found - skipping test.\n");
3523 IEnumIDList_Release(peidl);
3525 IShellView_Release(psv);
3528 else
3529 skip("No SHCreateShellItemArrayFromDataObject.\n");
3531 IShellFolder_Release(psf);
3532 pILFree(pidl_testdir);
3533 Cleanup();
3536 static void test_ShellItemBindToHandler(void)
3538 IShellItem *psi;
3539 LPITEMIDLIST pidl_desktop;
3540 HRESULT hr;
3542 if(!pSHCreateShellItem)
3544 skip("SHCreateShellItem missing.\n");
3545 return;
3548 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3549 ok(hr == S_OK, "Got 0x%08x\n", hr);
3550 if(SUCCEEDED(hr))
3552 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3553 ok(hr == S_OK, "Got 0x%08x\n", hr);
3555 if(SUCCEEDED(hr))
3557 IPersistFolder2 *ppf2;
3558 IUnknown *punk;
3560 if(0)
3562 /* Crashes under Windows 7 */
3563 IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3564 IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3566 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3567 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3569 /* BHID_SFObject */
3570 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3571 ok(hr == S_OK, "Got 0x%08x\n", hr);
3572 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3573 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3574 ok(hr == S_OK, "Got 0x%08x\n", hr);
3575 if(SUCCEEDED(hr))
3577 LPITEMIDLIST pidl_tmp;
3578 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3579 ok(hr == S_OK, "Got 0x%08x\n", hr);
3580 if(SUCCEEDED(hr))
3582 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3583 pILFree(pidl_tmp);
3585 IPersistFolder2_Release(ppf2);
3588 /* BHID_SFUIObject */
3589 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3590 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3591 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3592 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3593 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3594 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3596 /* BHID_DataObject */
3597 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3598 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3599 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3601 todo_wine
3603 /* BHID_SFViewObject */
3604 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3605 ok(hr == S_OK, "Got 0x%08x\n", hr);
3606 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3607 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3608 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3609 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3611 /* BHID_Storage */
3612 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3613 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3614 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3615 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3616 ok(hr == S_OK, "Got 0x%08x\n", hr);
3617 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3619 /* BHID_Stream */
3620 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3621 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3622 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3623 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3624 ok(hr == S_OK, "Got 0x%08x\n", hr);
3625 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3627 /* BHID_StorageEnum */
3628 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3629 ok(hr == S_OK, "Got 0x%08x\n", hr);
3630 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3632 /* BHID_Transfer */
3633 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3634 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3635 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3637 /* BHID_EnumItems */
3638 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3639 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3640 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3642 /* BHID_Filter */
3643 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3644 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3645 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3647 /* BHID_LinkTargetItem */
3648 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3649 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3650 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3651 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3652 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3653 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3655 /* BHID_PropertyStore */
3656 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3657 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3658 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3659 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3660 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3661 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3663 /* BHID_ThumbnailHandler */
3664 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3665 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3666 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3668 /* BHID_AssociationArray */
3669 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3670 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3671 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3673 /* BHID_EnumAssocHandlers */
3674 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3675 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3676 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3679 IShellItem_Release(psi);
3681 else
3682 skip("Failed to create ShellItem.\n");
3684 pILFree(pidl_desktop);
3687 static void test_ShellItemGetAttributes(void)
3689 IShellItem *psi;
3690 LPITEMIDLIST pidl_desktop;
3691 SFGAOF sfgao;
3692 HRESULT hr;
3694 if(!pSHCreateShellItem)
3696 skip("SHCreateShellItem missing.\n");
3697 return;
3700 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3701 ok(hr == S_OK, "Got 0x%08x\n", hr);
3702 if(SUCCEEDED(hr))
3704 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3705 ok(hr == S_OK, "Got 0x%08x\n", hr);
3706 pILFree(pidl_desktop);
3708 if(FAILED(hr))
3710 skip("Skipping tests.\n");
3711 return;
3714 if(0)
3716 /* Crashes on native (Win 7) */
3717 IShellItem_GetAttributes(psi, 0, NULL);
3720 /* Test GetAttributes on the desktop folder. */
3721 sfgao = 0xdeadbeef;
3722 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
3723 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
3724 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
3726 IShellItem_Release(psi);
3729 static void test_SHParseDisplayName(void)
3731 LPITEMIDLIST pidl1, pidl2;
3732 IShellFolder *desktop;
3733 WCHAR dirW[MAX_PATH];
3734 WCHAR nameW[10];
3735 HRESULT hr;
3736 BOOL ret, is_wow64;
3738 if (!pSHParseDisplayName)
3740 win_skip("SHParseDisplayName isn't available\n");
3741 return;
3744 if (0)
3746 /* crashes on native */
3747 pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3748 nameW[0] = 0;
3749 pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3752 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3753 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3754 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3755 hr == E_INVALIDARG, "failed %08x\n", hr);
3756 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3758 /* dummy name */
3759 nameW[0] = 0;
3760 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3761 ok(hr == S_OK, "failed %08x\n", hr);
3762 hr = SHGetDesktopFolder(&desktop);
3763 ok(hr == S_OK, "failed %08x\n", hr);
3764 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3765 ok(hr == S_OK, "failed %08x\n", hr);
3766 ret = pILIsEqual(pidl1, pidl2);
3767 ok(ret == TRUE, "expected equal idls\n");
3768 pILFree(pidl1);
3769 pILFree(pidl2);
3771 /* with path */
3772 GetWindowsDirectoryW( dirW, MAX_PATH );
3774 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3775 ok(hr == S_OK, "failed %08x\n", hr);
3776 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3777 ok(hr == S_OK, "failed %08x\n", hr);
3779 ret = pILIsEqual(pidl1, pidl2);
3780 ok(ret == TRUE, "expected equal idls\n");
3781 pILFree(pidl1);
3782 pILFree(pidl2);
3784 /* system32 is not redirected to syswow64 on WOW64 */
3785 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
3786 if (is_wow64 && pGetSystemWow64DirectoryW)
3788 UINT len;
3789 *dirW = 0;
3790 len = GetSystemDirectoryW(dirW, MAX_PATH);
3791 ok(len > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
3792 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3793 ok(hr == S_OK, "failed %08x\n", hr);
3794 *dirW = 0;
3795 len = pGetSystemWow64DirectoryW(dirW, MAX_PATH);
3796 ok(len > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
3797 hr = pSHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
3798 ok(hr == S_OK, "failed %08x\n", hr);
3799 ret = pILIsEqual(pidl1, pidl2);
3800 ok(ret == FALSE, "expected different idls\n");
3801 pILFree(pidl1);
3802 pILFree(pidl2);
3805 IShellFolder_Release(desktop);
3808 static void test_desktop_IPersist(void)
3810 IShellFolder *desktop;
3811 IPersist *persist;
3812 IPersistFolder2 *ppf2;
3813 CLSID clsid;
3814 HRESULT hr;
3816 hr = SHGetDesktopFolder(&desktop);
3817 ok(hr == S_OK, "failed %08x\n", hr);
3819 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3820 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3822 if (hr == S_OK)
3824 if (0)
3826 /* crashes on native */
3827 IPersist_GetClassID(persist, NULL);
3829 memset(&clsid, 0, sizeof(clsid));
3830 hr = IPersist_GetClassID(persist, &clsid);
3831 ok(hr == S_OK, "failed %08x\n", hr);
3832 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3833 IPersist_Release(persist);
3836 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3837 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3838 if(SUCCEEDED(hr))
3840 IPersistFolder *ppf;
3841 LPITEMIDLIST pidl;
3842 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3843 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3844 if(SUCCEEDED(hr))
3845 IPersistFolder_Release(ppf);
3847 todo_wine {
3848 hr = IPersistFolder2_Initialize(ppf2, NULL);
3849 ok(hr == S_OK, "got %08x\n", hr);
3852 pidl = NULL;
3853 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3854 ok(hr == S_OK, "got %08x\n", hr);
3855 ok(pidl != NULL, "pidl was NULL.\n");
3856 if(SUCCEEDED(hr)) pILFree(pidl);
3858 IPersistFolder2_Release(ppf2);
3861 IShellFolder_Release(desktop);
3864 static void test_GetUIObject(void)
3866 IShellFolder *psf_desktop;
3867 IContextMenu *pcm;
3868 LPITEMIDLIST pidl;
3869 HRESULT hr;
3870 WCHAR path[MAX_PATH];
3871 const WCHAR filename[] =
3872 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3874 if(!pSHBindToParent)
3876 win_skip("SHBindToParent missing.\n");
3877 return;
3880 GetCurrentDirectoryW(MAX_PATH, path);
3881 if(!lstrlenW(path))
3883 skip("GetCurrentDirectoryW returned an empty string.\n");
3884 return;
3886 lstrcatW(path, filename);
3887 SHGetDesktopFolder(&psf_desktop);
3889 CreateFilesFolders();
3891 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3892 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3893 if(SUCCEEDED(hr))
3895 IShellFolder *psf;
3896 LPCITEMIDLIST pidl_child;
3897 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3898 ok(hr == S_OK, "Got 0x%08x\n", hr);
3899 if(SUCCEEDED(hr))
3901 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, &pidl_child, &IID_IContextMenu, NULL,
3902 (void**)&pcm);
3903 ok(hr == S_OK, "Got 0x%08x\n", hr);
3904 if(SUCCEEDED(hr))
3906 HMENU hmenu = CreatePopupMenu();
3907 INT max_id, max_id_check;
3908 UINT count, i;
3909 const int id_upper_limit = 32767;
3910 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3911 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3912 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3913 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3914 count = GetMenuItemCount(hmenu);
3915 ok(count, "Got %d\n", count);
3917 max_id_check = 0;
3918 for(i = 0; i < count; i++)
3920 MENUITEMINFOA mii;
3921 INT res;
3922 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3923 mii.cbSize = sizeof(MENUITEMINFOA);
3924 mii.fMask = MIIM_ID | MIIM_FTYPE;
3926 SetLastError(0);
3927 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3928 ok(res, "Failed (last error: %d).\n", GetLastError());
3930 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3931 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3932 if(!(mii.fType & MFT_SEPARATOR))
3933 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3935 ok((max_id_check == max_id) ||
3936 (max_id_check == max_id-1 /* Win 7 */),
3937 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3939 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3941 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3943 CMINVOKECOMMANDINFO cmi;
3944 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3945 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3947 /* Attempt to execute a nonexistent command */
3948 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3949 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3950 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3952 cmi.lpVerb = "foobar_wine_test";
3953 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3954 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3955 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3956 "Got 0x%08x\n", hr);
3958 #undef is_win2k
3960 DestroyMenu(hmenu);
3961 IContextMenu_Release(pcm);
3963 IShellFolder_Release(psf);
3965 if(pILFree) pILFree(pidl);
3968 IShellFolder_Release(psf_desktop);
3969 Cleanup();
3972 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3973 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3975 LPCITEMIDLIST child;
3976 IShellFolder *parent;
3977 STRRET filename;
3978 HRESULT hr;
3980 if(!pSHBindToParent){
3981 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3982 if(path)
3983 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3984 else
3985 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3986 return;
3989 if(path){
3990 if(!pidl){
3991 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3992 return;
3995 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3996 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3997 if(FAILED(hr))
3998 return;
4000 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
4001 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
4002 if(FAILED(hr)){
4003 IShellFolder_Release(parent);
4004 return;
4007 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
4008 "Got unexpected string type: %d\n", filename.uType);
4009 if(filename.uType == STRRET_WSTR){
4010 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
4011 "didn't get expected path (%s), instead: %s\n",
4012 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
4013 SHFree(U(filename).pOleStr);
4014 }else if(filename.uType == STRRET_CSTR){
4015 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
4016 "didn't get expected path (%s), instead: %s\n",
4017 wine_dbgstr_w(path), U(filename).cStr);
4020 IShellFolder_Release(parent);
4021 }else
4022 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4025 static void test_SHSimpleIDListFromPath(void)
4027 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4028 const CHAR adirA[] = "C:\\sidlfpdir";
4029 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4031 LPITEMIDLIST pidl = NULL;
4033 if(!pSHSimpleIDListFromPathAW){
4034 win_skip("SHSimpleIDListFromPathAW not available\n");
4035 return;
4038 br = CreateDirectoryA(adirA, NULL);
4039 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4041 if(is_unicode)
4042 pidl = pSHSimpleIDListFromPathAW(adirW);
4043 else
4044 pidl = pSHSimpleIDListFromPathAW(adirA);
4045 verify_pidl(pidl, adirW);
4046 pILFree(pidl);
4048 br = RemoveDirectoryA(adirA);
4049 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4051 if(is_unicode)
4052 pidl = pSHSimpleIDListFromPathAW(adirW);
4053 else
4054 pidl = pSHSimpleIDListFromPathAW(adirA);
4055 verify_pidl(pidl, adirW);
4056 pILFree(pidl);
4059 /* IFileSystemBindData impl */
4060 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4061 REFIID riid, void **ppv)
4063 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4064 IsEqualIID(riid, &IID_IUnknown)){
4065 *ppv = fsbd;
4066 return S_OK;
4068 return E_NOINTERFACE;
4071 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4073 return 2;
4076 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4078 return 1;
4081 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4082 const WIN32_FIND_DATAW *pfd)
4084 ok(0, "SetFindData called\n");
4085 return E_NOTIMPL;
4088 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4089 WIN32_FIND_DATAW *pfd)
4091 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4092 return S_OK;
4095 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4096 WIN32_FIND_DATAW *pfd)
4098 memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4099 return S_OK;
4102 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4103 WIN32_FIND_DATAW *pfd)
4105 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4106 *pfd->cFileName = 'a';
4107 *pfd->cAlternateFileName = 'a';
4108 return S_OK;
4111 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4112 WIN32_FIND_DATAW *pfd)
4114 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4115 HANDLE handle = FindFirstFileW(adirW, pfd);
4116 FindClose(handle);
4117 return S_OK;
4120 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4121 WIN32_FIND_DATAW *pfd)
4123 return E_FAIL;
4126 static IFileSystemBindDataVtbl fsbdVtbl = {
4127 fsbd_QueryInterface,
4128 fsbd_AddRef,
4129 fsbd_Release,
4130 fsbd_SetFindData,
4131 NULL
4134 static IFileSystemBindData fsbd = { &fsbdVtbl };
4136 static void test_ParseDisplayNamePBC(void)
4138 WCHAR wFileSystemBindData[] =
4139 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4140 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4141 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4142 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4143 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4145 IShellFolder *psf;
4146 IBindCtx *pbc;
4147 HRESULT hres;
4148 ITEMIDLIST *pidl;
4150 /* Check if we support WCHAR functions */
4151 SetLastError(0xdeadbeef);
4152 lstrcmpiW(adirW, adirW);
4153 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4154 win_skip("Most W-calls are not implemented\n");
4155 return;
4158 hres = SHGetDesktopFolder(&psf);
4159 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4160 if(FAILED(hres)){
4161 win_skip("Failed to get IShellFolder, can't run tests\n");
4162 return;
4165 /* fails on unknown dir with no IBindCtx */
4166 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4167 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4168 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4169 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4170 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4171 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4172 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4173 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4174 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4176 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4177 hres = CreateBindCtx(0, &pbc);
4178 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4180 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4181 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4182 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4183 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4184 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4185 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4186 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4187 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4188 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4190 /* unknown dir with IBindCtx with IFileSystemBindData */
4191 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4192 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4194 /* return E_FAIL from GetFindData */
4195 pidl = (ITEMIDLIST*)0xdeadbeef;
4196 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4197 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4198 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4199 "ParseDisplayName failed: 0x%08x\n", hres);
4200 if(SUCCEEDED(hres)){
4201 verify_pidl(pidl, adirW);
4202 ILFree(pidl);
4205 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4206 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4207 "ParseDisplayName failed: 0x%08x\n", hres);
4208 if(SUCCEEDED(hres)){
4209 verify_pidl(pidl, afileW);
4210 ILFree(pidl);
4213 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4214 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4215 "ParseDisplayName failed: 0x%08x\n", hres);
4216 if(SUCCEEDED(hres)){
4217 verify_pidl(pidl, afile2W);
4218 ILFree(pidl);
4221 /* set FIND_DATA struct to NULLs */
4222 pidl = (ITEMIDLIST*)0xdeadbeef;
4223 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4224 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4225 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4226 "ParseDisplayName failed: 0x%08x\n", hres);
4227 if(SUCCEEDED(hres)){
4228 verify_pidl(pidl, adirW);
4229 ILFree(pidl);
4232 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4233 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4234 "ParseDisplayName failed: 0x%08x\n", hres);
4235 if(SUCCEEDED(hres)){
4236 verify_pidl(pidl, afileW);
4237 ILFree(pidl);
4240 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4241 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4242 "ParseDisplayName failed: 0x%08x\n", hres);
4243 if(SUCCEEDED(hres)){
4244 verify_pidl(pidl, afile2W);
4245 ILFree(pidl);
4248 /* set FIND_DATA struct to junk */
4249 pidl = (ITEMIDLIST*)0xdeadbeef;
4250 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4251 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4252 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4253 "ParseDisplayName failed: 0x%08x\n", hres);
4254 if(SUCCEEDED(hres)){
4255 verify_pidl(pidl, adirW);
4256 ILFree(pidl);
4259 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4260 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4261 "ParseDisplayName failed: 0x%08x\n", hres);
4262 if(SUCCEEDED(hres)){
4263 verify_pidl(pidl, afileW);
4264 ILFree(pidl);
4267 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4268 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4269 "ParseDisplayName failed: 0x%08x\n", hres);
4270 if(SUCCEEDED(hres)){
4271 verify_pidl(pidl, afile2W);
4272 ILFree(pidl);
4275 /* set FIND_DATA struct to invalid data */
4276 pidl = (ITEMIDLIST*)0xdeadbeef;
4277 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4278 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4279 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4280 "ParseDisplayName failed: 0x%08x\n", hres);
4281 if(SUCCEEDED(hres)){
4282 verify_pidl(pidl, adirW);
4283 ILFree(pidl);
4286 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4287 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4288 "ParseDisplayName failed: 0x%08x\n", hres);
4289 if(SUCCEEDED(hres)){
4290 verify_pidl(pidl, afileW);
4291 ILFree(pidl);
4294 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4295 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4296 "ParseDisplayName failed: 0x%08x\n", hres);
4297 if(SUCCEEDED(hres)){
4298 verify_pidl(pidl, afile2W);
4299 ILFree(pidl);
4302 /* set FIND_DATA struct to valid data */
4303 pidl = (ITEMIDLIST*)0xdeadbeef;
4304 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4305 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4306 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4307 "ParseDisplayName failed: 0x%08x\n", hres);
4308 if(SUCCEEDED(hres)){
4309 verify_pidl(pidl, adirW);
4310 ILFree(pidl);
4313 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4314 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4315 "ParseDisplayName failed: 0x%08x\n", hres);
4316 if(SUCCEEDED(hres)){
4317 verify_pidl(pidl, afileW);
4318 ILFree(pidl);
4321 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4322 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4323 "ParseDisplayName failed: 0x%08x\n", hres);
4324 if(SUCCEEDED(hres)){
4325 verify_pidl(pidl, afile2W);
4326 ILFree(pidl);
4329 IBindCtx_Release(pbc);
4330 IShellFolder_Release(psf);
4333 static const CHAR testwindow_class[] = "testwindow";
4334 #define WM_USER_NOTIFY (WM_APP+1)
4336 struct ChNotifyTest {
4337 const char id[256];
4338 const UINT notify_count;
4339 UINT missing_events;
4340 UINT signal;
4341 const char path_1[256];
4342 const char path_2[256];
4343 } chnotify_tests[] = {
4344 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4345 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4346 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4349 struct ChNotifyTest *exp_data;
4350 BOOL test_new_delivery_flag;
4352 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4354 LONG signal = (LONG)lparam;
4356 switch(msg){
4357 case WM_USER_NOTIFY:
4358 if(exp_data->missing_events > 0) {
4359 WCHAR *path1, *path2;
4360 LPITEMIDLIST *pidls = (LPITEMIDLIST*)wparam;
4361 HANDLE hLock = NULL;
4363 if(test_new_delivery_flag) {
4364 hLock = SHChangeNotification_Lock((HANDLE)wparam, lparam, &pidls, &signal);
4365 ok(hLock != NULL, "SHChangeNotification_Lock returned NULL\n");
4368 ok(exp_data->signal == signal,
4369 "%s: expected notification type %x, got: %x\n",
4370 exp_data->id, exp_data->signal, signal);
4372 trace("verifying pidls for: %s\n", exp_data->id);
4373 path1 = make_wstr(exp_data->path_1);
4374 path2 = make_wstr(exp_data->path_2);
4375 verify_pidl(pidls[0], path1);
4376 verify_pidl(pidls[1], path2);
4377 HeapFree(GetProcessHeap(), 0, path1);
4378 HeapFree(GetProcessHeap(), 0, path2);
4380 exp_data->missing_events--;
4382 if(test_new_delivery_flag)
4383 SHChangeNotification_Unlock(hLock);
4384 }else
4385 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4386 return 0;
4388 return DefWindowProc(hwnd, msg, wparam, lparam);
4391 static void register_testwindow_class(void)
4393 WNDCLASSEXA cls;
4394 ATOM ret;
4396 ZeroMemory(&cls, sizeof(cls));
4397 cls.cbSize = sizeof(cls);
4398 cls.style = 0;
4399 cls.lpfnWndProc = testwindow_wndproc;
4400 cls.hInstance = GetModuleHandleA(NULL);
4401 cls.lpszClassName = testwindow_class;
4403 SetLastError(0);
4404 ret = RegisterClassExA(&cls);
4405 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4408 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4409 * have to poll repeatedly for the message to appear */
4410 static void do_events(void)
4412 int c = 0;
4413 while (exp_data->missing_events && (c++ < 10)){
4414 MSG msg;
4415 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4416 TranslateMessage(&msg);
4417 DispatchMessageA(&msg);
4419 if(exp_data->missing_events)
4420 Sleep(500);
4422 trace("%s: took %d tries\n", exp_data->id, c);
4425 static void test_SHChangeNotify(BOOL test_new_delivery)
4427 HWND wnd;
4428 ULONG notifyID, i;
4429 HRESULT hr;
4430 BOOL br, has_unicode;
4431 SHChangeNotifyEntry entries[1];
4432 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4433 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4435 trace("SHChangeNotify tests (%x)\n", test_new_delivery);
4437 CreateDirectoryW(NULL, NULL);
4438 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4440 test_new_delivery_flag = test_new_delivery;
4441 if(!test_new_delivery)
4442 register_testwindow_class();
4444 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4445 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4446 NULL, NULL, GetModuleHandleA(NULL), 0);
4447 ok(wnd != NULL, "Failed to make a window\n");
4449 br = CreateDirectoryA(root_dirA, NULL);
4450 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4452 entries[0].pidl = NULL;
4453 if(has_unicode)
4454 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4455 else
4456 hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4457 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4458 entries[0].fRecursive = TRUE;
4460 notifyID = SHChangeNotifyRegister(wnd, !test_new_delivery ? SHCNRF_ShellLevel : SHCNRF_ShellLevel|SHCNRF_NewDelivery,
4461 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4462 ok(notifyID != 0, "Failed to register a window for change notifications\n");
4464 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
4465 exp_data = chnotify_tests + i;
4467 exp_data->missing_events = exp_data->notify_count;
4468 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4469 strlen(exp_data->path_1) > 0 ? exp_data->path_1 : NULL,
4470 strlen(exp_data->path_2) > 0 ? exp_data->path_2 : NULL);
4471 do_events();
4472 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4474 if(has_unicode){
4475 WCHAR *path1, *path2;
4477 path1 = make_wstr(exp_data->path_1);
4478 path2 = make_wstr(exp_data->path_2);
4480 exp_data->missing_events = exp_data->notify_count;
4481 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
4482 do_events();
4483 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4485 HeapFree(GetProcessHeap(), 0, path1);
4486 HeapFree(GetProcessHeap(), 0, path2);
4490 SHChangeNotifyDeregister(notifyID);
4491 DestroyWindow(wnd);
4493 ILFree((LPITEMIDLIST)entries[0].pidl);
4494 br = RemoveDirectoryA(root_dirA);
4495 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4498 static void test_SHCreateDefaultContextMenu(void)
4500 HKEY keys[16];
4501 WCHAR path[MAX_PATH];
4502 IShellFolder *desktop,*folder;
4503 IPersistFolder2 *persist;
4504 IContextMenu *cmenu;
4505 LONG status;
4506 LPITEMIDLIST pidlFolder, pidl_child, pidl;
4507 DEFCONTEXTMENU cminfo;
4508 HRESULT hr;
4509 UINT i;
4510 const WCHAR filename[] =
4511 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4512 if(!pSHCreateDefaultContextMenu)
4514 win_skip("SHCreateDefaultContextMenu missing.\n");
4515 return;
4518 if(!pSHBindToParent)
4520 skip("SHBindToParent missing.\n");
4521 return;
4524 GetCurrentDirectoryW(MAX_PATH, path);
4525 if(!lstrlenW(path))
4527 skip("GetCurrentDirectoryW returned an empty string.\n");
4528 return;
4530 lstrcatW(path, filename);
4531 SHGetDesktopFolder(&desktop);
4533 CreateFilesFolders();
4535 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &pidl, 0);
4536 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
4537 if(SUCCEEDED(hr))
4540 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&folder, (LPCITEMIDLIST*)&pidl_child);
4541 ok(hr == S_OK, "Got 0x%08x\n", hr);
4543 IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
4544 IPersistFolder2_GetCurFolder(persist,&pidlFolder);
4545 IPersistFolder2_Release(persist);
4546 if(SUCCEEDED(hr))
4549 cminfo.hwnd=NULL;
4550 cminfo.pcmcb=NULL;
4551 cminfo.psf=folder;
4552 cminfo.pidlFolder=NULL;
4553 cminfo.apidl=(LPCITEMIDLIST*)&pidl_child;
4554 cminfo.cidl=1;
4555 cminfo.aKeys=NULL;
4556 cminfo.cKeys=0;
4557 cminfo.punkAssociationInfo=NULL;
4558 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
4559 ok(hr==S_OK,"Got 0x%08x\n", hr);
4560 IContextMenu_Release(cmenu);
4561 cminfo.pidlFolder=pidlFolder;
4562 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
4563 ok(hr==S_OK,"Got 0x%08x\n", hr);
4564 IContextMenu_Release(cmenu);
4565 status = RegOpenKeyExA(HKEY_CLASSES_ROOT,"*",0,KEY_READ,keys);
4566 if(status==ERROR_SUCCESS){
4567 for(i=1;i<16;i++)
4568 keys[i]=keys[0];
4569 cminfo.aKeys=keys;
4570 cminfo.cKeys=16;
4571 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
4572 RegCloseKey(keys[0]);
4573 ok(hr==S_OK,"Got 0x%08x\n", hr);
4574 IContextMenu_Release(cmenu);
4577 ILFree(pidlFolder);
4578 IShellFolder_Release(folder);
4580 IShellFolder_Release(desktop);
4581 ILFree(pidl);
4582 Cleanup();
4585 START_TEST(shlfolder)
4587 init_function_pointers();
4588 /* if OleInitialize doesn't get called, ParseDisplayName returns
4589 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4590 OleInitialize(NULL);
4592 test_ParseDisplayName();
4593 test_SHParseDisplayName();
4594 test_BindToObject();
4595 test_EnumObjects_and_CompareIDs();
4596 test_GetDisplayName();
4597 test_GetAttributesOf();
4598 test_SHGetPathFromIDList();
4599 test_CallForAttributes();
4600 test_FolderShortcut();
4601 test_ITEMIDLIST_format();
4602 test_SHGetFolderPathA();
4603 test_SHGetFolderPathAndSubDirA();
4604 test_LocalizedNames();
4605 test_SHCreateShellItem();
4606 test_SHCreateShellItemArray();
4607 test_desktop_IPersist();
4608 test_GetUIObject();
4609 test_SHSimpleIDListFromPath();
4610 test_ParseDisplayNamePBC();
4611 test_SHGetNameFromIDList();
4612 test_SHGetItemFromDataObject();
4613 test_SHGetIDListFromObject();
4614 test_SHGetItemFromObject();
4615 test_ShellItemCompare();
4616 test_SHChangeNotify(FALSE);
4617 test_SHChangeNotify(TRUE);
4618 test_ShellItemBindToHandler();
4619 test_ShellItemGetAttributes();
4620 test_SHCreateDefaultContextMenu();
4622 OleUninitialize();