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