quartz: Free two assert calls from having side effects.
[wine/testsucceed.git] / dlls / shell32 / tests / shlfolder.c
blobc61a9723904144cdedb9ca083338911ce3cd2ffe
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);
1810 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1811 "FileStructW's offset and length should add up to the PIDL's length!\n");
1813 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1814 /* Since we just created the file, time of creation,
1815 * time of last access and time of last write access just be the same.
1816 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1817 * after the first run. I do remember something with NTFS keeping the creation time
1818 * if a file is deleted and then created again within a couple of seconds or so.
1819 * Might be the reason. */
1820 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1821 pFileStructA->uFileTime == pFileStructW->uTime,
1822 "Last write time should match creation time!\n");
1824 /* On FAT filesystems the last access time is midnight
1825 local time, so the values of uDate2 and uTime2 will
1826 depend on the local timezone. If the times are exactly
1827 equal then the dates should be identical for both FAT
1828 and NTFS as no timezone is more than 1 day away from UTC.
1830 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1832 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1833 "Last write date and time should match last access date and time!\n");
1835 else
1837 /* Filesystem may be FAT. Check date within 1 day
1838 and seconds are zero. */
1839 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1840 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1841 "Last access time on FAT filesystems should have zero seconds.\n");
1842 /* TODO: Perform check for date being within one day.*/
1845 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1846 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1847 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1848 "The filename should be stored in unicode at this position!\n");
1852 pILFree(pidlFile);
1855 IShellFolder_Release(psfPersonal);
1858 static void test_SHGetFolderPathA(void)
1860 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1861 BOOL is_wow64;
1862 char path[MAX_PATH];
1863 char path_x86[MAX_PATH];
1864 char path_key[MAX_PATH];
1865 HRESULT hr;
1866 HKEY key;
1868 if (!pSHGetFolderPathA)
1870 win_skip("SHGetFolderPathA not present\n");
1871 return;
1873 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1875 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1876 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1877 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1878 if (hr == E_FAIL)
1880 win_skip( "Program Files (x86) not supported\n" );
1881 return;
1883 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1884 if (is_win64)
1886 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1887 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1888 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1890 else
1892 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1893 if (is_wow64)
1894 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1895 else
1896 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1898 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1900 DWORD type, count = sizeof(path_x86);
1901 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1903 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1904 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1906 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1907 RegCloseKey( key );
1910 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1911 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1912 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1913 if (hr == E_FAIL)
1915 win_skip( "Common Files (x86) not supported\n" );
1916 return;
1918 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1919 if (is_win64)
1921 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1922 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1923 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1925 else
1927 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1928 if (is_wow64)
1929 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1930 else
1931 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1933 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1935 DWORD type, count = sizeof(path_x86);
1936 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1938 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1939 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1941 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1945 static void test_SHGetFolderPathAndSubDirA(void)
1947 HRESULT ret;
1948 BOOL delret;
1949 DWORD dwret;
1950 int i;
1951 static char wine[] = "wine";
1952 static char winetemp[] = "wine\\temp";
1953 static char appdata[MAX_PATH];
1954 static char testpath[MAX_PATH];
1955 static char toolongpath[MAX_PATH+1];
1957 if(!pSHGetFolderPathAndSubDirA)
1959 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1960 return;
1963 if(!pSHGetFolderPathA) {
1964 win_skip("SHGetFolderPathA not present!\n");
1965 return;
1967 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1969 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1970 return;
1973 sprintf(testpath, "%s\\%s", appdata, winetemp);
1974 delret = RemoveDirectoryA(testpath);
1975 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1976 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1977 return;
1980 sprintf(testpath, "%s\\%s", appdata, wine);
1981 delret = RemoveDirectoryA(testpath);
1982 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1983 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1984 return;
1987 /* test invalid second parameter */
1988 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1989 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1991 /* test fourth parameter */
1992 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1993 switch(ret) {
1994 case S_OK: /* winvista */
1995 ok(!strncmp(appdata, testpath, strlen(appdata)),
1996 "expected %s to start with %s\n", testpath, appdata);
1997 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1998 "expected %s to end with %s\n", testpath, winetemp);
1999 break;
2000 case E_INVALIDARG: /* winxp, win2k3 */
2001 break;
2002 default:
2003 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
2006 /* test fifth parameter */
2007 testpath[0] = '\0';
2008 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
2009 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2010 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2012 testpath[0] = '\0';
2013 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
2014 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2015 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2017 testpath[0] = '\0';
2018 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
2019 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2020 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2022 for(i=0; i< MAX_PATH; i++)
2023 toolongpath[i] = '0' + i % 10;
2024 toolongpath[MAX_PATH] = '\0';
2025 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2026 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2027 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2029 testpath[0] = '\0';
2030 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2031 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2033 /* test a not existing path */
2034 testpath[0] = '\0';
2035 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2036 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2037 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2039 /* create a directory inside a not existing directory */
2040 testpath[0] = '\0';
2041 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2042 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2043 ok(!strncmp(appdata, testpath, strlen(appdata)),
2044 "expected %s to start with %s\n", testpath, appdata);
2045 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2046 "expected %s to end with %s\n", testpath, winetemp);
2047 dwret = GetFileAttributes(testpath);
2048 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2050 /* cleanup */
2051 sprintf(testpath, "%s\\%s", appdata, winetemp);
2052 RemoveDirectoryA(testpath);
2053 sprintf(testpath, "%s\\%s", appdata, wine);
2054 RemoveDirectoryA(testpath);
2057 static void test_LocalizedNames(void)
2059 static char cCurrDirA[MAX_PATH];
2060 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2061 IShellFolder *IDesktopFolder, *testIShellFolder;
2062 ITEMIDLIST *newPIDL;
2063 int len;
2064 HRESULT hr;
2065 static char resourcefile[MAX_PATH];
2066 DWORD res;
2067 HANDLE file;
2068 STRRET strret;
2069 BOOL ret;
2071 static const char desktopini_contents1[] =
2072 "[.ShellClassInfo]\r\n"
2073 "LocalizedResourceName=@";
2074 static const char desktopini_contents2[] =
2075 ",-1\r\n";
2076 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2077 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2079 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2080 CreateDirectoryA(".\\testfolder", NULL);
2082 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2084 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2086 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2087 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2088 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2089 ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2090 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2091 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
2092 ok(ret, "WriteFile failed %i\n", GetLastError());
2093 CloseHandle(file);
2095 /* get IShellFolder for parent */
2096 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2097 len = lstrlenA(cCurrDirA);
2099 if (len == 0) {
2100 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2101 goto cleanup;
2103 if(cCurrDirA[len-1] == '\\')
2104 cCurrDirA[len-1] = 0;
2106 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2108 hr = SHGetDesktopFolder(&IDesktopFolder);
2109 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2111 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2112 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2114 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2115 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2117 IMalloc_Free(ppM, newPIDL);
2119 /* windows reads the display name from the resource */
2120 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2121 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2123 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2124 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2126 if (hr == S_OK && pStrRetToBufW)
2128 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2129 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2130 todo_wine
2131 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2132 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2133 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2136 /* editing name is also read from the resource */
2137 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2138 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2140 if (hr == S_OK && pStrRetToBufW)
2142 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2143 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2144 todo_wine
2145 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2146 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2147 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2150 /* parsing name is unchanged */
2151 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2152 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2154 if (hr == S_OK && pStrRetToBufW)
2156 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2157 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2158 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2161 IShellFolder_Release(IDesktopFolder);
2162 IShellFolder_Release(testIShellFolder);
2164 IMalloc_Free(ppM, newPIDL);
2166 cleanup:
2167 DeleteFileA(".\\testfolder\\desktop.ini");
2168 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2169 RemoveDirectoryA(".\\testfolder");
2172 static void test_SHCreateShellItem(void)
2174 IShellItem *shellitem, *shellitem2;
2175 IPersistIDList *persistidl;
2176 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2177 HRESULT ret;
2178 char curdirA[MAX_PATH];
2179 WCHAR curdirW[MAX_PATH];
2180 WCHAR fnbufW[MAX_PATH];
2181 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2182 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2184 GetCurrentDirectoryA(MAX_PATH, curdirA);
2186 if (!pSHCreateShellItem)
2188 win_skip("SHCreateShellItem isn't available\n");
2189 return;
2192 if (!lstrlenA(curdirA))
2194 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2195 return;
2198 if(pSHGetSpecialFolderLocation)
2200 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2201 ok(ret == S_OK, "Got 0x%08x\n", ret);
2203 else
2205 win_skip("pSHGetSpecialFolderLocation missing.\n");
2206 pidl_desktop = NULL;
2209 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2211 ret = SHGetDesktopFolder(&desktopfolder);
2212 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2214 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2215 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2217 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2218 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2220 CreateTestFile(".\\testfile");
2222 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2223 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2225 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2227 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2228 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2230 if (0) /* crashes on Windows XP */
2232 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2233 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2234 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2235 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2238 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2239 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2240 if (SUCCEEDED(ret))
2242 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2243 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2244 if (SUCCEEDED(ret))
2246 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2247 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2248 if (SUCCEEDED(ret))
2250 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2251 pILFree(pidl_test);
2253 IPersistIDList_Release(persistidl);
2255 IShellItem_Release(shellitem);
2258 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2259 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2260 if (SUCCEEDED(ret))
2262 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2263 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2264 if (SUCCEEDED(ret))
2266 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2267 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2268 if (SUCCEEDED(ret))
2270 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2271 pILFree(pidl_test);
2273 IPersistIDList_Release(persistidl);
2276 ret = IShellItem_GetParent(shellitem, &shellitem2);
2277 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2278 if (SUCCEEDED(ret))
2280 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2281 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2282 if (SUCCEEDED(ret))
2284 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2285 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2286 if (SUCCEEDED(ret))
2288 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2289 pILFree(pidl_test);
2291 IPersistIDList_Release(persistidl);
2293 IShellItem_Release(shellitem2);
2296 IShellItem_Release(shellitem);
2299 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2300 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2301 if (SUCCEEDED(ret))
2303 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2304 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2305 if (SUCCEEDED(ret))
2307 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2308 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2309 if (SUCCEEDED(ret))
2311 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2312 pILFree(pidl_test);
2314 IPersistIDList_Release(persistidl);
2316 IShellItem_Release(shellitem);
2319 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2320 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2321 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2322 if (SUCCEEDED(ret))
2324 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2325 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2326 if (SUCCEEDED(ret))
2328 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2329 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2330 if (SUCCEEDED(ret))
2332 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2333 pILFree(pidl_test);
2335 IPersistIDList_Release(persistidl);
2337 IShellItem_Release(shellitem);
2340 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2341 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2342 if (SUCCEEDED(ret))
2344 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2345 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2346 if (SUCCEEDED(ret))
2348 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2349 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2350 if (SUCCEEDED(ret))
2352 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2353 pILFree(pidl_test);
2355 IPersistIDList_Release(persistidl);
2358 IShellItem_Release(shellitem);
2361 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2362 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2363 if (SUCCEEDED(ret))
2365 ret = IShellItem_GetParent(shellitem, &shellitem2);
2366 ok(FAILED(ret), "Got 0x%08x\n", ret);
2367 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2368 IShellItem_Release(shellitem);
2371 /* SHCreateItemFromParsingName */
2372 if(pSHCreateItemFromParsingName)
2374 if(0)
2376 /* Crashes under windows 7 */
2377 pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2380 shellitem = (void*)0xdeadbeef;
2381 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2382 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2383 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2385 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2386 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2387 "SHCreateItemFromParsingName returned %x\n", ret);
2388 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2390 lstrcpyW(fnbufW, curdirW);
2391 myPathAddBackslashW(fnbufW);
2392 lstrcatW(fnbufW, testfileW);
2394 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2395 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2396 if(SUCCEEDED(ret))
2398 LPWSTR tmp_fname;
2399 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2400 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2401 if(SUCCEEDED(ret))
2403 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2404 CoTaskMemFree(tmp_fname);
2406 IShellItem_Release(shellitem);
2409 else
2410 win_skip("No SHCreateItemFromParsingName\n");
2413 /* SHCreateItemFromIDList */
2414 if(pSHCreateItemFromIDList)
2416 if(0)
2418 /* Crashes under win7 */
2419 pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2422 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2423 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2425 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2426 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2427 if (SUCCEEDED(ret))
2429 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2430 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2431 if (SUCCEEDED(ret))
2433 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2434 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2435 if (SUCCEEDED(ret))
2437 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2438 pILFree(pidl_test);
2440 IPersistIDList_Release(persistidl);
2442 IShellItem_Release(shellitem);
2445 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2446 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2447 if (SUCCEEDED(ret))
2449 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2450 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2451 if (SUCCEEDED(ret))
2453 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2454 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2455 if (SUCCEEDED(ret))
2457 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2458 pILFree(pidl_test);
2460 IPersistIDList_Release(persistidl);
2462 IShellItem_Release(shellitem);
2465 else
2466 win_skip("No SHCreateItemFromIDList\n");
2468 DeleteFileA(".\\testfile");
2469 pILFree(pidl_abstestfile);
2470 pILFree(pidl_testfile);
2471 pILFree(pidl_desktop);
2472 pILFree(pidl_cwd);
2473 IShellFolder_Release(currentfolder);
2474 IShellFolder_Release(desktopfolder);
2477 static void test_SHGetNameFromIDList(void)
2479 IShellItem *shellitem;
2480 LPITEMIDLIST pidl;
2481 LPWSTR name_string;
2482 HRESULT hres;
2483 UINT i;
2484 static const DWORD flags[] = {
2485 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2486 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2487 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2488 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2490 if(!pSHGetNameFromIDList)
2492 win_skip("SHGetNameFromIDList missing.\n");
2493 return;
2496 /* These should be available on any platform that passed the above test. */
2497 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2498 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2499 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2500 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2502 if(0)
2504 /* Crashes under win7 */
2505 pSHGetNameFromIDList(NULL, 0, NULL);
2508 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2509 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2511 /* Test the desktop */
2512 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2513 ok(hres == S_OK, "Got 0x%08x\n", hres);
2514 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2515 ok(hres == S_OK, "Got 0x%08x\n", hres);
2516 if(SUCCEEDED(hres))
2518 WCHAR *nameSI, *nameSH;
2519 WCHAR buf[MAX_PATH];
2520 HRESULT hrSI, hrSH, hrSF;
2521 STRRET strret;
2522 IShellFolder *psf;
2523 BOOL res;
2525 SHGetDesktopFolder(&psf);
2526 for(i = 0; flags[i] != -1234; i++)
2528 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2529 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2530 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2531 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2532 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2533 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2535 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2536 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2538 if(SUCCEEDED(hrSF))
2540 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2541 if(SUCCEEDED(hrSI))
2542 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2543 if(SUCCEEDED(hrSF))
2544 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2546 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2547 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2549 IShellFolder_Release(psf);
2551 if(pSHGetPathFromIDListW){
2552 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2553 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2554 res = pSHGetPathFromIDListW(pidl, buf);
2555 ok(res == TRUE, "Got %d\n", res);
2556 if(SUCCEEDED(hrSI) && res)
2557 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2558 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2559 }else
2560 win_skip("pSHGetPathFromIDListW not available\n");
2562 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2563 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2564 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2566 IShellItem_Release(shellitem);
2568 pILFree(pidl);
2570 /* Test the control panel */
2571 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2572 ok(hres == S_OK, "Got 0x%08x\n", hres);
2573 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2574 ok(hres == S_OK, "Got 0x%08x\n", hres);
2575 if(SUCCEEDED(hres))
2577 WCHAR *nameSI, *nameSH;
2578 WCHAR buf[MAX_PATH];
2579 HRESULT hrSI, hrSH, hrSF;
2580 STRRET strret;
2581 IShellFolder *psf;
2582 BOOL res;
2584 SHGetDesktopFolder(&psf);
2585 for(i = 0; flags[i] != -1234; i++)
2587 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2588 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2589 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2590 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2591 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2592 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2594 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2595 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2597 if(SUCCEEDED(hrSF))
2599 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2600 if(SUCCEEDED(hrSI))
2601 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2602 if(SUCCEEDED(hrSF))
2603 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2605 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2606 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2608 IShellFolder_Release(psf);
2610 if(pSHGetPathFromIDListW){
2611 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2612 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2613 res = pSHGetPathFromIDListW(pidl, buf);
2614 ok(res == FALSE, "Got %d\n", res);
2615 if(SUCCEEDED(hrSI) && res)
2616 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2617 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2618 }else
2619 win_skip("pSHGetPathFromIDListW not available\n");
2621 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2622 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2623 "Got 0x%08x\n", hres);
2624 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2626 IShellItem_Release(shellitem);
2628 pILFree(pidl);
2631 static void test_SHGetItemFromDataObject(void)
2633 IShellFolder *psfdesktop;
2634 IShellItem *psi;
2635 IShellView *psv;
2636 HRESULT hres;
2638 if(!pSHGetItemFromDataObject)
2640 win_skip("No SHGetItemFromDataObject.\n");
2641 return;
2644 if(0)
2646 /* Crashes under win7 */
2647 pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2650 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2651 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2653 SHGetDesktopFolder(&psfdesktop);
2655 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2656 ok(hres == S_OK, "got 0x%08x\n", hres);
2657 if(SUCCEEDED(hres))
2659 IEnumIDList *peidl;
2660 IDataObject *pdo;
2661 SHCONTF enum_flags;
2663 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2664 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2665 ok(hres == S_OK, "got 0x%08x\n", hres);
2666 if(SUCCEEDED(hres))
2668 LPITEMIDLIST apidl[5];
2669 UINT count = 0, i;
2671 for(count = 0; count < 5; count++)
2672 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2673 break;
2675 if(count)
2677 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2678 &IID_IDataObject, NULL, (void**)&pdo);
2679 ok(hres == S_OK, "got 0x%08x\n", hres);
2680 if(SUCCEEDED(hres))
2682 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2683 ok(hres == S_OK, "got 0x%08x\n", hres);
2684 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2685 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2686 ok(hres == S_OK, "got 0x%08x\n", hres);
2687 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2688 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2689 ok(hres == S_OK, "got 0x%08x\n", hres);
2690 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2691 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2692 ok(hres == S_OK, "got 0x%08x\n", hres);
2693 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2694 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2695 ok(hres == S_OK, "got 0x%08x\n", hres);
2696 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2698 IDataObject_Release(pdo);
2701 else
2702 skip("No file(s) found - skipping single-file test.\n");
2704 if(count > 1)
2706 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2707 &IID_IDataObject, NULL, (void**)&pdo);
2708 ok(hres == S_OK, "got 0x%08x\n", hres);
2709 if(SUCCEEDED(hres))
2711 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2712 ok(hres == S_OK, "got 0x%08x\n", hres);
2713 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2714 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2715 ok(hres == S_OK, "got 0x%08x\n", hres);
2716 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2717 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2718 ok(hres == S_OK, "got 0x%08x\n", hres);
2719 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2720 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2721 ok(hres == S_OK, "got 0x%08x\n", hres);
2722 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2723 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2724 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2725 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2726 IDataObject_Release(pdo);
2729 else
2730 skip("zero or one file found - skipping multi-file test.\n");
2732 for(i = 0; i < count; i++)
2733 pILFree(apidl[i]);
2735 IEnumIDList_Release(peidl);
2738 IShellView_Release(psv);
2741 IShellFolder_Release(psfdesktop);
2744 static void test_ShellItemCompare(void)
2746 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2747 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2748 IShellFolder *psf_desktop, *psf_current;
2749 LPITEMIDLIST pidl_cwd;
2750 WCHAR curdirW[MAX_PATH];
2751 BOOL failed;
2752 HRESULT hr;
2753 static const WCHAR filesW[][9] = {
2754 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2755 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2756 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2757 int order;
2758 UINT i;
2760 if(!pSHCreateShellItem)
2762 win_skip("SHCreateShellItem missing.\n");
2763 return;
2766 GetCurrentDirectoryW(MAX_PATH, curdirW);
2767 if(!lstrlenW(curdirW))
2769 skip("Failed to get current directory, skipping.\n");
2770 return;
2773 CreateDirectoryA(".\\a", NULL);
2774 CreateDirectoryA(".\\b", NULL);
2775 CreateDirectoryA(".\\c", NULL);
2776 CreateTestFile(".\\a\\a");
2777 CreateTestFile(".\\a\\b");
2778 CreateTestFile(".\\a\\c");
2779 CreateTestFile(".\\b\\a");
2780 CreateTestFile(".\\b\\b");
2781 CreateTestFile(".\\b\\c");
2782 CreateTestFile(".\\c\\a");
2783 CreateTestFile(".\\c\\b");
2784 CreateTestFile(".\\c\\c");
2786 SHGetDesktopFolder(&psf_desktop);
2787 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2788 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2789 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2790 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2791 IShellFolder_Release(psf_desktop);
2792 ILFree(pidl_cwd);
2794 /* Generate ShellItems for the files */
2795 memset(&psi, 0, sizeof(psi));
2796 failed = FALSE;
2797 for(i = 0; i < 9; i++)
2799 LPITEMIDLIST pidl_testfile = NULL;
2801 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2802 NULL, &pidl_testfile, NULL);
2803 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2804 if(SUCCEEDED(hr))
2806 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2807 ok(hr == S_OK, "Got 0x%08x\n", hr);
2808 pILFree(pidl_testfile);
2810 if(FAILED(hr)) failed = TRUE;
2812 if(failed)
2814 skip("Failed to create all shellitems.\n");
2815 goto cleanup;
2818 /* Generate ShellItems for the folders */
2819 hr = IShellItem_GetParent(psi[0], &psi_a);
2820 ok(hr == S_OK, "Got 0x%08x\n", hr);
2821 if(FAILED(hr)) failed = TRUE;
2822 hr = IShellItem_GetParent(psi[3], &psi_b);
2823 ok(hr == S_OK, "Got 0x%08x\n", hr);
2824 if(FAILED(hr)) failed = TRUE;
2825 hr = IShellItem_GetParent(psi[6], &psi_c);
2826 ok(hr == S_OK, "Got 0x%08x\n", hr);
2827 if(FAILED(hr)) failed = TRUE;
2829 if(failed)
2831 skip("Failed to create shellitems.\n");
2832 goto cleanup;
2835 if(0)
2837 /* Crashes on native (win7, winxp) */
2838 IShellItem_Compare(psi_a, NULL, 0, NULL);
2839 IShellItem_Compare(psi_a, psi_b, 0, NULL);
2840 IShellItem_Compare(psi_a, NULL, 0, &order);
2843 /* Basics */
2844 for(i = 0; i < 9; i++)
2846 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2847 ok(hr == S_OK, "Got 0x%08x\n", hr);
2848 ok(order == 0, "Got order %d\n", order);
2849 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2850 ok(hr == S_OK, "Got 0x%08x\n", hr);
2851 ok(order == 0, "Got order %d\n", order);
2852 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2853 ok(hr == S_OK, "Got 0x%08x\n", hr);
2854 ok(order == 0, "Got order %d\n", order);
2857 /* Order */
2858 /* a\b:a\a , a\b:a\c, a\b:a\b */
2859 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2860 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2861 ok(order == 1, "Got order %d\n", order);
2862 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2863 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2864 ok(order == -1, "Got order %d\n", order);
2865 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2866 ok(hr == S_OK, "Got 0x%08x\n", hr);
2867 ok(order == 0, "Got order %d\n", order);
2869 /* b\b:a\b, b\b:c\b, b\b:c\b */
2870 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2871 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2872 ok(order == 1, "Got order %d\n", order);
2873 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2874 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2875 ok(order == -1, "Got order %d\n", order);
2876 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2877 ok(hr == S_OK, "Got 0x%08x\n", hr);
2878 ok(order == 0, "Got order %d\n", order);
2880 /* b:a\a, b:a\c, b:a\b */
2881 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2882 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2883 todo_wine ok(order == 1, "Got order %d\n", order);
2884 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2885 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2886 todo_wine ok(order == 1, "Got order %d\n", order);
2887 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2888 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2889 todo_wine ok(order == 1, "Got order %d\n", order);
2891 /* b:c\a, b:c\c, b:c\b */
2892 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2893 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2894 ok(order == -1, "Got order %d\n", order);
2895 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2896 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2897 ok(order == -1, "Got order %d\n", order);
2898 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2899 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2900 ok(order == -1, "Got order %d\n", order);
2902 /* a\b:a\a , a\b:a\c, a\b:a\b */
2903 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2904 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2905 ok(order == 1, "Got order %d\n", order);
2906 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2907 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2908 ok(order == -1, "Got order %d\n", order);
2909 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2910 ok(hr == S_OK, "Got 0x%08x\n", hr);
2911 ok(order == 0, "Got order %d\n", order);
2913 /* b\b:a\b, b\b:c\b, b\b:c\b */
2914 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2915 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2916 ok(order == 1, "Got order %d\n", order);
2917 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2918 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2919 ok(order == -1, "Got order %d\n", order);
2920 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2921 ok(hr == S_OK, "Got 0x%08x\n", hr);
2922 ok(order == 0, "Got order %d\n", order);
2924 /* b:a\a, b:a\c, b:a\b */
2925 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2926 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2927 todo_wine ok(order == 1, "Got order %d\n", order);
2928 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2929 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2930 todo_wine ok(order == 1, "Got order %d\n", order);
2931 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2932 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2933 todo_wine ok(order == 1, "Got order %d\n", order);
2935 /* b:c\a, b:c\c, b:c\b */
2936 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2937 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2938 ok(order == -1, "Got order %d\n", order);
2939 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2940 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2941 ok(order == -1, "Got order %d\n", order);
2942 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2943 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2944 ok(order == -1, "Got order %d\n", order);
2946 cleanup:
2947 IShellFolder_Release(psf_current);
2949 DeleteFileA(".\\a\\a");
2950 DeleteFileA(".\\a\\b");
2951 DeleteFileA(".\\a\\c");
2952 DeleteFileA(".\\b\\a");
2953 DeleteFileA(".\\b\\b");
2954 DeleteFileA(".\\b\\c");
2955 DeleteFileA(".\\c\\a");
2956 DeleteFileA(".\\c\\b");
2957 DeleteFileA(".\\c\\c");
2958 RemoveDirectoryA(".\\a");
2959 RemoveDirectoryA(".\\b");
2960 RemoveDirectoryA(".\\c");
2962 if(psi_a) IShellItem_Release(psi_a);
2963 if(psi_b) IShellItem_Release(psi_b);
2964 if(psi_c) IShellItem_Release(psi_c);
2966 for(i = 0; i < 9; i++)
2967 if(psi[i]) IShellItem_Release(psi[i]);
2970 /**************************************************************/
2971 /* IUnknown implementation for counting QueryInterface calls. */
2972 typedef struct {
2973 IUnknown IUnknown_iface;
2974 struct if_count {
2975 REFIID id;
2976 LONG count;
2977 } *ifaces;
2978 LONG unknown;
2979 } IUnknownImpl;
2981 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
2983 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
2986 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2988 IUnknownImpl *This = impl_from_IUnknown(iunk);
2989 UINT i, found;
2990 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2992 if(IsEqualIID(This->ifaces[i].id, riid))
2994 This->ifaces[i].count++;
2995 found = 1;
2996 break;
2999 if(!found)
3000 This->unknown++;
3001 return E_NOINTERFACE;
3004 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
3006 return 2;
3009 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3011 return 1;
3014 static const IUnknownVtbl vt_IUnknown = {
3015 unk_fnQueryInterface,
3016 unk_fnAddRef,
3017 unk_fnRelease
3020 static void test_SHGetIDListFromObject(void)
3022 IUnknownImpl *punkimpl;
3023 IShellFolder *psfdesktop;
3024 IShellView *psv;
3025 LPITEMIDLIST pidl, pidl_desktop;
3026 HRESULT hres;
3027 UINT i;
3028 struct if_count ifaces[] =
3029 { {&IID_IPersistIDList, 0},
3030 {&IID_IPersistFolder2, 0},
3031 {&IID_IDataObject, 0},
3032 {&IID_IParentAndItem, 0},
3033 {&IID_IFolderView, 0},
3034 {NULL, 0} };
3036 if(!pSHGetIDListFromObject)
3038 win_skip("SHGetIDListFromObject missing.\n");
3039 return;
3042 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3044 if(0)
3046 /* Crashes native */
3047 pSHGetIDListFromObject(NULL, NULL);
3048 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3051 hres = pSHGetIDListFromObject(NULL, &pidl);
3052 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3054 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3055 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3056 punkimpl->ifaces = ifaces;
3057 punkimpl->unknown = 0;
3059 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3060 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3061 ok(ifaces[0].count, "interface not requested.\n");
3062 ok(ifaces[1].count, "interface not requested.\n");
3063 ok(ifaces[2].count, "interface not requested.\n");
3064 todo_wine
3065 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3066 "interface not requested.\n");
3067 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3068 "interface not requested.\n");
3070 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3071 HeapFree(GetProcessHeap(), 0, punkimpl);
3073 pidl_desktop = NULL;
3074 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3075 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3077 SHGetDesktopFolder(&psfdesktop);
3079 /* Test IShellItem */
3080 if(pSHCreateShellItem)
3082 IShellItem *shellitem;
3083 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3084 ok(hres == S_OK, "got 0x%08x\n", hres);
3085 if(SUCCEEDED(hres))
3087 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3088 ok(hres == S_OK, "got 0x%08x\n", hres);
3089 if(SUCCEEDED(hres))
3091 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3092 pILFree(pidl);
3094 IShellItem_Release(shellitem);
3097 else
3098 skip("no SHCreateShellItem.\n");
3100 /* Test IShellFolder */
3101 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3102 ok(hres == S_OK, "got 0x%08x\n", hres);
3103 if(SUCCEEDED(hres))
3105 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3106 pILFree(pidl);
3109 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3110 ok(hres == S_OK, "got 0x%08x\n", hres);
3111 if(SUCCEEDED(hres))
3113 IEnumIDList *peidl;
3114 IDataObject *pdo;
3115 SHCONTF enum_flags;
3117 /* Test IFolderView */
3118 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3119 ok(hres == S_OK, "got 0x%08x\n", hres);
3120 if(SUCCEEDED(hres))
3122 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3123 pILFree(pidl);
3126 /* Test IDataObject */
3127 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3128 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3129 ok(hres == S_OK, "got 0x%08x\n", hres);
3130 if(SUCCEEDED(hres))
3132 LPITEMIDLIST apidl[5];
3133 UINT count = 0;
3134 for(count = 0; count < 5; count++)
3135 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3136 break;
3138 if(count)
3140 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3141 &IID_IDataObject, NULL, (void**)&pdo);
3142 ok(hres == S_OK, "got 0x%08x\n", hres);
3143 if(SUCCEEDED(hres))
3145 pidl = (void*)0xDEADBEEF;
3146 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3147 ok(hres == S_OK, "got 0x%08x\n", hres);
3148 ok(pidl != NULL, "pidl is NULL.\n");
3149 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3150 pILFree(pidl);
3152 IDataObject_Release(pdo);
3155 else
3156 skip("No files found - skipping single-file test.\n");
3158 if(count > 1)
3160 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3161 &IID_IDataObject, NULL, (void**)&pdo);
3162 ok(hres == S_OK, "got 0x%08x\n", hres);
3163 if(SUCCEEDED(hres))
3165 pidl = (void*)0xDEADBEEF;
3166 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3167 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3168 "got 0x%08x\n", hres);
3169 ok(pidl == NULL, "pidl is not NULL.\n");
3171 IDataObject_Release(pdo);
3174 else
3175 skip("zero or one file found - skipping multi-file test.\n");
3177 for(i = 0; i < count; i++)
3178 pILFree(apidl[i]);
3180 IEnumIDList_Release(peidl);
3183 IShellView_Release(psv);
3186 IShellFolder_Release(psfdesktop);
3187 pILFree(pidl_desktop);
3190 static void test_SHGetItemFromObject(void)
3192 IUnknownImpl *punkimpl;
3193 IShellFolder *psfdesktop;
3194 LPITEMIDLIST pidl;
3195 IShellItem *psi;
3196 IUnknown *punk;
3197 HRESULT hres;
3198 struct if_count ifaces[] =
3199 { {&IID_IPersistIDList, 0},
3200 {&IID_IPersistFolder2, 0},
3201 {&IID_IDataObject, 0},
3202 {&IID_IParentAndItem, 0},
3203 {&IID_IFolderView, 0},
3204 {NULL, 0} };
3206 if(!pSHGetItemFromObject)
3208 skip("No SHGetItemFromObject.\n");
3209 return;
3212 SHGetDesktopFolder(&psfdesktop);
3214 if(0)
3216 /* Crashes with Windows 7 */
3217 pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3218 pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3219 pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3222 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3223 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3225 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3226 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3227 punkimpl->ifaces = ifaces;
3228 punkimpl->unknown = 0;
3230 /* The same as SHGetIDListFromObject */
3231 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3232 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3233 ok(ifaces[0].count, "interface not requested.\n");
3234 ok(ifaces[1].count, "interface not requested.\n");
3235 ok(ifaces[2].count, "interface not requested.\n");
3236 todo_wine
3237 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3238 "interface not requested.\n");
3239 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3240 "interface not requested.\n");
3242 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3243 HeapFree(GetProcessHeap(), 0, punkimpl);
3245 /* Test IShellItem */
3246 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3247 ok(hres == S_OK, "Got 0x%08x\n", hres);
3248 if(SUCCEEDED(hres))
3250 IShellItem *psi2;
3251 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3252 ok(hres == S_OK, "Got 0x%08x\n", hres);
3253 if(SUCCEEDED(hres))
3255 todo_wine
3256 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3257 IShellItem_Release(psi2);
3259 IShellItem_Release(psi);
3262 IShellFolder_Release(psfdesktop);
3265 static void test_SHCreateShellItemArray(void)
3267 IShellFolder *pdesktopsf, *psf;
3268 IShellItemArray *psia;
3269 IEnumIDList *peidl;
3270 HRESULT hr;
3271 WCHAR cTestDirW[MAX_PATH];
3272 LPITEMIDLIST pidl_testdir, pidl;
3273 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3275 if(!pSHCreateShellItemArray) {
3276 skip("No pSHCreateShellItemArray!\n");
3277 return;
3280 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3282 if(0)
3284 /* Crashes under native */
3285 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3286 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3287 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3288 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3291 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3292 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3294 SHGetDesktopFolder(&pdesktopsf);
3295 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3296 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3298 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3299 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3301 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3302 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3303 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3304 pILFree(pidl);
3306 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3307 myPathAddBackslashW(cTestDirW);
3308 lstrcatW(cTestDirW, testdirW);
3310 CreateFilesFolders();
3312 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3313 ok(hr == S_OK, "got 0x%08x\n", hr);
3314 if(SUCCEEDED(hr))
3316 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3317 (void**)&psf);
3318 ok(hr == S_OK, "Got 0x%08x\n", hr);
3320 IShellFolder_Release(pdesktopsf);
3322 if(FAILED(hr))
3324 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3325 pILFree(pidl_testdir);
3326 Cleanup();
3327 return;
3330 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3331 ok(hr == S_OK, "Got %08x\n", hr);
3332 if(SUCCEEDED(hr))
3334 LPITEMIDLIST apidl[5];
3335 UINT done, numitems, i;
3337 for(done = 0; done < 5; done++)
3338 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3339 break;
3340 ok(done == 5, "Got %d pidls\n", done);
3341 IEnumIDList_Release(peidl);
3343 /* Create a ShellItemArray */
3344 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3345 ok(hr == S_OK, "Got 0x%08x\n", hr);
3346 if(SUCCEEDED(hr))
3348 IShellItem *psi;
3350 if(0)
3352 /* Crashes in Windows 7 */
3353 IShellItemArray_GetCount(psia, NULL);
3356 IShellItemArray_GetCount(psia, &numitems);
3357 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3359 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3360 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3362 /* Compare all the items */
3363 for(i = 0; i < numitems; i++)
3365 LPITEMIDLIST pidl_abs;
3366 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3368 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3369 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3370 if(SUCCEEDED(hr))
3372 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3373 ok(hr == S_OK, "Got 0x%08x\n", hr);
3374 if(SUCCEEDED(hr))
3376 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3377 pILFree(pidl);
3379 IShellItem_Release(psi);
3381 pILFree(pidl_abs);
3383 for(i = 0; i < done; i++)
3384 pILFree(apidl[i]);
3385 IShellItemArray_Release(psia);
3389 /* SHCreateShellItemArrayFromShellItem */
3390 if(pSHCreateShellItemArrayFromShellItem)
3392 IShellItem *psi;
3394 if(0)
3396 /* Crashes under Windows 7 */
3397 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3398 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3399 pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3402 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3403 ok(hr == S_OK, "Got 0x%08x\n", hr);
3404 if(SUCCEEDED(hr))
3406 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3407 ok(hr == S_OK, "Got 0x%08x\n", hr);
3408 if(SUCCEEDED(hr))
3410 IShellItem *psi2;
3411 UINT count;
3412 hr = IShellItemArray_GetCount(psia, &count);
3413 ok(hr == S_OK, "Got 0x%08x\n", hr);
3414 ok(count == 1, "Got count %d\n", count);
3415 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3416 ok(hr == S_OK, "Got 0x%08x\n", hr);
3417 todo_wine
3418 ok(psi != psi2, "ShellItems are of the same instance.\n");
3419 if(SUCCEEDED(hr))
3421 LPITEMIDLIST pidl1, pidl2;
3422 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3423 ok(hr == S_OK, "Got 0x%08x\n", hr);
3424 ok(pidl1 != NULL, "pidl1 was null.\n");
3425 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3426 ok(hr == S_OK, "Got 0x%08x\n", hr);
3427 ok(pidl2 != NULL, "pidl2 was null.\n");
3428 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3429 pILFree(pidl1);
3430 pILFree(pidl2);
3431 IShellItem_Release(psi2);
3433 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3434 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3435 IShellItemArray_Release(psia);
3437 IShellItem_Release(psi);
3440 else
3441 skip("No SHCreateShellItemArrayFromShellItem.\n");
3443 if(pSHCreateShellItemArrayFromDataObject)
3445 IShellView *psv;
3447 if(0)
3449 /* Crashes under Windows 7 */
3450 pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3452 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3453 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3455 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3456 ok(hr == S_OK, "got 0x%08x\n", hr);
3457 if(SUCCEEDED(hr))
3459 IEnumIDList *peidl;
3460 IDataObject *pdo;
3461 SHCONTF enum_flags;
3463 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3464 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3465 ok(hr == S_OK, "got 0x%08x\n", hr);
3466 if(SUCCEEDED(hr))
3468 LPITEMIDLIST apidl[5];
3469 UINT count, i;
3471 for(count = 0; count < 5; count++)
3472 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3473 break;
3474 ok(count == 5, "Got %d\n", count);
3476 if(count)
3478 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3479 &IID_IDataObject, NULL, (void**)&pdo);
3480 ok(hr == S_OK, "Got 0x%08x\n", hr);
3481 if(SUCCEEDED(hr))
3483 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3484 (void**)&psia);
3485 ok(hr == S_OK, "Got 0x%08x\n", hr);
3486 if(SUCCEEDED(hr))
3488 UINT count_sia, i;
3489 hr = IShellItemArray_GetCount(psia, &count_sia);
3490 ok(hr == S_OK, "Got 0x%08x\n", hr);
3491 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3492 for(i = 0; i < count_sia; i++)
3494 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3495 IShellItem *psi;
3496 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3497 ok(hr == S_OK, "Got 0x%08x\n", hr);
3498 if(SUCCEEDED(hr))
3500 LPITEMIDLIST pidl;
3501 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3502 ok(hr == S_OK, "Got 0x%08x\n", hr);
3503 ok(pidl != NULL, "pidl as NULL.\n");
3504 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3505 pILFree(pidl);
3506 IShellItem_Release(psi);
3508 pILFree(pidl_abs);
3511 IShellItemArray_Release(psia);
3514 IDataObject_Release(pdo);
3516 for(i = 0; i < count; i++)
3517 pILFree(apidl[i]);
3519 else
3520 skip("No files found - skipping test.\n");
3522 IEnumIDList_Release(peidl);
3524 IShellView_Release(psv);
3527 else
3528 skip("No SHCreateShellItemArrayFromDataObject.\n");
3530 IShellFolder_Release(psf);
3531 pILFree(pidl_testdir);
3532 Cleanup();
3535 static void test_ShellItemBindToHandler(void)
3537 IShellItem *psi;
3538 LPITEMIDLIST pidl_desktop;
3539 HRESULT hr;
3541 if(!pSHCreateShellItem)
3543 skip("SHCreateShellItem missing.\n");
3544 return;
3547 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3548 ok(hr == S_OK, "Got 0x%08x\n", hr);
3549 if(SUCCEEDED(hr))
3551 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3552 ok(hr == S_OK, "Got 0x%08x\n", hr);
3554 if(SUCCEEDED(hr))
3556 IPersistFolder2 *ppf2;
3557 IUnknown *punk;
3559 if(0)
3561 /* Crashes under Windows 7 */
3562 IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3563 IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3565 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3566 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3568 /* BHID_SFObject */
3569 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3570 ok(hr == S_OK, "Got 0x%08x\n", hr);
3571 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3572 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3573 ok(hr == S_OK, "Got 0x%08x\n", hr);
3574 if(SUCCEEDED(hr))
3576 LPITEMIDLIST pidl_tmp;
3577 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3578 ok(hr == S_OK, "Got 0x%08x\n", hr);
3579 if(SUCCEEDED(hr))
3581 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3582 pILFree(pidl_tmp);
3584 IPersistFolder2_Release(ppf2);
3587 /* BHID_SFUIObject */
3588 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3589 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3590 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3591 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3592 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3593 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3595 /* BHID_DataObject */
3596 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3597 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3598 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3600 todo_wine
3602 /* BHID_SFViewObject */
3603 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3604 ok(hr == S_OK, "Got 0x%08x\n", hr);
3605 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3606 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3607 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3608 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3610 /* BHID_Storage */
3611 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3612 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3613 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3614 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3615 ok(hr == S_OK, "Got 0x%08x\n", hr);
3616 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3618 /* BHID_Stream */
3619 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3620 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3621 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3622 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3623 ok(hr == S_OK, "Got 0x%08x\n", hr);
3624 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3626 /* BHID_StorageEnum */
3627 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3628 ok(hr == S_OK, "Got 0x%08x\n", hr);
3629 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3631 /* BHID_Transfer */
3632 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3633 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3634 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3636 /* BHID_EnumItems */
3637 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3638 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3639 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3641 /* BHID_Filter */
3642 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3643 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3644 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3646 /* BHID_LinkTargetItem */
3647 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3648 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3649 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3650 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3651 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3652 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3654 /* BHID_PropertyStore */
3655 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3656 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3657 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3658 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3659 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3660 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3662 /* BHID_ThumbnailHandler */
3663 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3664 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3665 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3667 /* BHID_AssociationArray */
3668 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3669 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3670 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3672 /* BHID_EnumAssocHandlers */
3673 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3674 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3675 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3678 IShellItem_Release(psi);
3680 else
3681 skip("Failed to create ShellItem.\n");
3683 pILFree(pidl_desktop);
3686 static void test_ShellItemGetAttributes(void)
3688 IShellItem *psi;
3689 LPITEMIDLIST pidl_desktop;
3690 SFGAOF sfgao;
3691 HRESULT hr;
3693 if(!pSHCreateShellItem)
3695 skip("SHCreateShellItem missing.\n");
3696 return;
3699 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3700 ok(hr == S_OK, "Got 0x%08x\n", hr);
3701 if(SUCCEEDED(hr))
3703 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3704 ok(hr == S_OK, "Got 0x%08x\n", hr);
3705 pILFree(pidl_desktop);
3707 if(FAILED(hr))
3709 skip("Skipping tests.\n");
3710 return;
3713 if(0)
3715 /* Crashes on native (Win 7) */
3716 IShellItem_GetAttributes(psi, 0, NULL);
3719 /* Test GetAttributes on the desktop folder. */
3720 sfgao = 0xdeadbeef;
3721 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
3722 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
3723 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
3725 IShellItem_Release(psi);
3728 static void test_SHParseDisplayName(void)
3730 LPITEMIDLIST pidl1, pidl2;
3731 IShellFolder *desktop;
3732 WCHAR dirW[MAX_PATH];
3733 WCHAR nameW[10];
3734 HRESULT hr;
3735 BOOL ret, is_wow64;
3737 if (!pSHParseDisplayName)
3739 win_skip("SHParseDisplayName isn't available\n");
3740 return;
3743 if (0)
3745 /* crashes on native */
3746 pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3747 nameW[0] = 0;
3748 pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3751 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3752 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3753 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3754 hr == E_INVALIDARG, "failed %08x\n", hr);
3755 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3757 /* dummy name */
3758 nameW[0] = 0;
3759 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3760 ok(hr == S_OK, "failed %08x\n", hr);
3761 hr = SHGetDesktopFolder(&desktop);
3762 ok(hr == S_OK, "failed %08x\n", hr);
3763 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3764 ok(hr == S_OK, "failed %08x\n", hr);
3765 ret = pILIsEqual(pidl1, pidl2);
3766 ok(ret == TRUE, "expected equal idls\n");
3767 pILFree(pidl1);
3768 pILFree(pidl2);
3770 /* with path */
3771 GetWindowsDirectoryW( dirW, MAX_PATH );
3773 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3774 ok(hr == S_OK, "failed %08x\n", hr);
3775 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3776 ok(hr == S_OK, "failed %08x\n", hr);
3778 ret = pILIsEqual(pidl1, pidl2);
3779 ok(ret == TRUE, "expected equal idls\n");
3780 pILFree(pidl1);
3781 pILFree(pidl2);
3783 /* system32 is not redirected to syswow64 on WOW64 */
3784 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
3785 if (is_wow64 && pGetSystemWow64DirectoryW)
3787 UINT len;
3788 *dirW = 0;
3789 len = GetSystemDirectoryW(dirW, MAX_PATH);
3790 ok(len > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
3791 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3792 ok(hr == S_OK, "failed %08x\n", hr);
3793 *dirW = 0;
3794 len = pGetSystemWow64DirectoryW(dirW, MAX_PATH);
3795 ok(len > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
3796 hr = pSHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
3797 ok(hr == S_OK, "failed %08x\n", hr);
3798 ret = pILIsEqual(pidl1, pidl2);
3799 ok(ret == FALSE, "expected different idls\n");
3800 pILFree(pidl1);
3801 pILFree(pidl2);
3804 IShellFolder_Release(desktop);
3807 static void test_desktop_IPersist(void)
3809 IShellFolder *desktop;
3810 IPersist *persist;
3811 IPersistFolder2 *ppf2;
3812 CLSID clsid;
3813 HRESULT hr;
3815 hr = SHGetDesktopFolder(&desktop);
3816 ok(hr == S_OK, "failed %08x\n", hr);
3818 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3819 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3821 if (hr == S_OK)
3823 if (0)
3825 /* crashes on native */
3826 IPersist_GetClassID(persist, NULL);
3828 memset(&clsid, 0, sizeof(clsid));
3829 hr = IPersist_GetClassID(persist, &clsid);
3830 ok(hr == S_OK, "failed %08x\n", hr);
3831 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3832 IPersist_Release(persist);
3835 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3836 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3837 if(SUCCEEDED(hr))
3839 IPersistFolder *ppf;
3840 LPITEMIDLIST pidl;
3841 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3842 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3843 if(SUCCEEDED(hr))
3844 IPersistFolder_Release(ppf);
3846 todo_wine {
3847 hr = IPersistFolder2_Initialize(ppf2, NULL);
3848 ok(hr == S_OK, "got %08x\n", hr);
3851 pidl = NULL;
3852 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3853 ok(hr == S_OK, "got %08x\n", hr);
3854 ok(pidl != NULL, "pidl was NULL.\n");
3855 if(SUCCEEDED(hr)) pILFree(pidl);
3857 IPersistFolder2_Release(ppf2);
3860 IShellFolder_Release(desktop);
3863 static void test_GetUIObject(void)
3865 IShellFolder *psf_desktop;
3866 IContextMenu *pcm;
3867 LPITEMIDLIST pidl;
3868 HRESULT hr;
3869 WCHAR path[MAX_PATH];
3870 const WCHAR filename[] =
3871 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3873 if(!pSHBindToParent)
3875 win_skip("SHBindToParent missing.\n");
3876 return;
3879 GetCurrentDirectoryW(MAX_PATH, path);
3880 if(!lstrlenW(path))
3882 skip("GetCurrentDirectoryW returned an empty string.\n");
3883 return;
3885 lstrcatW(path, filename);
3886 SHGetDesktopFolder(&psf_desktop);
3888 CreateFilesFolders();
3890 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3891 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3892 if(SUCCEEDED(hr))
3894 IShellFolder *psf;
3895 LPCITEMIDLIST pidl_child;
3896 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3897 ok(hr == S_OK, "Got 0x%08x\n", hr);
3898 if(SUCCEEDED(hr))
3900 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, &pidl_child, &IID_IContextMenu, NULL,
3901 (void**)&pcm);
3902 ok(hr == S_OK, "Got 0x%08x\n", hr);
3903 if(SUCCEEDED(hr))
3905 HMENU hmenu = CreatePopupMenu();
3906 INT max_id, max_id_check;
3907 UINT count, i;
3908 const int id_upper_limit = 32767;
3909 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3910 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3911 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3912 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3913 count = GetMenuItemCount(hmenu);
3914 ok(count, "Got %d\n", count);
3916 max_id_check = 0;
3917 for(i = 0; i < count; i++)
3919 MENUITEMINFOA mii;
3920 INT res;
3921 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3922 mii.cbSize = sizeof(MENUITEMINFOA);
3923 mii.fMask = MIIM_ID | MIIM_FTYPE;
3925 SetLastError(0);
3926 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3927 ok(res, "Failed (last error: %d).\n", GetLastError());
3929 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3930 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3931 if(!(mii.fType & MFT_SEPARATOR))
3932 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3934 ok((max_id_check == max_id) ||
3935 (max_id_check == max_id-1 /* Win 7 */),
3936 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3938 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3940 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3942 CMINVOKECOMMANDINFO cmi;
3943 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3944 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3946 /* Attempt to execute a nonexistent command */
3947 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3948 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3949 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3951 cmi.lpVerb = "foobar_wine_test";
3952 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3953 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3954 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3955 "Got 0x%08x\n", hr);
3957 #undef is_win2k
3959 DestroyMenu(hmenu);
3960 IContextMenu_Release(pcm);
3962 IShellFolder_Release(psf);
3964 if(pILFree) pILFree(pidl);
3967 IShellFolder_Release(psf_desktop);
3968 Cleanup();
3971 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3972 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3974 LPCITEMIDLIST child;
3975 IShellFolder *parent;
3976 STRRET filename;
3977 HRESULT hr;
3979 if(!pSHBindToParent){
3980 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3981 if(path)
3982 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3983 else
3984 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3985 return;
3988 if(path){
3989 if(!pidl){
3990 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3991 return;
3994 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3995 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3996 if(FAILED(hr))
3997 return;
3999 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
4000 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
4001 if(FAILED(hr)){
4002 IShellFolder_Release(parent);
4003 return;
4006 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
4007 "Got unexpected string type: %d\n", filename.uType);
4008 if(filename.uType == STRRET_WSTR){
4009 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
4010 "didn't get expected path (%s), instead: %s\n",
4011 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
4012 SHFree(U(filename).pOleStr);
4013 }else if(filename.uType == STRRET_CSTR){
4014 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
4015 "didn't get expected path (%s), instead: %s\n",
4016 wine_dbgstr_w(path), U(filename).cStr);
4019 IShellFolder_Release(parent);
4020 }else
4021 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4024 static void test_SHSimpleIDListFromPath(void)
4026 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4027 const CHAR adirA[] = "C:\\sidlfpdir";
4028 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4030 LPITEMIDLIST pidl = NULL;
4032 if(!pSHSimpleIDListFromPathAW){
4033 win_skip("SHSimpleIDListFromPathAW not available\n");
4034 return;
4037 br = CreateDirectoryA(adirA, NULL);
4038 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4040 if(is_unicode)
4041 pidl = pSHSimpleIDListFromPathAW(adirW);
4042 else
4043 pidl = pSHSimpleIDListFromPathAW(adirA);
4044 verify_pidl(pidl, adirW);
4045 pILFree(pidl);
4047 br = RemoveDirectoryA(adirA);
4048 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4050 if(is_unicode)
4051 pidl = pSHSimpleIDListFromPathAW(adirW);
4052 else
4053 pidl = pSHSimpleIDListFromPathAW(adirA);
4054 verify_pidl(pidl, adirW);
4055 pILFree(pidl);
4058 /* IFileSystemBindData impl */
4059 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4060 REFIID riid, void **ppv)
4062 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4063 IsEqualIID(riid, &IID_IUnknown)){
4064 *ppv = fsbd;
4065 return S_OK;
4067 return E_NOINTERFACE;
4070 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4072 return 2;
4075 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4077 return 1;
4080 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4081 const WIN32_FIND_DATAW *pfd)
4083 ok(0, "SetFindData called\n");
4084 return E_NOTIMPL;
4087 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4088 WIN32_FIND_DATAW *pfd)
4090 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4091 return S_OK;
4094 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4095 WIN32_FIND_DATAW *pfd)
4097 memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4098 return S_OK;
4101 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4102 WIN32_FIND_DATAW *pfd)
4104 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4105 *pfd->cFileName = 'a';
4106 *pfd->cAlternateFileName = 'a';
4107 return S_OK;
4110 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4111 WIN32_FIND_DATAW *pfd)
4113 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4114 HANDLE handle = FindFirstFileW(adirW, pfd);
4115 FindClose(handle);
4116 return S_OK;
4119 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4120 WIN32_FIND_DATAW *pfd)
4122 return E_FAIL;
4125 static IFileSystemBindDataVtbl fsbdVtbl = {
4126 fsbd_QueryInterface,
4127 fsbd_AddRef,
4128 fsbd_Release,
4129 fsbd_SetFindData,
4130 NULL
4133 static IFileSystemBindData fsbd = { &fsbdVtbl };
4135 static void test_ParseDisplayNamePBC(void)
4137 WCHAR wFileSystemBindData[] =
4138 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4139 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4140 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4141 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4142 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4144 IShellFolder *psf;
4145 IBindCtx *pbc;
4146 HRESULT hres;
4147 ITEMIDLIST *pidl;
4149 /* Check if we support WCHAR functions */
4150 SetLastError(0xdeadbeef);
4151 lstrcmpiW(adirW, adirW);
4152 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4153 win_skip("Most W-calls are not implemented\n");
4154 return;
4157 hres = SHGetDesktopFolder(&psf);
4158 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4159 if(FAILED(hres)){
4160 win_skip("Failed to get IShellFolder, can't run tests\n");
4161 return;
4164 /* fails on unknown dir with no IBindCtx */
4165 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4166 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4167 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4168 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4169 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4170 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4171 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4172 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4173 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4175 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4176 hres = CreateBindCtx(0, &pbc);
4177 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4179 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4180 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4181 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4182 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4183 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4184 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4185 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4186 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4187 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4189 /* unknown dir with IBindCtx with IFileSystemBindData */
4190 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4191 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4193 /* return E_FAIL from GetFindData */
4194 pidl = (ITEMIDLIST*)0xdeadbeef;
4195 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4196 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4197 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4198 "ParseDisplayName failed: 0x%08x\n", hres);
4199 if(SUCCEEDED(hres)){
4200 verify_pidl(pidl, adirW);
4201 ILFree(pidl);
4204 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4205 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4206 "ParseDisplayName failed: 0x%08x\n", hres);
4207 if(SUCCEEDED(hres)){
4208 verify_pidl(pidl, afileW);
4209 ILFree(pidl);
4212 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4213 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4214 "ParseDisplayName failed: 0x%08x\n", hres);
4215 if(SUCCEEDED(hres)){
4216 verify_pidl(pidl, afile2W);
4217 ILFree(pidl);
4220 /* set FIND_DATA struct to NULLs */
4221 pidl = (ITEMIDLIST*)0xdeadbeef;
4222 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4223 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4224 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4225 "ParseDisplayName failed: 0x%08x\n", hres);
4226 if(SUCCEEDED(hres)){
4227 verify_pidl(pidl, adirW);
4228 ILFree(pidl);
4231 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4232 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4233 "ParseDisplayName failed: 0x%08x\n", hres);
4234 if(SUCCEEDED(hres)){
4235 verify_pidl(pidl, afileW);
4236 ILFree(pidl);
4239 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4240 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4241 "ParseDisplayName failed: 0x%08x\n", hres);
4242 if(SUCCEEDED(hres)){
4243 verify_pidl(pidl, afile2W);
4244 ILFree(pidl);
4247 /* set FIND_DATA struct to junk */
4248 pidl = (ITEMIDLIST*)0xdeadbeef;
4249 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4250 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4251 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4252 "ParseDisplayName failed: 0x%08x\n", hres);
4253 if(SUCCEEDED(hres)){
4254 verify_pidl(pidl, adirW);
4255 ILFree(pidl);
4258 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4259 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4260 "ParseDisplayName failed: 0x%08x\n", hres);
4261 if(SUCCEEDED(hres)){
4262 verify_pidl(pidl, afileW);
4263 ILFree(pidl);
4266 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4267 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4268 "ParseDisplayName failed: 0x%08x\n", hres);
4269 if(SUCCEEDED(hres)){
4270 verify_pidl(pidl, afile2W);
4271 ILFree(pidl);
4274 /* set FIND_DATA struct to invalid data */
4275 pidl = (ITEMIDLIST*)0xdeadbeef;
4276 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4277 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4278 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4279 "ParseDisplayName failed: 0x%08x\n", hres);
4280 if(SUCCEEDED(hres)){
4281 verify_pidl(pidl, adirW);
4282 ILFree(pidl);
4285 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4286 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4287 "ParseDisplayName failed: 0x%08x\n", hres);
4288 if(SUCCEEDED(hres)){
4289 verify_pidl(pidl, afileW);
4290 ILFree(pidl);
4293 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4294 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4295 "ParseDisplayName failed: 0x%08x\n", hres);
4296 if(SUCCEEDED(hres)){
4297 verify_pidl(pidl, afile2W);
4298 ILFree(pidl);
4301 /* set FIND_DATA struct to valid data */
4302 pidl = (ITEMIDLIST*)0xdeadbeef;
4303 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4304 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4305 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4306 "ParseDisplayName failed: 0x%08x\n", hres);
4307 if(SUCCEEDED(hres)){
4308 verify_pidl(pidl, adirW);
4309 ILFree(pidl);
4312 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4313 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4314 "ParseDisplayName failed: 0x%08x\n", hres);
4315 if(SUCCEEDED(hres)){
4316 verify_pidl(pidl, afileW);
4317 ILFree(pidl);
4320 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4321 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4322 "ParseDisplayName failed: 0x%08x\n", hres);
4323 if(SUCCEEDED(hres)){
4324 verify_pidl(pidl, afile2W);
4325 ILFree(pidl);
4328 IBindCtx_Release(pbc);
4329 IShellFolder_Release(psf);
4332 static const CHAR testwindow_class[] = "testwindow";
4333 #define WM_USER_NOTIFY (WM_APP+1)
4335 struct ChNotifyTest {
4336 const char id[256];
4337 const UINT notify_count;
4338 UINT missing_events;
4339 UINT signal;
4340 const char path_1[256];
4341 const char path_2[256];
4342 } chnotify_tests[] = {
4343 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4344 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4345 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4348 struct ChNotifyTest *exp_data;
4349 BOOL test_new_delivery_flag;
4351 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4353 LONG signal = (LONG)lparam;
4355 switch(msg){
4356 case WM_USER_NOTIFY:
4357 if(exp_data->missing_events > 0) {
4358 WCHAR *path1, *path2;
4359 LPITEMIDLIST *pidls = (LPITEMIDLIST*)wparam;
4360 HANDLE hLock = NULL;
4362 if(test_new_delivery_flag) {
4363 hLock = SHChangeNotification_Lock((HANDLE)wparam, lparam, &pidls, &signal);
4364 ok(hLock != NULL, "SHChangeNotification_Lock returned NULL\n");
4367 ok(exp_data->signal == signal,
4368 "%s: expected notification type %x, got: %x\n",
4369 exp_data->id, exp_data->signal, signal);
4371 trace("verifying pidls for: %s\n", exp_data->id);
4372 path1 = make_wstr(exp_data->path_1);
4373 path2 = make_wstr(exp_data->path_2);
4374 verify_pidl(pidls[0], path1);
4375 verify_pidl(pidls[1], path2);
4376 HeapFree(GetProcessHeap(), 0, path1);
4377 HeapFree(GetProcessHeap(), 0, path2);
4379 exp_data->missing_events--;
4381 if(test_new_delivery_flag)
4382 SHChangeNotification_Unlock(hLock);
4383 }else
4384 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4385 return 0;
4387 return DefWindowProc(hwnd, msg, wparam, lparam);
4390 static void register_testwindow_class(void)
4392 WNDCLASSEXA cls;
4393 ATOM ret;
4395 ZeroMemory(&cls, sizeof(cls));
4396 cls.cbSize = sizeof(cls);
4397 cls.style = 0;
4398 cls.lpfnWndProc = testwindow_wndproc;
4399 cls.hInstance = GetModuleHandleA(NULL);
4400 cls.lpszClassName = testwindow_class;
4402 SetLastError(0);
4403 ret = RegisterClassExA(&cls);
4404 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4407 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4408 * have to poll repeatedly for the message to appear */
4409 static void do_events(void)
4411 int c = 0;
4412 while (exp_data->missing_events && (c++ < 10)){
4413 MSG msg;
4414 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4415 TranslateMessage(&msg);
4416 DispatchMessageA(&msg);
4418 if(exp_data->missing_events)
4419 Sleep(500);
4421 trace("%s: took %d tries\n", exp_data->id, c);
4424 static void test_SHChangeNotify(BOOL test_new_delivery)
4426 HWND wnd;
4427 ULONG notifyID, i;
4428 HRESULT hr;
4429 BOOL br, has_unicode;
4430 SHChangeNotifyEntry entries[1];
4431 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4432 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4434 trace("SHChangeNotify tests (%x)\n", test_new_delivery);
4436 CreateDirectoryW(NULL, NULL);
4437 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4439 test_new_delivery_flag = test_new_delivery;
4440 if(!test_new_delivery)
4441 register_testwindow_class();
4443 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4444 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4445 NULL, NULL, GetModuleHandleA(NULL), 0);
4446 ok(wnd != NULL, "Failed to make a window\n");
4448 br = CreateDirectoryA(root_dirA, NULL);
4449 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4451 entries[0].pidl = NULL;
4452 if(has_unicode)
4453 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4454 else
4455 hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4456 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4457 entries[0].fRecursive = TRUE;
4459 notifyID = SHChangeNotifyRegister(wnd, !test_new_delivery ? SHCNRF_ShellLevel : SHCNRF_ShellLevel|SHCNRF_NewDelivery,
4460 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4461 ok(notifyID != 0, "Failed to register a window for change notifications\n");
4463 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
4464 exp_data = chnotify_tests + i;
4466 exp_data->missing_events = exp_data->notify_count;
4467 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4468 strlen(exp_data->path_1) > 0 ? exp_data->path_1 : NULL,
4469 strlen(exp_data->path_2) > 0 ? exp_data->path_2 : NULL);
4470 do_events();
4471 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4473 if(has_unicode){
4474 WCHAR *path1, *path2;
4476 path1 = make_wstr(exp_data->path_1);
4477 path2 = make_wstr(exp_data->path_2);
4479 exp_data->missing_events = exp_data->notify_count;
4480 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
4481 do_events();
4482 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4484 HeapFree(GetProcessHeap(), 0, path1);
4485 HeapFree(GetProcessHeap(), 0, path2);
4489 SHChangeNotifyDeregister(notifyID);
4490 DestroyWindow(wnd);
4492 ILFree((LPITEMIDLIST)entries[0].pidl);
4493 br = RemoveDirectoryA(root_dirA);
4494 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4497 static void test_SHCreateDefaultContextMenu(void)
4499 HKEY keys[16];
4500 WCHAR path[MAX_PATH];
4501 IShellFolder *desktop,*folder;
4502 IPersistFolder2 *persist;
4503 IContextMenu *cmenu;
4504 LONG status;
4505 LPITEMIDLIST pidlFolder, pidl_child, pidl;
4506 DEFCONTEXTMENU cminfo;
4507 HRESULT hr;
4508 UINT i;
4509 const WCHAR filename[] =
4510 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4511 if(!pSHCreateDefaultContextMenu)
4513 win_skip("SHCreateDefaultContextMenu missing.\n");
4514 return;
4517 if(!pSHBindToParent)
4519 skip("SHBindToParent missing.\n");
4520 return;
4523 GetCurrentDirectoryW(MAX_PATH, path);
4524 if(!lstrlenW(path))
4526 skip("GetCurrentDirectoryW returned an empty string.\n");
4527 return;
4529 lstrcatW(path, filename);
4530 SHGetDesktopFolder(&desktop);
4532 CreateFilesFolders();
4534 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &pidl, 0);
4535 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
4536 if(SUCCEEDED(hr))
4539 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&folder, (LPCITEMIDLIST*)&pidl_child);
4540 ok(hr == S_OK, "Got 0x%08x\n", hr);
4542 IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
4543 IPersistFolder2_GetCurFolder(persist,&pidlFolder);
4544 IPersistFolder2_Release(persist);
4545 if(SUCCEEDED(hr))
4548 cminfo.hwnd=NULL;
4549 cminfo.pcmcb=NULL;
4550 cminfo.psf=folder;
4551 cminfo.pidlFolder=NULL;
4552 cminfo.apidl=(LPCITEMIDLIST*)&pidl_child;
4553 cminfo.cidl=1;
4554 cminfo.aKeys=NULL;
4555 cminfo.cKeys=0;
4556 cminfo.punkAssociationInfo=NULL;
4557 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
4558 ok(hr==S_OK,"Got 0x%08x\n", hr);
4559 IContextMenu_Release(cmenu);
4560 cminfo.pidlFolder=pidlFolder;
4561 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
4562 ok(hr==S_OK,"Got 0x%08x\n", hr);
4563 IContextMenu_Release(cmenu);
4564 status = RegOpenKeyExA(HKEY_CLASSES_ROOT,"*",0,KEY_READ,keys);
4565 if(status==ERROR_SUCCESS){
4566 for(i=1;i<16;i++)
4567 keys[i]=keys[0];
4568 cminfo.aKeys=keys;
4569 cminfo.cKeys=16;
4570 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
4571 RegCloseKey(keys[0]);
4572 ok(hr==S_OK,"Got 0x%08x\n", hr);
4573 IContextMenu_Release(cmenu);
4576 ILFree(pidlFolder);
4577 IShellFolder_Release(folder);
4579 IShellFolder_Release(desktop);
4580 ILFree(pidl);
4581 Cleanup();
4584 START_TEST(shlfolder)
4586 init_function_pointers();
4587 /* if OleInitialize doesn't get called, ParseDisplayName returns
4588 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4589 OleInitialize(NULL);
4591 test_ParseDisplayName();
4592 test_SHParseDisplayName();
4593 test_BindToObject();
4594 test_EnumObjects_and_CompareIDs();
4595 test_GetDisplayName();
4596 test_GetAttributesOf();
4597 test_SHGetPathFromIDList();
4598 test_CallForAttributes();
4599 test_FolderShortcut();
4600 test_ITEMIDLIST_format();
4601 test_SHGetFolderPathA();
4602 test_SHGetFolderPathAndSubDirA();
4603 test_LocalizedNames();
4604 test_SHCreateShellItem();
4605 test_SHCreateShellItemArray();
4606 test_desktop_IPersist();
4607 test_GetUIObject();
4608 test_SHSimpleIDListFromPath();
4609 test_ParseDisplayNamePBC();
4610 test_SHGetNameFromIDList();
4611 test_SHGetItemFromDataObject();
4612 test_SHGetIDListFromObject();
4613 test_SHGetItemFromObject();
4614 test_ShellItemCompare();
4615 test_SHChangeNotify(FALSE);
4616 test_SHChangeNotify(TRUE);
4617 test_ShellItemBindToHandler();
4618 test_ShellItemGetAttributes();
4619 test_SHCreateDefaultContextMenu();
4621 OleUninitialize();