shell32: Support BHID_SFUIObject and BHID_DataObject in IShellItem::BindToHandler.
[wine.git] / dlls / shell32 / tests / shlfolder.c
blob34bf59da5f70a1762c79e72dbc7e219757203dc4
1 /*
2 * Unit test of the IShellFolder functions.
4 * Copyright 2004 Vitaliy Margolen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdio.h>
24 #define COBJMACROS
25 #define CONST_VTABLE
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wtypes.h"
30 #include "shellapi.h"
33 #include "shlguid.h"
34 #include "shlobj.h"
35 #include "shobjidl.h"
36 #include "shlwapi.h"
37 #include "ocidl.h"
38 #include "oleauto.h"
40 #include "wine/test.h"
42 #include <initguid.h>
43 DEFINE_GUID(IID_IParentAndItem, 0xB3A4B685, 0xB685, 0x4805, 0x99,0xD9, 0x5D,0xEA,0xD2,0x87,0x32,0x36);
45 static IMalloc *ppM;
47 static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
48 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
49 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
50 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
51 static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
52 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
53 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
54 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
55 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
56 static void (WINAPI *pILFree)(LPITEMIDLIST);
57 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
58 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
59 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
60 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
61 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
62 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
63 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
64 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
65 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
66 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
67 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
68 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
69 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
70 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
72 static int strcmp_wa(LPCWSTR strw, const char *stra)
74 CHAR buf[512];
75 WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
76 return lstrcmpA(stra, buf);
79 static void init_function_pointers(void)
81 HMODULE hmod;
82 HRESULT hr;
83 void *ptr;
85 hmod = GetModuleHandleA("shell32.dll");
87 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
88 MAKEFUNC(SHBindToParent);
89 MAKEFUNC(SHCreateItemFromIDList);
90 MAKEFUNC(SHCreateItemFromParsingName);
91 MAKEFUNC(SHCreateShellItem);
92 MAKEFUNC(SHCreateShellItemArray);
93 MAKEFUNC(SHCreateShellItemArrayFromDataObject);
94 MAKEFUNC(SHCreateShellItemArrayFromShellItem);
95 MAKEFUNC(SHGetFolderPathA);
96 MAKEFUNC(SHGetFolderPathAndSubDirA);
97 MAKEFUNC(SHGetPathFromIDListW);
98 MAKEFUNC(SHGetSpecialFolderPathA);
99 MAKEFUNC(SHGetSpecialFolderPathW);
100 MAKEFUNC(SHGetSpecialFolderLocation);
101 MAKEFUNC(SHParseDisplayName);
102 MAKEFUNC(SHGetNameFromIDList);
103 MAKEFUNC(SHGetItemFromDataObject);
104 MAKEFUNC(SHGetIDListFromObject);
105 MAKEFUNC(SHGetItemFromObject);
106 #undef MAKEFUNC
108 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
109 MAKEFUNC_ORD(ILFindLastID, 16);
110 MAKEFUNC_ORD(ILIsEqual, 21);
111 MAKEFUNC_ORD(ILCombine, 25);
112 MAKEFUNC_ORD(ILFree, 155);
113 MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
114 #undef MAKEFUNC_ORD
116 /* test named exports */
117 ptr = GetProcAddress(hmod, "ILFree");
118 ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
119 if (ptr)
121 #define TESTNAMED(f) \
122 ptr = (void*)GetProcAddress(hmod, #f); \
123 ok(ptr != 0, "expected named export for " #f "\n");
125 TESTNAMED(ILAppendID);
126 TESTNAMED(ILClone);
127 TESTNAMED(ILCloneFirst);
128 TESTNAMED(ILCombine);
129 TESTNAMED(ILCreateFromPath);
130 TESTNAMED(ILCreateFromPathA);
131 TESTNAMED(ILCreateFromPathW);
132 TESTNAMED(ILFindChild);
133 TESTNAMED(ILFindLastID);
134 TESTNAMED(ILGetNext);
135 TESTNAMED(ILGetSize);
136 TESTNAMED(ILIsEqual);
137 TESTNAMED(ILIsParent);
138 TESTNAMED(ILRemoveLastID);
139 TESTNAMED(ILSaveToStream);
140 #undef TESTNAMED
143 hmod = GetModuleHandleA("shlwapi.dll");
144 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
146 hr = SHGetMalloc(&ppM);
147 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
150 static void test_ParseDisplayName(void)
152 HRESULT hr;
153 IShellFolder *IDesktopFolder;
154 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
155 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
156 static const char *cInetTestA = "http:\\yyy";
157 static const char *cInetTest2A = "xx:yyy";
158 DWORD res;
159 WCHAR cTestDirW [MAX_PATH] = {0};
160 ITEMIDLIST *newPIDL;
161 BOOL bRes;
163 hr = SHGetDesktopFolder(&IDesktopFolder);
164 ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
165 if(hr != S_OK) return;
167 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
168 if (pSHCreateShellItem)
170 /* null name and pidl */
171 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
172 NULL, NULL, NULL, NULL, NULL, 0);
173 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
175 /* null name */
176 newPIDL = (ITEMIDLIST*)0xdeadbeef;
177 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
178 NULL, NULL, NULL, NULL, &newPIDL, 0);
179 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
180 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
182 else
183 win_skip("Tests would crash on W2K and below\n");
185 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
186 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
187 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
188 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
189 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
190 if (hr == S_OK)
192 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
193 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
194 IMalloc_Free(ppM, newPIDL);
197 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
198 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
199 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
200 todo_wine ok(hr == S_OK || broken(hr == E_FAIL) /* NT4 */,
201 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
202 if (hr == S_OK)
204 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
205 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
206 IMalloc_Free(ppM, newPIDL);
209 res = GetFileAttributesA(cNonExistDir1A);
210 if(res != INVALID_FILE_ATTRIBUTES)
212 skip("Test directory unexpectedly exists\n");
213 goto finished;
216 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
217 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
218 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
219 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
220 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
222 res = GetFileAttributesA(cNonExistDir2A);
223 if(res != INVALID_FILE_ATTRIBUTES)
225 skip("Test directory unexpectedly exists\n");
226 goto finished;
229 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
230 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
231 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
232 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
233 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
235 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
236 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
237 * out it doesn't. The magic seems to happen in the file dialogs, then. */
238 if (!pSHGetSpecialFolderPathW || !pILFindLastID)
240 win_skip("SHGetSpecialFolderPathW and/or ILFindLastID are not available\n");
241 goto finished;
244 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
245 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
246 if (!bRes) goto finished;
248 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
249 ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
250 if (hr != S_OK) goto finished;
252 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
253 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
254 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
255 pILFindLastID(newPIDL)->mkid.abID[0]);
256 IMalloc_Free(ppM, newPIDL);
258 finished:
259 IShellFolder_Release(IDesktopFolder);
262 /* creates a file with the specified name for tests */
263 static void CreateTestFile(const CHAR *name)
265 HANDLE file;
266 DWORD written;
268 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
269 if (file != INVALID_HANDLE_VALUE)
271 WriteFile(file, name, strlen(name), &written, NULL);
272 WriteFile(file, "\n", strlen("\n"), &written, NULL);
273 CloseHandle(file);
278 /* initializes the tests */
279 static void CreateFilesFolders(void)
281 CreateDirectoryA(".\\testdir", NULL);
282 CreateDirectoryA(".\\testdir\\test.txt", NULL);
283 CreateTestFile (".\\testdir\\test1.txt ");
284 CreateTestFile (".\\testdir\\test2.txt ");
285 CreateTestFile (".\\testdir\\test3.txt ");
286 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
287 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
290 /* cleans after tests */
291 static void Cleanup(void)
293 DeleteFileA(".\\testdir\\test1.txt");
294 DeleteFileA(".\\testdir\\test2.txt");
295 DeleteFileA(".\\testdir\\test3.txt");
296 RemoveDirectoryA(".\\testdir\\test.txt");
297 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
298 RemoveDirectoryA(".\\testdir\\testdir2");
299 RemoveDirectoryA(".\\testdir");
303 /* perform test */
304 static void test_EnumObjects(IShellFolder *iFolder)
306 IEnumIDList *iEnumList;
307 LPITEMIDLIST newPIDL, idlArr[10];
308 ULONG NumPIDLs;
309 int i=0, j;
310 HRESULT hr;
312 static const WORD iResults [5][5] =
314 { 0,-1,-1,-1,-1},
315 { 1, 0,-1,-1,-1},
316 { 1, 1, 0,-1,-1},
317 { 1, 1, 1, 0,-1},
318 { 1, 1, 1, 1, 0}
321 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
322 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
323 static const ULONG attrs[5] =
325 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
326 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
327 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
328 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
329 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
332 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
333 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
335 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
336 * the filesystem shellfolders return S_OK even if less than 'celt' items are
337 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
338 * only ever returns a single entry per call. */
339 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
340 i += NumPIDLs;
341 ok (i == 5, "i: %d\n", i);
343 hr = IEnumIDList_Release(iEnumList);
344 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
346 /* Sort them first in case of wrong order from system */
347 for (i=0;i<5;i++) for (j=0;j<5;j++)
348 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
350 newPIDL = idlArr[i];
351 idlArr[i] = idlArr[j];
352 idlArr[j] = newPIDL;
355 for (i=0;i<5;i++) for (j=0;j<5;j++)
357 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
358 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
362 for (i = 0; i < 5; i++)
364 SFGAOF flags;
365 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
366 /* Native returns all flags no matter what we ask for */
367 flags = SFGAO_CANCOPY;
368 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
369 flags &= SFGAO_testfor;
370 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
371 ok(flags == (attrs[i]) ||
372 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
373 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
374 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
376 flags = SFGAO_testfor;
377 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
378 flags &= SFGAO_testfor;
379 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
380 ok(flags == attrs[i] ||
381 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
382 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
385 for (i=0;i<5;i++)
386 IMalloc_Free(ppM, idlArr[i]);
389 static void test_BindToObject(void)
391 HRESULT hr;
392 UINT cChars;
393 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
394 SHITEMID emptyitem = { 0, { 0 } };
395 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
396 WCHAR wszSystemDir[MAX_PATH];
397 char szSystemDir[MAX_PATH];
398 WCHAR wszMyComputer[] = {
399 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
400 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
402 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
403 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
405 hr = SHGetDesktopFolder(&psfDesktop);
406 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
407 if (hr != S_OK) return;
409 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
410 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
412 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
413 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
415 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
416 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
417 if (hr != S_OK) {
418 IShellFolder_Release(psfDesktop);
419 return;
422 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
423 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
424 IShellFolder_Release(psfDesktop);
425 IMalloc_Free(ppM, pidlMyComputer);
426 if (hr != S_OK) return;
428 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
429 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
431 if (0)
433 /* this call segfaults on 98SE */
434 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
435 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
438 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
439 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
440 if (cChars == 0 || cChars >= MAX_PATH) {
441 IShellFolder_Release(psfMyComputer);
442 return;
444 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
446 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
447 ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
448 if (hr != S_OK) {
449 IShellFolder_Release(psfMyComputer);
450 return;
453 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
454 ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
455 IShellFolder_Release(psfMyComputer);
456 IMalloc_Free(ppM, pidlSystemDir);
457 if (hr != S_OK) return;
459 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
460 ok (hr == E_INVALIDARG,
461 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
463 if (0)
465 /* this call segfaults on 98SE */
466 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
467 ok (hr == E_INVALIDARG,
468 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
471 IShellFolder_Release(psfSystemDir);
474 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
475 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
477 size_t iLen;
479 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
480 return NULL;
482 if (iLen)
484 lpszPath += iLen;
485 if (lpszPath[-1] != '\\')
487 *lpszPath++ = '\\';
488 *lpszPath = '\0';
491 return lpszPath;
494 static void test_GetDisplayName(void)
496 BOOL result;
497 HRESULT hr;
498 HANDLE hTestFile;
499 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
500 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
501 DWORD attr;
502 STRRET strret;
503 LPSHELLFOLDER psfDesktop, psfPersonal;
504 IUnknown *psfFile;
505 SHITEMID emptyitem = { 0, { 0 } };
506 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
507 LPCITEMIDLIST pidlLast;
508 static const CHAR szFileName[] = "winetest.foo";
509 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
510 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
512 /* I'm trying to figure if there is a functional difference between calling
513 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
514 * binding to the shellfolder. One thing I thought of was that perhaps
515 * SHGetPathFromIDListW would be able to get the path to a file, which does
516 * not exist anymore, while the other method wouldn't. It turns out there's
517 * no functional difference in this respect.
520 if(!pSHGetSpecialFolderPathA) {
521 win_skip("SHGetSpecialFolderPathA is not available\n");
522 return;
525 /* First creating a directory in MyDocuments and a file in this directory. */
526 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
527 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
528 if (!result) return;
530 /* Use ANSI file functions so this works on Windows 9x */
531 lstrcatA(szTestDir, "\\winetest");
532 CreateDirectoryA(szTestDir, NULL);
533 attr=GetFileAttributesA(szTestDir);
534 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
536 ok(0, "unable to create the '%s' directory\n", szTestDir);
537 return;
540 lstrcpyA(szTestFile, szTestDir);
541 lstrcatA(szTestFile, "\\");
542 lstrcatA(szTestFile, szFileName);
543 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
544 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
545 if (hTestFile == INVALID_HANDLE_VALUE) return;
546 CloseHandle(hTestFile);
548 /* Getting an itemidlist for the file. */
549 hr = SHGetDesktopFolder(&psfDesktop);
550 ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
551 if (hr != S_OK) return;
553 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
555 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
556 ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
557 if (hr != S_OK) {
558 IShellFolder_Release(psfDesktop);
559 return;
562 pidlLast = pILFindLastID(pidlTestFile);
563 ok(pidlLast->mkid.cb >=76 ||
564 broken(pidlLast->mkid.cb == 28) || /* W2K */
565 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
566 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
567 if (pidlLast->mkid.cb >= 28) {
568 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
569 "Filename should be stored as ansi-string at this position!\n");
571 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
572 if (pidlLast->mkid.cb >= 76) {
573 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
574 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
575 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
576 "Filename should be stored as wchar-string at this position!\n");
579 /* It seems as if we cannot bind to regular files on windows, but only directories.
581 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
582 todo_wine
583 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
584 hr == E_NOTIMPL || /* Vista */
585 broken(hr == S_OK), /* Win9x, W2K */
586 "hr = %08x\n", hr);
587 if (hr == S_OK) {
588 IShellFolder_Release(psfFile);
591 if (!pSHBindToParent)
593 win_skip("SHBindToParent is missing\n");
594 DeleteFileA(szTestFile);
595 RemoveDirectoryA(szTestDir);
596 return;
599 /* Some tests for IShellFolder::SetNameOf */
600 if (pSHGetFolderPathAndSubDirA)
602 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
603 ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
604 if (hr == S_OK) {
605 /* It's ok to use this fixed path. Call will fail anyway. */
606 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
607 LPITEMIDLIST pidlNew;
609 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
610 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
611 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
612 if (hr == S_OK)
614 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
615 "pidl returned from SetNameOf should be simple!\n");
617 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
618 * is implemented on top of SHFileOperation in WinXP. */
619 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
620 SHGDN_FORPARSING, NULL);
621 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
623 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
624 * SHGDN flags specify an absolute path. */
625 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
626 ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
628 pILFree(pidlNew);
631 IShellFolder_Release(psfPersonal);
634 else
635 win_skip("Avoid needs of interaction on Win2k\n");
637 /* Deleting the file and the directory */
638 DeleteFileA(szTestFile);
639 RemoveDirectoryA(szTestDir);
641 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
642 if (pSHGetPathFromIDListW)
644 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
645 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
646 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
649 /* SHBindToParent fails, if called with a NULL PIDL. */
650 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
651 ok (hr != S_OK, "SHBindToParent(NULL) should fail!\n");
653 /* But it succeeds with an empty PIDL. */
654 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
655 ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
656 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
657 if (hr == S_OK)
658 IShellFolder_Release(psfPersonal);
660 /* Binding to the folder and querying the display name of the file also works. */
661 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
662 ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
663 if (hr != S_OK) {
664 IShellFolder_Release(psfDesktop);
665 return;
668 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
669 * pidlTestFile (In accordance with MSDN). */
670 ok (pILFindLastID(pidlTestFile) == pidlLast,
671 "SHBindToParent doesn't return the last id of the pidl param!\n");
673 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
674 ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
675 if (hr != S_OK) {
676 IShellFolder_Release(psfDesktop);
677 IShellFolder_Release(psfPersonal);
678 return;
681 if (pStrRetToBufW)
683 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
684 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
685 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
688 ILFree(pidlTestFile);
689 IShellFolder_Release(psfDesktop);
690 IShellFolder_Release(psfPersonal);
693 static void test_CallForAttributes(void)
695 HKEY hKey;
696 LONG lResult;
697 HRESULT hr;
698 DWORD dwSize;
699 LPSHELLFOLDER psfDesktop;
700 LPITEMIDLIST pidlMyDocuments;
701 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
702 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
703 static const WCHAR wszCallForAttributes[] = {
704 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
705 static const WCHAR wszMyDocumentsKey[] = {
706 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
707 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
708 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
709 WCHAR wszMyDocuments[] = {
710 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
711 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
713 /* For the root of a namespace extension, the attributes are not queried by binding
714 * to the object and calling GetAttributesOf. Instead, the attributes are read from
715 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
717 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
718 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
719 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
720 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
722 hr = SHGetDesktopFolder(&psfDesktop);
723 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
724 if (hr != S_OK) return;
726 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
727 &pidlMyDocuments, NULL);
728 ok (hr == S_OK ||
729 broken(hr == E_INVALIDARG), /* Win95, NT4 */
730 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
731 if (hr != S_OK) {
732 IShellFolder_Release(psfDesktop);
733 return;
736 dwAttributes = 0xffffffff;
737 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
738 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
739 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
741 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
742 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
743 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
744 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
746 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
747 * key. So the test will return at this point, if run on wine.
749 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
750 ok (lResult == ERROR_SUCCESS ||
751 lResult == ERROR_ACCESS_DENIED,
752 "RegOpenKeyEx failed! result: %08x\n", lResult);
753 if (lResult != ERROR_SUCCESS) {
754 if (lResult == ERROR_ACCESS_DENIED)
755 skip("Not enough rights to open the registry key\n");
756 IMalloc_Free(ppM, pidlMyDocuments);
757 IShellFolder_Release(psfDesktop);
758 return;
761 /* Query MyDocuments' Attributes value, to be able to restore it later. */
762 dwSize = sizeof(DWORD);
763 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
764 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
765 if (lResult != ERROR_SUCCESS) {
766 RegCloseKey(hKey);
767 IMalloc_Free(ppM, pidlMyDocuments);
768 IShellFolder_Release(psfDesktop);
769 return;
772 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
773 dwSize = sizeof(DWORD);
774 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
775 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
776 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
777 if (lResult != ERROR_SUCCESS) {
778 RegCloseKey(hKey);
779 IMalloc_Free(ppM, pidlMyDocuments);
780 IShellFolder_Release(psfDesktop);
781 return;
784 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
785 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
786 * SFGAO_FILESYSTEM attributes. */
787 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
788 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
789 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
790 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
791 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
793 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
794 * GetAttributesOf. It seems that once there is a single attribute queried, for which
795 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
796 * the flags in Attributes are ignored.
798 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
799 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
800 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
801 ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
802 if (hr == S_OK)
803 ok (dwAttributes == SFGAO_FILESYSTEM,
804 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
805 dwAttributes);
807 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
808 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
809 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
810 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
811 RegCloseKey(hKey);
812 IMalloc_Free(ppM, pidlMyDocuments);
813 IShellFolder_Release(psfDesktop);
816 static void test_GetAttributesOf(void)
818 HRESULT hr;
819 LPSHELLFOLDER psfDesktop, psfMyComputer;
820 SHITEMID emptyitem = { 0, { 0 } };
821 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
822 LPITEMIDLIST pidlMyComputer;
823 DWORD dwFlags;
824 static const DWORD desktopFlags[] = {
825 /* WinXP */
826 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
827 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
828 /* Win2k */
829 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
830 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
831 /* WinMe, Win9x, WinNT*/
832 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
833 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
835 static const DWORD myComputerFlags[] = {
836 /* WinXP */
837 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
838 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
839 /* Win2k */
840 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
841 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
842 /* WinMe, Win9x, WinNT */
843 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
844 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
845 /* Win95, WinNT when queried directly */
846 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
847 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
849 WCHAR wszMyComputer[] = {
850 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
851 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
852 char cCurrDirA [MAX_PATH] = {0};
853 WCHAR cCurrDirW [MAX_PATH];
854 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
855 IShellFolder *IDesktopFolder, *testIShellFolder;
856 ITEMIDLIST *newPIDL;
857 int len, i;
858 BOOL foundFlagsMatch;
860 hr = SHGetDesktopFolder(&psfDesktop);
861 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
862 if (hr != S_OK) return;
864 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
865 dwFlags = 0xffffffff;
866 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
867 ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
868 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
869 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
871 if (desktopFlags[i] == dwFlags)
872 foundFlagsMatch = TRUE;
874 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
876 /* .. or with no itemidlist at all. */
877 dwFlags = 0xffffffff;
878 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
879 ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
880 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
881 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
883 if (desktopFlags[i] == dwFlags)
884 foundFlagsMatch = TRUE;
886 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
888 /* Testing the attributes of the MyComputer shellfolder */
889 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
890 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
891 if (hr != S_OK) {
892 IShellFolder_Release(psfDesktop);
893 return;
896 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
897 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
899 dwFlags = 0xffffffff;
900 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
901 ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
902 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
903 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
905 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
906 foundFlagsMatch = TRUE;
908 todo_wine
909 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
911 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
912 ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
913 IShellFolder_Release(psfDesktop);
914 IMalloc_Free(ppM, pidlMyComputer);
915 if (hr != S_OK) return;
917 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
918 todo_wine
919 ok (hr == E_INVALIDARG ||
920 broken(hr == S_OK), /* W2K and earlier */
921 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
923 dwFlags = 0xffffffff;
924 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
925 ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
926 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
927 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
929 if (myComputerFlags[i] == dwFlags)
930 foundFlagsMatch = TRUE;
932 todo_wine
933 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
935 IShellFolder_Release(psfMyComputer);
937 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
938 len = lstrlenA(cCurrDirA);
940 if (len == 0) {
941 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
942 return;
944 if (len > 3 && cCurrDirA[len-1] == '\\')
945 cCurrDirA[len-1] = 0;
947 /* create test directory */
948 CreateFilesFolders();
950 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
952 hr = SHGetDesktopFolder(&IDesktopFolder);
953 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
955 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
956 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
958 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
959 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
961 IMalloc_Free(ppM, newPIDL);
963 /* get relative PIDL */
964 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
965 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
967 /* test the shell attributes of the test directory using the relative PIDL */
968 dwFlags = SFGAO_FOLDER;
969 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
970 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
971 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
973 /* free memory */
974 IMalloc_Free(ppM, newPIDL);
976 /* append testdirectory name to path */
977 if (cCurrDirA[len-1] == '\\')
978 cCurrDirA[len-1] = 0;
979 lstrcatA(cCurrDirA, "\\testdir");
980 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
982 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
983 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
985 /* test the shell attributes of the test directory using the absolute PIDL */
986 dwFlags = SFGAO_FOLDER;
987 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
988 ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
989 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
991 /* free memory */
992 IMalloc_Free(ppM, newPIDL);
994 IShellFolder_Release(testIShellFolder);
996 Cleanup();
998 IShellFolder_Release(IDesktopFolder);
1001 static void test_SHGetPathFromIDList(void)
1003 SHITEMID emptyitem = { 0, { 0 } };
1004 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1005 LPITEMIDLIST pidlMyComputer;
1006 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1007 BOOL result;
1008 HRESULT hr;
1009 LPSHELLFOLDER psfDesktop;
1010 WCHAR wszMyComputer[] = {
1011 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1012 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1013 WCHAR wszFileName[MAX_PATH];
1014 LPITEMIDLIST pidlTestFile;
1015 HANDLE hTestFile;
1016 STRRET strret;
1017 static WCHAR wszTestFile[] = {
1018 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1019 LPITEMIDLIST pidlPrograms;
1021 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
1023 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
1024 return;
1027 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1028 wszPath[0] = 'a';
1029 wszPath[1] = '\0';
1030 result = pSHGetPathFromIDListW(NULL, wszPath);
1031 ok(!result, "Expected failure\n");
1032 ok(!wszPath[0], "Expected empty string\n");
1034 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1035 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
1036 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1037 if (!result) return;
1039 /* Check if we are on Win9x */
1040 SetLastError(0xdeadbeef);
1041 lstrcmpiW(wszDesktop, wszDesktop);
1042 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1044 win_skip("Most W-calls are not implemented\n");
1045 return;
1048 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
1049 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1050 if (!result) return;
1051 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1053 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1054 hr = SHGetDesktopFolder(&psfDesktop);
1055 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1056 if (hr != S_OK) return;
1058 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1059 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1060 if (hr != S_OK) {
1061 IShellFolder_Release(psfDesktop);
1062 return;
1065 SetLastError(0xdeadbeef);
1066 wszPath[0] = 'a';
1067 wszPath[1] = '\0';
1068 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
1069 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1070 ok (GetLastError()==0xdeadbeef ||
1071 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1072 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1073 ok (!wszPath[0], "Expected empty path\n");
1074 if (result) {
1075 IShellFolder_Release(psfDesktop);
1076 return;
1079 IMalloc_Free(ppM, pidlMyComputer);
1081 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1082 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1083 if (!result) {
1084 IShellFolder_Release(psfDesktop);
1085 return;
1087 myPathAddBackslashW(wszFileName);
1088 lstrcatW(wszFileName, wszTestFile);
1089 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1090 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1091 if (hTestFile == INVALID_HANDLE_VALUE) {
1092 IShellFolder_Release(psfDesktop);
1093 return;
1095 CloseHandle(hTestFile);
1097 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1098 ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1099 if (hr != S_OK) {
1100 IShellFolder_Release(psfDesktop);
1101 DeleteFileW(wszFileName);
1102 IMalloc_Free(ppM, pidlTestFile);
1103 return;
1106 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1107 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1108 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1109 ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1110 IShellFolder_Release(psfDesktop);
1111 DeleteFileW(wszFileName);
1112 if (hr != S_OK) {
1113 IMalloc_Free(ppM, pidlTestFile);
1114 return;
1116 if (pStrRetToBufW)
1118 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1119 ok(0 == lstrcmpW(wszFileName, wszPath),
1120 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1121 "returned incorrect path for file placed on desktop\n");
1124 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1125 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1126 IMalloc_Free(ppM, pidlTestFile);
1127 if (!result) return;
1128 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1131 /* Test if we can get the path from the start menu "program files" PIDL. */
1132 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1133 ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1135 SetLastError(0xdeadbeef);
1136 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1137 IMalloc_Free(ppM, pidlPrograms);
1138 ok(result, "SHGetPathFromIDListW failed\n");
1141 static void test_EnumObjects_and_CompareIDs(void)
1143 ITEMIDLIST *newPIDL;
1144 IShellFolder *IDesktopFolder, *testIShellFolder;
1145 char cCurrDirA [MAX_PATH] = {0};
1146 static const CHAR cTestDirA[] = "\\testdir";
1147 WCHAR cTestDirW[MAX_PATH];
1148 int len;
1149 HRESULT hr;
1151 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1152 len = lstrlenA(cCurrDirA);
1154 if(len == 0) {
1155 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1156 return;
1158 if(cCurrDirA[len-1] == '\\')
1159 cCurrDirA[len-1] = 0;
1161 lstrcatA(cCurrDirA, cTestDirA);
1162 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1164 hr = SHGetDesktopFolder(&IDesktopFolder);
1165 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1167 CreateFilesFolders();
1169 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1170 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1172 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1173 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1175 test_EnumObjects(testIShellFolder);
1177 IShellFolder_Release(testIShellFolder);
1179 Cleanup();
1181 IMalloc_Free(ppM, newPIDL);
1183 IShellFolder_Release(IDesktopFolder);
1186 /* A simple implementation of an IPropertyBag, which returns fixed values for
1187 * 'Target' and 'Attributes' properties.
1189 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1190 void **ppvObject)
1192 if (!ppvObject)
1193 return E_INVALIDARG;
1195 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1196 *ppvObject = iface;
1197 } else {
1198 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1199 return E_NOINTERFACE;
1202 IPropertyBag_AddRef(iface);
1203 return S_OK;
1206 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1207 return 2;
1210 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1211 return 1;
1214 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1215 VARIANT *pVar, IErrorLog *pErrorLog)
1217 static const WCHAR wszTargetSpecialFolder[] = {
1218 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1219 static const WCHAR wszTarget[] = {
1220 'T','a','r','g','e','t',0 };
1221 static const WCHAR wszAttributes[] = {
1222 'A','t','t','r','i','b','u','t','e','s',0 };
1223 static const WCHAR wszResolveLinkFlags[] = {
1224 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1225 static const WCHAR wszTargetKnownFolder[] = {
1226 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1227 static const WCHAR wszCLSID[] = {
1228 'C','L','S','I','D',0 };
1230 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1231 ok(V_VT(pVar) == VT_I4 ||
1232 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1233 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1234 return E_INVALIDARG;
1237 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1239 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1240 return E_INVALIDARG;
1243 if (!lstrcmpW(pszPropName, wszTarget)) {
1244 WCHAR wszPath[MAX_PATH];
1245 BOOL result;
1247 ok(V_VT(pVar) == VT_BSTR ||
1248 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1249 "Wrong variant type for 'Target' property!\n");
1250 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1252 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1253 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1254 if (!result) return E_INVALIDARG;
1256 V_BSTR(pVar) = SysAllocString(wszPath);
1257 return S_OK;
1260 if (!lstrcmpW(pszPropName, wszAttributes)) {
1261 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1262 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1263 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1264 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1265 return S_OK;
1268 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1269 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1270 /* TODO */
1271 return E_INVALIDARG;
1274 if (!lstrcmpW(pszPropName, wszCLSID)) {
1275 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1276 /* TODO */
1277 return E_INVALIDARG;
1280 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1281 return E_INVALIDARG;
1284 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1285 VARIANT *pVar)
1287 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1288 return E_NOTIMPL;
1291 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1292 InitPropertyBag_IPropertyBag_QueryInterface,
1293 InitPropertyBag_IPropertyBag_AddRef,
1294 InitPropertyBag_IPropertyBag_Release,
1295 InitPropertyBag_IPropertyBag_Read,
1296 InitPropertyBag_IPropertyBag_Write
1299 static struct IPropertyBag InitPropertyBag = {
1300 &InitPropertyBag_IPropertyBagVtbl
1303 static void test_FolderShortcut(void) {
1304 IPersistPropertyBag *pPersistPropertyBag;
1305 IShellFolder *pShellFolder, *pDesktopFolder;
1306 IPersistFolder3 *pPersistFolder3;
1307 HRESULT hr;
1308 STRRET strret;
1309 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1310 BOOL result;
1311 CLSID clsid;
1312 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1313 HKEY hShellExtKey;
1314 WCHAR wszWineTestFolder[] = {
1315 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1316 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1317 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1318 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1319 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1320 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1321 'N','a','m','e','S','p','a','c','e','\\',
1322 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1323 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1325 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1326 static const GUID CLSID_UnixDosFolder =
1327 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1329 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1330 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1331 return;
1334 if (!pSHGetFolderPathAndSubDirA)
1336 win_skip("FolderShortcut test doesn't work on Win2k\n");
1337 return;
1340 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1341 * via their IPersistPropertyBag interface. And that the target folder
1342 * is taken from the IPropertyBag's 'Target' property.
1344 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1345 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1346 if (hr == REGDB_E_CLASSNOTREG) {
1347 win_skip("CLSID_FolderShortcut is not implemented\n");
1348 return;
1350 ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1351 if (hr != S_OK) return;
1353 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1354 ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1355 if (hr != S_OK) {
1356 IPersistPropertyBag_Release(pPersistPropertyBag);
1357 return;
1360 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1361 (LPVOID*)&pShellFolder);
1362 IPersistPropertyBag_Release(pPersistPropertyBag);
1363 ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1364 if (hr != S_OK) return;
1366 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1367 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1368 if (hr != S_OK) {
1369 IShellFolder_Release(pShellFolder);
1370 return;
1373 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1374 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1375 if (!result) return;
1377 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1378 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1380 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1381 IShellFolder_Release(pShellFolder);
1382 ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1383 if (hr != S_OK) return;
1385 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1386 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1387 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1389 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1390 todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1391 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1393 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1394 * shell namespace. The target folder, read from the property bag above, remains untouched.
1395 * The following tests show this: The itemidlist for some imaginary shellfolder object
1396 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1397 * itemidlist, but GetDisplayNameOf still returns the path from above.
1399 hr = SHGetDesktopFolder(&pDesktopFolder);
1400 ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1401 if (hr != S_OK) return;
1403 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1404 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1405 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1406 RegCloseKey(hShellExtKey);
1407 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1408 &pidlWineTestFolder, NULL);
1409 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1410 IShellFolder_Release(pDesktopFolder);
1411 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1412 if (hr != S_OK) return;
1414 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1415 ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1416 if (hr != S_OK) {
1417 IPersistFolder3_Release(pPersistFolder3);
1418 pILFree(pidlWineTestFolder);
1419 return;
1422 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1423 ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1424 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1425 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1426 pILFree(pidlCurrentFolder);
1427 pILFree(pidlWineTestFolder);
1429 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1430 IPersistFolder3_Release(pPersistFolder3);
1431 ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1432 if (hr != S_OK) return;
1434 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1435 ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1436 if (hr != S_OK) {
1437 IShellFolder_Release(pShellFolder);
1438 return;
1441 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1442 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1444 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1445 * but ShellFSFolders. */
1446 myPathAddBackslashW(wszDesktopPath);
1447 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1448 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1449 IShellFolder_Release(pShellFolder);
1450 return;
1453 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1454 &pidlSubFolder, NULL);
1455 RemoveDirectoryW(wszDesktopPath);
1456 ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1457 if (hr != S_OK) {
1458 IShellFolder_Release(pShellFolder);
1459 return;
1462 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1463 (LPVOID*)&pPersistFolder3);
1464 IShellFolder_Release(pShellFolder);
1465 pILFree(pidlSubFolder);
1466 ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1467 if (hr != S_OK)
1468 return;
1470 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1471 * a little bit and also allow CLSID_UnixDosFolder. */
1472 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1473 ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1474 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1475 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1477 IPersistFolder3_Release(pPersistFolder3);
1480 #include "pshpack1.h"
1481 struct FileStructA {
1482 BYTE type;
1483 BYTE dummy;
1484 DWORD dwFileSize;
1485 WORD uFileDate; /* In our current implementation this is */
1486 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1487 WORD uFileAttribs;
1488 CHAR szName[1];
1491 struct FileStructW {
1492 WORD cbLen; /* Length of this element. */
1493 BYTE abFooBar1[6]; /* Beyond any recognition. */
1494 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1495 WORD uTime; /* (this is currently speculation) */
1496 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1497 WORD uTime2; /* (this is currently speculation) */
1498 BYTE abFooBar2[4]; /* Beyond any recognition. */
1499 WCHAR wszName[1]; /* The long filename in unicode. */
1500 /* Just for documentation: Right after the unicode string: */
1501 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1502 * SHITEMID->cb == uOffset + cbLen */
1504 #include "poppack.h"
1506 static void test_ITEMIDLIST_format(void) {
1507 WCHAR wszPersonal[MAX_PATH];
1508 LPSHELLFOLDER psfDesktop, psfPersonal;
1509 LPITEMIDLIST pidlPersonal, pidlFile;
1510 HANDLE hFile;
1511 HRESULT hr;
1512 BOOL bResult;
1513 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1514 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1515 int i;
1517 if (!pSHGetSpecialFolderPathW) return;
1519 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1520 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1521 if (!bResult) return;
1523 SetLastError(0xdeadbeef);
1524 bResult = SetCurrentDirectoryW(wszPersonal);
1525 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1526 win_skip("Most W-calls are not implemented\n");
1527 return;
1529 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1530 if (!bResult) return;
1532 hr = SHGetDesktopFolder(&psfDesktop);
1533 ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1534 if (hr != S_OK) return;
1536 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1537 ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1538 if (hr != S_OK) {
1539 IShellFolder_Release(psfDesktop);
1540 return;
1543 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1544 (LPVOID*)&psfPersonal);
1545 IShellFolder_Release(psfDesktop);
1546 pILFree(pidlPersonal);
1547 ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1548 if (hr != S_OK) return;
1550 for (i=0; i<3; i++) {
1551 CHAR szFile[MAX_PATH];
1552 struct FileStructA *pFileStructA;
1553 WORD cbOffset;
1555 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1557 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1558 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1559 if (hFile == INVALID_HANDLE_VALUE) {
1560 IShellFolder_Release(psfPersonal);
1561 return;
1563 CloseHandle(hFile);
1565 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1566 DeleteFileW(wszFile[i]);
1567 ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1568 if (hr != S_OK) {
1569 IShellFolder_Release(psfPersonal);
1570 return;
1573 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1574 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1575 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1576 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1578 if (i < 2) /* First two file names are already in valid 8.3 format */
1579 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1580 else
1581 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1582 * can't implement this correctly, since unix filesystems don't support
1583 * this nasty short/long filename stuff. So we'll probably stay with our
1584 * current habbit of storing the long filename here, which seems to work
1585 * just fine. */
1586 todo_wine
1587 ok(pidlFile->mkid.abID[18] == '~' ||
1588 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1589 "Should be derived 8.3 name!\n");
1591 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1592 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1593 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1594 "Alignment byte, where there shouldn't be!\n");
1596 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1597 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1598 "There should be an alignment byte, but isn't!\n");
1600 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1601 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1602 ok ((cbOffset >= sizeof(struct FileStructA) &&
1603 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1604 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1605 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1606 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1608 if (cbOffset >= sizeof(struct FileStructA) &&
1609 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1611 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1613 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1614 "FileStructW's offset and length should add up to the PIDL's length!\n");
1616 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1617 /* Since we just created the file, time of creation,
1618 * time of last access and time of last write access just be the same.
1619 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1620 * after the first run. I do remember something with NTFS keeping the creation time
1621 * if a file is deleted and then created again within a couple of seconds or so.
1622 * Might be the reason. */
1623 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1624 pFileStructA->uFileTime == pFileStructW->uTime,
1625 "Last write time should match creation time!\n");
1627 /* On FAT filesystems the last access time is midnight
1628 local time, so the values of uDate2 and uTime2 will
1629 depend on the local timezone. If the times are exactly
1630 equal then the dates should be identical for both FAT
1631 and NTFS as no timezone is more than 1 day away from UTC.
1633 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1635 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1636 "Last write date and time should match last access date and time!\n");
1638 else
1640 /* Filesystem may be FAT. Check date within 1 day
1641 and seconds are zero. */
1642 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1643 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1644 "Last access time on FAT filesystems should have zero seconds.\n");
1645 /* TODO: Perform check for date being within one day.*/
1648 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1649 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1650 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1651 "The filename should be stored in unicode at this position!\n");
1655 pILFree(pidlFile);
1658 IShellFolder_Release(psfPersonal);
1661 static void test_SHGetFolderPathAndSubDirA(void)
1663 HRESULT ret;
1664 BOOL delret;
1665 DWORD dwret;
1666 int i;
1667 static char wine[] = "wine";
1668 static char winetemp[] = "wine\\temp";
1669 static char appdata[MAX_PATH];
1670 static char testpath[MAX_PATH];
1671 static char toolongpath[MAX_PATH+1];
1673 if(!pSHGetFolderPathAndSubDirA)
1675 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1676 return;
1679 if(!pSHGetFolderPathA) {
1680 win_skip("SHGetFolderPathA not present!\n");
1681 return;
1683 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1685 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1686 return;
1689 sprintf(testpath, "%s\\%s", appdata, winetemp);
1690 delret = RemoveDirectoryA(testpath);
1691 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1692 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1693 return;
1696 sprintf(testpath, "%s\\%s", appdata, wine);
1697 delret = RemoveDirectoryA(testpath);
1698 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1699 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1700 return;
1703 /* test invalid second parameter */
1704 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1705 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1707 /* test fourth parameter */
1708 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1709 switch(ret) {
1710 case S_OK: /* winvista */
1711 ok(!strncmp(appdata, testpath, strlen(appdata)),
1712 "expected %s to start with %s\n", testpath, appdata);
1713 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1714 "expected %s to end with %s\n", testpath, winetemp);
1715 break;
1716 case E_INVALIDARG: /* winxp, win2k3 */
1717 break;
1718 default:
1719 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
1722 /* test fifth parameter */
1723 testpath[0] = '\0';
1724 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1725 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1726 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1728 testpath[0] = '\0';
1729 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1730 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1731 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1733 testpath[0] = '\0';
1734 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1735 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1736 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1738 for(i=0; i< MAX_PATH; i++)
1739 toolongpath[i] = '0' + i % 10;
1740 toolongpath[MAX_PATH] = '\0';
1741 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1742 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1743 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1745 testpath[0] = '\0';
1746 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1747 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1749 /* test a not existing path */
1750 testpath[0] = '\0';
1751 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1752 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1753 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1755 /* create a directory inside a not existing directory */
1756 testpath[0] = '\0';
1757 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1758 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1759 ok(!strncmp(appdata, testpath, strlen(appdata)),
1760 "expected %s to start with %s\n", testpath, appdata);
1761 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1762 "expected %s to end with %s\n", testpath, winetemp);
1763 dwret = GetFileAttributes(testpath);
1764 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1766 /* cleanup */
1767 sprintf(testpath, "%s\\%s", appdata, winetemp);
1768 RemoveDirectoryA(testpath);
1769 sprintf(testpath, "%s\\%s", appdata, wine);
1770 RemoveDirectoryA(testpath);
1773 static void test_LocalizedNames(void)
1775 static char cCurrDirA[MAX_PATH];
1776 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1777 IShellFolder *IDesktopFolder, *testIShellFolder;
1778 ITEMIDLIST *newPIDL;
1779 int len;
1780 HRESULT hr;
1781 static char resourcefile[MAX_PATH];
1782 DWORD res;
1783 HANDLE file;
1784 STRRET strret;
1786 static const char desktopini_contents1[] =
1787 "[.ShellClassInfo]\r\n"
1788 "LocalizedResourceName=@";
1789 static const char desktopini_contents2[] =
1790 ",-1\r\n";
1791 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1792 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1794 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1795 CreateDirectoryA(".\\testfolder", NULL);
1797 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1799 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1801 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1802 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1803 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1804 ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1805 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1806 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
1807 "WriteFile failed %i\n", GetLastError());
1808 CloseHandle(file);
1810 /* get IShellFolder for parent */
1811 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1812 len = lstrlenA(cCurrDirA);
1814 if (len == 0) {
1815 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1816 goto cleanup;
1818 if(cCurrDirA[len-1] == '\\')
1819 cCurrDirA[len-1] = 0;
1821 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1823 hr = SHGetDesktopFolder(&IDesktopFolder);
1824 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1826 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1827 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1829 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1830 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1832 IMalloc_Free(ppM, newPIDL);
1834 /* windows reads the display name from the resource */
1835 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1836 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1838 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1839 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1841 if (hr == S_OK && pStrRetToBufW)
1843 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1844 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1845 todo_wine
1846 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1847 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1848 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1851 /* editing name is also read from the resource */
1852 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1853 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1855 if (hr == S_OK && pStrRetToBufW)
1857 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1858 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1859 todo_wine
1860 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1861 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1862 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1865 /* parsing name is unchanged */
1866 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1867 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1869 if (hr == S_OK && pStrRetToBufW)
1871 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1872 ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1873 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1876 IShellFolder_Release(IDesktopFolder);
1877 IShellFolder_Release(testIShellFolder);
1879 IMalloc_Free(ppM, newPIDL);
1881 cleanup:
1882 DeleteFileA(".\\testfolder\\desktop.ini");
1883 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1884 RemoveDirectoryA(".\\testfolder");
1887 static void test_SHCreateShellItem(void)
1889 IShellItem *shellitem, *shellitem2;
1890 IPersistIDList *persistidl;
1891 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
1892 HRESULT ret;
1893 char curdirA[MAX_PATH];
1894 WCHAR curdirW[MAX_PATH];
1895 WCHAR fnbufW[MAX_PATH];
1896 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
1897 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
1899 GetCurrentDirectoryA(MAX_PATH, curdirA);
1901 if (!pSHCreateShellItem)
1903 win_skip("SHCreateShellItem isn't available\n");
1904 return;
1907 if (!lstrlenA(curdirA))
1909 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
1910 return;
1913 if(pSHGetSpecialFolderLocation)
1915 ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
1916 ok(ret == S_OK, "Got 0x%08x\n", ret);
1918 else
1920 win_skip("pSHGetSpecialFolderLocation missing.\n");
1921 pidl_desktop = NULL;
1924 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
1926 ret = SHGetDesktopFolder(&desktopfolder);
1927 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
1929 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
1930 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1932 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
1933 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
1935 CreateTestFile(".\\testfile");
1937 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
1938 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1940 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
1942 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
1943 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
1945 if (0) /* crashes on Windows XP */
1947 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
1948 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
1949 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
1950 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
1953 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
1954 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1955 if (SUCCEEDED(ret))
1957 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1958 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1959 if (SUCCEEDED(ret))
1961 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1962 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1963 if (SUCCEEDED(ret))
1965 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1966 pILFree(pidl_test);
1968 IPersistIDList_Release(persistidl);
1970 IShellItem_Release(shellitem);
1973 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
1974 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1975 if (SUCCEEDED(ret))
1977 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1978 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1979 if (SUCCEEDED(ret))
1981 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1982 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1983 if (SUCCEEDED(ret))
1985 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1986 pILFree(pidl_test);
1988 IPersistIDList_Release(persistidl);
1991 ret = IShellItem_GetParent(shellitem, &shellitem2);
1992 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
1993 if (SUCCEEDED(ret))
1995 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
1996 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1997 if (SUCCEEDED(ret))
1999 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2000 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2001 if (SUCCEEDED(ret))
2003 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2004 pILFree(pidl_test);
2006 IPersistIDList_Release(persistidl);
2008 IShellItem_Release(shellitem2);
2011 IShellItem_Release(shellitem);
2014 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2015 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2016 if (SUCCEEDED(ret))
2018 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2019 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2020 if (SUCCEEDED(ret))
2022 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2023 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2024 if (SUCCEEDED(ret))
2026 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2027 pILFree(pidl_test);
2029 IPersistIDList_Release(persistidl);
2031 IShellItem_Release(shellitem);
2034 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2035 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2036 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2037 if (SUCCEEDED(ret))
2039 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2040 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2041 if (SUCCEEDED(ret))
2043 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2044 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2045 if (SUCCEEDED(ret))
2047 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2048 pILFree(pidl_test);
2050 IPersistIDList_Release(persistidl);
2052 IShellItem_Release(shellitem);
2055 ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2056 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2057 if (SUCCEEDED(ret))
2059 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2060 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2061 if (SUCCEEDED(ret))
2063 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2064 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2065 if (SUCCEEDED(ret))
2067 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2068 pILFree(pidl_test);
2070 IPersistIDList_Release(persistidl);
2073 IShellItem_Release(shellitem);
2076 ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2077 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2078 if (SUCCEEDED(ret))
2080 ret = IShellItem_GetParent(shellitem, &shellitem2);
2081 ok(FAILED(ret), "Got 0x%08x\n", ret);
2082 if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2083 IShellItem_Release(shellitem);
2086 /* SHCreateItemFromParsingName */
2087 if(pSHCreateItemFromParsingName)
2089 if(0)
2091 /* Crashes under windows 7 */
2092 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2095 shellitem = (void*)0xdeadbeef;
2096 ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2097 ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2098 ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2100 ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2101 ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
2102 "SHCreateItemFromParsingName returned %x\n", ret);
2103 if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2105 lstrcpyW(fnbufW, curdirW);
2106 myPathAddBackslashW(fnbufW);
2107 lstrcatW(fnbufW, testfileW);
2109 ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2110 ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2111 if(SUCCEEDED(ret))
2113 LPWSTR tmp_fname;
2114 ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2115 ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2116 if(SUCCEEDED(ret))
2118 ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2119 CoTaskMemFree(tmp_fname);
2121 IShellItem_Release(shellitem);
2124 else
2125 win_skip("No SHCreateItemFromParsingName\n");
2128 /* SHCreateItemFromIDList */
2129 if(pSHCreateItemFromIDList)
2131 if(0)
2133 /* Crashes under win7 */
2134 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2137 ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2138 ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2140 ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2141 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2142 if (SUCCEEDED(ret))
2144 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2145 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2146 if (SUCCEEDED(ret))
2148 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2149 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2150 if (SUCCEEDED(ret))
2152 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2153 pILFree(pidl_test);
2155 IPersistIDList_Release(persistidl);
2157 IShellItem_Release(shellitem);
2160 ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2161 ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2162 if (SUCCEEDED(ret))
2164 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2165 ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2166 if (SUCCEEDED(ret))
2168 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2169 ok(ret == S_OK, "GetIDList returned %x\n", ret);
2170 if (SUCCEEDED(ret))
2172 ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2173 pILFree(pidl_test);
2175 IPersistIDList_Release(persistidl);
2177 IShellItem_Release(shellitem);
2180 else
2181 win_skip("No SHCreateItemFromIDList\n");
2183 DeleteFileA(".\\testfile");
2184 pILFree(pidl_abstestfile);
2185 pILFree(pidl_testfile);
2186 pILFree(pidl_desktop);
2187 pILFree(pidl_cwd);
2188 IShellFolder_Release(currentfolder);
2189 IShellFolder_Release(desktopfolder);
2192 static void test_SHGetNameFromIDList(void)
2194 IShellItem *shellitem;
2195 LPITEMIDLIST pidl;
2196 LPWSTR name_string;
2197 HRESULT hres;
2198 UINT i;
2199 static const DWORD flags[] = {
2200 SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2201 SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2202 SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2203 SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2205 if(!pSHGetNameFromIDList)
2207 win_skip("SHGetNameFromIDList missing.\n");
2208 return;
2211 /* These should be available on any platform that passed the above test. */
2212 ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2213 ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
2214 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2215 ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
2217 if(0)
2219 /* Crashes under win7 */
2220 hres = pSHGetNameFromIDList(NULL, 0, NULL);
2223 hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2224 ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2226 /* Test the desktop */
2227 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
2228 ok(hres == S_OK, "Got 0x%08x\n", hres);
2229 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2230 ok(hres == S_OK, "Got 0x%08x\n", hres);
2231 if(SUCCEEDED(hres))
2233 WCHAR *nameSI, *nameSH;
2234 WCHAR buf[MAX_PATH];
2235 HRESULT hrSI, hrSH, hrSF;
2236 STRRET strret;
2237 IShellFolder *psf;
2238 BOOL res;
2240 SHGetDesktopFolder(&psf);
2241 for(i = 0; flags[i] != -1234; i++)
2243 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2244 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2245 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2246 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2247 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2248 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2250 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2251 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2253 if(SUCCEEDED(hrSF))
2255 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2256 if(SUCCEEDED(hrSI))
2257 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2258 if(SUCCEEDED(hrSF))
2259 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2261 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2262 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2264 IShellFolder_Release(psf);
2266 if(pSHGetPathFromIDListW){
2267 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2268 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2269 res = pSHGetPathFromIDListW(pidl, buf);
2270 ok(res == TRUE, "Got %d\n", res);
2271 if(SUCCEEDED(hrSI) && res)
2272 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2273 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2274 }else
2275 win_skip("pSHGetPathFromIDListW not available\n");
2277 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2278 todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2279 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2281 IShellItem_Release(shellitem);
2283 pILFree(pidl);
2285 /* Test the control panel */
2286 hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
2287 ok(hres == S_OK, "Got 0x%08x\n", hres);
2288 hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2289 ok(hres == S_OK, "Got 0x%08x\n", hres);
2290 if(SUCCEEDED(hres))
2292 WCHAR *nameSI, *nameSH;
2293 WCHAR buf[MAX_PATH];
2294 HRESULT hrSI, hrSH, hrSF;
2295 STRRET strret;
2296 IShellFolder *psf;
2297 BOOL res;
2299 SHGetDesktopFolder(&psf);
2300 for(i = 0; flags[i] != -1234; i++)
2302 hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2303 ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2304 hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2305 ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2306 hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2307 ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2309 if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2310 ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2312 if(SUCCEEDED(hrSF))
2314 pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
2315 if(SUCCEEDED(hrSI))
2316 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2317 if(SUCCEEDED(hrSF))
2318 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2320 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2321 if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2323 IShellFolder_Release(psf);
2325 if(pSHGetPathFromIDListW){
2326 hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2327 ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2328 res = pSHGetPathFromIDListW(pidl, buf);
2329 ok(res == FALSE, "Got %d\n", res);
2330 if(SUCCEEDED(hrSI) && res)
2331 ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2332 if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2333 }else
2334 win_skip("pSHGetPathFromIDListW not available\n");
2336 hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2337 todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2338 "Got 0x%08x\n", hres);
2339 if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2341 IShellItem_Release(shellitem);
2343 pILFree(pidl);
2346 static void test_SHGetItemFromDataObject(void)
2348 IShellFolder *psfdesktop;
2349 IShellItem *psi;
2350 IShellView *psv;
2351 HRESULT hres;
2353 if(!pSHGetItemFromDataObject)
2355 win_skip("No SHGetItemFromDataObject.\n");
2356 return;
2359 if(0)
2361 /* Crashes under win7 */
2362 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2365 hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2366 ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2368 SHGetDesktopFolder(&psfdesktop);
2370 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2371 ok(hres == S_OK, "got 0x%08x\n", hres);
2372 if(SUCCEEDED(hres))
2374 IEnumIDList *peidl;
2375 IDataObject *pdo;
2376 SHCONTF enum_flags;
2378 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2379 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2380 ok(hres == S_OK, "got 0x%08x\n", hres);
2381 if(SUCCEEDED(hres))
2383 LPITEMIDLIST apidl[5];
2384 UINT count = 0, i;
2386 for(count = 0; count < 5; count++)
2387 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2388 break;
2390 if(count)
2392 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2393 &IID_IDataObject, NULL, (void**)&pdo);
2394 ok(hres == S_OK, "got 0x%08x\n", hres);
2395 if(SUCCEEDED(hres))
2397 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2398 ok(hres == S_OK, "got 0x%08x\n", hres);
2399 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2400 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2401 ok(hres == S_OK, "got 0x%08x\n", hres);
2402 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2403 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2404 ok(hres == S_OK, "got 0x%08x\n", hres);
2405 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2406 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2407 ok(hres == S_OK, "got 0x%08x\n", hres);
2408 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2409 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2410 ok(hres == S_OK, "got 0x%08x\n", hres);
2411 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2413 IDataObject_Release(pdo);
2416 else
2417 skip("No file(s) found - skipping single-file test.\n");
2419 if(count > 1)
2421 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2422 &IID_IDataObject, NULL, (void**)&pdo);
2423 ok(hres == S_OK, "got 0x%08x\n", hres);
2424 if(SUCCEEDED(hres))
2426 hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2427 ok(hres == S_OK, "got 0x%08x\n", hres);
2428 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2429 hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2430 ok(hres == S_OK, "got 0x%08x\n", hres);
2431 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2432 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2433 ok(hres == S_OK, "got 0x%08x\n", hres);
2434 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2435 hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2436 ok(hres == S_OK, "got 0x%08x\n", hres);
2437 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2438 hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2439 ok(hres == E_FAIL, "got 0x%08x\n", hres);
2440 if(SUCCEEDED(hres)) IShellItem_Release(psi);
2441 IDataObject_Release(pdo);
2444 else
2445 skip("zero or one file found - skipping multi-file test.\n");
2447 for(i = 0; i < count; i++)
2448 pILFree(apidl[i]);
2450 IEnumIDList_Release(peidl);
2453 IShellView_Release(psv);
2456 IShellFolder_Release(psfdesktop);
2459 static void test_ShellItemCompare(void)
2461 IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2462 IShellItem *psi_a, *psi_b, *psi_c;
2463 IShellFolder *psf_desktop, *psf_current;
2464 LPITEMIDLIST pidl_cwd;
2465 WCHAR curdirW[MAX_PATH];
2466 BOOL failed;
2467 HRESULT hr;
2468 static const WCHAR filesW[][9] = {
2469 {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2470 {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2471 {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2472 int order;
2473 UINT i;
2475 if(!pSHCreateShellItem)
2477 win_skip("SHCreateShellItem missing.\n");
2478 return;
2481 GetCurrentDirectoryW(MAX_PATH, curdirW);
2482 if(!lstrlenW(curdirW))
2484 skip("Failed to get current directory, skipping.\n");
2485 return;
2488 CreateDirectoryA(".\\a", NULL);
2489 CreateDirectoryA(".\\b", NULL);
2490 CreateDirectoryA(".\\c", NULL);
2491 CreateTestFile(".\\a\\a");
2492 CreateTestFile(".\\a\\b");
2493 CreateTestFile(".\\a\\c");
2494 CreateTestFile(".\\b\\a");
2495 CreateTestFile(".\\b\\b");
2496 CreateTestFile(".\\b\\c");
2497 CreateTestFile(".\\c\\a");
2498 CreateTestFile(".\\c\\b");
2499 CreateTestFile(".\\c\\c");
2501 SHGetDesktopFolder(&psf_desktop);
2502 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2503 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2504 hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2505 ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2506 IShellFolder_Release(psf_desktop);
2508 /* Generate ShellItems for the files */
2509 ZeroMemory(&psi, sizeof(IShellItem*)*9);
2510 failed = FALSE;
2511 for(i = 0; i < 9; i++)
2513 LPITEMIDLIST pidl_testfile = NULL;
2515 hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2516 NULL, &pidl_testfile, NULL);
2517 ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2518 if(SUCCEEDED(hr))
2520 hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2521 ok(hr == S_OK, "Got 0x%08x\n", hr);
2522 pILFree(pidl_testfile);
2524 if(FAILED(hr)) failed = TRUE;
2526 if(failed)
2528 skip("Failed to create all shellitems.\n");
2529 goto cleanup;
2532 /* Generate ShellItems for the folders */
2533 psi_a = psi_b = psi_c = NULL;
2534 hr = IShellItem_GetParent(psi[0], &psi_a);
2535 ok(hr == S_OK, "Got 0x%08x\n", hr);
2536 if(FAILED(hr)) failed = TRUE;
2537 hr = IShellItem_GetParent(psi[3], &psi_b);
2538 ok(hr == S_OK, "Got 0x%08x\n", hr);
2539 if(FAILED(hr)) failed = TRUE;
2540 hr = IShellItem_GetParent(psi[6], &psi_c);
2541 ok(hr == S_OK, "Got 0x%08x\n", hr);
2542 if(FAILED(hr)) failed = TRUE;
2544 if(failed)
2546 skip("Failed to create shellitems.\n");
2547 goto cleanup;
2550 if(0)
2552 /* Crashes on native (win7, winxp) */
2553 hr = IShellItem_Compare(psi_a, NULL, 0, NULL);
2554 hr = IShellItem_Compare(psi_a, psi_b, 0, NULL);
2555 hr = IShellItem_Compare(psi_a, NULL, 0, &order);
2558 /* Basics */
2559 for(i = 0; i < 9; i++)
2561 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2562 ok(hr == S_OK, "Got 0x%08x\n", hr);
2563 ok(order == 0, "Got order %d\n", order);
2564 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2565 ok(hr == S_OK, "Got 0x%08x\n", hr);
2566 ok(order == 0, "Got order %d\n", order);
2567 hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2568 ok(hr == S_OK, "Got 0x%08x\n", hr);
2569 ok(order == 0, "Got order %d\n", order);
2572 /* Order */
2573 /* a\b:a\a , a\b:a\c, a\b:a\b */
2574 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2575 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2576 ok(order == 1, "Got order %d\n", order);
2577 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2578 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2579 ok(order == -1, "Got order %d\n", order);
2580 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2581 ok(hr == S_OK, "Got 0x%08x\n", hr);
2582 ok(order == 0, "Got order %d\n", order);
2584 /* b\b:a\b, b\b:c\b, b\b:c\b */
2585 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2586 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2587 ok(order == 1, "Got order %d\n", order);
2588 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2589 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2590 ok(order == -1, "Got order %d\n", order);
2591 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2592 ok(hr == S_OK, "Got 0x%08x\n", hr);
2593 ok(order == 0, "Got order %d\n", order);
2595 /* b:a\a, b:a\c, b:a\b */
2596 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2597 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2598 todo_wine ok(order == 1, "Got order %d\n", order);
2599 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2600 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2601 todo_wine ok(order == 1, "Got order %d\n", order);
2602 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2603 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2604 todo_wine ok(order == 1, "Got order %d\n", order);
2606 /* b:c\a, b:c\c, b:c\b */
2607 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2608 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2609 ok(order == -1, "Got order %d\n", order);
2610 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2611 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2612 ok(order == -1, "Got order %d\n", order);
2613 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2614 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2615 ok(order == -1, "Got order %d\n", order);
2617 /* a\b:a\a , a\b:a\c, a\b:a\b */
2618 hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2619 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2620 ok(order == 1, "Got order %d\n", order);
2621 hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2622 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2623 ok(order == -1, "Got order %d\n", order);
2624 hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2625 ok(hr == S_OK, "Got 0x%08x\n", hr);
2626 ok(order == 0, "Got order %d\n", order);
2628 /* b\b:a\b, b\b:c\b, b\b:c\b */
2629 hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2630 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2631 ok(order == 1, "Got order %d\n", order);
2632 hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2633 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2634 ok(order == -1, "Got order %d\n", order);
2635 hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2636 ok(hr == S_OK, "Got 0x%08x\n", hr);
2637 ok(order == 0, "Got order %d\n", order);
2639 /* b:a\a, b:a\c, b:a\b */
2640 hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2641 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2642 todo_wine ok(order == 1, "Got order %d\n", order);
2643 hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2644 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2645 todo_wine ok(order == 1, "Got order %d\n", order);
2646 hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2647 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2648 todo_wine ok(order == 1, "Got order %d\n", order);
2650 /* b:c\a, b:c\c, b:c\b */
2651 hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2652 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2653 ok(order == -1, "Got order %d\n", order);
2654 hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2655 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2656 ok(order == -1, "Got order %d\n", order);
2657 hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2658 ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2659 ok(order == -1, "Got order %d\n", order);
2661 cleanup:
2662 IShellFolder_Release(psf_current);
2664 DeleteFileA(".\\a\\a");
2665 DeleteFileA(".\\a\\b");
2666 DeleteFileA(".\\a\\c");
2667 DeleteFileA(".\\b\\a");
2668 DeleteFileA(".\\b\\b");
2669 DeleteFileA(".\\b\\c");
2670 DeleteFileA(".\\c\\a");
2671 DeleteFileA(".\\c\\b");
2672 DeleteFileA(".\\c\\c");
2673 RemoveDirectoryA(".\\a");
2674 RemoveDirectoryA(".\\b");
2675 RemoveDirectoryA(".\\c");
2677 if(psi_a) IShellItem_Release(psi_a);
2678 if(psi_b) IShellItem_Release(psi_b);
2679 if(psi_c) IShellItem_Release(psi_c);
2681 for(i = 0; i < 9; i++)
2682 if(psi[i]) IShellItem_Release(psi[i]);
2685 /**************************************************************/
2686 /* IUnknown implementation for counting QueryInterface calls. */
2687 typedef struct {
2688 const IUnknownVtbl *lpVtbl;
2689 struct if_count {
2690 REFIID id;
2691 LONG count;
2692 } *ifaces;
2693 LONG unknown;
2694 } IUnknownImpl;
2696 static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
2698 IUnknownImpl *This = (IUnknownImpl*)iunk;
2699 UINT i, found;
2700 for(i = found = 0; This->ifaces[i].id != NULL; i++)
2702 if(IsEqualIID(This->ifaces[i].id, riid))
2704 This->ifaces[i].count++;
2705 found = 1;
2706 break;
2709 if(!found)
2710 This->unknown++;
2711 return E_NOINTERFACE;
2714 static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
2716 return 2;
2719 static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
2721 return 1;
2724 const IUnknownVtbl vt_IUnknown = {
2725 unk_fnQueryInterface,
2726 unk_fnAddRef,
2727 unk_fnRelease
2730 static void test_SHGetIDListFromObject(void)
2732 IUnknownImpl *punkimpl;
2733 IShellFolder *psfdesktop;
2734 IShellView *psv;
2735 LPITEMIDLIST pidl, pidl_desktop;
2736 HRESULT hres;
2737 UINT i;
2738 struct if_count ifaces[] =
2739 { {&IID_IPersistIDList, 0},
2740 {&IID_IPersistFolder2, 0},
2741 {&IID_IDataObject, 0},
2742 {&IID_IParentAndItem, 0},
2743 {&IID_IFolderView, 0},
2744 {NULL, 0} };
2746 if(!pSHGetIDListFromObject)
2748 win_skip("SHGetIDListFromObject missing.\n");
2749 return;
2752 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2754 if(0)
2756 /* Crashes native */
2757 pSHGetIDListFromObject(NULL, NULL);
2758 pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
2761 hres = pSHGetIDListFromObject(NULL, &pidl);
2762 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2764 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
2765 punkimpl->lpVtbl = &vt_IUnknown;
2766 punkimpl->ifaces = ifaces;
2767 punkimpl->unknown = 0;
2769 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
2770 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2771 ok(ifaces[0].count, "interface not requested.\n");
2772 ok(ifaces[1].count, "interface not requested.\n");
2773 ok(ifaces[2].count, "interface not requested.\n");
2774 todo_wine
2775 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
2776 "interface not requested.\n");
2777 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
2778 "interface not requested.\n");
2780 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
2781 HeapFree(GetProcessHeap(), 0, punkimpl);
2783 pidl_desktop = NULL;
2784 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2785 ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
2787 SHGetDesktopFolder(&psfdesktop);
2789 /* Test IShellItem */
2790 if(pSHCreateShellItem)
2792 IShellItem *shellitem;
2793 hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2794 ok(hres == S_OK, "got 0x%08x\n", hres);
2795 if(SUCCEEDED(hres))
2797 hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
2798 ok(hres == S_OK, "got 0x%08x\n", hres);
2799 if(SUCCEEDED(hres))
2801 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2802 pILFree(pidl);
2804 IShellItem_Release(shellitem);
2807 else
2808 skip("no SHCreateShellItem.\n");
2810 /* Test IShellFolder */
2811 hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
2812 ok(hres == S_OK, "got 0x%08x\n", hres);
2813 if(SUCCEEDED(hres))
2815 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2816 pILFree(pidl);
2819 hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2820 ok(hres == S_OK, "got 0x%08x\n", hres);
2821 if(SUCCEEDED(hres))
2823 IEnumIDList *peidl;
2824 IDataObject *pdo;
2825 SHCONTF enum_flags;
2827 /* Test IFolderView */
2828 hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
2829 ok(hres == S_OK, "got 0x%08x\n", hres);
2830 if(SUCCEEDED(hres))
2832 ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
2833 pILFree(pidl);
2836 /* Test IDataObject */
2837 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2838 hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2839 ok(hres == S_OK, "got 0x%08x\n", hres);
2840 if(SUCCEEDED(hres))
2842 LPITEMIDLIST apidl[5];
2843 UINT count = 0;
2844 for(count = 0; count < 5; count++)
2845 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2846 break;
2848 if(count)
2850 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2851 &IID_IDataObject, NULL, (void**)&pdo);
2852 ok(hres == S_OK, "got 0x%08x\n", hres);
2853 if(SUCCEEDED(hres))
2855 pidl = (void*)0xDEADBEEF;
2856 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
2857 ok(hres == S_OK, "got 0x%08x\n", hres);
2858 ok(pidl != NULL, "pidl is NULL.\n");
2859 ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
2860 pILFree(pidl);
2862 IDataObject_Release(pdo);
2865 else
2866 skip("No files found - skipping single-file test.\n");
2868 if(count > 1)
2870 hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2871 &IID_IDataObject, NULL, (void**)&pdo);
2872 ok(hres == S_OK, "got 0x%08x\n", hres);
2873 if(SUCCEEDED(hres))
2875 pidl = (void*)0xDEADBEEF;
2876 hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
2877 ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
2878 "got 0x%08x\n", hres);
2879 ok(pidl == NULL, "pidl is not NULL.\n");
2881 IDataObject_Release(pdo);
2884 else
2885 skip("zero or one file found - skipping multi-file test.\n");
2887 for(i = 0; i < count; i++)
2888 pILFree(apidl[i]);
2890 IEnumIDList_Release(peidl);
2893 IShellView_Release(psv);
2896 IShellFolder_Release(psfdesktop);
2897 pILFree(pidl_desktop);
2900 static void test_SHGetItemFromObject(void)
2902 IUnknownImpl *punkimpl;
2903 IShellFolder *psfdesktop;
2904 LPITEMIDLIST pidl;
2905 IShellItem *psi;
2906 IUnknown *punk;
2907 HRESULT hres;
2908 struct if_count ifaces[] =
2909 { {&IID_IPersistIDList, 0},
2910 {&IID_IPersistFolder2, 0},
2911 {&IID_IDataObject, 0},
2912 {&IID_IParentAndItem, 0},
2913 {&IID_IFolderView, 0},
2914 {NULL, 0} };
2916 if(!pSHGetItemFromObject)
2918 skip("No SHGetItemFromObject.\n");
2919 return;
2922 SHGetDesktopFolder(&psfdesktop);
2924 if(0)
2926 /* Crashes with Windows 7 */
2927 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
2928 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
2929 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
2932 hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
2933 ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
2935 punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
2936 punkimpl->lpVtbl = &vt_IUnknown;
2937 punkimpl->ifaces = ifaces;
2938 punkimpl->unknown = 0;
2940 /* The same as SHGetIDListFromObject */
2941 hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
2942 ok(hres == E_NOINTERFACE, "Got %x\n", hres);
2943 ok(ifaces[0].count, "interface not requested.\n");
2944 ok(ifaces[1].count, "interface not requested.\n");
2945 ok(ifaces[2].count, "interface not requested.\n");
2946 todo_wine
2947 ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
2948 "interface not requested.\n");
2949 ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
2950 "interface not requested.\n");
2952 ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
2953 HeapFree(GetProcessHeap(), 0, punkimpl);
2955 /* Test IShellItem */
2956 hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
2957 ok(hres == S_OK, "Got 0x%08x\n", hres);
2958 if(SUCCEEDED(hres))
2960 IShellItem *psi2;
2961 hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
2962 ok(hres == S_OK, "Got 0x%08x\n", hres);
2963 if(SUCCEEDED(hres))
2965 todo_wine
2966 ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
2967 IShellItem_Release(psi2);
2969 IShellItem_Release(psi);
2972 IShellFolder_Release(psfdesktop);
2975 static void test_SHCreateShellItemArray(void)
2977 IShellFolder *pdesktopsf, *psf;
2978 IShellItemArray *psia;
2979 IEnumIDList *peidl;
2980 HRESULT hr;
2981 WCHAR cTestDirW[MAX_PATH];
2982 LPITEMIDLIST pidl_testdir, pidl;
2983 static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
2985 if(!pSHCreateShellItemArray) {
2986 skip("No pSHCreateShellItemArray!\n");
2987 return;
2990 ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
2992 if(0)
2994 /* Crashes under native */
2995 pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
2996 pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
2997 pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
2998 pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3001 hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3002 ok(hr == E_POINTER, "got 0x%08x\n", hr);
3004 SHGetDesktopFolder(&pdesktopsf);
3005 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3006 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3008 hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3009 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3011 pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
3012 hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3013 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3014 pILFree(pidl);
3016 GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3017 myPathAddBackslashW(cTestDirW);
3018 lstrcatW(cTestDirW, testdirW);
3020 CreateFilesFolders();
3022 hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3023 ok(hr == S_OK, "got 0x%08x\n", hr);
3024 if(SUCCEEDED(hr))
3026 hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3027 (void**)&psf);
3028 ok(hr == S_OK, "Got 0x%08x\n", hr);
3030 IShellFolder_Release(pdesktopsf);
3032 if(FAILED(hr))
3034 skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3035 pILFree(pidl_testdir);
3036 Cleanup();
3037 return;
3040 hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3041 ok(hr == S_OK, "Got %08x\n", hr);
3042 if(SUCCEEDED(hr))
3044 LPITEMIDLIST apidl[5];
3045 UINT done, numitems, i;
3047 for(done = 0; done < 5; done++)
3048 if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3049 break;
3050 ok(done == 5, "Got %d pidls\n", done);
3051 IEnumIDList_Release(peidl);
3053 /* Create a ShellItemArray */
3054 hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3055 ok(hr == S_OK, "Got 0x%08x\n", hr);
3056 if(SUCCEEDED(hr))
3058 IShellItem *psi;
3060 if(0)
3062 /* Crashes in Windows 7 */
3063 hr = IShellItemArray_GetCount(psia, NULL);
3066 IShellItemArray_GetCount(psia, &numitems);
3067 ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3069 hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3070 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3072 /* Compare all the items */
3073 for(i = 0; i < numitems; i++)
3075 LPITEMIDLIST pidl_abs;
3076 pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3078 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3079 ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3080 if(SUCCEEDED(hr))
3082 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3083 ok(hr == S_OK, "Got 0x%08x\n", hr);
3084 if(SUCCEEDED(hr))
3086 ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3087 pILFree(pidl);
3089 IShellItem_Release(psi);
3091 pILFree(pidl_abs);
3093 for(i = 0; i < done; i++)
3094 pILFree(apidl[i]);
3095 IShellItemArray_Release(psia);
3099 /* SHCreateShellItemArrayFromShellItem */
3100 if(pSHCreateShellItemArrayFromShellItem)
3102 IShellItem *psi;
3104 if(0)
3106 /* Crashes under Windows 7 */
3107 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3108 hr = pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3109 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3112 hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3113 ok(hr == S_OK, "Got 0x%08x\n", hr);
3114 if(SUCCEEDED(hr))
3116 hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3117 ok(hr == S_OK, "Got 0x%08x\n", hr);
3118 if(SUCCEEDED(hr))
3120 IShellItem *psi2;
3121 UINT count;
3122 hr = IShellItemArray_GetCount(psia, &count);
3123 ok(hr == S_OK, "Got 0x%08x\n", hr);
3124 ok(count == 1, "Got count %d\n", count);
3125 hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3126 ok(hr == S_OK, "Got 0x%08x\n", hr);
3127 todo_wine
3128 ok(psi != psi2, "ShellItems are of the same instance.\n");
3129 if(SUCCEEDED(hr))
3131 LPITEMIDLIST pidl1, pidl2;
3132 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3133 ok(hr == S_OK, "Got 0x%08x\n", hr);
3134 ok(pidl1 != NULL, "pidl1 was null.\n");
3135 hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3136 ok(hr == S_OK, "Got 0x%08x\n", hr);
3137 ok(pidl2 != NULL, "pidl2 was null.\n");
3138 ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3139 pILFree(pidl1);
3140 pILFree(pidl2);
3141 IShellItem_Release(psi2);
3143 hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3144 ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3145 IShellItemArray_Release(psia);
3147 IShellItem_Release(psi);
3150 else
3151 skip("No SHCreateShellItemArrayFromShellItem.\n");
3153 if(pSHCreateShellItemArrayFromDataObject)
3155 IShellView *psv;
3157 if(0)
3159 /* Crashes under Windows 7 */
3160 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3162 hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3163 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3165 hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3166 ok(hr == S_OK, "got 0x%08x\n", hr);
3167 if(SUCCEEDED(hr))
3169 IEnumIDList *peidl;
3170 IDataObject *pdo;
3171 SHCONTF enum_flags;
3173 enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3174 hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3175 ok(hr == S_OK, "got 0x%08x\n", hr);
3176 if(SUCCEEDED(hr))
3178 LPITEMIDLIST apidl[5];
3179 UINT count, i;
3181 for(count = 0; count < 5; count++)
3182 if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3183 break;
3184 ok(count == 5, "Got %d\n", count);
3186 if(count)
3188 hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3189 &IID_IDataObject, NULL, (void**)&pdo);
3190 ok(hr == S_OK, "Got 0x%08x\n", hr);
3191 if(SUCCEEDED(hr))
3193 hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3194 (void**)&psia);
3195 ok(hr == S_OK, "Got 0x%08x\n", hr);
3196 if(SUCCEEDED(hr))
3198 UINT count_sia, i;
3199 hr = IShellItemArray_GetCount(psia, &count_sia);
3200 ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3201 for(i = 0; i < count_sia; i++)
3203 LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3204 IShellItem *psi;
3205 hr = IShellItemArray_GetItemAt(psia, i, &psi);
3206 ok(hr == S_OK, "Got 0x%08x\n", hr);
3207 if(SUCCEEDED(hr))
3209 LPITEMIDLIST pidl;
3210 hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3211 ok(hr == S_OK, "Got 0x%08x\n", hr);
3212 ok(pidl != NULL, "pidl as NULL.\n");
3213 ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3214 pILFree(pidl);
3215 IShellItem_Release(psi);
3217 pILFree(pidl_abs);
3220 IShellItemArray_Release(psia);
3223 IDataObject_Release(pdo);
3225 for(i = 0; i < count; i++)
3226 pILFree(apidl[i]);
3228 else
3229 skip("No files found - skipping test.\n");
3231 IEnumIDList_Release(peidl);
3233 IShellView_Release(psv);
3236 else
3237 skip("No SHCreateShellItemArrayFromDataObject.\n");
3239 IShellFolder_Release(psf);
3240 pILFree(pidl_testdir);
3241 Cleanup();
3244 static void test_ShellItemBindToHandler(void)
3246 IShellItem *psi;
3247 LPITEMIDLIST pidl_desktop;
3248 HRESULT hr;
3250 if(!pSHCreateShellItem)
3252 skip("SHCreateShellItem missing.\n");
3253 return;
3256 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
3257 ok(hr == S_OK, "Got 0x%08x\n", hr);
3258 if(SUCCEEDED(hr))
3260 hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
3261 ok(hr == S_OK, "Got 0x%08x\n", hr);
3263 if(SUCCEEDED(hr))
3265 IPersistFolder2 *ppf2;
3266 IUnknown *punk;
3268 if(0)
3270 /* Crashes under Windows 7 */
3271 hr = IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
3272 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
3274 hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
3275 ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
3277 /* BHID_SFObject */
3278 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
3279 ok(hr == S_OK, "Got 0x%08x\n", hr);
3280 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3281 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
3282 ok(hr == S_OK, "Got 0x%08x\n", hr);
3283 if(SUCCEEDED(hr))
3285 LPITEMIDLIST pidl_tmp;
3286 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
3287 ok(hr == S_OK, "Got 0x%08x\n", hr);
3288 if(SUCCEEDED(hr))
3290 ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
3291 pILFree(pidl_tmp);
3293 IPersistFolder2_Release(ppf2);
3296 /* BHID_SFUIObject */
3297 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
3298 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3299 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3300 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
3301 ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
3302 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3304 /* BHID_DataObject */
3305 hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
3306 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3307 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3309 todo_wine
3311 /* BHID_SFViewObject */
3312 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
3313 ok(hr == S_OK, "Got 0x%08x\n", hr);
3314 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3315 hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
3316 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3317 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3319 /* BHID_Storage */
3320 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
3321 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3322 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3323 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
3324 ok(hr == S_OK, "Got 0x%08x\n", hr);
3325 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3327 /* BHID_Stream */
3328 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
3329 ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
3330 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3331 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
3332 ok(hr == S_OK, "Got 0x%08x\n", hr);
3333 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3335 /* BHID_StorageEnum */
3336 hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
3337 ok(hr == S_OK, "Got 0x%08x\n", hr);
3338 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3340 /* BHID_Transfer */
3341 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
3342 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3343 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3345 /* BHID_EnumItems */
3346 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
3347 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3348 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3350 /* BHID_Filter */
3351 hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
3352 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3353 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3355 /* BHID_LinkTargetItem */
3356 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
3357 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3358 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3359 hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
3360 ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
3361 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3363 /* BHID_PropertyStore */
3364 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
3365 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3366 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3367 hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
3368 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3369 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3371 /* BHID_ThumbnailHandler */
3372 hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
3373 ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3374 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3376 /* BHID_AssociationArray */
3377 hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
3378 ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3379 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3381 /* BHID_EnumAssocHandlers */
3382 hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
3383 ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
3384 if(SUCCEEDED(hr)) IUnknown_Release(punk);
3387 IShellItem_Release(psi);
3389 else
3390 skip("Failed to create ShellItem.\n");
3392 pILFree(pidl_desktop);
3395 static void test_SHParseDisplayName(void)
3397 LPITEMIDLIST pidl1, pidl2;
3398 IShellFolder *desktop;
3399 WCHAR dirW[MAX_PATH];
3400 WCHAR nameW[10];
3401 HRESULT hr;
3402 BOOL ret;
3404 if (!pSHParseDisplayName)
3406 win_skip("SHParseDisplayName isn't available\n");
3407 return;
3410 if (0)
3412 /* crashes on native */
3413 hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
3414 nameW[0] = 0;
3415 hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
3418 pidl1 = (LPITEMIDLIST)0xdeadbeef;
3419 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
3420 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
3421 hr == E_INVALIDARG, "failed %08x\n", hr);
3422 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
3424 /* dummy name */
3425 nameW[0] = 0;
3426 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
3427 ok(hr == S_OK, "failed %08x\n", hr);
3428 hr = SHGetDesktopFolder(&desktop);
3429 ok(hr == S_OK, "failed %08x\n", hr);
3430 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
3431 ok(hr == S_OK, "failed %08x\n", hr);
3432 ret = pILIsEqual(pidl1, pidl2);
3433 ok(ret == TRUE, "expected equal idls\n");
3434 pILFree(pidl1);
3435 pILFree(pidl2);
3437 /* with path */
3438 GetWindowsDirectoryW( dirW, MAX_PATH );
3440 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
3441 ok(hr == S_OK, "failed %08x\n", hr);
3442 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
3443 ok(hr == S_OK, "failed %08x\n", hr);
3445 ret = pILIsEqual(pidl1, pidl2);
3446 ok(ret == TRUE, "expected equal idls\n");
3447 pILFree(pidl1);
3448 pILFree(pidl2);
3450 IShellFolder_Release(desktop);
3453 static void test_desktop_IPersist(void)
3455 IShellFolder *desktop;
3456 IPersist *persist;
3457 IPersistFolder2 *ppf2;
3458 CLSID clsid;
3459 HRESULT hr;
3461 hr = SHGetDesktopFolder(&desktop);
3462 ok(hr == S_OK, "failed %08x\n", hr);
3464 hr = IShellFolder_QueryInterface(desktop, &IID_IPersist, (void**)&persist);
3465 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* NT4, W9X */, "failed %08x\n", hr);
3467 if (hr == S_OK)
3469 if (0)
3471 /* crashes on native */
3472 hr = IPersist_GetClassID(persist, NULL);
3474 memset(&clsid, 0, sizeof(clsid));
3475 hr = IPersist_GetClassID(persist, &clsid);
3476 ok(hr == S_OK, "failed %08x\n", hr);
3477 ok(IsEqualIID(&CLSID_ShellDesktop, &clsid), "Expected CLSID_ShellDesktop\n");
3478 IPersist_Release(persist);
3481 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
3482 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
3483 if(SUCCEEDED(hr))
3485 IPersistFolder *ppf;
3486 LPITEMIDLIST pidl;
3487 hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
3488 ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
3489 if(SUCCEEDED(hr))
3490 IPersistFolder_Release(ppf);
3492 todo_wine {
3493 hr = IPersistFolder2_Initialize(ppf2, NULL);
3494 ok(hr == S_OK, "got %08x\n", hr);
3497 pidl = NULL;
3498 hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
3499 ok(hr == S_OK, "got %08x\n", hr);
3500 ok(pidl != NULL, "pidl was NULL.\n");
3501 if(SUCCEEDED(hr)) pILFree(pidl);
3503 IPersistFolder2_Release(ppf2);
3506 IShellFolder_Release(desktop);
3509 static void test_GetUIObject(void)
3511 IShellFolder *psf_desktop;
3512 IContextMenu *pcm;
3513 LPITEMIDLIST pidl;
3514 HRESULT hr;
3515 WCHAR path[MAX_PATH];
3516 const WCHAR filename[] =
3517 {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
3519 if(!pSHBindToParent)
3521 win_skip("SHBindToParent missing.\n");
3522 return;
3525 GetCurrentDirectoryW(MAX_PATH, path);
3526 if(!lstrlenW(path))
3528 skip("GetCurrentDirectoryW returned an empty string.\n");
3529 return;
3531 lstrcatW(path, filename);
3532 SHGetDesktopFolder(&psf_desktop);
3534 CreateFilesFolders();
3536 hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
3537 ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
3538 if(SUCCEEDED(hr))
3540 IShellFolder *psf;
3541 LPCITEMIDLIST pidl_child;
3542 hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
3543 ok(hr == S_OK, "Got 0x%08x\n", hr);
3544 if(SUCCEEDED(hr))
3546 hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, (LPCITEMIDLIST*)&pidl_child,
3547 &IID_IContextMenu, NULL, (void**)&pcm);
3548 ok(hr == S_OK, "Got 0x%08x\n", hr);
3549 if(SUCCEEDED(hr))
3551 HMENU hmenu = CreatePopupMenu();
3552 INT max_id, max_id_check;
3553 UINT count, i;
3554 const int id_upper_limit = 32767;
3555 hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
3556 ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
3557 max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
3558 ok(max_id <= id_upper_limit, "Got %d\n", max_id);
3559 count = GetMenuItemCount(hmenu);
3560 ok(count, "Got %d\n", count);
3562 max_id_check = 0;
3563 for(i = 0; i < count; i++)
3565 MENUITEMINFOA mii;
3566 INT res;
3567 ZeroMemory(&mii, sizeof(MENUITEMINFOA));
3568 mii.cbSize = sizeof(MENUITEMINFOA);
3569 mii.fMask = MIIM_ID | MIIM_FTYPE;
3571 SetLastError(0);
3572 res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
3573 ok(res, "Failed (last error: %d).\n", GetLastError());
3575 ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
3576 "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
3577 if(!(mii.fType & MFT_SEPARATOR))
3578 max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
3580 ok((max_id_check == max_id) ||
3581 (max_id_check == max_id-1 /* Win 7 */),
3582 "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
3584 #define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
3586 if(count && !is_win2k()) /* Test is interactive on w2k, so skip */
3588 CMINVOKECOMMANDINFO cmi;
3589 ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
3590 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3592 /* Attempt to execute a nonexistent command */
3593 cmi.lpVerb = MAKEINTRESOURCEA(9999);
3594 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3595 ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3597 cmi.lpVerb = "foobar_wine_test";
3598 hr = IContextMenu_InvokeCommand(pcm, &cmi);
3599 ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
3600 (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
3601 "Got 0x%08x\n", hr);
3603 #undef is_win2k
3605 DestroyMenu(hmenu);
3606 IContextMenu_Release(pcm);
3608 IShellFolder_Release(psf);
3610 if(pILFree) pILFree(pidl);
3613 IShellFolder_Release(psf_desktop);
3614 Cleanup();
3617 #define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
3618 static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
3620 LPCITEMIDLIST child;
3621 IShellFolder *parent;
3622 STRRET filename;
3623 HRESULT hr;
3625 if(!pSHBindToParent){
3626 win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
3627 if(path)
3628 ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
3629 else
3630 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3631 return;
3634 if(path){
3635 if(!pidl){
3636 ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
3637 return;
3640 hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
3641 ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
3642 if(FAILED(hr))
3643 return;
3645 hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
3646 ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
3647 if(FAILED(hr)){
3648 IShellFolder_Release(parent);
3649 return;
3652 ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
3653 "Got unexpected string type: %d\n", filename.uType);
3654 if(filename.uType == STRRET_WSTR){
3655 ok_(__FILE__,l)(lstrcmpW(path, filename.pOleStr) == 0,
3656 "didn't get expected path (%s), instead: %s\n",
3657 wine_dbgstr_w(path), wine_dbgstr_w(filename.pOleStr));
3658 }else if(filename.uType == STRRET_CSTR){
3659 ok_(__FILE__,l)(strcmp_wa(path, filename.cStr) == 0,
3660 "didn't get expected path (%s), instead: %s\n",
3661 wine_dbgstr_w(path), filename.cStr);
3664 IShellFolder_Release(parent);
3665 }else
3666 ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
3669 static void test_SHSimpleIDListFromPath(void)
3671 const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
3672 const CHAR adirA[] = "C:\\sidlfpdir";
3673 BOOL br, is_unicode = !(GetVersion() & 0x80000000);
3675 LPITEMIDLIST pidl = NULL;
3677 if(!pSHSimpleIDListFromPathAW){
3678 win_skip("SHSimpleIDListFromPathAW not available\n");
3679 return;
3682 br = CreateDirectoryA(adirA, NULL);
3683 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3685 if(is_unicode)
3686 pidl = pSHSimpleIDListFromPathAW(adirW);
3687 else
3688 pidl = pSHSimpleIDListFromPathAW(adirA);
3689 verify_pidl(pidl, adirW);
3690 pILFree(pidl);
3692 br = RemoveDirectoryA(adirA);
3693 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
3695 if(is_unicode)
3696 pidl = pSHSimpleIDListFromPathAW(adirW);
3697 else
3698 pidl = pSHSimpleIDListFromPathAW(adirA);
3699 verify_pidl(pidl, adirW);
3700 pILFree(pidl);
3703 /* IFileSystemBindData impl */
3704 static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
3705 REFIID riid, void **ppv)
3707 if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
3708 IsEqualIID(riid, &IID_IUnknown)){
3709 *ppv = fsbd;
3710 return S_OK;
3712 return E_NOINTERFACE;
3715 static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
3717 return 2;
3720 static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
3722 return 1;
3725 static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
3726 const WIN32_FIND_DATAW *pfd)
3728 ok(0, "SetFindData called\n");
3729 return E_NOTIMPL;
3732 static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
3733 WIN32_FIND_DATAW *pfd)
3735 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3736 return S_OK;
3739 static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
3740 WIN32_FIND_DATAW *pfd)
3742 memset(pfd, 0xdeadbeef, sizeof(WIN32_FIND_DATAW));
3743 return S_OK;
3746 static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
3747 WIN32_FIND_DATAW *pfd)
3749 memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
3750 *pfd->cFileName = 'a';
3751 *pfd->cAlternateFileName = 'a';
3752 return S_OK;
3755 static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
3756 WIN32_FIND_DATAW *pfd)
3758 static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
3759 HANDLE handle = FindFirstFileW(adirW, pfd);
3760 FindClose(handle);
3761 return S_OK;
3764 static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
3765 WIN32_FIND_DATAW *pfd)
3767 return E_FAIL;
3770 static IFileSystemBindDataVtbl fsbdVtbl = {
3771 fsbd_QueryInterface,
3772 fsbd_AddRef,
3773 fsbd_Release,
3774 fsbd_SetFindData,
3775 NULL
3778 static IFileSystemBindData fsbd = { &fsbdVtbl };
3780 static void test_ParseDisplayNamePBC(void)
3782 WCHAR wFileSystemBindData[] =
3783 {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
3784 WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
3785 const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
3787 IShellFolder *psf;
3788 IBindCtx *pbc;
3789 HRESULT hres;
3790 ITEMIDLIST *pidl;
3792 /* Check if we support WCHAR functions */
3793 SetLastError(0xdeadbeef);
3794 lstrcmpiW(adirW, adirW);
3795 if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
3796 win_skip("Most W-calls are not implemented\n");
3797 return;
3800 hres = SHGetDesktopFolder(&psf);
3801 ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
3802 if(FAILED(hres)){
3803 win_skip("Failed to get IShellFolder, can't run tests\n");
3804 return;
3807 /* fails on unknown dir with no IBindCtx */
3808 hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
3809 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
3810 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
3812 /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
3813 hres = CreateBindCtx(0, &pbc);
3814 ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
3816 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3817 ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
3818 "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
3820 /* unknown dir with IBindCtx with IFileSystemBindData */
3821 hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
3822 ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
3824 /* return E_FAIL from GetFindData */
3825 pidl = (ITEMIDLIST*)0xdeadbeef;
3826 fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
3827 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3828 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3829 "ParseDisplayName failed: 0x%08x\n", hres);
3830 if(SUCCEEDED(hres)){
3831 verify_pidl(pidl, adirW);
3832 ILFree(pidl);
3835 /* set FIND_DATA struct to NULLs */
3836 pidl = (ITEMIDLIST*)0xdeadbeef;
3837 fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
3838 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3839 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3840 "ParseDisplayName failed: 0x%08x\n", hres);
3841 if(SUCCEEDED(hres)){
3842 verify_pidl(pidl, adirW);
3843 ILFree(pidl);
3846 /* set FIND_DATA struct to junk */
3847 pidl = (ITEMIDLIST*)0xdeadbeef;
3848 fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
3849 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3850 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3851 "ParseDisplayName failed: 0x%08x\n", hres);
3852 if(SUCCEEDED(hres)){
3853 verify_pidl(pidl, adirW);
3854 ILFree(pidl);
3857 /* set FIND_DATA struct to invalid data */
3858 pidl = (ITEMIDLIST*)0xdeadbeef;
3859 fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
3860 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3861 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3862 "ParseDisplayName failed: 0x%08x\n", hres);
3863 if(SUCCEEDED(hres)){
3864 verify_pidl(pidl, adirW);
3865 ILFree(pidl);
3868 /* set FIND_DATA struct to valid data */
3869 pidl = (ITEMIDLIST*)0xdeadbeef;
3870 fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
3871 hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
3872 ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
3873 "ParseDisplayName failed: 0x%08x\n", hres);
3874 if(SUCCEEDED(hres)){
3875 verify_pidl(pidl, adirW);
3876 ILFree(pidl);
3879 IBindCtx_Release(pbc);
3880 IShellFolder_Release(psf);
3883 static const CHAR testwindow_class[] = "testwindow";
3884 #define WM_USER_NOTIFY (WM_APP+1)
3886 static struct {
3887 const char *id;
3888 BOOL exp_notify;
3889 UINT signal;
3890 const WCHAR *path_1;
3891 const WCHAR *path_2;
3892 } exp_data;
3894 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
3896 UINT signal = (UINT)lparam;
3898 switch(msg){
3899 case WM_USER_NOTIFY:
3900 if(exp_data.exp_notify){
3901 LPCITEMIDLIST *pidls = (LPCITEMIDLIST*)wparam;
3903 ok(exp_data.signal == signal,
3904 "%s: expected notification type %x, got: %x\n",
3905 exp_data.id, exp_data.signal, signal);
3907 trace("verifying pidls for: %s\n", exp_data.id);
3908 verify_pidl(pidls[0], exp_data.path_1);
3909 verify_pidl(pidls[1], exp_data.path_2);
3911 exp_data.exp_notify = FALSE;
3912 }else
3913 ok(exp_data.exp_notify, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
3914 return 0;
3916 return DefWindowProc(hwnd, msg, wparam, lparam);
3919 static void register_testwindow_class(void)
3921 WNDCLASSEXA cls;
3922 ATOM ret;
3924 ZeroMemory(&cls, sizeof(cls));
3925 cls.cbSize = sizeof(cls);
3926 cls.style = 0;
3927 cls.lpfnWndProc = testwindow_wndproc;
3928 cls.hInstance = GetModuleHandleA(NULL);
3929 cls.lpszClassName = testwindow_class;
3931 SetLastError(0);
3932 ret = RegisterClassExA(&cls);
3933 ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
3936 /* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
3937 * have to poll repeatedly for the message to appear */
3938 static void do_events(void)
3940 int c = 0;
3941 while (exp_data.exp_notify && (c++ < 10)){
3942 MSG msg;
3943 while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
3944 TranslateMessage(&msg);
3945 DispatchMessageA(&msg);
3947 if(exp_data.exp_notify)
3948 Sleep(500);
3950 trace("%s: took %d tries\n", exp_data.id, c);
3953 static void test_SHChangeNotify(void)
3955 HWND wnd;
3956 ULONG notifyID;
3957 HRESULT hr;
3958 BOOL br, has_unicode;
3959 SHChangeNotifyEntry entries[1];
3960 const CHAR root_dirA[] = "C:\\shell32_cn_test";
3961 const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
3962 const CHAR test_dirA[] = "C:\\shell32_cn_test\\test";
3963 const WCHAR test_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t','\\','t','e','s','t',0};
3965 CreateDirectoryW(NULL, NULL);
3966 has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
3968 /* set up the root directory & window */
3969 br = CreateDirectoryA(root_dirA, NULL);
3970 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3972 register_testwindow_class();
3974 wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
3975 CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
3976 NULL, NULL, GetModuleHandleA(NULL), 0);
3977 ok(wnd != NULL, "Failed to make a window\n");
3979 entries[0].pidl = NULL;
3980 if(has_unicode)
3981 hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
3982 else
3983 hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
3984 ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
3985 entries[0].fRecursive = TRUE;
3987 notifyID = SHChangeNotifyRegister(wnd, SHCNRF_ShellLevel,
3988 SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
3989 ok(notifyID != 0, "Failed to register a window for change notifications\n");
3991 /* MKDIR */
3992 br = CreateDirectoryA(test_dirA, NULL);
3993 ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
3995 if(has_unicode){
3996 exp_data.id = "MKDIR PATHW";
3997 exp_data.signal = SHCNE_MKDIR;
3998 exp_data.exp_notify = TRUE;
3999 exp_data.path_1 = test_dirW;
4000 exp_data.path_2 = NULL;
4001 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW | SHCNF_FLUSH, test_dirW, NULL);
4002 do_events();
4003 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4004 }else
4005 win_skip("skipping WCHAR tests\n");
4007 exp_data.id = "MKDIR PATHA";
4008 exp_data.signal = SHCNE_MKDIR;
4009 exp_data.exp_notify = TRUE;
4010 exp_data.path_1 = test_dirW;
4011 exp_data.path_2 = NULL;
4012 SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHA | SHCNF_FLUSH, test_dirA, NULL);
4013 do_events();
4014 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4016 /* RMDIR */
4017 br = RemoveDirectoryA(test_dirA);
4018 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4020 if(has_unicode){
4021 exp_data.id = "RMDIR PATHW";
4022 exp_data.signal = SHCNE_RMDIR;
4023 exp_data.exp_notify = TRUE;
4024 exp_data.path_1 = test_dirW;
4025 exp_data.path_2 = NULL;
4026 SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW | SHCNF_FLUSH, test_dirW, NULL);
4027 do_events();
4028 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4029 }else
4030 win_skip("skipping WCHAR tests\n");
4032 exp_data.id = "RMDIR PATHA";
4033 exp_data.signal = SHCNE_RMDIR;
4034 exp_data.exp_notify = TRUE;
4035 exp_data.path_1 = test_dirW;
4036 exp_data.path_2 = NULL;
4037 SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHA | SHCNF_FLUSH, test_dirA, NULL);
4038 do_events();
4039 ok(exp_data.exp_notify == FALSE, "Expected wndproc to be called\n");
4041 SHChangeNotifyDeregister(notifyID);
4042 DestroyWindow(wnd);
4044 br = RemoveDirectoryA(root_dirA);
4045 ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
4048 START_TEST(shlfolder)
4050 init_function_pointers();
4051 /* if OleInitialize doesn't get called, ParseDisplayName returns
4052 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
4053 OleInitialize(NULL);
4055 test_ParseDisplayName();
4056 test_SHParseDisplayName();
4057 test_BindToObject();
4058 test_EnumObjects_and_CompareIDs();
4059 test_GetDisplayName();
4060 test_GetAttributesOf();
4061 test_SHGetPathFromIDList();
4062 test_CallForAttributes();
4063 test_FolderShortcut();
4064 test_ITEMIDLIST_format();
4065 test_SHGetFolderPathAndSubDirA();
4066 test_LocalizedNames();
4067 test_SHCreateShellItem();
4068 test_SHCreateShellItemArray();
4069 test_desktop_IPersist();
4070 test_GetUIObject();
4071 test_SHSimpleIDListFromPath();
4072 test_ParseDisplayNamePBC();
4073 test_SHGetNameFromIDList();
4074 test_SHGetItemFromDataObject();
4075 test_SHGetIDListFromObject();
4076 test_SHGetItemFromObject();
4077 test_ShellItemCompare();
4078 test_SHChangeNotify();
4079 test_ShellItemBindToHandler();
4081 OleUninitialize();