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