shell32: Don't allow binding to files in any ShellFolder implementation.
[wine/multimedia.git] / dlls / shell32 / tests / shlfolder.c
blob67a9630e3e74f62070e19a9d8580a5fa01f89adc
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);
74 static int strcmp_wa(LPCWSTR strw, const char *stra)
76 CHAR buf[512];
77 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
78 return lstrcmpA(stra, buf);
81 static void init_function_pointers(void)
83 HMODULE hmod;
84 HRESULT hr;
85 void *ptr;
87 hmod = GetModuleHandleA("shell32.dll");
89 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
90 MAKEFUNC(SHBindToParent);
91 MAKEFUNC(SHCreateItemFromIDList);
92 MAKEFUNC(SHCreateItemFromParsingName);
93 MAKEFUNC(SHCreateShellItem);
94 MAKEFUNC(SHCreateShellItemArray);
95 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
96 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
97 MAKEFUNC(SHGetFolderPathA);
98 MAKEFUNC(SHGetFolderPathAndSubDirA);
99 MAKEFUNC(SHGetPathFromIDListW);
100 MAKEFUNC(SHGetSpecialFolderPathA);
101 MAKEFUNC(SHGetSpecialFolderPathW);
102 MAKEFUNC(SHGetSpecialFolderLocation);
103 MAKEFUNC(SHParseDisplayName);
104 MAKEFUNC(SHGetNameFromIDList);
105 MAKEFUNC(SHGetItemFromDataObject);
106 MAKEFUNC(SHGetIDListFromObject);
107 MAKEFUNC(SHGetItemFromObject);
108 #undef MAKEFUNC
110 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
111 MAKEFUNC_ORD(ILFindLastID, 16);
112 MAKEFUNC_ORD(ILIsEqual, 21);
113 MAKEFUNC_ORD(ILCombine, 25);
114 MAKEFUNC_ORD(ILFree, 155);
115 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
116 #undef MAKEFUNC_ORD
118 /* test named exports */
119 ptr = GetProcAddress(hmod, "ILFree");
120 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
121 if (ptr)
123 #define TESTNAMED(f) \
124 ptr = (void*)GetProcAddress(hmod, #f); \
125 ok(ptr != 0, "expected named export for " #f "\n");
127 TESTNAMED(ILAppendID);
128 TESTNAMED(ILClone);
129 TESTNAMED(ILCloneFirst);
130 TESTNAMED(ILCombine);
131 TESTNAMED(ILCreateFromPath);
132 TESTNAMED(ILCreateFromPathA);
133 TESTNAMED(ILCreateFromPathW);
134 TESTNAMED(ILFindChild);
135 TESTNAMED(ILFindLastID);
136 TESTNAMED(ILGetNext);
137 TESTNAMED(ILGetSize);
138 TESTNAMED(ILIsEqual);
139 TESTNAMED(ILIsParent);
140 TESTNAMED(ILRemoveLastID);
141 TESTNAMED(ILSaveToStream);
142 #undef TESTNAMED
145 hmod = GetModuleHandleA("shlwapi.dll");
146 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
148 pIsWow64Process = (void*)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
150 hr = SHGetMalloc(&ppM);
151 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
154 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
155 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
157 size_t iLen;
159 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
160 return NULL;
162 if (iLen)
164 lpszPath += iLen;
165 if (lpszPath[-1] != '\\')
167 *lpszPath++ = '\\';
168 *lpszPath = '\0';
171 return lpszPath;
174 static void test_ParseDisplayName(void)
176 HRESULT hr;
177 IShellFolder *IDesktopFolder;
178 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
179 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
180 static const char *cInetTestA = "http:\\yyy";
181 static const char *cInetTest2A = "xx:yyy";
182 DWORD res;
183 WCHAR cTestDirW [MAX_PATH] = {0};
184 ITEMIDLIST *newPIDL;
185 BOOL bRes;
187 hr = SHGetDesktopFolder(&IDesktopFolder);
188 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
189 if(hr != S_OK) return;
191 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
192 if (pSHCreateShellItem)
194 /* null name and pidl */
195 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
196 NULL, NULL, NULL, NULL, NULL, 0);
197 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
199 /* null name */
200 newPIDL = (ITEMIDLIST*)0xdeadbeef;
201 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
202 NULL, NULL, NULL, NULL, &newPIDL, 0);
203 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
204 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
206 else
207 win_skip("Tests would crash on W2K and below\n");
209 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
210 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
211 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
212 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
213 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
214 if (hr == S_OK)
216 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
217 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
218 IMalloc_Free(ppM, newPIDL);
221 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
222 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
223 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
224 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
225 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
226 if (hr == S_OK)
228 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
229 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
230 IMalloc_Free(ppM, newPIDL);
233 res = GetFileAttributesA(cNonExistDir1A);
234 if(res != INVALID_FILE_ATTRIBUTES)
236 skip("Test directory unexpectedly exists\n");
237 goto finished;
240 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
241 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
242 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
243 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
244 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
246 res = GetFileAttributesA(cNonExistDir2A);
247 if(res != INVALID_FILE_ATTRIBUTES)
249 skip("Test directory unexpectedly exists\n");
250 goto finished;
253 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
254 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
255 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
256 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
257 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
259 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
260 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
261 * out it doesn't. The magic seems to happen in the file dialogs, then. */
262 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
264 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
265 goto finished;
268 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
269 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
270 if (!bRes) goto finished;
272 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
273 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
274 if (hr != S_OK) goto finished;
276 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
277 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
278 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
279 pILFindLastID(newPIDL)->mkid.abID[0]);
280 IMalloc_Free(ppM, newPIDL);
282 finished:
283 IShellFolder_Release(IDesktopFolder);
286 /* creates a file with the specified name for tests */
287 static void CreateTestFile(const CHAR *name)
289 HANDLE file;
290 DWORD written;
292 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
293 if (file != INVALID_HANDLE_VALUE)
295 WriteFile(file, name, strlen(name), &written, NULL);
296 WriteFile(file, "\n", strlen("\n"), &written, NULL);
297 CloseHandle(file);
302 /* initializes the tests */
303 static void CreateFilesFolders(void)
305 CreateDirectoryA(".\\testdir", NULL);
306 CreateDirectoryA(".\\testdir\\test.txt", NULL);
307 CreateTestFile (".\\testdir\\test1.txt ");
308 CreateTestFile (".\\testdir\\test2.txt ");
309 CreateTestFile (".\\testdir\\test3.txt ");
310 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
311 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
314 /* cleans after tests */
315 static void Cleanup(void)
317 DeleteFileA(".\\testdir\\test1.txt");
318 DeleteFileA(".\\testdir\\test2.txt");
319 DeleteFileA(".\\testdir\\test3.txt");
320 RemoveDirectoryA(".\\testdir\\test.txt");
321 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
322 RemoveDirectoryA(".\\testdir\\testdir2");
323 RemoveDirectoryA(".\\testdir");
327 /* perform test */
328 static void test_EnumObjects(IShellFolder *iFolder)
330 IEnumIDList *iEnumList;
331 LPITEMIDLIST newPIDL, idlArr[10];
332 ULONG NumPIDLs;
333 int i=0, j;
334 HRESULT hr;
336 static const WORD iResults [5][5] =
338 { 0,-1,-1,-1,-1},
339 { 1, 0,-1,-1,-1},
340 { 1, 1, 0,-1,-1},
341 { 1, 1, 1, 0,-1},
342 { 1, 1, 1, 1, 0}
345 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
346 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
347 static const ULONG attrs[5] =
349 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
350 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
351 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
352 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
353 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
356 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
357 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
359 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
360 * the filesystem shellfolders return S_OK even if less than 'celt' items are
361 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
362 * only ever returns a single entry per call. */
363 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
364 i += NumPIDLs;
365 ok (i == 5, "i: %d\n", i);
367 hr = IEnumIDList_Release(iEnumList);
368 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
370 /* Sort them first in case of wrong order from system */
371 for (i=0;i<5;i++) for (j=0;j<5;j++)
372 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
374 newPIDL = idlArr[i];
375 idlArr[i] = idlArr[j];
376 idlArr[j] = newPIDL;
379 for (i=0;i<5;i++) for (j=0;j<5;j++)
381 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
382 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
386 for (i = 0; i < 5; i++)
388 SFGAOF flags;
389 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
390 /* Native returns all flags no matter what we ask for */
391 flags = SFGAO_CANCOPY;
392 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
393 flags &= SFGAO_testfor;
394 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
395 ok(flags == (attrs[i]) ||
396 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
397 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
398 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
400 flags = SFGAO_testfor;
401 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
402 flags &= SFGAO_testfor;
403 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
404 ok(flags == attrs[i] ||
405 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
406 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
409 for (i=0;i<5;i++)
410 IMalloc_Free(ppM, idlArr[i]);
413 static void test_BindToObject(void)
415 HRESULT hr;
416 UINT cChars;
417 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
418 SHITEMID emptyitem = { 0, { 0 } };
419 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
420 WCHAR wszSystemDir[MAX_PATH];
421 char szSystemDir[MAX_PATH];
422 char buf[MAX_PATH];
423 WCHAR cwd[MAX_PATH];
424 WCHAR path[MAX_PATH];
425 HANDLE hfile;
426 WCHAR wszMyComputer[] = {
427 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
428 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
429 static const WCHAR filename_html[] = {'w','i','n','e','t','e','s','t','.','h','t','m','l',0};
430 static const WCHAR filename_txt[] = {'w','i','n','e','t','e','s','t','.','t','x','t',0};
431 static const WCHAR filename_foo[] = {'w','i','n','e','t','e','s','t','.','f','o','o',0};
433 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
434 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
436 hr = SHGetDesktopFolder(&psfDesktop);
437 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
438 if (hr != S_OK) return;
440 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
441 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
443 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
444 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
446 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
447 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
448 if (hr != S_OK) {
449 IShellFolder_Release(psfDesktop);
450 return;
453 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
454 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
455 IShellFolder_Release(psfDesktop);
456 IMalloc_Free(ppM, pidlMyComputer);
457 if (hr != S_OK) return;
459 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
460 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
462 if (0)
464 /* this call segfaults on 98SE */
465 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
466 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
469 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
470 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
471 if (cChars == 0 || cChars >= MAX_PATH) {
472 IShellFolder_Release(psfMyComputer);
473 return;
475 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
477 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
478 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
479 if (hr != S_OK) {
480 IShellFolder_Release(psfMyComputer);
481 return;
484 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
485 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
486 IShellFolder_Release(psfMyComputer);
487 IMalloc_Free(ppM, pidlSystemDir);
488 if (hr != S_OK) return;
490 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
491 ok (hr == E_INVALIDARG,
492 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
494 if (0)
496 /* this call segfaults on 98SE */
497 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
498 ok (hr == E_INVALIDARG,
499 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
502 IShellFolder_Release(psfSystemDir);
504 GetCurrentDirectoryA(MAX_PATH, buf);
505 if(!lstrlenA(buf))
507 skip("Failed to get current directory, skipping tests.\n");
508 return;
510 MultiByteToWideChar(CP_ACP, 0, buf, -1, cwd, MAX_PATH);
512 SHGetDesktopFolder(&psfDesktop);
514 /* Attempt BindToObject on files. */
516 /* .html */
517 lstrcpyW(path, cwd);
518 myPathAddBackslashW(path);
519 lstrcatW(path, filename_html);
520 hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
521 if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
523 CloseHandle(hfile);
524 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
525 ok(hr == S_OK ||
526 broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */ ||
527 broken(hr == E_FAIL) /* Win95 */,
528 "Got 0x%08x\n", hr);
529 if(SUCCEEDED(hr))
531 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
532 ok(hr == S_OK /* Win 7 */ || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) /* WinXP */,
533 "Got 0x%08x\n", hr);
534 if(SUCCEEDED(hr))
536 IPersist *pp;
537 hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
538 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* W2K */, "Got 0x%08x\n", hr);
539 if(SUCCEEDED(hr))
541 CLSID id;
542 hr = IPersist_GetClassID(pp, &id);
543 ok(hr == S_OK, "Got 0x%08x\n", hr);
544 ok(IsEqualIID(&id, &CLSID_ShellDocObjView), "Unexpected classid\n");
545 IPersist_Release(pp);
548 IShellFolder_Release(psfChild);
550 pILFree(pidl);
552 DeleteFileW(path);
554 else
555 win_skip("Failed to create .html testfile.\n");
557 /* .txt */
558 lstrcpyW(path, cwd);
559 myPathAddBackslashW(path);
560 lstrcatW(path, filename_txt);
561 hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
562 if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
564 CloseHandle(hfile);
565 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
566 ok(hr == S_OK ||
567 broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */ ||
568 broken(hr == E_FAIL) /* Win95 */,
569 "Got 0x%08x\n", hr);
570 if(SUCCEEDED(hr))
572 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
573 ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
574 || broken(hr == S_OK) /* W2K */,
575 "Got 0x%08x\n", hr);
576 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
577 pILFree(pidl);
579 DeleteFileW(path);
581 else
582 win_skip("Failed to create .txt testfile.\n");
584 /* .foo */
585 lstrcpyW(path, cwd);
586 myPathAddBackslashW(path);
587 lstrcatW(path, filename_foo);
588 hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
589 if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
591 CloseHandle(hfile);
592 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
593 ok(hr == S_OK ||
594 broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */ ||
595 broken(hr == E_FAIL) /* Win95 */,
596 "Got 0x%08x\n", hr);
597 if(SUCCEEDED(hr))
599 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
600 ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
601 || broken(hr == S_OK) /* W2K */,
602 "Got 0x%08x\n", hr);
603 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
604 pILFree(pidl);
606 DeleteFileW(path);
608 else
609 win_skip("Failed to create .foo testfile.\n");
611 /* And on the desktop */
612 if(pSHGetSpecialFolderPathW)
615 pSHGetSpecialFolderPathW(NULL, path, CSIDL_DESKTOP, FALSE);
616 myPathAddBackslashW(path);
617 lstrcatW(path, filename_html);
618 hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
619 if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
621 CloseHandle(hfile);
622 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
623 ok(hr == S_OK || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */,
624 "Got 0x%08x\n", hr);
625 if(SUCCEEDED(hr))
627 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
628 ok(hr == S_OK || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
629 "Got 0x%08x\n", hr);
630 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
631 pILFree(pidl);
633 if(!DeleteFileW(path))
634 trace("Failed to delete: %d\n", GetLastError());
637 else
638 win_skip("Failed to create .html testfile.\n");
640 pSHGetSpecialFolderPathW(NULL, path, CSIDL_DESKTOP, FALSE);
641 myPathAddBackslashW(path);
642 lstrcatW(path, filename_foo);
643 hfile = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
644 if(hfile != (HANDLE)INVALID_FILE_ATTRIBUTES)
646 CloseHandle(hfile);
647 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
648 ok(hr == S_OK || broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Win98SE */,
649 "Got 0x%08x\n", hr);
650 if(SUCCEEDED(hr))
652 hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
653 ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
654 || broken(hr == S_OK) /* W2K */,
655 "Got 0x%08x\n", hr);
656 if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
657 pILFree(pidl);
659 DeleteFileW(path);
661 else
662 win_skip("Failed to create .foo testfile.\n");
665 IShellFolder_Release(psfDesktop);
668 static void test_GetDisplayName(void)
670 BOOL result;
671 HRESULT hr;
672 HANDLE hTestFile;
673 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
674 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
675 DWORD attr;
676 STRRET strret;
677 LPSHELLFOLDER psfDesktop, psfPersonal;
678 IUnknown *psfFile;
679 SHITEMID emptyitem = { 0, { 0 } };
680 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
681 LPCITEMIDLIST pidlLast;
682 static const CHAR szFileName[] = "winetest.foo";
683 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
684 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
686 /* I'm trying to figure if there is a functional difference between calling
687 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
688 * binding to the shellfolder. One thing I thought of was that perhaps
689 * SHGetPathFromIDListW would be able to get the path to a file, which does
690 * not exist anymore, while the other method wouldn't. It turns out there's
691 * no functional difference in this respect.
694 if(!pSHGetSpecialFolderPathA) {
695 win_skip("SHGetSpecialFolderPathA is not available\n");
696 return;
699 /* First creating a directory in MyDocuments and a file in this directory. */
700 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
701 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
702 if (!result) return;
704 /* Use ANSI file functions so this works on Windows 9x */
705 lstrcatA(szTestDir, "\\winetest");
706 CreateDirectoryA(szTestDir, NULL);
707 attr=GetFileAttributesA(szTestDir);
708 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
710 ok(0, "unable to create the '%s' directory\n", szTestDir);
711 return;
714 lstrcpyA(szTestFile, szTestDir);
715 lstrcatA(szTestFile, "\\");
716 lstrcatA(szTestFile, szFileName);
717 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
718 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
719 if (hTestFile == INVALID_HANDLE_VALUE) return;
720 CloseHandle(hTestFile);
722 /* Getting an itemidlist for the file. */
723 hr = SHGetDesktopFolder(&psfDesktop);
724 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
725 if (hr != S_OK) return;
727 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
729 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
730 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
731 if (hr != S_OK) {
732 IShellFolder_Release(psfDesktop);
733 return;
736 pidlLast = pILFindLastID(pidlTestFile);
737 ok(pidlLast->mkid.cb >=76 ||
738 broken(pidlLast->mkid.cb == 28) || /* W2K */
739 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
740 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
741 if (pidlLast->mkid.cb >= 28) {
742 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
743 "Filename should be stored as ansi-string at this position!\n");
745 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
746 if (pidlLast->mkid.cb >= 76) {
747 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
748 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
749 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
750 "Filename should be stored as wchar-string at this position!\n");
753 /* It seems as if we cannot bind to regular files on windows, but only directories.
755 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
756 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
757 hr == E_NOTIMPL || /* Vista */
758 broken(hr == S_OK), /* Win9x, W2K */
759 "hr = %08x\n", hr);
760 if (hr == S_OK) {
761 IShellFolder_Release(psfFile);
764 if (!pSHBindToParent)
766 win_skip("SHBindToParent is missing\n");
767 DeleteFileA(szTestFile);
768 RemoveDirectoryA(szTestDir);
769 return;
772 /* Some tests for IShellFolder::SetNameOf */
773 if (pSHGetFolderPathAndSubDirA)
775 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
776 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
777 if (hr == S_OK) {
778 /* It's ok to use this fixed path. Call will fail anyway. */
779 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
780 LPITEMIDLIST pidlNew;
782 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
783 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
784 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
785 if (hr == S_OK)
787 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
788 "pidl returned from SetNameOf should be simple!\n");
790 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
791 * is implemented on top of SHFileOperation in WinXP. */
792 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
793 SHGDN_FORPARSING, NULL);
794 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
796 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
797 * SHGDN flags specify an absolute path. */
798 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
799 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
801 pILFree(pidlNew);
804 IShellFolder_Release(psfPersonal);
807 else
808 win_skip("Avoid needs of interaction on Win2k\n");
810 /* Deleting the file and the directory */
811 DeleteFileA(szTestFile);
812 RemoveDirectoryA(szTestDir);
814 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
815 if (pSHGetPathFromIDListW)
817 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
818 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
819 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
822 /* SHBindToParent fails, if called with a NULL PIDL. */
823 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
824 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
826 /* But it succeeds with an empty PIDL. */
827 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
828 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
829 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
830 if (hr == S_OK)
831 IShellFolder_Release(psfPersonal);
833 /* Binding to the folder and querying the display name of the file also works. */
834 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
835 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
836 if (hr != S_OK) {
837 IShellFolder_Release(psfDesktop);
838 return;
841 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
842 * pidlTestFile (In accordance with MSDN). */
843 ok (pILFindLastID(pidlTestFile) == pidlLast,
844 "SHBindToParent doesn't return the last id of the pidl param!\n");
846 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
847 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
848 if (hr != S_OK) {
849 IShellFolder_Release(psfDesktop);
850 IShellFolder_Release(psfPersonal);
851 return;
854 if (pStrRetToBufW)
856 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
857 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
858 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
861 ILFree(pidlTestFile);
862 IShellFolder_Release(psfDesktop);
863 IShellFolder_Release(psfPersonal);
866 static void test_CallForAttributes(void)
868 HKEY hKey;
869 LONG lResult;
870 HRESULT hr;
871 DWORD dwSize;
872 LPSHELLFOLDER psfDesktop;
873 LPITEMIDLIST pidlMyDocuments;
874 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
875 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
876 static const WCHAR wszCallForAttributes[] = {
877 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
878 static const WCHAR wszMyDocumentsKey[] = {
879 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
880 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
881 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
882 WCHAR wszMyDocuments[] = {
883 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
884 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
886 /* For the root of a namespace extension, the attributes are not queried by binding
887 * to the object and calling GetAttributesOf. Instead, the attributes are read from
888 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
890 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
891 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
892 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
893 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
895 hr = SHGetDesktopFolder(&psfDesktop);
896 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
897 if (hr != S_OK) return;
899 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
900 &pidlMyDocuments, NULL);
901 ok (hr == S_OK ||
902 broken(hr == E_INVALIDARG), /* Win95, NT4 */
903 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
904 if (hr != S_OK) {
905 IShellFolder_Release(psfDesktop);
906 return;
909 dwAttributes = 0xffffffff;
910 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
911 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
912 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
914 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
915 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
916 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
917 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
919 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
920 * key. So the test will return at this point, if run on wine.
922 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
923 ok (lResult == ERROR_SUCCESS ||
924 lResult == ERROR_ACCESS_DENIED,
925 "RegOpenKeyEx failed! result: %08x\n", lResult);
926 if (lResult != ERROR_SUCCESS) {
927 if (lResult == ERROR_ACCESS_DENIED)
928 skip("Not enough rights to open the registry key\n");
929 IMalloc_Free(ppM, pidlMyDocuments);
930 IShellFolder_Release(psfDesktop);
931 return;
934 /* Query MyDocuments' Attributes value, to be able to restore it later. */
935 dwSize = sizeof(DWORD);
936 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
937 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
938 if (lResult != ERROR_SUCCESS) {
939 RegCloseKey(hKey);
940 IMalloc_Free(ppM, pidlMyDocuments);
941 IShellFolder_Release(psfDesktop);
942 return;
945 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
946 dwSize = sizeof(DWORD);
947 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
948 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
949 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
950 if (lResult != ERROR_SUCCESS) {
951 RegCloseKey(hKey);
952 IMalloc_Free(ppM, pidlMyDocuments);
953 IShellFolder_Release(psfDesktop);
954 return;
957 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
958 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
959 * SFGAO_FILESYSTEM attributes. */
960 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
961 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
962 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
963 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
964 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
966 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
967 * GetAttributesOf. It seems that once there is a single attribute queried, for which
968 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
969 * the flags in Attributes are ignored.
971 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
972 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
973 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
974 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
975 if (hr == S_OK)
976 ok (dwAttributes == SFGAO_FILESYSTEM,
977 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
978 dwAttributes);
980 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
981 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
982 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
983 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
984 RegCloseKey(hKey);
985 IMalloc_Free(ppM, pidlMyDocuments);
986 IShellFolder_Release(psfDesktop);
989 static void test_GetAttributesOf(void)
991 HRESULT hr;
992 LPSHELLFOLDER psfDesktop, psfMyComputer;
993 SHITEMID emptyitem = { 0, { 0 } };
994 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
995 LPITEMIDLIST pidlMyComputer;
996 DWORD dwFlags;
997 static const DWORD desktopFlags[] = {
998 /* WinXP */
999 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
1000 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1001 /* Win2k */
1002 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
1003 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
1004 /* WinMe, Win9x, WinNT*/
1005 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
1006 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1008 static const DWORD myComputerFlags[] = {
1009 /* WinXP */
1010 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
1011 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1012 /* Win2k */
1013 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
1014 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1015 /* WinMe, Win9x, WinNT */
1016 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1017 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
1018 /* Win95, WinNT when queried directly */
1019 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
1020 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
1022 WCHAR wszMyComputer[] = {
1023 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1024 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1025 char cCurrDirA [MAX_PATH] = {0};
1026 WCHAR cCurrDirW [MAX_PATH];
1027 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
1028 IShellFolder *IDesktopFolder, *testIShellFolder;
1029 ITEMIDLIST *newPIDL;
1030 int len, i;
1031 BOOL foundFlagsMatch;
1033 hr = SHGetDesktopFolder(&psfDesktop);
1034 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1035 if (hr != S_OK) return;
1037 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
1038 dwFlags = 0xffffffff;
1039 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
1040 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
1041 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1042 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1044 if (desktopFlags[i] == dwFlags)
1045 foundFlagsMatch = TRUE;
1047 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1049 /* .. or with no itemidlist at all. */
1050 dwFlags = 0xffffffff;
1051 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
1052 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1053 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1054 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
1056 if (desktopFlags[i] == dwFlags)
1057 foundFlagsMatch = TRUE;
1059 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
1061 /* Testing the attributes of the MyComputer shellfolder */
1062 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1063 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1064 if (hr != S_OK) {
1065 IShellFolder_Release(psfDesktop);
1066 return;
1069 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
1070 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
1072 dwFlags = 0xffffffff;
1073 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
1074 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
1075 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1076 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1078 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
1079 foundFlagsMatch = TRUE;
1081 todo_wine
1082 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1084 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
1085 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
1086 IShellFolder_Release(psfDesktop);
1087 IMalloc_Free(ppM, pidlMyComputer);
1088 if (hr != S_OK) return;
1090 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
1091 todo_wine
1092 ok (hr == E_INVALIDARG ||
1093 broken(hr == S_OK), /* W2K and earlier */
1094 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
1096 dwFlags = 0xffffffff;
1097 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
1098 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
1099 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
1100 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
1102 if (myComputerFlags[i] == dwFlags)
1103 foundFlagsMatch = TRUE;
1105 todo_wine
1106 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
1108 IShellFolder_Release(psfMyComputer);
1110 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1111 len = lstrlenA(cCurrDirA);
1113 if (len == 0) {
1114 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1115 return;
1117 if (len > 3 && cCurrDirA[len-1] == '\\')
1118 cCurrDirA[len-1] = 0;
1120 /* create test directory */
1121 CreateFilesFolders();
1123 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1125 hr = SHGetDesktopFolder(&IDesktopFolder);
1126 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1128 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1129 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1131 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1132 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1134 IMalloc_Free(ppM, newPIDL);
1136 /* get relative PIDL */
1137 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1138 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1140 /* test the shell attributes of the test directory using the relative PIDL */
1141 dwFlags = SFGAO_FOLDER;
1142 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1143 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1144 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1146 /* free memory */
1147 IMalloc_Free(ppM, newPIDL);
1149 /* append testdirectory name to path */
1150 if (cCurrDirA[len-1] == '\\')
1151 cCurrDirA[len-1] = 0;
1152 lstrcatA(cCurrDirA, "\\testdir");
1153 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1155 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1156 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1158 /* test the shell attributes of the test directory using the absolute PIDL */
1159 dwFlags = SFGAO_FOLDER;
1160 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1161 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1162 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1164 /* free memory */
1165 IMalloc_Free(ppM, newPIDL);
1167 IShellFolder_Release(testIShellFolder);
1169 Cleanup();
1171 IShellFolder_Release(IDesktopFolder);
1174 static void test_SHGetPathFromIDList(void)
1176 SHITEMID emptyitem = { 0, { 0 } };
1177 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1178 LPITEMIDLIST pidlMyComputer;
1179 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1180 BOOL result;
1181 HRESULT hr;
1182 LPSHELLFOLDER psfDesktop;
1183 WCHAR wszMyComputer[] = {
1184 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1185 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1186 WCHAR wszFileName[MAX_PATH];
1187 LPITEMIDLIST pidlTestFile;
1188 HANDLE hTestFile;
1189 STRRET strret;
1190 static WCHAR wszTestFile[] = {
1191 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1192 LPITEMIDLIST pidlPrograms;
1194 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1196 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1197 return;
1200 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1201 wszPath[0] = 'a';
1202 wszPath[1] = '\0';
1203 result = pSHGetPathFromIDListW(NULL, wszPath);
1204 ok(!result, "Expected failure\n");
1205 ok(!wszPath[0], "Expected empty string\n");
1207 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1208 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1209 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1210 if (!result) return;
1212 /* Check if we are on Win9x */
1213 SetLastError(0xdeadbeef);
1214 lstrcmpiW(wszDesktop, wszDesktop);
1215 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1217 win_skip("Most W-calls are not implemented\n");
1218 return;
1221 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1222 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1223 if (!result) return;
1224 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1226 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1227 hr = SHGetDesktopFolder(&psfDesktop);
1228 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1229 if (hr != S_OK) return;
1231 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1232 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1233 if (hr != S_OK) {
1234 IShellFolder_Release(psfDesktop);
1235 return;
1238 SetLastError(0xdeadbeef);
1239 wszPath[0] = 'a';
1240 wszPath[1] = '\0';
1241 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1242 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1243 ok (GetLastError()==0xdeadbeef ||
1244 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1245 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1246 ok (!wszPath[0], "Expected empty path\n");
1247 if (result) {
1248 IShellFolder_Release(psfDesktop);
1249 return;
1252 IMalloc_Free(ppM, pidlMyComputer);
1254 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1255 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1256 if (!result) {
1257 IShellFolder_Release(psfDesktop);
1258 return;
1260 myPathAddBackslashW(wszFileName);
1261 lstrcatW(wszFileName, wszTestFile);
1262 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1263 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1264 if (hTestFile == INVALID_HANDLE_VALUE) {
1265 IShellFolder_Release(psfDesktop);
1266 return;
1268 CloseHandle(hTestFile);
1270 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1271 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1272 if (hr != S_OK) {
1273 IShellFolder_Release(psfDesktop);
1274 DeleteFileW(wszFileName);
1275 IMalloc_Free(ppM, pidlTestFile);
1276 return;
1279 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1280 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1281 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1282 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1283 IShellFolder_Release(psfDesktop);
1284 DeleteFileW(wszFileName);
1285 if (hr != S_OK) {
1286 IMalloc_Free(ppM, pidlTestFile);
1287 return;
1289 if (pStrRetToBufW)
1291 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1292 ok(0 == lstrcmpW(wszFileName, wszPath),
1293 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1294 "returned incorrect path for file placed on desktop\n");
1297 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1298 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1299 IMalloc_Free(ppM, pidlTestFile);
1300 if (!result) return;
1301 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1304 /* Test if we can get the path from the start menu "program files" PIDL. */
1305 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1306 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1308 SetLastError(0xdeadbeef);
1309 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1310 IMalloc_Free(ppM, pidlPrograms);
1311 ok(result, "SHGetPathFromIDListW failed\n");
1314 static void test_EnumObjects_and_CompareIDs(void)
1316 ITEMIDLIST *newPIDL;
1317 IShellFolder *IDesktopFolder, *testIShellFolder;
1318 char cCurrDirA [MAX_PATH] = {0};
1319 static const CHAR cTestDirA[] = "\\testdir";
1320 WCHAR cTestDirW[MAX_PATH];
1321 int len;
1322 HRESULT hr;
1324 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1325 len = lstrlenA(cCurrDirA);
1327 if(len == 0) {
1328 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1329 return;
1331 if(cCurrDirA[len-1] == '\\')
1332 cCurrDirA[len-1] = 0;
1334 lstrcatA(cCurrDirA, cTestDirA);
1335 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1337 hr = SHGetDesktopFolder(&IDesktopFolder);
1338 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1340 CreateFilesFolders();
1342 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1343 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1345 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1346 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1348 test_EnumObjects(testIShellFolder);
1350 IShellFolder_Release(testIShellFolder);
1352 Cleanup();
1354 IMalloc_Free(ppM, newPIDL);
1356 IShellFolder_Release(IDesktopFolder);
1359 /* A simple implementation of an IPropertyBag, which returns fixed values for
1360 * 'Target' and 'Attributes' properties.
1362 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1363 void **ppvObject)
1365 if (!ppvObject)
1366 return E_INVALIDARG;
1368 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1369 *ppvObject = iface;
1370 } else {
1371 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1372 return E_NOINTERFACE;
1375 IPropertyBag_AddRef(iface);
1376 return S_OK;
1379 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1380 return 2;
1383 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1384 return 1;
1387 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1388 VARIANT *pVar, IErrorLog *pErrorLog)
1390 static const WCHAR wszTargetSpecialFolder[] = {
1391 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1392 static const WCHAR wszTarget[] = {
1393 'T','a','r','g','e','t',0 };
1394 static const WCHAR wszAttributes[] = {
1395 'A','t','t','r','i','b','u','t','e','s',0 };
1396 static const WCHAR wszResolveLinkFlags[] = {
1397 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1398 static const WCHAR wszTargetKnownFolder[] = {
1399 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1400 static const WCHAR wszCLSID[] = {
1401 'C','L','S','I','D',0 };
1403 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1404 ok(V_VT(pVar) == VT_I4 ||
1405 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1406 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1407 return E_INVALIDARG;
1410 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1412 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1413 return E_INVALIDARG;
1416 if (!lstrcmpW(pszPropName, wszTarget)) {
1417 WCHAR wszPath[MAX_PATH];
1418 BOOL result;
1420 ok(V_VT(pVar) == VT_BSTR ||
1421 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1422 "Wrong variant type for 'Target' property!\n");
1423 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1425 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1426 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1427 if (!result) return E_INVALIDARG;
1429 V_BSTR(pVar) = SysAllocString(wszPath);
1430 return S_OK;
1433 if (!lstrcmpW(pszPropName, wszAttributes)) {
1434 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1435 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1436 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1437 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1438 return S_OK;
1441 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1442 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1443 /* TODO */
1444 return E_INVALIDARG;
1447 if (!lstrcmpW(pszPropName, wszCLSID)) {
1448 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1449 /* TODO */
1450 return E_INVALIDARG;
1453 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1454 return E_INVALIDARG;
1457 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1458 VARIANT *pVar)
1460 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1461 return E_NOTIMPL;
1464 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1465 InitPropertyBag_IPropertyBag_QueryInterface,
1466 InitPropertyBag_IPropertyBag_AddRef,
1467 InitPropertyBag_IPropertyBag_Release,
1468 InitPropertyBag_IPropertyBag_Read,
1469 InitPropertyBag_IPropertyBag_Write
1472 static struct IPropertyBag InitPropertyBag = {
1473 &InitPropertyBag_IPropertyBagVtbl
1476 static void test_FolderShortcut(void) {
1477 IPersistPropertyBag *pPersistPropertyBag;
1478 IShellFolder *pShellFolder, *pDesktopFolder;
1479 IPersistFolder3 *pPersistFolder3;
1480 HRESULT hr;
1481 STRRET strret;
1482 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1483 BOOL result;
1484 CLSID clsid;
1485 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1486 HKEY hShellExtKey;
1487 WCHAR wszWineTestFolder[] = {
1488 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1489 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1490 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1491 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1492 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1493 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1494 'N','a','m','e','S','p','a','c','e','\\',
1495 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1496 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1498 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1499 static const GUID CLSID_UnixDosFolder =
1500 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1502 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1503 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1504 return;
1507 if (!pSHGetFolderPathAndSubDirA)
1509 win_skip("FolderShortcut test doesn't work on Win2k\n");
1510 return;
1513 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1514 * via their IPersistPropertyBag interface. And that the target folder
1515 * is taken from the IPropertyBag's 'Target' property.
1517 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1518 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1519 if (hr == REGDB_E_CLASSNOTREG) {
1520 win_skip("CLSID_FolderShortcut is not implemented\n");
1521 return;
1523 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1524 if (hr != S_OK) return;
1526 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1527 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1528 if (hr != S_OK) {
1529 IPersistPropertyBag_Release(pPersistPropertyBag);
1530 return;
1533 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1534 (LPVOID*)&pShellFolder);
1535 IPersistPropertyBag_Release(pPersistPropertyBag);
1536 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1537 if (hr != S_OK) return;
1539 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1540 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1541 if (hr != S_OK) {
1542 IShellFolder_Release(pShellFolder);
1543 return;
1546 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1547 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1548 if (!result) return;
1550 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1551 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1553 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1554 IShellFolder_Release(pShellFolder);
1555 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1556 if (hr != S_OK) return;
1558 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1559 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1560 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1562 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1563 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1564 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1566 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1567 * shell namespace. The target folder, read from the property bag above, remains untouched.
1568 * The following tests show this: The itemidlist for some imaginary shellfolder object
1569 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1570 * itemidlist, but GetDisplayNameOf still returns the path from above.
1572 hr = SHGetDesktopFolder(&pDesktopFolder);
1573 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1574 if (hr != S_OK) return;
1576 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1577 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1578 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1579 RegCloseKey(hShellExtKey);
1580 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1581 &pidlWineTestFolder, NULL);
1582 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1583 IShellFolder_Release(pDesktopFolder);
1584 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1585 if (hr != S_OK) return;
1587 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1588 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1589 if (hr != S_OK) {
1590 IPersistFolder3_Release(pPersistFolder3);
1591 pILFree(pidlWineTestFolder);
1592 return;
1595 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1596 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1597 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1598 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1599 pILFree(pidlCurrentFolder);
1600 pILFree(pidlWineTestFolder);
1602 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1603 IPersistFolder3_Release(pPersistFolder3);
1604 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1605 if (hr != S_OK) return;
1607 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1608 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1609 if (hr != S_OK) {
1610 IShellFolder_Release(pShellFolder);
1611 return;
1614 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1615 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1617 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1618 * but ShellFSFolders. */
1619 myPathAddBackslashW(wszDesktopPath);
1620 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1621 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1622 IShellFolder_Release(pShellFolder);
1623 return;
1626 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1627 &pidlSubFolder, NULL);
1628 RemoveDirectoryW(wszDesktopPath);
1629 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1630 if (hr != S_OK) {
1631 IShellFolder_Release(pShellFolder);
1632 return;
1635 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1636 (LPVOID*)&pPersistFolder3);
1637 IShellFolder_Release(pShellFolder);
1638 pILFree(pidlSubFolder);
1639 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1640 if (hr != S_OK)
1641 return;
1643 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1644 * a little bit and also allow CLSID_UnixDosFolder. */
1645 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1646 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1647 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1648 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1650 IPersistFolder3_Release(pPersistFolder3);
1653 #include "pshpack1.h"
1654 struct FileStructA {
1655 BYTE type;
1656 BYTE dummy;
1657 DWORD dwFileSize;
1658 WORD uFileDate; /* In our current implementation this is */
1659 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1660 WORD uFileAttribs;
1661 CHAR szName[1];
1664 struct FileStructW {
1665 WORD cbLen; /* Length of this element. */
1666 BYTE abFooBar1[6]; /* Beyond any recognition. */
1667 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1668 WORD uTime; /* (this is currently speculation) */
1669 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1670 WORD uTime2; /* (this is currently speculation) */
1671 BYTE abFooBar2[4]; /* Beyond any recognition. */
1672 WCHAR wszName[1]; /* The long filename in unicode. */
1673 /* Just for documentation: Right after the unicode string: */
1674 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1675 * SHITEMID->cb == uOffset + cbLen */
1677 #include "poppack.h"
1679 static void test_ITEMIDLIST_format(void) {
1680 WCHAR wszPersonal[MAX_PATH];
1681 LPSHELLFOLDER psfDesktop, psfPersonal;
1682 LPITEMIDLIST pidlPersonal, pidlFile;
1683 HANDLE hFile;
1684 HRESULT hr;
1685 BOOL bResult;
1686 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1687 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1688 int i;
1690 if (!pSHGetSpecialFolderPathW) return;
1692 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1693 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1694 if (!bResult) return;
1696 SetLastError(0xdeadbeef);
1697 bResult = SetCurrentDirectoryW(wszPersonal);
1698 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1699 win_skip("Most W-calls are not implemented\n");
1700 return;
1702 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1703 if (!bResult) return;
1705 hr = SHGetDesktopFolder(&psfDesktop);
1706 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1707 if (hr != S_OK) return;
1709 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1710 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1711 if (hr != S_OK) {
1712 IShellFolder_Release(psfDesktop);
1713 return;
1716 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1717 (LPVOID*)&psfPersonal);
1718 IShellFolder_Release(psfDesktop);
1719 pILFree(pidlPersonal);
1720 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1721 if (hr != S_OK) return;
1723 for (i=0; i<3; i++) {
1724 CHAR szFile[MAX_PATH];
1725 struct FileStructA *pFileStructA;
1726 WORD cbOffset;
1728 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1730 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1731 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1732 if (hFile == INVALID_HANDLE_VALUE) {
1733 IShellFolder_Release(psfPersonal);
1734 return;
1736 CloseHandle(hFile);
1738 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1739 DeleteFileW(wszFile[i]);
1740 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1741 if (hr != S_OK) {
1742 IShellFolder_Release(psfPersonal);
1743 return;
1746 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1747 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1748 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1749 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1751 if (i < 2) /* First two file names are already in valid 8.3 format */
1752 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1753 else
1754 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1755 * can't implement this correctly, since unix filesystems don't support
1756 * this nasty short/long filename stuff. So we'll probably stay with our
1757 * current habbit of storing the long filename here, which seems to work
1758 * just fine. */
1759 todo_wine
1760 ok(pidlFile->mkid.abID[18] == '~' ||
1761 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1762 "Should be derived 8.3 name!\n");
1764 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1765 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1766 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1767 "Alignment byte, where there shouldn't be!\n");
1769 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1770 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1771 "There should be an alignment byte, but isn't!\n");
1773 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1774 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1775 ok ((cbOffset >= sizeof(struct FileStructA) &&
1776 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1777 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1778 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1779 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1781 if (cbOffset >= sizeof(struct FileStructA) &&
1782 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1784 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1786 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1787 "FileStructW's offset and length should add up to the PIDL's length!\n");
1789 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1790 /* Since we just created the file, time of creation,
1791 * time of last access and time of last write access just be the same.
1792 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1793 * after the first run. I do remember something with NTFS keeping the creation time
1794 * if a file is deleted and then created again within a couple of seconds or so.
1795 * Might be the reason. */
1796 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1797 pFileStructA->uFileTime == pFileStructW->uTime,
1798 "Last write time should match creation time!\n");
1800 /* On FAT filesystems the last access time is midnight
1801 local time, so the values of uDate2 and uTime2 will
1802 depend on the local timezone. If the times are exactly
1803 equal then the dates should be identical for both FAT
1804 and NTFS as no timezone is more than 1 day away from UTC.
1806 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1808 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1809 "Last write date and time should match last access date and time!\n");
1811 else
1813 /* Filesystem may be FAT. Check date within 1 day
1814 and seconds are zero. */
1815 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1816 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1817 "Last access time on FAT filesystems should have zero seconds.\n");
1818 /* TODO: Perform check for date being within one day.*/
1821 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1822 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1823 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1824 "The filename should be stored in unicode at this position!\n");
1828 pILFree(pidlFile);
1831 IShellFolder_Release(psfPersonal);
1834 static void test_SHGetFolderPathA(void)
1836 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1837 BOOL is_wow64;
1838 char path[MAX_PATH];
1839 char path_x86[MAX_PATH];
1840 char path_key[MAX_PATH];
1841 HRESULT hr;
1842 HKEY key;
1844 if (!pSHGetFolderPathA)
1846 win_skip("SHGetFolderPathA not present\n");
1847 return;
1849 if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1851 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
1852 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1853 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1854 if (hr == E_FAIL)
1856 win_skip( "Program Files (x86) not supported\n" );
1857 return;
1859 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1860 if (is_win64)
1862 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1863 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1864 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1866 else
1868 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1869 if (is_wow64)
1870 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1871 else
1872 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1874 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1876 DWORD type, count = sizeof(path_x86);
1877 if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1879 ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1880 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1882 else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1883 RegCloseKey( key );
1886 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
1887 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1888 hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
1889 if (hr == E_FAIL)
1891 win_skip( "Common Files (x86) not supported\n" );
1892 return;
1894 ok( !hr, "SHGetFolderPathA failed %x\n", hr );
1895 if (is_win64)
1897 ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1898 ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1899 ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1901 else
1903 ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1904 if (is_wow64)
1905 ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1906 else
1907 ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1909 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1911 DWORD type, count = sizeof(path_x86);
1912 if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1914 ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1915 ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1917 else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1921 static void test_SHGetFolderPathAndSubDirA(void)
1923 HRESULT ret;
1924 BOOL delret;
1925 DWORD dwret;
1926 int i;
1927 static char wine[] = "wine";
1928 static char winetemp[] = "wine\\temp";
1929 static char appdata[MAX_PATH];
1930 static char testpath[MAX_PATH];
1931 static char toolongpath[MAX_PATH+1];
1933 if(!pSHGetFolderPathAndSubDirA)
1935 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1936 return;
1939 if(!pSHGetFolderPathA) {
1940 win_skip("SHGetFolderPathA not present!\n");
1941 return;
1943 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1945 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1946 return;
1949 sprintf(testpath, "%s\\%s", appdata, winetemp);
1950 delret = RemoveDirectoryA(testpath);
1951 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1952 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1953 return;
1956 sprintf(testpath, "%s\\%s", appdata, wine);
1957 delret = RemoveDirectoryA(testpath);
1958 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1959 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1960 return;
1963 /* test invalid second parameter */
1964 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1965 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1967 /* test fourth parameter */
1968 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1969 switch(ret) {
1970 case S_OK: /* winvista */
1971 ok(!strncmp(appdata, testpath, strlen(appdata)),
1972 "expected %s to start with %s\n", testpath, appdata);
1973 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1974 "expected %s to end with %s\n", testpath, winetemp);
1975 break;
1976 case E_INVALIDARG: /* winxp, win2k3 */
1977 break;
1978 default:
1979 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
1982 /* test fifth parameter */
1983 testpath[0] = '\0';
1984 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1985 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1986 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1988 testpath[0] = '\0';
1989 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1990 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1991 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1993 testpath[0] = '\0';
1994 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1995 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1996 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1998 for(i=0; i< MAX_PATH; i++)
1999 toolongpath[i] = '0' + i % 10;
2000 toolongpath[MAX_PATH] = '\0';
2001 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
2002 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
2003 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
2005 testpath[0] = '\0';
2006 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
2007 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
2009 /* test a not existing path */
2010 testpath[0] = '\0';
2011 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2012 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
2013 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
2015 /* create a directory inside a not existing directory */
2016 testpath[0] = '\0';
2017 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
2018 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
2019 ok(!strncmp(appdata, testpath, strlen(appdata)),
2020 "expected %s to start with %s\n", testpath, appdata);
2021 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
2022 "expected %s to end with %s\n", testpath, winetemp);
2023 dwret = GetFileAttributes(testpath);
2024 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
2026 /* cleanup */
2027 sprintf(testpath, "%s\\%s", appdata, winetemp);
2028 RemoveDirectoryA(testpath);
2029 sprintf(testpath, "%s\\%s", appdata, wine);
2030 RemoveDirectoryA(testpath);
2033 static void test_LocalizedNames(void)
2035 static char cCurrDirA[MAX_PATH];
2036 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
2037 IShellFolder *IDesktopFolder, *testIShellFolder;
2038 ITEMIDLIST *newPIDL;
2039 int len;
2040 HRESULT hr;
2041 static char resourcefile[MAX_PATH];
2042 DWORD res;
2043 HANDLE file;
2044 STRRET strret;
2046 static const char desktopini_contents1[] =
2047 "[.ShellClassInfo]\r\n"
2048 "LocalizedResourceName=@";
2049 static const char desktopini_contents2[] =
2050 ",-1\r\n";
2051 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
2052 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
2054 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
2055 CreateDirectoryA(".\\testfolder", NULL);
2057 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
2059 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
2061 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
2062 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2063 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
2064 ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
2065 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
2066 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
2067 "WriteFile failed %i\n", GetLastError());
2068 CloseHandle(file);
2070 /* get IShellFolder for parent */
2071 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
2072 len = lstrlenA(cCurrDirA);
2074 if (len == 0) {
2075 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
2076 goto cleanup;
2078 if(cCurrDirA[len-1] == '\\')
2079 cCurrDirA[len-1] = 0;
2081 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
2083 hr = SHGetDesktopFolder(&IDesktopFolder);
2084 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
2086 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
2087 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2089 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
2090 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
2092 IMalloc_Free(ppM, newPIDL);
2094 /* windows reads the display name from the resource */
2095 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
2096 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
2098 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
2099 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2101 if (hr == S_OK && pStrRetToBufW)
2103 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2104 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2105 todo_wine
2106 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2107 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2108 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2111 /* editing name is also read from the resource */
2112 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
2113 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2115 if (hr == S_OK && pStrRetToBufW)
2117 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2118 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2119 todo_wine
2120 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
2121 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
2122 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2125 /* parsing name is unchanged */
2126 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
2127 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
2129 if (hr == S_OK && pStrRetToBufW)
2131 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
2132 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
2133 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
2136 IShellFolder_Release(IDesktopFolder);
2137 IShellFolder_Release(testIShellFolder);
2139 IMalloc_Free(ppM, newPIDL);
2141 cleanup:
2142 DeleteFileA(".\\testfolder\\desktop.ini");
2143 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
2144 RemoveDirectoryA(".\\testfolder");
2147 static void test_SHCreateShellItem(void)
2149 IShellItem *shellitem, *shellitem2;
2150 IPersistIDList *persistidl;
2151 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2152 HRESULT ret;
2153 char curdirA[MAX_PATH];
2154 WCHAR curdirW[MAX_PATH];
2155 WCHAR fnbufW[MAX_PATH];
2156 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2157 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2159 GetCurrentDirectoryA(MAX_PATH, curdirA);
2161 if (!pSHCreateShellItem)
2163 win_skip("SHCreateShellItem isn't available\n");
2164 return;
2167 if (!lstrlenA(curdirA))
2169 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2170 return;
2173 if(pSHGetSpecialFolderLocation)
2175 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2176 ok(ret == S_OK, "Got 0x%08x\n", ret);
2178 else
2180 win_skip("pSHGetSpecialFolderLocation missing.\n");
2181 pidl_desktop = NULL;
2184 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2186 ret = SHGetDesktopFolder(&desktopfolder);
2187 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2189 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2190 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2192 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2193 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2195 CreateTestFile(".\\testfile");
2197 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2198 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2200 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
2202 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2203 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2205 if (0) /* crashes on Windows XP */
2207 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2208 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2209 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2210 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2213 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2214 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2215 if (SUCCEEDED(ret))
2217 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2218 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2219 if (SUCCEEDED(ret))
2221 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2222 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2223 if (SUCCEEDED(ret))
2225 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2226 pILFree(pidl_test);
2228 IPersistIDList_Release(persistidl);
2230 IShellItem_Release(shellitem);
2233 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2234 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2235 if (SUCCEEDED(ret))
2237 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2238 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2239 if (SUCCEEDED(ret))
2241 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2242 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2243 if (SUCCEEDED(ret))
2245 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2246 pILFree(pidl_test);
2248 IPersistIDList_Release(persistidl);
2251 ret = IShellItem_GetParent(shellitem, &shellitem2);
2252 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2253 if (SUCCEEDED(ret))
2255 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2256 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2257 if (SUCCEEDED(ret))
2259 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2260 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2261 if (SUCCEEDED(ret))
2263 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2264 pILFree(pidl_test);
2266 IPersistIDList_Release(persistidl);
2268 IShellItem_Release(shellitem2);
2271 IShellItem_Release(shellitem);
2274 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2275 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2276 if (SUCCEEDED(ret))
2278 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2279 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2280 if (SUCCEEDED(ret))
2282 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2283 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2284 if (SUCCEEDED(ret))
2286 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2287 pILFree(pidl_test);
2289 IPersistIDList_Release(persistidl);
2291 IShellItem_Release(shellitem);
2294 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2295 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2296 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2297 if (SUCCEEDED(ret))
2299 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2300 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2301 if (SUCCEEDED(ret))
2303 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2304 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2305 if (SUCCEEDED(ret))
2307 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2308 pILFree(pidl_test);
2310 IPersistIDList_Release(persistidl);
2312 IShellItem_Release(shellitem);
2315 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2316 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2317 if (SUCCEEDED(ret))
2319 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2320 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2321 if (SUCCEEDED(ret))
2323 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2324 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2325 if (SUCCEEDED(ret))
2327 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2328 pILFree(pidl_test);
2330 IPersistIDList_Release(persistidl);
2333 IShellItem_Release(shellitem);
2336 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2337 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2338 if (SUCCEEDED(ret))
2340 ret = IShellItem_GetParent(shellitem, &shellitem2);
2341 ok(FAILED(ret), "Got 0x%08x\n", ret);
2342 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2343 IShellItem_Release(shellitem);
2346 /* SHCreateItemFromParsingName */
2347 if(pSHCreateItemFromParsingName)
2349 if(0)
2351 /* Crashes under windows 7 */
2352 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2355 shellitem = (void*)0xdeadbeef;
2356 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2357 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2358 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2360 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2361 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2362 "SHCreateItemFromParsingName returned %x\n", ret);
2363 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2365 lstrcpyW(fnbufW, curdirW);
2366 myPathAddBackslashW(fnbufW);
2367 lstrcatW(fnbufW, testfileW);
2369 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2370 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2371 if(SUCCEEDED(ret))
2373 LPWSTR tmp_fname;
2374 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2375 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2376 if(SUCCEEDED(ret))
2378 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2379 CoTaskMemFree(tmp_fname);
2381 IShellItem_Release(shellitem);
2384 else
2385 win_skip("No SHCreateItemFromParsingName\n");
2388 /* SHCreateItemFromIDList */
2389 if(pSHCreateItemFromIDList)
2391 if(0)
2393 /* Crashes under win7 */
2394 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2397 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2398 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2400 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2401 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2402 if (SUCCEEDED(ret))
2404 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2405 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2406 if (SUCCEEDED(ret))
2408 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2409 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2410 if (SUCCEEDED(ret))
2412 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2413 pILFree(pidl_test);
2415 IPersistIDList_Release(persistidl);
2417 IShellItem_Release(shellitem);
2420 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2421 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2422 if (SUCCEEDED(ret))
2424 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2425 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2426 if (SUCCEEDED(ret))
2428 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2429 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2430 if (SUCCEEDED(ret))
2432 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2433 pILFree(pidl_test);
2435 IPersistIDList_Release(persistidl);
2437 IShellItem_Release(shellitem);
2440 else
2441 win_skip("No SHCreateItemFromIDList\n");
2443 DeleteFileA(".\\testfile");
2444 pILFree(pidl_abstestfile);
2445 pILFree(pidl_testfile);
2446 pILFree(pidl_desktop);
2447 pILFree(pidl_cwd);
2448 IShellFolder_Release(currentfolder);
2449 IShellFolder_Release(desktopfolder);
2452 static void test_SHGetNameFromIDList(void)
2454 IShellItem *shellitem;
2455 LPITEMIDLIST pidl;
2456 LPWSTR name_string;
2457 HRESULT hres;
2458 UINT i;
2459 static const DWORD flags[] = {
2460 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2461 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2462 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2463 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2465 if(!pSHGetNameFromIDList)
2467 win_skip("SHGetNameFromIDList missing.\n");
2468 return;
2471 /* These should be available on any platform that passed the above test. */
2472 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2473 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2474 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2475 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2477 if(0)
2479 /* Crashes under win7 */
2480 hres = pSHGetNameFromIDList(NULL, 0, NULL);
2483 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2484 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2486 /* Test the desktop */
2487 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2488 ok(hres == S_OK, "Got 0x%08x\n", hres);
2489 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2490 ok(hres == S_OK, "Got 0x%08x\n", hres);
2491 if(SUCCEEDED(hres))
2493 WCHAR *nameSI, *nameSH;
2494 WCHAR buf[MAX_PATH];
2495 HRESULT hrSI, hrSH, hrSF;
2496 STRRET strret;
2497 IShellFolder *psf;
2498 BOOL res;
2500 SHGetDesktopFolder(&psf);
2501 for(i = 0; flags[i] != -1234; i++)
2503 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2504 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2505 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2506 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2507 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2508 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2510 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2511 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2513 if(SUCCEEDED(hrSF))
2515 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2516 if(SUCCEEDED(hrSI))
2517 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2518 if(SUCCEEDED(hrSF))
2519 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2521 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2522 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2524 IShellFolder_Release(psf);
2526 if(pSHGetPathFromIDListW){
2527 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2528 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2529 res = pSHGetPathFromIDListW(pidl, buf);
2530 ok(res == TRUE, "Got %d\n", res);
2531 if(SUCCEEDED(hrSI) && res)
2532 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2533 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2534 }else
2535 win_skip("pSHGetPathFromIDListW not available\n");
2537 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2538 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2539 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2541 IShellItem_Release(shellitem);
2543 pILFree(pidl);
2545 /* Test the control panel */
2546 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2547 ok(hres == S_OK, "Got 0x%08x\n", hres);
2548 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2549 ok(hres == S_OK, "Got 0x%08x\n", hres);
2550 if(SUCCEEDED(hres))
2552 WCHAR *nameSI, *nameSH;
2553 WCHAR buf[MAX_PATH];
2554 HRESULT hrSI, hrSH, hrSF;
2555 STRRET strret;
2556 IShellFolder *psf;
2557 BOOL res;
2559 SHGetDesktopFolder(&psf);
2560 for(i = 0; flags[i] != -1234; i++)
2562 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2563 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2564 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2565 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2566 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2567 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2569 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2570 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2572 if(SUCCEEDED(hrSF))
2574 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2575 if(SUCCEEDED(hrSI))
2576 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2577 if(SUCCEEDED(hrSF))
2578 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2580 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2581 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2583 IShellFolder_Release(psf);
2585 if(pSHGetPathFromIDListW){
2586 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2587 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2588 res = pSHGetPathFromIDListW(pidl, buf);
2589 ok(res == FALSE, "Got %d\n", res);
2590 if(SUCCEEDED(hrSI) && res)
2591 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2592 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2593 }else
2594 win_skip("pSHGetPathFromIDListW not available\n");
2596 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2597 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2598 "Got 0x%08x\n", hres);
2599 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2601 IShellItem_Release(shellitem);
2603 pILFree(pidl);
2606 static void test_SHGetItemFromDataObject(void)
2608 IShellFolder *psfdesktop;
2609 IShellItem *psi;
2610 IShellView *psv;
2611 HRESULT hres;
2613 if(!pSHGetItemFromDataObject)
2615 win_skip("No SHGetItemFromDataObject.\n");
2616 return;
2619 if(0)
2621 /* Crashes under win7 */
2622 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2625 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2626 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2628 SHGetDesktopFolder(&psfdesktop);
2630 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2631 ok(hres == S_OK, "got 0x%08x\n", hres);
2632 if(SUCCEEDED(hres))
2634 IEnumIDList *peidl;
2635 IDataObject *pdo;
2636 SHCONTF enum_flags;
2638 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2639 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2640 ok(hres == S_OK, "got 0x%08x\n", hres);
2641 if(SUCCEEDED(hres))
2643 LPITEMIDLIST apidl[5];
2644 UINT count = 0, i;
2646 for(count = 0; count < 5; count++)
2647 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2648 break;
2650 if(count)
2652 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2653 &IID_IDataObject, NULL, (void**)&pdo);
2654 ok(hres == S_OK, "got 0x%08x\n", hres);
2655 if(SUCCEEDED(hres))
2657 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2658 ok(hres == S_OK, "got 0x%08x\n", hres);
2659 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2660 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2661 ok(hres == S_OK, "got 0x%08x\n", hres);
2662 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2663 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2664 ok(hres == S_OK, "got 0x%08x\n", hres);
2665 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2666 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2667 ok(hres == S_OK, "got 0x%08x\n", hres);
2668 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2669 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2670 ok(hres == S_OK, "got 0x%08x\n", hres);
2671 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2673 IDataObject_Release(pdo);
2676 else
2677 skip("No file(s) found - skipping single-file test.\n");
2679 if(count > 1)
2681 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2682 &IID_IDataObject, NULL, (void**)&pdo);
2683 ok(hres == S_OK, "got 0x%08x\n", hres);
2684 if(SUCCEEDED(hres))
2686 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2687 ok(hres == S_OK, "got 0x%08x\n", hres);
2688 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2689 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2690 ok(hres == S_OK, "got 0x%08x\n", hres);
2691 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2692 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2693 ok(hres == S_OK, "got 0x%08x\n", hres);
2694 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2695 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2696 ok(hres == S_OK, "got 0x%08x\n", hres);
2697 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2698 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2699 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2700 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2701 IDataObject_Release(pdo);
2704 else
2705 skip("zero or one file found - skipping multi-file test.\n");
2707 for(i = 0; i < count; i++)
2708 pILFree(apidl[i]);
2710 IEnumIDList_Release(peidl);
2713 IShellView_Release(psv);
2716 IShellFolder_Release(psfdesktop);
2719 static void test_ShellItemCompare(void)
2721 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2722 IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2723 IShellFolder *psf_desktop, *psf_current;
2724 LPITEMIDLIST pidl_cwd;
2725 WCHAR curdirW[MAX_PATH];
2726 BOOL failed;
2727 HRESULT hr;
2728 static const WCHAR filesW[][9] = {
2729 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2730 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2731 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2732 int order;
2733 UINT i;
2735 if(!pSHCreateShellItem)
2737 win_skip("SHCreateShellItem missing.\n");
2738 return;
2741 GetCurrentDirectoryW(MAX_PATH, curdirW);
2742 if(!lstrlenW(curdirW))
2744 skip("Failed to get current directory, skipping.\n");
2745 return;
2748 CreateDirectoryA(".\\a", NULL);
2749 CreateDirectoryA(".\\b", NULL);
2750 CreateDirectoryA(".\\c", NULL);
2751 CreateTestFile(".\\a\\a");
2752 CreateTestFile(".\\a\\b");
2753 CreateTestFile(".\\a\\c");
2754 CreateTestFile(".\\b\\a");
2755 CreateTestFile(".\\b\\b");
2756 CreateTestFile(".\\b\\c");
2757 CreateTestFile(".\\c\\a");
2758 CreateTestFile(".\\c\\b");
2759 CreateTestFile(".\\c\\c");
2761 SHGetDesktopFolder(&psf_desktop);
2762 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2763 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2764 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2765 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2766 IShellFolder_Release(psf_desktop);
2768 /* Generate ShellItems for the files */
2769 ZeroMemory(&psi, sizeof(IShellItem*)*9);
2770 failed = FALSE;
2771 for(i = 0; i < 9; i++)
2773 LPITEMIDLIST pidl_testfile = NULL;
2775 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2776 NULL, &pidl_testfile, NULL);
2777 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2778 if(SUCCEEDED(hr))
2780 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2781 ok(hr == S_OK, "Got 0x%08x\n", hr);
2782 pILFree(pidl_testfile);
2784 if(FAILED(hr)) failed = TRUE;
2786 if(failed)
2788 skip("Failed to create all shellitems.\n");
2789 goto cleanup;
2792 /* Generate ShellItems for the folders */
2793 hr = IShellItem_GetParent(psi[0], &psi_a);
2794 ok(hr == S_OK, "Got 0x%08x\n", hr);
2795 if(FAILED(hr)) failed = TRUE;
2796 hr = IShellItem_GetParent(psi[3], &psi_b);
2797 ok(hr == S_OK, "Got 0x%08x\n", hr);
2798 if(FAILED(hr)) failed = TRUE;
2799 hr = IShellItem_GetParent(psi[6], &psi_c);
2800 ok(hr == S_OK, "Got 0x%08x\n", hr);
2801 if(FAILED(hr)) failed = TRUE;
2803 if(failed)
2805 skip("Failed to create shellitems.\n");
2806 goto cleanup;
2809 if(0)
2811 /* Crashes on native (win7, winxp) */
2812 hr = IShellItem_Compare(psi_a, NULL, 0, NULL);
2813 hr = IShellItem_Compare(psi_a, psi_b, 0, NULL);
2814 hr = IShellItem_Compare(psi_a, NULL, 0, &order);
2817 /* Basics */
2818 for(i = 0; i < 9; i++)
2820 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2821 ok(hr == S_OK, "Got 0x%08x\n", hr);
2822 ok(order == 0, "Got order %d\n", order);
2823 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2824 ok(hr == S_OK, "Got 0x%08x\n", hr);
2825 ok(order == 0, "Got order %d\n", order);
2826 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2827 ok(hr == S_OK, "Got 0x%08x\n", hr);
2828 ok(order == 0, "Got order %d\n", order);
2831 /* Order */
2832 /* a\b:a\a , a\b:a\c, a\b:a\b */
2833 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2834 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2835 ok(order == 1, "Got order %d\n", order);
2836 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2837 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2838 ok(order == -1, "Got order %d\n", order);
2839 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2840 ok(hr == S_OK, "Got 0x%08x\n", hr);
2841 ok(order == 0, "Got order %d\n", order);
2843 /* b\b:a\b, b\b:c\b, b\b:c\b */
2844 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2845 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2846 ok(order == 1, "Got order %d\n", order);
2847 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2848 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2849 ok(order == -1, "Got order %d\n", order);
2850 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2851 ok(hr == S_OK, "Got 0x%08x\n", hr);
2852 ok(order == 0, "Got order %d\n", order);
2854 /* b:a\a, b:a\c, b:a\b */
2855 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2856 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2857 todo_wine ok(order == 1, "Got order %d\n", order);
2858 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2859 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2860 todo_wine ok(order == 1, "Got order %d\n", order);
2861 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2862 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2863 todo_wine ok(order == 1, "Got order %d\n", order);
2865 /* b:c\a, b:c\c, b:c\b */
2866 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2867 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2868 ok(order == -1, "Got order %d\n", order);
2869 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2870 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2871 ok(order == -1, "Got order %d\n", order);
2872 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2873 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2874 ok(order == -1, "Got order %d\n", order);
2876 /* a\b:a\a , a\b:a\c, a\b:a\b */
2877 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &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[2], SICHINT_CANONICAL, &order);
2881 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2882 ok(order == -1, "Got order %d\n", order);
2883 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2884 ok(hr == S_OK, "Got 0x%08x\n", hr);
2885 ok(order == 0, "Got order %d\n", order);
2887 /* b\b:a\b, b\b:c\b, b\b:c\b */
2888 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2889 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2890 ok(order == 1, "Got order %d\n", order);
2891 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2892 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2893 ok(order == -1, "Got order %d\n", order);
2894 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2895 ok(hr == S_OK, "Got 0x%08x\n", hr);
2896 ok(order == 0, "Got order %d\n", order);
2898 /* b:a\a, b:a\c, b:a\b */
2899 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &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[2], SICHINT_CANONICAL, &order);
2903 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2904 todo_wine ok(order == 1, "Got order %d\n", order);
2905 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2906 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2907 todo_wine ok(order == 1, "Got order %d\n", order);
2909 /* b:c\a, b:c\c, b:c\b */
2910 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &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[8], SICHINT_CANONICAL, &order);
2914 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2915 ok(order == -1, "Got order %d\n", order);
2916 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2917 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2918 ok(order == -1, "Got order %d\n", order);
2920 cleanup:
2921 IShellFolder_Release(psf_current);
2923 DeleteFileA(".\\a\\a");
2924 DeleteFileA(".\\a\\b");
2925 DeleteFileA(".\\a\\c");
2926 DeleteFileA(".\\b\\a");
2927 DeleteFileA(".\\b\\b");
2928 DeleteFileA(".\\b\\c");
2929 DeleteFileA(".\\c\\a");
2930 DeleteFileA(".\\c\\b");
2931 DeleteFileA(".\\c\\c");
2932 RemoveDirectoryA(".\\a");
2933 RemoveDirectoryA(".\\b");
2934 RemoveDirectoryA(".\\c");
2936 if(psi_a) IShellItem_Release(psi_a);
2937 if(psi_b) IShellItem_Release(psi_b);
2938 if(psi_c) IShellItem_Release(psi_c);
2940 for(i = 0; i < 9; i++)
2941 if(psi[i]) IShellItem_Release(psi[i]);
2944 /**************************************************************/
2945 /* IUnknown implementation for counting QueryInterface calls. */
2946 typedef struct {
2947 const IUnknownVtbl *lpVtbl;
2948 struct if_count {
2949 REFIID id;
2950 LONG count;
2951 } *ifaces;
2952 LONG unknown;
2953 } IUnknownImpl;
2955 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2957 IUnknownImpl *This = (IUnknownImpl*)iunk;
2958 UINT i, found;
2959 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2961 if(IsEqualIID(This->ifaces[i].id, riid))
2963 This->ifaces[i].count++;
2964 found = 1;
2965 break;
2968 if(!found)
2969 This->unknown++;
2970 return E_NOINTERFACE;
2973 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
2975 return 2;
2978 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
2980 return 1;
2983 static const IUnknownVtbl vt_IUnknown = {
2984 unk_fnQueryInterface,
2985 unk_fnAddRef,
2986 unk_fnRelease
2989 static void test_SHGetIDListFromObject(void)
2991 IUnknownImpl *punkimpl;
2992 IShellFolder *psfdesktop;
2993 IShellView *psv;
2994 LPITEMIDLIST pidl, pidl_desktop;
2995 HRESULT hres;
2996 UINT i;
2997 struct if_count ifaces[] =
2998 { {&IID_IPersistIDList, 0},
2999 {&IID_IPersistFolder2, 0},
3000 {&IID_IDataObject, 0},
3001 {&IID_IParentAndItem, 0},
3002 {&IID_IFolderView, 0},
3003 {NULL, 0} };
3005 if(!pSHGetIDListFromObject)
3007 win_skip("SHGetIDListFromObject missing.\n");
3008 return;
3011 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3013 if(0)
3015 /* Crashes native */
3016 pSHGetIDListFromObject(NULL, NULL);
3017 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3020 hres = pSHGetIDListFromObject(NULL, &pidl);
3021 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3023 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3024 punkimpl->lpVtbl = &vt_IUnknown;
3025 punkimpl->ifaces = ifaces;
3026 punkimpl->unknown = 0;
3028 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3029 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3030 ok(ifaces[0].count, "interface not requested.\n");
3031 ok(ifaces[1].count, "interface not requested.\n");
3032 ok(ifaces[2].count, "interface not requested.\n");
3033 todo_wine
3034 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3035 "interface not requested.\n");
3036 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3037 "interface not requested.\n");
3039 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3040 HeapFree(GetProcessHeap(), 0, punkimpl);
3042 pidl_desktop = NULL;
3043 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3044 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3046 SHGetDesktopFolder(&psfdesktop);
3048 /* Test IShellItem */
3049 if(pSHCreateShellItem)
3051 IShellItem *shellitem;
3052 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3053 ok(hres == S_OK, "got 0x%08x\n", hres);
3054 if(SUCCEEDED(hres))
3056 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3057 ok(hres == S_OK, "got 0x%08x\n", hres);
3058 if(SUCCEEDED(hres))
3060 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3061 pILFree(pidl);
3063 IShellItem_Release(shellitem);
3066 else
3067 skip("no SHCreateShellItem.\n");
3069 /* Test IShellFolder */
3070 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3071 ok(hres == S_OK, "got 0x%08x\n", hres);
3072 if(SUCCEEDED(hres))
3074 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3075 pILFree(pidl);
3078 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3079 ok(hres == S_OK, "got 0x%08x\n", hres);
3080 if(SUCCEEDED(hres))
3082 IEnumIDList *peidl;
3083 IDataObject *pdo;
3084 SHCONTF enum_flags;
3086 /* Test IFolderView */
3087 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3088 ok(hres == S_OK, "got 0x%08x\n", hres);
3089 if(SUCCEEDED(hres))
3091 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3092 pILFree(pidl);
3095 /* Test IDataObject */
3096 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3097 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3098 ok(hres == S_OK, "got 0x%08x\n", hres);
3099 if(SUCCEEDED(hres))
3101 LPITEMIDLIST apidl[5];
3102 UINT count = 0;
3103 for(count = 0; count < 5; count++)
3104 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3105 break;
3107 if(count)
3109 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3110 &IID_IDataObject, NULL, (void**)&pdo);
3111 ok(hres == S_OK, "got 0x%08x\n", hres);
3112 if(SUCCEEDED(hres))
3114 pidl = (void*)0xDEADBEEF;
3115 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3116 ok(hres == S_OK, "got 0x%08x\n", hres);
3117 ok(pidl != NULL, "pidl is NULL.\n");
3118 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3119 pILFree(pidl);
3121 IDataObject_Release(pdo);
3124 else
3125 skip("No files found - skipping single-file test.\n");
3127 if(count > 1)
3129 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3130 &IID_IDataObject, NULL, (void**)&pdo);
3131 ok(hres == S_OK, "got 0x%08x\n", hres);
3132 if(SUCCEEDED(hres))
3134 pidl = (void*)0xDEADBEEF;
3135 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3136 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3137 "got 0x%08x\n", hres);
3138 ok(pidl == NULL, "pidl is not NULL.\n");
3140 IDataObject_Release(pdo);
3143 else
3144 skip("zero or one file found - skipping multi-file test.\n");
3146 for(i = 0; i < count; i++)
3147 pILFree(apidl[i]);
3149 IEnumIDList_Release(peidl);
3152 IShellView_Release(psv);
3155 IShellFolder_Release(psfdesktop);
3156 pILFree(pidl_desktop);
3159 static void test_SHGetItemFromObject(void)
3161 IUnknownImpl *punkimpl;
3162 IShellFolder *psfdesktop;
3163 LPITEMIDLIST pidl;
3164 IShellItem *psi;
3165 IUnknown *punk;
3166 HRESULT hres;
3167 struct if_count ifaces[] =
3168 { {&IID_IPersistIDList, 0},
3169 {&IID_IPersistFolder2, 0},
3170 {&IID_IDataObject, 0},
3171 {&IID_IParentAndItem, 0},
3172 {&IID_IFolderView, 0},
3173 {NULL, 0} };
3175 if(!pSHGetItemFromObject)
3177 skip("No SHGetItemFromObject.\n");
3178 return;
3181 SHGetDesktopFolder(&psfdesktop);
3183 if(0)
3185 /* Crashes with Windows 7 */
3186 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3187 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3188 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3191 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3192 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3194 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
3195 punkimpl->lpVtbl = &vt_IUnknown;
3196 punkimpl->ifaces = ifaces;
3197 punkimpl->unknown = 0;
3199 /* The same as SHGetIDListFromObject */
3200 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
3201 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3202 ok(ifaces[0].count, "interface not requested.\n");
3203 ok(ifaces[1].count, "interface not requested.\n");
3204 ok(ifaces[2].count, "interface not requested.\n");
3205 todo_wine
3206 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3207 "interface not requested.\n");
3208 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3209 "interface not requested.\n");
3211 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3212 HeapFree(GetProcessHeap(), 0, punkimpl);
3214 /* Test IShellItem */
3215 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3216 ok(hres == S_OK, "Got 0x%08x\n", hres);
3217 if(SUCCEEDED(hres))
3219 IShellItem *psi2;
3220 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3221 ok(hres == S_OK, "Got 0x%08x\n", hres);
3222 if(SUCCEEDED(hres))
3224 todo_wine
3225 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3226 IShellItem_Release(psi2);
3228 IShellItem_Release(psi);
3231 IShellFolder_Release(psfdesktop);
3234 static void test_SHCreateShellItemArray(void)
3236 IShellFolder *pdesktopsf, *psf;
3237 IShellItemArray *psia;
3238 IEnumIDList *peidl;
3239 HRESULT hr;
3240 WCHAR cTestDirW[MAX_PATH];
3241 LPITEMIDLIST pidl_testdir, pidl;
3242 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3244 if(!pSHCreateShellItemArray) {
3245 skip("No pSHCreateShellItemArray!\n");
3246 return;
3249 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
3251 if(0)
3253 /* Crashes under native */
3254 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3255 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3256 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3257 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3260 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3261 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3263 SHGetDesktopFolder(&pdesktopsf);
3264 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3265 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3267 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3268 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3270 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3271 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3272 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3273 pILFree(pidl);
3275 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3276 myPathAddBackslashW(cTestDirW);
3277 lstrcatW(cTestDirW, testdirW);
3279 CreateFilesFolders();
3281 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3282 ok(hr == S_OK, "got 0x%08x\n", hr);
3283 if(SUCCEEDED(hr))
3285 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3286 (void**)&psf);
3287 ok(hr == S_OK, "Got 0x%08x\n", hr);
3289 IShellFolder_Release(pdesktopsf);
3291 if(FAILED(hr))
3293 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3294 pILFree(pidl_testdir);
3295 Cleanup();
3296 return;
3299 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3300 ok(hr == S_OK, "Got %08x\n", hr);
3301 if(SUCCEEDED(hr))
3303 LPITEMIDLIST apidl[5];
3304 UINT done, numitems, i;
3306 for(done = 0; done < 5; done++)
3307 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3308 break;
3309 ok(done == 5, "Got %d pidls\n", done);
3310 IEnumIDList_Release(peidl);
3312 /* Create a ShellItemArray */
3313 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3314 ok(hr == S_OK, "Got 0x%08x\n", hr);
3315 if(SUCCEEDED(hr))
3317 IShellItem *psi;
3319 if(0)
3321 /* Crashes in Windows 7 */
3322 hr = IShellItemArray_GetCount(psia, NULL);
3325 IShellItemArray_GetCount(psia, &numitems);
3326 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3328 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3329 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3331 /* Compare all the items */
3332 for(i = 0; i < numitems; i++)
3334 LPITEMIDLIST pidl_abs;
3335 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3337 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3338 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3339 if(SUCCEEDED(hr))
3341 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3342 ok(hr == S_OK, "Got 0x%08x\n", hr);
3343 if(SUCCEEDED(hr))
3345 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3346 pILFree(pidl);
3348 IShellItem_Release(psi);
3350 pILFree(pidl_abs);
3352 for(i = 0; i < done; i++)
3353 pILFree(apidl[i]);
3354 IShellItemArray_Release(psia);
3358 /* SHCreateShellItemArrayFromShellItem */
3359 if(pSHCreateShellItemArrayFromShellItem)
3361 IShellItem *psi;
3363 if(0)
3365 /* Crashes under Windows 7 */
3366 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3367 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3368 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3371 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3372 ok(hr == S_OK, "Got 0x%08x\n", hr);
3373 if(SUCCEEDED(hr))
3375 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3376 ok(hr == S_OK, "Got 0x%08x\n", hr);
3377 if(SUCCEEDED(hr))
3379 IShellItem *psi2;
3380 UINT count;
3381 hr = IShellItemArray_GetCount(psia, &count);
3382 ok(hr == S_OK, "Got 0x%08x\n", hr);
3383 ok(count == 1, "Got count %d\n", count);
3384 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3385 ok(hr == S_OK, "Got 0x%08x\n", hr);
3386 todo_wine
3387 ok(psi != psi2, "ShellItems are of the same instance.\n");
3388 if(SUCCEEDED(hr))
3390 LPITEMIDLIST pidl1, pidl2;
3391 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3392 ok(hr == S_OK, "Got 0x%08x\n", hr);
3393 ok(pidl1 != NULL, "pidl1 was null.\n");
3394 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3395 ok(hr == S_OK, "Got 0x%08x\n", hr);
3396 ok(pidl2 != NULL, "pidl2 was null.\n");
3397 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3398 pILFree(pidl1);
3399 pILFree(pidl2);
3400 IShellItem_Release(psi2);
3402 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3403 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3404 IShellItemArray_Release(psia);
3406 IShellItem_Release(psi);
3409 else
3410 skip("No SHCreateShellItemArrayFromShellItem.\n");
3412 if(pSHCreateShellItemArrayFromDataObject)
3414 IShellView *psv;
3416 if(0)
3418 /* Crashes under Windows 7 */
3419 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3421 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3422 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3424 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3425 ok(hr == S_OK, "got 0x%08x\n", hr);
3426 if(SUCCEEDED(hr))
3428 IEnumIDList *peidl;
3429 IDataObject *pdo;
3430 SHCONTF enum_flags;
3432 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3433 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3434 ok(hr == S_OK, "got 0x%08x\n", hr);
3435 if(SUCCEEDED(hr))
3437 LPITEMIDLIST apidl[5];
3438 UINT count, i;
3440 for(count = 0; count < 5; count++)
3441 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3442 break;
3443 ok(count == 5, "Got %d\n", count);
3445 if(count)
3447 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3448 &IID_IDataObject, NULL, (void**)&pdo);
3449 ok(hr == S_OK, "Got 0x%08x\n", hr);
3450 if(SUCCEEDED(hr))
3452 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3453 (void**)&psia);
3454 ok(hr == S_OK, "Got 0x%08x\n", hr);
3455 if(SUCCEEDED(hr))
3457 UINT count_sia, i;
3458 hr = IShellItemArray_GetCount(psia, &count_sia);
3459 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3460 for(i = 0; i < count_sia; i++)
3462 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3463 IShellItem *psi;
3464 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3465 ok(hr == S_OK, "Got 0x%08x\n", hr);
3466 if(SUCCEEDED(hr))
3468 LPITEMIDLIST pidl;
3469 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3470 ok(hr == S_OK, "Got 0x%08x\n", hr);
3471 ok(pidl != NULL, "pidl as NULL.\n");
3472 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3473 pILFree(pidl);
3474 IShellItem_Release(psi);
3476 pILFree(pidl_abs);
3479 IShellItemArray_Release(psia);
3482 IDataObject_Release(pdo);
3484 for(i = 0; i < count; i++)
3485 pILFree(apidl[i]);
3487 else
3488 skip("No files found - skipping test.\n");
3490 IEnumIDList_Release(peidl);
3492 IShellView_Release(psv);
3495 else
3496 skip("No SHCreateShellItemArrayFromDataObject.\n");
3498 IShellFolder_Release(psf);
3499 pILFree(pidl_testdir);
3500 Cleanup();
3503 static void test_ShellItemBindToHandler(void)
3505 IShellItem *psi;
3506 LPITEMIDLIST pidl_desktop;
3507 HRESULT hr;
3509 if(!pSHCreateShellItem)
3511 skip("SHCreateShellItem missing.\n");
3512 return;
3515 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3516 ok(hr == S_OK, "Got 0x%08x\n", hr);
3517 if(SUCCEEDED(hr))
3519 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3520 ok(hr == S_OK, "Got 0x%08x\n", hr);
3522 if(SUCCEEDED(hr))
3524 IPersistFolder2 *ppf2;
3525 IUnknown *punk;
3527 if(0)
3529 /* Crashes under Windows 7 */
3530 hr = IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3531 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3533 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3534 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3536 /* BHID_SFObject */
3537 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3538 ok(hr == S_OK, "Got 0x%08x\n", hr);
3539 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3540 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3541 ok(hr == S_OK, "Got 0x%08x\n", hr);
3542 if(SUCCEEDED(hr))
3544 LPITEMIDLIST pidl_tmp;
3545 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3546 ok(hr == S_OK, "Got 0x%08x\n", hr);
3547 if(SUCCEEDED(hr))
3549 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3550 pILFree(pidl_tmp);
3552 IPersistFolder2_Release(ppf2);
3555 /* BHID_SFUIObject */
3556 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3557 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3558 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3559 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3560 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3561 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3563 /* BHID_DataObject */
3564 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3565 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3566 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3568 todo_wine
3570 /* BHID_SFViewObject */
3571 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3572 ok(hr == S_OK, "Got 0x%08x\n", hr);
3573 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3574 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3575 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3576 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3578 /* BHID_Storage */
3579 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3580 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3581 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3582 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3583 ok(hr == S_OK, "Got 0x%08x\n", hr);
3584 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3586 /* BHID_Stream */
3587 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3588 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3589 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3590 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3591 ok(hr == S_OK, "Got 0x%08x\n", hr);
3592 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3594 /* BHID_StorageEnum */
3595 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3596 ok(hr == S_OK, "Got 0x%08x\n", hr);
3597 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3599 /* BHID_Transfer */
3600 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3601 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3602 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3604 /* BHID_EnumItems */
3605 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3606 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3607 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3609 /* BHID_Filter */
3610 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3611 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3612 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3614 /* BHID_LinkTargetItem */
3615 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3616 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3617 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3618 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3619 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3620 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3622 /* BHID_PropertyStore */
3623 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3624 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3625 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3626 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3627 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3628 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3630 /* BHID_ThumbnailHandler */
3631 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3632 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3633 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3635 /* BHID_AssociationArray */
3636 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3637 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3638 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3640 /* BHID_EnumAssocHandlers */
3641 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3642 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3643 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3646 IShellItem_Release(psi);
3648 else
3649 skip("Failed to create ShellItem.\n");
3651 pILFree(pidl_desktop);
3654 static void test_SHParseDisplayName(void)
3656 LPITEMIDLIST pidl1, pidl2;
3657 IShellFolder *desktop;
3658 WCHAR dirW[MAX_PATH];
3659 WCHAR nameW[10];
3660 HRESULT hr;
3661 BOOL ret;
3663 if (!pSHParseDisplayName)
3665 win_skip("SHParseDisplayName isn't available\n");
3666 return;
3669 if (0)
3671 /* crashes on native */
3672 hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3673 nameW[0] = 0;
3674 hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3677 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3678 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3679 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3680 hr == E_INVALIDARG, "failed %08x\n", hr);
3681 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3683 /* dummy name */
3684 nameW[0] = 0;
3685 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3686 ok(hr == S_OK, "failed %08x\n", hr);
3687 hr = SHGetDesktopFolder(&desktop);
3688 ok(hr == S_OK, "failed %08x\n", hr);
3689 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3690 ok(hr == S_OK, "failed %08x\n", hr);
3691 ret = pILIsEqual(pidl1, pidl2);
3692 ok(ret == TRUE, "expected equal idls\n");
3693 pILFree(pidl1);
3694 pILFree(pidl2);
3696 /* with path */
3697 GetWindowsDirectoryW( dirW, MAX_PATH );
3699 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3700 ok(hr == S_OK, "failed %08x\n", hr);
3701 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3702 ok(hr == S_OK, "failed %08x\n", hr);
3704 ret = pILIsEqual(pidl1, pidl2);
3705 ok(ret == TRUE, "expected equal idls\n");
3706 pILFree(pidl1);
3707 pILFree(pidl2);
3709 IShellFolder_Release(desktop);
3712 static void test_desktop_IPersist(void)
3714 IShellFolder *desktop;
3715 IPersist *persist;
3716 IPersistFolder2 *ppf2;
3717 CLSID clsid;
3718 HRESULT hr;
3720 hr = SHGetDesktopFolder(&desktop);
3721 ok(hr == S_OK, "failed %08x\n", hr);
3723 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3724 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3726 if (hr == S_OK)
3728 if (0)
3730 /* crashes on native */
3731 hr = IPersist_GetClassID(persist, NULL);
3733 memset(&clsid, 0, sizeof(clsid));
3734 hr = IPersist_GetClassID(persist, &clsid);
3735 ok(hr == S_OK, "failed %08x\n", hr);
3736 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3737 IPersist_Release(persist);
3740 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3741 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3742 if(SUCCEEDED(hr))
3744 IPersistFolder *ppf;
3745 LPITEMIDLIST pidl;
3746 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3747 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3748 if(SUCCEEDED(hr))
3749 IPersistFolder_Release(ppf);
3751 todo_wine {
3752 hr = IPersistFolder2_Initialize(ppf2, NULL);
3753 ok(hr == S_OK, "got %08x\n", hr);
3756 pidl = NULL;
3757 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3758 ok(hr == S_OK, "got %08x\n", hr);
3759 ok(pidl != NULL, "pidl was NULL.\n");
3760 if(SUCCEEDED(hr)) pILFree(pidl);
3762 IPersistFolder2_Release(ppf2);
3765 IShellFolder_Release(desktop);
3768 static void test_GetUIObject(void)
3770 IShellFolder *psf_desktop;
3771 IContextMenu *pcm;
3772 LPITEMIDLIST pidl;
3773 HRESULT hr;
3774 WCHAR path[MAX_PATH];
3775 const WCHAR filename[] =
3776 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3778 if(!pSHBindToParent)
3780 win_skip("SHBindToParent missing.\n");
3781 return;
3784 GetCurrentDirectoryW(MAX_PATH, path);
3785 if(!lstrlenW(path))
3787 skip("GetCurrentDirectoryW returned an empty string.\n");
3788 return;
3790 lstrcatW(path, filename);
3791 SHGetDesktopFolder(&psf_desktop);
3793 CreateFilesFolders();
3795 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3796 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3797 if(SUCCEEDED(hr))
3799 IShellFolder *psf;
3800 LPCITEMIDLIST pidl_child;
3801 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3802 ok(hr == S_OK, "Got 0x%08x\n", hr);
3803 if(SUCCEEDED(hr))
3805 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3806 &IID_IContextMenu, NULL, (void**)&pcm);
3807 ok(hr == S_OK, "Got 0x%08x\n", hr);
3808 if(SUCCEEDED(hr))
3810 HMENU hmenu = CreatePopupMenu();
3811 INT max_id, max_id_check;
3812 UINT count, i;
3813 const int id_upper_limit = 32767;
3814 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3815 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3816 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3817 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3818 count = GetMenuItemCount(hmenu);
3819 ok(count, "Got %d\n", count);
3821 max_id_check = 0;
3822 for(i = 0; i < count; i++)
3824 MENUITEMINFOA mii;
3825 INT res;
3826 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3827 mii.cbSize = sizeof(MENUITEMINFOA);
3828 mii.fMask = MIIM_ID | MIIM_FTYPE;
3830 SetLastError(0);
3831 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3832 ok(res, "Failed (last error: %d).\n", GetLastError());
3834 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3835 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3836 if(!(mii.fType & MFT_SEPARATOR))
3837 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3839 ok((max_id_check == max_id) ||
3840 (max_id_check == max_id-1 /* Win 7 */),
3841 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3843 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3845 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3847 CMINVOKECOMMANDINFO cmi;
3848 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3849 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3851 /* Attempt to execute a nonexistent command */
3852 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3853 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3854 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3856 cmi.lpVerb = "foobar_wine_test";
3857 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3858 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3859 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3860 "Got 0x%08x\n", hr);
3862 #undef is_win2k
3864 DestroyMenu(hmenu);
3865 IContextMenu_Release(pcm);
3867 IShellFolder_Release(psf);
3869 if(pILFree) pILFree(pidl);
3872 IShellFolder_Release(psf_desktop);
3873 Cleanup();
3876 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3877 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3879 LPCITEMIDLIST child;
3880 IShellFolder *parent;
3881 STRRET filename;
3882 HRESULT hr;
3884 if(!pSHBindToParent){
3885 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3886 if(path)
3887 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3888 else
3889 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3890 return;
3893 if(path){
3894 if(!pidl){
3895 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3896 return;
3899 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3900 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3901 if(FAILED(hr))
3902 return;
3904 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3905 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3906 if(FAILED(hr)){
3907 IShellFolder_Release(parent);
3908 return;
3911 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
3912 "Got unexpected string type: %d\n", filename.uType);
3913 if(filename.uType == STRRET_WSTR){
3914 ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
3915 "didn't get expected path (%s), instead: %s\n",
3916 wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
3917 }else if(filename.uType == STRRET_CSTR){
3918 ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
3919 "didn't get expected path (%s), instead: %s\n",
3920 wine_dbgstr_w(path), U(filename).cStr);
3923 IShellFolder_Release(parent);
3924 }else
3925 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3928 static void test_SHSimpleIDListFromPath(void)
3930 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
3931 const CHAR adirA[] = "C:\\sidlfpdir";
3932 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
3934 LPITEMIDLIST pidl = NULL;
3936 if(!pSHSimpleIDListFromPathAW){
3937 win_skip("SHSimpleIDListFromPathAW not available\n");
3938 return;
3941 br = CreateDirectoryA(adirA, NULL);
3942 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3944 if(is_unicode)
3945 pidl = pSHSimpleIDListFromPathAW(adirW);
3946 else
3947 pidl = pSHSimpleIDListFromPathAW(adirA);
3948 verify_pidl(pidl, adirW);
3949 pILFree(pidl);
3951 br = RemoveDirectoryA(adirA);
3952 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
3954 if(is_unicode)
3955 pidl = pSHSimpleIDListFromPathAW(adirW);
3956 else
3957 pidl = pSHSimpleIDListFromPathAW(adirA);
3958 verify_pidl(pidl, adirW);
3959 pILFree(pidl);
3962 /* IFileSystemBindData impl */
3963 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
3964 REFIID riid, void **ppv)
3966 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
3967 IsEqualIID(riid, &IID_IUnknown)){
3968 *ppv = fsbd;
3969 return S_OK;
3971 return E_NOINTERFACE;
3974 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
3976 return 2;
3979 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
3981 return 1;
3984 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
3985 const WIN32_FIND_DATAW *pfd)
3987 ok(0, "SetFindData called\n");
3988 return E_NOTIMPL;
3991 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
3992 WIN32_FIND_DATAW *pfd)
3994 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3995 return S_OK;
3998 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
3999 WIN32_FIND_DATAW *pfd)
4001 memset(pfd, 0xdeadbeef, sizeof(WIN32_FIND_DATAW));
4002 return S_OK;
4005 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
4006 WIN32_FIND_DATAW *pfd)
4008 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
4009 *pfd->cFileName = 'a';
4010 *pfd->cAlternateFileName = 'a';
4011 return S_OK;
4014 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
4015 WIN32_FIND_DATAW *pfd)
4017 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4018 HANDLE handle = FindFirstFileW(adirW, pfd);
4019 FindClose(handle);
4020 return S_OK;
4023 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
4024 WIN32_FIND_DATAW *pfd)
4026 return E_FAIL;
4029 static IFileSystemBindDataVtbl fsbdVtbl = {
4030 fsbd_QueryInterface,
4031 fsbd_AddRef,
4032 fsbd_Release,
4033 fsbd_SetFindData,
4034 NULL
4037 static IFileSystemBindData fsbd = { &fsbdVtbl };
4039 static void test_ParseDisplayNamePBC(void)
4041 WCHAR wFileSystemBindData[] =
4042 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
4043 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
4044 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
4046 IShellFolder *psf;
4047 IBindCtx *pbc;
4048 HRESULT hres;
4049 ITEMIDLIST *pidl;
4051 /* Check if we support WCHAR functions */
4052 SetLastError(0xdeadbeef);
4053 lstrcmpiW(adirW, adirW);
4054 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
4055 win_skip("Most W-calls are not implemented\n");
4056 return;
4059 hres = SHGetDesktopFolder(&psf);
4060 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
4061 if(FAILED(hres)){
4062 win_skip("Failed to get IShellFolder, can't run tests\n");
4063 return;
4066 /* fails on unknown dir with no IBindCtx */
4067 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
4068 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4069 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4071 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
4072 hres = CreateBindCtx(0, &pbc);
4073 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
4075 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4076 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
4077 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
4079 /* unknown dir with IBindCtx with IFileSystemBindData */
4080 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
4081 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
4083 /* return E_FAIL from GetFindData */
4084 pidl = (ITEMIDLIST*)0xdeadbeef;
4085 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
4086 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4087 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4088 "ParseDisplayName failed: 0x%08x\n", hres);
4089 if(SUCCEEDED(hres)){
4090 verify_pidl(pidl, adirW);
4091 ILFree(pidl);
4094 /* set FIND_DATA struct to NULLs */
4095 pidl = (ITEMIDLIST*)0xdeadbeef;
4096 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
4097 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4098 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4099 "ParseDisplayName failed: 0x%08x\n", hres);
4100 if(SUCCEEDED(hres)){
4101 verify_pidl(pidl, adirW);
4102 ILFree(pidl);
4105 /* set FIND_DATA struct to junk */
4106 pidl = (ITEMIDLIST*)0xdeadbeef;
4107 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
4108 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4109 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4110 "ParseDisplayName failed: 0x%08x\n", hres);
4111 if(SUCCEEDED(hres)){
4112 verify_pidl(pidl, adirW);
4113 ILFree(pidl);
4116 /* set FIND_DATA struct to invalid data */
4117 pidl = (ITEMIDLIST*)0xdeadbeef;
4118 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
4119 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4120 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4121 "ParseDisplayName failed: 0x%08x\n", hres);
4122 if(SUCCEEDED(hres)){
4123 verify_pidl(pidl, adirW);
4124 ILFree(pidl);
4127 /* set FIND_DATA struct to valid data */
4128 pidl = (ITEMIDLIST*)0xdeadbeef;
4129 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
4130 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
4131 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
4132 "ParseDisplayName failed: 0x%08x\n", hres);
4133 if(SUCCEEDED(hres)){
4134 verify_pidl(pidl, adirW);
4135 ILFree(pidl);
4138 IBindCtx_Release(pbc);
4139 IShellFolder_Release(psf);
4142 static const CHAR testwindow_class[] = "testwindow";
4143 #define WM_USER_NOTIFY (WM_APP+1)
4145 static struct {
4146 const char *id;
4147 BOOL exp_notify;
4148 UINT signal;
4149 const WCHAR *path_1;
4150 const WCHAR *path_2;
4151 } exp_data;
4153 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
4155 UINT signal = (UINT)lparam;
4157 switch(msg){
4158 case WM_USER_NOTIFY:
4159 if(exp_data.exp_notify){
4160 LPCITEMIDLIST *pidls = (LPCITEMIDLIST*)wparam;
4162 ok(exp_data.signal == signal,
4163 "%s: expected notification type %x, got: %x\n",
4164 exp_data.id, exp_data.signal, signal);
4166 trace("verifying pidls for: %s\n", exp_data.id);
4167 verify_pidl(pidls[0], exp_data.path_1);
4168 verify_pidl(pidls[1], exp_data.path_2);
4170 exp_data.exp_notify = FALSE;
4171 }else
4172 ok(exp_data.exp_notify, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
4173 return 0;
4175 return DefWindowProc(hwnd, msg, wparam, lparam);
4178 static void register_testwindow_class(void)
4180 WNDCLASSEXA cls;
4181 ATOM ret;
4183 ZeroMemory(&cls, sizeof(cls));
4184 cls.cbSize = sizeof(cls);
4185 cls.style = 0;
4186 cls.lpfnWndProc = testwindow_wndproc;
4187 cls.hInstance = GetModuleHandleA(NULL);
4188 cls.lpszClassName = testwindow_class;
4190 SetLastError(0);
4191 ret = RegisterClassExA(&cls);
4192 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
4195 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
4196 * have to poll repeatedly for the message to appear */
4197 static void do_events(void)
4199 int c = 0;
4200 while (exp_data.exp_notify && (c++ < 10)){
4201 MSG msg;
4202 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
4203 TranslateMessage(&msg);
4204 DispatchMessageA(&msg);
4206 if(exp_data.exp_notify)
4207 Sleep(500);
4209 trace("%s: took %d tries\n", exp_data.id, c);
4212 static void test_SHChangeNotify(void)
4214 HWND wnd;
4215 ULONG notifyID;
4216 HRESULT hr;
4217 BOOL br, has_unicode;
4218 SHChangeNotifyEntry entries[1];
4219 const CHAR root_dirA[] = "C:\\shell32_cn_test";
4220 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
4221 const CHAR test_dirA[] = "C:\\shell32_cn_test\\test";
4222 const WCHAR test_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t','\\','t','e','s','t',0};
4224 CreateDirectoryW(NULL, NULL);
4225 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
4227 /* set up the root directory & window */
4228 br = CreateDirectoryA(root_dirA, NULL);
4229 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4231 register_testwindow_class();
4233 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
4234 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
4235 NULL, NULL, GetModuleHandleA(NULL), 0);
4236 ok(wnd != NULL, "Failed to make a window\n");
4238 entries[0].pidl = NULL;
4239 if(has_unicode)
4240 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
4241 else
4242 hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
4243 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
4244 entries[0].fRecursive = TRUE;
4246 notifyID = SHChangeNotifyRegister(wnd, SHCNRF_ShellLevel,
4247 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
4248 ok(notifyID != 0, "Failed to register a window for change notifications\n");
4250 /* MKDIR */
4251 br = CreateDirectoryA(test_dirA, NULL);
4252 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
4254 if(has_unicode){
4255 exp_data.id = "MKDIR PATHW";
4256 exp_data.signal = SHCNE_MKDIR;
4257 exp_data.exp_notify = TRUE;
4258 exp_data.path_1 = test_dirW;
4259 exp_data.path_2 = NULL;
4260 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW | SHCNF_FLUSH, test_dirW, NULL);
4261 do_events();
4262 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4263 }else
4264 win_skip("skipping WCHAR tests\n");
4266 exp_data.id = "MKDIR PATHA";
4267 exp_data.signal = SHCNE_MKDIR;
4268 exp_data.exp_notify = TRUE;
4269 exp_data.path_1 = test_dirW;
4270 exp_data.path_2 = NULL;
4271 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHA | SHCNF_FLUSH, test_dirA, NULL);
4272 do_events();
4273 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4275 /* RMDIR */
4276 br = RemoveDirectoryA(test_dirA);
4277 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4279 if(has_unicode){
4280 exp_data.id = "RMDIR PATHW";
4281 exp_data.signal = SHCNE_RMDIR;
4282 exp_data.exp_notify = TRUE;
4283 exp_data.path_1 = test_dirW;
4284 exp_data.path_2 = NULL;
4285 SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW | SHCNF_FLUSH, test_dirW, NULL);
4286 do_events();
4287 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4288 }else
4289 win_skip("skipping WCHAR tests\n");
4291 exp_data.id = "RMDIR PATHA";
4292 exp_data.signal = SHCNE_RMDIR;
4293 exp_data.exp_notify = TRUE;
4294 exp_data.path_1 = test_dirW;
4295 exp_data.path_2 = NULL;
4296 SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHA | SHCNF_FLUSH, test_dirA, NULL);
4297 do_events();
4298 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4300 SHChangeNotifyDeregister(notifyID);
4301 DestroyWindow(wnd);
4303 br = RemoveDirectoryA(root_dirA);
4304 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4307 START_TEST(shlfolder)
4309 init_function_pointers();
4310 /* if OleInitialize doesn't get called, ParseDisplayName returns
4311 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4312 OleInitialize(NULL);
4314 test_ParseDisplayName();
4315 test_SHParseDisplayName();
4316 test_BindToObject();
4317 test_EnumObjects_and_CompareIDs();
4318 test_GetDisplayName();
4319 test_GetAttributesOf();
4320 test_SHGetPathFromIDList();
4321 test_CallForAttributes();
4322 test_FolderShortcut();
4323 test_ITEMIDLIST_format();
4324 test_SHGetFolderPathA();
4325 test_SHGetFolderPathAndSubDirA();
4326 test_LocalizedNames();
4327 test_SHCreateShellItem();
4328 test_SHCreateShellItemArray();
4329 test_desktop_IPersist();
4330 test_GetUIObject();
4331 test_SHSimpleIDListFromPath();
4332 test_ParseDisplayNamePBC();
4333 test_SHGetNameFromIDList();
4334 test_SHGetItemFromDataObject();
4335 test_SHGetIDListFromObject();
4336 test_SHGetItemFromObject();
4337 test_ShellItemCompare();
4338 test_SHChangeNotify();
4339 test_ShellItemBindToHandler();
4341 OleUninitialize();