push 6e61d6ca5bcaf95ac09a664b4ba4f88238c927be
[wine/hacks.git] / dlls / shell32 / tests / shlfolder.c
blobbce7c3ebe441c016572e7877fe57ae08b4e749a7
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"
43 static IMalloc *ppM;
45 static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEMIDLIST*);
46 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
47 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
48 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
49 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
50 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
51 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
52 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
53 static void (WINAPI *pILFree)(LPITEMIDLIST);
54 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
55 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
56 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
57 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
59 static void init_function_pointers(void)
61 HMODULE hmod;
62 HRESULT hr;
64 hmod = GetModuleHandleA("shell32.dll");
66 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
67 MAKEFUNC(SHBindToParent);
68 MAKEFUNC(SHCreateShellItem);
69 MAKEFUNC(SHGetFolderPathA);
70 MAKEFUNC(SHGetFolderPathAndSubDirA);
71 MAKEFUNC(SHGetPathFromIDListW);
72 MAKEFUNC(SHGetSpecialFolderPathA);
73 MAKEFUNC(SHGetSpecialFolderPathW);
74 MAKEFUNC(SHParseDisplayName);
75 #undef MAKEFUNC
77 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
78 MAKEFUNC_ORD(ILFindLastID, 16);
79 MAKEFUNC_ORD(ILIsEqual, 21);
80 MAKEFUNC_ORD(ILCombine, 25);
81 MAKEFUNC_ORD(ILFree, 155);
82 #undef MAKEFUNC_ORD
84 hmod = GetModuleHandleA("shlwapi.dll");
85 pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
87 hr = SHGetMalloc(&ppM);
88 ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
91 static void test_ParseDisplayName(void)
93 HRESULT hr;
94 IShellFolder *IDesktopFolder;
95 static const char *cNonExistDir1A = "c:\\nonexist_subdir";
96 static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
97 static const char *cInetTestA = "http:\\yyy";
98 static const char *cInetTest2A = "xx:yyy";
99 DWORD res;
100 WCHAR cTestDirW [MAX_PATH] = {0};
101 ITEMIDLIST *newPIDL;
102 BOOL bRes;
104 hr = SHGetDesktopFolder(&IDesktopFolder);
105 if(hr != S_OK) return;
107 /* Tests crash on W2K and below (SHCreateShellItem available as of XP) */
108 if (pSHCreateShellItem)
110 /* null name and pidl */
111 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
112 NULL, NULL, NULL, NULL, NULL, 0);
113 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
115 /* null name */
116 newPIDL = (ITEMIDLIST*)0xdeadbeef;
117 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
118 NULL, NULL, NULL, NULL, &newPIDL, 0);
119 ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
120 ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
122 else
123 win_skip("Tests would crash on W2K and below\n");
125 MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
126 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
127 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
128 todo_wine ok((SUCCEEDED(hr) || broken(hr == E_FAIL) /* NT4 */),
129 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
130 if (SUCCEEDED(hr))
132 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
133 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
134 IMalloc_Free(ppM, newPIDL);
137 MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
138 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
139 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
140 todo_wine ok((SUCCEEDED(hr) || broken(hr == E_FAIL) /* NT4 */),
141 "ParseDisplayName returned %08x, expected SUCCESS or E_FAIL\n", hr);
142 if (SUCCEEDED(hr))
144 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
145 "PT_IESPECIAL1, but is: %02x\n", pILFindLastID(newPIDL)->mkid.abID[0]);
146 IMalloc_Free(ppM, newPIDL);
149 res = GetFileAttributesA(cNonExistDir1A);
150 if(res != INVALID_FILE_ATTRIBUTES) return;
152 MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
153 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
154 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
155 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL),
156 "ParseDisplayName returned %08x, expected 80070002 or E_FAIL\n", hr);
158 res = GetFileAttributesA(cNonExistDir2A);
159 if(res != INVALID_FILE_ATTRIBUTES) return;
161 MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
162 hr = IShellFolder_ParseDisplayName(IDesktopFolder,
163 NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
164 ok((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == E_FAIL) || (hr == E_INVALIDARG),
165 "ParseDisplayName returned %08x, expected 80070002, E_FAIL or E_INVALIDARG\n", hr);
167 /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
168 * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
169 * out it doesn't. The magic seems to happen in the file dialogs, then. */
170 if (!pSHGetSpecialFolderPathW || !pILFindLastID) goto finished;
172 bRes = pSHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
173 ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
174 if (!bRes) goto finished;
176 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
177 ok(SUCCEEDED(hr), "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
178 if (FAILED(hr)) goto finished;
180 ok(pILFindLastID(newPIDL)->mkid.abID[0] == 0x31 ||
181 pILFindLastID(newPIDL)->mkid.abID[0] == 0xb1, /* Win98 */
182 "Last pidl should be of type PT_FOLDER or PT_IESPECIAL2, but is: %02x\n",
183 pILFindLastID(newPIDL)->mkid.abID[0]);
184 IMalloc_Free(ppM, newPIDL);
186 finished:
187 IShellFolder_Release(IDesktopFolder);
190 /* creates a file with the specified name for tests */
191 static void CreateTestFile(const CHAR *name)
193 HANDLE file;
194 DWORD written;
196 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
197 if (file != INVALID_HANDLE_VALUE)
199 WriteFile(file, name, strlen(name), &written, NULL);
200 WriteFile(file, "\n", strlen("\n"), &written, NULL);
201 CloseHandle(file);
206 /* initializes the tests */
207 static void CreateFilesFolders(void)
209 CreateDirectoryA(".\\testdir", NULL);
210 CreateDirectoryA(".\\testdir\\test.txt", NULL);
211 CreateTestFile (".\\testdir\\test1.txt ");
212 CreateTestFile (".\\testdir\\test2.txt ");
213 CreateTestFile (".\\testdir\\test3.txt ");
214 CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
215 CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
218 /* cleans after tests */
219 static void Cleanup(void)
221 DeleteFileA(".\\testdir\\test1.txt");
222 DeleteFileA(".\\testdir\\test2.txt");
223 DeleteFileA(".\\testdir\\test3.txt");
224 RemoveDirectoryA(".\\testdir\\test.txt");
225 RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
226 RemoveDirectoryA(".\\testdir\\testdir2");
227 RemoveDirectoryA(".\\testdir");
231 /* perform test */
232 static void test_EnumObjects(IShellFolder *iFolder)
234 IEnumIDList *iEnumList;
235 LPITEMIDLIST newPIDL, idlArr[10];
236 ULONG NumPIDLs;
237 int i=0, j;
238 HRESULT hr;
240 static const WORD iResults [5][5] =
242 { 0,-1,-1,-1,-1},
243 { 1, 0,-1,-1,-1},
244 { 1, 1, 0,-1,-1},
245 { 1, 1, 1, 0,-1},
246 { 1, 1, 1, 1, 0}
249 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
250 /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
251 static const ULONG attrs[5] =
253 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
254 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
255 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
256 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
257 SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
260 hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
261 ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
263 /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
264 * the filesystem shellfolders return S_OK even if less than 'celt' items are
265 * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
266 * only ever returns a single entry per call. */
267 while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
268 i += NumPIDLs;
269 ok (i == 5, "i: %d\n", i);
271 hr = IEnumIDList_Release(iEnumList);
272 ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
274 /* Sort them first in case of wrong order from system */
275 for (i=0;i<5;i++) for (j=0;j<5;j++)
276 if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
278 newPIDL = idlArr[i];
279 idlArr[i] = idlArr[j];
280 idlArr[j] = newPIDL;
283 for (i=0;i<5;i++) for (j=0;j<5;j++)
285 hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
286 ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
290 for (i = 0; i < 5; i++)
292 SFGAOF flags;
293 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
294 /* Native returns all flags no matter what we ask for */
295 flags = SFGAO_CANCOPY;
296 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
297 flags &= SFGAO_testfor;
298 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
299 ok(flags == (attrs[i]) ||
300 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR) || /* Win9x, NT4 */
301 flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
302 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
304 flags = SFGAO_testfor;
305 hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
306 flags &= SFGAO_testfor;
307 ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
308 ok(flags == attrs[i] ||
309 flags == (attrs[i] & ~SFGAO_FILESYSANCESTOR), /* Win9x, NT4 */
310 "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
313 for (i=0;i<5;i++)
314 IMalloc_Free(ppM, idlArr[i]);
317 static void test_BindToObject(void)
319 HRESULT hr;
320 UINT cChars;
321 IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
322 SHITEMID emptyitem = { 0, { 0 } };
323 LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
324 WCHAR wszSystemDir[MAX_PATH];
325 char szSystemDir[MAX_PATH];
326 WCHAR wszMyComputer[] = {
327 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
328 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
330 /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
331 * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
333 hr = SHGetDesktopFolder(&psfDesktop);
334 ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
335 if (FAILED(hr)) return;
337 hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
338 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
340 hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
341 ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
343 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
344 ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
345 if (FAILED(hr)) {
346 IShellFolder_Release(psfDesktop);
347 return;
350 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
351 ok (SUCCEEDED(hr), "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
352 IShellFolder_Release(psfDesktop);
353 IMalloc_Free(ppM, pidlMyComputer);
354 if (FAILED(hr)) return;
356 hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
357 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
359 if (0)
361 /* this call segfaults on 98SE */
362 hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
363 ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
366 cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
367 ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
368 if (cChars == 0 || cChars >= MAX_PATH) {
369 IShellFolder_Release(psfMyComputer);
370 return;
372 MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
374 hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
375 ok (SUCCEEDED(hr), "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
376 if (FAILED(hr)) {
377 IShellFolder_Release(psfMyComputer);
378 return;
381 hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
382 ok (SUCCEEDED(hr), "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
383 IShellFolder_Release(psfMyComputer);
384 IMalloc_Free(ppM, pidlSystemDir);
385 if (FAILED(hr)) return;
387 hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
388 ok (hr == E_INVALIDARG,
389 "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
391 if (0)
393 /* this call segfaults on 98SE */
394 hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
395 ok (hr == E_INVALIDARG,
396 "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
399 IShellFolder_Release(psfSystemDir);
402 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
403 static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
405 size_t iLen;
407 if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
408 return NULL;
410 if (iLen)
412 lpszPath += iLen;
413 if (lpszPath[-1] != '\\')
415 *lpszPath++ = '\\';
416 *lpszPath = '\0';
419 return lpszPath;
422 static void test_GetDisplayName(void)
424 BOOL result;
425 HRESULT hr;
426 HANDLE hTestFile;
427 WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
428 char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
429 DWORD attr;
430 STRRET strret;
431 LPSHELLFOLDER psfDesktop, psfPersonal;
432 IUnknown *psfFile;
433 SHITEMID emptyitem = { 0, { 0 } };
434 LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
435 LPCITEMIDLIST pidlLast;
436 static const CHAR szFileName[] = "winetest.foo";
437 static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
438 static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
440 /* I'm trying to figure if there is a functional difference between calling
441 * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
442 * binding to the shellfolder. One thing I thought of was that perhaps
443 * SHGetPathFromIDListW would be able to get the path to a file, which does
444 * not exist anymore, while the other method wouldn't. It turns out there's
445 * no functional difference in this respect.
448 if(!pSHGetSpecialFolderPathA) {
449 win_skip("SHGetSpecialFolderPathA is not available\n");
450 return;
453 /* First creating a directory in MyDocuments and a file in this directory. */
454 result = pSHGetSpecialFolderPathA(NULL, szTestDir, CSIDL_PERSONAL, FALSE);
455 ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
456 if (!result) return;
458 /* Use ANSI file functions so this works on Windows 9x */
459 lstrcatA(szTestDir, "\\winetest");
460 CreateDirectoryA(szTestDir, NULL);
461 attr=GetFileAttributesA(szTestDir);
462 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
464 ok(0, "unable to create the '%s' directory\n", szTestDir);
465 return;
468 lstrcpyA(szTestFile, szTestDir);
469 lstrcatA(szTestFile, "\\");
470 lstrcatA(szTestFile, szFileName);
471 hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
472 ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
473 if (hTestFile == INVALID_HANDLE_VALUE) return;
474 CloseHandle(hTestFile);
476 /* Getting an itemidlist for the file. */
477 hr = SHGetDesktopFolder(&psfDesktop);
478 ok(SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
479 if (FAILED(hr)) return;
481 MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
483 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
484 ok(SUCCEEDED(hr), "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
485 if (FAILED(hr)) {
486 IShellFolder_Release(psfDesktop);
487 return;
490 pidlLast = pILFindLastID(pidlTestFile);
491 ok(pidlLast->mkid.cb >=76 ||
492 broken(pidlLast->mkid.cb == 28) || /* W2K */
493 broken(pidlLast->mkid.cb == 40), /* Win9x, WinME */
494 "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
495 if (pidlLast->mkid.cb >= 28) {
496 ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
497 "Filename should be stored as ansi-string at this position!\n");
499 /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
500 if (pidlLast->mkid.cb >= 76) {
501 ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
502 (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
503 (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)), /* Win7 */
504 "Filename should be stored as wchar-string at this position!\n");
507 /* It seems as if we cannot bind to regular files on windows, but only directories.
509 hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
510 todo_wine
511 ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
512 hr == E_NOTIMPL || /* Vista */
513 broken(SUCCEEDED(hr)), /* Win9x, W2K */
514 "hr = %08x\n", hr);
515 if (SUCCEEDED(hr)) {
516 IShellFolder_Release(psfFile);
519 if (!pSHBindToParent)
521 win_skip("SHBindToParent is missing\n");
522 DeleteFileA(szTestFile);
523 RemoveDirectoryA(szTestDir);
524 return;
527 /* Some tests for IShellFolder::SetNameOf */
528 if (pSHGetFolderPathAndSubDirA)
530 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
531 ok(SUCCEEDED(hr), "SHBindToParent failed! hr = %08x\n", hr);
532 if (SUCCEEDED(hr)) {
533 /* It's ok to use this fixed path. Call will fail anyway. */
534 WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
535 LPITEMIDLIST pidlNew;
537 /* The pidl returned through the last parameter of SetNameOf is a simple one. */
538 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
539 ok (SUCCEEDED(hr), "SetNameOf failed! hr = %08x\n", hr);
540 if (hr == S_OK)
542 ok (((LPITEMIDLIST)((LPBYTE)pidlNew+pidlNew->mkid.cb))->mkid.cb == 0,
543 "pidl returned from SetNameOf should be simple!\n");
545 /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
546 * is implemented on top of SHFileOperation in WinXP. */
547 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename,
548 SHGDN_FORPARSING, NULL);
549 ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
551 /* Rename the file back to its original name. SetNameOf ignores the fact, that the
552 * SHGDN flags specify an absolute path. */
553 hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
554 ok (SUCCEEDED(hr), "SetNameOf failed! hr = %08x\n", hr);
556 pILFree(pidlNew);
559 IShellFolder_Release(psfPersonal);
562 else
563 win_skip("Avoid needs of interaction on Win2k\n");
565 /* Deleting the file and the directory */
566 DeleteFileA(szTestFile);
567 RemoveDirectoryA(szTestDir);
569 /* SHGetPathFromIDListW still works, although the file is not present anymore. */
570 if (pSHGetPathFromIDListW)
572 result = pSHGetPathFromIDListW(pidlTestFile, wszTestFile2);
573 ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
574 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
577 /* SHBindToParent fails, if called with a NULL PIDL. */
578 hr = pSHBindToParent(NULL, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
579 ok (FAILED(hr), "SHBindToParent(NULL) should fail!\n");
581 /* But it succeeds with an empty PIDL. */
582 hr = pSHBindToParent(pidlEmpty, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
583 ok (SUCCEEDED(hr), "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
584 ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
585 if (SUCCEEDED(hr))
586 IShellFolder_Release(psfPersonal);
588 /* Binding to the folder and querying the display name of the file also works. */
589 hr = pSHBindToParent(pidlTestFile, &IID_IShellFolder, (VOID**)&psfPersonal, &pidlLast);
590 ok (SUCCEEDED(hr), "SHBindToParent failed! hr = %08x\n", hr);
591 if (FAILED(hr)) {
592 IShellFolder_Release(psfDesktop);
593 return;
596 /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
597 * pidlTestFile (In accordance with MSDN). */
598 ok (pILFindLastID(pidlTestFile) == pidlLast,
599 "SHBindToParent doesn't return the last id of the pidl param!\n");
601 hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
602 ok (SUCCEEDED(hr), "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
603 if (FAILED(hr)) {
604 IShellFolder_Release(psfDesktop);
605 IShellFolder_Release(psfPersonal);
606 return;
609 if (pStrRetToBufW)
611 hr = pStrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
612 ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr);
613 ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
616 ILFree(pidlTestFile);
617 IShellFolder_Release(psfDesktop);
618 IShellFolder_Release(psfPersonal);
621 static void test_CallForAttributes(void)
623 HKEY hKey;
624 LONG lResult;
625 HRESULT hr;
626 DWORD dwSize;
627 LPSHELLFOLDER psfDesktop;
628 LPITEMIDLIST pidlMyDocuments;
629 DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
630 static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
631 static const WCHAR wszCallForAttributes[] = {
632 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
633 static const WCHAR wszMyDocumentsKey[] = {
634 'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
635 '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
636 '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
637 WCHAR wszMyDocuments[] = {
638 ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
639 '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
641 /* For the root of a namespace extension, the attributes are not queried by binding
642 * to the object and calling GetAttributesOf. Instead, the attributes are read from
643 * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
645 * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
646 * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
647 * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
648 * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
650 hr = SHGetDesktopFolder(&psfDesktop);
651 ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
652 if (FAILED(hr)) return;
654 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
655 &pidlMyDocuments, NULL);
656 ok (SUCCEEDED(hr) ||
657 broken(hr == E_INVALIDARG), /* Win95, NT4 */
658 "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
659 if (FAILED(hr)) {
660 IShellFolder_Release(psfDesktop);
661 return;
664 dwAttributes = 0xffffffff;
665 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
666 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
667 ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
669 /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
670 ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
671 ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
672 ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
674 /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
675 * key. So the test will return at this point, if run on wine.
677 lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
678 ok (lResult == ERROR_SUCCESS ||
679 lResult == ERROR_ACCESS_DENIED,
680 "RegOpenKeyEx failed! result: %08x\n", lResult);
681 if (lResult != ERROR_SUCCESS) {
682 if (lResult == ERROR_ACCESS_DENIED)
683 skip("Not enough rights to open the registry key\n");
684 IMalloc_Free(ppM, pidlMyDocuments);
685 IShellFolder_Release(psfDesktop);
686 return;
689 /* Query MyDocuments' Attributes value, to be able to restore it later. */
690 dwSize = sizeof(DWORD);
691 lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
692 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
693 if (lResult != ERROR_SUCCESS) {
694 RegCloseKey(hKey);
695 IMalloc_Free(ppM, pidlMyDocuments);
696 IShellFolder_Release(psfDesktop);
697 return;
700 /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
701 dwSize = sizeof(DWORD);
702 lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
703 (LPBYTE)&dwOrigCallForAttributes, &dwSize);
704 ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
705 if (lResult != ERROR_SUCCESS) {
706 RegCloseKey(hKey);
707 IMalloc_Free(ppM, pidlMyDocuments);
708 IShellFolder_Release(psfDesktop);
709 return;
712 /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
713 * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
714 * SFGAO_FILESYSTEM attributes. */
715 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
716 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
717 dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
718 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
719 (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
721 /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
722 * GetAttributesOf. It seems that once there is a single attribute queried, for which
723 * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
724 * the flags in Attributes are ignored.
726 dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
727 hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
728 (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
729 ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
730 if (SUCCEEDED(hr))
731 ok (dwAttributes == SFGAO_FILESYSTEM,
732 "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
733 dwAttributes);
735 /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
736 RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
737 RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
738 (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
739 RegCloseKey(hKey);
740 IMalloc_Free(ppM, pidlMyDocuments);
741 IShellFolder_Release(psfDesktop);
744 static void test_GetAttributesOf(void)
746 HRESULT hr;
747 LPSHELLFOLDER psfDesktop, psfMyComputer;
748 SHITEMID emptyitem = { 0, { 0 } };
749 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
750 LPITEMIDLIST pidlMyComputer;
751 DWORD dwFlags;
752 static const DWORD desktopFlags[] = {
753 /* WinXP */
754 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR |
755 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
756 /* Win2k */
757 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_STREAM | SFGAO_FILESYSANCESTOR |
758 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER,
759 /* WinMe, Win9x, WinNT*/
760 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR |
761 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
763 static const DWORD myComputerFlags[] = {
764 /* WinXP */
765 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
766 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
767 /* Win2k */
768 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_STREAM |
769 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
770 /* WinMe, Win9x, WinNT */
771 SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
772 SFGAO_FOLDER | SFGAO_HASSUBFOLDER,
773 /* Win95, WinNT when queried directly */
774 SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR |
775 SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER
777 WCHAR wszMyComputer[] = {
778 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
779 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
780 char cCurrDirA [MAX_PATH] = {0};
781 WCHAR cCurrDirW [MAX_PATH];
782 static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
783 IShellFolder *IDesktopFolder, *testIShellFolder;
784 ITEMIDLIST *newPIDL;
785 int len, i;
786 BOOL foundFlagsMatch;
788 hr = SHGetDesktopFolder(&psfDesktop);
789 ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
790 if (FAILED(hr)) return;
792 /* The Desktop attributes can be queried with a single empty itemidlist, .. */
793 dwFlags = 0xffffffff;
794 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
795 ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
796 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
797 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
799 if (desktopFlags[i] == dwFlags)
800 foundFlagsMatch = TRUE;
802 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
804 /* .. or with no itemidlist at all. */
805 dwFlags = 0xffffffff;
806 hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
807 ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
808 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
809 i < sizeof(desktopFlags) / sizeof(desktopFlags[0]); i++)
811 if (desktopFlags[i] == dwFlags)
812 foundFlagsMatch = TRUE;
814 ok (foundFlagsMatch, "Wrong Desktop attributes: %08x\n", dwFlags);
816 /* Testing the attributes of the MyComputer shellfolder */
817 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
818 ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
819 if (FAILED(hr)) {
820 IShellFolder_Release(psfDesktop);
821 return;
824 /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
825 * folder object. It doesn't do this, if MyComputer is queried directly (see below).
827 dwFlags = 0xffffffff;
828 hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
829 ok (SUCCEEDED(hr), "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
830 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
831 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
833 if ((myComputerFlags[i] | SFGAO_CANLINK) == dwFlags)
834 foundFlagsMatch = TRUE;
836 todo_wine
837 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
839 hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
840 ok (SUCCEEDED(hr), "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
841 IShellFolder_Release(psfDesktop);
842 IMalloc_Free(ppM, pidlMyComputer);
843 if (FAILED(hr)) return;
845 hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
846 todo_wine
847 ok (hr == E_INVALIDARG ||
848 broken(SUCCEEDED(hr)), /* W2K and earlier */
849 "MyComputer->GetAttributesOf(emtpy pidl) should fail! hr = %08x\n", hr);
851 dwFlags = 0xffffffff;
852 hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
853 ok (SUCCEEDED(hr), "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
854 for (i = 0, foundFlagsMatch = FALSE; !foundFlagsMatch &&
855 i < sizeof(myComputerFlags) / sizeof(myComputerFlags[0]); i++)
857 if (myComputerFlags[i] == dwFlags)
858 foundFlagsMatch = TRUE;
860 todo_wine
861 ok (foundFlagsMatch, "Wrong MyComputer attributes: %08x\n", dwFlags);
863 IShellFolder_Release(psfMyComputer);
865 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
866 len = lstrlenA(cCurrDirA);
868 if (len == 0) {
869 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
870 return;
872 if (len > 3 && cCurrDirA[len-1] == '\\')
873 cCurrDirA[len-1] = 0;
875 /* create test directory */
876 CreateFilesFolders();
878 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
880 hr = SHGetDesktopFolder(&IDesktopFolder);
881 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
883 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
884 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
886 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
887 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
889 IMalloc_Free(ppM, newPIDL);
891 /* get relative PIDL */
892 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
893 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
895 /* test the shell attributes of the test directory using the relative PIDL */
896 dwFlags = SFGAO_FOLDER;
897 hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
898 ok (SUCCEEDED(hr), "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
899 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
901 /* free memory */
902 IMalloc_Free(ppM, newPIDL);
904 /* append testdirectory name to path */
905 if (cCurrDirA[len-1] == '\\')
906 cCurrDirA[len-1] = 0;
907 lstrcatA(cCurrDirA, "\\testdir");
908 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
910 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
911 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
913 /* test the shell attributes of the test directory using the absolute PIDL */
914 dwFlags = SFGAO_FOLDER;
915 hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
916 ok (SUCCEEDED(hr), "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
917 ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
919 /* free memory */
920 IMalloc_Free(ppM, newPIDL);
922 IShellFolder_Release(testIShellFolder);
924 Cleanup();
926 IShellFolder_Release(IDesktopFolder);
929 static void test_SHGetPathFromIDList(void)
931 SHITEMID emptyitem = { 0, { 0 } };
932 LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
933 LPITEMIDLIST pidlMyComputer;
934 WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
935 BOOL result;
936 HRESULT hr;
937 LPSHELLFOLDER psfDesktop;
938 WCHAR wszMyComputer[] = {
939 ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
940 'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
941 WCHAR wszFileName[MAX_PATH];
942 LPITEMIDLIST pidlTestFile;
943 HANDLE hTestFile;
944 STRRET strret;
945 static WCHAR wszTestFile[] = {
946 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
947 HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
948 HMODULE hShell32;
949 LPITEMIDLIST pidlPrograms;
951 if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
953 win_skip("SHGetPathFromIDListW() or SHGetSpecialFolderPathW() is missing\n");
954 return;
957 /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
958 wszPath[0] = 'a';
959 wszPath[1] = '\0';
960 result = pSHGetPathFromIDListW(NULL, wszPath);
961 ok(!result, "Expected failure\n");
962 ok(!wszPath[0], "Expected empty string\n");
964 /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
965 result = pSHGetSpecialFolderPathW(NULL, wszDesktop, CSIDL_DESKTOP, FALSE);
966 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
967 if (!result) return;
969 /* Check if we are on Win9x */
970 SetLastError(0xdeadbeef);
971 lstrcmpiW(wszDesktop, wszDesktop);
972 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
974 win_skip("Most W-calls are not implemented\n");
975 return;
978 result = pSHGetPathFromIDListW(pidlEmpty, wszPath);
979 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
980 if (!result) return;
981 ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
983 /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
984 hr = SHGetDesktopFolder(&psfDesktop);
985 ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
986 if (FAILED(hr)) return;
988 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
989 ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
990 if (FAILED(hr)) {
991 IShellFolder_Release(psfDesktop);
992 return;
995 SetLastError(0xdeadbeef);
996 wszPath[0] = 'a';
997 wszPath[1] = '\0';
998 result = pSHGetPathFromIDListW(pidlMyComputer, wszPath);
999 ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1000 ok (GetLastError()==0xdeadbeef ||
1001 GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1002 "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1003 ok (!wszPath[0], "Expected empty path\n");
1004 if (result) {
1005 IShellFolder_Release(psfDesktop);
1006 return;
1009 IMalloc_Free(ppM, pidlMyComputer);
1011 result = pSHGetSpecialFolderPathW(NULL, wszFileName, CSIDL_DESKTOPDIRECTORY, FALSE);
1012 ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1013 if (!result) {
1014 IShellFolder_Release(psfDesktop);
1015 return;
1017 myPathAddBackslashW(wszFileName);
1018 lstrcatW(wszFileName, wszTestFile);
1019 hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1020 ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1021 if (hTestFile == INVALID_HANDLE_VALUE) {
1022 IShellFolder_Release(psfDesktop);
1023 return;
1025 CloseHandle(hTestFile);
1027 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1028 ok (SUCCEEDED(hr), "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1029 if (FAILED(hr)) {
1030 IShellFolder_Release(psfDesktop);
1031 DeleteFileW(wszFileName);
1032 IMalloc_Free(ppM, pidlTestFile);
1033 return;
1036 /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1037 * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1038 hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1039 ok (SUCCEEDED(hr), "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1040 IShellFolder_Release(psfDesktop);
1041 DeleteFileW(wszFileName);
1042 if (FAILED(hr)) {
1043 IMalloc_Free(ppM, pidlTestFile);
1044 return;
1046 if (pStrRetToBufW)
1048 pStrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1049 ok(0 == lstrcmpW(wszFileName, wszPath),
1050 "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1051 "returned incorrect path for file placed on desktop\n");
1054 result = pSHGetPathFromIDListW(pidlTestFile, wszPath);
1055 ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1056 IMalloc_Free(ppM, pidlTestFile);
1057 if (!result) return;
1058 ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1061 /* Test if we can get the path from the start menu "program files" PIDL. */
1062 hShell32 = GetModuleHandleA("shell32");
1063 pSHGetSpecialFolderLocation = (void *)GetProcAddress(hShell32, "SHGetSpecialFolderLocation");
1065 hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
1066 ok(SUCCEEDED(hr), "SHGetFolderLocation failed: 0x%08x\n", hr);
1068 SetLastError(0xdeadbeef);
1069 result = pSHGetPathFromIDListW(pidlPrograms, wszPath);
1070 IMalloc_Free(ppM, pidlPrograms);
1071 ok(result, "SHGetPathFromIDListW failed\n");
1074 static void test_EnumObjects_and_CompareIDs(void)
1076 ITEMIDLIST *newPIDL;
1077 IShellFolder *IDesktopFolder, *testIShellFolder;
1078 char cCurrDirA [MAX_PATH] = {0};
1079 static const CHAR cTestDirA[] = "\\testdir";
1080 WCHAR cTestDirW[MAX_PATH];
1081 int len;
1082 HRESULT hr;
1084 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1085 len = lstrlenA(cCurrDirA);
1087 if(len == 0) {
1088 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1089 return;
1091 if(cCurrDirA[len-1] == '\\')
1092 cCurrDirA[len-1] = 0;
1094 lstrcatA(cCurrDirA, cTestDirA);
1095 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1097 hr = SHGetDesktopFolder(&IDesktopFolder);
1098 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1100 CreateFilesFolders();
1102 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1103 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1105 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1106 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1108 test_EnumObjects(testIShellFolder);
1110 IShellFolder_Release(testIShellFolder);
1112 Cleanup();
1114 IMalloc_Free(ppM, newPIDL);
1116 IShellFolder_Release(IDesktopFolder);
1119 /* A simple implementation of an IPropertyBag, which returns fixed values for
1120 * 'Target' and 'Attributes' properties.
1122 static HRESULT WINAPI InitPropertyBag_IPropertyBag_QueryInterface(IPropertyBag *iface, REFIID riid,
1123 void **ppvObject)
1125 if (!ppvObject)
1126 return E_INVALIDARG;
1128 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPropertyBag, riid)) {
1129 *ppvObject = iface;
1130 } else {
1131 ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1132 return E_NOINTERFACE;
1135 IPropertyBag_AddRef(iface);
1136 return S_OK;
1139 static ULONG WINAPI InitPropertyBag_IPropertyBag_AddRef(IPropertyBag *iface) {
1140 return 2;
1143 static ULONG WINAPI InitPropertyBag_IPropertyBag_Release(IPropertyBag *iface) {
1144 return 1;
1147 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1148 VARIANT *pVar, IErrorLog *pErrorLog)
1150 static const WCHAR wszTargetSpecialFolder[] = {
1151 'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1152 static const WCHAR wszTarget[] = {
1153 'T','a','r','g','e','t',0 };
1154 static const WCHAR wszAttributes[] = {
1155 'A','t','t','r','i','b','u','t','e','s',0 };
1156 static const WCHAR wszResolveLinkFlags[] = {
1157 'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1158 static const WCHAR wszTargetKnownFolder[] = {
1159 'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1160 static const WCHAR wszCLSID[] = {
1161 'C','L','S','I','D',0 };
1163 if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1164 ok(V_VT(pVar) == VT_I4 ||
1165 broken(V_VT(pVar) == VT_BSTR), /* Win2k */
1166 "Wrong variant type for 'TargetSpecialFolder' property!\n");
1167 return E_INVALIDARG;
1170 if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1172 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1173 return E_INVALIDARG;
1176 if (!lstrcmpW(pszPropName, wszTarget)) {
1177 WCHAR wszPath[MAX_PATH];
1178 BOOL result;
1180 ok(V_VT(pVar) == VT_BSTR ||
1181 broken(V_VT(pVar) == VT_EMPTY), /* Win2k */
1182 "Wrong variant type for 'Target' property!\n");
1183 if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1185 result = pSHGetSpecialFolderPathW(NULL, wszPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1186 ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1187 if (!result) return E_INVALIDARG;
1189 V_BSTR(pVar) = SysAllocString(wszPath);
1190 return S_OK;
1193 if (!lstrcmpW(pszPropName, wszAttributes)) {
1194 ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1195 if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1196 V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1197 SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1198 return S_OK;
1201 if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1202 ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1203 /* TODO */
1204 return E_INVALIDARG;
1207 if (!lstrcmpW(pszPropName, wszCLSID)) {
1208 ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1209 /* TODO */
1210 return E_INVALIDARG;
1213 ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1214 return E_INVALIDARG;
1217 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1218 VARIANT *pVar)
1220 ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1221 return E_NOTIMPL;
1224 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1225 InitPropertyBag_IPropertyBag_QueryInterface,
1226 InitPropertyBag_IPropertyBag_AddRef,
1227 InitPropertyBag_IPropertyBag_Release,
1228 InitPropertyBag_IPropertyBag_Read,
1229 InitPropertyBag_IPropertyBag_Write
1232 static struct IPropertyBag InitPropertyBag = {
1233 &InitPropertyBag_IPropertyBagVtbl
1236 static void test_FolderShortcut(void) {
1237 IPersistPropertyBag *pPersistPropertyBag;
1238 IShellFolder *pShellFolder, *pDesktopFolder;
1239 IPersistFolder3 *pPersistFolder3;
1240 HRESULT hr;
1241 STRRET strret;
1242 WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1243 BOOL result;
1244 CLSID clsid;
1245 LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1246 HKEY hShellExtKey;
1247 WCHAR wszWineTestFolder[] = {
1248 ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1249 'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1250 WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1251 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1252 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1253 'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1254 'N','a','m','e','S','p','a','c','e','\\',
1255 '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1256 'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1258 WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1259 static const GUID CLSID_UnixDosFolder =
1260 {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1262 if (!pSHGetSpecialFolderPathW || !pStrRetToBufW) {
1263 win_skip("SHGetSpecialFolderPathW and/or StrRetToBufW are not available\n");
1264 return;
1267 if (!pSHGetFolderPathAndSubDirA)
1269 win_skip("FolderShortcut test doesn't work on Win2k\n");
1270 return;
1273 /* These tests basically show, that CLSID_FolderShortcuts are initialized
1274 * via their IPersistPropertyBag interface. And that the target folder
1275 * is taken from the IPropertyBag's 'Target' property.
1277 hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1278 &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1279 if (hr == REGDB_E_CLASSNOTREG) {
1280 win_skip("CLSID_FolderShortcut is not implemented\n");
1281 return;
1283 ok (SUCCEEDED(hr), "CoCreateInstance failed! hr = 0x%08x\n", hr);
1284 if (FAILED(hr)) return;
1286 hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1287 ok(SUCCEEDED(hr), "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1288 if (FAILED(hr)) {
1289 IPersistPropertyBag_Release(pPersistPropertyBag);
1290 return;
1293 hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1294 (LPVOID*)&pShellFolder);
1295 IPersistPropertyBag_Release(pPersistPropertyBag);
1296 ok(SUCCEEDED(hr), "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1297 if (FAILED(hr)) return;
1299 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1300 ok(SUCCEEDED(hr), "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1301 if (FAILED(hr)) {
1302 IShellFolder_Release(pShellFolder);
1303 return;
1306 result = pSHGetSpecialFolderPathW(NULL, wszDesktopPath, CSIDL_DESKTOPDIRECTORY, FALSE);
1307 ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1308 if (!result) return;
1310 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1311 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1313 hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1314 IShellFolder_Release(pShellFolder);
1315 ok(SUCCEEDED(hr), "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1316 if (FAILED(hr)) return;
1318 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1319 ok(SUCCEEDED(hr), "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1320 ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1322 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1323 ok(SUCCEEDED(hr), "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1324 ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1326 /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1327 * shell namespace. The target folder, read from the property bag above, remains untouched.
1328 * The following tests show this: The itemidlist for some imaginary shellfolder object
1329 * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1330 * itemidlist, but GetDisplayNameOf still returns the path from above.
1332 hr = SHGetDesktopFolder(&pDesktopFolder);
1333 ok (SUCCEEDED(hr), "SHGetDesktopFolder failed! hr = %08x\n", hr);
1334 if (FAILED(hr)) return;
1336 /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1337 * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1338 RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1339 RegCloseKey(hShellExtKey);
1340 hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1341 &pidlWineTestFolder, NULL);
1342 RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1343 IShellFolder_Release(pDesktopFolder);
1344 ok (SUCCEEDED(hr), "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1345 if (FAILED(hr)) return;
1347 hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1348 ok (SUCCEEDED(hr), "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1349 if (FAILED(hr)) {
1350 IPersistFolder3_Release(pPersistFolder3);
1351 pILFree(pidlWineTestFolder);
1352 return;
1355 hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1356 ok(SUCCEEDED(hr), "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1357 ok(pILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1358 "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1359 pILFree(pidlCurrentFolder);
1360 pILFree(pidlWineTestFolder);
1362 hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1363 IPersistFolder3_Release(pPersistFolder3);
1364 ok(SUCCEEDED(hr), "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1365 if (FAILED(hr)) return;
1367 hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1368 ok(SUCCEEDED(hr), "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1369 if (FAILED(hr)) {
1370 IShellFolder_Release(pShellFolder);
1371 return;
1374 pStrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1375 ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1377 /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1378 * but ShellFSFolders. */
1379 myPathAddBackslashW(wszDesktopPath);
1380 lstrcatW(wszDesktopPath, wszSomeSubFolder);
1381 if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1382 IShellFolder_Release(pShellFolder);
1383 return;
1386 hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1387 &pidlSubFolder, NULL);
1388 RemoveDirectoryW(wszDesktopPath);
1389 ok (SUCCEEDED(hr), "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1390 if (FAILED(hr)) {
1391 IShellFolder_Release(pShellFolder);
1392 return;
1395 hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1396 (LPVOID*)&pPersistFolder3);
1397 IShellFolder_Release(pShellFolder);
1398 pILFree(pidlSubFolder);
1399 ok (SUCCEEDED(hr), "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1400 if (FAILED(hr))
1401 return;
1403 /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1404 * a little bit and also allow CLSID_UnixDosFolder. */
1405 hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1406 ok(SUCCEEDED(hr), "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1407 ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1408 "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1410 IPersistFolder3_Release(pPersistFolder3);
1413 #include "pshpack1.h"
1414 struct FileStructA {
1415 BYTE type;
1416 BYTE dummy;
1417 DWORD dwFileSize;
1418 WORD uFileDate; /* In our current implementation this is */
1419 WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1420 WORD uFileAttribs;
1421 CHAR szName[1];
1424 struct FileStructW {
1425 WORD cbLen; /* Length of this element. */
1426 BYTE abFooBar1[6]; /* Beyond any recognition. */
1427 WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1428 WORD uTime; /* (this is currently speculation) */
1429 WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1430 WORD uTime2; /* (this is currently speculation) */
1431 BYTE abFooBar2[4]; /* Beyond any recognition. */
1432 WCHAR wszName[1]; /* The long filename in unicode. */
1433 /* Just for documentation: Right after the unicode string: */
1434 WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1435 * SHITEMID->cb == uOffset + cbLen */
1437 #include "poppack.h"
1439 static void test_ITEMIDLIST_format(void) {
1440 WCHAR wszPersonal[MAX_PATH];
1441 LPSHELLFOLDER psfDesktop, psfPersonal;
1442 LPITEMIDLIST pidlPersonal, pidlFile;
1443 HANDLE hFile;
1444 HRESULT hr;
1445 BOOL bResult;
1446 WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1447 { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1448 int i;
1450 if (!pSHGetSpecialFolderPathW) return;
1452 bResult = pSHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1453 ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1454 if (!bResult) return;
1456 SetLastError(0xdeadbeef);
1457 bResult = SetCurrentDirectoryW(wszPersonal);
1458 if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1459 win_skip("Most W-calls are not implemented\n");
1460 return;
1462 ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1463 if (!bResult) return;
1465 hr = SHGetDesktopFolder(&psfDesktop);
1466 ok(SUCCEEDED(hr), "SHGetDesktopFolder failed! hr: %08x\n", hr);
1467 if (FAILED(hr)) return;
1469 hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1470 ok(SUCCEEDED(hr), "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1471 if (FAILED(hr)) {
1472 IShellFolder_Release(psfDesktop);
1473 return;
1476 hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1477 (LPVOID*)&psfPersonal);
1478 IShellFolder_Release(psfDesktop);
1479 pILFree(pidlPersonal);
1480 ok(SUCCEEDED(hr), "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1481 if (FAILED(hr)) return;
1483 for (i=0; i<3; i++) {
1484 CHAR szFile[MAX_PATH];
1485 struct FileStructA *pFileStructA;
1486 WORD cbOffset;
1488 WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1490 hFile = CreateFileW(wszFile[i], GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_WRITE_THROUGH, NULL);
1491 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1492 if (hFile == INVALID_HANDLE_VALUE) {
1493 IShellFolder_Release(psfPersonal);
1494 return;
1496 CloseHandle(hFile);
1498 hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1499 DeleteFileW(wszFile[i]);
1500 ok(SUCCEEDED(hr), "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1501 if (FAILED(hr)) {
1502 IShellFolder_Release(psfPersonal);
1503 return;
1506 pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1507 ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1508 ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1509 ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1511 if (i < 2) /* First two file names are already in valid 8.3 format */
1512 ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1513 else
1514 /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1515 * can't implement this correctly, since unix filesystems don't support
1516 * this nasty short/long filename stuff. So we'll probably stay with our
1517 * current habbit of storing the long filename here, which seems to work
1518 * just fine. */
1519 todo_wine
1520 ok(pidlFile->mkid.abID[18] == '~' ||
1521 broken(pidlFile->mkid.abID[34] == '~'), /* Win2k */
1522 "Should be derived 8.3 name!\n");
1524 if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1525 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0' ||
1526 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1), /* Win2k */
1527 "Alignment byte, where there shouldn't be!\n");
1529 if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1530 ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1531 "There should be an alignment byte, but isn't!\n");
1533 /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1534 cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1535 ok ((cbOffset >= sizeof(struct FileStructA) &&
1536 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)) ||
1537 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 1) || /* Win2k on short names */
1538 broken(pidlFile->mkid.cb == 2 + 12 + strlen(szFile) + 1 + 12 + 1), /* Win2k on long names */
1539 "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1541 if (cbOffset >= sizeof(struct FileStructA) &&
1542 cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1544 struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1546 ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1547 "FileStructW's offset and length should add up to the PIDL's length!\n");
1549 if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1550 /* Since we just created the file, time of creation,
1551 * time of last access and time of last write access just be the same.
1552 * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1553 * after the first run. I do remember something with NTFS keeping the creation time
1554 * if a file is deleted and then created again within a couple of seconds or so.
1555 * Might be the reason. */
1556 ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1557 pFileStructA->uFileTime == pFileStructW->uTime,
1558 "Last write time should match creation time!\n");
1560 /* On FAT filesystems the last access time is midnight
1561 local time, so the values of uDate2 and uTime2 will
1562 depend on the local timezone. If the times are exactly
1563 equal then the dates should be identical for both FAT
1564 and NTFS as no timezone is more than 1 day away from UTC.
1566 if (pFileStructA->uFileTime == pFileStructW->uTime2)
1568 ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1569 "Last write date and time should match last access date and time!\n");
1571 else
1573 /* Filesystem may be FAT. Check date within 1 day
1574 and seconds are zero. */
1575 trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1576 ok ((pFileStructW->uTime2 & 0x1F) == 0,
1577 "Last access time on FAT filesystems should have zero seconds.\n");
1578 /* TODO: Perform check for date being within one day.*/
1581 ok (!lstrcmpW(wszFile[i], pFileStructW->wszName) ||
1582 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 22)) || /* Vista */
1583 !lstrcmpW(wszFile[i], (WCHAR *)(pFileStructW->abFooBar2 + 26)), /* Win7 */
1584 "The filename should be stored in unicode at this position!\n");
1588 pILFree(pidlFile);
1591 IShellFolder_Release(psfPersonal);
1594 static void test_SHGetFolderPathAndSubDirA(void)
1596 HRESULT ret;
1597 BOOL delret;
1598 DWORD dwret;
1599 int i;
1600 static char wine[] = "wine";
1601 static char winetemp[] = "wine\\temp";
1602 static char appdata[MAX_PATH];
1603 static char testpath[MAX_PATH];
1604 static char toolongpath[MAX_PATH+1];
1606 if(!pSHGetFolderPathAndSubDirA)
1608 win_skip("SHGetFolderPathAndSubDirA not present!\n");
1609 return;
1612 if(!pSHGetFolderPathA) {
1613 win_skip("SHGetFolderPathA not present!\n");
1614 return;
1616 if(FAILED(pSHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdata)))
1618 win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1619 return;
1622 sprintf(testpath, "%s\\%s", appdata, winetemp);
1623 delret = RemoveDirectoryA(testpath);
1624 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1625 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1626 return;
1629 sprintf(testpath, "%s\\%s", appdata, wine);
1630 delret = RemoveDirectoryA(testpath);
1631 if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1632 win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1633 return;
1636 /* test invalid second parameter */
1637 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | 0xff, NULL, SHGFP_TYPE_CURRENT, wine, testpath);
1638 ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1640 /* test fourth parameter */
1641 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, 2, winetemp, testpath);
1642 switch(ret) {
1643 case S_OK: /* winvista */
1644 ok(!strncmp(appdata, testpath, strlen(appdata)),
1645 "expected %s to start with %s\n", testpath, appdata);
1646 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1647 "expected %s to end with %s\n", testpath, winetemp);
1648 break;
1649 case E_INVALIDARG: /* winxp, win2k3 */
1650 break;
1651 default:
1652 ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
1655 /* test fifth parameter */
1656 testpath[0] = '\0';
1657 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, NULL, testpath);
1658 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1659 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1661 testpath[0] = '\0';
1662 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "", testpath);
1663 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1664 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1666 testpath[0] = '\0';
1667 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, "\\", testpath);
1668 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1669 ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1671 for(i=0; i< MAX_PATH; i++)
1672 toolongpath[i] = '0' + i % 10;
1673 toolongpath[MAX_PATH] = '\0';
1674 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, toolongpath, testpath);
1675 ok(HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) == ret,
1676 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1678 testpath[0] = '\0';
1679 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wine, NULL);
1680 ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1682 /* test a not existing path */
1683 testpath[0] = '\0';
1684 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1685 ok(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == ret,
1686 "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1688 /* create a directory inside a not existing directory */
1689 testpath[0] = '\0';
1690 ret = pSHGetFolderPathAndSubDirA(NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, winetemp, testpath);
1691 ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1692 ok(!strncmp(appdata, testpath, strlen(appdata)),
1693 "expected %s to start with %s\n", testpath, appdata);
1694 ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1695 "expected %s to end with %s\n", testpath, winetemp);
1696 dwret = GetFileAttributes(testpath);
1697 ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1699 /* cleanup */
1700 sprintf(testpath, "%s\\%s", appdata, winetemp);
1701 RemoveDirectoryA(testpath);
1702 sprintf(testpath, "%s\\%s", appdata, wine);
1703 RemoveDirectoryA(testpath);
1706 static void test_LocalizedNames(void)
1708 static char cCurrDirA[MAX_PATH];
1709 WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1710 IShellFolder *IDesktopFolder, *testIShellFolder;
1711 ITEMIDLIST *newPIDL;
1712 int len;
1713 HRESULT hr;
1714 static char resourcefile[MAX_PATH];
1715 DWORD res;
1716 HANDLE file;
1717 STRRET strret;
1719 static const char desktopini_contents1[] =
1720 "[.ShellClassInfo]\r\n"
1721 "LocalizedResourceName=@";
1722 static const char desktopini_contents2[] =
1723 ",-1\r\n";
1724 static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1725 static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1727 /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1728 CreateDirectoryA(".\\testfolder", NULL);
1730 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1732 GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1734 file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1735 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1736 ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1737 ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1738 WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1739 WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
1740 "WriteFile failed %i\n", GetLastError());
1741 CloseHandle(file);
1743 /* get IShellFolder for parent */
1744 GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1745 len = lstrlenA(cCurrDirA);
1747 if (len == 0) {
1748 win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1749 goto cleanup;
1751 if(cCurrDirA[len-1] == '\\')
1752 cCurrDirA[len-1] = 0;
1754 MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1756 hr = SHGetDesktopFolder(&IDesktopFolder);
1757 ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1759 hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1760 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1762 hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1763 ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1765 IMalloc_Free(ppM, newPIDL);
1767 /* windows reads the display name from the resource */
1768 hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1769 ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1771 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1772 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1774 if (SUCCEEDED(hr) && pStrRetToBufW)
1776 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1777 ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr);
1778 todo_wine
1779 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1780 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1781 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1784 /* editing name is also read from the resource */
1785 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1786 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1788 if (SUCCEEDED(hr) && pStrRetToBufW)
1790 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1791 ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr);
1792 todo_wine
1793 ok (!lstrcmpiW(tempbufW, folderdisplayW) ||
1794 broken(!lstrcmpiW(tempbufW, foldernameW)), /* W2K */
1795 "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1798 /* parsing name is unchanged */
1799 hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1800 ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1802 if (SUCCEEDED(hr) && pStrRetToBufW)
1804 hr = pStrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
1805 ok (SUCCEEDED(hr), "StrRetToBufW failed! hr = %08x\n", hr);
1806 ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1809 IShellFolder_Release(IDesktopFolder);
1810 IShellFolder_Release(testIShellFolder);
1812 IMalloc_Free(ppM, newPIDL);
1814 cleanup:
1815 DeleteFileA(".\\testfolder\\desktop.ini");
1816 SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1817 RemoveDirectoryA(".\\testfolder");
1820 static void test_SHCreateShellItem(void)
1822 IShellItem *shellitem, *shellitem2;
1823 IPersistIDList *persistidl;
1824 LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test;
1825 HRESULT ret;
1826 char curdirA[MAX_PATH];
1827 WCHAR curdirW[MAX_PATH];
1828 IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
1829 static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
1831 GetCurrentDirectoryA(MAX_PATH, curdirA);
1833 if (!pSHCreateShellItem)
1835 win_skip("SHCreateShellItem isn't available\n");
1836 return;
1839 if (!lstrlenA(curdirA))
1841 win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
1842 return;
1845 MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
1847 ret = SHGetDesktopFolder(&desktopfolder);
1848 ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
1850 ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
1851 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1853 ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
1854 ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
1856 CreateTestFile(".\\testfile");
1858 ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
1859 ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
1861 pidl_abstestfile = pILCombine(pidl_cwd, pidl_testfile);
1863 ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
1864 ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
1866 if (0) /* crashes on Windows XP */
1868 pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
1869 pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
1870 pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
1871 pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
1874 ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
1875 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1876 if (SUCCEEDED(ret))
1878 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1879 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1880 if (SUCCEEDED(ret))
1882 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1883 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1884 if (SUCCEEDED(ret))
1886 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1887 pILFree(pidl_test);
1889 IPersistIDList_Release(persistidl);
1891 IShellItem_Release(shellitem);
1894 ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
1895 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1896 if (SUCCEEDED(ret))
1898 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1899 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1900 if (SUCCEEDED(ret))
1902 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1903 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1904 if (SUCCEEDED(ret))
1906 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1907 pILFree(pidl_test);
1909 IPersistIDList_Release(persistidl);
1912 ret = IShellItem_GetParent(shellitem, &shellitem2);
1913 ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
1914 if (SUCCEEDED(ret))
1916 ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
1917 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1918 if (SUCCEEDED(ret))
1920 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1921 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1922 if (SUCCEEDED(ret))
1924 ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
1925 pILFree(pidl_test);
1927 IPersistIDList_Release(persistidl);
1929 IShellItem_Release(shellitem2);
1932 IShellItem_Release(shellitem);
1935 ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
1936 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1937 if (SUCCEEDED(ret))
1939 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1940 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1941 if (SUCCEEDED(ret))
1943 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1944 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1945 if (SUCCEEDED(ret))
1947 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1948 pILFree(pidl_test);
1950 IPersistIDList_Release(persistidl);
1952 IShellItem_Release(shellitem);
1955 /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
1956 ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
1957 ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
1958 if (SUCCEEDED(ret))
1960 ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
1961 ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
1962 if (SUCCEEDED(ret))
1964 ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
1965 ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
1966 if (SUCCEEDED(ret))
1968 ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
1969 pILFree(pidl_test);
1971 IPersistIDList_Release(persistidl);
1973 IShellItem_Release(shellitem);
1976 DeleteFileA(".\\testfile");
1977 pILFree(pidl_abstestfile);
1978 pILFree(pidl_testfile);
1979 pILFree(pidl_cwd);
1980 IShellFolder_Release(currentfolder);
1981 IShellFolder_Release(desktopfolder);
1984 static void test_SHParseDisplayName(void)
1986 static const WCHAR prefixW[] = {'w','t',0};
1987 LPITEMIDLIST pidl1, pidl2;
1988 IShellFolder *desktop;
1989 WCHAR dirW[MAX_PATH];
1990 WCHAR nameW[10];
1991 HRESULT hr;
1992 BOOL ret;
1994 if (!pSHParseDisplayName)
1996 win_skip("SHParseDisplayName isn't available\n");
1997 return;
2000 if (0)
2002 /* crashes on native */
2003 hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
2004 nameW[0] = 0;
2005 hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
2008 pidl1 = (LPITEMIDLIST)0xdeadbeef;
2009 hr = pSHParseDisplayName(NULL, NULL, &pidl1, 0, NULL);
2010 ok(broken(hr == E_OUTOFMEMORY) /* < Vista */ ||
2011 hr == E_INVALIDARG, "failed %08x\n", hr);
2012 ok(pidl1 == 0, "expected null ptr, got %p\n", pidl1);
2014 /* dummy name */
2015 nameW[0] = 0;
2016 hr = pSHParseDisplayName(nameW, NULL, &pidl1, 0, NULL);
2017 ok(hr == S_OK, "failed %08x\n", hr);
2018 hr = SHGetDesktopFolder(&desktop);
2019 ok(hr == S_OK, "failed %08x\n", hr);
2020 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, nameW, NULL, &pidl2, NULL);
2021 ok(hr == S_OK, "failed %08x\n", hr);
2022 ret = pILIsEqual(pidl1, pidl2);
2023 ok(ret == TRUE, "expected equal idls\n");
2024 pILFree(pidl1);
2025 pILFree(pidl2);
2027 /* with path */
2028 GetTempPathW(sizeof(dirW)/sizeof(WCHAR), dirW);
2029 GetTempFileNameW(dirW, prefixW, 0, dirW);
2030 CreateFileW(dirW, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2032 hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
2033 ok(hr == S_OK, "failed %08x\n", hr);
2034 hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, dirW, NULL, &pidl2, NULL);
2035 ok(hr == S_OK, "failed %08x\n", hr);
2037 ret = pILIsEqual(pidl1, pidl2);
2038 ok(ret == TRUE, "expected equal idls\n");
2039 pILFree(pidl1);
2040 pILFree(pidl2);
2042 DeleteFileW(dirW);
2044 IShellFolder_Release(desktop);
2047 START_TEST(shlfolder)
2049 init_function_pointers();
2050 /* if OleInitialize doesn't get called, ParseDisplayName returns
2051 CO_E_NOTINITIALIZED for malformed directory names on win2k. */
2052 OleInitialize(NULL);
2054 test_ParseDisplayName();
2055 test_SHParseDisplayName();
2056 test_BindToObject();
2057 test_EnumObjects_and_CompareIDs();
2058 test_GetDisplayName();
2059 test_GetAttributesOf();
2060 test_SHGetPathFromIDList();
2061 test_CallForAttributes();
2062 test_FolderShortcut();
2063 test_ITEMIDLIST_format();
2064 test_SHGetFolderPathAndSubDirA();
2065 test_LocalizedNames();
2066 test_SHCreateShellItem();
2068 OleUninitialize();