ReactOS  0.4.13-dev-249-gcba1a2f
shlfolder.c
Go to the documentation of this file.
1 /*
2  * Unit test of the IShellFolder functions.
3  *
4  * Copyright 2004 Vitaliy Margolen
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #include <stdarg.h>
22 #include <stdio.h>
23 
24 #define COBJMACROS
25 #define CONST_VTABLE
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wtypes.h"
30 #include "shellapi.h"
31 
32 
33 #include "shlguid.h"
34 #include "shlobj.h"
35 #include "shobjidl.h"
36 #include "shlwapi.h"
37 #include "ocidl.h"
38 #include "oleauto.h"
39 
40 #include "wine/heap.h"
41 #include "wine/test.h"
42 
43 #include <initguid.h>
44 DEFINE_GUID(IID_IParentAndItem, 0xB3A4B685, 0xB685, 0x4805, 0x99,0xD9, 0x5D,0xEA,0xD2,0x87,0x32,0x36);
45 DEFINE_GUID(CLSID_ShellDocObjView, 0xe7e4bc40, 0xe76a, 0x11ce, 0xa9,0xbb, 0x00,0xaa,0x00,0x4a,0xe8,0x37);
46 
47 static IMalloc *ppM;
48 
49 static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
50 static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
51 static HRESULT (WINAPI *pSHCreateItemFromRelativeName)(IShellItem*,PCWSTR,IBindCtx*,REFIID,void**);
52 static HRESULT (WINAPI *pSHCreateItemInKnownFolder)(REFKNOWNFOLDERID,DWORD,PCWSTR,REFIID,void **);
54 static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
55 static HRESULT (WINAPI *pSHCreateShellItemArrayFromIDLists)(UINT, PCIDLIST_ABSOLUTE*, IShellItemArray**);
56 static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
57 static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
58 static HRESULT (WINAPI *pSHGetKnownFolderPath)(REFKNOWNFOLDERID,DWORD,HANDLE,PWSTR*);
59 static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
60 static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
61 static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
62 static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
63 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
64 static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
65 static BOOL (WINAPI *pSHGetPathFromIDListEx)(PCIDLIST_ABSOLUTE,WCHAR*,DWORD,GPFIDL_FLAGS);
66 #ifdef __REACTOS__
67 typedef SHFOLDERCUSTOMSETTINGSW SHFOLDERCUSTOMSETTINGS, *LPSHFOLDERCUSTOMSETTINGS;
68 #endif
69 static HRESULT (WINAPI *pSHGetSetFolderCustomSettings)(LPSHFOLDERCUSTOMSETTINGS,PCWSTR,DWORD);
70 
71 static WCHAR *make_wstr(const char *str)
72 {
73  WCHAR *ret;
74  int len;
75 
76  if (!str || !str[0])
77  return NULL;
78 
79  len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
80  if(!len || len < 0)
81  return NULL;
82 
83  ret = heap_alloc(len * sizeof(WCHAR));
84  if(!ret)
85  return NULL;
86 
88  return ret;
89 }
90 
91 static int strcmp_wa(LPCWSTR strw, const char *stra)
92 {
93  CHAR buf[512];
94  WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
95  return lstrcmpA(stra, buf);
96 }
97 
98 static void init_function_pointers(void)
99 {
100  HMODULE hmod;
101  HRESULT hr;
102  void *ptr;
103 
104  hmod = GetModuleHandleA("shell32.dll");
105 
106 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
109  MAKEFUNC(SHCreateItemFromRelativeName);
110  MAKEFUNC(SHCreateItemInKnownFolder);
116  MAKEFUNC(SHGetKnownFolderPath);
122  MAKEFUNC(SHGetPathFromIDListEx);
123  MAKEFUNC(SHGetSetFolderCustomSettings);
124 #undef MAKEFUNC
125 
126  /* test named exports */
127  ptr = GetProcAddress(hmod, "ILFree");
128  ok(broken(ptr == 0) || ptr != 0, "expected named export for ILFree\n");
129  if (ptr)
130  {
131 #define TESTNAMED(f) \
132  ptr = (void*)GetProcAddress(hmod, #f); \
133  ok(ptr != 0, "expected named export for " #f "\n");
134 
150 #undef TESTNAMED
151  }
152 
153  hmod = GetModuleHandleA("kernel32.dll");
154  pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
155 
156  hr = SHGetMalloc(&ppM);
157  ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
158 }
159 
160 /* Based on PathAddBackslashW from dlls/shlwapi/path.c */
162 {
163  size_t iLen;
164 
165  if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
166  return NULL;
167 
168  if (iLen)
169  {
170  lpszPath += iLen;
171  if (lpszPath[-1] != '\\')
172  {
173  *lpszPath++ = '\\';
174  *lpszPath = '\0';
175  }
176  }
177  return lpszPath;
178 }
179 
180 static struct
181 {
184  int todo;
185 } parse_tests[] = {
186  {{'c',':','\\',0}, S_OK},
187  {{'c',':','\\','\\',0}, E_INVALIDARG, 1},
188  {{'c',':','\\','f','a','k','e',0}, 0x80070002}, /* ERROR_FILE_NOT_FOUND */
189  {{'c',':','f','a','k','e',0}, E_INVALIDARG, 1},
190  {{'c',':','/',0}, E_INVALIDARG, 1},
191  {{'c',':','\\','w','i','n','d','o','w','s',0}, S_OK},
192  {{'c',':','\\','w','i','n','d','o','w','s','\\',0}, S_OK},
193  {{'c',':','\\','w','i','n','d','o','w','s','\\','.',0}, E_INVALIDARG, 1},
194  {{'c',':','\\','w','i','n','d','o','w','s','\\','.','.',0}, E_INVALIDARG, 1},
195  {{'.',0}, E_INVALIDARG, 1},
196  {{'.','.',0}, E_INVALIDARG, 1},
197  {{'t','e','s','t',0}, 0x80070002},
198  {{'t','e','s','t','\\',0}, 0x80070002},
199  {{'s','u','b','\\','d','i','r',0}, 0x80070002},
200  {{'s','u','b','/','d','i','r',0}, E_INVALIDARG, 1},
201  {{'h','t','t','p',':',0}, S_OK, 1},
202  {{'h','t','t','p',':','t','e','s','t',0}, S_OK, 1},
203  {{'h','t','t','p',':','\\','t','e','s','t',0}, S_OK, 1},
204  {{'x','x',':',0}, S_OK, 1},
205 };
206 
207 static void test_ParseDisplayName(void)
208 {
209  static WCHAR testdirW[] = {'p','a','r','s','e','t','e','s','t',0};
210  static WCHAR backslashW[] = {'\\',0};
211  WCHAR buffer[MAX_PATH], buffer2[MAX_PATH];
212  IShellFolder *desktop;
213  ITEMIDLIST *pidl;
214  HRESULT hr;
215  BOOL bRes;
216  int i;
217 
218  hr = SHGetDesktopFolder(&desktop);
219  ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
220 
221  hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, NULL, NULL, &pidl, NULL);
222  ok(hr == E_INVALIDARG, "got %#x\n", hr);
223 
224  for (i = 0; i < ARRAY_SIZE(parse_tests); i++)
225  {
226  hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, parse_tests[i].path, NULL, &pidl, NULL);
228  ok(hr == parse_tests[i].hr, "%s: expected %#x, got %#x\n",
230  if (SUCCEEDED(hr))
231  CoTaskMemFree(pidl);
232  }
233 
234  /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
235  * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
236  * out it doesn't. The magic seems to happen in the file dialogs, then. */
237 
239  ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
240 
241  hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, buffer, NULL, &pidl, 0);
242  ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
243 
244  ok(ILFindLastID(pidl)->mkid.abID[0] == 0x31,
245  "Last pidl should be of type PT_FOLDER, but is: %02x\n",
246  ILFindLastID(pidl)->mkid.abID[0]);
247  CoTaskMemFree(pidl);
248 
249  /* Relative paths are interpreted relative to the desktop. */
253  CreateDirectoryW(testdirW, NULL);
254 
255  hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, testdirW, NULL, &pidl, NULL);
256  ok(hr == 0x80070002, "got %#x\n", hr);
257 
258  RemoveDirectoryW(testdirW);
259 
261  ok(hr == S_FALSE, "got %#x\n", hr);
263  CreateDirectoryW(testdirW, NULL);
264 
265  hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, testdirW, NULL, &pidl, NULL);
266  ok(hr == S_OK, "got %#x\n", hr);
267 
268  ok(SHGetPathFromIDListW(pidl, buffer2), "SHGetPathFromIDList failed\n");
270  lstrcatW(buffer, testdirW);
271  ok(!lstrcmpW(buffer, buffer2), "expected %s, got %s\n", wine_dbgstr_w(buffer), wine_dbgstr_w(buffer2));
272 
273  RemoveDirectoryW(testdirW);
274  CoTaskMemFree(pidl);
275 
276  IShellFolder_Release(desktop);
277 }
278 
279 /* creates a file with the specified name for tests */
280 static void CreateTestFile(const CHAR *name)
281 {
282  HANDLE file;
283  DWORD written;
284 
286  if (file != INVALID_HANDLE_VALUE)
287  {
288  WriteFile(file, name, strlen(name), &written, NULL);
289  WriteFile(file, "\n", strlen("\n"), &written, NULL);
290  CloseHandle(file);
291  }
292 }
293 
294 
295 /* initializes the tests */
296 static void CreateFilesFolders(void)
297 {
298  CreateDirectoryA(".\\testdir", NULL);
299  CreateDirectoryA(".\\testdir\\test.txt", NULL);
300  CreateTestFile (".\\testdir\\test1.txt ");
301  CreateTestFile (".\\testdir\\test2.txt ");
302  CreateTestFile (".\\testdir\\test3.txt ");
303  CreateDirectoryA(".\\testdir\\testdir2 ", NULL);
304  CreateDirectoryA(".\\testdir\\testdir2\\subdir", NULL);
305 }
306 
307 /* cleans after tests */
308 static void Cleanup(void)
309 {
310  DeleteFileA(".\\testdir\\test1.txt");
311  DeleteFileA(".\\testdir\\test2.txt");
312  DeleteFileA(".\\testdir\\test3.txt");
313  RemoveDirectoryA(".\\testdir\\test.txt");
314  RemoveDirectoryA(".\\testdir\\testdir2\\subdir");
315  RemoveDirectoryA(".\\testdir\\testdir2");
316  RemoveDirectoryA(".\\testdir");
317 }
318 
319 
320 /* perform test */
321 static void test_EnumObjects(IShellFolder *iFolder)
322 {
323  IEnumIDList *iEnumList;
324  LPITEMIDLIST newPIDL, idlArr[10];
325  ULONG NumPIDLs;
326  int i=0, j;
327  HRESULT hr;
328 
329  static const WORD iResults [5][5] =
330  {
331  { 0,-1,-1,-1,-1},
332  { 1, 0,-1,-1,-1},
333  { 1, 1, 0,-1,-1},
334  { 1, 1, 1, 0,-1},
335  { 1, 1, 1, 1, 0}
336  };
337 
338 #define SFGAO_testfor SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CAPABILITYMASK
339  /* Don't test for SFGAO_HASSUBFOLDER since we return real state and native cached */
340  static const ULONG attrs[5] =
341  {
342  SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
343  SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
344  SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
345  SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
346  SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM,
347  };
348  static const ULONG full_attrs[5] =
349  {
350  SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
351  SFGAO_CAPABILITYMASK | SFGAO_STORAGE | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR,
352  SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
353  SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
354  SFGAO_CAPABILITYMASK | SFGAO_STREAM | SFGAO_FILESYSTEM,
355  };
356 
357  hr = IShellFolder_EnumObjects(iFolder, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &iEnumList);
358  ok(hr == S_OK, "EnumObjects failed %08x\n", hr);
359 
360  /* This is to show that, contrary to what is said on MSDN, on IEnumIDList::Next,
361  * the filesystem shellfolders return S_OK even if less than 'celt' items are
362  * returned (in contrast to S_FALSE). We have to do it in a loop since WinXP
363  * only ever returns a single entry per call. */
364  while (IEnumIDList_Next(iEnumList, 10-i, &idlArr[i], &NumPIDLs) == S_OK)
365  i += NumPIDLs;
366  ok (i == 5, "i: %d\n", i);
367 
368  hr = IEnumIDList_Release(iEnumList);
369  ok(hr == S_OK, "IEnumIDList_Release failed %08x\n", hr);
370 
371  /* Sort them first in case of wrong order from system */
372  for (i=0;i<5;i++) for (j=0;j<5;j++)
373  if ((SHORT)IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]) < 0)
374  {
375  newPIDL = idlArr[i];
376  idlArr[i] = idlArr[j];
377  idlArr[j] = newPIDL;
378  }
379 
380  for (i=0;i<5;i++) for (j=0;j<5;j++)
381  {
382  hr = IShellFolder_CompareIDs(iFolder, 0, idlArr[i], idlArr[j]);
383  ok(hr == iResults[i][j], "Got %x expected [%d]-[%d]=%x\n", hr, i, j, iResults[i][j]);
384  }
385 
386 
387  for (i = 0; i < 5; i++)
388  {
389  SFGAOF flags;
390 #define SFGAO_VISTA SFGAO_DROPTARGET | SFGAO_CANLINK | SFGAO_CANCOPY
391  /* Native returns all flags no matter what we ask for */
392  flags = SFGAO_CANCOPY;
393  hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
394  flags &= SFGAO_testfor;
395  ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
396  ok(flags == (attrs[i]) ||
397  flags == ((attrs[i] & ~SFGAO_CAPABILITYMASK) | SFGAO_VISTA), /* Vista and higher */
398  "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
399 
401  hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
402  flags &= SFGAO_testfor;
403  ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
404  ok(flags == attrs[i], "GetAttributesOf[%i] got %08x, expected %08x\n", i, flags, attrs[i]);
405 
406  flags = ~0u;
407  hr = IShellFolder_GetAttributesOf(iFolder, 1, (LPCITEMIDLIST*)(idlArr + i), &flags);
408  ok(hr == S_OK, "GetAttributesOf returns %08x\n", hr);
409  ok((flags & ~(SFGAO_HASSUBFOLDER|SFGAO_COMPRESSED)) == full_attrs[i], "%d: got %08x expected %08x\n", i, flags, full_attrs[i]);
410  }
411 
412  for (i=0;i<5;i++)
413  IMalloc_Free(ppM, idlArr[i]);
414 }
415 
416 static void test_BindToObject(void)
417 {
418  HRESULT hr;
419  UINT cChars;
420  IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
421  SHITEMID emptyitem = { 0, { 0 } };
422  LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
423  WCHAR wszSystemDir[MAX_PATH];
424  char szSystemDir[MAX_PATH];
425  char buf[MAX_PATH];
428  HANDLE hfile;
429  WCHAR wszMyComputer[] = {
430  ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
431  'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
432  static const CHAR filename_html[] = "winetest.html";
433  static const CHAR filename_txt[] = "winetest.txt";
434  static const CHAR filename_foo[] = "winetest.foo";
435 
436  /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
437  * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
438  */
439  hr = SHGetDesktopFolder(&psfDesktop);
440  ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
441  if (hr != S_OK) return;
442 
443  hr = IShellFolder_BindToObject(psfDesktop, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
444  ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
445 
446  hr = IShellFolder_BindToObject(psfDesktop, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
447  ok (hr == E_INVALIDARG, "Desktop's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
448 
449  hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
450  ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
451  if (hr != S_OK) {
452  IShellFolder_Release(psfDesktop);
453  return;
454  }
455 
456  hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
457  ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
458  IShellFolder_Release(psfDesktop);
459  IMalloc_Free(ppM, pidlMyComputer);
460  if (hr != S_OK) return;
461 
462  hr = IShellFolder_BindToObject(psfMyComputer, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
463  ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
464 
465  hr = IShellFolder_BindToObject(psfMyComputer, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
466  ok (hr == E_INVALIDARG, "MyComputers's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
467 
468  cChars = GetSystemDirectoryA(szSystemDir, MAX_PATH);
469  ok (cChars > 0 && cChars < MAX_PATH, "GetSystemDirectoryA failed! LastError: %u\n", GetLastError());
470  if (cChars == 0 || cChars >= MAX_PATH) {
471  IShellFolder_Release(psfMyComputer);
472  return;
473  }
474  MultiByteToWideChar(CP_ACP, 0, szSystemDir, -1, wszSystemDir, MAX_PATH);
475 
476  hr = IShellFolder_ParseDisplayName(psfMyComputer, NULL, NULL, wszSystemDir, NULL, &pidlSystemDir, NULL);
477  ok (hr == S_OK, "MyComputers's ParseDisplayName failed to parse the SystemDirectory! hr = %08x\n", hr);
478  if (hr != S_OK) {
479  IShellFolder_Release(psfMyComputer);
480  return;
481  }
482 
483  hr = IShellFolder_BindToObject(psfMyComputer, pidlSystemDir, NULL, &IID_IShellFolder, (LPVOID*)&psfSystemDir);
484  ok (hr == S_OK, "MyComputer failed to bind to a FileSystem ShellFolder! hr = %08x\n", hr);
485  IShellFolder_Release(psfMyComputer);
486  IMalloc_Free(ppM, pidlSystemDir);
487  if (hr != S_OK) return;
488 
489  hr = IShellFolder_BindToObject(psfSystemDir, pidlEmpty, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
490  ok (hr == E_INVALIDARG,
491  "FileSystem ShellFolder's BindToObject should fail, when called with empty pidl! hr = %08x\n", hr);
492 
493  hr = IShellFolder_BindToObject(psfSystemDir, NULL, NULL, &IID_IShellFolder, (LPVOID*)&psfChild);
494  ok (hr == E_INVALIDARG,
495  "FileSystem ShellFolder's BindToObject should fail, when called with NULL pidl! hr = %08x\n", hr);
496 
497  IShellFolder_Release(psfSystemDir);
498 
500  if(!cChars)
501  {
502  skip("Failed to get current directory, skipping tests.\n");
503  return;
504  }
505  if(buf[cChars-1] != '\\') lstrcatA(buf, "\\");
506 
507  SHGetDesktopFolder(&psfDesktop);
508 
509  /* Attempt BindToObject on files. */
510 
511  /* .html */
512  lstrcpyA(pathA, buf);
513  lstrcatA(pathA, filename_html);
515  if(hfile != INVALID_HANDLE_VALUE)
516  {
517  CloseHandle(hfile);
519  hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
520  ok(hr == S_OK, "Got 0x%08x\n", hr);
521  if(SUCCEEDED(hr))
522  {
523  hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
524  ok(hr == S_OK ||
525  hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
526  "Got 0x%08x\n", hr);
527  if(SUCCEEDED(hr))
528  {
529  IPersist *pp;
530  hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
531  ok(hr == S_OK, "Got 0x%08x\n", hr);
532  if(SUCCEEDED(hr))
533  {
534  CLSID id;
535  hr = IPersist_GetClassID(pp, &id);
536  ok(hr == S_OK, "Got 0x%08x\n", hr);
537  ok(IsEqualIID(&id, &CLSID_ShellDocObjView), "Unexpected classid %s\n", wine_dbgstr_guid(&id));
538  IPersist_Release(pp);
539  }
540 
541  IShellFolder_Release(psfChild);
542  }
543  ILFree(pidl);
544  }
546  }
547  else
548  win_skip("Failed to create .html testfile.\n");
549 
550  /* .txt */
551  lstrcpyA(pathA, buf);
552  lstrcatA(pathA, filename_txt);
554  if(hfile != INVALID_HANDLE_VALUE)
555  {
556  CloseHandle(hfile);
558  hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
559  ok(hr == S_OK, "Got 0x%08x\n", hr);
560  if(SUCCEEDED(hr))
561  {
562  hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
563  ok(hr == E_FAIL || /* Vista+ */
564  hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
565  "Got 0x%08x\n", hr);
566  if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
567  ILFree(pidl);
568  }
570  }
571  else
572  win_skip("Failed to create .txt testfile.\n");
573 
574  /* .foo */
575  lstrcpyA(pathA, buf);
576  lstrcatA(pathA, filename_foo);
578  if(hfile != INVALID_HANDLE_VALUE)
579  {
580  CloseHandle(hfile);
582  hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
583  ok(hr == S_OK, "Got 0x%08x\n", hr);
584  if(SUCCEEDED(hr))
585  {
586  hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
587  ok(hr == E_FAIL || /* Vista+ */
588  hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
589  "Got 0x%08x\n", hr);
590  if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
591  ILFree(pidl);
592  }
594  }
595  else
596  win_skip("Failed to create .foo testfile.\n");
597 
598  /* And on the desktop */
600  lstrcatA(pathA, "\\");
601  lstrcatA(pathA, filename_html);
603 
604  CloseHandle(hfile);
606  hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
607  ok(hr == S_OK, "Got 0x%08x\n", hr);
608 
609  hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void **)&psfChild);
610  ok(hr == S_OK ||
611  hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
612  "Got 0x%08x\n", hr);
613  if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
614  ILFree(pidl);
615  if(!DeleteFileA(pathA))
616  trace("Failed to delete: %d\n", GetLastError());
617 
619  lstrcatA(pathA, "\\");
620  lstrcatA(pathA, filename_foo);
622 
623  CloseHandle(hfile);
625  hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
626  ok(hr == S_OK, "Got 0x%08x\n", hr);
627 
628  hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void **)&psfChild);
629  ok(hr == E_FAIL || /* Vista+ */
630  hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
631  "Got 0x%08x\n", hr);
632  if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
633  ILFree(pidl);
635 
636  IShellFolder_Release(psfDesktop);
637 }
638 
639 static void test_GetDisplayName(void)
640 {
641  BOOL result;
642  HRESULT hr;
643  HANDLE hTestFile;
644  WCHAR wszTestFile[MAX_PATH], wszTestFile2[MAX_PATH];
645  char szTestFile[MAX_PATH], szTestDir[MAX_PATH];
646  DWORD attr;
647  STRRET strret;
648  LPSHELLFOLDER psfDesktop, psfPersonal;
649  IUnknown *psfFile;
650  SHITEMID emptyitem = { 0, { 0 } };
651  LPITEMIDLIST pidlTestFile, pidlEmpty = (LPITEMIDLIST)&emptyitem;
652  LPCITEMIDLIST pidlLast;
653  static const CHAR szFileName[] = "winetest.foo";
654  static const WCHAR wszFileName[] = { 'w','i','n','e','t','e','s','t','.','f','o','o',0 };
655  static const WCHAR wszDirName[] = { 'w','i','n','e','t','e','s','t',0 };
656 
657  /* It's ok to use this fixed path. Call will fail anyway. */
658  WCHAR wszAbsoluteFilename[] = { 'C',':','\\','w','i','n','e','t','e','s','t', 0 };
659  LPITEMIDLIST pidlNew;
660 
661  /* I'm trying to figure if there is a functional difference between calling
662  * SHGetPathFromIDListW and calling GetDisplayNameOf(SHGDN_FORPARSING) after
663  * binding to the shellfolder. One thing I thought of was that perhaps
664  * SHGetPathFromIDListW would be able to get the path to a file, which does
665  * not exist anymore, while the other method wouldn't. It turns out there's
666  * no functional difference in this respect.
667  */
668 
669  /* First creating a directory in MyDocuments and a file in this directory. */
671  ok(result, "SHGetSpecialFolderPathA failed! Last error: %u\n", GetLastError());
672  if (!result) return;
673 
674  /* Use ANSI file functions so this works on Windows 9x */
675  lstrcatA(szTestDir, "\\winetest");
676  CreateDirectoryA(szTestDir, NULL);
677  attr=GetFileAttributesA(szTestDir);
679  {
680  ok(0, "unable to create the '%s' directory\n", szTestDir);
681  return;
682  }
683 
684  lstrcpyA(szTestFile, szTestDir);
685  lstrcatA(szTestFile, "\\");
686  lstrcatA(szTestFile, szFileName);
687  hTestFile = CreateFileA(szTestFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
688  ok((hTestFile != INVALID_HANDLE_VALUE), "CreateFileA failed! Last error: %u\n", GetLastError());
689  if (hTestFile == INVALID_HANDLE_VALUE) return;
690  CloseHandle(hTestFile);
691 
692  /* Getting an itemidlist for the file. */
693  hr = SHGetDesktopFolder(&psfDesktop);
694  ok(hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
695  if (hr != S_OK) return;
696 
697  MultiByteToWideChar(CP_ACP, 0, szTestFile, -1, wszTestFile, MAX_PATH);
698 
699  hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
700  ok(hr == S_OK, "Desktop->ParseDisplayName failed! hr = %08x\n", hr);
701  if (hr != S_OK) {
702  IShellFolder_Release(psfDesktop);
703  return;
704  }
705 
706  pidlLast = ILFindLastID(pidlTestFile);
707  ok(pidlLast->mkid.cb >= 76, "Expected pidl length of at least 76, got %d.\n", pidlLast->mkid.cb);
708  if (pidlLast->mkid.cb >= 28) {
709  ok(!lstrcmpA((CHAR*)&pidlLast->mkid.abID[12], szFileName),
710  "Filename should be stored as ansi-string at this position!\n");
711  }
712  /* WinXP and up store the filenames as both ANSI and UNICODE in the pidls */
713  if (pidlLast->mkid.cb >= 76) {
714  ok(!lstrcmpW((WCHAR*)&pidlLast->mkid.abID[46], wszFileName) ||
715  (pidlLast->mkid.cb >= 94 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[64], wszFileName)) || /* Vista */
716  (pidlLast->mkid.cb >= 98 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[68], wszFileName)) || /* Win7 */
717  (pidlLast->mkid.cb >= 102 && !lstrcmpW((WCHAR*)&pidlLast->mkid.abID[72], wszFileName)), /* Win8 */
718  "Filename should be stored as wchar-string at this position!\n");
719  }
720 
721  /* It seems as if we cannot bind to regular files on windows, but only directories.
722  */
723  hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
725  hr == E_NOTIMPL, /* Vista */
726  "hr = %08x\n", hr);
727  if (hr == S_OK) {
728  IUnknown_Release(psfFile);
729  }
730 
731  /* Some tests for IShellFolder::SetNameOf */
732  hr = SHBindToParent(pidlTestFile, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
733  ok(hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
734 
735  /* The pidl returned through the last parameter of SetNameOf is a simple one. */
736  hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlLast, wszDirName, SHGDN_NORMAL, &pidlNew);
737  ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
738 
739  ok (((ITEMIDLIST *)((BYTE *)pidlNew + pidlNew->mkid.cb))->mkid.cb == 0,
740  "pidl returned from SetNameOf should be simple!\n");
741 
742  /* Passing an absolute path to SetNameOf fails. The HRESULT code indicates that SetNameOf
743  * is implemented on top of SHFileOperation in WinXP. */
744  hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszAbsoluteFilename, SHGDN_FORPARSING, NULL);
745  ok (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED), "SetNameOf succeeded! hr = %08x\n", hr);
746 
747  /* Rename the file back to its original name. SetNameOf ignores the fact, that the
748  * SHGDN flags specify an absolute path. */
749  hr = IShellFolder_SetNameOf(psfPersonal, NULL, pidlNew, wszFileName, SHGDN_FORPARSING, NULL);
750  ok (hr == S_OK, "SetNameOf failed! hr = %08x\n", hr);
751 
752  ILFree(pidlNew);
753  IShellFolder_Release(psfPersonal);
754 
755  /* Deleting the file and the directory */
756  DeleteFileA(szTestFile);
757  RemoveDirectoryA(szTestDir);
758 
759  /* SHGetPathFromIDListW still works, although the file is not present anymore. */
760  result = SHGetPathFromIDListW(pidlTestFile, wszTestFile2);
761  ok (result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
762  ok (!lstrcmpiW(wszTestFile, wszTestFile2), "SHGetPathFromIDListW returns incorrect path!\n");
763 
764  /* SHBindToParent fails, if called with a NULL PIDL. */
765  hr = SHBindToParent(NULL, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
766  ok (hr == E_INVALIDARG || broken(hr == E_OUTOFMEMORY) /* XP */,
767  "SHBindToParent(NULL) should fail! hr = %08x\n", hr);
768 
769  /* But it succeeds with an empty PIDL. */
770  hr = SHBindToParent(pidlEmpty, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
771  ok (hr == S_OK, "SHBindToParent(empty PIDL) should succeed! hr = %08x\n", hr);
772  ok (pidlLast == pidlEmpty, "The last element of an empty PIDL should be the PIDL itself!\n");
773  if (hr == S_OK)
774  IShellFolder_Release(psfPersonal);
775 
776  /* Binding to the folder and querying the display name of the file also works. */
777  hr = SHBindToParent(pidlTestFile, &IID_IShellFolder, (void **)&psfPersonal, &pidlLast);
778  ok (hr == S_OK, "SHBindToParent failed! hr = %08x\n", hr);
779  if (hr != S_OK) {
780  IShellFolder_Release(psfDesktop);
781  return;
782  }
783 
784  /* This test shows that Windows doesn't allocate a new pidlLast, but returns a pointer into
785  * pidlTestFile (In accordance with MSDN). */
786  ok (ILFindLastID(pidlTestFile) == pidlLast,
787  "SHBindToParent doesn't return the last id of the pidl param!\n");
788 
789  hr = IShellFolder_GetDisplayNameOf(psfPersonal, pidlLast, SHGDN_FORPARSING, &strret);
790  ok (hr == S_OK, "Personal->GetDisplayNameOf failed! hr = %08x\n", hr);
791  if (hr != S_OK) {
792  IShellFolder_Release(psfDesktop);
793  IShellFolder_Release(psfPersonal);
794  return;
795  }
796 
797  hr = StrRetToBufW(&strret, pidlLast, wszTestFile2, MAX_PATH);
798  ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
799  ok (!lstrcmpiW(wszTestFile, wszTestFile2), "GetDisplayNameOf returns incorrect path!\n");
800 
801  ILFree(pidlTestFile);
802  IShellFolder_Release(psfDesktop);
803  IShellFolder_Release(psfPersonal);
804 }
805 
806 static void test_CallForAttributes(void)
807 {
808  HKEY hKey;
809  LONG lResult;
810  HRESULT hr;
811  DWORD dwSize;
812  LPSHELLFOLDER psfDesktop;
813  LPITEMIDLIST pidlMyDocuments;
814  DWORD dwAttributes, dwCallForAttributes, dwOrigAttributes, dwOrigCallForAttributes;
815  static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 };
816  static const WCHAR wszCallForAttributes[] = {
817  'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 };
818  static const WCHAR wszMyDocumentsKey[] = {
819  'C','L','S','I','D','\\','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-',
820  '1','1','D','0','-','9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',
821  '\\','S','h','e','l','l','F','o','l','d','e','r',0 };
822  WCHAR wszMyDocuments[] = {
823  ':',':','{','4','5','0','D','8','F','B','A','-','A','D','2','5','-','1','1','D','0','-',
824  '9','8','A','8','-','0','8','0','0','3','6','1','B','1','1','0','3','}',0 };
825 
826  /* For the root of a namespace extension, the attributes are not queried by binding
827  * to the object and calling GetAttributesOf. Instead, the attributes are read from
828  * the registry value HKCR/CLSID/{...}/ShellFolder/Attributes. This is documented on MSDN.
829  *
830  * The MyDocuments shellfolder on WinXP has a HKCR/CLSID/{...}/ShellFolder/CallForAttributes
831  * value. It seems that if the folder is queried for one of the flags set in CallForAttributes,
832  * the shell does bind to the folder object and calls GetAttributesOf. This is not documented
833  * on MSDN. This test is meant to document the observed behaviour on WinXP SP2.
834  */
835  hr = SHGetDesktopFolder(&psfDesktop);
836  ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
837  if (hr != S_OK) return;
838 
839  hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyDocuments, NULL,
840  &pidlMyDocuments, NULL);
841  ok (hr == S_OK,
842  "Desktop's ParseDisplayName failed to parse MyDocuments's CLSID! hr = %08x\n", hr);
843  if (hr != S_OK) {
844  IShellFolder_Release(psfDesktop);
845  return;
846  }
847 
848  dwAttributes = 0xffffffff;
849  hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
850  (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
851  ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
852 
853  /* We need the following setup (as observed on WinXP SP2), for the tests to make sense. */
854  ok (dwAttributes & SFGAO_FILESYSTEM, "SFGAO_FILESYSTEM attribute is not set for MyDocuments!\n");
855  ok (!(dwAttributes & SFGAO_ISSLOW), "SFGAO_ISSLOW attribute is set for MyDocuments!\n");
856  ok (!(dwAttributes & SFGAO_GHOSTED), "SFGAO_GHOSTED attribute is set for MyDocuments!\n");
857 
858  /* We don't have the MyDocuments shellfolder in wine yet, and thus we don't have the registry
859  * key. So the test will return at this point, if run on wine.
860  */
861  lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszMyDocumentsKey, 0, KEY_WRITE|KEY_READ, &hKey);
862  ok (lResult == ERROR_SUCCESS ||
863  lResult == ERROR_ACCESS_DENIED,
864  "RegOpenKeyEx failed! result: %08x\n", lResult);
865  if (lResult != ERROR_SUCCESS) {
866  if (lResult == ERROR_ACCESS_DENIED)
867  skip("Not enough rights to open the registry key\n");
868  IMalloc_Free(ppM, pidlMyDocuments);
869  IShellFolder_Release(psfDesktop);
870  return;
871  }
872 
873  /* Query MyDocuments' Attributes value, to be able to restore it later. */
874  dwSize = sizeof(DWORD);
875  lResult = RegQueryValueExW(hKey, wszAttributes, NULL, NULL, (LPBYTE)&dwOrigAttributes, &dwSize);
876  ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
877  if (lResult != ERROR_SUCCESS) {
878  RegCloseKey(hKey);
879  IMalloc_Free(ppM, pidlMyDocuments);
880  IShellFolder_Release(psfDesktop);
881  return;
882  }
883 
884  /* Query MyDocuments' CallForAttributes value, to be able to restore it later. */
885  dwSize = sizeof(DWORD);
886  lResult = RegQueryValueExW(hKey, wszCallForAttributes, NULL, NULL,
887  (LPBYTE)&dwOrigCallForAttributes, &dwSize);
888  ok (lResult == ERROR_SUCCESS, "RegQueryValueEx failed! result: %08x\n", lResult);
889  if (lResult != ERROR_SUCCESS) {
890  RegCloseKey(hKey);
891  IMalloc_Free(ppM, pidlMyDocuments);
892  IShellFolder_Release(psfDesktop);
893  return;
894  }
895 
896  /* Define via the Attributes value that MyDocuments attributes are SFGAO_ISSLOW and
897  * SFGAO_GHOSTED and that MyDocuments should be called for the SFGAO_ISSLOW and
898  * SFGAO_FILESYSTEM attributes. */
899  dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED;
900  RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwAttributes, sizeof(DWORD));
901  dwCallForAttributes = SFGAO_ISSLOW|SFGAO_FILESYSTEM;
902  RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
903  (LPBYTE)&dwCallForAttributes, sizeof(DWORD));
904 
905  /* Although it is not set in CallForAttributes, the SFGAO_GHOSTED flag is reset by
906  * GetAttributesOf. It seems that once there is a single attribute queried, for which
907  * CallForAttributes is set, all flags are taken from the GetAttributesOf call and
908  * the flags in Attributes are ignored.
909  */
910  dwAttributes = SFGAO_ISSLOW|SFGAO_GHOSTED|SFGAO_FILESYSTEM;
911  hr = IShellFolder_GetAttributesOf(psfDesktop, 1,
912  (LPCITEMIDLIST*)&pidlMyDocuments, &dwAttributes);
913  ok (hr == S_OK, "Desktop->GetAttributesOf(MyDocuments) failed! hr = %08x\n", hr);
914  if (hr == S_OK)
915  ok (dwAttributes == SFGAO_FILESYSTEM,
916  "Desktop->GetAttributes(MyDocuments) returned unexpected attributes: %08x\n",
917  dwAttributes);
918 
919  /* Restore MyDocuments' original Attributes and CallForAttributes registry values */
920  RegSetValueExW(hKey, wszAttributes, 0, REG_DWORD, (LPBYTE)&dwOrigAttributes, sizeof(DWORD));
921  RegSetValueExW(hKey, wszCallForAttributes, 0, REG_DWORD,
922  (LPBYTE)&dwOrigCallForAttributes, sizeof(DWORD));
923  RegCloseKey(hKey);
924  IMalloc_Free(ppM, pidlMyDocuments);
925  IShellFolder_Release(psfDesktop);
926 }
927 
928 static void test_GetAttributesOf(void)
929 {
930  HRESULT hr;
931  LPSHELLFOLDER psfDesktop, psfMyComputer;
932  SHITEMID emptyitem = { 0, { 0 } };
933  LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
934  LPITEMIDLIST pidlMyComputer;
935  DWORD dwFlags;
936  static const DWORD desktopFlags = SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
937  SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER;
938  static const DWORD myComputerFlags = SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET |
939  SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
940  WCHAR wszMyComputer[] = {
941  ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
942  'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
943  char cCurrDirA [MAX_PATH] = {0};
944  WCHAR cCurrDirW [MAX_PATH];
945  static WCHAR cTestDirW[] = {'t','e','s','t','d','i','r',0};
946  IShellFolder *IDesktopFolder, *testIShellFolder;
947  ITEMIDLIST *newPIDL;
948  int len;
949 
950  hr = SHGetDesktopFolder(&psfDesktop);
951  ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
952  if (hr != S_OK) return;
953 
954  /* The Desktop attributes can be queried with a single empty itemidlist, .. */
955  dwFlags = 0xffffffff;
956  hr = IShellFolder_GetAttributesOf(psfDesktop, 1, &pidlEmpty, &dwFlags);
957  ok (hr == S_OK, "Desktop->GetAttributesOf(empty pidl) failed! hr = %08x\n", hr);
958  ok (dwFlags == desktopFlags, "Wrong Desktop attributes: %08x\n", dwFlags);
959 
960  /* .. or with no itemidlist at all. */
961  dwFlags = 0xffffffff;
962  hr = IShellFolder_GetAttributesOf(psfDesktop, 0, NULL, &dwFlags);
963  ok (hr == S_OK, "Desktop->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
964  ok (dwFlags == desktopFlags, "Wrong Desktop attributes: %08x\n", dwFlags);
965 
966  /* Testing the attributes of the MyComputer shellfolder */
967  hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
968  ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
969  if (hr != S_OK) {
970  IShellFolder_Release(psfDesktop);
971  return;
972  }
973 
974  /* Windows sets the SFGAO_CANLINK flag, when MyComputer is queried via the Desktop
975  * folder object. It doesn't do this, if MyComputer is queried directly (see below).
976  */
977  dwFlags = 0xffffffff;
978  hr = IShellFolder_GetAttributesOf(psfDesktop, 1, (LPCITEMIDLIST*)&pidlMyComputer, &dwFlags);
979  ok (hr == S_OK, "Desktop->GetAttributesOf(MyComputer) failed! hr = %08x\n", hr);
980  todo_wine
981  ok (dwFlags == (myComputerFlags | SFGAO_CANLINK), "Wrong MyComputer attributes: %08x\n", dwFlags);
982 
983  hr = IShellFolder_BindToObject(psfDesktop, pidlMyComputer, NULL, &IID_IShellFolder, (LPVOID*)&psfMyComputer);
984  ok (hr == S_OK, "Desktop failed to bind to MyComputer object! hr = %08x\n", hr);
985  IShellFolder_Release(psfDesktop);
986  IMalloc_Free(ppM, pidlMyComputer);
987  if (hr != S_OK) return;
988 
989  hr = IShellFolder_GetAttributesOf(psfMyComputer, 1, &pidlEmpty, &dwFlags);
990  todo_wine
991  ok (hr == E_INVALIDARG, "MyComputer->GetAttributesOf(empty pidl) should fail! hr = %08x\n", hr);
992 
993  dwFlags = 0xffffffff;
994  hr = IShellFolder_GetAttributesOf(psfMyComputer, 0, NULL, &dwFlags);
995  ok (hr == S_OK, "MyComputer->GetAttributesOf(NULL) failed! hr = %08x\n", hr);
996  todo_wine
997  ok (dwFlags == myComputerFlags, "Wrong MyComputer attributes: %08x\n", dwFlags);
998 
999  IShellFolder_Release(psfMyComputer);
1000 
1001  GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1002  len = lstrlenA(cCurrDirA);
1003 
1004  if (len == 0) {
1005  win_skip("GetCurrentDirectoryA returned empty string. Skipping test_GetAttributesOf\n");
1006  return;
1007  }
1008  if (len > 3 && cCurrDirA[len-1] == '\\')
1009  cCurrDirA[len-1] = 0;
1010 
1011  /* create test directory */
1013 
1014  MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1015 
1016  hr = SHGetDesktopFolder(&IDesktopFolder);
1017  ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1018 
1019  hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1020  ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1021 
1022  hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1023  ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1024 
1025  IMalloc_Free(ppM, newPIDL);
1026 
1027  /* get relative PIDL */
1028  hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1029  ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1030 
1031  /* test the shell attributes of the test directory using the relative PIDL */
1032  dwFlags = SFGAO_FOLDER;
1033  hr = IShellFolder_GetAttributesOf(testIShellFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1034  ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1035  ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for relative PIDL: %08x\n", dwFlags);
1036 
1037  /* free memory */
1038  IMalloc_Free(ppM, newPIDL);
1039 
1040  /* append testdirectory name to path */
1041  if (cCurrDirA[len-1] == '\\')
1042  cCurrDirA[len-1] = 0;
1043  lstrcatA(cCurrDirA, "\\testdir");
1044  MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1045 
1046  hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1047  ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1048 
1049  /* test the shell attributes of the test directory using the absolute PIDL */
1050  dwFlags = SFGAO_FOLDER;
1051  hr = IShellFolder_GetAttributesOf(IDesktopFolder, 1, (LPCITEMIDLIST*)&newPIDL, &dwFlags);
1052  ok (hr == S_OK, "Desktop->GetAttributesOf() failed! hr = %08x\n", hr);
1053  ok ((dwFlags&SFGAO_FOLDER), "Wrong directory attribute for absolute PIDL: %08x\n", dwFlags);
1054 
1055  /* free memory */
1056  IMalloc_Free(ppM, newPIDL);
1057 
1058  IShellFolder_Release(testIShellFolder);
1059 
1060  Cleanup();
1061 
1062  IShellFolder_Release(IDesktopFolder);
1063 }
1064 
1065 static void test_SHGetPathFromIDList(void)
1066 {
1067  SHITEMID emptyitem = { 0, { 0 } };
1068  LPCITEMIDLIST pidlEmpty = (LPCITEMIDLIST)&emptyitem;
1069  LPITEMIDLIST pidlMyComputer;
1070  WCHAR wszPath[MAX_PATH], wszDesktop[MAX_PATH];
1071  BOOL result;
1072  HRESULT hr;
1073  LPSHELLFOLDER psfDesktop;
1074  WCHAR wszMyComputer[] = {
1075  ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
1076  'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
1078  LPITEMIDLIST pidlTestFile;
1079  HANDLE hTestFile;
1080  STRRET strret;
1081  static WCHAR wszTestFile[] = {
1082  'w','i','n','e','t','e','s','t','.','f','o','o',0 };
1083  LPITEMIDLIST pidlPrograms;
1084 
1085  /* Calling SHGetPathFromIDListW with no pidl should return the empty string */
1086  wszPath[0] = 'a';
1087  wszPath[1] = '\0';
1088  result = SHGetPathFromIDListW(NULL, wszPath);
1089  ok(!result, "Expected failure\n");
1090  ok(!wszPath[0], "Expected empty string\n");
1091 
1092  /* Calling SHGetPathFromIDListW with an empty pidl should return the desktop folder's path. */
1094  ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOP) failed! Last error: %u\n", GetLastError());
1095  if (!result) return;
1096 
1097  result = SHGetPathFromIDListW(pidlEmpty, wszPath);
1098  ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1099  if (!result) return;
1100  ok(!lstrcmpiW(wszDesktop, wszPath), "SHGetPathFromIDListW didn't return desktop path for empty pidl!\n");
1101 
1102  /* MyComputer does not map to a filesystem path. SHGetPathFromIDListW should fail. */
1103  hr = SHGetDesktopFolder(&psfDesktop);
1104  ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1105  if (hr != S_OK) return;
1106 
1107  hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszMyComputer, NULL, &pidlMyComputer, NULL);
1108  ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse MyComputer's CLSID! hr = %08x\n", hr);
1109  if (hr != S_OK) {
1110  IShellFolder_Release(psfDesktop);
1111  return;
1112  }
1113 
1114  SetLastError(0xdeadbeef);
1115  wszPath[0] = 'a';
1116  wszPath[1] = '\0';
1117  result = SHGetPathFromIDListW(pidlMyComputer, wszPath);
1118  ok (!result, "SHGetPathFromIDListW succeeded where it shouldn't!\n");
1119  ok (GetLastError()==0xdeadbeef ||
1120  GetLastError()==ERROR_SUCCESS, /* Vista and higher */
1121  "Unexpected last error from SHGetPathFromIDListW: %u\n", GetLastError());
1122  ok (!wszPath[0], "Expected empty path\n");
1123  if (result) {
1124  IShellFolder_Release(psfDesktop);
1125  return;
1126  }
1127 
1128  IMalloc_Free(ppM, pidlMyComputer);
1129 
1131  ok(result, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1132  if (!result) {
1133  IShellFolder_Release(psfDesktop);
1134  return;
1135  }
1137  lstrcatW(wszFileName, wszTestFile);
1138  hTestFile = CreateFileW(wszFileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
1139  ok(hTestFile != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: %u\n", GetLastError());
1140  if (hTestFile == INVALID_HANDLE_VALUE) {
1141  IShellFolder_Release(psfDesktop);
1142  return;
1143  }
1144  CloseHandle(hTestFile);
1145 
1146  hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszTestFile, NULL, &pidlTestFile, NULL);
1147  ok (hr == S_OK, "Desktop's ParseDisplayName failed to parse filename hr = %08x\n", hr);
1148  if (hr != S_OK) {
1149  IShellFolder_Release(psfDesktop);
1151  IMalloc_Free(ppM, pidlTestFile);
1152  return;
1153  }
1154 
1155  /* This test is to show that the Desktop shellfolder prepends the CSIDL_DESKTOPDIRECTORY
1156  * path for files placed on the desktop, if called with SHGDN_FORPARSING. */
1157  hr = IShellFolder_GetDisplayNameOf(psfDesktop, pidlTestFile, SHGDN_FORPARSING, &strret);
1158  ok (hr == S_OK, "Desktop's GetDisplayNamfOf failed! hr = %08x\n", hr);
1159  IShellFolder_Release(psfDesktop);
1161  if (hr != S_OK) {
1162  IMalloc_Free(ppM, pidlTestFile);
1163  return;
1164  }
1165  StrRetToBufW(&strret, pidlTestFile, wszPath, MAX_PATH);
1166  ok(0 == lstrcmpW(wszFileName, wszPath),
1167  "Desktop->GetDisplayNameOf(pidlTestFile, SHGDN_FORPARSING) "
1168  "returned incorrect path for file placed on desktop\n");
1169 
1170  result = SHGetPathFromIDListW(pidlTestFile, wszPath);
1171  ok(result, "SHGetPathFromIDListW failed! Last error: %u\n", GetLastError());
1172  ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
1173 
1174  if (pSHGetPathFromIDListEx)
1175  {
1176  result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1177  ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1178  ok(!lstrcmpiW(wszDesktop, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1179  wine_dbgstr_w(wszPath), wine_dbgstr_w(wszDesktop));
1180 
1181  result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, MAX_PATH, SFGAO_FILESYSTEM);
1182  ok(result, "SHGetPathFromIDListEx failed: %u\n", GetLastError());
1183  ok(!lstrcmpiW(wszFileName, wszPath), "Unexpected SHGetPathFromIDListEx result %s, expected %s\n",
1185 
1186  SetLastError(0xdeadbeef);
1187  memset(wszPath, 0x55, sizeof(wszPath));
1188  result = pSHGetPathFromIDListEx(pidlTestFile, wszPath, 5, SFGAO_FILESYSTEM);
1189  ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1190 
1191  SetLastError(0xdeadbeef);
1192  memset(wszPath, 0x55, sizeof(wszPath));
1193  result = pSHGetPathFromIDListEx(pidlEmpty, wszPath, 5, SFGAO_FILESYSTEM);
1194  ok(!result, "SHGetPathFromIDListEx returned: %x(%u)\n", result, GetLastError());
1195  }
1196  else
1197  win_skip("SHGetPathFromIDListEx not available\n");
1198 
1199  IMalloc_Free(ppM, pidlTestFile);
1200 
1201  /* Test if we can get the path from the start menu "program files" PIDL. */
1203  ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
1204 
1205  SetLastError(0xdeadbeef);
1206  result = SHGetPathFromIDListW(pidlPrograms, wszPath);
1207  IMalloc_Free(ppM, pidlPrograms);
1208  ok(result, "SHGetPathFromIDListW failed\n");
1209 }
1210 
1212 {
1213  ITEMIDLIST *newPIDL;
1214  IShellFolder *IDesktopFolder, *testIShellFolder;
1215  char cCurrDirA [MAX_PATH] = {0};
1216  static const CHAR cTestDirA[] = "\\testdir";
1217  WCHAR cTestDirW[MAX_PATH];
1218  int len;
1219  HRESULT hr;
1220 
1221  GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1222  len = lstrlenA(cCurrDirA);
1223 
1224  if(len == 0) {
1225  win_skip("GetCurrentDirectoryA returned empty string. Skipping test_EnumObjects_and_CompareIDs\n");
1226  return;
1227  }
1228  if(cCurrDirA[len-1] == '\\')
1229  cCurrDirA[len-1] = 0;
1230 
1231  lstrcatA(cCurrDirA, cTestDirA);
1232  MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cTestDirW, MAX_PATH);
1233 
1234  hr = SHGetDesktopFolder(&IDesktopFolder);
1235  ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1236 
1238 
1239  hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
1240  ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1241 
1242  hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1243  ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1244 
1245  test_EnumObjects(testIShellFolder);
1246 
1247  IShellFolder_Release(testIShellFolder);
1248 
1249  Cleanup();
1250 
1251  IMalloc_Free(ppM, newPIDL);
1252 
1253  IShellFolder_Release(IDesktopFolder);
1254 }
1255 
1256 /* A simple implementation of an IPropertyBag, which returns fixed values for
1257  * 'Target' and 'Attributes' properties.
1258  */
1260  void **ppvObject)
1261 {
1262  if (!ppvObject)
1263  return E_INVALIDARG;
1264 
1266  *ppvObject = iface;
1267  } else {
1268  ok (FALSE, "InitPropertyBag asked for unknown interface!\n");
1269  return E_NOINTERFACE;
1270  }
1271 
1272  IPropertyBag_AddRef(iface);
1273  return S_OK;
1274 }
1275 
1277  return 2;
1278 }
1279 
1281  return 1;
1282 }
1283 
1284 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Read(IPropertyBag *iface, LPCOLESTR pszPropName,
1285  VARIANT *pVar, IErrorLog *pErrorLog)
1286 {
1287  static const WCHAR wszTargetSpecialFolder[] = {
1288  'T','a','r','g','e','t','S','p','e','c','i','a','l','F','o','l','d','e','r',0 };
1289  static const WCHAR wszTarget[] = {
1290  'T','a','r','g','e','t',0 };
1291  static const WCHAR wszAttributes[] = {
1292  'A','t','t','r','i','b','u','t','e','s',0 };
1293  static const WCHAR wszResolveLinkFlags[] = {
1294  'R','e','s','o','l','v','e','L','i','n','k','F','l','a','g','s',0 };
1295  static const WCHAR wszTargetKnownFolder[] = {
1296  'T','a','r','g','e','t','K','n','o','w','n','F','o','l','d','e','r',0 };
1297  static const WCHAR wszCLSID[] = {
1298  'C','L','S','I','D',0 };
1299 
1300  if (!lstrcmpW(pszPropName, wszTargetSpecialFolder)) {
1301  ok(V_VT(pVar) == VT_I4, "Wrong variant type for 'TargetSpecialFolder' property!\n");
1302  return E_INVALIDARG;
1303  }
1304 
1305  if (!lstrcmpW(pszPropName, wszResolveLinkFlags))
1306  {
1307  ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'ResolveLinkFlags' property!\n");
1308  return E_INVALIDARG;
1309  }
1310 
1311  if (!lstrcmpW(pszPropName, wszTarget)) {
1312  WCHAR wszPath[MAX_PATH];
1313  BOOL result;
1314 
1315  ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'Target' property!\n");
1316  if (V_VT(pVar) != VT_BSTR) return E_INVALIDARG;
1317 
1319  ok(result, "SHGetSpecialFolderPathW(DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1320  if (!result) return E_INVALIDARG;
1321 
1322  V_BSTR(pVar) = SysAllocString(wszPath);
1323  return S_OK;
1324  }
1325 
1326  if (!lstrcmpW(pszPropName, wszAttributes)) {
1327  ok(V_VT(pVar) == VT_UI4, "Wrong variant type for 'Attributes' property!\n");
1328  if (V_VT(pVar) != VT_UI4) return E_INVALIDARG;
1329  V_UI4(pVar) = SFGAO_FOLDER|SFGAO_HASSUBFOLDER|SFGAO_FILESYSANCESTOR|
1330  SFGAO_CANRENAME|SFGAO_FILESYSTEM;
1331  return S_OK;
1332  }
1333 
1334  if (!lstrcmpW(pszPropName, wszTargetKnownFolder)) {
1335  ok(V_VT(pVar) == VT_BSTR, "Wrong variant type for 'TargetKnownFolder' property!\n");
1336  /* TODO */
1337  return E_INVALIDARG;
1338  }
1339 
1340  if (!lstrcmpW(pszPropName, wszCLSID)) {
1341  ok(V_VT(pVar) == VT_EMPTY, "Wrong variant type for 'CLSID' property!\n");
1342  /* TODO */
1343  return E_INVALIDARG;
1344  }
1345 
1346  ok(FALSE, "PropertyBag was asked for unknown property %s (vt=%d)!\n", wine_dbgstr_w(pszPropName), V_VT(pVar));
1347  return E_INVALIDARG;
1348 }
1349 
1350 static HRESULT WINAPI InitPropertyBag_IPropertyBag_Write(IPropertyBag *iface, LPCOLESTR pszPropName,
1351  VARIANT *pVar)
1352 {
1353  ok(FALSE, "Unexpected call to IPropertyBag_Write\n");
1354  return E_NOTIMPL;
1355 }
1356 
1357 static const IPropertyBagVtbl InitPropertyBag_IPropertyBagVtbl = {
1363 };
1364 
1367 };
1368 
1369 static void test_FolderShortcut(void) {
1370  IPersistPropertyBag *pPersistPropertyBag;
1371  IShellFolder *pShellFolder, *pDesktopFolder;
1372  IPersistFolder3 *pPersistFolder3;
1373  HRESULT hr;
1374  STRRET strret;
1375  WCHAR wszDesktopPath[MAX_PATH], wszBuffer[MAX_PATH];
1376  BOOL result;
1377  CLSID clsid;
1378  LPITEMIDLIST pidlCurrentFolder, pidlWineTestFolder, pidlSubFolder;
1379  HKEY hShellExtKey;
1380  WCHAR wszWineTestFolder[] = {
1381  ':',':','{','9','B','3','5','2','E','B','F','-','2','7','6','5','-','4','5','C','1','-',
1382  'B','4','C','6','-','8','5','C','C','7','F','7','A','B','C','6','4','}',0 };
1383  WCHAR wszShellExtKey[] = { 'S','o','f','t','w','a','r','e','\\',
1384  'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
1385  'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1386  'E','x','p','l','o','r','e','r','\\','D','e','s','k','t','o','p','\\',
1387  'N','a','m','e','S','p','a','c','e','\\',
1388  '{','9','b','3','5','2','e','b','f','-','2','7','6','5','-','4','5','c','1','-',
1389  'b','4','c','6','-','8','5','c','c','7','f','7','a','b','c','6','4','}',0 };
1390 
1391  WCHAR wszSomeSubFolder[] = { 'S','u','b','F','o','l','d','e','r', 0};
1392  static const GUID CLSID_UnixDosFolder =
1393  {0x9d20aae8, 0x0625, 0x44b0, {0x9c, 0xa7, 0x71, 0x88, 0x9c, 0x22, 0x54, 0xd9}};
1394 
1395  /* These tests basically show, that CLSID_FolderShortcuts are initialized
1396  * via their IPersistPropertyBag interface. And that the target folder
1397  * is taken from the IPropertyBag's 'Target' property.
1398  */
1399  hr = CoCreateInstance(&CLSID_FolderShortcut, NULL, CLSCTX_INPROC_SERVER,
1400  &IID_IPersistPropertyBag, (LPVOID*)&pPersistPropertyBag);
1401  if (hr == REGDB_E_CLASSNOTREG) {
1402  win_skip("CLSID_FolderShortcut is not implemented\n");
1403  return;
1404  }
1405  ok (hr == S_OK, "CoCreateInstance failed! hr = 0x%08x\n", hr);
1406  if (hr != S_OK) return;
1407 
1408  hr = IPersistPropertyBag_Load(pPersistPropertyBag, &InitPropertyBag, NULL);
1409  ok(hr == S_OK, "IPersistPropertyBag_Load failed! hr = %08x\n", hr);
1410  if (hr != S_OK) {
1411  IPersistPropertyBag_Release(pPersistPropertyBag);
1412  return;
1413  }
1414 
1415  hr = IPersistPropertyBag_QueryInterface(pPersistPropertyBag, &IID_IShellFolder,
1416  (LPVOID*)&pShellFolder);
1417  IPersistPropertyBag_Release(pPersistPropertyBag);
1418  ok(hr == S_OK, "IPersistPropertyBag_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1419  if (hr != S_OK) return;
1420 
1421  hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1422  ok(hr == S_OK || broken(hr == E_INVALIDARG) /* win10 */,
1423  "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1424  if (hr != S_OK) {
1425  IShellFolder_Release(pShellFolder);
1426  return;
1427  }
1428 
1430  ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
1431  if (!result) return;
1432 
1433  StrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1434  ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1435 
1436  hr = IShellFolder_QueryInterface(pShellFolder, &IID_IPersistFolder3, (LPVOID*)&pPersistFolder3);
1437  IShellFolder_Release(pShellFolder);
1438  ok(hr == S_OK, "IShellFolder_QueryInterface(IID_IPersistFolder3 failed! hr = 0x%08x\n", hr);
1439  if (hr != S_OK) return;
1440 
1441  hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1442  ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1443  ok(IsEqualCLSID(&clsid, &CLSID_FolderShortcut), "Unexpected CLSID!\n");
1444 
1445  hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1446  todo_wine ok(hr == S_FALSE, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1447  ok(!pidlCurrentFolder, "IPersistFolder3_GetCurFolder should return a NULL pidl!\n");
1448 
1449  /* For FolderShortcut objects, the Initialize method initialized the folder's position in the
1450  * shell namespace. The target folder, read from the property bag above, remains untouched.
1451  * The following tests show this: The itemidlist for some imaginary shellfolder object
1452  * is created and the FolderShortcut is initialized with it. GetCurFolder now returns this
1453  * itemidlist, but GetDisplayNameOf still returns the path from above.
1454  */
1455  hr = SHGetDesktopFolder(&pDesktopFolder);
1456  ok (hr == S_OK, "SHGetDesktopFolder failed! hr = %08x\n", hr);
1457  if (hr != S_OK) return;
1458 
1459  /* Temporarily register WineTestFolder as a shell namespace extension at the Desktop.
1460  * Otherwise ParseDisplayName fails on WinXP with E_INVALIDARG */
1461  RegCreateKeyW(HKEY_CURRENT_USER, wszShellExtKey, &hShellExtKey);
1462  RegCloseKey(hShellExtKey);
1463  hr = IShellFolder_ParseDisplayName(pDesktopFolder, NULL, NULL, wszWineTestFolder, NULL,
1464  &pidlWineTestFolder, NULL);
1465  RegDeleteKeyW(HKEY_CURRENT_USER, wszShellExtKey);
1466  IShellFolder_Release(pDesktopFolder);
1467  ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1468  if (hr != S_OK) return;
1469 
1470  hr = IPersistFolder3_Initialize(pPersistFolder3, pidlWineTestFolder);
1471  ok (hr == S_OK, "IPersistFolder3::Initialize failed! hr = %08x\n", hr);
1472  if (hr != S_OK) {
1473  IPersistFolder3_Release(pPersistFolder3);
1474  ILFree(pidlWineTestFolder);
1475  return;
1476  }
1477 
1478  hr = IPersistFolder3_GetCurFolder(pPersistFolder3, &pidlCurrentFolder);
1479  ok(hr == S_OK, "IPersistFolder3_GetCurFolder failed! hr=0x%08x\n", hr);
1480  ok(ILIsEqual(pidlCurrentFolder, pidlWineTestFolder),
1481  "IPersistFolder3_GetCurFolder should return pidlWineTestFolder!\n");
1482  ILFree(pidlCurrentFolder);
1483  ILFree(pidlWineTestFolder);
1484 
1485  hr = IPersistFolder3_QueryInterface(pPersistFolder3, &IID_IShellFolder, (LPVOID*)&pShellFolder);
1486  IPersistFolder3_Release(pPersistFolder3);
1487  ok(hr == S_OK, "IPersistFolder3_QueryInterface(IShellFolder) failed! hr = %08x\n", hr);
1488  if (hr != S_OK) return;
1489 
1490  hr = IShellFolder_GetDisplayNameOf(pShellFolder, NULL, SHGDN_FORPARSING, &strret);
1491  ok(hr == S_OK, "IShellFolder_GetDisplayNameOf(NULL) failed! hr = %08x\n", hr);
1492  if (hr != S_OK) {
1493  IShellFolder_Release(pShellFolder);
1494  return;
1495  }
1496 
1497  StrRetToBufW(&strret, NULL, wszBuffer, MAX_PATH);
1498  ok(!lstrcmpiW(wszDesktopPath, wszBuffer), "FolderShortcut returned incorrect folder!\n");
1499 
1500  /* Next few lines are meant to show that children of FolderShortcuts are not FolderShortcuts,
1501  * but ShellFSFolders. */
1502  myPathAddBackslashW(wszDesktopPath);
1503  lstrcatW(wszDesktopPath, wszSomeSubFolder);
1504  if (!CreateDirectoryW(wszDesktopPath, NULL)) {
1505  IShellFolder_Release(pShellFolder);
1506  return;
1507  }
1508 
1509  hr = IShellFolder_ParseDisplayName(pShellFolder, NULL, NULL, wszSomeSubFolder, NULL,
1510  &pidlSubFolder, NULL);
1511  RemoveDirectoryW(wszDesktopPath);
1512  ok (hr == S_OK, "IShellFolder::ParseDisplayName failed! hr = %08x\n", hr);
1513  if (hr != S_OK) {
1514  IShellFolder_Release(pShellFolder);
1515  return;
1516  }
1517 
1518  hr = IShellFolder_BindToObject(pShellFolder, pidlSubFolder, NULL, &IID_IPersistFolder3,
1519  (LPVOID*)&pPersistFolder3);
1520  IShellFolder_Release(pShellFolder);
1521  ILFree(pidlSubFolder);
1522  ok (hr == S_OK, "IShellFolder::BindToObject failed! hr = %08x\n", hr);
1523  if (hr != S_OK)
1524  return;
1525 
1526  /* On windows, we expect CLSID_ShellFSFolder. On wine we relax this constraint
1527  * a little bit and also allow CLSID_UnixDosFolder. */
1528  hr = IPersistFolder3_GetClassID(pPersistFolder3, &clsid);
1529  ok(hr == S_OK, "IPersistFolder3_GetClassID failed! hr=0x%08x\n", hr);
1530  ok(IsEqualCLSID(&clsid, &CLSID_ShellFSFolder) || IsEqualCLSID(&clsid, &CLSID_UnixDosFolder),
1531  "IPersistFolder3::GetClassID returned unexpected CLSID!\n");
1532 
1533  IPersistFolder3_Release(pPersistFolder3);
1534 }
1535 
1536 #include "pshpack1.h"
1537 struct FileStructA {
1541  WORD uFileDate; /* In our current implementation this is */
1542  WORD uFileTime; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastWriteTime) */
1545 };
1546 
1547 struct FileStructW {
1548  WORD cbLen; /* Length of this element. */
1549  BYTE abFooBar1[6]; /* Beyond any recognition. */
1550  WORD uDate; /* FileTimeToDosDate(WIN32_FIND_DATA->ftCreationTime)? */
1551  WORD uTime; /* (this is currently speculation) */
1552  WORD uDate2; /* FileTimeToDosDate(WIN32_FIND_DATA->ftLastAccessTime)? */
1553  WORD uTime2; /* (this is currently speculation) */
1554  BYTE abFooBar2[4]; /* Beyond any recognition. */
1555  WCHAR wszName[1]; /* The long filename in unicode. */
1556  /* Just for documentation: Right after the unicode string: */
1557  WORD cbOffset; /* FileStructW's offset from the beginning of the SHITMEID.
1558  * SHITEMID->cb == uOffset + cbLen */
1559 };
1560 #include "poppack.h"
1561 
1562 static void test_ITEMIDLIST_format(void) {
1563  WCHAR wszPersonal[MAX_PATH];
1564  LPSHELLFOLDER psfDesktop, psfPersonal;
1565  LPITEMIDLIST pidlPersonal, pidlFile;
1566  HANDLE hFile;
1567  HRESULT hr;
1568  BOOL bResult;
1569  WCHAR wszFile[3][17] = { { 'e','v','e','n','_',0 }, { 'o','d','d','_',0 },
1570  { 'l','o','n','g','e','r','_','t','h','a','n','.','8','_','3',0 } };
1571  int i;
1572 
1573  bResult = SHGetSpecialFolderPathW(NULL, wszPersonal, CSIDL_PERSONAL, FALSE);
1574  ok(bResult, "SHGetSpecialFolderPathW failed! Last error: %u\n", GetLastError());
1575  if (!bResult) return;
1576 
1577  SetLastError(0xdeadbeef);
1578  bResult = SetCurrentDirectoryW(wszPersonal);
1579  if (!bResult && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
1580  win_skip("Most W-calls are not implemented\n");
1581  return;
1582  }
1583  ok(bResult, "SetCurrentDirectory failed! Last error: %u\n", GetLastError());
1584  if (!bResult) return;
1585 
1586  hr = SHGetDesktopFolder(&psfDesktop);
1587  ok(hr == S_OK, "SHGetDesktopFolder failed! hr: %08x\n", hr);
1588  if (hr != S_OK) return;
1589 
1590  hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, wszPersonal, NULL, &pidlPersonal, NULL);
1591  ok(hr == S_OK, "psfDesktop->ParseDisplayName failed! hr = %08x\n", hr);
1592  if (hr != S_OK) {
1593  IShellFolder_Release(psfDesktop);
1594  return;
1595  }
1596 
1597  hr = IShellFolder_BindToObject(psfDesktop, pidlPersonal, NULL, &IID_IShellFolder,
1598  (LPVOID*)&psfPersonal);
1599  IShellFolder_Release(psfDesktop);
1600  ILFree(pidlPersonal);
1601  ok(hr == S_OK, "psfDesktop->BindToObject failed! hr = %08x\n", hr);
1602  if (hr != S_OK) return;
1603 
1604  for (i=0; i<3; i++) {
1605  CHAR szFile[MAX_PATH];
1606  struct FileStructA *pFileStructA;
1607  WORD cbOffset;
1608 
1609  WideCharToMultiByte(CP_ACP, 0, wszFile[i], -1, szFile, MAX_PATH, NULL, NULL);
1610 
1612  ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed! (%u)\n", GetLastError());
1613  if (hFile == INVALID_HANDLE_VALUE) {
1614  IShellFolder_Release(psfPersonal);
1615  return;
1616  }
1617  CloseHandle(hFile);
1618 
1619  hr = IShellFolder_ParseDisplayName(psfPersonal, NULL, NULL, wszFile[i], NULL, &pidlFile, NULL);
1620  DeleteFileW(wszFile[i]);
1621  ok(hr == S_OK, "psfPersonal->ParseDisplayName failed! hr: %08x\n", hr);
1622  if (hr != S_OK) {
1623  IShellFolder_Release(psfPersonal);
1624  return;
1625  }
1626 
1627  pFileStructA = (struct FileStructA *)pidlFile->mkid.abID;
1628  ok(pFileStructA->type == 0x32, "PIDLTYPE should be 0x32!\n");
1629  ok(pFileStructA->dummy == 0x00, "Dummy Byte should be 0x00!\n");
1630  ok(pFileStructA->dwFileSize == 0, "Filesize should be zero!\n");
1631 
1632  if (i < 2) /* First two file names are already in valid 8.3 format */
1633  ok(!strcmp(szFile, (CHAR*)&pidlFile->mkid.abID[12]), "Wrong file name!\n");
1634  else
1635  /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
1636  * can't implement this correctly, since unix filesystems don't support
1637  * this nasty short/long filename stuff. So we'll probably stay with our
1638  * current habit of storing the long filename here, which seems to work
1639  * just fine. */
1640  todo_wine
1641  ok(pidlFile->mkid.abID[18] == '~', "Should be derived 8.3 name!\n");
1642 
1643  if (i == 0) /* First file name has an even number of chars. No need for alignment. */
1644  ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] != '\0',
1645  "Alignment byte, where there shouldn't be!\n");
1646 
1647  if (i == 1) /* Second file name has an uneven number of chars => alignment byte */
1648  ok(pidlFile->mkid.abID[12 + strlen(szFile) + 1] == '\0',
1649  "There should be an alignment byte, but isn't!\n");
1650 
1651  /* The offset of the FileStructW member is stored as a WORD at the end of the pidl. */
1652  cbOffset = *(WORD*)(((LPBYTE)pidlFile)+pidlFile->mkid.cb-sizeof(WORD));
1653  ok ((cbOffset >= sizeof(struct FileStructA) &&
1654  cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW)),
1655  "Wrong offset value (%d) stored at the end of the PIDL\n", cbOffset);
1656 
1657  if (cbOffset >= sizeof(struct FileStructA) &&
1658  cbOffset <= pidlFile->mkid.cb - sizeof(struct FileStructW))
1659  {
1660  struct FileStructW *pFileStructW = (struct FileStructW *)(((LPBYTE)pidlFile)+cbOffset);
1661  WCHAR *name = pFileStructW->wszName;
1662 
1663  ok(pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen,
1664  "FileStructW's offset and length should add up to the PIDL's length!\n");
1665 
1666  if (pidlFile->mkid.cb == cbOffset + pFileStructW->cbLen) {
1667  /* Since we just created the file, time of creation,
1668  * time of last access and time of last write access just be the same.
1669  * These tests seem to fail sometimes (on WinXP), if the test is run again shortly
1670  * after the first run. I do remember something with NTFS keeping the creation time
1671  * if a file is deleted and then created again within a couple of seconds or so.
1672  * Might be the reason. */
1673  ok (pFileStructA->uFileDate == pFileStructW->uDate &&
1674  pFileStructA->uFileTime == pFileStructW->uTime,
1675  "Last write time should match creation time!\n");
1676 
1677  /* On FAT filesystems the last access time is midnight
1678  local time, so the values of uDate2 and uTime2 will
1679  depend on the local timezone. If the times are exactly
1680  equal then the dates should be identical for both FAT
1681  and NTFS as no timezone is more than 1 day away from UTC.
1682  */
1683  if (pFileStructA->uFileTime == pFileStructW->uTime2)
1684  {
1685  ok (pFileStructA->uFileDate == pFileStructW->uDate2,
1686  "Last write date and time should match last access date and time!\n");
1687  }
1688  else
1689  {
1690  /* Filesystem may be FAT. Check date within 1 day
1691  and seconds are zero. */
1692  trace ("Filesystem may be FAT. Performing less strict atime test.\n");
1693  ok ((pFileStructW->uTime2 & 0x1F) == 0,
1694  "Last access time on FAT filesystems should have zero seconds.\n");
1695  /* TODO: Perform check for date being within one day.*/
1696  }
1697 
1698  ok (!lstrcmpW(wszFile[i], name) ||
1699  !lstrcmpW(wszFile[i], name + 9) || /* Vista */
1700  !lstrcmpW(wszFile[i], name + 11) || /* Win7 */
1701  !lstrcmpW(wszFile[i], name + 13), /* Win8 */
1702  "The filename should be stored in unicode at this position!\n");
1703  }
1704  }
1705 
1706  ILFree(pidlFile);
1707  }
1708 
1709  IShellFolder_Release(psfPersonal);
1710 }
1711 
1712 static void test_SHGetFolderPathA(void)
1713 {
1714  static const BOOL is_win64 = sizeof(void *) > sizeof(int);
1715  BOOL is_wow64;
1716  char path[MAX_PATH];
1717  char path_x86[MAX_PATH];
1718  char path_key[MAX_PATH];
1719  HRESULT hr;
1720  HKEY key;
1721 
1722  if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
1723 
1725  ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1727  if (hr == E_FAIL)
1728  {
1729  win_skip( "Program Files (x86) not supported\n" );
1730  return;
1731  }
1732  ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1733  if (is_win64)
1734  {
1735  ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1736  ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1737  ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1738  }
1739  else
1740  {
1741  ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1742  if (is_wow64)
1743  ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1744  else
1745  ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1746  }
1747  if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1748  {
1749  DWORD type, count = sizeof(path_x86);
1750  if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1751  {
1752  ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
1753  ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1754  }
1755  else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
1756  RegCloseKey( key );
1757  }
1758 
1760  ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1762  if (hr == E_FAIL)
1763  {
1764  win_skip( "Common Files (x86) not supported\n" );
1765  return;
1766  }
1767  ok( hr == S_OK, "SHGetFolderPathA failed %x\n", hr );
1768  if (is_win64)
1769  {
1770  ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
1771  ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
1772  ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
1773  }
1774  else
1775  {
1776  ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
1777  if (is_wow64)
1778  ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
1779  else
1780  ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
1781  }
1782  if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
1783  {
1784  DWORD type, count = sizeof(path_x86);
1785  if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
1786  {
1787  ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
1788  ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
1789  }
1790  else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
1791  }
1792 }
1793 
1795 {
1796  HRESULT ret;
1797  BOOL delret;
1798  DWORD dwret;
1799  int i;
1800  static const char wine[] = "wine";
1801  static const char winetemp[] = "wine\\temp";
1802  static char appdata[MAX_PATH];
1803  static char testpath[MAX_PATH];
1804  static char toolongpath[MAX_PATH+1];
1805 
1807  {
1808  win_skip("SHGetFolderPathA failed for CSIDL_LOCAL_APPDATA!\n");
1809  return;
1810  }
1811 
1812  sprintf(testpath, "%s\\%s", appdata, winetemp);
1813  delret = RemoveDirectoryA(testpath);
1814  if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) ) {
1815  win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1816  return;
1817  }
1818 
1819  sprintf(testpath, "%s\\%s", appdata, wine);
1820  delret = RemoveDirectoryA(testpath);
1821  if(!delret && (ERROR_PATH_NOT_FOUND != GetLastError()) && (ERROR_FILE_NOT_FOUND != GetLastError())) {
1822  win_skip("RemoveDirectoryA(%s) failed with error %u\n", testpath, GetLastError());
1823  return;
1824  }
1825 
1826  /* test invalid second parameter */
1828  ok(E_INVALIDARG == ret, "expected E_INVALIDARG, got %x\n", ret);
1829 
1830  /* test fourth parameter */
1832  switch(ret) {
1833  case S_OK: /* winvista */
1834  ok(!strncmp(appdata, testpath, strlen(appdata)),
1835  "expected %s to start with %s\n", testpath, appdata);
1836  ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1837  "expected %s to end with %s\n", testpath, winetemp);
1838  break;
1839  case E_INVALIDARG: /* winxp, win2k3 */
1840  break;
1841  default:
1842  ok(0, "expected S_OK or E_INVALIDARG, got %x\n", ret);
1843  }
1844 
1845  /* test fifth parameter */
1846  testpath[0] = '\0';
1848  ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1849  ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1850 
1851  testpath[0] = '\0';
1853  ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1854  ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1855 
1856  testpath[0] = '\0';
1858  ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1859  ok(!lstrcmpA(appdata, testpath), "expected %s, got %s\n", appdata, testpath);
1860 
1861  for(i=0; i< MAX_PATH; i++)
1862  toolongpath[i] = '0' + i % 10;
1863  toolongpath[MAX_PATH] = '\0';
1866  "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), ret);
1867 
1868  testpath[0] = '\0';
1870  ok((S_OK == ret) || (E_INVALIDARG == ret), "expected S_OK or E_INVALIDARG, got %x\n", ret);
1871 
1872  /* test a not existing path */
1873  testpath[0] = '\0';
1876  "expected %x, got %x\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), ret);
1877 
1878  /* create a directory inside a not existing directory */
1879  testpath[0] = '\0';
1881  ok(S_OK == ret, "expected S_OK, got %x\n", ret);
1882  ok(!strncmp(appdata, testpath, strlen(appdata)),
1883  "expected %s to start with %s\n", testpath, appdata);
1884  ok(!lstrcmpA(&testpath[1 + strlen(appdata)], winetemp),
1885  "expected %s to end with %s\n", testpath, winetemp);
1886  dwret = GetFileAttributesA(testpath);
1887  ok(FILE_ATTRIBUTE_DIRECTORY | dwret, "expected %x to contain FILE_ATTRIBUTE_DIRECTORY\n", dwret);
1888 
1889  /* cleanup */
1890  sprintf(testpath, "%s\\%s", appdata, winetemp);
1891  RemoveDirectoryA(testpath);
1892  sprintf(testpath, "%s\\%s", appdata, wine);
1893  RemoveDirectoryA(testpath);
1894 }
1895 
1896 static void test_LocalizedNames(void)
1897 {
1898  static char cCurrDirA[MAX_PATH];
1899  WCHAR cCurrDirW[MAX_PATH], tempbufW[25];
1900  IShellFolder *IDesktopFolder, *testIShellFolder;
1901  ITEMIDLIST *newPIDL;
1902  int len;
1903  HRESULT hr;
1904  static char resourcefile[MAX_PATH];
1905  DWORD res;
1906  HANDLE file;
1907  STRRET strret;
1908  BOOL ret;
1909 
1910  static const char desktopini_contents1[] =
1911  "[.ShellClassInfo]\r\n"
1912  "LocalizedResourceName=@";
1913  static const char desktopini_contents2[] =
1914  ",-1\r\n";
1915  static WCHAR foldernameW[] = {'t','e','s','t','f','o','l','d','e','r',0};
1916  static const WCHAR folderdisplayW[] = {'F','o','l','d','e','r',' ','N','a','m','e',' ','R','e','s','o','u','r','c','e',0};
1917 
1918  /* create folder with desktop.ini and localized name in GetModuleFileNameA(NULL) */
1919  CreateDirectoryA(".\\testfolder", NULL);
1920 
1921  SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")|FILE_ATTRIBUTE_SYSTEM);
1922 
1923  GetModuleFileNameA(NULL, resourcefile, MAX_PATH);
1924 
1925  file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
1927  ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
1928  ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
1929  WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
1930  WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
1931  ok(ret, "WriteFile failed %i\n", GetLastError());
1932  CloseHandle(file);
1933 
1934  /* get IShellFolder for parent */
1935  GetCurrentDirectoryA(MAX_PATH, cCurrDirA);
1936  len = lstrlenA(cCurrDirA);
1937 
1938  if (len == 0) {
1939  win_skip("GetCurrentDirectoryA returned empty string. Skipping test_LocalizedNames\n");
1940  goto cleanup;
1941  }
1942  if(cCurrDirA[len-1] == '\\')
1943  cCurrDirA[len-1] = 0;
1944 
1945  MultiByteToWideChar(CP_ACP, 0, cCurrDirA, -1, cCurrDirW, MAX_PATH);
1946 
1947  hr = SHGetDesktopFolder(&IDesktopFolder);
1948  ok(hr == S_OK, "SHGetDesktopfolder failed %08x\n", hr);
1949 
1950  hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cCurrDirW, NULL, &newPIDL, 0);
1951  ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1952 
1953  hr = IShellFolder_BindToObject(IDesktopFolder, newPIDL, NULL, (REFIID)&IID_IShellFolder, (LPVOID *)&testIShellFolder);
1954  ok(hr == S_OK, "BindToObject failed %08x\n", hr);
1955 
1956  IMalloc_Free(ppM, newPIDL);
1957 
1958  /* windows reads the display name from the resource */
1959  hr = IShellFolder_ParseDisplayName(testIShellFolder, NULL, NULL, foldernameW, NULL, &newPIDL, 0);
1960  ok(hr == S_OK, "ParseDisplayName failed %08x\n", hr);
1961 
1962  hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
1963  ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1964 
1965  hr = StrRetToBufW(&strret, newPIDL, tempbufW, ARRAY_SIZE(tempbufW));
1966  ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1967  todo_wine
1968  ok (!lstrcmpiW(tempbufW, folderdisplayW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1969 
1970  /* editing name is also read from the resource */
1971  hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
1972  ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1973 
1974  hr = StrRetToBufW(&strret, newPIDL, tempbufW, ARRAY_SIZE(tempbufW));
1975  ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1976  todo_wine
1977  ok (!lstrcmpiW(tempbufW, folderdisplayW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1978 
1979  /* parsing name is unchanged */
1980  hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
1981  ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
1982 
1983  hr = StrRetToBufW(&strret, newPIDL, tempbufW, ARRAY_SIZE(tempbufW));
1984  ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
1985  ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
1986 
1987  IShellFolder_Release(IDesktopFolder);
1988  IShellFolder_Release(testIShellFolder);
1989 
1990  IMalloc_Free(ppM, newPIDL);
1991 
1992 cleanup:
1993  DeleteFileA(".\\testfolder\\desktop.ini");
1994  SetFileAttributesA(".\\testfolder", GetFileAttributesA(".\\testfolder")&~FILE_ATTRIBUTE_SYSTEM);
1995  RemoveDirectoryA(".\\testfolder");
1996 }
1997 
1998 static void test_SHCreateShellItem(void)
1999 {
2000  IShellItem *shellitem, *shellitem2;
2001  IPersistIDList *persistidl;
2002  LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
2003  HRESULT ret;
2004  char curdirA[MAX_PATH];
2005  WCHAR curdirW[MAX_PATH];
2006  WCHAR fnbufW[MAX_PATH];
2007  IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
2008  static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
2009 
2010  GetCurrentDirectoryA(MAX_PATH, curdirA);
2011 
2012  if (!pSHCreateShellItem)
2013  {
2014  win_skip("SHCreateShellItem isn't available\n");
2015  return;
2016  }
2017 
2018  if (!curdirA[0])
2019  {
2020  win_skip("GetCurrentDirectoryA returned empty string, skipping test_SHCreateShellItem\n");
2021  return;
2022  }
2023 
2024  ret = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
2025  ok(ret == S_OK, "Got 0x%08x\n", ret);
2026 
2027  MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
2028 
2029  ret = SHGetDesktopFolder(&desktopfolder);
2030  ok(SUCCEEDED(ret), "SHGetShellFolder returned %x\n", ret);
2031 
2032  ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2033  ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2034 
2035  ret = IShellFolder_BindToObject(desktopfolder, pidl_cwd, NULL, &IID_IShellFolder, (void**)&currentfolder);
2036  ok(SUCCEEDED(ret), "BindToObject returned %x\n", ret);
2037 
2038  CreateTestFile(".\\testfile");
2039 
2040  ret = IShellFolder_ParseDisplayName(currentfolder, NULL, NULL, testfileW, NULL, &pidl_testfile, NULL);
2041  ok(SUCCEEDED(ret), "ParseDisplayName returned %x\n", ret);
2042 
2043  pidl_abstestfile = ILCombine(pidl_cwd, pidl_testfile);
2044 
2045  shellitem = (void*)0xdeadbeef;
2046  ret = pSHCreateShellItem(NULL, NULL, NULL, &shellitem);
2047  ok(ret == E_INVALIDARG, "SHCreateShellItem returned %x\n", ret);
2048  ok(shellitem == 0, "Got %p\n", shellitem);
2049 
2050  if (0) /* crashes on Windows XP */
2051  {
2052  pSHCreateShellItem(NULL, NULL, pidl_cwd, NULL);
2053  pSHCreateShellItem(pidl_cwd, NULL, NULL, &shellitem);
2054  pSHCreateShellItem(NULL, currentfolder, NULL, &shellitem);
2055  pSHCreateShellItem(pidl_cwd, currentfolder, NULL, &shellitem);
2056  }
2057 
2058  ret = pSHCreateShellItem(NULL, NULL, pidl_cwd, &shellitem);
2059  ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2060  if (SUCCEEDED(ret))
2061  {
2062  ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2063  ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2064  if (SUCCEEDED(ret))
2065  {
2066  ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2067  ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2068  if (SUCCEEDED(ret))
2069  {
2070  ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2071  ILFree(pidl_test);
2072  }
2073  IPersistIDList_Release(persistidl);
2074  }
2075  IShellItem_Release(shellitem);
2076  }
2077 
2078  ret = pSHCreateShellItem(pidl_cwd, NULL, pidl_testfile, &shellitem);
2079  ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2080  if (SUCCEEDED(ret))
2081  {
2082  ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2083  ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2084  if (SUCCEEDED(ret))
2085  {
2086  ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2087  ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2088  if (SUCCEEDED(ret))
2089  {
2090  ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2091  ILFree(pidl_test);
2092  }
2093  IPersistIDList_Release(persistidl);
2094  }
2095 
2096  ret = IShellItem_GetParent(shellitem, &shellitem2);
2097  ok(SUCCEEDED(ret), "GetParent returned %x\n", ret);
2098  if (SUCCEEDED(ret))
2099  {
2100  ret = IShellItem_QueryInterface(shellitem2, &IID_IPersistIDList, (void**)&persistidl);
2101  ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2102  if (SUCCEEDED(ret))
2103  {
2104  ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2105  ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2106  if (SUCCEEDED(ret))
2107  {
2108  ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2109  ILFree(pidl_test);
2110  }
2111  IPersistIDList_Release(persistidl);
2112  }
2113  IShellItem_Release(shellitem2);
2114  }
2115 
2116  IShellItem_Release(shellitem);
2117  }
2118 
2119  ret = pSHCreateShellItem(NULL, currentfolder, pidl_testfile, &shellitem);
2120  ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2121  if (SUCCEEDED(ret))
2122  {
2123  ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2124  ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2125  if (SUCCEEDED(ret))
2126  {
2127  ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2128  ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2129  if (SUCCEEDED(ret))
2130  {
2131  ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2132  ILFree(pidl_test);
2133  }
2134  IPersistIDList_Release(persistidl);
2135  }
2136  IShellItem_Release(shellitem);
2137  }
2138 
2139  /* if a parent pidl and shellfolder are specified, the shellfolder is ignored */
2140  ret = pSHCreateShellItem(pidl_cwd, desktopfolder, pidl_testfile, &shellitem);
2141  ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2142  if (SUCCEEDED(ret))
2143  {
2144  ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2145  ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2146  if (SUCCEEDED(ret))
2147  {
2148  ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2149  ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2150  if (SUCCEEDED(ret))
2151  {
2152  ok(ILIsEqual(pidl_abstestfile, pidl_test), "id lists are not equal\n");
2153  ILFree(pidl_test);
2154  }
2155  IPersistIDList_Release(persistidl);
2156  }
2157  IShellItem_Release(shellitem);
2158  }
2159 
2160  ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
2161  ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2162  if (SUCCEEDED(ret))
2163  {
2164  ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2165  ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
2166  if (SUCCEEDED(ret))
2167  {
2168  ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2169  ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
2170  if (SUCCEEDED(ret))
2171  {
2172  ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2173  ILFree(pidl_test);
2174  }
2175  IPersistIDList_Release(persistidl);
2176  }
2177 
2178  IShellItem_Release(shellitem);
2179  }
2180 
2181  ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
2182  ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2183  if (SUCCEEDED(ret))
2184  {
2185  ret = IShellItem_GetParent(shellitem, &shellitem2);
2186  ok(FAILED(ret), "Got 0x%08x\n", ret);
2187  if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
2188  IShellItem_Release(shellitem);
2189  }
2190 
2191  /* SHCreateItemFromParsingName */
2192  if(pSHCreateItemFromParsingName)
2193  {
2194  if(0)
2195  {
2196  /* Crashes under windows 7 */
2197  pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
2198  }
2199 
2200  shellitem = (void*)0xdeadbeef;
2201  ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
2202  ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
2203  ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2204 
2205  ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
2207  "SHCreateItemFromParsingName returned %x\n", ret);
2208  if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
2209 
2210  lstrcpyW(fnbufW, curdirW);
2211  myPathAddBackslashW(fnbufW);
2212  lstrcatW(fnbufW, testfileW);
2213 
2214  ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
2215  ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
2216  if(SUCCEEDED(ret))
2217  {
2218  LPWSTR tmp_fname;
2219  ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
2220  ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
2221  if(SUCCEEDED(ret))
2222  {
2223  ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
2224  CoTaskMemFree(tmp_fname);
2225  }
2226  IShellItem_Release(shellitem);
2227  }
2228  }
2229  else
2230  win_skip("No SHCreateItemFromParsingName\n");
2231 
2232 
2233  /* SHCreateItemFromIDList */
2234  if(pSHCreateItemFromIDList)
2235  {
2236  if(0)
2237  {
2238  /* Crashes under win7 */
2239  pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
2240  }
2241 
2242  ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
2243  ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
2244 
2245  ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
2246  ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2247  if (SUCCEEDED(ret))
2248  {
2249  ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2250  ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2251  if (SUCCEEDED(ret))
2252  {
2253  ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2254  ok(ret == S_OK, "GetIDList returned %x\n", ret);
2255  if (SUCCEEDED(ret))
2256  {
2257  ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
2258  ILFree(pidl_test);
2259  }
2260  IPersistIDList_Release(persistidl);
2261  }
2262  IShellItem_Release(shellitem);
2263  }
2264 
2265  ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
2266  ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
2267  if (SUCCEEDED(ret))
2268  {
2269  ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
2270  ok(ret == S_OK, "QueryInterface returned %x\n", ret);
2271  if (SUCCEEDED(ret))
2272  {
2273  ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
2274  ok(ret == S_OK, "GetIDList returned %x\n", ret);
2275  if (SUCCEEDED(ret))
2276  {
2277  ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
2278  ILFree(pidl_test);
2279  }
2280  IPersistIDList_Release(persistidl);
2281  }
2282  IShellItem_Release(shellitem);
2283  }
2284  }
2285  else
2286  win_skip("No SHCreateItemFromIDList\n");
2287 
2288  /* SHCreateItemFromRelativeName */
2289  if(pSHCreateItemFromRelativeName && pSHGetKnownFolderPath)
2290  {
2291  IShellItem *shellitem_desktop = NULL;
2292  WCHAR *desktop_path, *displayname;
2293  WCHAR testfile_path[MAX_PATH] = {0};
2294  HANDLE file;
2295  LPITEMIDLIST pidl_desktop_testfile = NULL;
2296  int order;
2297 
2298  ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem_desktop);
2299  ok(ret == S_OK, "SHCreateShellItem failed: 0x%08x.\n", ret);
2300 
2301  shellitem = (void*)0xdeadbeef;
2302  ret = pSHCreateItemFromRelativeName(shellitem_desktop, NULL, NULL, &IID_IShellItem,
2303  (void**)&shellitem);
2304  ok(ret == E_INVALIDARG, "Expected 0x%08x but SHCreateItemFromRelativeName return: 0x%08x.\n",
2305  E_INVALIDARG, ret);
2306  ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2307 
2308  /* Test with a non-existent file */
2309  shellitem = (void*)0xdeadbeef;
2310  ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2311  (void**)&shellitem);
2313  "Expected 0x%08x but SHCreateItemFromRelativeName return: 0x%08x.\n",
2315  ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2316 
2317  /* Create a file for testing in desktop folder */
2318  pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &desktop_path);
2319  lstrcatW(testfile_path, desktop_path);
2320  myPathAddBackslashW(testfile_path);
2321  lstrcatW(testfile_path, testfileW);
2322  file = CreateFileW(testfile_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
2323  ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: 0x%08x.\n", GetLastError());
2324  CloseHandle(file);
2325 
2326  shellitem = (void*)0xdeadbeef;
2327  ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2328  (void**)&shellitem);
2329  ok(ret == S_OK, "SHCreateItemFromRelativeName failed: 0x%08x.\n", ret);
2330  ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2331  if(SUCCEEDED(ret))
2332  {
2333  ret = IShellItem_GetDisplayName(shellitem, 0, &displayname);
2334  ok(ret == S_OK, "IShellItem_GetDisplayName failed: 0x%08x.\n", ret);
2335  ok(!lstrcmpW(displayname, testfileW), "got wrong display name: %s.\n", wine_dbgstr_w(displayname));
2336  CoTaskMemFree(displayname);
2337 
2338  shellitem2 = (void*)0xdeadbeef;
2339  ret = pSHCreateItemFromRelativeName(shellitem_desktop, testfileW, NULL, &IID_IShellItem,
2340  (void**)&shellitem2);
2341  ok(ret == S_OK, "SHCreateItemFromRelativeName failed: 0x%08x.\n", ret);
2342  ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2343  ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2344  ok(!order, "order got wrong value: %d.\n", order);
2345  IShellItem_Release(shellitem2);
2346 
2347  shellitem2 = (void*)0xdeadbeef;
2348  ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, testfileW, NULL,
2349  &pidl_desktop_testfile, NULL);
2350  ok(ret == S_OK, "ParseDisplayName failed 0x%08x.\n", ret);
2351  ret = pSHCreateItemFromIDList(pidl_desktop_testfile, &IID_IShellItem, (void**)&shellitem2);
2352  ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2353  ok(ret == S_OK, "IShellItem_Compare fail: 0x%08x.\n", ret);
2354  ok(!order, "order got wrong value: %d.\n", order);
2355  ILFree(pidl_desktop_testfile);
2356  IShellItem_Release(shellitem2);
2357 
2358  IShellItem_Release(shellitem);
2359  }
2360 
2361  DeleteFileW(testfile_path);
2362  CoTaskMemFree(desktop_path);
2363  IShellItem_Release(shellitem_desktop);
2364  }
2365  else
2366  win_skip("No SHCreateItemFromRelativeName or SHGetKnownFolderPath\n");
2367 
2368  /* SHCreateItemInKnownFolder */
2369  if(pSHCreateItemInKnownFolder && pSHGetKnownFolderPath)
2370  {
2371  WCHAR *desktop_path;
2372  WCHAR testfile_path[MAX_PATH] = {0};
2373  HANDLE file;
2374  WCHAR *displayname = NULL;
2375  int order;
2376  LPITEMIDLIST pidl_desktop_testfile = NULL;
2377 
2378  shellitem = (void*)0xdeadbeef;
2379  ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, NULL, &IID_IShellItem,
2380  (void**)&shellitem);
2381  ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2382  ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2383  if(SUCCEEDED(ret))
2384  {
2385  shellitem2 = (void*)0xdeadbeef;
2386  ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem2);
2387  ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
2388  if(SUCCEEDED(ret))
2389  {
2390  ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2391  ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2392  ok(!order, "order got wrong value: %d.\n", order);
2393  IShellItem_Release(shellitem2);
2394  }
2395  IShellItem_Release(shellitem);
2396  }
2397 
2398  /* Test with a non-existent file */
2399  shellitem = (void*)0xdeadbeef;
2400  ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2401  (void**)&shellitem);
2403  "Expected 0x%08x but SHCreateItemInKnownFolder return: 0x%08x.\n",
2405  ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
2406 
2407  pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &desktop_path);
2408  lstrcatW(testfile_path, desktop_path);
2409  myPathAddBackslashW(testfile_path);
2410  lstrcatW(testfile_path, testfileW);
2411  file = CreateFileW(testfile_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
2412  ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed! Last error: 0x%08x.\n", GetLastError());
2413  CloseHandle(file);
2414 
2415  shellitem = (void*)0xdeadbeef;
2416  ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2417  (void**)&shellitem);
2418  ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2419  ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2420  if(SUCCEEDED(ret))
2421  {
2422  ret = IShellItem_GetDisplayName(shellitem, 0, &displayname);
2423  ok(ret == S_OK, "IShellItem_GetDisplayName failed: 0x%08x.\n", ret);
2424  ok(!lstrcmpW(displayname, testfileW), "got wrong display name: %s.\n",
2425  wine_dbgstr_w(displayname));
2426  CoTaskMemFree(displayname);
2427 
2428  shellitem2 = (void*)0xdeadbeef;
2429  ret = pSHCreateItemInKnownFolder(&FOLDERID_Desktop, 0, testfileW, &IID_IShellItem,
2430  (void**)&shellitem2);
2431  ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2432  ok(shellitem2 != NULL, "shellitem was %p.\n", shellitem);
2433  ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2434  ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2435  ok(!order, "order got wrong value: %d.\n", order);
2436  IShellItem_Release(shellitem2);
2437 
2438  shellitem2 = (void*)0xdeadbeef;
2439  ret = IShellFolder_ParseDisplayName(desktopfolder, NULL, NULL, testfileW, NULL,
2440  &pidl_desktop_testfile, NULL);
2441  ok(SUCCEEDED(ret), "ParseDisplayName returned %x.\n", ret);
2442  ret = pSHCreateItemFromIDList(pidl_desktop_testfile, &IID_IShellItem, (void**)&shellitem2);
2443  ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2444  ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2445  ok(!order, "order got wrong value: %d.\n", order);
2446  ILFree(pidl_desktop_testfile);
2447  IShellItem_Release(shellitem2);
2448 
2449  IShellItem_Release(shellitem);
2450  }
2451 
2452  shellitem = (void*)0xdeadbeef;
2453  ret = pSHCreateItemInKnownFolder(&FOLDERID_Documents, 0, NULL, &IID_IShellItem,
2454  (void**)&shellitem);
2455  ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2456  ok(shellitem != NULL, "shellitem was %p.\n", shellitem);
2457  if(SUCCEEDED(ret))
2458  {
2459  shellitem2 = (void*)0xdeadbeef;
2460  ret = pSHCreateItemInKnownFolder(&FOLDERID_Documents, 0, NULL, &IID_IShellItem,
2461  (void**)&shellitem2);
2462  ok(ret == S_OK, "SHCreateItemInKnownFolder failed: 0x%08x.\n", ret);
2463  ok(shellitem2 != NULL, "shellitem was %p.\n", shellitem);
2464  ret = IShellItem_Compare(shellitem, shellitem2, 0, &order);
2465  ok(ret == S_OK, "IShellItem_Compare failed: 0x%08x.\n", ret);
2466  ok(!order, "order got wrong value: %d.\n", order);
2467  IShellItem_Release(shellitem2);
2468 
2469  IShellItem_Release(shellitem);
2470  }
2471  DeleteFileW(testfile_path);
2472  CoTaskMemFree(desktop_path);
2473  }
2474  else
2475  win_skip("No SHCreateItemInKnownFolder or SHGetKnownFolderPath\n");
2476 
2477  DeleteFileA(".\\testfile");
2478  ILFree(pidl_abstestfile);
2479  ILFree(pidl_testfile);
2480  ILFree(pidl_desktop);
2481  ILFree(pidl_cwd);
2482  IShellFolder_Release(currentfolder);
2483  IShellFolder_Release(desktopfolder);
2484 }
2485 
2486 static void test_SHGetNameFromIDList(void)
2487 {
2488  IShellItem *shellitem;
2489  LPITEMIDLIST pidl;
2490  LPWSTR name_string;
2491  HRESULT hres;
2492  UINT i;
2493  static const DWORD flags[] = {
2494  SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
2495  SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
2496  SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
2497  SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
2498 
2499  if(!pSHGetNameFromIDList)
2500  {
2501  win_skip("SHGetNameFromIDList missing.\n");
2502  return;
2503  }
2504 
2505  /* This should be available on any platform that passed the above test. */
2506  ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
2507 
2508  if(0)
2509  {
2510  /* Crashes under win7 */
2511  pSHGetNameFromIDList(NULL, 0, NULL);
2512  }
2513 
2514  hres = pSHGetNameFromIDList(NULL, 0, &name_string);
2515  ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
2516 
2517  /* Test the desktop */
2519  ok(hres == S_OK, "Got 0x%08x\n", hres);
2520  hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2521  ok(hres == S_OK, "Got 0x%08x\n", hres);
2522  if(SUCCEEDED(hres))
2523  {
2524  WCHAR *nameSI, *nameSH;
2525  WCHAR buf[MAX_PATH];
2526  HRESULT hrSI, hrSH, hrSF;
2527  STRRET strret;
2528  IShellFolder *psf;
2529  BOOL res;
2530 
2531  SHGetDesktopFolder(&psf);
2532  for(i = 0; flags[i] != -1234; i++)
2533  {
2534  hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2535  ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2536  hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2537  ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2538  hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2539  ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2540 
2541  if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2542  ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2543 
2544  if(SUCCEEDED(hrSF))
2545  {
2546  StrRetToBufW(&strret, NULL, buf, MAX_PATH);
2547  if(SUCCEEDED(hrSI))
2548  ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2549  if(SUCCEEDED(hrSF))
2550  ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2551  }
2552  if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2553  if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2554  }
2555  IShellFolder_Release(psf);
2556 
2557  hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2558  ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2559  res = SHGetPathFromIDListW(pidl, buf);
2560  ok(res == TRUE, "Got %d\n", res);
2561  if(SUCCEEDED(hrSI) && res)
2562  ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2563  if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2564 
2565  hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2566  todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
2567  if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2568 
2569  IShellItem_Release(shellitem);
2570  }
2571  ILFree(pidl);
2572 
2573  /* Test the control panel */
2575  ok(hres == S_OK, "Got 0x%08x\n", hres);
2576  hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
2577  ok(hres == S_OK, "Got 0x%08x\n", hres);
2578  if(SUCCEEDED(hres))
2579  {
2580  WCHAR *nameSI, *nameSH;
2581  WCHAR buf[MAX_PATH];
2582  HRESULT hrSI, hrSH, hrSF;
2583  STRRET strret;
2584  IShellFolder *psf;
2585  BOOL res;
2586 
2587  SHGetDesktopFolder(&psf);
2588  for(i = 0; flags[i] != -1234; i++)
2589  {
2590  hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
2591  ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
2592  hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
2593  ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
2594  hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
2595  ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
2596 
2597  if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
2598  ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
2599 
2600  if(SUCCEEDED(hrSF))
2601  {
2602  StrRetToBufW(&strret, NULL, buf, MAX_PATH);
2603  if(SUCCEEDED(hrSI))
2604  ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2605  if(SUCCEEDED(hrSF))
2606  ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2607  }
2608  if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2609  if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
2610  }
2611  IShellFolder_Release(psf);
2612 
2613  hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
2614  ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
2615  res = SHGetPathFromIDListW(pidl, buf);
2616  ok(res == FALSE, "Got %d\n", res);
2617  if(SUCCEEDED(hrSI) && res)
2618  ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
2619  if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
2620 
2621  hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
2622  todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
2623  "Got 0x%08x\n", hres);
2624  if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
2625 
2626  IShellItem_Release(shellitem);
2627  }
2628  ILFree(pidl);
2629 }
2630 
2632 {
2633  IShellFolder *psfdesktop;
2634  IShellItem *psi;
2635  IShellView *psv;
2636  HRESULT hres;
2637 
2638  if(!pSHGetItemFromDataObject)
2639  {
2640  win_skip("No SHGetItemFromDataObject.\n");
2641  return;
2642  }
2643 
2644  if(0)
2645  {
2646  /* Crashes under win7 */
2647  pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
2648  }
2649 
2650  hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
2651  ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
2652 
2653  SHGetDesktopFolder(&psfdesktop);
2654 
2655  hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
2656  ok(hres == S_OK, "got 0x%08x\n", hres);
2657  if(SUCCEEDED(hres))
2658  {
2659  IEnumIDList *peidl;
2660  IDataObject *pdo;
2661  SHCONTF enum_flags;
2662 
2663  enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
2664  hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
2665  ok(hres == S_OK, "got 0x%08x\n", hres);
2666  if(SUCCEEDED(hres))
2667  {
2668  LPITEMIDLIST apidl[5];
2669  UINT count = 0, i;
2670 
2671  for(count = 0; count < 5; count++)
2672  if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
2673  break;
2674 
2675  if(count)
2676  {
2677  hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
2678  &IID_IDataObject, NULL, (void**)&pdo);
2679  ok(hres == S_OK, "got 0x%08x\n", hres);
2680  if(SUCCEEDED(hres))
2681  {
2682  hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2683  ok(hres == S_OK, "got 0x%08x\n", hres);
2684  if(SUCCEEDED(hres)) IShellItem_Release(psi);
2685  hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2686  ok(hres == S_OK, "got 0x%08x\n", hres);
2687  if(SUCCEEDED(hres)) IShellItem_Release(psi);
2688  hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2689  ok(hres == S_OK, "got 0x%08x\n", hres);
2690  if(SUCCEEDED(hres)) IShellItem_Release(psi);
2691  hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2692  ok(hres == S_OK, "got 0x%08x\n", hres);
2693  if(SUCCEEDED(hres)) IShellItem_Release(psi);
2694  hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2695  ok(hres == S_OK, "got 0x%08x\n", hres);
2696  if(SUCCEEDED(hres)) IShellItem_Release(psi);
2697 
2698  IDataObject_Release(pdo);
2699  }
2700  }
2701  else
2702  skip("No file(s) found - skipping single-file test.\n");
2703 
2704  if(count > 1)
2705  {
2706  hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
2707  &IID_IDataObject, NULL, (void**)&pdo);
2708  ok(hres == S_OK, "got 0x%08x\n", hres);
2709  if(SUCCEEDED(hres))
2710  {
2711  hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
2712  ok(hres == S_OK, "got 0x%08x\n", hres);
2713  if(SUCCEEDED(hres)) IShellItem_Release(psi);
2714  hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
2715  ok(hres == S_OK, "got 0x%08x\n", hres);
2716  if(SUCCEEDED(hres)) IShellItem_Release(psi);
2717  hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
2718  ok(hres == S_OK, "got 0x%08x\n", hres);
2719  if(SUCCEEDED(hres)) IShellItem_Release(psi);
2720  hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
2721  ok(hres == S_OK, "got 0x%08x\n", hres);
2722  if(SUCCEEDED(hres)) IShellItem_Release(psi);
2723  hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
2724  ok(hres == E_FAIL, "got 0x%08x\n", hres);
2725  if(SUCCEEDED(hres)) IShellItem_Release(psi);
2726  IDataObject_Release(pdo);
2727  }
2728  }
2729  else
2730  skip("zero or one file found - skipping multi-file test.\n");
2731 
2732  for(i = 0; i < count; i++)
2733  ILFree(apidl[i]);
2734 
2735  IEnumIDList_Release(peidl);
2736  }
2737 
2738  IShellView_Release(psv);
2739  }
2740 
2741  IShellFolder_Release(psfdesktop);
2742 }
2743 
2744 static void test_ShellItemCompare(void)
2745 {
2746  IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
2747  IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
2748  IShellFolder *psf_desktop, *psf_current;
2749  LPITEMIDLIST pidl_cwd;
2750  WCHAR curdirW[MAX_PATH];
2751  BOOL failed;
2752  HRESULT hr;
2753  static const WCHAR filesW[][9] = {
2754  {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
2755  {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
2756  {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
2757  int order;
2758  UINT i;
2759 
2760  if(!pSHCreateShellItem)
2761  {
2762  win_skip("SHCreateShellItem missing.\n");
2763  return;
2764  }
2765 
2766  GetCurrentDirectoryW(MAX_PATH, curdirW);
2767  if (!curdirW[0])
2768  {
2769  skip("Failed to get current directory, skipping.\n");
2770  return;
2771  }
2772 
2773  CreateDirectoryA(".\\a", NULL);
2774  CreateDirectoryA(".\\b", NULL);
2775  CreateDirectoryA(".\\c", NULL);
2776  CreateTestFile(".\\a\\a");
2777  CreateTestFile(".\\a\\b");
2778  CreateTestFile(".\\a\\c");
2779  CreateTestFile(".\\b\\a");
2780  CreateTestFile(".\\b\\b");
2781  CreateTestFile(".\\b\\c");
2782  CreateTestFile(".\\c\\a");
2783  CreateTestFile(".\\c\\b");
2784  CreateTestFile(".\\c\\c");
2785 
2786  SHGetDesktopFolder(&psf_desktop);
2787  hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
2788  ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2789  hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
2790  ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
2791  IShellFolder_Release(psf_desktop);
2792  ILFree(pidl_cwd);
2793 
2794  /* Generate ShellItems for the files */
2795  memset(&psi, 0, sizeof(psi));
2796  failed = FALSE;
2797  for(i = 0; i < 9; i++)
2798  {
2799  LPITEMIDLIST pidl_testfile = NULL;
2800 
2801  hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
2802  NULL, &pidl_testfile, NULL);
2803  ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
2804  if(SUCCEEDED(hr))
2805  {
2806  hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
2807  ok(hr == S_OK, "Got 0x%08x\n", hr);
2808  ILFree(pidl_testfile);
2809  }
2810  if(FAILED(hr)) failed = TRUE;
2811  }
2812  if(failed)
2813  {
2814  skip("Failed to create all shellitems.\n");
2815  goto cleanup;
2816  }
2817 
2818  /* Generate ShellItems for the folders */
2819  hr = IShellItem_GetParent(psi[0], &psi_a);
2820  ok(hr == S_OK, "Got 0x%08x\n", hr);
2821  if(FAILED(hr)) failed = TRUE;
2822  hr = IShellItem_GetParent(psi[3], &psi_b);
2823  ok(hr == S_OK, "Got 0x%08x\n", hr);
2824  if(FAILED(hr)) failed = TRUE;
2825  hr = IShellItem_GetParent(psi[6], &psi_c);
2826  ok(hr == S_OK, "Got 0x%08x\n", hr);
2827  if(FAILED(hr)) failed = TRUE;
2828 
2829  if(failed)
2830  {
2831  skip("Failed to create shellitems.\n");
2832  goto cleanup;
2833  }
2834 
2835  if(0)
2836  {
2837  /* Crashes on native (win7, winxp) */
2838  IShellItem_Compare(psi_a, NULL, 0, NULL);
2839  IShellItem_Compare(psi_a, psi_b, 0, NULL);
2840  IShellItem_Compare(psi_a, NULL, 0, &order);
2841  }
2842 
2843  /* Basics */
2844  for(i = 0; i < 9; i++)
2845  {
2846  hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
2847  ok(hr == S_OK, "Got 0x%08x\n", hr);
2848  ok(order == 0, "Got order %d\n", order);
2849  hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
2850  ok(hr == S_OK, "Got 0x%08x\n", hr);
2851  ok(order == 0, "Got order %d\n", order);
2852  hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
2853  ok(hr == S_OK, "Got 0x%08x\n", hr);
2854  ok(order == 0, "Got order %d\n", order);
2855  }
2856 
2857  /* Order */
2858  /* a\b:a\a , a\b:a\c, a\b:a\b */
2859  hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
2860  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2861  ok(order == 1, "Got order %d\n", order);
2862  hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
2863  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2864  ok(order == -1, "Got order %d\n", order);
2865  hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
2866  ok(hr == S_OK, "Got 0x%08x\n", hr);
2867  ok(order == 0, "Got order %d\n", order);
2868 
2869  /* b\b:a\b, b\b:c\b, b\b:c\b */
2870  hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
2871  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2872  ok(order == 1, "Got order %d\n", order);
2873  hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
2874  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2875  ok(order == -1, "Got order %d\n", order);
2876  hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
2877  ok(hr == S_OK, "Got 0x%08x\n", hr);
2878  ok(order == 0, "Got order %d\n", order);
2879 
2880  /* b:a\a, b:a\c, b:a\b */
2881  hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
2882  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2883  todo_wine ok(order == 1, "Got order %d\n", order);
2884  hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
2885  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2886  todo_wine ok(order == 1, "Got order %d\n", order);
2887  hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
2888  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2889  todo_wine ok(order == 1, "Got order %d\n", order);
2890 
2891  /* b:c\a, b:c\c, b:c\b */
2892  hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
2893  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2894  ok(order == -1, "Got order %d\n", order);
2895  hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
2896  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2897  ok(order == -1, "Got order %d\n", order);
2898  hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
2899  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2900  ok(order == -1, "Got order %d\n", order);
2901 
2902  /* a\b:a\a , a\b:a\c, a\b:a\b */
2903  hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
2904  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2905  ok(order == 1, "Got order %d\n", order);
2906  hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
2907  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2908  ok(order == -1, "Got order %d\n", order);
2909  hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
2910  ok(hr == S_OK, "Got 0x%08x\n", hr);
2911  ok(order == 0, "Got order %d\n", order);
2912 
2913  /* b\b:a\b, b\b:c\b, b\b:c\b */
2914  hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
2915  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2916  ok(order == 1, "Got order %d\n", order);
2917  hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
2918  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2919  ok(order == -1, "Got order %d\n", order);
2920  hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
2921  ok(hr == S_OK, "Got 0x%08x\n", hr);
2922  ok(order == 0, "Got order %d\n", order);
2923 
2924  /* b:a\a, b:a\c, b:a\b */
2925  hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
2926  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2927  todo_wine ok(order == 1, "Got order %d\n", order);
2928  hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
2929  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2930  todo_wine ok(order == 1, "Got order %d\n", order);
2931  hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
2932  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2933  todo_wine ok(order == 1, "Got order %d\n", order);
2934 
2935  /* b:c\a, b:c\c, b:c\b */
2936  hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
2937  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2938  ok(order == -1, "Got order %d\n", order);
2939  hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
2940  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2941  ok(order == -1, "Got order %d\n", order);
2942  hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
2943  ok(hr == S_FALSE, "Got 0x%08x\n", hr);
2944  ok(order == -1, "Got order %d\n", order);
2945 
2946 cleanup:
2947  IShellFolder_Release(psf_current);
2948 
2949  DeleteFileA(".\\a\\a");
2950  DeleteFileA(".\\a\\b");
2951  DeleteFileA(".\\a\\c");
2952  DeleteFileA(".\\b\\a");
2953  DeleteFileA(".\\b\\b");
2954  DeleteFileA(".\\b\\c");
2955  DeleteFileA(".\\c\\a");
2956  DeleteFileA(".\\c\\b");
2957  DeleteFileA(".\\c\\c");
2958  RemoveDirectoryA(".\\a");
2959  RemoveDirectoryA(".\\b");
2960  RemoveDirectoryA(".\\c");
2961 
2962  if(psi_a) IShellItem_Release(psi_a);
2963  if(psi_b) IShellItem_Release(psi_b);
2964  if(psi_c) IShellItem_Release(psi_c);
2965 
2966  for(i = 0; i < 9; i++)
2967  if(psi[i]) IShellItem_Release(psi[i]);
2968 }
2969 
2970 /**************************************************************/
2971 /* IUnknown implementation for counting QueryInterface calls. */
2972 typedef struct {
2973  IUnknown IUnknown_iface;
2974  struct if_count {
2977  } *ifaces;
2979 } IUnknownImpl;
2980 
2982 {
2983  return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
2984 }
2985 
2987 {
2989  UINT i;
2990  BOOL found = FALSE;
2991  for(i = 0; This->ifaces[i].id != NULL; i++)
2992  {
2993  if(IsEqualIID(This->ifaces[i].id, riid))
2994  {
2995  This->ifaces[i].count++;
2996  found = TRUE;
2997  break;
2998  }
2999  }
3000  if(!found)
3001  This->unknown++;
3002  return E_NOINTERFACE;
3003 }
3004 
3006 {
3007  return 2;
3008 }
3009 
3011 {
3012  return 1;
3013 }
3014 
3015 static const IUnknownVtbl vt_IUnknown = {
3017  unk_fnAddRef,
3019 };
3020 
3022 {
3023  IUnknownImpl *punkimpl;
3024  IShellFolder *psfdesktop;
3025  IShellView *psv;
3026  LPITEMIDLIST pidl, pidl_desktop;
3027  HRESULT hres;
3028  UINT i;
3029  struct if_count ifaces[] =
3030  { {&IID_IPersistIDList, 0},
3031  {&IID_IPersistFolder2, 0},
3032  {&IID_IDataObject, 0},
3033  {&IID_IParentAndItem, 0},
3034  {&IID_IFolderView, 0},
3035  {NULL, 0} };
3036 
3037  if(!pSHGetIDListFromObject)
3038  {
3039  win_skip("SHGetIDListFromObject missing.\n");
3040  return;
3041  }
3042 
3043  if(0)
3044  {
3045  /* Crashes native */
3046  pSHGetIDListFromObject(NULL, NULL);
3047  pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
3048  }
3049 
3050  hres = pSHGetIDListFromObject(NULL, &pidl);
3051  ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3052 
3053  punkimpl = heap_alloc(sizeof(*punkimpl));
3054  punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3055  punkimpl->ifaces = ifaces;
3056  punkimpl->unknown = 0;
3057 
3058  hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3059  ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3060  ok(ifaces[0].count, "interface not requested.\n");
3061  ok(ifaces[1].count, "interface not requested.\n");
3062  ok(ifaces[2].count, "interface not requested.\n");
3063  todo_wine
3064  ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3065  "interface not requested.\n");
3066  ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3067  "interface not requested.\n");
3068 
3069  ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3070  heap_free(punkimpl);
3071 
3072  pidl_desktop = NULL;
3074  ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
3075 
3076  SHGetDesktopFolder(&psfdesktop);
3077 
3078  /* Test IShellItem */
3079  if(pSHCreateShellItem)
3080  {
3081  IShellItem *shellitem;
3082  hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
3083  ok(hres == S_OK, "got 0x%08x\n", hres);
3084  if(SUCCEEDED(hres))
3085  {
3086  hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
3087  ok(hres == S_OK, "got 0x%08x\n", hres);
3088  if(SUCCEEDED(hres))
3089  {
3090  ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3091  ILFree(pidl);
3092  }
3093  IShellItem_Release(shellitem);
3094  }
3095  }
3096  else
3097  skip("no SHCreateShellItem.\n");
3098 
3099  /* Test IShellFolder */
3100  hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
3101  ok(hres == S_OK, "got 0x%08x\n", hres);
3102  if(SUCCEEDED(hres))
3103  {
3104  ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3105  ILFree(pidl);
3106  }
3107 
3108  hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
3109  ok(hres == S_OK, "got 0x%08x\n", hres);
3110  if(SUCCEEDED(hres))
3111  {
3112  IEnumIDList *peidl;
3113  IDataObject *pdo;
3114  SHCONTF enum_flags;
3115 
3116  /* Test IFolderView */
3117  hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
3118  ok(hres == S_OK, "got 0x%08x\n", hres);
3119  if(SUCCEEDED(hres))
3120  {
3121  ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
3122  ILFree(pidl);
3123  }
3124 
3125  /* Test IDataObject */
3126  enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3127  hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
3128  ok(hres == S_OK, "got 0x%08x\n", hres);
3129  if(SUCCEEDED(hres))
3130  {
3131  LPITEMIDLIST apidl[5];
3132  UINT count = 0;
3133  for(count = 0; count < 5; count++)
3134  if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3135  break;
3136 
3137  if(count)
3138  {
3139  hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
3140  &IID_IDataObject, NULL, (void**)&pdo);
3141  ok(hres == S_OK, "got 0x%08x\n", hres);
3142  if(SUCCEEDED(hres))
3143  {
3144  pidl = (void*)0xDEADBEEF;
3145  hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3146  ok(hres == S_OK, "got 0x%08x\n", hres);
3147  ok(pidl != NULL, "pidl is NULL.\n");
3148  ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
3149  ILFree(pidl);
3150 
3151  IDataObject_Release(pdo);
3152  }
3153  }
3154  else
3155  skip("No files found - skipping single-file test.\n");
3156 
3157  if(count > 1)
3158  {
3159  hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
3160  &IID_IDataObject, NULL, (void**)&pdo);
3161  ok(hres == S_OK, "got 0x%08x\n", hres);
3162  if(SUCCEEDED(hres))
3163  {
3164  pidl = (void*)0xDEADBEEF;
3165  hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
3166  ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
3167  "got 0x%08x\n", hres);
3168  ok(pidl == NULL, "pidl is not NULL.\n");
3169 
3170  IDataObject_Release(pdo);
3171  }
3172  }
3173  else
3174  skip("zero or one file found - skipping multi-file test.\n");
3175 
3176  for(i = 0; i < count; i++)
3177  ILFree(apidl[i]);
3178 
3179  IEnumIDList_Release(peidl);
3180  }
3181 
3182  IShellView_Release(psv);
3183  }
3184 
3185  IShellFolder_Release(psfdesktop);
3186  ILFree(pidl_desktop);
3187 }
3188 
3189 static void test_SHGetItemFromObject(void)
3190 {
3191  IUnknownImpl *punkimpl;
3192  IShellFolder *psfdesktop;
3193  LPITEMIDLIST pidl;
3194  IShellItem *psi;
3195  IUnknown *punk;
3196  HRESULT hres;
3197  struct if_count ifaces[] =
3198  { {&IID_IPersistIDList, 0},
3199  {&IID_IPersistFolder2, 0},
3200  {&IID_IDataObject, 0},
3201  {&IID_IParentAndItem, 0},
3202  {&IID_IFolderView, 0},
3203  {NULL, 0} };
3204 
3205  if(!pSHGetItemFromObject)
3206  {
3207  skip("No SHGetItemFromObject.\n");
3208  return;
3209  }
3210 
3211  SHGetDesktopFolder(&psfdesktop);
3212 
3213  if(0)
3214  {
3215  /* Crashes with Windows 7 */
3216  pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
3217  pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
3218  pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
3219  }
3220 
3221  hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
3222  ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
3223 
3224  punkimpl = heap_alloc(sizeof(*punkimpl));
3225  punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
3226  punkimpl->ifaces = ifaces;
3227  punkimpl->unknown = 0;
3228 
3229  /* The same as SHGetIDListFromObject */
3230  hres = pSHGetIDListFromObject(&punkimpl->IUnknown_iface, &pidl);
3231  ok(hres == E_NOINTERFACE, "Got %x\n", hres);
3232  ok(ifaces[0].count, "interface not requested.\n");
3233  ok(ifaces[1].count, "interface not requested.\n");
3234  ok(ifaces[2].count, "interface not requested.\n");
3235  todo_wine
3236  ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
3237  "interface not requested.\n");
3238  ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
3239  "interface not requested.\n");
3240 
3241  ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
3242  heap_free(punkimpl);
3243 
3244  /* Test IShellItem */
3245  hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
3246  ok(hres == S_OK, "Got 0x%08x\n", hres);
3247  if(SUCCEEDED(hres))
3248  {
3249  IShellItem *psi2;
3250  hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
3251  ok(hres == S_OK, "Got 0x%08x\n", hres);
3252  if(SUCCEEDED(hres))
3253  {
3254  todo_wine
3255  ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
3256  IShellItem_Release(psi2);
3257  }
3258  IShellItem_Release(psi);
3259  }
3260 
3261  IShellFolder_Release(psfdesktop);
3262 }
3263 
3265 {
3266  IShellFolder *pdesktopsf, *psf;
3267  IShellItemArray *psia;
3268  IEnumIDList *peidl;
3269  HRESULT hr;
3270  WCHAR cTestDirW[MAX_PATH];
3271  LPITEMIDLIST pidl_testdir, pidl;
3272  static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3273 
3274  if(!pSHCreateShellItemArray) {
3275  skip("No pSHCreateShellItemArray!\n");
3276  return;
3277  }
3278 
3279  if(0)
3280  {
3281  /* Crashes under native */
3282  pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
3283  pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
3284  pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
3285  pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
3286  }
3287 
3288  hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
3289  ok(hr == E_POINTER, "got 0x%08x\n", hr);
3290 
3291  SHGetDesktopFolder(&pdesktopsf);
3292  hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
3293  ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3294 
3295  hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
3296  ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3297 
3299  hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
3300  ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3301  ILFree(pidl);
3302 
3303  GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3304  myPathAddBackslashW(cTestDirW);
3305  lstrcatW(cTestDirW, testdirW);
3306 
3308 
3309  hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
3310  ok(hr == S_OK, "got 0x%08x\n", hr);
3311  if(SUCCEEDED(hr))
3312  {
3313  hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
3314  (void**)&psf);
3315  ok(hr == S_OK, "Got 0x%08x\n", hr);
3316  }
3317  IShellFolder_Release(pdesktopsf);
3318 
3319  if(FAILED(hr))
3320  {
3321  skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
3322  ILFree(pidl_testdir);
3323  Cleanup();
3324  return;
3325  }
3326 
3327  hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
3328  ok(hr == S_OK, "Got %08x\n", hr);
3329  if(SUCCEEDED(hr))
3330  {
3331  LPITEMIDLIST apidl[5];
3332  UINT done, numitems, i;
3333 
3334  for(done = 0; done < 5; done++)
3335  if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
3336  break;
3337  ok(done == 5, "Got %d pidls\n", done);
3338  IEnumIDList_Release(peidl);
3339 
3340  /* Create a ShellItemArray */
3341  hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
3342  ok(hr == S_OK, "Got 0x%08x\n", hr);
3343  if(SUCCEEDED(hr))
3344  {
3345  IShellItem *psi;
3346 
3347  if(0)
3348  {
3349  /* Crashes in Windows 7 */
3350  IShellItemArray_GetCount(psia, NULL);
3351  }
3352 
3353  IShellItemArray_GetCount(psia, &numitems);
3354  ok(numitems == done, "Got %d, expected %d\n", numitems, done);
3355 
3356  hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
3357  ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3358 
3359  /* Compare all the items */
3360  for(i = 0; i < numitems; i++)
3361  {
3362  LPITEMIDLIST pidl_abs;
3363  pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3364 
3365  hr = IShellItemArray_GetItemAt(psia, i, &psi);
3366  ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
3367  if(SUCCEEDED(hr))
3368  {
3369  hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3370  ok(hr == S_OK, "Got 0x%08x\n", hr);
3371  if(SUCCEEDED(hr))
3372  {
3373  ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
3374  ILFree(pidl);
3375  }
3376  IShellItem_Release(psi);
3377  }
3378  ILFree(pidl_abs);
3379  }
3380  for(i = 0; i < done; i++)
3381  ILFree(apidl[i]);
3382  IShellItemArray_Release(psia);
3383  }
3384  }
3385 
3386  /* SHCreateShellItemArrayFromShellItem */
3387  if(pSHCreateShellItemArrayFromShellItem)
3388  {
3389  IShellItem *psi;
3390 
3391  if(0)
3392  {
3393  /* Crashes under Windows 7 */
3394  pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
3395  pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
3396  pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
3397  }
3398 
3399  hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
3400  ok(hr == S_OK, "Got 0x%08x\n", hr);
3401  if(SUCCEEDED(hr))
3402  {
3403  hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
3404  ok(hr == S_OK, "Got 0x%08x\n", hr);
3405  if(SUCCEEDED(hr))
3406  {
3407  IShellItem *psi2;
3408  UINT count;
3409  hr = IShellItemArray_GetCount(psia, &count);
3410  ok(hr == S_OK, "Got 0x%08x\n", hr);
3411  ok(count == 1, "Got count %d\n", count);
3412  hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
3413  ok(hr == S_OK, "Got 0x%08x\n", hr);
3414  todo_wine
3415  ok(psi != psi2, "ShellItems are of the same instance.\n");
3416  if(SUCCEEDED(hr))
3417  {
3418  LPITEMIDLIST pidl1, pidl2;
3419  hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
3420  ok(hr == S_OK, "Got 0x%08x\n", hr);
3421  ok(pidl1 != NULL, "pidl1 was null.\n");
3422  hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
3423  ok(hr == S_OK, "Got 0x%08x\n", hr);
3424  ok(pidl2 != NULL, "pidl2 was null.\n");
3425  ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
3426  ILFree(pidl1);
3427  ILFree(pidl2);
3428  IShellItem_Release(psi2);
3429  }
3430  hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
3431  ok(hr == E_FAIL, "Got 0x%08x\n", hr);
3432  IShellItemArray_Release(psia);
3433  }
3434  IShellItem_Release(psi);
3435  }
3436  }
3437  else
3438  skip("No SHCreateShellItemArrayFromShellItem.\n");
3439 
3440  if(pSHCreateShellItemArrayFromDataObject)
3441  {
3442  IShellView *psv;
3443 
3444  if(0)
3445  {
3446  /* Crashes under Windows 7 */
3447  pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
3448  }
3449  hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
3450  ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3451 
3452  hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
3453  ok(hr == S_OK, "got 0x%08x\n", hr);
3454  if(SUCCEEDED(hr))
3455  {
3456  IEnumIDList *peidl;
3457  IDataObject *pdo;
3458  SHCONTF enum_flags;
3459 
3460  enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
3461  hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
3462  ok(hr == S_OK, "got 0x%08x\n", hr);
3463  if(SUCCEEDED(hr))
3464  {
3465  LPITEMIDLIST apidl[5];
3466  UINT count, i;
3467 
3468  for(count = 0; count < 5; count++)
3469  if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
3470  break;
3471  ok(count == 5, "Got %d\n", count);
3472 
3473  if(count)
3474  {
3475  hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
3476  &IID_IDataObject, NULL, (void**)&pdo);
3477  ok(hr == S_OK, "Got 0x%08x\n", hr);
3478  if(SUCCEEDED(hr))
3479  {
3480  hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
3481  (void**)&psia);
3482  ok(hr == S_OK, "Got 0x%08x\n", hr);
3483  if(SUCCEEDED(hr))
3484  {
3485  UINT count_sia, i;
3486  hr = IShellItemArray_GetCount(psia, &count_sia);
3487  ok(hr == S_OK, "Got 0x%08x\n", hr);
3488  ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
3489  for(i = 0; i < count_sia; i++)
3490  {
3491  LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
3492  IShellItem *psi;
3493  hr = IShellItemArray_GetItemAt(psia, i, &psi);
3494  ok(hr == S_OK, "Got 0x%08x\n", hr);
3495  if(SUCCEEDED(hr))
3496  {
3497  LPITEMIDLIST pidl;
3498  hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
3499  ok(hr == S_OK, "Got 0x%08x\n", hr);
3500  ok(pidl != NULL, "pidl as NULL.\n");
3501  ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
3502  ILFree(pidl);
3503  IShellItem_Release(psi);
3504  }
3505  ILFree(pidl_abs);
3506  }
3507 
3508  IShellItemArray_Release(psia);
3509  }
3510 
3511  IDataObject_Release(pdo);
3512  }
3513  for(i = 0; i < count; i++)
3514  ILFree(apidl[i]);
3515  }
3516  else
3517  skip("No files found - skipping test.\n");
3518 
3519  IEnumIDList_Release(peidl);
3520  }
3521  IShellView_Release(psv);
3522  }
3523  }
3524  else
3525  skip("No SHCreateShellItemArrayFromDataObject.\n");
3526 
3527  if(pSHCreateShellItemArrayFromIDLists)
3528  {
3529  WCHAR test1W[] = {'t','e','s','t','1','.','t','x','t',0};
3530  WCHAR test1pathW[MAX_PATH];
3531  LPITEMIDLIST pidltest1;
3532  LPCITEMIDLIST pidl_array[2];
3533 
3534  if(0)
3535  {
3536  /* Crashes */
3537  hr = pSHCreateShellItemArrayFromIDLists(0, NULL, NULL);
3538  }
3539 
3540  psia = (void*)0xdeadbeef;
3541  hr = pSHCreateShellItemArrayFromIDLists(0, NULL, &psia);
3542  ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3543  ok(psia == NULL, "Got %p\n", psia);
3544 
3545  psia = (void*)0xdeadbeef;
3546  hr = pSHCreateShellItemArrayFromIDLists(0, pidl_array, &psia);
3547  ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
3548  ok(psia == NULL, "Got %p\n", psia);
3549 
3550  psia = (void*)0xdeadbeef;
3551  pidl_array[0] = NULL;
3552  hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3553  todo_wine ok(hr == E_OUTOFMEMORY, "Got 0x%08x\n", hr);
3554  ok(psia == NULL, "Got %p\n", psia);
3555 
3556  psia = (void*)0xdeadbeef;
3557  pidl_array[0] = pidl_testdir;
3558  pidl_array[1] = NULL;
3559  hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3560  todo_wine ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Vista */, "Got 0x%08x\n", hr);
3561  todo_wine ok(psia != NULL || broken(psia == NULL) /* Vista */, "Got %p\n", psia);
3562  if(SUCCEEDED(hr))
3563  {
3564  IShellItem *psi;
3565  UINT count = 0;
3566 
3567  hr = IShellItemArray_GetCount(psia, &count);
3568  ok(hr == S_OK, "Got 0x%08x\n", hr);
3569  ok(count == 2, "Got %d\n", count);
3570 
3571  hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3572  ok(hr == S_OK, "Got 0x%08x\n", hr);
3573  if(SUCCEEDED(hr))
3574  {
3575  LPWSTR path;
3576  hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3577  ok(hr == S_OK, "Got 0x%08x\n", hr);
3578  ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3579  if(SUCCEEDED(hr))
3581 
3582  IShellItem_Release(psi);
3583  }
3584 
3585  hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3586  ok(hr == S_OK, "Got 0x%08x\n", hr);
3587  if(SUCCEEDED(hr))
3588  {
3589  LPWSTR path;
3590  WCHAR desktoppath[MAX_PATH];
3591  BOOL result;
3592 
3594  ok(result, "SHGetSpecialFolderPathW(CSIDL_DESKTOPDIRECTORY) failed! %u\n", GetLastError());
3595 
3596  hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3597  ok(hr == S_OK, "Got 0x%08x\n", hr);
3598  ok(!lstrcmpW(path, desktoppath), "Got %s\n", wine_dbgstr_w(path));
3599  if(SUCCEEDED(hr))
3601 
3602  IShellItem_Release(psi);
3603  }
3604 
3605 
3606  IShellItemArray_Release(psia);
3607  }
3608 
3609 
3610  /* Single pidl */
3611  psia = (void*)0xdeadbeef;
3612  pidl_array[0] = pidl_testdir;
3613  hr = pSHCreateShellItemArrayFromIDLists(1, pidl_array, &psia);
3614  ok(hr == S_OK, "Got 0x%08x\n", hr);
3615  if(SUCCEEDED(hr))
3616  {
3617  IShellItem *psi;
3618  UINT count = 0;
3619 
3620  hr = IShellItemArray_GetCount(psia, &count);
3621  ok(hr == S_OK, "Got 0x%08x\n", hr);
3622  ok(count == 1, "Got %d\n", count);
3623 
3624  hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3625  ok(hr == S_OK, "Got 0x%08x\n", hr);
3626  if(SUCCEEDED(hr))
3627  {
3628  LPWSTR path;
3629  hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3630  ok(hr == S_OK, "Got 0x%08x\n", hr);
3631  ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3632  if(SUCCEEDED(hr))
3634 
3635  IShellItem_Release(psi);
3636  }
3637 
3638  IShellItemArray_Release(psia);
3639  }
3640 
3641 
3642  lstrcpyW(test1pathW, cTestDirW);
3643  myPathAddBackslashW(test1pathW);
3644  lstrcatW(test1pathW, test1W);
3645 
3646  SHGetDesktopFolder(&pdesktopsf);
3647 
3648  hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, test1pathW, NULL, &pidltest1, NULL);
3649  ok(hr == S_OK, "Got 0x%08x\n", hr);
3650  if(SUCCEEDED(hr))
3651  {
3652  psia = (void*)0xdeadbeef;
3653  pidl_array[0] = pidl_testdir;
3654  pidl_array[1] = pidltest1;
3655  hr = pSHCreateShellItemArrayFromIDLists(2, pidl_array, &psia);
3656  ok(hr == S_OK, "Got 0x%08x\n", hr);
3657  if(SUCCEEDED(hr))
3658  {
3659  IShellItem *psi;
3660  UINT count = 0;
3661 
3662  hr = IShellItemArray_GetCount(psia, &count);
3663  ok(hr == S_OK, "Got 0x%08x\n", hr);
3664  ok(count == 2, "Got %d\n", count);
3665 
3666  hr = IShellItemArray_GetItemAt(psia, 0, &psi);
3667  ok(hr == S_OK, "Got 0x%08x\n", hr);
3668  if(SUCCEEDED(hr))
3669  {
3670  LPWSTR path;
3671  hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3672  ok(hr == S_OK, "Got 0x%08x\n", hr);
3673  ok(!lstrcmpW(path, cTestDirW), "Got %s\n", wine_dbgstr_w(path));
3674  if(SUCCEEDED(hr))
3676 
3677  IShellItem_Release(psi);
3678  }
3679 
3680  hr = IShellItemArray_GetItemAt(psia, 1, &psi);
3681  ok(hr == S_OK, "Got 0x%08x\n", hr);
3682  if(SUCCEEDED(hr))
3683  {
3684  LPWSTR path;
3685  hr = IShellItem_GetDisplayName(psi, SIGDN_DESKTOPABSOLUTEPARSING, &path);
3686  ok(hr == S_OK, "Got 0x%08x\n", hr);
3687  ok(!lstrcmpW(path, test1pathW), "Got %s\n", wine_dbgstr_w(path));
3688  if(SUCCEEDED(hr))
3690 
3691  IShellItem_Release(psi);
3692  }
3693 
3694 
3695  IShellItemArray_Release(psia);
3696  }
3697 
3698  ILFree(pidltest1);
3699  }
3700 
3701  IShellFolder_Release(pdesktopsf);
3702  }
3703  else
3704  skip("No SHCreateShellItemArrayFromIDLists.\n");
3705 
3706  IShellFolder_Release(psf);
3707  ILFree(pidl_testdir);
3708  Cleanup();
3709 }
3710 
3712 {
3713  IShellFolder *pdesktopsf, *psf;
3714  IEnumIDList *peidl;
3715  WCHAR cTestDirW[MAX_PATH];
3716  HRESULT hr;
3717  LPITEMIDLIST pidl_testdir;
3718  static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
3719 
3720  if(!pSHCreateShellItemArray)
3721  {
3722  win_skip("No SHCreateShellItemArray, skipping test...\n");
3723  return;
3724  }
3725 
3727 
3728  SHGetDesktopFolder(&pdesktopsf);
3729 
3730  GetCurrentDirectoryW(MAX_PATH, cTestDirW);
3731  myPathAddBackslashW(cTestDirW);
3732  lstrcatW(cTestDirW, testdirW);
3733 
3734  hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL,