1 /*
2  * Unit tests for shell32 SHGet{Special}Folder{Path|Location} functions.
3  *
4  * Copyright 2004 Juan Lang
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  * This is a test program for the SHGet{Special}Folder{Path|Location} functions
20  * of shell32, that get either a filesystem path or a LPITEMIDLIST (shell
21  * namespace) path for a given folder (CSIDL value).
22  */
23 
24 #include "precomp.h"
25 
26 #include <initguid.h>
27 
28 /* CSIDL_MYDOCUMENTS is now the same as CSIDL_PERSONAL, but what we want
29  * here is its original value.
30  */
31 #define OLD_CSIDL_MYDOCUMENTS  0x000c
32 
33 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
34 
35 #ifndef ARRAY_SIZE
36 #define ARRAY_SIZE(x) ( sizeof(x) / sizeof((x)[0]) )
37 #endif
38 
39 /* from pidl.h, not included here: */
40 #ifndef PT_CPL             /* Guess, Win7 uses this for CSIDL_CONTROLS */
41 #define PT_CPL        0x01 /* no path */
42 #endif
43 #ifndef PT_GUID
44 #define PT_GUID       0x1f /* no path */
45 #endif
46 #ifndef PT_DRIVE
47 #define PT_DRIVE      0x23 /* has path */
48 #endif
49 #ifndef PT_DRIVE2
50 #define PT_DRIVE2     0x25 /* has path */
51 #endif
52 #ifndef PT_SHELLEXT
53 #define PT_SHELLEXT   0x2e /* no path */
54 #endif
55 #ifndef PT_FOLDER
56 #define PT_FOLDER     0x31 /* has path */
57 #endif
58 #ifndef PT_FOLDERW
59 #define PT_FOLDERW    0x35 /* has path */
60 #endif
61 #ifndef PT_WORKGRP
62 #define PT_WORKGRP    0x41 /* no path */
63 #endif
64 #ifndef PT_YAGUID
65 #define PT_YAGUID     0x70 /* no path */
66 #endif
67 /* FIXME: this is used for history/favorites folders; what's a better name? */
68 #ifndef PT_IESPECIAL2
69 #define PT_IESPECIAL2 0xb1 /* has path */
70 #endif
71 
72 static GUID CLSID_CommonDocuments = { 0x0000000c, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1a } };
73 
74 struct shellExpectedValues {
75     int folder;
76     int numTypes;
77     const BYTE *types;
78 };
79 
80 static HRESULT (WINAPI *pDllGetVersion)(DLLVERSIONINFO *);
81 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
82 static HRESULT (WINAPI *pSHGetFolderLocation)(HWND, int, HANDLE, DWORD,
83  LPITEMIDLIST *);
84 static BOOL    (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
85 static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
86 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
87 static int (WINAPI *pSHFileOperationA)(LPSHFILEOPSTRUCTA);
88 static HRESULT (WINAPI *pSHGetMalloc)(LPMALLOC *);
89 static UINT (WINAPI *pGetSystemWow64DirectoryA)(LPSTR,UINT);
90 static HRESULT (WINAPI *pSHGetKnownFolderPath)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *);
91 static HRESULT (WINAPI *pSHSetKnownFolderPath)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR);
92 static HRESULT (WINAPI *pSHGetFolderPathEx)(REFKNOWNFOLDERID, DWORD, HANDLE, LPWSTR, DWORD);
93 static BOOL (WINAPI *pPathYetAnotherMakeUniqueName)(PWSTR, PCWSTR, PCWSTR, PCWSTR);
94 static HRESULT (WINAPI *pSHGetKnownFolderIDList)(REFKNOWNFOLDERID, DWORD, HANDLE, PIDLIST_ABSOLUTE*);
95 
96 static DLLVERSIONINFO shellVersion = { 0 };
97 static LPMALLOC pMalloc;
98 static const BYTE guidType[] = { PT_GUID };
99 static const BYTE controlPanelType[] = { PT_SHELLEXT, PT_GUID, PT_CPL };
100 static const BYTE folderType[] = { PT_FOLDER, PT_FOLDERW };
101 static const BYTE favoritesType[] = { PT_FOLDER, PT_FOLDERW, 0, PT_IESPECIAL2 /* Win98 */ };
102 static const BYTE folderOrSpecialType[] = { PT_FOLDER, PT_IESPECIAL2 };
103 static const BYTE personalType[] = { PT_FOLDER, PT_GUID, PT_DRIVE, 0xff /* Win9x */,
104  PT_IESPECIAL2 /* Win98 */, 0 /* Vista */, PT_SHELLEXT /* win8 */ };
105 /* FIXME: don't know the type of 0x71 returned by Vista/2008 for printers */
106 static const BYTE printersType[] = { PT_YAGUID, PT_SHELLEXT, 0x71 };
107 static const BYTE ieSpecialType[] = { PT_IESPECIAL2 };
108 static const BYTE shellExtType[] = { PT_SHELLEXT };
109 static const BYTE workgroupType[] = { PT_WORKGRP };
110 #define DECLARE_TYPE(x, y) { x, sizeof(y) / sizeof(y[0]), y }
111 static const struct shellExpectedValues requiredShellValues[] = {
112  DECLARE_TYPE(CSIDL_BITBUCKET, guidType),
113  DECLARE_TYPE(CSIDL_CONTROLS, controlPanelType),
114  DECLARE_TYPE(CSIDL_COOKIES, folderType),
115  DECLARE_TYPE(CSIDL_DESKTOPDIRECTORY, folderType),
116  DECLARE_TYPE(CSIDL_DRIVES, guidType),
117  DECLARE_TYPE(CSIDL_FAVORITES, favoritesType),
118  DECLARE_TYPE(CSIDL_FONTS, folderOrSpecialType),
119 /* FIXME: the following fails in Wine, returns type PT_FOLDER
120  DECLARE_TYPE(CSIDL_HISTORY, ieSpecialType),
121  */
122  DECLARE_TYPE(CSIDL_INTERNET, guidType),
123  DECLARE_TYPE(CSIDL_NETHOOD, folderType),
124  DECLARE_TYPE(CSIDL_NETWORK, guidType),
125  DECLARE_TYPE(CSIDL_PERSONAL, personalType),
126  DECLARE_TYPE(CSIDL_PRINTERS, printersType),
127  DECLARE_TYPE(CSIDL_PRINTHOOD, folderType),
128  DECLARE_TYPE(CSIDL_PROGRAMS, folderType),
129  DECLARE_TYPE(CSIDL_RECENT, folderOrSpecialType),
130  DECLARE_TYPE(CSIDL_SENDTO, folderType),
131  DECLARE_TYPE(CSIDL_STARTMENU, folderType),
132  DECLARE_TYPE(CSIDL_STARTUP, folderType),
133  DECLARE_TYPE(CSIDL_TEMPLATES, folderType),
134 };
135 static const struct shellExpectedValues optionalShellValues[] = {
136 /* FIXME: the following only semi-succeed; they return NULL PIDLs on XP.. hmm.
137  DECLARE_TYPE(CSIDL_ALTSTARTUP, folderType),
138  DECLARE_TYPE(CSIDL_COMMON_ALTSTARTUP, folderType),
139  DECLARE_TYPE(CSIDL_COMMON_OEM_LINKS, folderType),
140  */
141 /* Windows NT-only: */
142  DECLARE_TYPE(CSIDL_COMMON_DESKTOPDIRECTORY, folderType),
143  DECLARE_TYPE(CSIDL_COMMON_DOCUMENTS, shellExtType),
144  DECLARE_TYPE(CSIDL_COMMON_FAVORITES, folderType),
145  DECLARE_TYPE(CSIDL_COMMON_PROGRAMS, folderType),
146  DECLARE_TYPE(CSIDL_COMMON_STARTMENU, folderType),
147  DECLARE_TYPE(CSIDL_COMMON_STARTUP, folderType),
148  DECLARE_TYPE(CSIDL_COMMON_TEMPLATES, folderType),
149 /* first appearing in shell32 version 4.71: */
150  DECLARE_TYPE(CSIDL_APPDATA, folderType),
151 /* first appearing in shell32 version 4.72: */
152  DECLARE_TYPE(CSIDL_INTERNET_CACHE, ieSpecialType),
153 /* first appearing in shell32 version 5.0: */
154  DECLARE_TYPE(CSIDL_ADMINTOOLS, folderType),
155  DECLARE_TYPE(CSIDL_COMMON_APPDATA, folderType),
156  DECLARE_TYPE(CSIDL_LOCAL_APPDATA, folderType),
157  DECLARE_TYPE(OLD_CSIDL_MYDOCUMENTS, folderType),
158  DECLARE_TYPE(CSIDL_MYMUSIC, folderType),
159  DECLARE_TYPE(CSIDL_MYPICTURES, folderType),
160  DECLARE_TYPE(CSIDL_MYVIDEO, folderType),
161  DECLARE_TYPE(CSIDL_PROFILE, folderType),
162  DECLARE_TYPE(CSIDL_PROGRAM_FILES, folderType),
163  DECLARE_TYPE(CSIDL_PROGRAM_FILESX86, folderType),
164  DECLARE_TYPE(CSIDL_PROGRAM_FILES_COMMON, folderType),
165  DECLARE_TYPE(CSIDL_PROGRAM_FILES_COMMONX86, folderType),
166  DECLARE_TYPE(CSIDL_SYSTEM, folderType),
167  DECLARE_TYPE(CSIDL_WINDOWS, folderType),
168 /* first appearing in shell32 6.0: */
169  DECLARE_TYPE(CSIDL_CDBURN_AREA, folderType),
170  DECLARE_TYPE(CSIDL_COMMON_MUSIC, folderType),
171  DECLARE_TYPE(CSIDL_COMMON_PICTURES, folderType),
172  DECLARE_TYPE(CSIDL_COMMON_VIDEO, folderType),
173  DECLARE_TYPE(CSIDL_COMPUTERSNEARME, workgroupType),
174  DECLARE_TYPE(CSIDL_RESOURCES, folderType),
175  DECLARE_TYPE(CSIDL_RESOURCES_LOCALIZED, folderType),
176 };
177 #undef DECLARE_TYPE
178 
179 static void loadShell32(void)
180 {
181     HMODULE hShell32 = GetModuleHandleA("shell32");
182 
183 #define GET_PROC(func) \
184     p ## func = (void*)GetProcAddress(hShell32, #func); \
185     if(!p ## func) \
186       trace("GetProcAddress(%s) failed\n", #func);
187 
188     GET_PROC(DllGetVersion)
189     GET_PROC(SHGetFolderPathA)
190     GET_PROC(SHGetFolderPathEx)
191     GET_PROC(SHGetFolderLocation)
192     GET_PROC(SHGetKnownFolderPath)
193     GET_PROC(SHSetKnownFolderPath)
194     GET_PROC(SHGetSpecialFolderPathA)
195     GET_PROC(SHGetSpecialFolderLocation)
196     GET_PROC(ILFindLastID)
197     if (!pILFindLastID)
198         pILFindLastID = (void *)GetProcAddress(hShell32, (LPCSTR)16);
199     GET_PROC(SHFileOperationA)
200     GET_PROC(SHGetMalloc)
201     GET_PROC(PathYetAnotherMakeUniqueName)
202     GET_PROC(SHGetKnownFolderIDList)
203 
204     ok(pSHGetMalloc != NULL, "shell32 is missing SHGetMalloc\n");
205     if (pSHGetMalloc)
206     {
207         HRESULT hr = pSHGetMalloc(&pMalloc);
208 
209         ok(hr == S_OK, "SHGetMalloc failed: 0x%08x\n", hr);
210         ok(pMalloc != NULL, "SHGetMalloc returned a NULL IMalloc\n");
211     }
212 
213     if (pDllGetVersion)
214     {
215         shellVersion.cbSize = sizeof(shellVersion);
216         pDllGetVersion(&shellVersion);
217         trace("shell32 version is %d.%d\n",
218               shellVersion.dwMajorVersion, shellVersion.dwMinorVersion);
219     }
220 #undef GET_PROC
221 }
222 
223 #ifndef CSIDL_PROFILES
224 #define CSIDL_PROFILES		0x003e
225 #endif
226 
227 /* A couple utility printing functions */
228 static const char *getFolderName(int folder)
229 {
230     static char unknown[32];
231 
232 #define CSIDL_TO_STR(x) case x: return#x;
233     switch (folder)
234     {
235     CSIDL_TO_STR(CSIDL_DESKTOP);
236     CSIDL_TO_STR(CSIDL_INTERNET);
237     CSIDL_TO_STR(CSIDL_PROGRAMS);
238     CSIDL_TO_STR(CSIDL_CONTROLS);
239     CSIDL_TO_STR(CSIDL_PRINTERS);
240     CSIDL_TO_STR(CSIDL_PERSONAL);
241     CSIDL_TO_STR(CSIDL_FAVORITES);
242     CSIDL_TO_STR(CSIDL_STARTUP);
243     CSIDL_TO_STR(CSIDL_RECENT);
244     CSIDL_TO_STR(CSIDL_SENDTO);
245     CSIDL_TO_STR(CSIDL_BITBUCKET);
246     CSIDL_TO_STR(CSIDL_STARTMENU);
247     CSIDL_TO_STR(OLD_CSIDL_MYDOCUMENTS);
248     CSIDL_TO_STR(CSIDL_MYMUSIC);
249     CSIDL_TO_STR(CSIDL_MYVIDEO);
250     CSIDL_TO_STR(CSIDL_DESKTOPDIRECTORY);
251     CSIDL_TO_STR(CSIDL_DRIVES);
252     CSIDL_TO_STR(CSIDL_NETWORK);
253     CSIDL_TO_STR(CSIDL_NETHOOD);
254     CSIDL_TO_STR(CSIDL_FONTS);
255     CSIDL_TO_STR(CSIDL_TEMPLATES);
256     CSIDL_TO_STR(CSIDL_COMMON_STARTMENU);
257     CSIDL_TO_STR(CSIDL_COMMON_PROGRAMS);
258     CSIDL_TO_STR(CSIDL_COMMON_STARTUP);
259     CSIDL_TO_STR(CSIDL_COMMON_DESKTOPDIRECTORY);
260     CSIDL_TO_STR(CSIDL_APPDATA);
261     CSIDL_TO_STR(CSIDL_PRINTHOOD);
262     CSIDL_TO_STR(CSIDL_LOCAL_APPDATA);
263     CSIDL_TO_STR(CSIDL_ALTSTARTUP);
264     CSIDL_TO_STR(CSIDL_COMMON_ALTSTARTUP);
265     CSIDL_TO_STR(CSIDL_COMMON_FAVORITES);
266     CSIDL_TO_STR(CSIDL_INTERNET_CACHE);
267     CSIDL_TO_STR(CSIDL_COOKIES);
268     CSIDL_TO_STR(CSIDL_HISTORY);
269     CSIDL_TO_STR(CSIDL_COMMON_APPDATA);
270     CSIDL_TO_STR(CSIDL_WINDOWS);
271     CSIDL_TO_STR(CSIDL_SYSTEM);
272     CSIDL_TO_STR(CSIDL_PROGRAM_FILES);
273     CSIDL_TO_STR(CSIDL_MYPICTURES);
274     CSIDL_TO_STR(CSIDL_PROFILE);
275     CSIDL_TO_STR(CSIDL_SYSTEMX86);
276     CSIDL_TO_STR(CSIDL_PROGRAM_FILESX86);
277     CSIDL_TO_STR(CSIDL_PROGRAM_FILES_COMMON);
278     CSIDL_TO_STR(CSIDL_PROGRAM_FILES_COMMONX86);
279     CSIDL_TO_STR(CSIDL_COMMON_TEMPLATES);
280     CSIDL_TO_STR(CSIDL_COMMON_DOCUMENTS);
281     CSIDL_TO_STR(CSIDL_COMMON_ADMINTOOLS);
282     CSIDL_TO_STR(CSIDL_ADMINTOOLS);
283     CSIDL_TO_STR(CSIDL_CONNECTIONS);
284     CSIDL_TO_STR(CSIDL_PROFILES);
285     CSIDL_TO_STR(CSIDL_COMMON_MUSIC);
286     CSIDL_TO_STR(CSIDL_COMMON_PICTURES);
287     CSIDL_TO_STR(CSIDL_COMMON_VIDEO);
288     CSIDL_TO_STR(CSIDL_RESOURCES);
289     CSIDL_TO_STR(CSIDL_RESOURCES_LOCALIZED);
290     CSIDL_TO_STR(CSIDL_COMMON_OEM_LINKS);
291     CSIDL_TO_STR(CSIDL_CDBURN_AREA);
292     CSIDL_TO_STR(CSIDL_COMPUTERSNEARME);
293 #undef CSIDL_TO_STR
294     default:
295         sprintf(unknown, "unknown (0x%04x)", folder);
296         return unknown;
297     }
298 }
299 
300 static void test_parameters(void)
301 {
302     LPITEMIDLIST pidl = NULL;
303     char path[MAX_PATH];
304     HRESULT hr;
305 
306     if (pSHGetFolderLocation)
307     {
308         /* check a bogus CSIDL: */
309         pidl = NULL;
310         hr = pSHGetFolderLocation(NULL, 0xeeee, NULL, 0, &pidl);
311         ok(hr == E_INVALIDARG, "got 0x%08x, expected E_INVALIDARG\n", hr);
312         if (hr == S_OK) IMalloc_Free(pMalloc, pidl);
313 
314         /* check a bogus user token: */
315         pidl = NULL;
316         hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, (HANDLE)2, 0, &pidl);
317         ok(hr == E_FAIL || hr == E_HANDLE, "got 0x%08x, expected E_FAIL or E_HANDLE\n", hr);
318         if (hr == S_OK) IMalloc_Free(pMalloc, pidl);
319 
320         /* a NULL pidl pointer crashes, so don't test it */
321     }
322 
323     if (pSHGetSpecialFolderLocation)
324     {
325         if (0)
326             /* crashes */
327             SHGetSpecialFolderLocation(NULL, 0, NULL);
328 
329         hr = pSHGetSpecialFolderLocation(NULL, 0xeeee, &pidl);
330         ok(hr == E_INVALIDARG, "got returned 0x%08x\n", hr);
331     }
332 
333     if (pSHGetFolderPathA)
334     {
335         /* expect 2's a bogus handle, especially since we didn't open it */
336         hr = pSHGetFolderPathA(NULL, CSIDL_DESKTOP, (HANDLE)2, SHGFP_TYPE_DEFAULT, path);
337         ok(hr == E_FAIL || hr == E_HANDLE || /* Vista and 2k8 */
338            broken(hr == S_OK), /* W2k and Me */ "got 0x%08x, expected E_FAIL\n", hr);
339 
340         hr = pSHGetFolderPathA(NULL, 0xeeee, NULL, SHGFP_TYPE_DEFAULT, path);
341         ok(hr == E_INVALIDARG, "got 0x%08x, expected E_INVALIDARG\n", hr);
342     }
343 
344     if (pSHGetSpecialFolderPathA)
345     {
346         BOOL ret;
347 
348         if (0)
349            pSHGetSpecialFolderPathA(NULL, NULL, CSIDL_BITBUCKET, FALSE);
350 
351         /* odd but true: calling with a NULL path still succeeds if it's a real
352          * dir (on some windows platform).  on winME it generates exception.
353          */
354         ret = pSHGetSpecialFolderPathA(NULL, path, CSIDL_PROGRAMS, FALSE);
355         ok(ret, "got %d\n", ret);
356 
357         ret = pSHGetSpecialFolderPathA(NULL, path, 0xeeee, FALSE);
358         ok(!ret, "got %d\n", ret);
359     }
360 }
361 
362 /* Returns the folder's PIDL type, or 0xff if one can't be found. */
363 static BYTE testSHGetFolderLocation(int folder)
364 {
365     LPITEMIDLIST pidl;
366     HRESULT hr;
367     BYTE ret = 0xff;
368 
369     /* treat absence of function as success */
370     if (!pSHGetFolderLocation) return TRUE;
371 
372     pidl = NULL;
373     hr = pSHGetFolderLocation(NULL, folder, NULL, 0, &pidl);
374     if (hr == S_OK)
375     {
376         if (pidl)
377         {
378             LPITEMIDLIST pidlLast = pILFindLastID(pidl);
379 
380             ok(pidlLast != NULL, "%s: ILFindLastID failed\n",
381              getFolderName(folder));
382             if (pidlLast)
383                 ret = pidlLast->mkid.abID[0];
384             IMalloc_Free(pMalloc, pidl);
385         }
386     }
387     return ret;
388 }
389 
390 /* Returns the folder's PIDL type, or 0xff if one can't be found. */
391 static BYTE testSHGetSpecialFolderLocation(int folder)
392 {
393     LPITEMIDLIST pidl;
394     HRESULT hr;
395     BYTE ret = 0xff;
396 
397     /* treat absence of function as success */
398     if (!pSHGetSpecialFolderLocation) return TRUE;
399 
400     pidl = NULL;
401     hr = pSHGetSpecialFolderLocation(NULL, folder, &pidl);
402     if (hr == S_OK)
403     {
404         if (pidl)
405         {
406             LPITEMIDLIST pidlLast = pILFindLastID(pidl);
407 
408             ok(pidlLast != NULL,
409                 "%s: ILFindLastID failed\n", getFolderName(folder));
410             if (pidlLast)
411                 ret = pidlLast->mkid.abID[0];
412             IMalloc_Free(pMalloc, pidl);
413         }
414     }
415     return ret;
416 }
417 
418 static void test_SHGetFolderPath(BOOL optional, int folder)
419 {
420     char path[MAX_PATH];
421     HRESULT hr;
422 
423     if (!pSHGetFolderPathA) return;
424 
425     hr = pSHGetFolderPathA(NULL, folder, NULL, SHGFP_TYPE_CURRENT, path);
426     ok(hr == S_OK || optional,
427      "SHGetFolderPathA(NULL, %s, NULL, SHGFP_TYPE_CURRENT, path) failed: 0x%08x\n", getFolderName(folder), hr);
428 }
429 
430 static void test_SHGetSpecialFolderPath(BOOL optional, int folder)
431 {
432     char path[MAX_PATH];
433     BOOL ret;
434 
435     if (!pSHGetSpecialFolderPathA) return;
436 
437     ret = pSHGetSpecialFolderPathA(NULL, path, folder, FALSE);
438     if (ret && winetest_interactive)
439         printf("%s: %s\n", getFolderName(folder), path);
440     ok(ret || optional,
441      "SHGetSpecialFolderPathA(NULL, path, %s, FALSE) failed\n",
442      getFolderName(folder));
443 }
444 
445 static void test_ShellValues(const struct shellExpectedValues testEntries[],
446  int numEntries, BOOL optional)
447 {
448     int i;
449 
450     for (i = 0; i < numEntries; i++)
451     {
452         BYTE type;
453         int j;
454         BOOL foundTypeMatch = FALSE;
455 
456         if (pSHGetFolderLocation)
457         {
458             type = testSHGetFolderLocation(testEntries[i].folder);
459             for (j = 0; !foundTypeMatch && j < testEntries[i].numTypes; j++)
460                 if (testEntries[i].types[j] == type)
461                     foundTypeMatch = TRUE;
462             ok(foundTypeMatch || optional || broken(type == 0xff) /* Win9x */,
463              "%s has unexpected type %d (0x%02x)\n",
464              getFolderName(testEntries[i].folder), type, type);
465         }
466         type = testSHGetSpecialFolderLocation(testEntries[i].folder);
467         for (j = 0, foundTypeMatch = FALSE; !foundTypeMatch &&
468          j < testEntries[i].numTypes; j++)
469             if (testEntries[i].types[j] == type)
470                 foundTypeMatch = TRUE;
471         ok(foundTypeMatch || optional || broken(type == 0xff) /* Win9x */,
472          "%s has unexpected type %d (0x%02x)\n",
473          getFolderName(testEntries[i].folder), type, type);
474         switch (type)
475         {
476             case PT_FOLDER:
477             case PT_DRIVE:
478             case PT_DRIVE2:
479             case PT_IESPECIAL2:
480                 test_SHGetFolderPath(optional, testEntries[i].folder);
481                 test_SHGetSpecialFolderPath(optional, testEntries[i].folder);
482                 break;
483         }
484     }
485 }
486 
487 /* Attempts to verify that the folder path corresponding to the folder CSIDL
488  * value has the same value as the environment variable with name envVar.
489  * Doesn't mind if SHGetSpecialFolderPath fails for folder or if envVar isn't
490  * set in this environment; different OS and shell version behave differently.
491  * However, if both are present, fails if envVar's value is not the same
492  * (byte-for-byte) as what SHGetSpecialFolderPath returns.
493  */
494 static void matchSpecialFolderPathToEnv(int folder, const char *envVar)
495 {
496     char path[MAX_PATH];
497 
498     if (!pSHGetSpecialFolderPathA) return;
499 
500     if (pSHGetSpecialFolderPathA(NULL, path, folder, FALSE))
501     {
502         char *envVal = getenv(envVar);
503 
504         ok(!envVal || !lstrcmpiA(envVal, path),
505          "%%%s%% does not match SHGetSpecialFolderPath:\n"
506          "%%%s%% is %s\nSHGetSpecialFolderPath returns %s\n",
507          envVar, envVar, envVal, path);
508     }
509 }
510 
511 /* Attempts to match the GUID returned by SHGetFolderLocation for folder with
512  * GUID.  Assumes the type of the returned PIDL is in fact a GUID, but doesn't
513  * fail if it isn't--that check should already have been done.
514  * Fails if the returned PIDL is a GUID whose value does not match guid.
515  */
516 static void matchGUID(int folder, const GUID *guid, const GUID *guid_alt)
517 {
518     LPITEMIDLIST pidl;
519     HRESULT hr;
520 
521     if (!pSHGetFolderLocation) return;
522     if (!guid) return;
523 
524     pidl = NULL;
525     hr = pSHGetFolderLocation(NULL, folder, NULL, 0, &pidl);
526     if (hr == S_OK)
527     {
528         LPITEMIDLIST pidlLast = pILFindLastID(pidl);
529 
530         if (pidlLast && (pidlLast->mkid.abID[0] == PT_SHELLEXT ||
531          pidlLast->mkid.abID[0] == PT_GUID))
532         {
533             GUID *shellGuid = (GUID *)(pidlLast->mkid.abID + 2);
534 
535             if (!guid_alt)
536              ok(IsEqualIID(shellGuid, guid),
537               "%s: got GUID %s, expected %s\n", getFolderName(folder),
538               wine_dbgstr_guid(shellGuid), wine_dbgstr_guid(guid));
539             else
540              ok(IsEqualIID(shellGuid, guid) ||
541               IsEqualIID(shellGuid, guid_alt),
542               "%s: got GUID %s, expected %s or %s\n", getFolderName(folder),
543               wine_dbgstr_guid(shellGuid), wine_dbgstr_guid(guid), wine_dbgstr_guid(guid_alt));
544         }
545         IMalloc_Free(pMalloc, pidl);
546     }
547 }
548 
549 /* Checks the PIDL type of all the known values. */
550 static void test_PidlTypes(void)
551 {
552     /* Desktop */
553     test_SHGetFolderPath(FALSE, CSIDL_DESKTOP);
554     test_SHGetSpecialFolderPath(FALSE, CSIDL_DESKTOP);
555 
556     test_ShellValues(requiredShellValues, ARRAY_SIZE(requiredShellValues), FALSE);
557     test_ShellValues(optionalShellValues, ARRAY_SIZE(optionalShellValues), TRUE);
558 }
559 
560 /* FIXME: Should be in shobjidl.idl */
561 DEFINE_GUID(CLSID_NetworkExplorerFolder, 0xF02C1A0D, 0xBE21, 0x4350, 0x88, 0xB0, 0x73, 0x67, 0xFC, 0x96, 0xEF, 0x3C);
562 DEFINE_GUID(_CLSID_Documents, 0xA8CDFF1C, 0x4878, 0x43be, 0xB5, 0xFD, 0xF8, 0x09, 0x1C, 0x1C, 0x60, 0xD0);
563 
564 /* Verifies various shell virtual folders have the correct well-known GUIDs. */
565 static void test_GUIDs(void)
566 {
567     matchGUID(CSIDL_BITBUCKET, &CLSID_RecycleBin, NULL);
568     matchGUID(CSIDL_CONTROLS, &CLSID_ControlPanel, NULL);
569     matchGUID(CSIDL_DRIVES, &CLSID_MyComputer, NULL);
570     matchGUID(CSIDL_INTERNET, &CLSID_Internet, NULL);
571     matchGUID(CSIDL_NETWORK, &CLSID_NetworkPlaces, &CLSID_NetworkExplorerFolder); /* Vista and higher */
572     matchGUID(CSIDL_PERSONAL, &CLSID_MyDocuments, &_CLSID_Documents /* win8 */);
573     matchGUID(CSIDL_COMMON_DOCUMENTS, &CLSID_CommonDocuments, NULL);
574     matchGUID(CSIDL_PRINTERS, &CLSID_Printers, NULL);
575 }
576 
577 /* Verifies various shell paths match the environment variables to which they
578  * correspond.
579  */
580 static void test_EnvVars(void)
581 {
582     matchSpecialFolderPathToEnv(CSIDL_PROGRAM_FILES, "ProgramFiles");
583     matchSpecialFolderPathToEnv(CSIDL_APPDATA, "APPDATA");
584     matchSpecialFolderPathToEnv(CSIDL_PROFILE, "USERPROFILE");
585     matchSpecialFolderPathToEnv(CSIDL_WINDOWS, "SystemRoot");
586     matchSpecialFolderPathToEnv(CSIDL_WINDOWS, "windir");
587     matchSpecialFolderPathToEnv(CSIDL_PROGRAM_FILES_COMMON, "CommonProgramFiles");
588     /* this is only set on Wine, but can't hurt to verify it: */
589     matchSpecialFolderPathToEnv(CSIDL_SYSTEM, "winsysdir");
590 }
591 
592 /* Loosely based on PathRemoveBackslashA from dlls/shlwapi/path.c */
593 static BOOL myPathIsRootA(LPCSTR lpszPath)
594 {
595   if (lpszPath && *lpszPath &&
596       lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0')
597       return TRUE; /* X:\ */
598   return FALSE;
599 }
600 static LPSTR myPathRemoveBackslashA( LPSTR lpszPath )
601 {
602   LPSTR szTemp = NULL;
603 
604   if(lpszPath)
605   {
606     szTemp = CharPrevA(lpszPath, lpszPath + strlen(lpszPath));
607     if (!myPathIsRootA(lpszPath) && *szTemp == '\\')
608       *szTemp = '\0';
609   }
610   return szTemp;
611 }
612 
613 /* Verifies the shell path for CSIDL_WINDOWS matches the return from
614  * GetWindowsDirectory.  If SHGetSpecialFolderPath fails, no harm, no foul--not
615  * every shell32 version supports CSIDL_WINDOWS.
616  */
617 static void testWinDir(void)
618 {
619     char windowsShellPath[MAX_PATH], windowsDir[MAX_PATH] = { 0 };
620 
621     if (!pSHGetSpecialFolderPathA) return;
622 
623     if (pSHGetSpecialFolderPathA(NULL, windowsShellPath, CSIDL_WINDOWS, FALSE))
624     {
625         myPathRemoveBackslashA(windowsShellPath);
626         GetWindowsDirectoryA(windowsDir, sizeof(windowsDir));
627         myPathRemoveBackslashA(windowsDir);
628         ok(!lstrcmpiA(windowsDir, windowsShellPath),
629          "GetWindowsDirectory returns %s SHGetSpecialFolderPath returns %s\n",
630          windowsDir, windowsShellPath);
631     }
632 }
633 
634 /* Verifies the shell path for CSIDL_SYSTEM matches the return from
635  * GetSystemDirectory.  If SHGetSpecialFolderPath fails, no harm,
636  * no foul--not every shell32 version supports CSIDL_SYSTEM.
637  */
638 static void testSystemDir(void)
639 {
640     char systemShellPath[MAX_PATH], systemDir[MAX_PATH], systemDirx86[MAX_PATH];
641 
642     if (!pSHGetSpecialFolderPathA) return;
643 
644     GetSystemDirectoryA(systemDir, sizeof(systemDir));
645     myPathRemoveBackslashA(systemDir);
646     if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEM, FALSE))
647     {
648         myPathRemoveBackslashA(systemShellPath);
649         ok(!lstrcmpiA(systemDir, systemShellPath),
650          "GetSystemDirectory returns %s SHGetSpecialFolderPath returns %s\n",
651          systemDir, systemShellPath);
652     }
653 
654     if (!pGetSystemWow64DirectoryA || !pGetSystemWow64DirectoryA(systemDirx86, sizeof(systemDirx86)))
655         GetSystemDirectoryA(systemDirx86, sizeof(systemDirx86));
656     myPathRemoveBackslashA(systemDirx86);
657     if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEMX86, FALSE))
658     {
659         myPathRemoveBackslashA(systemShellPath);
660         ok(!lstrcmpiA(systemDirx86, systemShellPath) || broken(!lstrcmpiA(systemDir, systemShellPath)),
661          "GetSystemDirectory returns %s SHGetSpecialFolderPath returns %s\n",
662          systemDir, systemShellPath);
663     }
664 }
665 
666 /* Globals used by subprocesses */
667 static int    myARGC;
668 static char **myARGV;
669 static char   base[MAX_PATH];
670 static char   selfname[MAX_PATH];
671 
672 static BOOL init(void)
673 {
674     myARGC = winetest_get_mainargs(&myARGV);
675     if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE;
676     strcpy(selfname, myARGV[0]);
677     return TRUE;
678 }
679 
680 static void doChild(const char *arg)
681 {
682     char path[MAX_PATH];
683     HRESULT hr;
684 
685     if (arg[0] == '1')
686     {
687         LPITEMIDLIST pidl;
688         char *p;
689 
690         /* test what happens when CSIDL_FAVORITES is set to a nonexistent directory */
691 
692         /* test some failure cases first: */
693         hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES, NULL, SHGFP_TYPE_CURRENT, path);
694         ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
695             "SHGetFolderPath returned 0x%08x, expected 0x80070002\n", hr);
696 
697         pidl = NULL;
698         hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, NULL, 0, &pidl);
699         ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
700             "SHGetFolderLocation returned 0x%08x\n", hr);
701         if (hr == S_OK && pidl) IMalloc_Free(pMalloc, pidl);
702 
703         ok(!pSHGetSpecialFolderPathA(NULL, path, CSIDL_FAVORITES, FALSE),
704             "SHGetSpecialFolderPath succeeded, expected failure\n");
705 
706         pidl = NULL;
707         hr = pSHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidl);
708         ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
709             "SHGetFolderLocation returned 0x%08x\n", hr);
710 
711         if (hr == S_OK && pidl) IMalloc_Free(pMalloc, pidl);
712 
713         /* now test success: */
714         hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL,
715                                SHGFP_TYPE_CURRENT, path);
716         ok (hr == S_OK, "got 0x%08x\n", hr);
717         if (hr == S_OK)
718         {
719             BOOL ret;
720 
721             trace("CSIDL_FAVORITES was changed to %s\n", path);
722             ret = CreateDirectoryA(path, NULL);
723             ok(!ret, "expected failure with ERROR_ALREADY_EXISTS\n");
724             if (!ret)
725                 ok(GetLastError() == ERROR_ALREADY_EXISTS,
726                   "got %d, expected ERROR_ALREADY_EXISTS\n", GetLastError());
727 
728             p = path + strlen(path);
729             strcpy(p, "\\desktop.ini");
730             DeleteFileA(path);
731             *p = 0;
732             SetFileAttributesA( path, FILE_ATTRIBUTE_NORMAL );
733             ret = RemoveDirectoryA(path);
734             ok( ret, "failed to remove %s error %u\n", path, GetLastError() );
735         }
736     }
737     else if (arg[0] == '2')
738     {
739         /* make sure SHGetFolderPath still succeeds when the
740            original value of CSIDL_FAVORITES is restored. */
741         hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL,
742             SHGFP_TYPE_CURRENT, path);
743         ok(hr == S_OK, "SHGetFolderPath failed: 0x%08x\n", hr);
744     }
745 }
746 
747 /* Tests the return values from the various shell functions both with and
748  * without the use of the CSIDL_FLAG_CREATE flag.  This flag only appeared in
749  * version 5 of the shell, so don't test unless it's at least version 5.
750  * The test reads a value from the registry, modifies it, calls
751  * SHGetFolderPath once with the CSIDL_FLAG_CREATE flag, and immediately
752  * afterward without it.  Then it restores the registry and deletes the folder
753  * that was created.
754  * One oddity with respect to restoration: shell32 caches somehow, so it needs
755  * to be reloaded in order to see the correct (restored) value.
756  * Some APIs unrelated to the ones under test may fail, but I expect they're
757  * covered by other unit tests; I just print out something about failure to
758  * help trace what's going on.
759  */
760 static void test_NonExistentPath(void)
761 {
762     static const char userShellFolders[] =
763      "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
764     char originalPath[MAX_PATH], modifiedPath[MAX_PATH];
765     HKEY key;
766 
767     if (!pSHGetFolderPathA) return;
768     if (!pSHGetFolderLocation) return;
769     if (!pSHGetSpecialFolderPathA) return;
770     if (!pSHGetSpecialFolderLocation) return;
771     if (!pSHFileOperationA) return;
772     if (shellVersion.dwMajorVersion < 5) return;
773 
774     if (!RegOpenKeyExA(HKEY_CURRENT_USER, userShellFolders, 0, KEY_ALL_ACCESS,
775      &key))
776     {
777         DWORD len, type;
778 
779         len = sizeof(originalPath);
780         if (!RegQueryValueExA(key, "Favorites", NULL, &type,
781          (LPBYTE)&originalPath, &len))
782         {
783             size_t len = strlen(originalPath);
784 
785             memcpy(modifiedPath, originalPath, len);
786             modifiedPath[len++] = '2';
787             modifiedPath[len++] = '\0';
788             trace("Changing CSIDL_FAVORITES to %s\n", modifiedPath);
789             if (!RegSetValueExA(key, "Favorites", 0, type,
790              (LPBYTE)modifiedPath, len))
791             {
792                 char buffer[MAX_PATH+20];
793                 STARTUPINFOA startup;
794                 PROCESS_INFORMATION info;
795 
796                 sprintf(buffer, "%s tests/shellpath.c 1", selfname);
797                 memset(&startup, 0, sizeof(startup));
798                 startup.cb = sizeof(startup);
799                 startup.dwFlags = STARTF_USESHOWWINDOW;
800                 startup.wShowWindow = SW_SHOWNORMAL;
801                 CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL,
802                  &startup, &info);
803                 winetest_wait_child_process( info.hProcess );
804 
805                 /* restore original values: */
806                 trace("Restoring CSIDL_FAVORITES to %s\n", originalPath);
807                 RegSetValueExA(key, "Favorites", 0, type, (LPBYTE) originalPath,
808                  strlen(originalPath) + 1);
809                 RegFlushKey(key);
810 
811                 sprintf(buffer, "%s tests/shellpath.c 2", selfname);
812                 memset(&startup, 0, sizeof(startup));
813                 startup.cb = sizeof(startup);
814                 startup.dwFlags = STARTF_USESHOWWINDOW;
815                 startup.wShowWindow = SW_SHOWNORMAL;
816                 CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL,
817                  &startup, &info);
818                 ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0,
819                  "child process termination\n");
820             }
821         }
822         else skip("RegQueryValueExA(key, Favorites, ...) failed\n");
823         if (key)
824             RegCloseKey(key);
825     }
826     else skip("RegOpenKeyExA(HKEY_CURRENT_USER, %s, ...) failed\n", userShellFolders);
827 }
828 
829 static void test_SHGetFolderPathEx(void)
830 {
831     HRESULT hr;
832     WCHAR buffer[MAX_PATH], *path;
833     DWORD len;
834 
835     if (!pSHGetKnownFolderPath || !pSHGetFolderPathEx)
836     {
837         win_skip("SHGetKnownFolderPath or SHGetFolderPathEx not available\n");
838         return;
839     }
840 
841 if (0) { /* crashes */
842     hr = pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, NULL);
843     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
844 }
845     /* non-existent folder id */
846     path = (void *)0xdeadbeef;
847     hr = pSHGetKnownFolderPath(&IID_IOleObject, 0, NULL, &path);
848     ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got 0x%08x\n", hr);
849     ok(path == NULL, "got %p\n", path);
850 
851     path = NULL;
852     hr = pSHGetKnownFolderPath(&FOLDERID_Desktop, KF_FLAG_DEFAULT_PATH, NULL, &path);
853     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
854     ok(path != NULL, "expected path != NULL\n");
855     CoTaskMemFree(path);
856 
857     path = NULL;
858     hr = pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &path);
859     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
860     ok(path != NULL, "expected path != NULL\n");
861 
862     hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, buffer, MAX_PATH);
863     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
864     ok(!lstrcmpiW(path, buffer), "expected equal paths\n");
865     len = lstrlenW(buffer);
866     CoTaskMemFree(path);
867 
868     hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, buffer, 0);
869     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
870 
871 if (0) { /* crashes */
872     hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, NULL, len + 1);
873     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
874 
875     hr = pSHGetFolderPathEx(NULL, 0, NULL, buffer, MAX_PATH);
876     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
877 }
878     hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, buffer, len);
879     ok(hr == E_NOT_SUFFICIENT_BUFFER, "expected E_NOT_SUFFICIENT_BUFFER, got 0x%08x\n", hr);
880 
881     hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, buffer, len + 1);
882     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
883 }
884 
885 /* Standard CSIDL values (and their flags) uses only two less-significant bytes */
886 #define NO_CSIDL 0x10000
887 #define WINE_ATTRIBUTES_OPTIONAL 0x20000
888 #define KNOWN_FOLDER(id, csidl, name, category, parent1, parent2, relative_path, parsing_name, attributes, definitionFlags) \
889     { &id, # id, csidl, # csidl, name, category, {&parent1, &parent2}, relative_path, parsing_name, attributes, definitionFlags, __LINE__ }
890 
891 /* non-published known folders test */
892 static const GUID _FOLDERID_CryptoKeys =            {0xB88F4DAA, 0xE7BD, 0x49A9, {0xB7, 0x4D, 0x02, 0x88, 0x5A, 0x5D, 0xC7, 0x65} };
893 static const GUID _FOLDERID_DpapiKeys =             {0x10C07CD0, 0xEF91, 0x4567, {0xB8, 0x50, 0x44, 0x8B, 0x77, 0xCB, 0x37, 0xF9} };
894 static const GUID _FOLDERID_SystemCertificates =    {0x54EED2E0, 0xE7CA, 0x4FDB, {0x91, 0x48, 0x0F, 0x42, 0x47, 0x29, 0x1C, 0xFA} };
895 static const GUID _FOLDERID_CredentialManager =     {0x915221FB, 0x9EFE, 0x4BDA, {0x8F, 0xD7, 0xF7, 0x8D, 0xCA, 0x77, 0x4F, 0x87} };
896 
897 struct knownFolderDef {
898     const KNOWNFOLDERID *folderId;
899     const char *sFolderId;
900     const int csidl;
901     const char *sCsidl;
902     const char *sName;
903     const KF_CATEGORY category;
904     const KNOWNFOLDERID *fidParents[2];
905     const char *sRelativePath;
906     const char *sParsingName;
907     const DWORD attributes;
908     const KF_DEFINITION_FLAGS definitionFlags;
909     const int line;
910 };
911 
912 /* Note: content of parsing name may vary between Windows versions.
913  * As a base, values from 6.0 (Vista) were used. Some entries may contain
914  * alternative values. In that case, Windows version where the value was
915  * found is noted.
916  *
917  * The list of values for parsing name was encoded as a number of null-
918  * terminated strings placed one by one (separated by null byte only).
919  * End of list is marked by two consecutive null bytes.
920  */
921 static const struct knownFolderDef known_folders[] = {
922     KNOWN_FOLDER(FOLDERID_AddNewPrograms,
923                  NO_CSIDL,
924                  "AddNewProgramsFolder",
925                  KF_CATEGORY_VIRTUAL,
926                  GUID_NULL, GUID_NULL,
927                  NULL,
928                  "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{15eae92e-f17a-4431-9f28-805e482dafd4}\0"
929                 "shell:::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{15eae92e-f17a-4431-9f28-805e482dafd4}\0\0" /* 6.1 */,
930                 0,
931                 0),
932     KNOWN_FOLDER(FOLDERID_AdminTools,
933                  CSIDL_ADMINTOOLS,
934                  "Administrative Tools",
935                  KF_CATEGORY_PERUSER,
936                  FOLDERID_Programs, GUID_NULL,
937                  "Administrative Tools",
938                  NULL,
939                  FILE_ATTRIBUTE_READONLY,
940                  KFDF_PRECREATE),
941     KNOWN_FOLDER(FOLDERID_AppUpdates,
942                  NO_CSIDL,
943                  "AppUpdatesFolder",
944                  KF_CATEGORY_VIRTUAL,
945                  GUID_NULL, GUID_NULL,
946                  NULL,
947                  "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7b81be6a-ce2b-4676-a29e-eb907a5126c5}\\::{d450a8a1-9568-45c7-9c0e-b4f9fb4537bd}\0"
948                  "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{7b81be6a-ce2b-4676-a29e-eb907a5126c5}\\::{d450a8a1-9568-45c7-9c0e-b4f9fb4537bd}\0\0" /* 6.1 */,
949                  0,
950                  0),
951     KNOWN_FOLDER(FOLDERID_CDBurning,
952                  CSIDL_CDBURN_AREA,
953                  "CD Burning",
954                  KF_CATEGORY_PERUSER,
955                  FOLDERID_LocalAppData, GUID_NULL,
956                  "Microsoft\\Windows\\Burn\\Burn",
957                  NULL,
958                  FILE_ATTRIBUTE_READONLY,
959                  KFDF_LOCAL_REDIRECT_ONLY),
960     KNOWN_FOLDER(FOLDERID_ChangeRemovePrograms,
961                  NO_CSIDL,
962                  "ChangeRemoveProgramsFolder",
963                  KF_CATEGORY_VIRTUAL,
964                  GUID_NULL, GUID_NULL,
965                  NULL,
966                  "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7b81be6a-ce2b-4676-a29e-eb907a5126c5}\0"
967                  "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{7b81be6a-ce2b-4676-a29e-eb907a5126c5}\0\0" /* 6.1 */,
968                  0,
969                  0),
970     KNOWN_FOLDER(FOLDERID_CommonAdminTools,
971                  CSIDL_COMMON_ADMINTOOLS,
972                  "Common Administrative Tools",
973                  KF_CATEGORY_COMMON,
974                  FOLDERID_CommonPrograms, GUID_NULL,
975                  "Administrative Tools",
976                  NULL,
977                  FILE_ATTRIBUTE_READONLY,
978                  KFDF_PRECREATE),
979     KNOWN_FOLDER(FOLDERID_CommonOEMLinks,
980                  CSIDL_COMMON_OEM_LINKS,
981                  "OEM Links",
982                  KF_CATEGORY_COMMON,
983                  FOLDERID_ProgramData, GUID_NULL,
984                  "OEM Links",
985                  NULL,
986                  0,
987                  0),
988     KNOWN_FOLDER(FOLDERID_CommonPrograms,
989                  CSIDL_COMMON_PROGRAMS,
990                  "Common Programs",
991                  KF_CATEGORY_COMMON,
992                  FOLDERID_CommonStartMenu, GUID_NULL,
993                  "Programs",
994                  NULL,
995                  FILE_ATTRIBUTE_READONLY,
996                  KFDF_PRECREATE),
997     KNOWN_FOLDER(FOLDERID_CommonStartMenu,
998                  CSIDL_COMMON_STARTMENU,
999                  "Common Start Menu",
1000                  KF_CATEGORY_COMMON,
1001                  FOLDERID_ProgramData, GUID_NULL,
1002                  "Microsoft\\Windows\\Start Menu\0",
1003                  NULL,
1004                  FILE_ATTRIBUTE_READONLY,
1005                  KFDF_PRECREATE),
1006     KNOWN_FOLDER(FOLDERID_CommonStartup,
1007                  CSIDL_COMMON_STARTUP,
1008                  "Common Startup",
1009                  KF_CATEGORY_COMMON,
1010                  FOLDERID_CommonPrograms, GUID_NULL,
1011                  "StartUp",
1012                  NULL,
1013                  FILE_ATTRIBUTE_READONLY,
1014                  KFDF_PRECREATE),
1015     KNOWN_FOLDER(FOLDERID_CommonTemplates,
1016                  CSIDL_COMMON_TEMPLATES,
1017                  "Common Templates",
1018                  KF_CATEGORY_COMMON,
1019                  FOLDERID_ProgramData, GUID_NULL,
1020                  "Microsoft\\Windows\\Templates\0",
1021                  NULL,
1022                  0,
1023                  0),
1024     KNOWN_FOLDER(FOLDERID_ComputerFolder,
1025                  CSIDL_DRIVES,
1026                  "MyComputerFolder",
1027                  KF_CATEGORY_VIRTUAL,
1028                  GUID_NULL, GUID_NULL,
1029                  NULL,
1030                  "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\0\0",
1031                  0,
1032                  0),
1033     KNOWN_FOLDER(FOLDERID_ConflictFolder,
1034                  NO_CSIDL,
1035                  "ConflictFolder",
1036                  KF_CATEGORY_VIRTUAL,
1037                  GUID_NULL, GUID_NULL,
1038                  NULL,
1039                  "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{E413D040-6788-4C22-957E-175D1C513A34},\0"
1040                  "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{E413D040-6788-4C22-957E-175D1C513A34},\0\0" /* 6.1 */,
1041                  0,
1042                  0),
1043     KNOWN_FOLDER(FOLDERID_ConnectionsFolder,
1044                  CSIDL_CONNECTIONS,
1045                  "ConnectionsFolder",
1046                  KF_CATEGORY_VIRTUAL,
1047                  GUID_NULL, GUID_NULL,
1048                  NULL,
1049                  "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}\0"
1050                  "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}\0\0" /* 6.1 */,
1051                  0,
1052                  0),
1053     KNOWN_FOLDER(FOLDERID_Contacts,
1054                  NO_CSIDL,
1055                  "Contacts",
1056                  KF_CATEGORY_PERUSER,
1057                  FOLDERID_Profile, GUID_NULL,
1058                  "Contacts",
1059                  "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{56784854-C6CB-462B-8169-88E350ACB882}\0\0",
1060                  FILE_ATTRIBUTE_READONLY,
1061                  KFDF_ROAMABLE | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
1062     KNOWN_FOLDER(FOLDERID_ControlPanelFolder,
1063                  CSIDL_CONTROLS,
1064                  "ControlPanelFolder",
1065                  KF_CATEGORY_VIRTUAL,
1066                  GUID_NULL, GUID_NULL,
1067                  NULL,
1068                  "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\0"
1069                  "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\0\0" /* 6.1 */,
1070                  0,
1071                  0),
1072     KNOWN_FOLDER(FOLDERID_Cookies,
1073                  CSIDL_COOKIES,
1074                  "Cookies",
1075                  KF_CATEGORY_PERUSER,
1076                  FOLDERID_RoamingAppData, FOLDERID_LocalAppData,
1077                  "Microsoft\\Windows\\Cookies\0Microsoft\\Windows\\INetCookies\0" /* win8 */,
1078                  NULL,
1079                  0,
1080                  0),
1081     KNOWN_FOLDER(FOLDERID_Desktop,
1082                  CSIDL_DESKTOP,
1083                  "Desktop",
1084                  KF_CATEGORY_PERUSER,
1085                  FOLDERID_Profile, GUID_NULL,
1086                  "Desktop",
1087                  NULL,
1088                  FILE_ATTRIBUTE_READONLY,
1089                  KFDF_ROAMABLE | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
1090     KNOWN_FOLDER(FOLDERID_DeviceMetadataStore,
1091                  NO_CSIDL,
1092                  "Device Metadata Store",
1093                  KF_CATEGORY_COMMON,
1094                  FOLDERID_ProgramData, GUID_NULL,
1095                  "Microsoft\\Windows\\DeviceMetadataStore\0",
1096                  NULL,
1097                  0,
1098                  0),
1099     KNOWN_FOLDER(FOLDERID_Documents,
1100                  CSIDL_MYDOCUMENTS,
1101                  "Personal",
1102                  KF_CATEGORY_PERUSER,
1103                  FOLDERID_Profile, GUID_NULL,
1104                  "Documents\0",
1105                  "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{FDD39AD0-238F-46AF-ADB4-6C85480369C7}\0shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{A8CDFF1C-4878-43be-B5FD-F8091C1C60D0}\0\0", /* win8 */
1106                  FILE_ATTRIBUTE_READONLY,
1107                  KFDF_ROAMABLE | KFDF_PRECREATE),
1108     KNOWN_FOLDER(FOLDERID_DocumentsLibrary,
1109                  NO_CSIDL,
1110                  "DocumentsLibrary",
1111                  KF_CATEGORY_PERUSER,
1112                  FOLDERID_Libraries, GUID_NULL,
1113                  "Documents.library-ms\0",
1114                  "::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\\{7b0db17d-9cd2-4a93-9733-46cc89022e7c}\0\0",
1115                  0,
1116                  KFDF_PRECREATE | KFDF_STREAM),
1117     KNOWN_FOLDER(FOLDERID_Downloads,
1118                  NO_CSIDL,
1119                  "Downloads",
1120                  KF_CATEGORY_PERUSER,
1121                  FOLDERID_Profile, GUID_NULL,
1122                  "Downloads\0",
1123                  "(null)\0shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{374DE290-123F-4565-9164-39C4925E467B}\0\0", /* win8 */
1124                  FILE_ATTRIBUTE_READONLY,
1125                  KFDF_ROAMABLE | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
1126     KNOWN_FOLDER(FOLDERID_Favorites,
1127                  CSIDL_FAVORITES,
1128                  "Favorites",
1129                  KF_CATEGORY_PERUSER,
1130                  FOLDERID_Profile, GUID_NULL,
1131                  "Favorites\0",
1132                  NULL,
1133                  FILE_ATTRIBUTE_READONLY,
1134                  KFDF_ROAMABLE | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
1135     KNOWN_FOLDER(FOLDERID_Fonts,
1136                  CSIDL_FONTS,
1137                  "Fonts",
1138                  KF_CATEGORY_FIXED,
1139                  FOLDERID_Windows, GUID_NULL,
1140                  NULL,
1141                  NULL,
1142                  0,
1143                  0),
1144     KNOWN_FOLDER(FOLDERID_Games,
1145                  NO_CSIDL,
1146                  "Games",
1147                  KF_CATEGORY_VIRTUAL,
1148                  GUID_NULL, GUID_NULL,
1149                  NULL,
1150                  "::{ED228FDF-9EA8-4870-83b1-96b02CFE0D52}\0\0",
1151                  0,
1152                  0),
1153     KNOWN_FOLDER(FOLDERID_GameTasks,
1154                  NO_CSIDL,
1155                  "GameTasks",
1156                  KF_CATEGORY_PERUSER,
1157                  FOLDERID_LocalAppData, GUID_NULL,
1158                  "Microsoft\\Windows\\GameExplorer\0",
1159                  NULL,
1160                  0,
1161                  KFDF_LOCAL_REDIRECT_ONLY),
1162     KNOWN_FOLDER(FOLDERID_History,
1163                  CSIDL_HISTORY,
1164                  "History",
1165                  KF_CATEGORY_PERUSER,
1166                  FOLDERID_LocalAppData, GUID_NULL,
1167                  "Microsoft\\Windows\\History\0",
1168                  NULL,
1169                  0,
1170                  KFDF_LOCAL_REDIRECT_ONLY),
1171     KNOWN_FOLDER(FOLDERID_HomeGroup,
1172                  NO_CSIDL,
1173                  "HomeGroupFolder",
1174                  KF_CATEGORY_VIRTUAL,
1175                  GUID_NULL, GUID_NULL,
1176                  NULL,
1177                  "::{B4FB3F98-C1EA-428d-A78A-D1F5659CBA93}\0\0",
1178                  0,
1179                  0),
1180     KNOWN_FOLDER(FOLDERID_ImplicitAppShortcuts,
1181                  NO_CSIDL,
1182                  "ImplicitAppShortcuts",
1183                  KF_CATEGORY_PERUSER,
1184                  FOLDERID_UserPinned, GUID_NULL,
1185                  "ImplicitAppShortcuts\0",
1186                  NULL,
1187                  0,
1188                  KFDF_PRECREATE),
1189     KNOWN_FOLDER(FOLDERID_InternetCache,
1190                  CSIDL_INTERNET_CACHE,
1191                  "Cache",
1192                  KF_CATEGORY_PERUSER,
1193                  FOLDERID_LocalAppData, GUID_NULL,
1194                  "Microsoft\\Windows\\Temporary Internet Files\0Microsoft\\Windows\\INetCache\0\0", /* win8 */
1195                  NULL,
1196                  0,
1197                  KFDF_LOCAL_REDIRECT_ONLY),
1198     KNOWN_FOLDER(FOLDERID_InternetFolder,
1199                  CSIDL_INTERNET,
1200                  "InternetFolder",
1201                  KF_CATEGORY_VIRTUAL,
1202                  GUID_NULL, GUID_NULL,
1203                  NULL,
1204                  "::{871C5380-42A0-1069-A2EA-08002B30309D}\0\0",
1205                  0,
1206                  0),
1207     KNOWN_FOLDER(FOLDERID_Libraries,
1208                  NO_CSIDL,
1209                  "Libraries",
1210                  KF_CATEGORY_PERUSER,
1211                  FOLDERID_RoamingAppData, GUID_NULL,
1212                  "Microsoft\\Windows\\Libraries\0",
1213                  NULL,
1214                  0,
1215                  KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
1216     KNOWN_FOLDER(FOLDERID_Links,
1217                  NO_CSIDL,
1218                  "Links",
1219                  KF_CATEGORY_PERUSER,
1220                  FOLDERID_Profile, GUID_NULL,
1221                  "Links\0",
1222                  "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{bfb9d5e0-c6a9-404c-b2b2-ae6db6af4968}\0\0",
1223                  FILE_ATTRIBUTE_READONLY,
1224                  KFDF_ROAMABLE | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
1225     KNOWN_FOLDER(FOLDERID_LocalAppData,
1226                  CSIDL_LOCAL_APPDATA,
1227                  "Local AppData",
1228                  KF_CATEGORY_PERUSER,
1229                  FOLDERID_Profile, GUID_NULL,
1230                  "AppData\\Local\0",
1231                  NULL,
1232                  0,
1233                  KFDF_LOCAL_REDIRECT_ONLY | KFDF_PUBLISHEXPANDEDPATH),
1234     KNOWN_FOLDER(FOLDERID_LocalAppDataLow,
1235                  NO_CSIDL,
1236                  "LocalAppDataLow",
1237                  KF_CATEGORY_PERUSER,
1238                  FOLDERID_Profile, GUID_NULL,
1239                  "AppData\\LocalLow\0",
1240                  NULL,
1241                  FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
1242                  KFDF_LOCAL_REDIRECT_ONLY | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
1243     KNOWN_FOLDER(FOLDERID_LocalizedResourcesDir,
1244                  CSIDL_RESOURCES_LOCALIZED,
1245                  "LocalizedResourcesDir",
1246                  KF_CATEGORY_FIXED,
1247                  GUID_NULL, GUID_NULL,
1248                  NULL,
1249                  NULL,
1250                  0,
1251                  0),
1252     KNOWN_FOLDER(FOLDERID_Music,
1253                  CSIDL_MYMUSIC,
1254                  "My Music",
1255                  KF_CATEGORY_PERUSER,
1256                  FOLDERID_Profile, GUID_NULL,
1257                  "Music\0",
1258                  "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{4BD8D571-6D19-48D3-BE97-422220080E43}\0shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{1CF1260C-4DD0-4EBB-811F-33C572699FDE}\0\0", /* win8 */
1259                  FILE_ATTRIBUTE_READONLY,
1260                  KFDF_ROAMABLE | KFDF_PRECREATE),
1261     KNOWN_FOLDER(FOLDERID_MusicLibrary,
1262                  NO_CSIDL,
1263                  "MusicLibrary",
1264                  KF_CATEGORY_PERUSER,
1265                  FOLDERID_Libraries, GUID_NULL,
1266                  "Music.library-ms\0",
1267                  "::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\\{2112AB0A-C86A-4ffe-A368-0DE96E47012E}\0\0",
1268                  0,
1269                  KFDF_PRECREATE | KFDF_STREAM),
1270     KNOWN_FOLDER(FOLDERID_NetHood,
1271                  CSIDL_NETHOOD,
1272                  "NetHood",
1273                  KF_CATEGORY_PERUSER,
1274                  FOLDERID_RoamingAppData, GUID_NULL,
1275                  "Microsoft\\Windows\\Network Shortcuts\0",
1276                  NULL,
1277                  0,
1278                  0),
1279     KNOWN_FOLDER(FOLDERID_NetworkFolder,
1280                  CSIDL_NETWORK,
1281                  "NetworkPlacesFolder",
1282                  KF_CATEGORY_VIRTUAL,
1283                  GUID_NULL, GUID_NULL,
1284                  NULL,
1285                  "::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\0\0",
1286                  0,
1287                  0),
1288     KNOWN_FOLDER(FOLDERID_OriginalImages,
1289                  NO_CSIDL,
1290                  "Original Images",
1291                  KF_CATEGORY_PERUSER,
1292                  FOLDERID_LocalAppData, GUID_NULL,
1293                  "Microsoft\\Windows Photo Gallery\\Original Images\0",
1294                  NULL,
1295                  0,
1296                  0),
1297     KNOWN_FOLDER(FOLDERID_PhotoAlbums,
1298                  NO_CSIDL,
1299                  "PhotoAlbums",
1300                  KF_CATEGORY_PERUSER,
1301                  FOLDERID_Pictures, GUID_NULL,
1302                  "Slide Shows\0",
1303                  NULL,
1304                  FILE_ATTRIBUTE_READONLY,
1305                  0),
1306     KNOWN_FOLDER(FOLDERID_Pictures,
1307                  CSIDL_MYPICTURES,
1308                  "My Pictures",
1309                  KF_CATEGORY_PERUSER,
1310                  FOLDERID_Profile, GUID_NULL,
1311                  "Pictures\0",
1312                  "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{33E28130-4E1E-4676-835A-98395C3BC3BB}\0shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{3ADD1653-EB32-4CB0-BBD7-DFA0ABB5ACCA}\0\0", /* win8 */
1313                  FILE_ATTRIBUTE_READONLY,
1314                  KFDF_ROAMABLE | KFDF_PRECREATE),
1315     KNOWN_FOLDER(FOLDERID_PicturesLibrary,
1316                  NO_CSIDL,
1317                  "PicturesLibrary",
1318                  KF_CATEGORY_PERUSER,
1319                  FOLDERID_Libraries, GUID_NULL,
1320                  "Pictures.library-ms\0",
1321                  "::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\\{A990AE9F-A03B-4e80-94BC-9912D7504104}\0\0",
1322                  0,
1323                  KFDF_PRECREATE | KFDF_STREAM),
1324     KNOWN_FOLDER(FOLDERID_Playlists,
1325                  NO_CSIDL,
1326                  "Playlists",
1327                  KF_CATEGORY_PERUSER,
1328                  FOLDERID_Music, GUID_NULL,
1329                  "Playlists\0",
1330                  NULL,
1331                  FILE_ATTRIBUTE_READONLY,
1332                  0),
1333     KNOWN_FOLDER(FOLDERID_PrintersFolder,
1334                  CSIDL_PRINTERS,
1335                  "PrintersFolder",
1336                  KF_CATEGORY_VIRTUAL,
1337                  GUID_NULL, GUID_NULL,
1338                  NULL,
1339                  "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}\0\0",
1340                  0,
1341                  0),
1342     KNOWN_FOLDER(FOLDERID_PrintHood,
1343                  CSIDL_PRINTHOOD,
1344                  "PrintHood",
1345                  KF_CATEGORY_PERUSER,
1346                  FOLDERID_RoamingAppData, GUID_NULL,
1347                  "Microsoft\\Windows\\Printer Shortcuts\0",
1348                  NULL,
1349                  0,
1350                  0),
1351     KNOWN_FOLDER(FOLDERID_Profile,
1352                  CSIDL_PROFILE,
1353                  "Profile",
1354                  KF_CATEGORY_FIXED,
1355                  GUID_NULL, GUID_NULL,
1356                  NULL,
1357                  NULL,
1358                  0,
1359                  0),
1360     KNOWN_FOLDER(FOLDERID_ProgramData,
1361                  CSIDL_COMMON_APPDATA,
1362                  "Common AppData",
1363                  KF_CATEGORY_FIXED,
1364                  GUID_NULL, GUID_NULL,
1365                  NULL,
1366                  NULL,
1367                  0,
1368                  0),
1369     KNOWN_FOLDER(FOLDERID_ProgramFiles,
1370                  CSIDL_PROGRAM_FILES,
1371                  "ProgramFiles",
1372                  KF_CATEGORY_FIXED,
1373                  GUID_NULL, GUID_NULL,
1374                  NULL,
1375                  NULL,
1376                  FILE_ATTRIBUTE_READONLY,
1377                  KFDF_PRECREATE
1378                 ),
1379     KNOWN_FOLDER(FOLDERID_ProgramFilesCommon,
1380                  CSIDL_PROGRAM_FILES_COMMON,
1381                  "ProgramFilesCommon",
1382                  KF_CATEGORY_FIXED,
1383                  GUID_NULL, GUID_NULL,
1384                  NULL,
1385                  NULL,
1386                  0,
1387                  0),
1388     KNOWN_FOLDER(FOLDERID_ProgramFilesCommonX64,
1389                  NO_CSIDL,
1390                  "ProgramFilesCommonX64",
1391                  KF_CATEGORY_FIXED,
1392                  GUID_NULL, GUID_NULL,
1393                  NULL,
1394                  NULL,
1395                  0,
1396                  0),
1397     KNOWN_FOLDER(FOLDERID_ProgramFilesCommonX86,
1398                  NO_CSIDL,
1399                  "ProgramFilesCommonX86",
1400                  KF_CATEGORY_FIXED,
1401                  GUID_NULL, GUID_NULL,
1402                  NULL,
1403                  NULL,
1404                  0,
1405                  0),
1406     KNOWN_FOLDER(FOLDERID_ProgramFilesX64,
1407                  NO_CSIDL,
1408                  "ProgramFilesX64",
1409                  KF_CATEGORY_FIXED,
1410                  GUID_NULL, GUID_NULL,
1411                  NULL,
1412                  NULL,
1413                  0,
1414                  0),
1415     KNOWN_FOLDER(FOLDERID_ProgramFilesX86,
1416                  CSIDL_PROGRAM_FILESX86,
1417                  "ProgramFilesX86",
1418                  KF_CATEGORY_FIXED,
1419                  GUID_NULL, GUID_NULL,
1420                  NULL,
1421                  NULL,
1422                  FILE_ATTRIBUTE_READONLY,
1423                  KFDF_PRECREATE),
1424     KNOWN_FOLDER(FOLDERID_Programs,
1425                  CSIDL_PROGRAMS,
1426                  "Programs",
1427                  KF_CATEGORY_PERUSER,
1428                  FOLDERID_StartMenu, GUID_NULL,
1429                  "Programs\0",
1430                  NULL,
1431                  FILE_ATTRIBUTE_READONLY,
1432                  KFDF_PRECREATE),
1433     KNOWN_FOLDER(FOLDERID_Public,
1434                  NO_CSIDL,
1435                  "Public",
1436                  KF_CATEGORY_FIXED,
1437                  GUID_NULL, GUID_NULL,
1438                  NULL,
1439                  "::{4336a54d-038b-4685-ab02-99bb52d3fb8b}\0"
1440                  "(null)\0\0" /* 6.1 */,
1441                  FILE_ATTRIBUTE_READONLY,
1442                  KFDF_PRECREATE),
1443     KNOWN_FOLDER(FOLDERID_PublicDesktop,
1444                  CSIDL_COMMON_DESKTOPDIRECTORY,
1445                  "Common Desktop",
1446                  KF_CATEGORY_COMMON,
1447                  FOLDERID_Public, GUID_NULL,
1448                  "Desktop\0",
1449                  NULL,
1450                  FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN,
1451                  KFDF_PRECREATE),
1452     KNOWN_FOLDER(FOLDERID_PublicDocuments,
1453                  CSIDL_COMMON_DOCUMENTS,
1454                  "Common Documents",
1455                  KF_CATEGORY_COMMON,
1456                  FOLDERID_Public, GUID_NULL,
1457                  "Documents\0",
1458                  NULL,
1459                  FILE_ATTRIBUTE_READONLY,
1460                  KFDF_PRECREATE),
1461     KNOWN_FOLDER(FOLDERID_PublicDownloads,
1462                  NO_CSIDL,
1463                  "CommonDownloads",
1464                  KF_CATEGORY_COMMON,
1465                  FOLDERID_Public, GUID_NULL,
1466                  "Downloads\0",
1467                  NULL,
1468                  FILE_ATTRIBUTE_READONLY,
1469                  KFDF_PRECREATE),
1470     KNOWN_FOLDER(FOLDERID_PublicGameTasks,
1471                  NO_CSIDL,
1472                  "PublicGameTasks",
1473                  KF_CATEGORY_COMMON,
1474                  FOLDERID_ProgramData, GUID_NULL,
1475                  "Microsoft\\Windows\\GameExplorer\0",
1476                  NULL,
1477                  0,
1478                  KFDF_LOCAL_REDIRECT_ONLY),
1479     KNOWN_FOLDER(FOLDERID_PublicLibraries,
1480                  NO_CSIDL,
1481                  "PublicLibraries",
1482                  KF_CATEGORY_COMMON,
1483                  FOLDERID_Public, GUID_NULL,
1484                  "Libraries\0",
1485                  NULL,
1486                  FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN,
1487                  KFDF_PRECREATE),
1488     KNOWN_FOLDER(FOLDERID_PublicMusic,
1489                  CSIDL_COMMON_MUSIC,
1490                  "CommonMusic",
1491                  KF_CATEGORY_COMMON,
1492                  FOLDERID_Public, GUID_NULL,
1493                  "Music\0",
1494                  NULL,
1495                  FILE_ATTRIBUTE_READONLY,
1496                  KFDF_PRECREATE),
1497     KNOWN_FOLDER(FOLDERID_PublicPictures,
1498                  CSIDL_COMMON_PICTURES,
1499                  "CommonPictures",
1500                  KF_CATEGORY_COMMON,
1501                  FOLDERID_Public, GUID_NULL,
1502                  "Pictures\0",
1503                  NULL,
1504                  FILE_ATTRIBUTE_READONLY,
1505                  KFDF_PRECREATE),
1506     KNOWN_FOLDER(FOLDERID_PublicRingtones,
1507                  NO_CSIDL,
1508                  "CommonRingtones",
1509                  KF_CATEGORY_COMMON,
1510                  FOLDERID_ProgramData, GUID_NULL,
1511                  "Microsoft\\Windows\\Ringtones\0",
1512                  NULL,
1513                  0,
1514                  KFDF_PRECREATE),
1515     KNOWN_FOLDER(FOLDERID_PublicVideos,
1516                  CSIDL_COMMON_VIDEO,
1517                  "CommonVideo",
1518                  KF_CATEGORY_COMMON,
1519                  FOLDERID_Public, GUID_NULL,
1520                  "Videos\0",
1521                  NULL,
1522                  FILE_ATTRIBUTE_READONLY,
1523                  KFDF_PRECREATE),
1524     KNOWN_FOLDER(FOLDERID_QuickLaunch,
1525                  NO_CSIDL,
1526                  "Quick Launch",
1527                  KF_CATEGORY_PERUSER,
1528                  FOLDERID_RoamingAppData, GUID_NULL,
1529                  "Microsoft\\Internet Explorer\\Quick Launch\0",
1530                  NULL,
1531                  0,
1532                  0),
1533     KNOWN_FOLDER(FOLDERID_Recent,
1534                  CSIDL_RECENT,
1535                  "Recent",
1536                  KF_CATEGORY_PERUSER,
1537                  FOLDERID_RoamingAppData, GUID_NULL,
1538                  "Microsoft\\Windows\\Recent\0",
1539                  NULL,
1540                  FILE_ATTRIBUTE_READONLY,
1541                  KFDF_PRECREATE),
1542     KNOWN_FOLDER(FOLDERID_RecordedTVLibrary,
1543                  NO_CSIDL,
1544                  "RecordedTVLibrary",
1545                  KF_CATEGORY_COMMON,
1546                  FOLDERID_PublicLibraries, GUID_NULL,
1547                  "RecordedTV.library-ms\0",
1548                  NULL,
1549                  0,
1550                  KFDF_PRECREATE | KFDF_STREAM),
1551     KNOWN_FOLDER(FOLDERID_RecycleBinFolder,
1552                  CSIDL_BITBUCKET,
1553                  "RecycleBinFolder",
1554                  KF_CATEGORY_VIRTUAL,
1555                  GUID_NULL, GUID_NULL,
1556                  NULL,
1557                  "::{645FF040-5081-101B-9F08-00AA002F954E}\0\0",
1558                  0,
1559                  0),
1560     KNOWN_FOLDER(FOLDERID_ResourceDir,
1561                  CSIDL_RESOURCES,
1562                  "ResourceDir",
1563                  KF_CATEGORY_FIXED,
1564                  GUID_NULL, GUID_NULL,
1565                  NULL,
1566                  NULL,
1567                  0,
1568                  0),
1569     KNOWN_FOLDER(FOLDERID_Ringtones,
1570                  NO_CSIDL,
1571                  "Ringtones",
1572                  KF_CATEGORY_PERUSER,
1573                  FOLDERID_LocalAppData, GUID_NULL,
1574                  "Microsoft\\Windows\\Ringtones\0",
1575                  NULL,
1576                  0,
1577                  KFDF_PRECREATE),
1578     KNOWN_FOLDER(FOLDERID_RoamingAppData,
1579                  CSIDL_APPDATA,
1580                  "AppData",
1581                  KF_CATEGORY_PERUSER,
1582                  FOLDERID_Profile, GUID_NULL,
1583                  "AppData\\Roaming\0",
1584                  NULL,
1585                  0,
1586                  0),
1587     KNOWN_FOLDER(FOLDERID_SampleMusic,
1588                  NO_CSIDL|WINE_ATTRIBUTES_OPTIONAL /* win8 */,
1589                  "SampleMusic",
1590                  KF_CATEGORY_COMMON,
1591                  FOLDERID_PublicMusic, GUID_NULL,
1592                  "Sample Music\0",
1593                  NULL,
1594                  FILE_ATTRIBUTE_READONLY,
1595                  KFDF_PRECREATE),
1596     KNOWN_FOLDER(FOLDERID_SamplePictures,
1597                  NO_CSIDL|WINE_ATTRIBUTES_OPTIONAL /* win8 */,
1598                  "SamplePictures",
1599                  KF_CATEGORY_COMMON,
1600                  FOLDERID_PublicPictures, GUID_NULL,
1601                  "Sample Pictures\0",
1602                  NULL,
1603                  FILE_ATTRIBUTE_READONLY,
1604                  KFDF_PRECREATE),
1605     KNOWN_FOLDER(FOLDERID_SamplePlaylists,
1606                  NO_CSIDL,
1607                  "SamplePlaylists",
1608                  KF_CATEGORY_COMMON,
1609                  FOLDERID_PublicMusic, GUID_NULL,
1610                  "Sample Playlists\0",
1611                  NULL,
1612                  FILE_ATTRIBUTE_READONLY,
1613                  0),
1614     KNOWN_FOLDER(FOLDERID_SampleVideos,
1615                  NO_CSIDL|WINE_ATTRIBUTES_OPTIONAL /* win8 */,
1616                  "SampleVideos",
1617                  KF_CATEGORY_COMMON,
1618                  FOLDERID_PublicVideos, GUID_NULL,
1619                  "Sample Videos\0",
1620                  NULL,
1621                  FILE_ATTRIBUTE_READONLY,
1622                  KFDF_PRECREATE),
1623     KNOWN_FOLDER(FOLDERID_SavedGames,
1624                  NO_CSIDL,
1625                  "SavedGames",
1626                  KF_CATEGORY_PERUSER,
1627                  FOLDERID_Profile, GUID_NULL,
1628                  "Saved Games\0",
1629                  "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4}\0\0",
1630                  FILE_ATTRIBUTE_READONLY,
1631                  KFDF_ROAMABLE | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
1632     KNOWN_FOLDER(FOLDERID_SavedSearches,
1633                  NO_CSIDL,
1634                  "Searches",
1635                  KF_CATEGORY_PERUSER,
1636                  FOLDERID_Profile, GUID_NULL,
1637                  "Searches\0",
1638                  "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{7d1d3a04-debb-4115-95cf-2f29da2920da}\0\0",
1639                  FILE_ATTRIBUTE_READONLY,
1640                  KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
1641     KNOWN_FOLDER(FOLDERID_SEARCH_CSC,
1642                  NO_CSIDL,
1643                  "CSCFolder",
1644                  KF_CATEGORY_VIRTUAL,
1645                  GUID_NULL, GUID_NULL,
1646                  NULL,
1647                  "shell:::{BD7A2E7B-21CB-41b2-A086-B309680C6B7E}\\*\0\0",
1648                  0,
1649                  0),
1650     KNOWN_FOLDER(FOLDERID_SearchHome,
1651                  NO_CSIDL,
1652                  "SearchHomeFolder",
1653                  KF_CATEGORY_VIRTUAL,
1654                  GUID_NULL, GUID_NULL,
1655                  NULL,
1656                  "::{9343812e-1c37-4a49-a12e-4b2d810d956b}\0\0",
1657                  0,
1658                  0),
1659     KNOWN_FOLDER(FOLDERID_SEARCH_MAPI,
1660                  NO_CSIDL,
1661                  "MAPIFolder",
1662                  KF_CATEGORY_VIRTUAL,
1663                  GUID_NULL, GUID_NULL,
1664                  NULL,
1665                  "shell:::{89D83576-6BD1-4C86-9454-BEB04E94C819}\\*\0\0",
1666                  0,
1667                  0),
1668     KNOWN_FOLDER(FOLDERID_SendTo,
1669                  CSIDL_SENDTO,
1670                  "SendTo",
1671                  KF_CATEGORY_PERUSER,
1672                  FOLDERID_RoamingAppData, GUID_NULL,
1673                  "Microsoft\\Windows\\SendTo\0",
1674                  NULL,
1675                  0,
1676                  0),
1677     KNOWN_FOLDER(FOLDERID_SidebarDefaultParts,
1678                  NO_CSIDL,
1679                  "Default Gadgets",
1680                  KF_CATEGORY_COMMON,
1681                  FOLDERID_ProgramFiles, GUID_NULL,
1682                  "Windows Sidebar\\Gadgets\0",
1683                  NULL,
1684                  0,
1685                  0),
1686     KNOWN_FOLDER(FOLDERID_SidebarParts,
1687                  NO_CSIDL,
1688                  "Gadgets",
1689                  KF_CATEGORY_PERUSER,
1690                  FOLDERID_LocalAppData, GUID_NULL,
1691                  "Microsoft\\Windows Sidebar\\Gadgets\0",
1692                  NULL,
1693                  0,
1694                  0),
1695     KNOWN_FOLDER(FOLDERID_StartMenu,
1696                  CSIDL_STARTMENU,
1697                  "Start Menu",
1698                  KF_CATEGORY_PERUSER,
1699                  FOLDERID_RoamingAppData, GUID_NULL,
1700                  "Microsoft\\Windows\\Start Menu\0",
1701                  NULL,
1702                  FILE_ATTRIBUTE_READONLY,
1703                  KFDF_PRECREATE),
1704     KNOWN_FOLDER(FOLDERID_Startup,
1705                  CSIDL_STARTUP,
1706                  "Startup",
1707                  KF_CATEGORY_PERUSER,
1708                  FOLDERID_Programs, GUID_NULL,
1709                  "StartUp\0",
1710                  NULL,
1711                  FILE_ATTRIBUTE_READONLY,
1712                  KFDF_PRECREATE),
1713     KNOWN_FOLDER(FOLDERID_SyncManagerFolder,
1714                  NO_CSIDL,
1715                  "SyncCenterFolder",
1716                  KF_CATEGORY_VIRTUAL,
1717                  GUID_NULL, GUID_NULL,
1718                  NULL,
1719                  "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\0"
1720                  "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\0\0" /* 6.1 */,
1721                  0,
1722                  0),
1723     KNOWN_FOLDER(FOLDERID_SyncResultsFolder,
1724                  NO_CSIDL,
1725                  "SyncResultsFolder",
1726                  KF_CATEGORY_VIRTUAL,
1727                  GUID_NULL, GUID_NULL,
1728                  NULL,
1729                  "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{BC48B32F-5910-47F5-8570-5074A8A5636A},\0"
1730                  "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{BC48B32F-5910-47F5-8570-5074A8A5636A},\0\0",
1731                  0,
1732                  0),
1733     KNOWN_FOLDER(FOLDERID_SyncSetupFolder,
1734                  NO_CSIDL,
1735                  "SyncSetupFolder",
1736                  KF_CATEGORY_VIRTUAL,
1737                  GUID_NULL, GUID_NULL,
1738                  NULL,
1739                  "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{F1390A9A-A3F4-4E5D-9C5F-98F3BD8D935C},\0"
1740                  "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{F1390A9A-A3F4-4E5D-9C5F-98F3BD8D935C},\0\0" /* 6.1 */,
1741                  0,
1742                  0),
1743     KNOWN_FOLDER(FOLDERID_System,
1744                  CSIDL_SYSTEM,
1745                  "System",
1746                  KF_CATEGORY_FIXED,
1747                  GUID_NULL, GUID_NULL,
1748                  NULL,
1749                  NULL,
1750                  0,
1751                  0),
1752     KNOWN_FOLDER(FOLDERID_SystemX86,
1753                  CSIDL_SYSTEMX86,
1754                  "SystemX86",
1755                  KF_CATEGORY_FIXED,
1756                  GUID_NULL, GUID_NULL,
1757                  NULL,
1758                  NULL,
1759                  0,
1760                  0),
1761     KNOWN_FOLDER(FOLDERID_Templates,
1762                  CSIDL_TEMPLATES,
1763                  "Templates",
1764                  KF_CATEGORY_PERUSER,
1765                  FOLDERID_RoamingAppData, GUID_NULL,
1766                  "Microsoft\\Windows\\Templates\0",
1767                  NULL,
1768                  0,
1769                  0),
1770     KNOWN_FOLDER(FOLDERID_UserPinned,
1771                  NO_CSIDL,
1772                  "User Pinned",
1773                  KF_CATEGORY_PERUSER,
1774                  FOLDERID_QuickLaunch, GUID_NULL,
1775                  "User Pinned\0",
1776                  NULL,
1777                  FILE_ATTRIBUTE_HIDDEN,
1778                  KFDF_PRECREATE),
1779     KNOWN_FOLDER(FOLDERID_UserProfiles,
1780                  NO_CSIDL,
1781                  "UserProfiles",
1782                  KF_CATEGORY_FIXED,
1783                  GUID_NULL, GUID_NULL,
1784                  NULL,
1785                  NULL,
1786                  FILE_ATTRIBUTE_READONLY,
1787                  KFDF_PRECREATE),
1788     KNOWN_FOLDER(FOLDERID_UserProgramFiles,
1789                  NO_CSIDL,
1790                  "UserProgramFiles",
1791                  KF_CATEGORY_PERUSER,
1792                  FOLDERID_LocalAppData, GUID_NULL,
1793                  "Programs\0",
1794                  NULL,
1795                  0,
1796                  0),
1797     KNOWN_FOLDER(FOLDERID_UserProgramFilesCommon,
1798                  NO_CSIDL,
1799                  "UserProgramFilesCommon",
1800                  KF_CATEGORY_PERUSER,
1801                  FOLDERID_UserProgramFiles, GUID_NULL,
1802                  "Common\0",
1803                  NULL,
1804                  0,
1805                  0),
1806     KNOWN_FOLDER(FOLDERID_UsersFiles,
1807                  NO_CSIDL,
1808                  "UsersFilesFolder",
1809                  KF_CATEGORY_VIRTUAL,
1810                  GUID_NULL, GUID_NULL,
1811                  NULL,
1812                  "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\0\0",
1813                  0,
1814                  0),
1815     KNOWN_FOLDER(FOLDERID_UsersLibraries,
1816                  NO_CSIDL,
1817                  "UsersLibrariesFolder",
1818                  KF_CATEGORY_VIRTUAL,
1819                  GUID_NULL, GUID_NULL,
1820                  NULL,
1821                  "::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\0\0",
1822                  0,
1823                  0),
1824     KNOWN_FOLDER(FOLDERID_Videos,
1825                  CSIDL_MYVIDEO,
1826                  "My Video",
1827                  KF_CATEGORY_PERUSER,
1828                  FOLDERID_Profile, GUID_NULL,
1829                  "Videos\0",
1830                  "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{18989B1D-99B5-455B-841C-AB7C74E4DDFC}\0shell:::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{A0953C92-50DC-43BF-BE83-3742FED03C9C}\0\0", /* win8 */
1831                  FILE_ATTRIBUTE_READONLY,
1832                  KFDF_ROAMABLE | KFDF_PRECREATE),
1833     KNOWN_FOLDER(FOLDERID_VideosLibrary,
1834                  NO_CSIDL,
1835                  "VideosLibrary",
1836                  KF_CATEGORY_PERUSER,
1837                  FOLDERID_Libraries, GUID_NULL,
1838                  "Videos.library-ms\0",
1839                  "::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\\{491E922F-5643-4af4-A7EB-4E7A138D8174}\0\0",
1840                  0,
1841                  KFDF_PRECREATE | KFDF_STREAM),
1842     KNOWN_FOLDER(FOLDERID_Windows,
1843                  CSIDL_WINDOWS,
1844                  "Windows",
1845                  KF_CATEGORY_FIXED,
1846                  GUID_NULL, GUID_NULL,
1847                  NULL,
1848                  NULL,
1849                  0,
1850                  0),
1851     KNOWN_FOLDER(_FOLDERID_CredentialManager,
1852                  NO_CSIDL,
1853                  "CredentialManager",
1854                  KF_CATEGORY_FIXED,
1855                  GUID_NULL, GUID_NULL,
1856                  NULL,
1857                  NULL,
1858                  0,
1859                  0),
1860     KNOWN_FOLDER(_FOLDERID_CryptoKeys,
1861                  NO_CSIDL,
1862                  "CryptoKeys",
1863                  KF_CATEGORY_FIXED,
1864                  GUID_NULL, GUID_NULL,
1865                  NULL,
1866                  NULL,
1867                  0,
1868                  0),
1869     KNOWN_FOLDER(_FOLDERID_DpapiKeys,
1870                  NO_CSIDL,
1871                  "DpapiKeys",
1872                  KF_CATEGORY_FIXED,
1873                  GUID_NULL, GUID_NULL,
1874                  NULL,
1875                  NULL,
1876                  0,
1877                  0),
1878     KNOWN_FOLDER(_FOLDERID_SystemCertificates,
1879                  NO_CSIDL,
1880                  "SystemCertificates",
1881                  KF_CATEGORY_FIXED,
1882                  GUID_NULL, GUID_NULL,
1883                  NULL,
1884                  NULL,
1885                  0,
1886                  0),
1887     { 0 }
1888 };
1889 #undef KNOWN_FOLDER
1890 BOOL known_folder_found[sizeof(known_folders)/sizeof(known_folders[0])-1];
1891 
1892 static BOOL is_in_strarray(const WCHAR *needle, const char *hay)
1893 {
1894     WCHAR wstr[MAX_PATH];
1895 
1896     if(!needle && !hay)
1897         return TRUE;
1898 
1899     while(hay && *hay)
1900     {
1901         DWORD ret;
1902 
1903         if(strcmp(hay, "(null)") == 0 && !needle)
1904             return TRUE;
1905 
1906         ret = MultiByteToWideChar(CP_ACP, 0, hay, -1, wstr, sizeof(wstr)/sizeof(wstr[0]));
1907         if(ret == 0)
1908         {
1909             ok(0, "Failed to convert string\n");
1910             return FALSE;
1911         }
1912 
1913         if(lstrcmpW(wstr, needle) == 0)
1914             return TRUE;
1915 
1916         hay += strlen(hay) + 1;
1917     }
1918 
1919     return FALSE;
1920 }
1921 
1922 static void check_known_folder(IKnownFolderManager *mgr, KNOWNFOLDERID *folderId)
1923 {
1924     HRESULT hr;
1925     const struct knownFolderDef *known_folder = &known_folders[0];
1926     int csidl, expectedCsidl, ret;
1927     KNOWNFOLDER_DEFINITION kfd;
1928     IKnownFolder *folder;
1929     WCHAR sName[1024];
1930     BOOL *current_known_folder_found = &known_folder_found[0];
1931     BOOL found = FALSE;
1932 
1933     while(known_folder->folderId != NULL)
1934     {
1935         if(IsEqualGUID(known_folder->folderId, folderId))
1936         {
1937             *current_known_folder_found = TRUE;
1938             found = TRUE;
1939             /* verify CSIDL */
1940             if(!(known_folder->csidl & NO_CSIDL))
1941             {
1942                 /* mask off winetest flags */
1943                 expectedCsidl = known_folder->csidl & 0xFFFF;
1944 
1945                 hr = IKnownFolderManager_FolderIdToCsidl(mgr, folderId, &csidl);
1946                 ok_(__FILE__, known_folder->line)(hr == S_OK, "cannot retrieve CSIDL for folder %s\n", known_folder->sFolderId);
1947 
1948                 ok_(__FILE__, known_folder->line)(csidl == expectedCsidl, "invalid CSIDL retrieved for folder %s. %d (%s) expected, but %d found\n", known_folder->sFolderId, expectedCsidl, known_folder->sCsidl, csidl);
1949             }
1950 
1951             hr = IKnownFolderManager_GetFolder(mgr, folderId, &folder);
1952             ok_(__FILE__, known_folder->line)(hr == S_OK, "cannot get known folder for %s\n", known_folder->sFolderId);
1953             if(SUCCEEDED(hr))
1954             {
1955                 hr = IKnownFolder_GetFolderDefinition(folder, &kfd);
1956                 ok_(__FILE__, known_folder->line)(hr == S_OK, "cannot get known folder definition for %s\n", known_folder->sFolderId);
1957                 if(SUCCEEDED(hr))
1958                 {
1959                     ret = MultiByteToWideChar(CP_ACP, 0, known_folder->sName, -1,  sName, sizeof(sName)/sizeof(sName[0]));
1960                     ok_(__FILE__, known_folder->line)(ret != 0, "cannot convert known folder name \"%s\" to wide characters\n", known_folder->sName);
1961 
1962                     ok_(__FILE__, known_folder->line)(lstrcmpW(kfd.pszName, sName)==0, "invalid known folder name returned for %s: %s expected, but %s retrieved\n", known_folder->sFolderId, wine_dbgstr_w(sName), wine_dbgstr_w(kfd.pszName));
1963 
1964                     ok_(__FILE__, known_folder->line)(kfd.category == known_folder->category, "invalid known folder category for %s: %d expected, but %d retrieved\n", known_folder->sFolderId, known_folder->category, kfd.category);
1965 
1966                     ok_(__FILE__, known_folder->line)(IsEqualGUID(known_folder->fidParents[0], &kfd.fidParent) ||
1967                                                               IsEqualGUID(known_folder->fidParents[1], &kfd.fidParent),
1968                                                       "invalid known folder parent for %s: %s retrieved\n",
1969                                                       known_folder->sFolderId, wine_dbgstr_guid(&kfd.fidParent));
1970 
1971                     ok_(__FILE__, known_folder->line)(is_in_strarray(kfd.pszRelativePath, known_folder->sRelativePath), "invalid known folder relative path returned for %s: %s expected, but %s retrieved\n", known_folder->sFolderId, known_folder->sRelativePath, wine_dbgstr_w(kfd.pszRelativePath));
1972 
1973                     ok_(__FILE__, known_folder->line)(is_in_strarray(kfd.pszParsingName, known_folder->sParsingName), "invalid known folder parsing name returned for %s: %s retrieved\n", known_folder->sFolderId, wine_dbgstr_w(kfd.pszParsingName));
1974 
1975                     ok_(__FILE__, known_folder->line)(known_folder->attributes == kfd.dwAttributes ||
1976                             (known_folder->csidl & WINE_ATTRIBUTES_OPTIONAL && kfd.dwAttributes == 0),
1977                             "invalid known folder attributes for %s: 0x%08x expected, but 0x%08x retrieved\n", known_folder->sFolderId, known_folder->attributes, kfd.dwAttributes);
1978 
1979                     ok_(__FILE__, known_folder->line)(!(kfd.kfdFlags & (~known_folder->definitionFlags)), "invalid known folder flags for %s: 0x%08x expected, but 0x%08x retrieved\n", known_folder->sFolderId, known_folder->definitionFlags, kfd.kfdFlags);
1980 
1981                     FreeKnownFolderDefinitionFields(&kfd);
1982                 }
1983 
1984             IKnownFolder_Release(folder);
1985             }
1986 
1987             break;
1988         }
1989         known_folder++;
1990         current_known_folder_found++;
1991     }
1992 
1993     if(!found)
1994     {
1995         trace("unknown known folder found: %s\n", wine_dbgstr_guid(folderId));
1996 
1997         hr = IKnownFolderManager_GetFolder(mgr, folderId, &folder);
1998         ok(hr == S_OK, "cannot get known folder for %s\n", wine_dbgstr_guid(folderId));
1999         if(SUCCEEDED(hr))
2000         {
2001             hr = IKnownFolder_GetFolderDefinition(folder, &kfd);
2002             todo_wine
2003             ok(hr == S_OK, "cannot get known folder definition for %s\n", wine_dbgstr_guid(folderId));
2004             if(SUCCEEDED(hr))
2005             {
2006                 trace("  category: %d\n", kfd.category);
2007                 trace("  name: %s\n", wine_dbgstr_w(kfd.pszName));
2008                 trace("  description: %s\n", wine_dbgstr_w(kfd.pszDescription));
2009                 trace("  parent: %s\n", wine_dbgstr_guid(&kfd.fidParent));
2010                 trace("  relative path: %s\n", wine_dbgstr_w(kfd.pszRelativePath));
2011                 trace("  parsing name: %s\n", wine_dbgstr_w(kfd.pszParsingName));
2012                 trace("  tooltip: %s\n", wine_dbgstr_w(kfd.pszTooltip));
2013                 trace("  localized name: %s\n", wine_dbgstr_w(kfd.pszLocalizedName));
2014                 trace("  icon: %s\n", wine_dbgstr_w(kfd.pszIcon));
2015                 trace("  security: %s\n", wine_dbgstr_w(kfd.pszSecurity));
2016                 trace("  attributes: 0x%08x\n", kfd.dwAttributes);
2017                 trace("  flags: 0x%08x\n", kfd.kfdFlags);
2018                 trace("  type: %s\n", wine_dbgstr_guid(&kfd.ftidType));
2019                 FreeKnownFolderDefinitionFields(&kfd);
2020             }
2021 
2022             IKnownFolder_Release(folder);
2023         }
2024     }
2025 }
2026 #undef NO_CSIDL
2027 
2028 static void test_knownFolders(void)
2029 {
2030     static const WCHAR sWindows[] = {'W','i','n','d','o','w','s',0};
2031     static const WCHAR sWindows2[] = {'w','i','n','d','o','w','s',0};
2032     static const WCHAR sExample[] = {'E','x','a','m','p','l','e',0};
2033     static const WCHAR sExample2[] = {'E','x','a','m','p','l','e','2',0};
2034     static const WCHAR sSubFolder[] = {'S','u','b','F','o','l','d','e','r',0};
2035     static const WCHAR sNoSuch[] = {'N','o','S','u','c','h',0};
2036     static const WCHAR sBackslash[] = {'\\',0};
2037     static const KNOWNFOLDERID newFolderId = {0x01234567, 0x89AB, 0xCDEF, {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x01} };
2038     static const KNOWNFOLDERID subFolderId = {0xFEDCBA98, 0x7654, 0x3210, {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF} };
2039     HRESULT hr;
2040     IKnownFolderManager *mgr = NULL;
2041     IKnownFolder *folder = NULL, *subFolder = NULL;
2042     KNOWNFOLDERID folderId, *folders;
2043     KF_CATEGORY cat = 0;
2044     KNOWNFOLDER_DEFINITION kfDefinition, kfSubDefinition;
2045     int csidl, i;
2046     UINT nCount = 0;
2047     LPWSTR folderPath, errorMsg;
2048     KF_REDIRECTION_CAPABILITIES redirectionCapabilities = 1;
2049     WCHAR sWinDir[MAX_PATH], sExamplePath[MAX_PATH], sExample2Path[MAX_PATH], sSubFolderPath[MAX_PATH], sSubFolder2Path[MAX_PATH];
2050     BOOL bRes;
2051     DWORD dwAttributes;
2052 
2053     GetWindowsDirectoryW( sWinDir, MAX_PATH );
2054 
2055     GetTempPathW(sizeof(sExamplePath)/sizeof(sExamplePath[0]), sExamplePath);
2056     lstrcatW(sExamplePath, sExample);
2057 
2058     GetTempPathW(sizeof(sExample2Path)/sizeof(sExample2Path[0]), sExample2Path);
2059     lstrcatW(sExample2Path, sExample2);
2060 
2061     lstrcpyW(sSubFolderPath, sExamplePath);
2062     lstrcatW(sSubFolderPath, sBackslash);
2063     lstrcatW(sSubFolderPath, sSubFolder);
2064 
2065     lstrcpyW(sSubFolder2Path, sExample2Path);
2066     lstrcatW(sSubFolder2Path, sBackslash);
2067     lstrcatW(sSubFolder2Path, sSubFolder);
2068 
2069     CoInitialize(NULL);
2070 
2071     hr = CoCreateInstance(&CLSID_KnownFolderManager, NULL, CLSCTX_INPROC_SERVER,
2072                           &IID_IKnownFolderManager, (LPVOID*)&mgr);
2073     if(hr == REGDB_E_CLASSNOTREG)
2074         win_skip("IKnownFolderManager unavailable\n");
2075     else
2076     {
2077         IUnknown *unk;
2078 
2079         ok(hr == S_OK, "failed to create KnownFolderManager instance: 0x%08x\n", hr);
2080 
2081         hr = IKnownFolderManager_QueryInterface(mgr, &IID_IMarshal, (void**)&unk);
2082         ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
2083 
2084         hr = IKnownFolderManager_FolderIdFromCsidl(mgr, CSIDL_WINDOWS, &folderId);
2085         ok(hr == S_OK, "failed to convert CSIDL to KNOWNFOLDERID: 0x%08x\n", hr);
2086         ok(IsEqualGUID(&folderId, &FOLDERID_Windows)==TRUE, "invalid KNOWNFOLDERID returned\n");
2087 
2088         hr = IKnownFolderManager_FolderIdToCsidl(mgr, &FOLDERID_Windows, &csidl);
2089         ok(hr == S_OK, "failed to convert CSIDL to KNOWNFOLDERID: 0x%08x\n", hr);
2090         ok(csidl == CSIDL_WINDOWS, "invalid CSIDL returned\n");
2091 
2092         hr = IKnownFolderManager_GetFolder(mgr, &FOLDERID_Windows, &folder);
2093         ok(hr == S_OK, "failed to get known folder: 0x%08x\n", hr);
2094         if(SUCCEEDED(hr))
2095         {
2096             hr = IKnownFolder_QueryInterface(folder, &IID_IMarshal, (void**)&unk);
2097             ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
2098 
2099             hr = IKnownFolder_GetCategory(folder, &cat);
2100             ok(hr == S_OK, "failed to get folder category: 0x%08x\n", hr);
2101             ok(cat==KF_CATEGORY_FIXED, "invalid folder category: %d\n", cat);
2102 
2103             hr = IKnownFolder_GetId(folder, &folderId);
2104             ok(hr == S_OK, "failed to get folder id: 0x%08x\n", hr);
2105             ok(IsEqualGUID(&folderId, &FOLDERID_Windows)==TRUE, "invalid KNOWNFOLDERID returned\n");
2106 
2107             hr = IKnownFolder_GetPath(folder, 0, &folderPath);
2108             ok(hr == S_OK, "failed to get path from known folder: 0x%08x\n", hr);
2109             ok(lstrcmpiW(sWinDir, folderPath)==0, "invalid path returned: \"%s\", expected: \"%s\"\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sWinDir));
2110             CoTaskMemFree(folderPath);
2111 
2112             hr = IKnownFolder_GetRedirectionCapabilities(folder, &redirectionCapabilities);
2113             todo_wine
2114             ok(hr == S_OK, "failed to get redirection capabilities: 0x%08x\n", hr);
2115             todo_wine
2116             ok(redirectionCapabilities==0, "invalid redirection capabilities returned: %d\n", redirectionCapabilities);
2117 
2118             hr = IKnownFolder_SetPath(folder, 0, sWinDir);
2119             todo_wine
2120             ok(hr == E_INVALIDARG, "unexpected value from SetPath: 0x%08x\n", hr);
2121 
2122             hr = IKnownFolder_GetFolderDefinition(folder, &kfDefinition);
2123             ok(hr == S_OK, "failed to get folder definition: 0x%08x\n", hr);
2124             if(SUCCEEDED(hr))
2125             {
2126                 ok(kfDefinition.category==KF_CATEGORY_FIXED, "invalid folder category: 0x%08x\n", kfDefinition.category);
2127                 ok(lstrcmpW(kfDefinition.pszName, sWindows)==0, "invalid folder name: %s\n", wine_dbgstr_w(kfDefinition.pszName));
2128                 ok(kfDefinition.dwAttributes==0, "invalid folder attributes: %d\n", kfDefinition.dwAttributes);
2129                 FreeKnownFolderDefinitionFields(&kfDefinition);
2130             }
2131 
2132             hr = IKnownFolder_Release(folder);
2133             ok(hr == S_OK, "failed to release KnownFolder instance: 0x%08x\n", hr);
2134         }
2135 
2136         hr = IKnownFolderManager_GetFolderByName(mgr, sWindows, &folder);
2137         ok(hr == S_OK, "failed to get known folder: 0x%08x\n", hr);
2138         if(SUCCEEDED(hr))
2139         {
2140             hr = IKnownFolder_GetId(folder, &folderId);
2141             ok(hr == S_OK, "failed to get folder id: 0x%08x\n", hr);
2142             ok(IsEqualGUID(&folderId, &FOLDERID_Windows)==TRUE, "invalid KNOWNFOLDERID returned\n");
2143 
2144             hr = IKnownFolder_Release(folder);
2145             ok(hr == S_OK, "failed to release KnownFolder instance: 0x%08x\n", hr);
2146         }
2147 
2148         hr = IKnownFolderManager_GetFolderByName(mgr, sWindows2, &folder);
2149         ok(hr == S_OK, "failed to get known folder: 0x%08x\n", hr);
2150         if(SUCCEEDED(hr))
2151         {
2152             hr = IKnownFolder_GetId(folder, &folderId);
2153             ok(hr == S_OK, "failed to get folder id: 0x%08x\n", hr);
2154             ok(IsEqualGUID(&folderId, &FOLDERID_Windows)==TRUE, "invalid KNOWNFOLDERID returned\n");
2155 
2156             hr = IKnownFolder_Release(folder);
2157             ok(hr == S_OK, "failed to release KnownFolder instance: 0x%08x\n", hr);
2158         }
2159 
2160         folder = (IKnownFolder *)0xdeadbeef;
2161         hr = IKnownFolderManager_GetFolderByName(mgr, sNoSuch, &folder);
2162         ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got 0x%08x\n", hr);
2163         ok(folder == NULL, "got %p\n", folder);
2164 
2165         for(i=0; i<sizeof(known_folder_found)/sizeof(known_folder_found[0]); ++i)
2166             known_folder_found[i] = FALSE;
2167 
2168         hr = IKnownFolderManager_GetFolderIds(mgr, &folders, &nCount);
2169         ok(hr == S_OK, "failed to get known folders: 0x%08x\n", hr);
2170         for(i=0;i<nCount;++i)
2171             check_known_folder(mgr, &folders[i]);
2172 
2173         for(i=0; i<sizeof(known_folder_found)/sizeof(known_folder_found[0]); ++i)
2174             if(!known_folder_found[i])
2175                 trace("Known folder %s not found on current platform\n", known_folders[i].sFolderId);
2176 
2177         CoTaskMemFree(folders);
2178 
2179         /* test of registering new known folders */
2180         bRes = CreateDirectoryW(sExamplePath, NULL);
2181         ok(bRes, "cannot create example directory: %s\n", wine_dbgstr_w(sExamplePath));
2182         bRes = CreateDirectoryW(sExample2Path, NULL);
2183         ok(bRes, "cannot create example directory: %s\n", wine_dbgstr_w(sExample2Path));
2184         bRes = CreateDirectoryW(sSubFolderPath, NULL);
2185         ok(bRes, "cannot create example directory: %s\n", wine_dbgstr_w(sSubFolderPath));
2186 
2187         ZeroMemory(&kfDefinition, sizeof(kfDefinition));
2188         kfDefinition.category = KF_CATEGORY_PERUSER;
2189         kfDefinition.pszName = CoTaskMemAlloc(sizeof(sExample));
2190         lstrcpyW(kfDefinition.pszName, sExample);
2191         kfDefinition.pszDescription = CoTaskMemAlloc(sizeof(sExample));
2192         lstrcpyW(kfDefinition.pszDescription, sExample);
2193         kfDefinition.pszRelativePath = CoTaskMemAlloc(sizeof(sExamplePath));
2194         lstrcpyW(kfDefinition.pszRelativePath, sExamplePath);
2195 
2196         hr = IKnownFolderManager_RegisterFolder(mgr, &newFolderId, &kfDefinition);
2197         if(hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED))
2198             win_skip("No permissions required to register custom known folder\n");
2199         else
2200         {
2201             ok(hr == S_OK, "failed to register known folder: 0x%08x\n", hr);
2202             if(SUCCEEDED(hr))
2203             {
2204                 hr = IKnownFolderManager_GetFolder(mgr, &newFolderId, &folder);
2205                 ok(hr == S_OK, "failed to get known folder: 0x%08x\n", hr);
2206                 if(SUCCEEDED(hr))
2207                 {
2208                     hr = IKnownFolder_GetCategory(folder, &cat);
2209                     ok(hr == S_OK, "failed to get folder category: hr=0x%0x\n", hr);
2210                     ok(cat == KF_CATEGORY_PERUSER, "invalid category returned: %d, while %d (KF_CATEGORY_PERUSER) expected\n", cat, KF_CATEGORY_PERUSER);
2211 
2212                     hr = IKnownFolder_GetId(folder, &folderId);
2213                     ok(hr == S_OK, "failed to get folder id: 0x%08x\n", hr);
2214                     ok(IsEqualGUID(&folderId, &newFolderId)==TRUE, "invalid KNOWNFOLDERID returned\n");
2215 
2216                     /* current path should be Temp\Example */
2217                     hr = IKnownFolder_GetPath(folder, 0, &folderPath);
2218                     ok(hr == S_OK, "failed to get path from known folder: 0x%08x\n", hr);
2219                     ok(lstrcmpiW(folderPath, sExamplePath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExamplePath));
2220                     CoTaskMemFree(folderPath);
2221 
2222                     /* register sub-folder and mark it as child of Example folder */
2223                     ZeroMemory(&kfSubDefinition, sizeof(kfSubDefinition));
2224                     kfSubDefinition.category = KF_CATEGORY_PERUSER;
2225                     kfSubDefinition.pszName = CoTaskMemAlloc(sizeof(sSubFolder));
2226                     lstrcpyW(kfSubDefinition.pszName, sSubFolder);
2227                     kfSubDefinition.pszDescription = CoTaskMemAlloc(sizeof(sSubFolder));
2228                     lstrcpyW(kfSubDefinition.pszDescription, sSubFolder);
2229                     kfSubDefinition.pszRelativePath = CoTaskMemAlloc(sizeof(sSubFolder));
2230                     lstrcpyW(kfSubDefinition.pszRelativePath, sSubFolder);
2231                     kfSubDefinition.fidParent = newFolderId;
2232 
2233                     hr = IKnownFolderManager_RegisterFolder(mgr, &subFolderId, &kfSubDefinition);
2234                     ok(hr == S_OK, "failed to register known folder: 0x%08x\n", hr);
2235                     if(SUCCEEDED(hr))
2236                     {
2237 
2238                         hr = IKnownFolderManager_GetFolder(mgr, &subFolderId, &subFolder);
2239                         ok(hr == S_OK, "failed to get known folder: 0x%08x\n", hr);
2240                         if(SUCCEEDED(hr))
2241                         {
2242                             /* check sub folder path */
2243                             hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
2244                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2245                             ok(lstrcmpiW(folderPath, sSubFolderPath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolderPath));
2246                             CoTaskMemFree(folderPath);
2247 
2248 
2249                             /* try to redirect Example to Temp\Example2  */
2250                             hr = IKnownFolderManager_Redirect(mgr, &newFolderId, NULL, 0, sExample2Path, 0, NULL, &errorMsg);
2251                             ok(hr == S_OK, "failed to redirect known folder: 0x%08x, errorMsg: %s\n", hr, wine_dbgstr_w(errorMsg));
2252 
2253                             /* verify */
2254                             hr = IKnownFolder_GetPath(folder, 0, &folderPath);
2255                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2256                             ok(lstrcmpiW(folderPath, sExample2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExample2Path));
2257                             CoTaskMemFree(folderPath);
2258 
2259                             /* verify sub folder - it should fail now, as we redirected its parent folder, but we have no sub folder in new location */
2260                             hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
2261                             ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "unexpected value from GetPath(): 0x%08x\n", hr);
2262                             ok(folderPath==NULL, "invalid known folder path retrieved: \"%s\" when NULL pointer was expected\n", wine_dbgstr_w(folderPath));
2263                             CoTaskMemFree(folderPath);
2264 
2265 
2266                             /* set Example path to original. Using SetPath() is valid here, as it also uses redirection internally */
2267                             hr = IKnownFolder_SetPath(folder, 0, sExamplePath);
2268                             ok(hr == S_OK, "SetPath() failed: 0x%08x\n", hr);
2269 
2270                             /* verify */
2271                             hr = IKnownFolder_GetPath(folder, 0, &folderPath);
2272                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2273                             ok(lstrcmpiW(folderPath, sExamplePath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExamplePath));
2274                             CoTaskMemFree(folderPath);
2275 
2276 
2277                             /* create sub folder in Temp\Example2 */
2278                             bRes = CreateDirectoryW(sSubFolder2Path, NULL);
2279                             ok(bRes, "cannot create example directory: %s\n", wine_dbgstr_w(sSubFolder2Path));
2280 
2281                             /* again perform that same redirection */
2282                             hr = IKnownFolderManager_Redirect(mgr, &newFolderId, NULL, 0, sExample2Path, 0, NULL, &errorMsg);
2283                             ok(hr == S_OK, "failed to redirect known folder: 0x%08x, errorMsg: %s\n", hr, wine_dbgstr_w(errorMsg));
2284 
2285                             /* verify sub folder. It should succeed now, as the required sub folder exists */
2286                             hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
2287                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2288                             ok(lstrcmpiW(folderPath, sSubFolder2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolder2Path));
2289                             CoTaskMemFree(folderPath);
2290 
2291                             /* remove newly created directory */
2292                             RemoveDirectoryW(sSubFolder2Path);
2293 
2294                             /* verify subfolder. It still succeeds, so Windows does not check folder presence each time */
2295                             hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
2296                             todo_wine
2297                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2298                             todo_wine
2299                             ok(lstrcmpiW(folderPath, sSubFolder2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolder2Path));
2300                             CoTaskMemFree(folderPath);
2301 
2302 
2303                             /* set Example path to original */
2304                             hr = IKnownFolder_SetPath(folder, 0, sExamplePath);
2305                             ok(hr == S_OK, "SetPath() failed: 0x%08x\n", hr);
2306 
2307                             /* verify */
2308                             hr = IKnownFolder_GetPath(folder, 0, &folderPath);
2309                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2310                             ok(lstrcmpiW(folderPath, sExamplePath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExamplePath));
2311                             CoTaskMemFree(folderPath);
2312 
2313                             /* verify sub folder */
2314                             hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
2315                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2316                             ok(lstrcmpiW(folderPath, sSubFolderPath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolderPath));
2317                             CoTaskMemFree(folderPath);
2318 
2319 
2320                             /* create sub folder in Temp\Example2 */
2321                             bRes = CreateDirectoryW(sSubFolder2Path, NULL);
2322                             ok(bRes, "cannot create example directory: %s\n", wine_dbgstr_w(sSubFolder2Path));
2323 
2324                             /* do that same redirection, but try to exclude sub-folder */
2325                             hr = IKnownFolderManager_Redirect(mgr, &newFolderId, NULL, 0, sExample2Path, 1, &subFolderId, &errorMsg);
2326                             ok(hr == S_OK, "failed to redirect known folder: 0x%08x, errorMsg: %s\n", hr, wine_dbgstr_w(errorMsg));
2327 
2328                             /* verify */
2329                             hr = IKnownFolder_GetPath(folder, 0, &folderPath);
2330                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2331                             ok(lstrcmpiW(folderPath, sExample2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExample2Path));
2332                             CoTaskMemFree(folderPath);
2333 
2334                             /* verify sub folder. Unexpectedly, this path was also changed. So, exclusion seems to be ignored (Windows bug)? This test however will let us know, if this behavior is changed */
2335                             hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
2336                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2337                             ok(lstrcmpiW(folderPath, sSubFolder2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolder2Path));
2338                             CoTaskMemFree(folderPath);
2339 
2340                             /* remove newly created directory */
2341                             RemoveDirectoryW(sSubFolder2Path);
2342 
2343 
2344                             /* set Example path to original */
2345                             hr = IKnownFolder_SetPath(folder, 0, sExamplePath);
2346                             ok(hr == S_OK, "SetPath() failed: 0x%08x\n", hr);
2347 
2348                             /* verify */
2349                             hr = IKnownFolder_GetPath(folder, 0, &folderPath);
2350                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2351                             ok(lstrcmpiW(folderPath, sExamplePath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExamplePath));
2352                             CoTaskMemFree(folderPath);
2353 
2354                             /* verify sub folder */
2355                             hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
2356                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2357                             ok(lstrcmpiW(folderPath, sSubFolderPath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolderPath));
2358                             CoTaskMemFree(folderPath);
2359 
2360 
2361                             /* do that same redirection again, but set it to copy content. It should also copy the sub folder, so checking it would succeed now */
2362                             hr = IKnownFolderManager_Redirect(mgr, &newFolderId, NULL, KF_REDIRECT_COPY_CONTENTS, sExample2Path, 0, NULL, &errorMsg);
2363                             ok(hr == S_OK, "failed to redirect known folder: 0x%08x, errorMsg: %s\n", hr, wine_dbgstr_w(errorMsg));
2364 
2365                             /* verify */
2366                             hr = IKnownFolder_GetPath(folder, 0, &folderPath);
2367                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2368                             ok(lstrcmpiW(folderPath, sExample2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExample2Path));
2369                             CoTaskMemFree(folderPath);
2370 
2371                             /* verify sub folder */
2372                             hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
2373                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2374                             ok(lstrcmpiW(folderPath, sSubFolder2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolder2Path));
2375                             CoTaskMemFree(folderPath);
2376 
2377                             /* remove copied directory */
2378                             RemoveDirectoryW(sSubFolder2Path);
2379 
2380 
2381                             /* set Example path to original */
2382                             hr = IKnownFolder_SetPath(folder, 0, sExamplePath);
2383                             ok(hr == S_OK, "SetPath() failed: 0x%08x\n", hr);
2384 
2385                             /* verify */
2386                             hr = IKnownFolder_GetPath(folder, 0, &folderPath);
2387                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2388                             ok(lstrcmpiW(folderPath, sExamplePath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExamplePath));
2389                             CoTaskMemFree(folderPath);
2390 
2391                             /* verify sub folder */
2392                             hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
2393                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2394                             ok(lstrcmpiW(folderPath, sSubFolderPath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolderPath));
2395                             CoTaskMemFree(folderPath);
2396 
2397 
2398                             /* redirect again, set it to copy content and remove originals */
2399                             hr = IKnownFolderManager_Redirect(mgr, &newFolderId, NULL, KF_REDIRECT_COPY_CONTENTS | KF_REDIRECT_DEL_SOURCE_CONTENTS, sExample2Path, 0, NULL, &errorMsg);
2400                             ok(hr == S_OK, "failed to redirect known folder: 0x%08x, errorMsg: %s\n", hr, wine_dbgstr_w(errorMsg));
2401 
2402                             /* verify */
2403                             hr = IKnownFolder_GetPath(folder, 0, &folderPath);
2404                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2405                             ok(lstrcmpiW(folderPath, sExample2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExample2Path));
2406                             CoTaskMemFree(folderPath);
2407 
2408                             /* verify sub folder */
2409                             hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
2410                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2411                             ok(lstrcmpiW(folderPath, sSubFolder2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolder2Path));
2412                             CoTaskMemFree(folderPath);
2413 
2414                             /* check if original directory was really removed */
2415                             dwAttributes = GetFileAttributesW(sExamplePath);
2416                             ok(dwAttributes==INVALID_FILE_ATTRIBUTES, "directory should not exist, but has attributes: 0x%08x\n", dwAttributes );
2417 
2418 
2419                             /* redirect (with copy) to original path */
2420                             hr = IKnownFolderManager_Redirect(mgr, &newFolderId, NULL, KF_REDIRECT_COPY_CONTENTS,  sExamplePath, 0, NULL, &errorMsg);
2421                             ok(hr == S_OK, "failed to redirect known folder: 0x%08x, errorMsg: %s\n", hr, wine_dbgstr_w(errorMsg));
2422 
2423                             /* verify */
2424                             hr = IKnownFolder_GetPath(folder, 0, &folderPath);
2425                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2426                             ok(lstrcmpiW(folderPath, sExamplePath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExamplePath));
2427                             CoTaskMemFree(folderPath);
2428 
2429                             /* verify sub folder */
2430                             hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
2431                             ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
2432                             ok(lstrcmpiW(folderPath, sSubFolderPath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolderPath));
2433                             CoTaskMemFree(folderPath);
2434 
2435                             /* check shell utility functions */
2436                             if(!pSHGetKnownFolderPath || !pSHSetKnownFolderPath)
2437                                 todo_wine
2438                                 win_skip("cannot get SHGet/SetKnownFolderPath routines\n");
2439                             else
2440                             {
2441                                 /* try to get current known folder path */
2442                                 hr = pSHGetKnownFolderPath(&newFolderId, 0, NULL, &folderPath);
2443                                 todo_wine
2444                                 ok(hr==S_OK, "cannot get known folder path: hr=0x%0x\n", hr);
2445                                 todo_wine
2446                                 ok(lstrcmpW(folderPath, sExamplePath)==0, "invalid path returned: %s\n", wine_dbgstr_w(folderPath));
2447 
2448                                 /* set it to new value */
2449                                 hr = pSHSetKnownFolderPath(&newFolderId, 0, NULL, sExample2Path);
2450                                 todo_wine
2451                                 ok(hr==S_OK, "cannot set known folder path: hr=0x%0x\n", hr);
2452 
2453                                 /* check if it changed */
2454                                 hr = pSHGetKnownFolderPath(&newFolderId, 0, NULL, &folderPath);
2455                                 todo_wine
2456                                 ok(hr==S_OK, "cannot get known folder path: hr=0x%0x\n", hr);
2457                                 todo_wine
2458                                 ok(lstrcmpW(folderPath, sExample2Path)==0, "invalid path returned: %s\n", wine_dbgstr_w(folderPath));
2459 
2460                                 /* set it back */
2461                                 hr = pSHSetKnownFolderPath(&newFolderId, 0, NULL, sExamplePath);
2462                                 todo_wine
2463                                 ok(hr==S_OK, "cannot set known folder path: hr=0x%0x\n", hr);
2464                             }
2465 
2466                             IKnownFolder_Release(subFolder);
2467                         }
2468 
2469                         hr = IKnownFolderManager_UnregisterFolder(mgr, &subFolderId);
2470                         ok(hr == S_OK, "failed to unregister folder: 0x%08x\n", hr);
2471                     }
2472 
2473                     FreeKnownFolderDefinitionFields(&kfSubDefinition);
2474 
2475                     hr = IKnownFolder_Release(folder);
2476                     ok(hr == S_OK, "failed to release KnownFolder instance: 0x%08x\n", hr);
2477 
2478                     /* update the folder */
2479                     CoTaskMemFree(kfDefinition.pszName);
2480                     kfDefinition.pszName = CoTaskMemAlloc(sizeof(sExample2));
2481                     lstrcpyW(kfDefinition.pszName, sExample2);
2482                     hr = IKnownFolderManager_RegisterFolder(mgr, &newFolderId, &kfDefinition);
2483                     ok(hr == S_OK, "failed to re-register known folder: 0x%08x\n", hr);
2484 
2485                     hr = IKnownFolderManager_GetFolder(mgr, &newFolderId, &folder);
2486                     ok(hr == S_OK, "failed to get known folder: 0x%08x\n", hr);
2487 
2488                     hr = IKnownFolder_GetFolderDefinition(folder, &kfSubDefinition);
2489                     ok(hr == S_OK, "failed to get folder definition: 0x%08x\n", hr);
2490                     ok(!memcmp(kfDefinition.pszName, kfSubDefinition.pszName, sizeof(sExample2)),
2491                             "Got wrong updated name: %s\n", wine_dbgstr_w(kfSubDefinition.pszName));
2492 
2493                     FreeKnownFolderDefinitionFields(&kfSubDefinition);
2494 
2495                     hr = IKnownFolder_Release(folder);
2496                     ok(hr == S_OK, "failed to release KnownFolder instance: 0x%08x\n", hr);
2497                 }
2498 
2499                 hr = IKnownFolderManager_UnregisterFolder(mgr, &newFolderId);
2500                 ok(hr == S_OK, "failed to unregister folder: 0x%08x\n", hr);
2501             }
2502         }
2503         FreeKnownFolderDefinitionFields(&kfDefinition);
2504 
2505         RemoveDirectoryW(sSubFolder2Path);
2506         RemoveDirectoryW(sSubFolderPath);
2507         RemoveDirectoryW(sExamplePath);
2508         RemoveDirectoryW(sExample2Path);
2509 
2510         hr = IKnownFolderManager_Release(mgr);
2511         ok(hr == S_OK, "failed to release KnownFolderManager instance: 0x%08x\n", hr);
2512     }
2513     CoUninitialize();
2514 }
2515 
2516 
2517 static void test_DoEnvironmentSubst(void)
2518 {
2519     WCHAR expectedW[MAX_PATH];
2520     WCHAR bufferW[MAX_PATH];
2521     CHAR  expectedA[MAX_PATH];
2522     CHAR  bufferA[MAX_PATH];
2523     DWORD res;
2524     DWORD res2;
2525     DWORD len;
2526     INT   i;
2527     static const WCHAR does_not_existW[] = {'%','D','O','E','S','_','N','O','T','_','E','X','I','S','T','%',0};
2528     static const CHAR  does_not_existA[] = "%DOES_NOT_EXIST%";
2529     static const CHAR  *names[] = {
2530                             /* interactive apps and services (works on all windows versions) */
2531                             "%ALLUSERSPROFILE%", "%APPDATA%", "%LOCALAPPDATA%",
2532                             "%NUMBER_OF_PROCESSORS%", "%OS%", "%PROCESSOR_ARCHITECTURE%",
2533                             "%PROCESSOR_IDENTIFIER%", "%PROCESSOR_LEVEL%", "%PROCESSOR_REVISION%",
2534                             "%ProgramFiles%", "%SystemDrive%",
2535                             "%SystemRoot%", "%USERPROFILE%", "%windir%",
2536                             /* todo_wine: "%COMPUTERNAME%", "%ProgramData%", "%PUBLIC%", */
2537 
2538                             /* replace more than one var is allowed */
2539                             "%HOMEDRIVE%%HOMEPATH%",
2540                             "%OS% %windir%"}; /* always the last entry in the table */
2541 
2542     for (i = 0; i < (sizeof(names)/sizeof(LPSTR)); i++)
2543     {
2544         memset(bufferA, '#', MAX_PATH - 1);
2545         bufferA[MAX_PATH - 1] = 0;
2546         lstrcpyA(bufferA, names[i]);
2547         MultiByteToWideChar(CP_ACP, 0, bufferA, MAX_PATH, bufferW, sizeof(bufferW)/sizeof(WCHAR));
2548 
2549         res2 = ExpandEnvironmentStringsA(names[i], expectedA, MAX_PATH);
2550         res = DoEnvironmentSubstA(bufferA, MAX_PATH);
2551 
2552         /* is the space for the terminating 0 included? */
2553         if (!i && HIWORD(res) && (LOWORD(res) == (lstrlenA(bufferA))))
2554         {
2555             win_skip("DoEnvironmentSubstA/W are broken on NT 4\n");
2556             return;
2557         }
2558         ok(HIWORD(res) && (LOWORD(res) == res2),
2559             "%d: got %d/%d (expected TRUE/%d)\n", i, HIWORD(res), LOWORD(res), res2);
2560         ok(!lstrcmpA(bufferA, expectedA),
2561             "%d: got %s (expected %s)\n", i, bufferA, expectedA);
2562 
2563         res2 = ExpandEnvironmentStringsW(bufferW, expectedW, MAX_PATH);
2564         res = DoEnvironmentSubstW(bufferW, MAX_PATH);
2565         ok(HIWORD(res) && (LOWORD(res) == res2),
2566             "%d: got %d/%d (expected TRUE/%d)\n", i, HIWORD(res), LOWORD(res), res2);
2567         ok(!lstrcmpW(bufferW, expectedW),
2568             "%d: got %s (expected %s)\n", i, wine_dbgstr_w(bufferW), wine_dbgstr_w(expectedW));
2569     }
2570 
2571     i--; /* reuse data in the last table entry */
2572     len = LOWORD(res); /* needed length */
2573 
2574     /* one character extra is fine */
2575     memset(bufferA, '#', MAX_PATH - 1);
2576     bufferA[len + 2] = 0;
2577     lstrcpyA(bufferA, names[i]);
2578     MultiByteToWideChar(CP_ACP, 0, bufferA, MAX_PATH, bufferW, sizeof(bufferW)/sizeof(WCHAR));
2579 
2580     res2 = ExpandEnvironmentStringsA(bufferA, expectedA, MAX_PATH);
2581     res = DoEnvironmentSubstA(bufferA, len + 1);
2582     ok(HIWORD(res) && (LOWORD(res) == res2),
2583         "+1: got %d/%d (expected TRUE/%d)\n", HIWORD(res), LOWORD(res), res2);
2584     ok(!lstrcmpA(bufferA, expectedA),
2585         "+1: got %s (expected %s)\n", bufferA, expectedA);
2586 
2587     res2 = ExpandEnvironmentStringsW(bufferW, expectedW, MAX_PATH);
2588     res = DoEnvironmentSubstW(bufferW, len + 1);
2589     ok(HIWORD(res) && (LOWORD(res) == res2),
2590         "+1: got %d/%d (expected TRUE/%d)\n", HIWORD(res), LOWORD(res), res2);
2591     ok(!lstrcmpW(bufferW, expectedW),
2592         "+1: got %s (expected %s)\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(expectedW));
2593 
2594 
2595     /* minimal buffer length (result string and terminating 0) */
2596     memset(bufferA, '#', MAX_PATH - 1);
2597     bufferA[len + 2] = 0;
2598     lstrcpyA(bufferA, names[i]);
2599     MultiByteToWideChar(CP_ACP, 0, bufferA, MAX_PATH, bufferW, sizeof(bufferW)/sizeof(WCHAR));
2600 
2601     /* ANSI version failed without an extra byte, as documented on msdn */
2602     res = DoEnvironmentSubstA(bufferA, len);
2603     ok(!HIWORD(res) && (LOWORD(res) == len),
2604         " 0: got %d/%d  (expected FALSE/%d)\n", HIWORD(res), LOWORD(res), len);
2605     ok(!lstrcmpA(bufferA, names[i]),
2606         " 0: got %s (expected %s)\n", bufferA, names[i]);
2607 
2608     /* DoEnvironmentSubstW works as expected */
2609     res2 = ExpandEnvironmentStringsW(bufferW, expectedW, MAX_PATH);
2610     res = DoEnvironmentSubstW(bufferW, len);
2611     ok(HIWORD(res) && (LOWORD(res) == res2),
2612         " 0: got %d/%d (expected TRUE/%d)\n", HIWORD(res), LOWORD(res), res2);
2613     ok(!lstrcmpW(bufferW, expectedW),
2614         " 0: got %s (expected %s)\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(expectedW));
2615 
2616 
2617     /* Buffer too small */
2618     /* result: FALSE / provided buffer length / the buffer is untouched */
2619     memset(bufferA, '#', MAX_PATH - 1);
2620     bufferA[len + 2] = 0;
2621     lstrcpyA(bufferA, names[i]);
2622     MultiByteToWideChar(CP_ACP, 0, bufferA, MAX_PATH, bufferW, sizeof(bufferW)/sizeof(WCHAR));
2623 
2624     res = DoEnvironmentSubstA(bufferA, len - 1);
2625     ok(!HIWORD(res) && (LOWORD(res) == (len - 1)),
2626         "-1: got %d/%d  (expected FALSE/%d)\n", HIWORD(res), LOWORD(res), len - 1);
2627     ok(!lstrcmpA(bufferA, names[i]),
2628         "-1: got %s (expected %s)\n", bufferA, names[i]);
2629 
2630     lstrcpyW(expectedW, bufferW);
2631     res = DoEnvironmentSubstW(bufferW, len - 1);
2632     ok(!HIWORD(res) && (LOWORD(res) == (len - 1)),
2633         "-1: got %d/%d  (expected FALSE/%d)\n", HIWORD(res), LOWORD(res), len - 1);
2634     ok(!lstrcmpW(bufferW, expectedW),
2635         "-1: got %s (expected %s)\n", wine_dbgstr_w(bufferW), wine_dbgstr_w(expectedW));
2636 
2637 
2638     /* unknown variable */
2639     /* result: TRUE / string length including terminating 0 / the buffer is untouched */
2640     memset(bufferA, '#', MAX_PATH - 1);
2641     bufferA[MAX_PATH - 1] = 0;
2642     lstrcpyA(bufferA, does_not_existA);
2643     MultiByteToWideChar(CP_ACP, 0, bufferA, MAX_PATH, bufferW, sizeof(bufferW)/sizeof(WCHAR));
2644 
2645     res2 = lstrlenA(does_not_existA) + 1;
2646     res = DoEnvironmentSubstA(bufferA, MAX_PATH);
2647     ok(HIWORD(res) && (LOWORD(res) == res2),
2648             "%d: got %d/%d (expected TRUE/%d)\n", i, HIWORD(res), LOWORD(res), res2);
2649     ok(!lstrcmpA(bufferA, does_not_existA),
2650         "%d: got %s (expected %s)\n", i, bufferA, does_not_existA);
2651 
2652     res = DoEnvironmentSubstW(bufferW, MAX_PATH);
2653     ok(HIWORD(res) && (LOWORD(res) == res2),
2654         "%d: got %d/%d (expected TRUE/%d)\n", i, HIWORD(res), LOWORD(res), res2);
2655     ok(!lstrcmpW(bufferW, does_not_existW),
2656         "%d: got %s (expected %s)\n", i, wine_dbgstr_w(bufferW), wine_dbgstr_w(does_not_existW));
2657 
2658 
2659     if (0)
2660     {
2661         /* NULL crashes on windows */
2662         res = DoEnvironmentSubstA(NULL, MAX_PATH);
2663         res = DoEnvironmentSubstW(NULL, MAX_PATH);
2664     }
2665 }
2666 
2667 static void test_PathYetAnotherMakeUniqueName(void)
2668 {
2669     static const WCHAR shortW[] = {'f','i','l','e','.','t','s','t',0};
2670     static const WCHAR short2W[] = {'f','i','l','e',' ','(','2',')','.','t','s','t',0};
2671     static const WCHAR tmpW[] = {'t','m','p',0};
2672     static const WCHAR longW[] = {'n','a','m','e',0};
2673     static const WCHAR long2W[] = {'n','a','m','e',' ','(','2',')',0};
2674     WCHAR nameW[MAX_PATH], buffW[MAX_PATH], pathW[MAX_PATH];
2675     HANDLE file;
2676     BOOL ret;
2677 
2678     if (!pPathYetAnotherMakeUniqueName)
2679     {
2680         win_skip("PathYetAnotherMakeUniqueName() is not available.\n");
2681         return;
2682     }
2683 
2684 if (0)
2685 {
2686     /* crashes on Windows */
2687     ret = pPathYetAnotherMakeUniqueName(NULL, NULL, NULL, NULL);
2688     ok(!ret, "got %d\n", ret);
2689 
2690     ret = pPathYetAnotherMakeUniqueName(nameW, NULL, NULL, NULL);
2691     ok(!ret, "got %d\n", ret);
2692 }
2693 
2694     GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
2695 
2696     /* Using short name only first */
2697     nameW[0] = 0;
2698     ret = pPathYetAnotherMakeUniqueName(nameW, pathW, shortW, NULL);
2699     ok(ret, "got %d\n", ret);
2700     lstrcpyW(buffW, pathW);
2701     lstrcatW(buffW, shortW);
2702     ok(!lstrcmpW(nameW, buffW), "got %s, expected %s\n", wine_dbgstr_w(nameW), wine_dbgstr_w(buffW));
2703 
2704     /* now create a file with this name and get next name */
2705     file = CreateFileW(nameW, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
2706     ok(file != NULL, "got %p\n", file);
2707 
2708     nameW[0] = 0;
2709     ret = pPathYetAnotherMakeUniqueName(nameW, pathW, shortW, NULL);
2710     ok(ret, "got %d\n", ret);
2711     lstrcpyW(buffW, pathW);
2712     lstrcatW(buffW, short2W);
2713     ok(!lstrcmpW(nameW, buffW), "got %s, expected %s\n", wine_dbgstr_w(nameW), wine_dbgstr_w(buffW));
2714 
2715     CloseHandle(file);
2716 
2717     /* Using short and long */
2718     nameW[0] = 0;
2719     ret = pPathYetAnotherMakeUniqueName(nameW, pathW, tmpW, longW);
2720     ok(ret, "got %d\n", ret);
2721     lstrcpyW(buffW, pathW);
2722     lstrcatW(buffW, longW);
2723     ok(!lstrcmpW(nameW, buffW), "got %s, expected %s\n", wine_dbgstr_w(nameW), wine_dbgstr_w(buffW));
2724 
2725     file = CreateFileW(nameW, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
2726     ok(file != NULL, "got %p\n", file);
2727 
2728     nameW[0] = 0;
2729     ret = pPathYetAnotherMakeUniqueName(nameW, pathW, tmpW, longW);
2730     ok(ret, "got %d\n", ret);
2731     lstrcpyW(buffW, pathW);
2732     lstrcatW(buffW, long2W);
2733     ok(!lstrcmpW(nameW, buffW), "got %s, expected %s\n", wine_dbgstr_w(nameW), wine_dbgstr_w(buffW));
2734 
2735     CloseHandle(file);
2736 
2737     /* Using long only */
2738     nameW[0] = 0;
2739     ret = pPathYetAnotherMakeUniqueName(nameW, pathW, NULL, longW);
2740     ok(ret, "got %d\n", ret);
2741     lstrcpyW(buffW, pathW);
2742     lstrcatW(buffW, longW);
2743     ok(!lstrcmpW(nameW, buffW), "got %s, expected %s\n", wine_dbgstr_w(nameW), wine_dbgstr_w(buffW));
2744 }
2745 
2746 static void test_SHGetKnownFolderIDList(void)
2747 {
2748     PIDLIST_ABSOLUTE pidl;
2749     HRESULT hr;
2750 
2751     if (!pSHGetKnownFolderIDList)
2752     {
2753         win_skip("SHGetKnownFolderIDList is not available.\n");
2754         return;
2755     }
2756 
2757     hr = pSHGetKnownFolderIDList(NULL, 0, NULL, NULL);
2758     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2759 
2760 if (0) { /* crashes on native */
2761     pidl = (void*)0xdeadbeef;
2762     hr = pSHGetKnownFolderIDList(NULL, 0, NULL, &pidl);
2763 }
2764     /* not a known folder */
2765     pidl = (void*)0xdeadbeef;
2766     hr = pSHGetKnownFolderIDList(&IID_IUnknown, 0, NULL, &pidl);
2767     ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got 0x%08x\n", hr);
2768     ok(pidl == NULL, "got %p\n", pidl);
2769 
2770     hr = pSHGetKnownFolderIDList(&FOLDERID_Desktop, 0, NULL, NULL);
2771     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2772 
2773     pidl = (void*)0xdeadbeef;
2774     hr = pSHGetKnownFolderIDList(&FOLDERID_Desktop, 0, NULL, &pidl);
2775     ok(hr == S_OK, "SHGetKnownFolderIDList failed: 0x%08x\n", hr);
2776     ok(ILIsEmpty(pidl), "pidl should be empty.\n");
2777     ok(pidl->mkid.cb == 0, "get wrong value: %d\n", pidl->mkid.cb);
2778     ILFree(pidl);
2779 
2780     pidl = (void*)0xdeadbeef;
2781     hr = pSHGetKnownFolderIDList(&FOLDERID_Desktop, KF_FLAG_NO_ALIAS, NULL, &pidl);
2782     ok(hr == S_OK, "SHGetKnownFolderIDList failed: 0x%08x\n", hr);
2783     todo_wine ok(!ILIsEmpty(pidl), "pidl should not be empty.\n");
2784     todo_wine ok(pidl->mkid.cb == 20, "get wrong value: %d\n", pidl->mkid.cb);
2785     ILFree(pidl);
2786 
2787     pidl = (void*)0xdeadbeef;
2788     hr = pSHGetKnownFolderIDList(&FOLDERID_Documents, 0, NULL, &pidl);
2789     ok(hr == S_OK, "SHGetKnownFolderIDList failed: 0x%08x\n", hr);
2790     ok(!ILIsEmpty(pidl), "pidl should not be empty.\n");
2791     ok(pidl->mkid.cb == 20, "get wrong value: %d\n", pidl->mkid.cb);
2792     ILFree(pidl);
2793 
2794     pidl = (void*)0xdeadbeef;
2795     hr = pSHGetKnownFolderIDList(&FOLDERID_Documents, KF_FLAG_NO_ALIAS, NULL, &pidl);
2796     ok(hr == S_OK, "SHGetKnownFolderIDList failed: 0x%08x\n", hr);
2797     ok(!ILIsEmpty(pidl), "pidl should not be empty.\n");
2798     ok(pidl->mkid.cb == 20, "get wrong value: %d\n", pidl->mkid.cb);
2799     ILFree(pidl);
2800 }
2801 
2802 START_TEST(shellpath)
2803 {
2804     if (!init()) return;
2805 
2806     loadShell32();
2807     pGetSystemWow64DirectoryA = (void *)GetProcAddress( GetModuleHandleA("kernel32.dll"),
2808                                                         "GetSystemWow64DirectoryA" );
2809     if (myARGC >= 3)
2810         doChild(myARGV[2]);
2811     else
2812     {
2813         /* Report missing functions once */
2814         if (!pSHGetFolderLocation)
2815             win_skip("SHGetFolderLocation is not available\n");
2816 
2817         /* first test various combinations of parameters: */
2818         test_parameters();
2819 
2820         /* check known values: */
2821         test_PidlTypes();
2822         test_GUIDs();
2823         test_EnvVars();
2824         testWinDir();
2825         testSystemDir();
2826         test_NonExistentPath();
2827         test_SHGetFolderPathEx();
2828         test_knownFolders();
2829         test_DoEnvironmentSubst();
2830         test_PathYetAnotherMakeUniqueName();
2831         test_SHGetKnownFolderIDList();
2832     }
2833 }
2834