mshtml: Pass external connection to WebBrowser host, if possible.
[wine.git] / dlls / shell32 / tests / shlfolder.c
blob169426e27c4db136721212088043f47c2575c1db
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 const char *debugstr_guid(REFIID riid)
78 static char buf[50];
80 sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
81 riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
82 riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
83 riid->Data4[5], riid->Data4[6], riid->Data4[7]);
85 return buf;
88 static WCHAR *make_wstr(const char *str)
90 WCHAR *ret;
91 int len;
93 if(!str || strlen(str) == 0)
94 return NULL;
96 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
97 if(!len || len < 0)
98 return NULL;
100 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
101 if(!ret)
102 return NULL;
104 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
105 return ret;
108 static int strcmp_wa(LPCWSTR strw, const char *stra)
110 CHAR buf[512];
111 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
112 return lstrcmpA(stra, buf);
115 static void init_function_pointers(void)
117 HMODULE hmod;
118 HRESULT hr;
119 void *ptr;
121 hmod = GetModuleHandleA("shell32.dll");
123 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
124 MAKEFUNC(SHBindToParent);
125 MAKEFUNC(SHCreateItemFromIDList);
126 MAKEFUNC(SHCreateItemFromParsingName);
127 MAKEFUNC(SHCreateShellItem);
128 MAKEFUNC(SHCreateShellItemArray);
129 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
130 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
131 MAKEFUNC(SHGetFolderPathA);
132 MAKEFUNC(SHGetFolderPathAndSubDirA);
133 MAKEFUNC(SHGetPathFromIDListW);
134 MAKEFUNC(SHGetSpecialFolderPathA);
135 MAKEFUNC(SHGetSpecialFolderPathW);
136 MAKEFUNC(SHGetSpecialFolderLocation);
137 MAKEFUNC(SHParseDisplayName);
138 MAKEFUNC(SHGetNameFromIDList);
139 MAKEFUNC(SHGetItemFromDataObject);
140 MAKEFUNC(SHGetIDListFromObject);
141 MAKEFUNC(SHGetItemFromObject);
142 MAKEFUNC(SHCreateDefaultContextMenu);
143 #undef MAKEFUNC
145 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
146 MAKEFUNC_ORD(ILFindLastID, 16);
147 MAKEFUNC_ORD(ILIsEqual, 21);
148 MAKEFUNC_ORD(ILCombine, 25);
149 MAKEFUNC_ORD(ILFree, 155);
150 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
151 #undef MAKEFUNC_ORD
153 /* test named exports */
154 ptr = GetProcAddress(hmod, "ILFree");
155 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
156 if (ptr)
158 #define TESTNAMED(f) \
159 ptr = (void*)GetProcAddress(hmod, #f); \
160 ok(ptr != 0, "expected named export for " #f "\n");
162 TESTNAMED(ILAppendID);
163 TESTNAMED(ILClone);
164 TESTNAMED(ILCloneFirst);
165 TESTNAMED(ILCombine);
166 TESTNAMED(ILCreateFromPath);
167 TESTNAMED(ILCreateFromPathA);
168 TESTNAMED(ILCreateFromPathW);
169 TESTNAMED(ILFindChild);
170 TESTNAMED(ILFindLastID);
171 TESTNAMED(ILGetNext);
172 TESTNAMED(ILGetSize);
173 TESTNAMED(ILIsEqual);
174 TESTNAMED(ILIsParent);
175 TESTNAMED(ILRemoveLastID);
176 TESTNAMED(ILSaveToStream);
177 #undef TESTNAMED
180 hmod = GetModuleHandleA("shlwapi.dll");
181 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
183 hmod = GetModuleHandleA("kernel32.dll");
184 pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
185 pGetSystemWow64DirectoryW = (void*)GetProcAddress(hmod, "GetSystemWow64DirectoryW");
187 hr = SHGetMalloc(&ppM);
188 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
191 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
192 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
194 size_t iLen;
196 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
197 return NULL;
199 if (iLen)
201 lpszPath += iLen;
202 if (lpszPath[-1] != '\\')
204 *lpszPath++ = '\\';
205 *lpszPath = '\0';
208 return lpszPath;
211 static void test_ParseDisplayName(void)
213 HRESULT hr;
214 IShellFolder *IDesktopFolder;
215 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
216 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
217 static const char *cInetTestA = "http:\\yyy";
218 static const char *cInetTest2A = "xx:yyy";
219 DWORD res;
220 WCHAR cTestDirW [MAX_PATH] = {0};
221 ITEMIDLIST *newPIDL;
222 BOOL bRes;
224 hr = SHGetDesktopFolder(&IDesktopFolder);
225 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
226 if(hr != S_OK) return;
228 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
229 if (pSHCreateShellItem)
231 /* null name and pidl */
232 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
233 NULL, NULL, NULL, NULL, NULL, 0);
234 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
236 /* null name */
237 newPIDL = (ITEMIDLIST*)0xdeadbeef;
238 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
239 NULL, NULL, NULL, NULL, &newPIDL, 0);
240 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
241 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
243 else
244 win_skip("Tests would crash on W2K and below\n");
246 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -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 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
259 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
260 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
261 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
262 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
263 if (hr == S_OK)
265 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
266 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
267 IMalloc_Free(ppM, newPIDL);
270 res = GetFileAttributesA(cNonExistDir1A);
271 if(res != INVALID_FILE_ATTRIBUTES)
273 skip("Test directory unexpectedly exists\n");
274 goto finished;
277 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
278 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
279 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
280 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
281 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
283 res = GetFileAttributesA(cNonExistDir2A);
284 if(res != INVALID_FILE_ATTRIBUTES)
286 skip("Test directory unexpectedly exists\n");
287 goto finished;
290 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
291 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
292 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
293 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
294 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
296 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
297 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
298 * out it doesn't. The magic seems to happen in the file dialogs, then. */
299 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
301 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
302 goto finished;
305 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
306 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
307 if (!bRes) goto finished;
309 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
310 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
311 if (hr != S_OK) goto finished;
313 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
314 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
315 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
316 pILFindLastID(newPIDL)->mkid.abID[0]);
317 IMalloc_Free(ppM, newPIDL);
319 finished:
320 IShellFolder_Release(IDesktopFolder);
323 /* creates a file with the specified name for tests */
324 static void CreateTestFile(const CHAR *name)
326 HANDLE file;
327 DWORD written;
329 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
330 if (file != INVALID_HANDLE_VALUE)
332 WriteFile(file, name, strlen(name), &written, NULL);
333 WriteFile(file, "\n", strlen("\n"), &written, NULL);
334 CloseHandle(file);
339 /* initializes the tests */
340 static void CreateFilesFolders(void)
342 CreateDirectoryA(".\\testdir", NULL);
343 CreateDirectoryA(".\\testdir\\test.txt", NULL);
344 CreateTestFile (".\\testdir\\test1.txt ");
345 CreateTestFile (".\\testdir\\test2.txt ");
346 CreateTestFile (".\\testdir\\test3.txt ");
347 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
348 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
351 /* cleans after tests */
352 static void Cleanup(void)
354 DeleteFileA(".\\testdir\\test1.txt");
355 DeleteFileA(".\\testdir\\test2.txt");
356 DeleteFileA(".\\testdir\\test3.txt");
357 RemoveDirectoryA(".\\testdir\\test.txt");
358 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
359 RemoveDirectoryA(".\\testdir\\testdir2");
360 RemoveDirectoryA(".\\testdir");
364 /* perform test */
365 static void test_EnumObjects(IShellFolder *iFolder)
367 IEnumIDList *iEnumList;
368 LPITEMIDLIST newPIDL, idlArr[10];
369 ULONG NumPIDLs;
370 int i=0, j;
371 HRESULT hr;
373 static const WORD iResults [5][5] =
375 { 0,-1,-1,-1,-1},
376 { 1, 0,-1,-1,-1},
377 { 1, 1, 0,-1,-1},
378 { 1, 1, 1, 0,-1},
379 { 1, 1, 1, 1, 0}
382 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
383 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
384 static const ULONG attrs[5] =
386 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
387 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
388 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
389 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
390 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
393 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
394 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
396 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
397 * the filesystem shellfolders return S_OK even if less than 'celt' items are
398 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
399 * only ever returns a single entry per call. */
400 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
401 i += NumPIDLs;
402 ok (i == 5, "i: %d\n", i);
404 hr = IEnumIDList_Release(iEnumList);
405 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
407 /* Sort them first in case of wrong order from system */
408 for (i=0;i<5;i++) for (j=0;j<5;j++)
409 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
411 newPIDL = idlArr[i];
412 idlArr[i] = idlArr[j];
413 idlArr[j] = newPIDL;
416 for (i=0;i<5;i++) for (j=0;j<5;j++)
418 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
419 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
423 for (i = 0; i < 5; i++)
425 SFGAOF flags;
426 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
427 /* Native returns all flags no matter what we ask for */
428 flags = SFGAO_CANCOPY;
429 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
430 flags &= SFGAO_testfor;
431 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
432 ok(flags == (attrs[i]) ||
433 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
434 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
435 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
437 flags = SFGAO_testfor;
438 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
439 flags &= SFGAO_testfor;
440 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
441 ok(flags == attrs[i] ||
442 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
443 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
446 for (i=0;i<5;i++)
447 IMalloc_Free(ppM, idlArr[i]);
450 static void test_BindToObject(void)
452 HRESULT hr;
453 UINT cChars;
454 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
455 SHITEMID emptyitem = { 0, { 0 } };
456 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
457 WCHAR wszSystemDir[MAX_PATH];
458 char szSystemDir[MAX_PATH];
459 char buf[MAX_PATH];
460 WCHAR path[MAX_PATH];
461 CHAR pathA[MAX_PATH];
462 HANDLE hfile;
463 WCHAR wszMyComputer[] = {
464 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
465 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
466 static const CHAR filename_html[] = "winetest.html";
467 static const CHAR filename_txt[] = "winetest.txt";
468 static const CHAR filename_foo[] = "winetest.foo";
470 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
471 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
473 hr = SHGetDesktopFolder(&psfDesktop);
474 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
475 if (hr != S_OK) return;
477 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
478 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
480 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
481 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
483 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
484 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
485 if (hr != S_OK) {
486 IShellFolder_Release(psfDesktop);
487 return;
490 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
491 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
492 IShellFolder_Release(psfDesktop);
493 IMalloc_Free(ppM, pidlMyComputer);
494 if (hr != S_OK) return;
496 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
497 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
499 if (0)
501 /* this call segfaults on 98SE */
502 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
503 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
506 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
507 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
508 if (cChars == 0 || cChars >= MAX_PATH) {
509 IShellFolder_Release(psfMyComputer);
510 return;
512 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
514 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
515 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
516 if (hr != S_OK) {
517 IShellFolder_Release(psfMyComputer);
518 return;
521 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
522 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
523 IShellFolder_Release(psfMyComputer);
524 IMalloc_Free(ppM, pidlSystemDir);
525 if (hr != S_OK) return;
527 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
528 ok (hr == E_INVALIDARG,
529 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
531 if (0)
533 /* this call segfaults on 98SE */
534 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
535 ok (hr == E_INVALIDARG,
536 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
539 IShellFolder_Release(psfSystemDir);
541 GetCurrentDirectoryA(MAX_PATH, buf);
542 if(!lstrlenA(buf))
544 skip("Failed to get current directory, skipping tests.\n");
545 return;
548 SHGetDesktopFolder(&psfDesktop);
550 /* Attempt BindToObject on files. */
552 /* .html */
553 lstrcpyA(pathA, buf);
554 lstrcatA(pathA, "\\");
555 lstrcatA(pathA, filename_html);
556 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
557 if(hfile != INVALID_HANDLE_VALUE)
559 CloseHandle(hfile);
560 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
561 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
562 ok(hr == S_OK, "Got 0x%08x\n", hr);
563 if(SUCCEEDED(hr))
565 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
566 ok(hr == S_OK ||
567 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
568 "Got 0x%08x\n", hr);
569 if(SUCCEEDED(hr))
571 IPersist *pp;
572 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
573 ok(hr == S_OK ||
574 broken(hr == E_NOINTERFACE), /* Win9x, NT4, W2K */
575 "Got 0x%08x\n", hr);
576 if(SUCCEEDED(hr))
578 CLSID id;
579 hr = IPersist_GetClassID(pp, &id);
580 ok(hr == S_OK, "Got 0x%08x\n", hr);
581 /* CLSID_ShellFSFolder on some w2k systems */
582 ok(IsEqualIID(&id, &CLSID_ShellDocObjView) || broken(IsEqualIID(&id, &CLSID_ShellFSFolder)),
583 "Unexpected classid %s\n", debugstr_guid(&id));
584 IPersist_Release(pp);
587 IShellFolder_Release(psfChild);
589 pILFree(pidl);
591 DeleteFileA(pathA);
593 else
594 win_skip("Failed to create .html testfile.\n");
596 /* .txt */
597 lstrcpyA(pathA, buf);
598 lstrcatA(pathA, "\\");
599 lstrcatA(pathA, filename_txt);
600 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
601 if(hfile != INVALID_HANDLE_VALUE)
603 CloseHandle(hfile);
604 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
605 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
606 ok(hr == S_OK, "Got 0x%08x\n", hr);
607 if(SUCCEEDED(hr))
609 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
610 ok(hr == E_FAIL || /* Vista+ */
611 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
612 broken(hr == S_OK), /* Win9x, NT4, W2K */
613 "Got 0x%08x\n", hr);
614 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
615 pILFree(pidl);
617 DeleteFileA(pathA);
619 else
620 win_skip("Failed to create .txt testfile.\n");
622 /* .foo */
623 lstrcpyA(pathA, buf);
624 lstrcatA(pathA, "\\");
625 lstrcatA(pathA, filename_foo);
626 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
627 if(hfile != INVALID_HANDLE_VALUE)
629 CloseHandle(hfile);
630 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
631 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
632 ok(hr == S_OK, "Got 0x%08x\n", hr);
633 if(SUCCEEDED(hr))
635 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
636 ok(hr == E_FAIL || /* Vista+ */
637 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
638 broken(hr == S_OK), /* Win9x, NT4, W2K */
639 "Got 0x%08x\n", hr);
640 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
641 pILFree(pidl);
643 DeleteFileA(pathA);
645 else
646 win_skip("Failed to create .foo testfile.\n");
648 /* And on the desktop */
649 if(pSHGetSpecialFolderPathA)
651 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
652 lstrcatA(pathA, "\\");
653 lstrcatA(pathA, filename_html);
654 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
655 if(hfile != INVALID_HANDLE_VALUE)
657 CloseHandle(hfile);
658 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
659 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
660 ok(hr == S_OK, "Got 0x%08x\n", hr);
661 if(SUCCEEDED(hr))
663 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
664 ok(hr == S_OK ||
665 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
666 "Got 0x%08x\n", hr);
667 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
668 pILFree(pidl);
670 if(!DeleteFileA(pathA))
671 trace("Failed to delete: %d\n", GetLastError());
674 else
675 win_skip("Failed to create .html testfile.\n");
677 pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
678 lstrcatA(pathA, "\\");
679 lstrcatA(pathA, filename_foo);
680 hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
681 if(hfile != INVALID_HANDLE_VALUE)
683 CloseHandle(hfile);
684 MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
685 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
686 ok(hr == S_OK, "Got 0x%08x\n", hr);
687 if(SUCCEEDED(hr))
689 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
690 ok(hr == E_FAIL || /* Vista+ */
691 hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
692 broken(hr == S_OK), /* Win9x, NT4, W2K */
693 "Got 0x%08x\n", hr);
694 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
695 pILFree(pidl);
697 DeleteFileA(pathA);
699 else
700 win_skip("Failed to create .foo testfile.\n");
703 IShellFolder_Release(psfDesktop);
706 static void test_GetDisplayName(void)
708 BOOL result;
709 HRESULT hr;
710 HANDLE hTestFile;
711 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
712 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
713 DWORD attr;
714 STRRET strret;
715 LPSHELLFOLDER psfDesktop, psfPersonal;
716 IUnknown *psfFile;
717 SHITEMID emptyitem = { 0, { 0 } };
718 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
719 LPCITEMIDLIST pidlLast;
720 static const CHAR szFileName[] = "winetest.foo";
721 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
722 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
724 /* I'm trying to figure if there is a functional difference between calling
725 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
726 * binding to the shellfolder. One thing I thought of was that perhaps
727 * SHGetPathFromIDListW would be able to get the path to a file, which does
728 * not exist anymore, while the other method wouldn't. It turns out there's
729 * no functional difference in this respect.
732 if(!pSHGetSpecialFolderPathA) {
733 win_skip("SHGetSpecialFolderPathA is not available\n");
734 return;
737 /* First creating a directory in MyDocuments and a file in this directory. */
738 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
739 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
740 if (!result) return;
742 /* Use ANSI file functions so this works on Windows 9x */
743 lstrcatA(szTestDir, "\\winetest");
744 CreateDirectoryA(szTestDir, NULL);
745 attr=GetFileAttributesA(szTestDir);
746 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
748 ok(0, "unable to create the '%s' directory\n", szTestDir);
749 return;
752 lstrcpyA(szTestFile, szTestDir);
753 lstrcatA(szTestFile, "\\");
754 lstrcatA(szTestFile, szFileName);
755 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
756 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
757 if (hTestFile == INVALID_HANDLE_VALUE) return;
758 CloseHandle(hTestFile);
760 /* Getting an itemidlist for the file. */
761 hr = SHGetDesktopFolder(&psfDesktop);
762 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
763 if (hr != S_OK) return;
765 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
767 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
768 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
769 if (hr != S_OK) {
770 IShellFolder_Release(psfDesktop);
771 return;
774 pidlLast = pILFindLastID(pidlTestFile);
775 ok(pidlLast->mkid.cb >=76 ||
776 broken(pidlLast->mkid.cb == 28) || /* W2K */
777 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
778 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
779 if (pidlLast->mkid.cb >= 28) {
780 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
781 "Filename should be stored as ansi-string at this position!\n");
783 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
784 if (pidlLast->mkid.cb >= 76) {
785 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
786 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
787 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
788 "Filename should be stored as wchar-string at this position!\n");
791 /* It seems as if we cannot bind to regular files on windows, but only directories.
793 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
794 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
795 hr == E_NOTIMPL || /* Vista */
796 broken(hr == S_OK), /* Win9x, W2K */
797 "hr = %08x\n", hr);
798 if (hr == S_OK) {
799 IUnknown_Release(psfFile);
802 if (!pSHBindToParent)
804 win_skip("SHBindToParent is missing\n");
805 DeleteFileA(szTestFile);
806 RemoveDirectoryA(szTestDir);
807 return;
810 /* Some tests for IShellFolder::SetNameOf */
811 if (pSHGetFolderPathAndSubDirA)
813 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
814 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
815 if (hr == S_OK) {
816 /* It's ok to use this fixed path. Call will fail anyway. */
817 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
818 LPITEMIDLIST pidlNew;
820 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
821 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
822 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
823 if (hr == S_OK)
825 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
826 "pidl returned from SetNameOf should be simple!\n");
828 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
829 * is implemented on top of SHFileOperation in WinXP. */
830 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
831 SHGDN_FORPARSING, NULL);
832 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
834 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
835 * SHGDN flags specify an absolute path. */
836 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
837 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
839 pILFree(pidlNew);
842 IShellFolder_Release(psfPersonal);
845 else
846 win_skip("Avoid needs of interaction on Win2k\n");
848 /* Deleting the file and the directory */
849 DeleteFileA(szTestFile);
850 RemoveDirectoryA(szTestDir);
852 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
853 if (pSHGetPathFromIDListW)
855 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
856 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
857 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
860 /* SHBindToParent fails, if called with a NULL PIDL. */
861 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
862 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
864 /* But it succeeds with an empty PIDL. */
865 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
866 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
867 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
868 if (hr == S_OK)
869 IShellFolder_Release(psfPersonal);
871 /* Binding to the folder and querying the display name of the file also works. */
872 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
873 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
874 if (hr != S_OK) {
875 IShellFolder_Release(psfDesktop);
876 return;
879 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
880 * pidlTestFile (In accordance with MSDN). */
881 ok (pILFindLastID(pidlTestFile) == pidlLast,
882 "SHBindToParent doesn't return the last id of the pidl param!\n");
884 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
885 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
886 if (hr != S_OK) {
887 IShellFolder_Release(psfDesktop);
888 IShellFolder_Release(psfPersonal);
889 return;
892 if (pStrRetToBufW)
894 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
895 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
896 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
899 ILFree(pidlTestFile);
900 IShellFolder_Release(psfDesktop);
901 IShellFolder_Release(psfPersonal);
904 static void test_CallForAttributes(void)
906 HKEY hKey;
907 LONG lResult;
908 HRESULT hr;
909 DWORD dwSize;
910 LPSHELLFOLDER psfDesktop;
911 LPITEMIDLIST pidlMyDocuments;
912 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
913 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
914 static const WCHAR wszCallForAttributes[] = {
915 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
916 static const WCHAR wszMyDocumentsKey[] = {
917 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
918 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
919 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
920 WCHAR wszMyDocuments[] = {
921 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
922 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
924 /* For the root of a namespace extension, the attributes are not queried by binding
925 * to the object and calling GetAttributesOf. Instead, the attributes are read from
926 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
928 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
929 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
930 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
931 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
933 hr = SHGetDesktopFolder(&psfDesktop);
934 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
935 if (hr != S_OK) return;
937 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
938 &pidlMyDocuments, NULL);
939 ok (hr == S_OK ||
940 broken(hr == E_INVALIDARG), /* Win95, NT4 */
941 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
942 if (hr != S_OK) {
943 IShellFolder_Release(psfDesktop);
944 return;
947 dwAttributes = 0xffffffff;
948 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
949 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
950 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
952 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
953 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
954 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
955 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
957 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
958 * key. So the test will return at this point, if run on wine.
960 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
961 ok (lResult == ERROR_SUCCESS ||
962 lResult == ERROR_ACCESS_DENIED,
963 "RegOpenKeyEx failed! result: %08x\n", lResult);
964 if (lResult != ERROR_SUCCESS) {
965 if (lResult == ERROR_ACCESS_DENIED)
966 skip("Not enough rights to open the registry key\n");
967 IMalloc_Free(ppM, pidlMyDocuments);
968 IShellFolder_Release(psfDesktop);
969 return;
972 /* Query MyDocuments' Attributes value, to be able to restore it later. */
973 dwSize = sizeof(DWORD);
974 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
975 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
976 if (lResult != ERROR_SUCCESS) {
977 RegCloseKey(hKey);
978 IMalloc_Free(ppM, pidlMyDocuments);
979 IShellFolder_Release(psfDesktop);
980 return;
983 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
984 dwSize = sizeof(DWORD);
985 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
986 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
987 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
988 if (lResult != ERROR_SUCCESS) {
989 RegCloseKey(hKey);
990 IMalloc_Free(ppM, pidlMyDocuments);
991 IShellFolder_Release(psfDesktop);
992 return;
995 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
996 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
997 * SFGAO_FILESYSTEM attributes. */
998 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
999 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
1000 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
1001 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1002 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
1004 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
1005 * GetAttributesOf. It seems that once there is a single attribute queried, for which
1006 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
1007 * the flags in Attributes are ignored.
1009 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
1010 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
1011 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
1012 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
1013 if (hr == S_OK)
1014 ok (dwAttributes == SFGAO_FILESYSTEM,
1015 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
1016 dwAttributes);
1018 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
1019 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
1020 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
1021 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
1022 RegCloseKey(hKey);
1023 IMalloc_Free(ppM, pidlMyDocuments);
1024 IShellFolder_Release(psfDesktop);
1027 static void test_GetAttributesOf(void)
1029 HRESULT hr;
1030 LPSHELLFOLDER psfDesktop, psfMyComputer;
1031 SHITEMID emptyitem = { 0, { 0 } };
1032 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1033 LPITEMIDLIST pidlMyComputer;
1034 DWORD dwFlags;
1035 static const DWORD desktopFlags[] = {
1036 /* WinXP */
1037 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
1038 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1039 /* Win2k */
1040 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
1041 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1042 /* WinMe, Win9x, WinNT*/
1043 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
1044 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1046 static const DWORD myComputerFlags[] = {
1047 /* WinXP */
1048 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
1049 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1050 /* Win2k */
1051 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
1052 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1053 /* WinMe, Win9x, WinNT */
1054 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1055 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1056 /* Win95, WinNT when queried directly */
1057 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1058 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1060 WCHAR wszMyComputer[] = {
1061 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1062 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1063 char cCurrDirA [MAX_PATH] = {0};
1064 WCHAR cCurrDirW [MAX_PATH];
1065 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
1066 IShellFolder *IDesktopFolder, *testIShellFolder;
1067 ITEMIDLIST *newPIDL;
1068 int len, i;
1069 BOOL foundFlagsMatch;
1071 hr = SHGetDesktopFolder(&psfDesktop);
1072 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1073 if (hr != S_OK) return;
1075 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
1076 dwFlags = 0xffffffff;
1077 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
1078 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
1079 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1080 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1082 if (desktopFlags[i] == dwFlags)
1083 foundFlagsMatch = TRUE;
1085 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1087 /* .. or with no itemidlist at all. */
1088 dwFlags = 0xffffffff;
1089 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
1090 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1091 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1092 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1094 if (desktopFlags[i] == dwFlags)
1095 foundFlagsMatch = TRUE;
1097 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1099 /* Testing the attributes of the MyComputer shellfolder */
1100 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1101 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1102 if (hr != S_OK) {
1103 IShellFolder_Release(psfDesktop);
1104 return;
1107 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
1108 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
1110 dwFlags = 0xffffffff;
1111 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
1112 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
1113 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1114 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1116 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
1117 foundFlagsMatch = TRUE;
1119 todo_wine
1120 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1122 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
1123 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
1124 IShellFolder_Release(psfDesktop);
1125 IMalloc_Free(ppM, pidlMyComputer);
1126 if (hr != S_OK) return;
1128 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
1129 todo_wine
1130 ok (hr == E_INVALIDARG ||
1131 broken(hr == S_OK), /* W2K and earlier */
1132 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
1134 dwFlags = 0xffffffff;
1135 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
1136 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1137 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1138 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1140 if (myComputerFlags[i] == dwFlags)
1141 foundFlagsMatch = TRUE;
1143 todo_wine
1144 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1146 IShellFolder_Release(psfMyComputer);
1148 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1149 len = lstrlenA(cCurrDirA);
1151 if (len == 0) {
1152 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1153 return;
1155 if (len > 3 && cCurrDirA[len-1] == '\\')
1156 cCurrDirA[len-1] = 0;
1158 /* create test directory */
1159 CreateFilesFolders();
1161 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1163 hr = SHGetDesktopFolder(&IDesktopFolder);
1164 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1166 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1167 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1169 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1170 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1172 IMalloc_Free(ppM, newPIDL);
1174 /* get relative PIDL */
1175 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1176 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1178 /* test the shell attributes of the test directory using the relative PIDL */
1179 dwFlags = SFGAO_FOLDER;
1180 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1181 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1182 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1184 /* free memory */
1185 IMalloc_Free(ppM, newPIDL);
1187 /* append testdirectory name to path */
1188 if (cCurrDirA[len-1] == '\\')
1189 cCurrDirA[len-1] = 0;
1190 lstrcatA(cCurrDirA, "\\testdir");
1191 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1193 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1194 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1196 /* test the shell attributes of the test directory using the absolute PIDL */
1197 dwFlags = SFGAO_FOLDER;
1198 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1199 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1200 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1202 /* free memory */
1203 IMalloc_Free(ppM, newPIDL);
1205 IShellFolder_Release(testIShellFolder);
1207 Cleanup();
1209 IShellFolder_Release(IDesktopFolder);
1212 static void test_SHGetPathFromIDList(void)
1214 SHITEMID emptyitem = { 0, { 0 } };
1215 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1216 LPITEMIDLIST pidlMyComputer;
1217 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1218 BOOL result;
1219 HRESULT hr;
1220 LPSHELLFOLDER psfDesktop;
1221 WCHAR wszMyComputer[] = {
1222 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1223 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1224 WCHAR wszFileName[MAX_PATH];
1225 LPITEMIDLIST pidlTestFile;
1226 HANDLE hTestFile;
1227 STRRET strret;
1228 static WCHAR wszTestFile[] = {
1229 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1230 LPITEMIDLIST pidlPrograms;
1232 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1234 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1235 return;
1238 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1239 wszPath[0] = 'a';
1240 wszPath[1] = '\0';
1241 result = pSHGetPathFromIDListW(NULL, wszPath);
1242 ok(!result, "Expected failure\n");
1243 ok(!wszPath[0], "Expected empty string\n");
1245 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1246 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1247 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1248 if (!result) return;
1250 /* Check if we are on Win9x */
1251 SetLastError(0xdeadbeef);
1252 lstrcmpiW(wszDesktop, wszDesktop);
1253 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1255 win_skip("Most W-calls are not implemented\n");
1256 return;
1259 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1260 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1261 if (!result) return;
1262 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1264 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1265 hr = SHGetDesktopFolder(&psfDesktop);
1266 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1267 if (hr != S_OK) return;
1269 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1270 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1271 if (hr != S_OK) {
1272 IShellFolder_Release(psfDesktop);
1273 return;
1276 SetLastError(0xdeadbeef);
1277 wszPath[0] = 'a';
1278 wszPath[1] = '\0';
1279 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1280 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1281 ok (GetLastError()==0xdeadbeef ||
1282 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1283 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1284 ok (!wszPath[0], "Expected empty path\n");
1285 if (result) {
1286 IShellFolder_Release(psfDesktop);
1287 return;
1290 IMalloc_Free(ppM, pidlMyComputer);
1292 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1293 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1294 if (!result) {
1295 IShellFolder_Release(psfDesktop);
1296 return;
1298 myPathAddBackslashW(wszFileName);
1299 lstrcatW(wszFileName, wszTestFile);
1300 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1301 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1302 if (hTestFile == INVALID_HANDLE_VALUE) {
1303 IShellFolder_Release(psfDesktop);
1304 return;
1306 CloseHandle(hTestFile);
1308 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1309 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1310 if (hr != S_OK) {
1311 IShellFolder_Release(psfDesktop);
1312 DeleteFileW(wszFileName);
1313 IMalloc_Free(ppM, pidlTestFile);
1314 return;
1317 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1318 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1319 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1320 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1321 IShellFolder_Release(psfDesktop);
1322 DeleteFileW(wszFileName);
1323 if (hr != S_OK) {
1324 IMalloc_Free(ppM, pidlTestFile);
1325 return;
1327 if (pStrRetToBufW)
1329 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1330 ok(0 == lstrcmpW(wszFileName, wszPath),
1331 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1332 "returned incorrect path for file placed on desktop\n");
1335 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1336 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1337 IMalloc_Free(ppM, pidlTestFile);
1338 if (!result) return;
1339 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1342 /* Test if we can get the path from the start menu "program files" PIDL. */
1343 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1344 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1346 SetLastError(0xdeadbeef);
1347 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1348 IMalloc_Free(ppM, pidlPrograms);
1349 ok(result, "SHGetPathFromIDListW failed\n");
1352 static void test_EnumObjects_and_CompareIDs(void)
1354 ITEMIDLIST *newPIDL;
1355 IShellFolder *IDesktopFolder, *testIShellFolder;
1356 char cCurrDirA [MAX_PATH] = {0};
1357 static const CHAR cTestDirA[] = "\\testdir";
1358 WCHAR cTestDirW[MAX_PATH];
1359 int len;
1360 HRESULT hr;
1362 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1363 len = lstrlenA(cCurrDirA);
1365 if(len == 0) {
1366 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1367 return;
1369 if(cCurrDirA[len-1] == '\\')
1370 cCurrDirA[len-1] = 0;
1372 lstrcatA(cCurrDirA, cTestDirA);
1373 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1375 hr = SHGetDesktopFolder(&IDesktopFolder);
1376 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1378 CreateFilesFolders();
1380 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1381 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1383 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1384 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1386 test_EnumObjects(testIShellFolder);
1388 IShellFolder_Release(testIShellFolder);
1390 Cleanup();
1392 IMalloc_Free(ppM, newPIDL);
1394 IShellFolder_Release(IDesktopFolder);
1397 /* A simple implementation of an IPropertyBag, which returns fixed values for
1398 * 'Target' and 'Attributes' properties.
1400 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1401 void **ppvObject)
1403 if (!ppvObject)
1404 return E_INVALIDARG;
1406 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1407 *ppvObject = iface;
1408 } else {
1409 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1410 return E_NOINTERFACE;
1413 IPropertyBag_AddRef(iface);
1414 return S_OK;
1417 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1418 return 2;
1421 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1422 return 1;
1425 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1426 VARIANT *pVar, IErrorLog *pErrorLog)
1428 static const WCHAR wszTargetSpecialFolder[] = {
1429 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1430 static const WCHAR wszTarget[] = {
1431 'T','a','r','g','e','t',0 };
1432 static const WCHAR wszAttributes[] = {
1433 'A','t','t','r','i','b','u','t','e','s',0 };
1434 static const WCHAR wszResolveLinkFlags[] = {
1435 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1436 static const WCHAR wszTargetKnownFolder[] = {
1437 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1438 static const WCHAR wszCLSID[] = {
1439 'C','L','S','I','D',0 };
1441 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1442 ok(V_VT(pVar) == VT_I4 ||
1443 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1444 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1445 return E_INVALIDARG;
1448 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1450 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1451 return E_INVALIDARG;
1454 if (!lstrcmpW(pszPropName, wszTarget)) {
1455 WCHAR wszPath[MAX_PATH];
1456 BOOL result;
1458 ok(V_VT(pVar) == VT_BSTR ||
1459 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1460 "Wrong variant type for 'Target' property!\n");
1461 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1463 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1464 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1465 if (!result) return E_INVALIDARG;
1467 V_BSTR(pVar) = SysAllocString(wszPath);
1468 return S_OK;
1471 if (!lstrcmpW(pszPropName, wszAttributes)) {
1472 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1473 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1474 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1475 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1476 return S_OK;
1479 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1480 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1481 /* TODO */
1482 return E_INVALIDARG;
1485 if (!lstrcmpW(pszPropName, wszCLSID)) {
1486 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1487 /* TODO */
1488 return E_INVALIDARG;
1491 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1492 return E_INVALIDARG;
1495 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1496 VARIANT *pVar)
1498 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1499 return E_NOTIMPL;
1502 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1503 InitPropertyBag_IPropertyBag_QueryInterface,
1504 InitPropertyBag_IPropertyBag_AddRef,
1505 InitPropertyBag_IPropertyBag_Release,
1506 InitPropertyBag_IPropertyBag_Read,
1507 InitPropertyBag_IPropertyBag_Write
1510 static struct IPropertyBag InitPropertyBag = {
1511 &InitPropertyBag_IPropertyBagVtbl
1514 static void test_FolderShortcut(void) {
1515 IPersistPropertyBag *pPersistPropertyBag;
1516 IShellFolder *pShellFolder, *pDesktopFolder;
1517 IPersistFolder3 *pPersistFolder3;
1518 HRESULT hr;
1519 STRRET strret;
1520 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1521 BOOL result;
1522 CLSID clsid;
1523 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1524 HKEY hShellExtKey;
1525 WCHAR wszWineTestFolder[] = {
1526 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1527 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1528 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1529 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1530 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1531 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1532 'N','a','m','e','S','p','a','c','e','\\',
1533 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1534 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1536 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1537 static const GUID CLSID_UnixDosFolder =
1538 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1540 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1541 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1542 return;
1545 if (!pSHGetFolderPathAndSubDirA)
1547 win_skip("FolderShortcut test doesn't work on Win2k\n");
1548 return;
1551 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1552 * via their IPersistPropertyBag interface. And that the target folder
1553 * is taken from the IPropertyBag's 'Target' property.
1555 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1556 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1557 if (hr == REGDB_E_CLASSNOTREG) {
1558 win_skip("CLSID_FolderShortcut is not implemented\n");
1559 return;
1561 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1562 if (hr != S_OK) return;
1564 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1565 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1566 if (hr != S_OK) {
1567 IPersistPropertyBag_Release(pPersistPropertyBag);
1568 return;
1571 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1572 (LPVOID*)&pShellFolder);
1573 IPersistPropertyBag_Release(pPersistPropertyBag);
1574 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1575 if (hr != S_OK) return;
1577 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1578 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1579 if (hr != S_OK) {
1580 IShellFolder_Release(pShellFolder);
1581 return;
1584 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1585 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1586 if (!result) return;
1588 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1589 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1591 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1592 IShellFolder_Release(pShellFolder);
1593 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1594 if (hr != S_OK) return;
1596 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1597 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1598 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1600 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1601 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1602 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1604 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1605 * shell namespace. The target folder, read from the property bag above, remains untouched.
1606 * The following tests show this: The itemidlist for some imaginary shellfolder object
1607 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1608 * itemidlist, but GetDisplayNameOf still returns the path from above.
1610 hr = SHGetDesktopFolder(&pDesktopFolder);
1611 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1612 if (hr != S_OK) return;
1614 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1615 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1616 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1617 RegCloseKey(hShellExtKey);
1618 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1619 &pidlWineTestFolder, NULL);
1620 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1621 IShellFolder_Release(pDesktopFolder);
1622 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1623 if (hr != S_OK) return;
1625 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1626 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1627 if (hr != S_OK) {
1628 IPersistFolder3_Release(pPersistFolder3);
1629 pILFree(pidlWineTestFolder);
1630 return;
1633 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1634 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1635 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1636 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1637 pILFree(pidlCurrentFolder);
1638 pILFree(pidlWineTestFolder);
1640 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1641 IPersistFolder3_Release(pPersistFolder3);
1642 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1643 if (hr != S_OK) return;
1645 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1646 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1647 if (hr != S_OK) {
1648 IShellFolder_Release(pShellFolder);
1649 return;
1652 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1653 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1655 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1656 * but ShellFSFolders. */
1657 myPathAddBackslashW(wszDesktopPath);
1658 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1659 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1660 IShellFolder_Release(pShellFolder);
1661 return;
1664 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1665 &pidlSubFolder, NULL);
1666 RemoveDirectoryW(wszDesktopPath);
1667 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1668 if (hr != S_OK) {
1669 IShellFolder_Release(pShellFolder);
1670 return;
1673 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1674 (LPVOID*)&pPersistFolder3);
1675 IShellFolder_Release(pShellFolder);
1676 pILFree(pidlSubFolder);
1677 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1678 if (hr != S_OK)
1679 return;
1681 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1682 * a little bit and also allow CLSID_UnixDosFolder. */
1683 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1684 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1685 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1686 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1688 IPersistFolder3_Release(pPersistFolder3);
1691 #include "pshpack1.h"
1692 struct FileStructA {
1693 BYTE type;
1694 BYTE dummy;
1695 DWORD dwFileSize;
1696 WORD uFileDate; /* In our current implementation this is */
1697 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1698 WORD uFileAttribs;
1699 CHAR szName[1];
1702 struct FileStructW {
1703 WORD cbLen; /* Length of this element. */
1704 BYTE abFooBar1[6]; /* Beyond any recognition. */
1705 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1706 WORD uTime; /* (this is currently speculation) */
1707 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1708 WORD uTime2; /* (this is currently speculation) */
1709 BYTE abFooBar2[4]; /* Beyond any recognition. */
1710 WCHAR wszName[1]; /* The long filename in unicode. */
1711 /* Just for documentation: Right after the unicode string: */
1712 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1713 * SHITEMID->cb == uOffset + cbLen */
1715 #include "poppack.h"
1717 static void test_ITEMIDLIST_format(void) {
1718 WCHAR wszPersonal[MAX_PATH];
1719 LPSHELLFOLDER psfDesktop, psfPersonal;
1720 LPITEMIDLIST pidlPersonal, pidlFile;
1721 HANDLE hFile;
1722 HRESULT hr;
1723 BOOL bResult;
1724 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1725 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1726 int i;
1728 if (!pSHGetSpecialFolderPathW) return;
1730 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1731 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1732 if (!bResult) return;
1734 SetLastError(0xdeadbeef);
1735 bResult = SetCurrentDirectoryW(wszPersonal);
1736 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1737 win_skip("Most W-calls are not implemented\n");
1738 return;
1740 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1741 if (!bResult) return;
1743 hr = SHGetDesktopFolder(&psfDesktop);
1744 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1745 if (hr != S_OK) return;
1747 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1748 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1749 if (hr != S_OK) {
1750 IShellFolder_Release(psfDesktop);
1751 return;
1754 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1755 (LPVOID*)&psfPersonal);
1756 IShellFolder_Release(psfDesktop);
1757 pILFree(pidlPersonal);
1758 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1759 if (hr != S_OK) return;
1761 for (i=0; i<3; i++) {
1762 CHAR szFile[MAX_PATH];
1763 struct FileStructA *pFileStructA;
1764 WORD cbOffset;
1766 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1768 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1769 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1770 if (hFile == INVALID_HANDLE_VALUE) {
1771 IShellFolder_Release(psfPersonal);
1772 return;
1774 CloseHandle(hFile);
1776 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1777 DeleteFileW(wszFile[i]);
1778 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1779 if (hr != S_OK) {
1780 IShellFolder_Release(psfPersonal);
1781 return;
1784 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1785 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1786 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1787 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1789 if (i < 2) /* First two file names are already in valid 8.3 format */
1790 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1791 else
1792 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1793 * can't implement this correctly, since unix filesystems don't support
1794 * this nasty short/long filename stuff. So we'll probably stay with our
1795 * current habit of storing the long filename here, which seems to work
1796 * just fine. */
1797 todo_wine
1798 ok(pidlFile->mkid.abID[18] == '~' ||
1799 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1800 "Should be derived 8.3 name!\n");
1802 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1803 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1804 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1805 "Alignment byte, where there shouldn't be!\n");
1807 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1808 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1809 "There should be an alignment byte, but isn't!\n");
1811 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1812 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1813 ok ((cbOffset >= sizeof(struct FileStructA) &&
1814 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1815 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1816 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1817 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1819 if (cbOffset >= sizeof(struct FileStructA) &&
1820 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1822 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1823 WCHAR *name = pFileStructW->wszName;
1825 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1826 "FileStructW's offset and length should add up to the PIDL's length!\n");
1828 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1829 /* Since we just created the file, time of creation,
1830 * time of last access and time of last write access just be the same.
1831 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1832 * after the first run. I do remember something with NTFS keeping the creation time
1833 * if a file is deleted and then created again within a couple of seconds or so.
1834 * Might be the reason. */
1835 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1836 pFileStructA->uFileTime == pFileStructW->uTime,
1837 "Last write time should match creation time!\n");
1839 /* On FAT filesystems the last access time is midnight
1840 local time, so the values of uDate2 and uTime2 will
1841 depend on the local timezone. If the times are exactly
1842 equal then the dates should be identical for both FAT
1843 and NTFS as no timezone is more than 1 day away from UTC.
1845 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1847 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1848 "Last write date and time should match last access date and time!\n");
1850 else
1852 /* Filesystem may be FAT. Check date within 1 day
1853 and seconds are zero. */
1854 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1855 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1856 "Last access time on FAT filesystems should have zero seconds.\n");
1857 /* TODO: Perform check for date being within one day.*/
1860 ok (!lstrcmpW(wszFile[i], name) ||
1861 !lstrcmpW(wszFile[i], name + 9) || /* Vista */
1862 !lstrcmpW(wszFile[i], name + 11), /* Win7 */
1863 "The filename should be stored in unicode at this position!\n");
1867 pILFree(pidlFile);
1870 IShellFolder_Release(psfPersonal);
1873 static void test_SHGetFolderPathA(void)
1875 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1876 BOOL is_wow64;
1877 char path[MAX_PATH];
1878 char path_x86[MAX_PATH];
1879 char path_key[MAX_PATH];
1880 HRESULT hr;
1881 HKEY key;
1883 if (!pSHGetFolderPathA)
1885 win_skip("SHGetFolderPathA not present\n");
1886 return;
1888 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1890 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1891 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1892 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1893 if (hr == E_FAIL)
1895 win_skip( "Program Files (x86) not supported\n" );
1896 return;
1898 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1899 if (is_win64)
1901 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1902 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1903 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1905 else
1907 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1908 if (is_wow64)
1909 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1910 else
1911 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1913 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1915 DWORD type, count = sizeof(path_x86);
1916 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1918 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1919 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1921 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1922 RegCloseKey( key );
1925 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1926 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1927 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1928 if (hr == E_FAIL)
1930 win_skip( "Common Files (x86) not supported\n" );
1931 return;
1933 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1934 if (is_win64)
1936 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1937 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1938 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1940 else
1942 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1943 if (is_wow64)
1944 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1945 else
1946 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1948 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1950 DWORD type, count = sizeof(path_x86);
1951 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1953 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1954 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1956 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1960 static void test_SHGetFolderPathAndSubDirA(void)
1962 HRESULT ret;
1963 BOOL delret;
1964 DWORD dwret;
1965 int i;
1966 static char wine[] = "wine";
1967 static char winetemp[] = "wine\\temp";
1968 static char appdata[MAX_PATH];
1969 static char testpath[MAX_PATH];
1970 static char toolongpath[MAX_PATH+1];
1972 if(!pSHGetFolderPathAndSubDirA)
1974 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1975 return;
1978 if(!pSHGetFolderPathA) {
1979 win_skip("SHGetFolderPathA not present!\n");
1980 return;
1982 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1984 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1985 return;
1988 sprintf(testpath, "%s\\%s", appdata, winetemp);
1989 delret = RemoveDirectoryA(testpath);
1990 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1991 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1992 return;
1995 sprintf(testpath, "%s\\%s", appdata, wine);
1996 delret = RemoveDirectoryA(testpath);
1997 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1998 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1999 return;
2002 /* test invalid second parameter */
2003 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
2004 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
2006 /* test fourth parameter */
2007 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
2008 switch(ret) {
2009 case S_OK: /* winvista */
2010 ok(!strncmp(appdata, testpath, strlen(appdata)),
2011 "expected %s to start with %s\n", testpath, appdata);
2012 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2013 "expected %s to end with %s\n", testpath, winetemp);
2014 break;
2015 case E_INVALIDARG: /* winxp, win2k3 */
2016 break;
2017 default:
2018 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
2021 /* test fifth parameter */
2022 testpath[0] = '\0';
2023 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
2024 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2025 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2027 testpath[0] = '\0';
2028 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
2029 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2030 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2032 testpath[0] = '\0';
2033 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
2034 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2035 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
2037 for(i=0; i< MAX_PATH; i++)
2038 toolongpath[i] = '0' + i % 10;
2039 toolongpath[MAX_PATH] = '\0';
2040 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2041 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2042 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2044 testpath[0] = '\0';
2045 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2046 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2048 /* test a not existing path */
2049 testpath[0] = '\0';
2050 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2051 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2052 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2054 /* create a directory inside a not existing directory */
2055 testpath[0] = '\0';
2056 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2057 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2058 ok(!strncmp(appdata, testpath, strlen(appdata)),
2059 "expected %s to start with %s\n", testpath, appdata);
2060 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2061 "expected %s to end with %s\n", testpath, winetemp);
2062 dwret = GetFileAttributes(testpath);
2063 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2065 /* cleanup */
2066 sprintf(testpath, "%s\\%s", appdata, winetemp);
2067 RemoveDirectoryA(testpath);
2068 sprintf(testpath, "%s\\%s", appdata, wine);
2069 RemoveDirectoryA(testpath);
2072 static void test_LocalizedNames(void)
2074 static char cCurrDirA[MAX_PATH];
2075 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2076 IShellFolder *IDesktopFolder, *testIShellFolder;
2077 ITEMIDLIST *newPIDL;
2078 int len;
2079 HRESULT hr;
2080 static char resourcefile[MAX_PATH];
2081 DWORD res;
2082 HANDLE file;
2083 STRRET strret;
2084 BOOL ret;
2086 static const char desktopini_contents1[] =
2087 "[.ShellClassInfo]\r\n"
2088 "LocalizedResourceName=@";
2089 static const char desktopini_contents2[] =
2090 ",-1\r\n";
2091 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2092 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2094 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2095 CreateDirectoryA(".\\testfolder", NULL);
2097 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2099 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2101 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2102 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2103 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2104 ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2105 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2106 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
2107 ok(ret, "WriteFile failed %i\n", GetLastError());
2108 CloseHandle(file);
2110 /* get IShellFolder for parent */
2111 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2112 len = lstrlenA(cCurrDirA);
2114 if (len == 0) {
2115 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2116 goto cleanup;
2118 if(cCurrDirA[len-1] == '\\')
2119 cCurrDirA[len-1] = 0;
2121 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2123 hr = SHGetDesktopFolder(&IDesktopFolder);
2124 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2126 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2127 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2129 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2130 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2132 IMalloc_Free(ppM, newPIDL);
2134 /* windows reads the display name from the resource */
2135 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2136 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2138 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2139 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2141 if (hr == S_OK && pStrRetToBufW)
2143 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2144 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2145 todo_wine
2146 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2147 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2148 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2151 /* editing name is also read from the resource */
2152 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2153 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2155 if (hr == S_OK && pStrRetToBufW)
2157 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2158 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2159 todo_wine
2160 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2161 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2162 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2165 /* parsing name is unchanged */
2166 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2167 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2169 if (hr == S_OK && pStrRetToBufW)
2171 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2172 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2173 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2176 IShellFolder_Release(IDesktopFolder);
2177 IShellFolder_Release(testIShellFolder);
2179 IMalloc_Free(ppM, newPIDL);
2181 cleanup:
2182 DeleteFileA(".\\testfolder\\desktop.ini");
2183 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2184 RemoveDirectoryA(".\\testfolder");
2187 static void test_SHCreateShellItem(void)
2189 IShellItem *shellitem, *shellitem2;
2190 IPersistIDList *persistidl;
2191 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2192 HRESULT ret;
2193 char curdirA[MAX_PATH];
2194 WCHAR curdirW[MAX_PATH];
2195 WCHAR fnbufW[MAX_PATH];
2196 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2197 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2199 GetCurrentDirectoryA(MAX_PATH, curdirA);
2201 if (!pSHCreateShellItem)
2203 win_skip("SHCreateShellItem isn't available\n");
2204 return;
2207 if (!lstrlenA(curdirA))
2209 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2210 return;
2213 if(pSHGetSpecialFolderLocation)
2215 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2216 ok(ret == S_OK, "Got 0x%08x\n", ret);
2218 else
2220 win_skip("pSHGetSpecialFolderLocation missing.\n");
2221 pidl_desktop = NULL;
2224 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2226 ret = SHGetDesktopFolder(&desktopfolder);
2227 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2229 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2230 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2232 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2233 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2235 CreateTestFile(".\\testfile");
2237 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2238 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2240 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2242 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2243 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2245 if (0) /* crashes on Windows XP */
2247 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2248 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2249 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2250 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2253 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2254 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2255 if (SUCCEEDED(ret))
2257 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2258 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2259 if (SUCCEEDED(ret))
2261 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2262 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2263 if (SUCCEEDED(ret))
2265 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2266 pILFree(pidl_test);
2268 IPersistIDList_Release(persistidl);
2270 IShellItem_Release(shellitem);
2273 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2274 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2275 if (SUCCEEDED(ret))
2277 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2278 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2279 if (SUCCEEDED(ret))
2281 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2282 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2283 if (SUCCEEDED(ret))
2285 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2286 pILFree(pidl_test);
2288 IPersistIDList_Release(persistidl);
2291 ret = IShellItem_GetParent(shellitem, &shellitem2);
2292 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2293 if (SUCCEEDED(ret))
2295 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2296 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2297 if (SUCCEEDED(ret))
2299 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2300 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2301 if (SUCCEEDED(ret))
2303 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2304 pILFree(pidl_test);
2306 IPersistIDList_Release(persistidl);
2308 IShellItem_Release(shellitem2);
2311 IShellItem_Release(shellitem);
2314 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2315 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2316 if (SUCCEEDED(ret))
2318 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2319 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2320 if (SUCCEEDED(ret))
2322 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2323 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2324 if (SUCCEEDED(ret))
2326 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2327 pILFree(pidl_test);
2329 IPersistIDList_Release(persistidl);
2331 IShellItem_Release(shellitem);
2334 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2335 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2336 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2337 if (SUCCEEDED(ret))
2339 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2340 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2341 if (SUCCEEDED(ret))
2343 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2344 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2345 if (SUCCEEDED(ret))
2347 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2348 pILFree(pidl_test);
2350 IPersistIDList_Release(persistidl);
2352 IShellItem_Release(shellitem);
2355 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2356 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2357 if (SUCCEEDED(ret))
2359 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2360 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2361 if (SUCCEEDED(ret))
2363 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2364 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2365 if (SUCCEEDED(ret))
2367 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2368 pILFree(pidl_test);
2370 IPersistIDList_Release(persistidl);
2373 IShellItem_Release(shellitem);
2376 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2377 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2378 if (SUCCEEDED(ret))
2380 ret = IShellItem_GetParent(shellitem, &shellitem2);
2381 ok(FAILED(ret), "Got 0x%08x\n", ret);
2382 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2383 IShellItem_Release(shellitem);
2386 /* SHCreateItemFromParsingName */
2387 if(pSHCreateItemFromParsingName)
2389 if(0)
2391 /* Crashes under windows 7 */
2392 pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2395 shellitem = (void*)0xdeadbeef;
2396 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2397 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2398 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2400 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2401 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2402 "SHCreateItemFromParsingName returned %x\n", ret);
2403 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2405 lstrcpyW(fnbufW, curdirW);
2406 myPathAddBackslashW(fnbufW);
2407 lstrcatW(fnbufW, testfileW);
2409 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2410 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2411 if(SUCCEEDED(ret))
2413 LPWSTR tmp_fname;
2414 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2415 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2416 if(SUCCEEDED(ret))
2418 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2419 CoTaskMemFree(tmp_fname);
2421 IShellItem_Release(shellitem);
2424 else
2425 win_skip("No SHCreateItemFromParsingName\n");
2428 /* SHCreateItemFromIDList */
2429 if(pSHCreateItemFromIDList)
2431 if(0)
2433 /* Crashes under win7 */
2434 pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2437 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2438 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2440 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2441 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2442 if (SUCCEEDED(ret))
2444 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2445 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2446 if (SUCCEEDED(ret))
2448 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2449 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2450 if (SUCCEEDED(ret))
2452 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2453 pILFree(pidl_test);
2455 IPersistIDList_Release(persistidl);
2457 IShellItem_Release(shellitem);
2460 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2461 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2462 if (SUCCEEDED(ret))
2464 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2465 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2466 if (SUCCEEDED(ret))
2468 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2469 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2470 if (SUCCEEDED(ret))
2472 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2473 pILFree(pidl_test);
2475 IPersistIDList_Release(persistidl);
2477 IShellItem_Release(shellitem);
2480 else
2481 win_skip("No SHCreateItemFromIDList\n");
2483 DeleteFileA(".\\testfile");
2484 pILFree(pidl_abstestfile);
2485 pILFree(pidl_testfile);
2486 pILFree(pidl_desktop);
2487 pILFree(pidl_cwd);
2488 IShellFolder_Release(currentfolder);
2489 IShellFolder_Release(desktopfolder);
2492 static void test_SHGetNameFromIDList(void)
2494 IShellItem *shellitem;
2495 LPITEMIDLIST pidl;
2496 LPWSTR name_string;
2497 HRESULT hres;
2498 UINT i;
2499 static const DWORD flags[] = {
2500 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2501 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2502 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2503 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2505 if(!pSHGetNameFromIDList)
2507 win_skip("SHGetNameFromIDList missing.\n");
2508 return;
2511 /* These should be available on any platform that passed the above test. */
2512 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2513 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2514 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2515 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2517 if(0)
2519 /* Crashes under win7 */
2520 pSHGetNameFromIDList(NULL, 0, NULL);
2523 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2524 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2526 /* Test the desktop */
2527 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2528 ok(hres == S_OK, "Got 0x%08x\n", hres);
2529 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2530 ok(hres == S_OK, "Got 0x%08x\n", hres);
2531 if(SUCCEEDED(hres))
2533 WCHAR *nameSI, *nameSH;
2534 WCHAR buf[MAX_PATH];
2535 HRESULT hrSI, hrSH, hrSF;
2536 STRRET strret;
2537 IShellFolder *psf;
2538 BOOL res;
2540 SHGetDesktopFolder(&psf);
2541 for(i = 0; flags[i] != -1234; i++)
2543 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2544 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2545 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2546 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2547 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2548 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2550 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2551 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2553 if(SUCCEEDED(hrSF))
2555 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2556 if(SUCCEEDED(hrSI))
2557 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2558 if(SUCCEEDED(hrSF))
2559 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2561 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2562 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2564 IShellFolder_Release(psf);
2566 if(pSHGetPathFromIDListW){
2567 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2568 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2569 res = pSHGetPathFromIDListW(pidl, buf);
2570 ok(res == TRUE, "Got %d\n", res);
2571 if(SUCCEEDED(hrSI) && res)
2572 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2573 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2574 }else
2575 win_skip("pSHGetPathFromIDListW not available\n");
2577 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2578 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2579 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2581 IShellItem_Release(shellitem);
2583 pILFree(pidl);
2585 /* Test the control panel */
2586 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2587 ok(hres == S_OK, "Got 0x%08x\n", hres);
2588 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2589 ok(hres == S_OK, "Got 0x%08x\n", hres);
2590 if(SUCCEEDED(hres))
2592 WCHAR *nameSI, *nameSH;
2593 WCHAR buf[MAX_PATH];
2594 HRESULT hrSI, hrSH, hrSF;
2595 STRRET strret;
2596 IShellFolder *psf;
2597 BOOL res;
2599 SHGetDesktopFolder(&psf);
2600 for(i = 0; flags[i] != -1234; i++)
2602 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2603 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2604 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2605 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2606 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2607 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2609 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2610 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2612 if(SUCCEEDED(hrSF))
2614 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2615 if(SUCCEEDED(hrSI))
2616 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2617 if(SUCCEEDED(hrSF))
2618 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2620 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2621 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2623 IShellFolder_Release(psf);
2625 if(pSHGetPathFromIDListW){
2626 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2627 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2628 res = pSHGetPathFromIDListW(pidl, buf);
2629 ok(res == FALSE, "Got %d\n", res);
2630 if(SUCCEEDED(hrSI) && res)
2631 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2632 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2633 }else
2634 win_skip("pSHGetPathFromIDListW not available\n");
2636 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2637 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2638 "Got 0x%08x\n", hres);
2639 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2641 IShellItem_Release(shellitem);
2643 pILFree(pidl);
2646 static void test_SHGetItemFromDataObject(void)
2648 IShellFolder *psfdesktop;
2649 IShellItem *psi;
2650 IShellView *psv;
2651 HRESULT hres;
2653 if(!pSHGetItemFromDataObject)
2655 win_skip("No SHGetItemFromDataObject.\n");
2656 return;
2659 if(0)
2661 /* Crashes under win7 */
2662 pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2665 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2666 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2668 SHGetDesktopFolder(&psfdesktop);
2670 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2671 ok(hres == S_OK, "got 0x%08x\n", hres);
2672 if(SUCCEEDED(hres))
2674 IEnumIDList *peidl;
2675 IDataObject *pdo;
2676 SHCONTF enum_flags;
2678 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2679 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2680 ok(hres == S_OK, "got 0x%08x\n", hres);
2681 if(SUCCEEDED(hres))
2683 LPITEMIDLIST apidl[5];
2684 UINT count = 0, i;
2686 for(count = 0; count < 5; count++)
2687 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2688 break;
2690 if(count)
2692 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2693 &IID_IDataObject, NULL, (void**)&pdo);
2694 ok(hres == S_OK, "got 0x%08x\n", hres);
2695 if(SUCCEEDED(hres))
2697 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2698 ok(hres == S_OK, "got 0x%08x\n", hres);
2699 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2700 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2701 ok(hres == S_OK, "got 0x%08x\n", hres);
2702 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2703 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2704 ok(hres == S_OK, "got 0x%08x\n", hres);
2705 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2706 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2707 ok(hres == S_OK, "got 0x%08x\n", hres);
2708 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2709 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2710 ok(hres == S_OK, "got 0x%08x\n", hres);
2711 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2713 IDataObject_Release(pdo);
2716 else
2717 skip("No file(s) found - skipping single-file test.\n");
2719 if(count > 1)
2721 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2722 &IID_IDataObject, NULL, (void**)&pdo);
2723 ok(hres == S_OK, "got 0x%08x\n", hres);
2724 if(SUCCEEDED(hres))
2726 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2727 ok(hres == S_OK, "got 0x%08x\n", hres);
2728 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2729 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2730 ok(hres == S_OK, "got 0x%08x\n", hres);
2731 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2732 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2733 ok(hres == S_OK, "got 0x%08x\n", hres);
2734 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2735 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2736 ok(hres == S_OK, "got 0x%08x\n", hres);
2737 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2738 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2739 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2740 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2741 IDataObject_Release(pdo);
2744 else
2745 skip("zero or one file found - skipping multi-file test.\n");
2747 for(i = 0; i < count; i++)
2748 pILFree(apidl[i]);
2750 IEnumIDList_Release(peidl);
2753 IShellView_Release(psv);
2756 IShellFolder_Release(psfdesktop);
2759 static void test_ShellItemCompare(void)
2761 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2762 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2763 IShellFolder *psf_desktop, *psf_current;
2764 LPITEMIDLIST pidl_cwd;
2765 WCHAR curdirW[MAX_PATH];
2766 BOOL failed;
2767 HRESULT hr;
2768 static const WCHAR filesW[][9] = {
2769 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2770 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2771 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2772 int order;
2773 UINT i;
2775 if(!pSHCreateShellItem)
2777 win_skip("SHCreateShellItem missing.\n");
2778 return;
2781 GetCurrentDirectoryW(MAX_PATH, curdirW);
2782 if(!lstrlenW(curdirW))
2784 skip("Failed to get current directory, skipping.\n");
2785 return;
2788 CreateDirectoryA(".\\a", NULL);
2789 CreateDirectoryA(".\\b", NULL);
2790 CreateDirectoryA(".\\c", NULL);
2791 CreateTestFile(".\\a\\a");
2792 CreateTestFile(".\\a\\b");
2793 CreateTestFile(".\\a\\c");
2794 CreateTestFile(".\\b\\a");
2795 CreateTestFile(".\\b\\b");
2796 CreateTestFile(".\\b\\c");
2797 CreateTestFile(".\\c\\a");
2798 CreateTestFile(".\\c\\b");
2799 CreateTestFile(".\\c\\c");
2801 SHGetDesktopFolder(&psf_desktop);
2802 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2803 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2804 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2805 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2806 IShellFolder_Release(psf_desktop);
2807 ILFree(pidl_cwd);
2809 /* Generate ShellItems for the files */
2810 memset(&psi, 0, sizeof(psi));
2811 failed = FALSE;
2812 for(i = 0; i < 9; i++)
2814 LPITEMIDLIST pidl_testfile = NULL;
2816 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2817 NULL, &pidl_testfile, NULL);
2818 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2819 if(SUCCEEDED(hr))
2821 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2822 ok(hr == S_OK, "Got 0x%08x\n", hr);
2823 pILFree(pidl_testfile);
2825 if(FAILED(hr)) failed = TRUE;
2827 if(failed)
2829 skip("Failed to create all shellitems.\n");
2830 goto cleanup;
2833 /* Generate ShellItems for the folders */
2834 hr = IShellItem_GetParent(psi[0], &psi_a);
2835 ok(hr == S_OK, "Got 0x%08x\n", hr);
2836 if(FAILED(hr)) failed = TRUE;
2837 hr = IShellItem_GetParent(psi[3], &psi_b);
2838 ok(hr == S_OK, "Got 0x%08x\n", hr);
2839 if(FAILED(hr)) failed = TRUE;
2840 hr = IShellItem_GetParent(psi[6], &psi_c);
2841 ok(hr == S_OK, "Got 0x%08x\n", hr);
2842 if(FAILED(hr)) failed = TRUE;
2844 if(failed)
2846 skip("Failed to create shellitems.\n");
2847 goto cleanup;
2850 if(0)
2852 /* Crashes on native (win7, winxp) */
2853 IShellItem_Compare(psi_a, NULL, 0, NULL);
2854 IShellItem_Compare(psi_a, psi_b, 0, NULL);
2855 IShellItem_Compare(psi_a, NULL, 0, &order);
2858 /* Basics */
2859 for(i = 0; i < 9; i++)
2861 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2862 ok(hr == S_OK, "Got 0x%08x\n", hr);
2863 ok(order == 0, "Got order %d\n", order);
2864 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2865 ok(hr == S_OK, "Got 0x%08x\n", hr);
2866 ok(order == 0, "Got order %d\n", order);
2867 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2868 ok(hr == S_OK, "Got 0x%08x\n", hr);
2869 ok(order == 0, "Got order %d\n", order);
2872 /* Order */
2873 /* a\b:a\a , a\b:a\c, a\b:a\b */
2874 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2875 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2876 ok(order == 1, "Got order %d\n", order);
2877 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2878 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2879 ok(order == -1, "Got order %d\n", order);
2880 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2881 ok(hr == S_OK, "Got 0x%08x\n", hr);
2882 ok(order == 0, "Got order %d\n", order);
2884 /* b\b:a\b, b\b:c\b, b\b:c\b */
2885 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2886 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2887 ok(order == 1, "Got order %d\n", order);
2888 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2889 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2890 ok(order == -1, "Got order %d\n", order);
2891 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2892 ok(hr == S_OK, "Got 0x%08x\n", hr);
2893 ok(order == 0, "Got order %d\n", order);
2895 /* b:a\a, b:a\c, b:a\b */
2896 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2897 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2898 todo_wine ok(order == 1, "Got order %d\n", order);
2899 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2900 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2901 todo_wine ok(order == 1, "Got order %d\n", order);
2902 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2903 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2904 todo_wine ok(order == 1, "Got order %d\n", order);
2906 /* b:c\a, b:c\c, b:c\b */
2907 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2908 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2909 ok(order == -1, "Got order %d\n", order);
2910 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2911 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2912 ok(order == -1, "Got order %d\n", order);
2913 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2914 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2915 ok(order == -1, "Got order %d\n", order);
2917 /* a\b:a\a , a\b:a\c, a\b:a\b */
2918 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2919 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2920 ok(order == 1, "Got order %d\n", order);
2921 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2922 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2923 ok(order == -1, "Got order %d\n", order);
2924 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2925 ok(hr == S_OK, "Got 0x%08x\n", hr);
2926 ok(order == 0, "Got order %d\n", order);
2928 /* b\b:a\b, b\b:c\b, b\b:c\b */
2929 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2930 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2931 ok(order == 1, "Got order %d\n", order);
2932 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2933 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2934 ok(order == -1, "Got order %d\n", order);
2935 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2936 ok(hr == S_OK, "Got 0x%08x\n", hr);
2937 ok(order == 0, "Got order %d\n", order);
2939 /* b:a\a, b:a\c, b:a\b */
2940 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2941 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2942 todo_wine ok(order == 1, "Got order %d\n", order);
2943 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2944 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2945 todo_wine ok(order == 1, "Got order %d\n", order);
2946 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2947 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2948 todo_wine ok(order == 1, "Got order %d\n", order);
2950 /* b:c\a, b:c\c, b:c\b */
2951 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2952 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2953 ok(order == -1, "Got order %d\n", order);
2954 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2955 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2956 ok(order == -1, "Got order %d\n", order);
2957 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2958 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2959 ok(order == -1, "Got order %d\n", order);
2961 cleanup:
2962 IShellFolder_Release(psf_current);
2964 DeleteFileA(".\\a\\a");
2965 DeleteFileA(".\\a\\b");
2966 DeleteFileA(".\\a\\c");
2967 DeleteFileA(".\\b\\a");
2968 DeleteFileA(".\\b\\b");
2969 DeleteFileA(".\\b\\c");
2970 DeleteFileA(".\\c\\a");
2971 DeleteFileA(".\\c\\b");
2972 DeleteFileA(".\\c\\c");
2973 RemoveDirectoryA(".\\a");
2974 RemoveDirectoryA(".\\b");
2975 RemoveDirectoryA(".\\c");
2977 if(psi_a) IShellItem_Release(psi_a);
2978 if(psi_b) IShellItem_Release(psi_b);
2979 if(psi_c) IShellItem_Release(psi_c);
2981 for(i = 0; i < 9; i++)
2982 if(psi[i]) IShellItem_Release(psi[i]);
2985 /**************************************************************/
2986 /* IUnknown implementation for counting QueryInterface calls. */
2987 typedef struct {
2988 IUnknown IUnknown_iface;
2989 struct if_count {
2990 REFIID id;
2991 LONG count;
2992 } *ifaces;
2993 LONG unknown;
2994 } IUnknownImpl;
2996 static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
2998 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
3001 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
3003 IUnknownImpl *This = impl_from_IUnknown(iunk);
3004 UINT i, found;
3005 for(i = found = 0; This->ifaces[i].id != NULL; i++)
3007 if(IsEqualIID(This->ifaces[i].id, riid))
3009 This->ifaces[i].count++;
3010 found = 1;
3011 break;
3014 if(!found)
3015 This->unknown++;
3016 return E_NOINTERFACE;
3019 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
3021 return 2;
3024 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
3026 return 1;
3029 static const IUnknownVtbl vt_IUnknown = {
3030 unk_fnQueryInterface,
3031 unk_fnAddRef,
3032 unk_fnRelease
3035 static void test_SHGetIDListFromObject(void)
3037 IUnknownImpl *punkimpl;
3038 IShellFolder *psfdesktop;
3039 IShellView *psv;
3040 LPITEMIDLIST pidl, pidl_desktop;
3041 HRESULT hres;
3042 UINT i;
3043 struct if_count ifaces[] =
3044 { {&IID_IPersistIDList, 0},
3045 {&IID_IPersistFolder2, 0},
3046 {&IID_IDataObject, 0},
3047 {&IID_IParentAndItem, 0},
3048 {&IID_IFolderView, 0},
3049 {NULL, 0} };
3051 if(!pSHGetIDListFromObject)
3053 win_skip("SHGetIDListFromObject missing.\n");
3054 return;
3057 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3059 if(0)
3061 /* Crashes native */
3062 pSHGetIDListFromObject(NULL, NULL);
3063 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3066 hres = pSHGetIDListFromObject(NULL, &pidl);
3067 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3069 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3070 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3071 punkimpl->ifaces = ifaces;
3072 punkimpl->unknown = 0;
3074 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3075 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3076 ok(ifaces[0].count, "interface not requested.\n");
3077 ok(ifaces[1].count, "interface not requested.\n");
3078 ok(ifaces[2].count, "interface not requested.\n");
3079 todo_wine
3080 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3081 "interface not requested.\n");
3082 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3083 "interface not requested.\n");
3085 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3086 HeapFree(GetProcessHeap(), 0, punkimpl);
3088 pidl_desktop = NULL;
3089 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3090 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3092 SHGetDesktopFolder(&psfdesktop);
3094 /* Test IShellItem */
3095 if(pSHCreateShellItem)
3097 IShellItem *shellitem;
3098 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3099 ok(hres == S_OK, "got 0x%08x\n", hres);
3100 if(SUCCEEDED(hres))
3102 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3103 ok(hres == S_OK, "got 0x%08x\n", hres);
3104 if(SUCCEEDED(hres))
3106 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3107 pILFree(pidl);
3109 IShellItem_Release(shellitem);
3112 else
3113 skip("no SHCreateShellItem.\n");
3115 /* Test IShellFolder */
3116 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3117 ok(hres == S_OK, "got 0x%08x\n", hres);
3118 if(SUCCEEDED(hres))
3120 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3121 pILFree(pidl);
3124 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3125 ok(hres == S_OK, "got 0x%08x\n", hres);
3126 if(SUCCEEDED(hres))
3128 IEnumIDList *peidl;
3129 IDataObject *pdo;
3130 SHCONTF enum_flags;
3132 /* Test IFolderView */
3133 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3134 ok(hres == S_OK, "got 0x%08x\n", hres);
3135 if(SUCCEEDED(hres))
3137 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3138 pILFree(pidl);
3141 /* Test IDataObject */
3142 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3143 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3144 ok(hres == S_OK, "got 0x%08x\n", hres);
3145 if(SUCCEEDED(hres))
3147 LPITEMIDLIST apidl[5];
3148 UINT count = 0;
3149 for(count = 0; count < 5; count++)
3150 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3151 break;
3153 if(count)
3155 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3156 &IID_IDataObject, NULL, (void**)&pdo);
3157 ok(hres == S_OK, "got 0x%08x\n", hres);
3158 if(SUCCEEDED(hres))
3160 pidl = (void*)0xDEADBEEF;
3161 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3162 ok(hres == S_OK, "got 0x%08x\n", hres);
3163 ok(pidl != NULL, "pidl is NULL.\n");
3164 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3165 pILFree(pidl);
3167 IDataObject_Release(pdo);
3170 else
3171 skip("No files found - skipping single-file test.\n");
3173 if(count > 1)
3175 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3176 &IID_IDataObject, NULL, (void**)&pdo);
3177 ok(hres == S_OK, "got 0x%08x\n", hres);
3178 if(SUCCEEDED(hres))
3180 pidl = (void*)0xDEADBEEF;
3181 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3182 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3183 "got 0x%08x\n", hres);
3184 ok(pidl == NULL, "pidl is not NULL.\n");
3186 IDataObject_Release(pdo);
3189 else
3190 skip("zero or one file found - skipping multi-file test.\n");
3192 for(i = 0; i < count; i++)
3193 pILFree(apidl[i]);
3195 IEnumIDList_Release(peidl);
3198 IShellView_Release(psv);
3201 IShellFolder_Release(psfdesktop);
3202 pILFree(pidl_desktop);
3205 static void test_SHGetItemFromObject(void)
3207 IUnknownImpl *punkimpl;
3208 IShellFolder *psfdesktop;
3209 LPITEMIDLIST pidl;
3210 IShellItem *psi;
3211 IUnknown *punk;
3212 HRESULT hres;
3213 struct if_count ifaces[] =
3214 { {&IID_IPersistIDList, 0},
3215 {&IID_IPersistFolder2, 0},
3216 {&IID_IDataObject, 0},
3217 {&IID_IParentAndItem, 0},
3218 {&IID_IFolderView, 0},
3219 {NULL, 0} };
3221 if(!pSHGetItemFromObject)
3223 skip("No SHGetItemFromObject.\n");
3224 return;
3227 SHGetDesktopFolder(&psfdesktop);
3229 if(0)
3231 /* Crashes with Windows 7 */
3232 pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3233 pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3234 pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3237 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3238 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3240 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3241 punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3242 punkimpl->ifaces = ifaces;
3243 punkimpl->unknown = 0;
3245 /* The same as SHGetIDListFromObject */
3246 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3247 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3248 ok(ifaces[0].count, "interface not requested.\n");
3249 ok(ifaces[1].count, "interface not requested.\n");
3250 ok(ifaces[2].count, "interface not requested.\n");
3251 todo_wine
3252 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3253 "interface not requested.\n");
3254 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3255 "interface not requested.\n");
3257 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3258 HeapFree(GetProcessHeap(), 0, punkimpl);
3260 /* Test IShellItem */
3261 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3262 ok(hres == S_OK, "Got 0x%08x\n", hres);
3263 if(SUCCEEDED(hres))
3265 IShellItem *psi2;
3266 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3267 ok(hres == S_OK, "Got 0x%08x\n", hres);
3268 if(SUCCEEDED(hres))
3270 todo_wine
3271 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3272 IShellItem_Release(psi2);
3274 IShellItem_Release(psi);
3277 IShellFolder_Release(psfdesktop);
3280 static void test_SHCreateShellItemArray(void)
3282 IShellFolder *pdesktopsf, *psf;
3283 IShellItemArray *psia;
3284 IEnumIDList *peidl;
3285 HRESULT hr;
3286 WCHAR cTestDirW[MAX_PATH];
3287 LPITEMIDLIST pidl_testdir, pidl;
3288 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3290 if(!pSHCreateShellItemArray) {
3291 skip("No pSHCreateShellItemArray!\n");
3292 return;
3295 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3297 if(0)
3299 /* Crashes under native */
3300 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3301 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3302 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3303 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3306 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3307 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3309 SHGetDesktopFolder(&pdesktopsf);
3310 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3311 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3313 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3314 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3316 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3317 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3318 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3319 pILFree(pidl);
3321 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3322 myPathAddBackslashW(cTestDirW);
3323 lstrcatW(cTestDirW, testdirW);
3325 CreateFilesFolders();
3327 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3328 ok(hr == S_OK, "got 0x%08x\n", hr);
3329 if(SUCCEEDED(hr))
3331 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3332 (void**)&psf);
3333 ok(hr == S_OK, "Got 0x%08x\n", hr);
3335 IShellFolder_Release(pdesktopsf);
3337 if(FAILED(hr))
3339 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3340 pILFree(pidl_testdir);
3341 Cleanup();
3342 return;
3345 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3346 ok(hr == S_OK, "Got %08x\n", hr);
3347 if(SUCCEEDED(hr))
3349 LPITEMIDLIST apidl[5];
3350 UINT done, numitems, i;
3352 for(done = 0; done < 5; done++)
3353 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3354 break;
3355 ok(done == 5, "Got %d pidls\n", done);
3356 IEnumIDList_Release(peidl);
3358 /* Create a ShellItemArray */
3359 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3360 ok(hr == S_OK, "Got 0x%08x\n", hr);
3361 if(SUCCEEDED(hr))
3363 IShellItem *psi;
3365 if(0)
3367 /* Crashes in Windows 7 */
3368 IShellItemArray_GetCount(psia, NULL);
3371 IShellItemArray_GetCount(psia, &numitems);
3372 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3374 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3375 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3377 /* Compare all the items */
3378 for(i = 0; i < numitems; i++)
3380 LPITEMIDLIST pidl_abs;
3381 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3383 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3384 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3385 if(SUCCEEDED(hr))
3387 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3388 ok(hr == S_OK, "Got 0x%08x\n", hr);
3389 if(SUCCEEDED(hr))
3391 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3392 pILFree(pidl);
3394 IShellItem_Release(psi);
3396 pILFree(pidl_abs);
3398 for(i = 0; i < done; i++)
3399 pILFree(apidl[i]);
3400 IShellItemArray_Release(psia);
3404 /* SHCreateShellItemArrayFromShellItem */
3405 if(pSHCreateShellItemArrayFromShellItem)
3407 IShellItem *psi;
3409 if(0)
3411 /* Crashes under Windows 7 */
3412 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3413 pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3414 pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3417 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3418 ok(hr == S_OK, "Got 0x%08x\n", hr);
3419 if(SUCCEEDED(hr))
3421 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3422 ok(hr == S_OK, "Got 0x%08x\n", hr);
3423 if(SUCCEEDED(hr))
3425 IShellItem *psi2;
3426 UINT count;
3427 hr = IShellItemArray_GetCount(psia, &count);
3428 ok(hr == S_OK, "Got 0x%08x\n", hr);
3429 ok(count == 1, "Got count %d\n", count);
3430 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3431 ok(hr == S_OK, "Got 0x%08x\n", hr);
3432 todo_wine
3433 ok(psi != psi2, "ShellItems are of the same instance.\n");
3434 if(SUCCEEDED(hr))
3436 LPITEMIDLIST pidl1, pidl2;
3437 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3438 ok(hr == S_OK, "Got 0x%08x\n", hr);
3439 ok(pidl1 != NULL, "pidl1 was null.\n");
3440 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3441 ok(hr == S_OK, "Got 0x%08x\n", hr);
3442 ok(pidl2 != NULL, "pidl2 was null.\n");
3443 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3444 pILFree(pidl1);
3445 pILFree(pidl2);
3446 IShellItem_Release(psi2);
3448 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3449 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3450 IShellItemArray_Release(psia);
3452 IShellItem_Release(psi);
3455 else
3456 skip("No SHCreateShellItemArrayFromShellItem.\n");
3458 if(pSHCreateShellItemArrayFromDataObject)
3460 IShellView *psv;
3462 if(0)
3464 /* Crashes under Windows 7 */
3465 pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3467 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3468 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3470 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3471 ok(hr == S_OK, "got 0x%08x\n", hr);
3472 if(SUCCEEDED(hr))
3474 IEnumIDList *peidl;
3475 IDataObject *pdo;
3476 SHCONTF enum_flags;
3478 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3479 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3480 ok(hr == S_OK, "got 0x%08x\n", hr);
3481 if(SUCCEEDED(hr))
3483 LPITEMIDLIST apidl[5];
3484 UINT count, i;
3486 for(count = 0; count < 5; count++)
3487 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3488 break;
3489 ok(count == 5, "Got %d\n", count);
3491 if(count)
3493 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3494 &IID_IDataObject, NULL, (void**)&pdo);
3495 ok(hr == S_OK, "Got 0x%08x\n", hr);
3496 if(SUCCEEDED(hr))
3498 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3499 (void**)&psia);
3500 ok(hr == S_OK, "Got 0x%08x\n", hr);
3501 if(SUCCEEDED(hr))
3503 UINT count_sia, i;
3504 hr = IShellItemArray_GetCount(psia, &count_sia);
3505 ok(hr == S_OK, "Got 0x%08x\n", hr);
3506 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3507 for(i = 0; i < count_sia; i++)
3509 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3510 IShellItem *psi;
3511 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3512 ok(hr == S_OK, "Got 0x%08x\n", hr);
3513 if(SUCCEEDED(hr))
3515 LPITEMIDLIST pidl;
3516 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3517 ok(hr == S_OK, "Got 0x%08x\n", hr);
3518 ok(pidl != NULL, "pidl as NULL.\n");
3519 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3520 pILFree(pidl);
3521 IShellItem_Release(psi);
3523 pILFree(pidl_abs);
3526 IShellItemArray_Release(psia);
3529 IDataObject_Release(pdo);
3531 for(i = 0; i < count; i++)
3532 pILFree(apidl[i]);
3534 else
3535 skip("No files found - skipping test.\n");
3537 IEnumIDList_Release(peidl);
3539 IShellView_Release(psv);
3542 else
3543 skip("No SHCreateShellItemArrayFromDataObject.\n");
3545 IShellFolder_Release(psf);
3546 pILFree(pidl_testdir);
3547 Cleanup();
3550 static void test_ShellItemBindToHandler(void)
3552 IShellItem *psi;
3553 LPITEMIDLIST pidl_desktop;
3554 HRESULT hr;
3556 if(!pSHCreateShellItem)
3558 skip("SHCreateShellItem missing.\n");
3559 return;
3562 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3563 ok(hr == S_OK, "Got 0x%08x\n", hr);
3564 if(SUCCEEDED(hr))
3566 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3567 ok(hr == S_OK, "Got 0x%08x\n", hr);
3569 if(SUCCEEDED(hr))
3571 IPersistFolder2 *ppf2;
3572 IUnknown *punk;
3574 if(0)
3576 /* Crashes under Windows 7 */
3577 IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3578 IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3580 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3581 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3583 /* BHID_SFObject */
3584 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3585 ok(hr == S_OK, "Got 0x%08x\n", hr);
3586 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3587 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3588 ok(hr == S_OK, "Got 0x%08x\n", hr);
3589 if(SUCCEEDED(hr))
3591 LPITEMIDLIST pidl_tmp;
3592 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3593 ok(hr == S_OK, "Got 0x%08x\n", hr);
3594 if(SUCCEEDED(hr))
3596 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3597 pILFree(pidl_tmp);
3599 IPersistFolder2_Release(ppf2);
3602 /* BHID_SFUIObject */
3603 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3604 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3605 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3606 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3607 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3608 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3610 /* BHID_DataObject */
3611 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3612 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3613 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3615 todo_wine
3617 /* BHID_SFViewObject */
3618 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3619 ok(hr == S_OK, "Got 0x%08x\n", hr);
3620 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3621 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3622 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3623 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3625 /* BHID_Storage */
3626 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3627 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3628 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3629 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3630 ok(hr == S_OK, "Got 0x%08x\n", hr);
3631 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3633 /* BHID_Stream */
3634 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3635 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3636 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3637 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3638 ok(hr == S_OK, "Got 0x%08x\n", hr);
3639 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3641 /* BHID_StorageEnum */
3642 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3643 ok(hr == S_OK, "Got 0x%08x\n", hr);
3644 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3646 /* BHID_Transfer */
3647 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3648 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3649 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3651 /* BHID_EnumItems */
3652 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3653 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3654 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3656 /* BHID_Filter */
3657 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3658 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3659 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3661 /* BHID_LinkTargetItem */
3662 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3663 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3664 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3665 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3666 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3667 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3669 /* BHID_PropertyStore */
3670 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3671 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3672 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3673 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (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);
3677 /* BHID_ThumbnailHandler */
3678 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3679 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3680 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3682 /* BHID_AssociationArray */
3683 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3684 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3685 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3687 /* BHID_EnumAssocHandlers */
3688 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3689 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3690 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3693 IShellItem_Release(psi);
3695 else
3696 skip("Failed to create ShellItem.\n");
3698 pILFree(pidl_desktop);
3701 static void test_ShellItemGetAttributes(void)
3703 IShellItem *psi;
3704 LPITEMIDLIST pidl_desktop;
3705 SFGAOF sfgao;
3706 HRESULT hr;
3708 if(!pSHCreateShellItem)
3710 skip("SHCreateShellItem missing.\n");
3711 return;
3714 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3715 ok(hr == S_OK, "Got 0x%08x\n", hr);
3716 if(SUCCEEDED(hr))
3718 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3719 ok(hr == S_OK, "Got 0x%08x\n", hr);
3720 pILFree(pidl_desktop);
3722 if(FAILED(hr))
3724 skip("Skipping tests.\n");
3725 return;
3728 if(0)
3730 /* Crashes on native (Win 7) */
3731 IShellItem_GetAttributes(psi, 0, NULL);
3734 /* Test GetAttributes on the desktop folder. */
3735 sfgao = 0xdeadbeef;
3736 hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
3737 ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
3738 ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
3740 IShellItem_Release(psi);
3743 static void test_SHParseDisplayName(void)
3745 LPITEMIDLIST pidl1, pidl2;
3746 IShellFolder *desktop;
3747 WCHAR dirW[MAX_PATH];
3748 WCHAR nameW[10];
3749 HRESULT hr;
3750 BOOL ret, is_wow64;
3752 if (!pSHParseDisplayName)
3754 win_skip("SHParseDisplayName isn't available\n");
3755 return;
3758 if (0)
3760 /* crashes on native */
3761 pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3762 nameW[0] = 0;
3763 pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3766 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3767 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3768 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3769 hr == E_INVALIDARG, "failed %08x\n", hr);
3770 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3772 /* dummy name */
3773 nameW[0] = 0;
3774 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3775 ok(hr == S_OK, "failed %08x\n", hr);
3776 hr = SHGetDesktopFolder(&desktop);
3777 ok(hr == S_OK, "failed %08x\n", hr);
3778 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3779 ok(hr == S_OK, "failed %08x\n", hr);
3780 ret = pILIsEqual(pidl1, pidl2);
3781 ok(ret == TRUE, "expected equal idls\n");
3782 pILFree(pidl1);
3783 pILFree(pidl2);
3785 /* with path */
3786 GetWindowsDirectoryW( dirW, MAX_PATH );
3788 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3789 ok(hr == S_OK, "failed %08x\n", hr);
3790 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3791 ok(hr == S_OK, "failed %08x\n", hr);
3793 ret = pILIsEqual(pidl1, pidl2);
3794 ok(ret == TRUE, "expected equal idls\n");
3795 pILFree(pidl1);
3796 pILFree(pidl2);
3798 /* system32 is not redirected to syswow64 on WOW64 */
3799 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
3800 if (is_wow64 && pGetSystemWow64DirectoryW)
3802 UINT len;
3803 *dirW = 0;
3804 len = GetSystemDirectoryW(dirW, MAX_PATH);
3805 ok(len > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
3806 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3807 ok(hr == S_OK, "failed %08x\n", hr);
3808 *dirW = 0;
3809 len = pGetSystemWow64DirectoryW(dirW, MAX_PATH);
3810 ok(len > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
3811 hr = pSHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
3812 ok(hr == S_OK, "failed %08x\n", hr);
3813 ret = pILIsEqual(pidl1, pidl2);
3814 ok(ret == FALSE, "expected different idls\n");
3815 pILFree(pidl1);
3816 pILFree(pidl2);
3819 IShellFolder_Release(desktop);
3822 static void test_desktop_IPersist(void)
3824 IShellFolder *desktop;
3825 IPersist *persist;
3826 IPersistFolder2 *ppf2;
3827 CLSID clsid;
3828 HRESULT hr;
3830 hr = SHGetDesktopFolder(&desktop);
3831 ok(hr == S_OK, "failed %08x\n", hr);
3833 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3834 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3836 if (hr == S_OK)
3838 if (0)
3840 /* crashes on native */
3841 IPersist_GetClassID(persist, NULL);
3843 memset(&clsid, 0, sizeof(clsid));
3844 hr = IPersist_GetClassID(persist, &clsid);
3845 ok(hr == S_OK, "failed %08x\n", hr);
3846 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3847 IPersist_Release(persist);
3850 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3851 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3852 if(SUCCEEDED(hr))
3854 IPersistFolder *ppf;
3855 LPITEMIDLIST pidl;
3856 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3857 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3858 if(SUCCEEDED(hr))
3859 IPersistFolder_Release(ppf);
3861 todo_wine {
3862 hr = IPersistFolder2_Initialize(ppf2, NULL);
3863 ok(hr == S_OK, "got %08x\n", hr);
3866 pidl = NULL;
3867 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3868 ok(hr == S_OK, "got %08x\n", hr);
3869 ok(pidl != NULL, "pidl was NULL.\n");
3870 if(SUCCEEDED(hr)) pILFree(pidl);
3872 IPersistFolder2_Release(ppf2);
3875 IShellFolder_Release(desktop);
3878 static void test_GetUIObject(void)
3880 IShellFolder *psf_desktop;
3881 IContextMenu *pcm;
3882 LPITEMIDLIST pidl;
3883 HRESULT hr;
3884 WCHAR path[MAX_PATH];
3885 const WCHAR filename[] =
3886 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3888 if(!pSHBindToParent)
3890 win_skip("SHBindToParent missing.\n");
3891 return;
3894 GetCurrentDirectoryW(MAX_PATH, path);
3895 if(!lstrlenW(path))
3897 skip("GetCurrentDirectoryW returned an empty string.\n");
3898 return;
3900 lstrcatW(path, filename);
3901 SHGetDesktopFolder(&psf_desktop);
3903 CreateFilesFolders();
3905 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3906 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3907 if(SUCCEEDED(hr))
3909 IShellFolder *psf;
3910 LPCITEMIDLIST pidl_child;
3911 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3912 ok(hr == S_OK, "Got 0x%08x\n", hr);
3913 if(SUCCEEDED(hr))
3915 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, &pidl_child, &IID_IContextMenu, NULL,
3916 (void**)&pcm);
3917 ok(hr == S_OK, "Got 0x%08x\n", hr);
3918 if(SUCCEEDED(hr))
3920 const int baseItem = 0x40;
3921 HMENU hmenu = CreatePopupMenu();
3922 INT max_id, max_id_check;
3923 UINT count, i;
3924 const int id_upper_limit = 32767;
3925 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, baseItem, id_upper_limit, CMF_NORMAL);
3926 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3927 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3928 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3929 count = GetMenuItemCount(hmenu);
3930 ok(count, "Got %d\n", count);
3932 max_id_check = 0;
3933 for(i = 0; i < count; i++)
3935 MENUITEMINFOA mii;
3936 INT res;
3937 char buf[255], buf2[255];
3938 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3939 mii.cbSize = sizeof(MENUITEMINFOA);
3940 mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING;
3941 mii.dwTypeData = buf2;
3942 mii.cch = sizeof(buf2);
3944 SetLastError(0);
3945 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3946 ok(res, "Failed (last error: %d).\n", GetLastError());
3948 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3949 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3950 if(!(mii.fType & MFT_SEPARATOR))
3952 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3953 hr = IContextMenu_GetCommandString(pcm, mii.wID - baseItem, GCS_VERBA, 0, buf, sizeof(buf));
3954 ok(SUCCEEDED(hr) || hr == E_NOTIMPL, "for id 0x%x got 0x%08x (menustr: %s)\n", mii.wID - baseItem, hr, mii.dwTypeData);
3955 if (SUCCEEDED(hr))
3956 trace("for id 0x%x got string %s (menu string: %s)\n", mii.wID - baseItem, buf, mii.dwTypeData);
3957 else if (hr == E_NOTIMPL)
3958 trace("for id 0x%x got E_NOTIMPL (menu string: %s)\n", mii.wID - baseItem, mii.dwTypeData);
3961 max_id_check -= baseItem;
3962 ok((max_id_check == max_id) ||
3963 (max_id_check == max_id-1 /* Win 7 */),
3964 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3966 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3968 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3970 CMINVOKECOMMANDINFO cmi;
3971 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3972 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3974 /* Attempt to execute a nonexistent command */
3975 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3976 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3977 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3979 cmi.lpVerb = "foobar_wine_test";
3980 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3981 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3982 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3983 "Got 0x%08x\n", hr);
3985 #undef is_win2k
3987 DestroyMenu(hmenu);
3988 IContextMenu_Release(pcm);
3990 IShellFolder_Release(psf);
3992 if(pILFree) pILFree(pidl);
3995 IShellFolder_Release(psf_desktop);
3996 Cleanup();
3999 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
4000 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
4002 LPCITEMIDLIST child;
4003 IShellFolder *parent;
4004 STRRET filename;
4005 HRESULT hr;
4007 if(!pSHBindToParent){
4008 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
4009 if(path)
4010 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
4011 else
4012 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4013 return;
4016 if(path){
4017 if(!pidl){
4018 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
4019 return;
4022 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
4023 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
4024 if(FAILED(hr))
4025 return;
4027 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
4028 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
4029 if(FAILED(hr)){
4030 IShellFolder_Release(parent);
4031 return;
4034 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
4035 "Got unexpected string type: %d\n", filename.uType);
4036 if(filename.uType == STRRET_WSTR){
4037 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
4038 "didn't get expected path (%s), instead: %s\n",
4039 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
4040 SHFree(U(filename).pOleStr);
4041 }else if(filename.uType == STRRET_CSTR){
4042 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
4043 "didn't get expected path (%s), instead: %s\n",
4044 wine_dbgstr_w(path), U(filename).cStr);
4047 IShellFolder_Release(parent);
4048 }else
4049 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
4052 static void test_SHSimpleIDListFromPath(void)
4054 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
4055 const CHAR adirA[] = "C:\\sidlfpdir";
4056 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
4058 LPITEMIDLIST pidl = NULL;
4060 if(!pSHSimpleIDListFromPathAW){
4061 win_skip("SHSimpleIDListFromPathAW not available\n");
4062 return;
4065 br = CreateDirectoryA(adirA, NULL);
4066 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4068 if(is_unicode)
4069 pidl = pSHSimpleIDListFromPathAW(adirW);
4070 else
4071 pidl = pSHSimpleIDListFromPathAW(adirA);
4072 verify_pidl(pidl, adirW);
4073 pILFree(pidl);
4075 br = RemoveDirectoryA(adirA);
4076 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4078 if(is_unicode)
4079 pidl = pSHSimpleIDListFromPathAW(adirW);
4080 else
4081 pidl = pSHSimpleIDListFromPathAW(adirA);
4082 verify_pidl(pidl, adirW);
4083 pILFree(pidl);
4086 /* IFileSystemBindData impl */
4087 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
4088 REFIID riid, void **ppv)
4090 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
4091 IsEqualIID(riid, &IID_IUnknown)){
4092 *ppv = fsbd;
4093 return S_OK;
4095 return E_NOINTERFACE;
4098 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
4100 return 2;
4103 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
4105 return 1;
4108 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
4109 const WIN32_FIND_DATAW *pfd)
4111 ok(0, "SetFindData called\n");
4112 return E_NOTIMPL;
4115 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
4116 WIN32_FIND_DATAW *pfd)
4118 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4119 return S_OK;
4122 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
4123 WIN32_FIND_DATAW *pfd)
4125 memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
4126 return S_OK;
4129 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4130 WIN32_FIND_DATAW *pfd)
4132 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4133 *pfd->cFileName = 'a';
4134 *pfd->cAlternateFileName = 'a';
4135 return S_OK;
4138 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4139 WIN32_FIND_DATAW *pfd)
4141 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4142 HANDLE handle = FindFirstFileW(adirW, pfd);
4143 FindClose(handle);
4144 return S_OK;
4147 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4148 WIN32_FIND_DATAW *pfd)
4150 return E_FAIL;
4153 static IFileSystemBindDataVtbl fsbdVtbl = {
4154 fsbd_QueryInterface,
4155 fsbd_AddRef,
4156 fsbd_Release,
4157 fsbd_SetFindData,
4158 NULL
4161 static IFileSystemBindData fsbd = { &fsbdVtbl };
4163 static void test_ParseDisplayNamePBC(void)
4165 WCHAR wFileSystemBindData[] =
4166 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4167 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4168 WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
4169 WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
4170 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4172 IShellFolder *psf;
4173 IBindCtx *pbc;
4174 HRESULT hres;
4175 ITEMIDLIST *pidl;
4177 /* Check if we support WCHAR functions */
4178 SetLastError(0xdeadbeef);
4179 lstrcmpiW(adirW, adirW);
4180 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4181 win_skip("Most W-calls are not implemented\n");
4182 return;
4185 hres = SHGetDesktopFolder(&psf);
4186 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4187 if(FAILED(hres)){
4188 win_skip("Failed to get IShellFolder, can't run tests\n");
4189 return;
4192 /* fails on unknown dir with no IBindCtx */
4193 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4194 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4195 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4196 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
4197 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4198 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4199 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
4200 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4201 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4203 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4204 hres = CreateBindCtx(0, &pbc);
4205 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4207 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4208 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4209 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4210 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4211 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4212 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4213 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4214 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4215 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4217 /* unknown dir with IBindCtx with IFileSystemBindData */
4218 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4219 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4221 /* return E_FAIL from GetFindData */
4222 pidl = (ITEMIDLIST*)0xdeadbeef;
4223 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4224 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4225 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4226 "ParseDisplayName failed: 0x%08x\n", hres);
4227 if(SUCCEEDED(hres)){
4228 verify_pidl(pidl, adirW);
4229 ILFree(pidl);
4232 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4233 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4234 "ParseDisplayName failed: 0x%08x\n", hres);
4235 if(SUCCEEDED(hres)){
4236 verify_pidl(pidl, afileW);
4237 ILFree(pidl);
4240 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4241 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4242 "ParseDisplayName failed: 0x%08x\n", hres);
4243 if(SUCCEEDED(hres)){
4244 verify_pidl(pidl, afile2W);
4245 ILFree(pidl);
4248 /* set FIND_DATA struct to NULLs */
4249 pidl = (ITEMIDLIST*)0xdeadbeef;
4250 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4251 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4252 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4253 "ParseDisplayName failed: 0x%08x\n", hres);
4254 if(SUCCEEDED(hres)){
4255 verify_pidl(pidl, adirW);
4256 ILFree(pidl);
4259 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4260 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4261 "ParseDisplayName failed: 0x%08x\n", hres);
4262 if(SUCCEEDED(hres)){
4263 verify_pidl(pidl, afileW);
4264 ILFree(pidl);
4267 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4268 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4269 "ParseDisplayName failed: 0x%08x\n", hres);
4270 if(SUCCEEDED(hres)){
4271 verify_pidl(pidl, afile2W);
4272 ILFree(pidl);
4275 /* set FIND_DATA struct to junk */
4276 pidl = (ITEMIDLIST*)0xdeadbeef;
4277 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4278 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4279 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4280 "ParseDisplayName failed: 0x%08x\n", hres);
4281 if(SUCCEEDED(hres)){
4282 verify_pidl(pidl, adirW);
4283 ILFree(pidl);
4286 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4287 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4288 "ParseDisplayName failed: 0x%08x\n", hres);
4289 if(SUCCEEDED(hres)){
4290 verify_pidl(pidl, afileW);
4291 ILFree(pidl);
4294 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4295 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4296 "ParseDisplayName failed: 0x%08x\n", hres);
4297 if(SUCCEEDED(hres)){
4298 verify_pidl(pidl, afile2W);
4299 ILFree(pidl);
4302 /* set FIND_DATA struct to invalid data */
4303 pidl = (ITEMIDLIST*)0xdeadbeef;
4304 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4305 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4306 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4307 "ParseDisplayName failed: 0x%08x\n", hres);
4308 if(SUCCEEDED(hres)){
4309 verify_pidl(pidl, adirW);
4310 ILFree(pidl);
4313 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4314 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4315 "ParseDisplayName failed: 0x%08x\n", hres);
4316 if(SUCCEEDED(hres)){
4317 verify_pidl(pidl, afileW);
4318 ILFree(pidl);
4321 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4322 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4323 "ParseDisplayName failed: 0x%08x\n", hres);
4324 if(SUCCEEDED(hres)){
4325 verify_pidl(pidl, afile2W);
4326 ILFree(pidl);
4329 /* set FIND_DATA struct to valid data */
4330 pidl = (ITEMIDLIST*)0xdeadbeef;
4331 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4332 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4333 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4334 "ParseDisplayName failed: 0x%08x\n", hres);
4335 if(SUCCEEDED(hres)){
4336 verify_pidl(pidl, adirW);
4337 ILFree(pidl);
4340 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
4341 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4342 "ParseDisplayName failed: 0x%08x\n", hres);
4343 if(SUCCEEDED(hres)){
4344 verify_pidl(pidl, afileW);
4345 ILFree(pidl);
4348 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
4349 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4350 "ParseDisplayName failed: 0x%08x\n", hres);
4351 if(SUCCEEDED(hres)){
4352 verify_pidl(pidl, afile2W);
4353 ILFree(pidl);
4356 IBindCtx_Release(pbc);
4357 IShellFolder_Release(psf);
4360 static const CHAR testwindow_class[] = "testwindow";
4361 #define WM_USER_NOTIFY (WM_APP+1)
4363 struct ChNotifyTest {
4364 const char id[256];
4365 const UINT notify_count;
4366 UINT missing_events;
4367 UINT signal;
4368 const char path_1[256];
4369 const char path_2[256];
4370 } chnotify_tests[] = {
4371 {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
4372 {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
4373 {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
4376 struct ChNotifyTest *exp_data;
4377 BOOL test_new_delivery_flag;
4379 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4381 LONG signal = (LONG)lparam;
4383 switch(msg){
4384 case WM_USER_NOTIFY:
4385 if(exp_data->missing_events > 0) {
4386 WCHAR *path1, *path2;
4387 LPITEMIDLIST *pidls = (LPITEMIDLIST*)wparam;
4388 HANDLE hLock = NULL;
4390 if(test_new_delivery_flag) {
4391 hLock = SHChangeNotification_Lock((HANDLE)wparam, lparam, &pidls, &signal);
4392 ok(hLock != NULL, "SHChangeNotification_Lock returned NULL\n");
4395 ok(exp_data->signal == signal,
4396 "%s: expected notification type %x, got: %x\n",
4397 exp_data->id, exp_data->signal, signal);
4399 trace("verifying pidls for: %s\n", exp_data->id);
4400 path1 = make_wstr(exp_data->path_1);
4401 path2 = make_wstr(exp_data->path_2);
4402 verify_pidl(pidls[0], path1);
4403 verify_pidl(pidls[1], path2);
4404 HeapFree(GetProcessHeap(), 0, path1);
4405 HeapFree(GetProcessHeap(), 0, path2);
4407 exp_data->missing_events--;
4409 if(test_new_delivery_flag)
4410 SHChangeNotification_Unlock(hLock);
4411 }else
4412 ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4413 return 0;
4415 return DefWindowProc(hwnd, msg, wparam, lparam);
4418 static void register_testwindow_class(void)
4420 WNDCLASSEXA cls;
4421 ATOM ret;
4423 ZeroMemory(&cls, sizeof(cls));
4424 cls.cbSize = sizeof(cls);
4425 cls.style = 0;
4426 cls.lpfnWndProc = testwindow_wndproc;
4427 cls.hInstance = GetModuleHandleA(NULL);
4428 cls.lpszClassName = testwindow_class;
4430 SetLastError(0);
4431 ret = RegisterClassExA(&cls);
4432 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4435 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4436 * have to poll repeatedly for the message to appear */
4437 static void do_events(void)
4439 int c = 0;
4440 while (exp_data->missing_events && (c++ < 10)){
4441 MSG msg;
4442 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4443 TranslateMessage(&msg);
4444 DispatchMessageA(&msg);
4446 if(exp_data->missing_events)
4447 Sleep(500);
4449 trace("%s: took %d tries\n", exp_data->id, c);
4452 static void test_SHChangeNotify(BOOL test_new_delivery)
4454 HWND wnd;
4455 ULONG notifyID, i;
4456 HRESULT hr;
4457 BOOL br, has_unicode;
4458 SHChangeNotifyEntry entries[1];
4459 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4460 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4462 trace("SHChangeNotify tests (%x)\n", test_new_delivery);
4464 CreateDirectoryW(NULL, NULL);
4465 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4467 test_new_delivery_flag = test_new_delivery;
4468 if(!test_new_delivery)
4469 register_testwindow_class();
4471 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4472 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4473 NULL, NULL, GetModuleHandleA(NULL), 0);
4474 ok(wnd != NULL, "Failed to make a window\n");
4476 br = CreateDirectoryA(root_dirA, NULL);
4477 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4479 entries[0].pidl = NULL;
4480 if(has_unicode)
4481 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4482 else
4483 hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4484 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4485 entries[0].fRecursive = TRUE;
4487 notifyID = SHChangeNotifyRegister(wnd, !test_new_delivery ? SHCNRF_ShellLevel : SHCNRF_ShellLevel|SHCNRF_NewDelivery,
4488 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4489 ok(notifyID != 0, "Failed to register a window for change notifications\n");
4491 for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
4492 exp_data = chnotify_tests + i;
4494 exp_data->missing_events = exp_data->notify_count;
4495 SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
4496 strlen(exp_data->path_1) > 0 ? exp_data->path_1 : NULL,
4497 strlen(exp_data->path_2) > 0 ? exp_data->path_2 : NULL);
4498 do_events();
4499 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4501 if(has_unicode){
4502 WCHAR *path1, *path2;
4504 path1 = make_wstr(exp_data->path_1);
4505 path2 = make_wstr(exp_data->path_2);
4507 exp_data->missing_events = exp_data->notify_count;
4508 SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
4509 do_events();
4510 ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
4512 HeapFree(GetProcessHeap(), 0, path1);
4513 HeapFree(GetProcessHeap(), 0, path2);
4517 SHChangeNotifyDeregister(notifyID);
4518 DestroyWindow(wnd);
4520 ILFree((LPITEMIDLIST)entries[0].pidl);
4521 br = RemoveDirectoryA(root_dirA);
4522 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4525 static void test_SHCreateDefaultContextMenu(void)
4527 HKEY keys[16];
4528 WCHAR path[MAX_PATH];
4529 IShellFolder *desktop,*folder;
4530 IPersistFolder2 *persist;
4531 IContextMenu *cmenu;
4532 LONG status;
4533 LPITEMIDLIST pidlFolder, pidl_child, pidl;
4534 DEFCONTEXTMENU cminfo;
4535 HRESULT hr;
4536 UINT i;
4537 const WCHAR filename[] =
4538 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
4539 if(!pSHCreateDefaultContextMenu)
4541 win_skip("SHCreateDefaultContextMenu missing.\n");
4542 return;
4545 if(!pSHBindToParent)
4547 skip("SHBindToParent missing.\n");
4548 return;
4551 GetCurrentDirectoryW(MAX_PATH, path);
4552 if(!lstrlenW(path))
4554 skip("GetCurrentDirectoryW returned an empty string.\n");
4555 return;
4557 lstrcatW(path, filename);
4558 SHGetDesktopFolder(&desktop);
4560 CreateFilesFolders();
4562 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &pidl, 0);
4563 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
4564 if(SUCCEEDED(hr))
4567 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&folder, (LPCITEMIDLIST*)&pidl_child);
4568 ok(hr == S_OK, "Got 0x%08x\n", hr);
4570 IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
4571 IPersistFolder2_GetCurFolder(persist,&pidlFolder);
4572 IPersistFolder2_Release(persist);
4573 if(SUCCEEDED(hr))
4576 cminfo.hwnd=NULL;
4577 cminfo.pcmcb=NULL;
4578 cminfo.psf=folder;
4579 cminfo.pidlFolder=NULL;
4580 cminfo.apidl=(LPCITEMIDLIST*)&pidl_child;
4581 cminfo.cidl=1;
4582 cminfo.aKeys=NULL;
4583 cminfo.cKeys=0;
4584 cminfo.punkAssociationInfo=NULL;
4585 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
4586 ok(hr==S_OK,"Got 0x%08x\n", hr);
4587 IContextMenu_Release(cmenu);
4588 cminfo.pidlFolder=pidlFolder;
4589 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
4590 ok(hr==S_OK,"Got 0x%08x\n", hr);
4591 IContextMenu_Release(cmenu);
4592 status = RegOpenKeyExA(HKEY_CLASSES_ROOT,"*",0,KEY_READ,keys);
4593 if(status==ERROR_SUCCESS){
4594 for(i=1;i<16;i++)
4595 keys[i]=keys[0];
4596 cminfo.aKeys=keys;
4597 cminfo.cKeys=16;
4598 hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
4599 RegCloseKey(keys[0]);
4600 ok(hr==S_OK,"Got 0x%08x\n", hr);
4601 IContextMenu_Release(cmenu);
4604 ILFree(pidlFolder);
4605 IShellFolder_Release(folder);
4607 IShellFolder_Release(desktop);
4608 ILFree(pidl);
4609 Cleanup();
4612 START_TEST(shlfolder)
4614 init_function_pointers();
4615 /* if OleInitialize doesn't get called, ParseDisplayName returns
4616 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4617 OleInitialize(NULL);
4619 test_ParseDisplayName();
4620 test_SHParseDisplayName();
4621 test_BindToObject();
4622 test_EnumObjects_and_CompareIDs();
4623 test_GetDisplayName();
4624 test_GetAttributesOf();
4625 test_SHGetPathFromIDList();
4626 test_CallForAttributes();
4627 test_FolderShortcut();
4628 test_ITEMIDLIST_format();
4629 test_SHGetFolderPathA();
4630 test_SHGetFolderPathAndSubDirA();
4631 test_LocalizedNames();
4632 test_SHCreateShellItem();
4633 test_SHCreateShellItemArray();
4634 test_desktop_IPersist();
4635 test_GetUIObject();
4636 test_SHSimpleIDListFromPath();
4637 test_ParseDisplayNamePBC();
4638 test_SHGetNameFromIDList();
4639 test_SHGetItemFromDataObject();
4640 test_SHGetIDListFromObject();
4641 test_SHGetItemFromObject();
4642 test_ShellItemCompare();
4643 test_SHChangeNotify(FALSE);
4644 test_SHChangeNotify(TRUE);
4645 test_ShellItemBindToHandler();
4646 test_ShellItemGetAttributes();
4647 test_SHCreateDefaultContextMenu();
4649 OleUninitialize();