[SCRRUN_WINETEST] Sync with Wine Staging 2.9. CORE-13362
[reactos.git] / rostests / winetests / scrrun / filesystem.c
1 /*
2 *
3 * Copyright 2012 Alistair Leslie-Hughes
4 * Copyright 2014 Dmitry Timoshkov
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #define COBJMACROS
22 #include <stdio.h>
23 #include <limits.h>
24
25 #include "windows.h"
26 #include "ole2.h"
27 #include "olectl.h"
28 #include "oleauto.h"
29 #include "dispex.h"
30
31 #include "wine/test.h"
32
33 #include "initguid.h"
34 #include "scrrun.h"
35
36 static IFileSystem3 *fs3;
37
38 /* w2k and 2k3 error code. */
39 #define E_VAR_NOT_SET 0x800a005b
40
41 static inline ULONG get_refcount(IUnknown *iface)
42 {
43 IUnknown_AddRef(iface);
44 return IUnknown_Release(iface);
45 }
46
47 static const WCHAR crlfW[] = {'\r','\n',0};
48 static const char utf16bom[] = {0xff,0xfe,0};
49
50 #define GET_REFCOUNT(iface) \
51 get_refcount((IUnknown*)iface)
52
53 static inline void get_temp_path(const WCHAR *prefix, WCHAR *path)
54 {
55 WCHAR buffW[MAX_PATH];
56
57 GetTempPathW(MAX_PATH, buffW);
58 GetTempFileNameW(buffW, prefix, 0, path);
59 DeleteFileW(path);
60 }
61
62 static IDrive *get_fixed_drive(void)
63 {
64 IDriveCollection *drives;
65 IEnumVARIANT *iter;
66 IDrive *drive;
67 HRESULT hr;
68
69 hr = IFileSystem3_get_Drives(fs3, &drives);
70 ok(hr == S_OK, "got 0x%08x\n", hr);
71
72 hr = IDriveCollection_get__NewEnum(drives, (IUnknown**)&iter);
73 ok(hr == S_OK, "got 0x%08x\n", hr);
74 IDriveCollection_Release(drives);
75
76 while (1) {
77 DriveTypeConst type;
78 VARIANT var;
79
80 hr = IEnumVARIANT_Next(iter, 1, &var, NULL);
81 if (hr == S_FALSE) {
82 drive = NULL;
83 break;
84 }
85 ok(hr == S_OK, "got 0x%08x\n", hr);
86
87 hr = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IDrive, (void**)&drive);
88 ok(hr == S_OK, "got 0x%08x\n", hr);
89 VariantClear(&var);
90
91 hr = IDrive_get_DriveType(drive, &type);
92 ok(hr == S_OK, "got 0x%08x\n", hr);
93 if (type == Fixed)
94 break;
95
96 IDrive_Release(drive);
97 }
98
99 IEnumVARIANT_Release(iter);
100 return drive;
101 }
102
103 #define test_provideclassinfo(a, b) _test_provideclassinfo((IDispatch*)a, b, __LINE__)
104 static void _test_provideclassinfo(IDispatch *disp, const GUID *guid, int line)
105 {
106 IProvideClassInfo *classinfo;
107 TYPEATTR *attr;
108 ITypeInfo *ti;
109 IUnknown *unk;
110 HRESULT hr;
111
112 hr = IDispatch_QueryInterface(disp, &IID_IProvideClassInfo, (void **)&classinfo);
113 ok_(__FILE__,line) (hr == S_OK, "Failed to get IProvideClassInfo, %#x.\n", hr);
114
115 hr = IProvideClassInfo_GetClassInfo(classinfo, &ti);
116 ok_(__FILE__,line) (hr == S_OK, "GetClassInfo() failed, %#x.\n", hr);
117
118 hr = ITypeInfo_GetTypeAttr(ti, &attr);
119 ok_(__FILE__,line) (hr == S_OK, "GetTypeAttr() failed, %#x.\n", hr);
120
121 ok_(__FILE__,line) (IsEqualGUID(&attr->guid, guid), "Unexpected typeinfo %s, expected %s\n", wine_dbgstr_guid(&attr->guid),
122 wine_dbgstr_guid(guid));
123
124 hr = IProvideClassInfo_QueryInterface(classinfo, &IID_IUnknown, (void **)&unk);
125 ok(hr == S_OK, "Failed to QI for IUnknown.\n");
126 ok(unk == (IUnknown *)disp, "Got unk %p, original %p.\n", unk, disp);
127 IUnknown_Release(unk);
128
129 IProvideClassInfo_Release(classinfo);
130 ITypeInfo_ReleaseTypeAttr(ti, attr);
131 ITypeInfo_Release(ti);
132 }
133
134 static void test_interfaces(void)
135 {
136 static const WCHAR nonexistent_dirW[] = {
137 'c', ':', '\\', 'N', 'o', 'n', 'e', 'x', 'i', 's', 't', 'e', 'n', 't', 0};
138 static const WCHAR pathW[] = {'p','a','t','h',0};
139 static const WCHAR file_kernel32W[] = {
140 '\\', 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', 0};
141 HRESULT hr;
142 IDispatch *disp;
143 IDispatchEx *dispex;
144 IObjectWithSite *site;
145 VARIANT_BOOL b;
146 BSTR path;
147 WCHAR windows_path[MAX_PATH];
148 WCHAR file_path[MAX_PATH];
149
150 IFileSystem3_QueryInterface(fs3, &IID_IDispatch, (void**)&disp);
151
152 GetSystemDirectoryW(windows_path, MAX_PATH);
153 lstrcpyW(file_path, windows_path);
154 lstrcatW(file_path, file_kernel32W);
155
156 test_provideclassinfo(disp, &CLSID_FileSystemObject);
157
158 hr = IDispatch_QueryInterface(disp, &IID_IObjectWithSite, (void**)&site);
159 ok(hr == E_NOINTERFACE, "got 0x%08x, expected 0x%08x\n", hr, E_NOINTERFACE);
160
161 hr = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
162 ok(hr == E_NOINTERFACE, "got 0x%08x, expected 0x%08x\n", hr, E_NOINTERFACE);
163
164 b = VARIANT_TRUE;
165 hr = IFileSystem3_FileExists(fs3, NULL, &b);
166 ok(hr == S_OK, "got 0x%08x, expected 0x%08x\n", hr, S_OK);
167 ok(b == VARIANT_FALSE, "got %x\n", b);
168
169 hr = IFileSystem3_FileExists(fs3, NULL, NULL);
170 ok(hr == E_POINTER, "got 0x%08x, expected 0x%08x\n", hr, E_POINTER);
171
172 path = SysAllocString(pathW);
173 b = VARIANT_TRUE;
174 hr = IFileSystem3_FileExists(fs3, path, &b);
175 ok(hr == S_OK, "got 0x%08x, expected 0x%08x\n", hr, S_OK);
176 ok(b == VARIANT_FALSE, "got %x\n", b);
177 SysFreeString(path);
178
179 path = SysAllocString(file_path);
180 b = VARIANT_FALSE;
181 hr = IFileSystem3_FileExists(fs3, path, &b);
182 ok(hr == S_OK, "got 0x%08x, expected 0x%08x\n", hr, S_OK);
183 ok(b == VARIANT_TRUE, "got %x\n", b);
184 SysFreeString(path);
185
186 path = SysAllocString(windows_path);
187 b = VARIANT_TRUE;
188 hr = IFileSystem3_FileExists(fs3, path, &b);
189 ok(hr == S_OK, "got 0x%08x, expected 0x%08x\n", hr, S_OK);
190 ok(b == VARIANT_FALSE, "got %x\n", b);
191 SysFreeString(path);
192
193 /* Folder Exists */
194 hr = IFileSystem3_FolderExists(fs3, NULL, NULL);
195 ok(hr == E_POINTER, "got 0x%08x, expected 0x%08x\n", hr, E_POINTER);
196
197 path = SysAllocString(windows_path);
198 hr = IFileSystem3_FolderExists(fs3, path, &b);
199 ok(hr == S_OK, "got 0x%08x, expected 0x%08x\n", hr, S_OK);
200 ok(b == VARIANT_TRUE, "Folder doesn't exists\n");
201 SysFreeString(path);
202
203 path = SysAllocString(nonexistent_dirW);
204 hr = IFileSystem3_FolderExists(fs3, path, &b);
205 ok(hr == S_OK, "got 0x%08x, expected 0x%08x\n", hr, S_OK);
206 ok(b == VARIANT_FALSE, "Folder exists\n");
207 SysFreeString(path);
208
209 path = SysAllocString(file_path);
210 hr = IFileSystem3_FolderExists(fs3, path, &b);
211 ok(hr == S_OK, "got 0x%08x, expected 0x%08x\n", hr, S_OK);
212 ok(b == VARIANT_FALSE, "Folder exists\n");
213 SysFreeString(path);
214
215 IDispatch_Release(disp);
216 }
217
218 static void test_createfolder(void)
219 {
220 WCHAR buffW[MAX_PATH];
221 HRESULT hr;
222 BSTR path;
223 IFolder *folder;
224 BOOL ret;
225
226 get_temp_path(NULL, buffW);
227 ret = CreateDirectoryW(buffW, NULL);
228 ok(ret, "got %d, %d\n", ret, GetLastError());
229
230 /* create existing directory */
231 path = SysAllocString(buffW);
232 folder = (void*)0xdeabeef;
233 hr = IFileSystem3_CreateFolder(fs3, path, &folder);
234 ok(hr == CTL_E_FILEALREADYEXISTS, "got 0x%08x\n", hr);
235 ok(folder == NULL, "got %p\n", folder);
236 SysFreeString(path);
237 RemoveDirectoryW(buffW);
238 }
239
240 static void test_textstream(void)
241 {
242 static const WCHAR testfileW[] = {'t','e','s','t','f','i','l','e','.','t','x','t',0};
243 ITextStream *stream;
244 VARIANT_BOOL b;
245 DWORD written;
246 HANDLE file;
247 HRESULT hr;
248 BSTR name, data;
249 BOOL ret;
250
251 file = CreateFileW(testfileW, GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
252 CloseHandle(file);
253
254 name = SysAllocString(testfileW);
255 b = VARIANT_FALSE;
256 hr = IFileSystem3_FileExists(fs3, name, &b);
257 ok(hr == S_OK, "got 0x%08x, expected 0x%08x\n", hr, S_OK);
258 ok(b == VARIANT_TRUE, "got %x\n", b);
259
260 /* different mode combinations */
261 hr = IFileSystem3_OpenTextFile(fs3, name, ForWriting | ForAppending, VARIANT_FALSE, TristateFalse, &stream);
262 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
263
264 hr = IFileSystem3_OpenTextFile(fs3, name, ForReading | ForAppending, VARIANT_FALSE, TristateFalse, &stream);
265 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
266
267 hr = IFileSystem3_OpenTextFile(fs3, name, ForWriting | ForReading, VARIANT_FALSE, TristateFalse, &stream);
268 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
269
270 hr = IFileSystem3_OpenTextFile(fs3, name, ForAppending, VARIANT_FALSE, TristateFalse, &stream);
271 ok(hr == S_OK, "got 0x%08x\n", hr);
272 hr = ITextStream_Read(stream, 1, &data);
273 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
274 ITextStream_Release(stream);
275
276 hr = IFileSystem3_OpenTextFile(fs3, name, ForWriting, VARIANT_FALSE, TristateFalse, &stream);
277 ok(hr == S_OK, "got 0x%08x\n", hr);
278 hr = ITextStream_Read(stream, 1, &data);
279 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
280 ITextStream_Release(stream);
281
282 hr = IFileSystem3_OpenTextFile(fs3, name, ForReading, VARIANT_FALSE, TristateFalse, &stream);
283 ok(hr == S_OK, "got 0x%08x\n", hr);
284
285 /* try to write when open for reading */
286 hr = ITextStream_WriteLine(stream, name);
287 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
288
289 hr = ITextStream_Write(stream, name);
290 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
291
292 hr = ITextStream_get_AtEndOfStream(stream, NULL);
293 ok(hr == E_POINTER, "got 0x%08x\n", hr);
294
295 b = 10;
296 hr = ITextStream_get_AtEndOfStream(stream, &b);
297 ok(hr == S_OK || broken(hr == S_FALSE), "got 0x%08x\n", hr);
298 ok(b == VARIANT_TRUE, "got 0x%x\n", b);
299
300 ITextStream_Release(stream);
301
302 hr = IFileSystem3_OpenTextFile(fs3, name, ForWriting, VARIANT_FALSE, TristateFalse, &stream);
303 ok(hr == S_OK, "got 0x%08x\n", hr);
304
305 b = 10;
306 hr = ITextStream_get_AtEndOfStream(stream, &b);
307 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
308 ok(b == VARIANT_TRUE || broken(b == 10), "got 0x%x\n", b);
309
310 b = 10;
311 hr = ITextStream_get_AtEndOfLine(stream, &b);
312 todo_wine {
313 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
314 ok(b == VARIANT_FALSE || broken(b == 10), "got 0x%x\n", b);
315 }
316 hr = ITextStream_Read(stream, 1, &data);
317 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
318
319 hr = ITextStream_ReadLine(stream, &data);
320 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
321
322 hr = ITextStream_ReadAll(stream, &data);
323 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
324
325 ITextStream_Release(stream);
326
327 hr = IFileSystem3_OpenTextFile(fs3, name, ForAppending, VARIANT_FALSE, TristateFalse, &stream);
328 ok(hr == S_OK, "got 0x%08x\n", hr);
329
330 b = 10;
331 hr = ITextStream_get_AtEndOfStream(stream, &b);
332 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
333 ok(b == VARIANT_TRUE || broken(b == 10), "got 0x%x\n", b);
334
335 b = 10;
336 hr = ITextStream_get_AtEndOfLine(stream, &b);
337 todo_wine {
338 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
339 ok(b == VARIANT_FALSE || broken(b == 10), "got 0x%x\n", b);
340 }
341 hr = ITextStream_Read(stream, 1, &data);
342 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
343
344 hr = ITextStream_ReadLine(stream, &data);
345 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
346
347 hr = ITextStream_ReadAll(stream, &data);
348 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
349
350 ITextStream_Release(stream);
351
352 /* now with non-empty file */
353 file = CreateFileW(testfileW, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
354 ret = WriteFile(file, testfileW, sizeof(testfileW), &written, NULL);
355 ok(ret && written == sizeof(testfileW), "got %d\n", ret);
356 CloseHandle(file);
357
358 hr = IFileSystem3_OpenTextFile(fs3, name, ForReading, VARIANT_FALSE, TristateFalse, &stream);
359 ok(hr == S_OK, "got 0x%08x\n", hr);
360 b = 10;
361 hr = ITextStream_get_AtEndOfStream(stream, &b);
362 ok(hr == S_OK, "got 0x%08x\n", hr);
363 ok(b == VARIANT_FALSE, "got 0x%x\n", b);
364 ITextStream_Release(stream);
365
366 SysFreeString(name);
367 DeleteFileW(testfileW);
368 }
369
370 static void test_GetFileVersion(void)
371 {
372 static const WCHAR k32W[] = {'\\','k','e','r','n','e','l','3','2','.','d','l','l',0};
373 static const WCHAR k33W[] = {'\\','k','e','r','n','e','l','3','3','.','d','l','l',0};
374 WCHAR pathW[MAX_PATH], filenameW[MAX_PATH];
375 BSTR path, version;
376 HRESULT hr;
377
378 GetSystemDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
379
380 lstrcpyW(filenameW, pathW);
381 lstrcatW(filenameW, k32W);
382
383 path = SysAllocString(filenameW);
384 hr = IFileSystem3_GetFileVersion(fs3, path, &version);
385 ok(hr == S_OK, "got 0x%08x\n", hr);
386 ok(*version != 0, "got %s\n", wine_dbgstr_w(version));
387 SysFreeString(version);
388 SysFreeString(path);
389
390 lstrcpyW(filenameW, pathW);
391 lstrcatW(filenameW, k33W);
392
393 path = SysAllocString(filenameW);
394 version = (void*)0xdeadbeef;
395 hr = IFileSystem3_GetFileVersion(fs3, path, &version);
396 ok(broken(hr == S_OK) || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got 0x%08x\n", hr);
397 if (hr == S_OK)
398 {
399 ok(*version == 0, "got %s\n", wine_dbgstr_w(version));
400 SysFreeString(version);
401 }
402 else
403 ok(version == (void*)0xdeadbeef, "got %p\n", version);
404 SysFreeString(path);
405 }
406
407 static void test_GetParentFolderName(void)
408 {
409 static const WCHAR path1[] = {'a',0};
410 static const WCHAR path2[] = {'a','/','a','/','a',0};
411 static const WCHAR path3[] = {'a','\\','a','\\','a',0};
412 static const WCHAR path4[] = {'a','/','a','/','/','\\','\\',0};
413 static const WCHAR path5[] = {'c',':','\\','\\','a',0};
414 static const WCHAR path6[] = {'a','c',':','\\','a',0};
415 static const WCHAR result2[] = {'a','/','a',0};
416 static const WCHAR result3[] = {'a','\\','a',0};
417 static const WCHAR result4[] = {'a',0};
418 static const WCHAR result5[] = {'c',':','\\',0};
419 static const WCHAR result6[] = {'a','c',':',0};
420
421 static const struct {
422 const WCHAR *path;
423 const WCHAR *result;
424 } tests[] = {
425 {NULL, NULL},
426 {path1, NULL},
427 {path2, result2},
428 {path3, result3},
429 {path4, result4},
430 {path5, result5},
431 {path6, result6}
432 };
433
434 BSTR path, result;
435 HRESULT hr;
436 int i;
437
438 hr = IFileSystem3_GetParentFolderName(fs3, NULL, NULL);
439 ok(hr == E_POINTER, "GetParentFolderName returned %x, expected E_POINTER\n", hr);
440
441 for(i=0; i<sizeof(tests)/sizeof(tests[0]); i++) {
442 result = (BSTR)0xdeadbeef;
443 path = tests[i].path ? SysAllocString(tests[i].path) : NULL;
444 hr = IFileSystem3_GetParentFolderName(fs3, path, &result);
445 ok(hr == S_OK, "%d) GetParentFolderName returned %x, expected S_OK\n", i, hr);
446 if(!tests[i].result)
447 ok(!result, "%d) result = %s\n", i, wine_dbgstr_w(result));
448 else
449 ok(!lstrcmpW(result, tests[i].result), "%d) result = %s\n", i, wine_dbgstr_w(result));
450 SysFreeString(path);
451 SysFreeString(result);
452 }
453 }
454
455 static void test_GetFileName(void)
456 {
457 static const WCHAR path1[] = {'a',0};
458 static const WCHAR path2[] = {'a','/','a','.','b',0};
459 static const WCHAR path3[] = {'a','\\',0};
460 static const WCHAR path4[] = {'c',':',0};
461 static const WCHAR path5[] = {'/','\\',0};
462 static const WCHAR result2[] = {'a','.','b',0};
463 static const WCHAR result3[] = {'a',0};
464
465 static const struct {
466 const WCHAR *path;
467 const WCHAR *result;
468 } tests[] = {
469 {NULL, NULL},
470 {path1, path1},
471 {path2, result2},
472 {path3, result3},
473 {path4, NULL},
474 {path5, NULL}
475 };
476
477 BSTR path, result;
478 HRESULT hr;
479 int i;
480
481 hr = IFileSystem3_GetFileName(fs3, NULL, NULL);
482 ok(hr == E_POINTER, "GetFileName returned %x, expected E_POINTER\n", hr);
483
484 for(i=0; i<sizeof(tests)/sizeof(tests[0]); i++) {
485 result = (BSTR)0xdeadbeef;
486 path = tests[i].path ? SysAllocString(tests[i].path) : NULL;
487 hr = IFileSystem3_GetFileName(fs3, path, &result);
488 ok(hr == S_OK, "%d) GetFileName returned %x, expected S_OK\n", i, hr);
489 if(!tests[i].result)
490 ok(!result, "%d) result = %s\n", i, wine_dbgstr_w(result));
491 else
492 ok(!lstrcmpW(result, tests[i].result), "%d) result = %s\n", i, wine_dbgstr_w(result));
493 SysFreeString(path);
494 SysFreeString(result);
495 }
496 }
497
498 static void test_GetBaseName(void)
499 {
500 static const WCHAR path1[] = {'a',0};
501 static const WCHAR path2[] = {'a','/','a','.','b','.','c',0};
502 static const WCHAR path3[] = {'a','.','b','\\',0};
503 static const WCHAR path4[] = {'c',':',0};
504 static const WCHAR path5[] = {'/','\\',0};
505 static const WCHAR path6[] = {'.','a',0};
506 static const WCHAR result1[] = {'a',0};
507 static const WCHAR result2[] = {'a','.','b',0};
508 static const WCHAR result6[] = {0};
509
510 static const struct {
511 const WCHAR *path;
512 const WCHAR *result;
513 } tests[] = {
514 {NULL, NULL},
515 {path1, result1},
516 {path2, result2},
517 {path3, result1},
518 {path4, NULL},
519 {path5, NULL},
520 {path6, result6}
521 };
522
523 BSTR path, result;
524 HRESULT hr;
525 int i;
526
527 hr = IFileSystem3_GetBaseName(fs3, NULL, NULL);
528 ok(hr == E_POINTER, "GetBaseName returned %x, expected E_POINTER\n", hr);
529
530 for(i=0; i<sizeof(tests)/sizeof(tests[0]); i++) {
531 result = (BSTR)0xdeadbeef;
532 path = tests[i].path ? SysAllocString(tests[i].path) : NULL;
533 hr = IFileSystem3_GetBaseName(fs3, path, &result);
534 ok(hr == S_OK, "%d) GetBaseName returned %x, expected S_OK\n", i, hr);
535 if(!tests[i].result)
536 ok(!result, "%d) result = %s\n", i, wine_dbgstr_w(result));
537 else
538 ok(!lstrcmpW(result, tests[i].result), "%d) result = %s\n", i, wine_dbgstr_w(result));
539 SysFreeString(path);
540 SysFreeString(result);
541 }
542 }
543
544 static void test_GetAbsolutePathName(void)
545 {
546 static const WCHAR dir1[] = {'t','e','s','t','_','d','i','r','1',0};
547 static const WCHAR dir2[] = {'t','e','s','t','_','d','i','r','2',0};
548 static const WCHAR dir_match1[] = {'t','e','s','t','_','d','i','r','*',0};
549 static const WCHAR dir_match2[] = {'t','e','s','t','_','d','i','*',0};
550 static const WCHAR cur_dir[] = {'.',0};
551
552 WIN32_FIND_DATAW fdata;
553 HANDLE find;
554 WCHAR buf[MAX_PATH], buf2[MAX_PATH];
555 BSTR path, result;
556 HRESULT hr;
557
558 hr = IFileSystem3_GetAbsolutePathName(fs3, NULL, NULL);
559 ok(hr == E_POINTER, "GetAbsolutePathName returned %x, expected E_POINTER\n", hr);
560
561 hr = IFileSystem3_GetAbsolutePathName(fs3, NULL, &result);
562 ok(hr == S_OK, "GetAbsolutePathName returned %x, expected S_OK\n", hr);
563 GetFullPathNameW(cur_dir, MAX_PATH, buf, NULL);
564 ok(!lstrcmpiW(buf, result), "result = %s, expected %s\n", wine_dbgstr_w(result), wine_dbgstr_w(buf));
565 SysFreeString(result);
566
567 find = FindFirstFileW(dir_match2, &fdata);
568 if(find != INVALID_HANDLE_VALUE) {
569 skip("GetAbsolutePathName tests\n");
570 FindClose(find);
571 return;
572 }
573
574 path = SysAllocString(dir_match1);
575 hr = IFileSystem3_GetAbsolutePathName(fs3, path, &result);
576 ok(hr == S_OK, "GetAbsolutePathName returned %x, expected S_OK\n", hr);
577 GetFullPathNameW(dir_match1, MAX_PATH, buf2, NULL);
578 ok(!lstrcmpiW(buf2, result), "result = %s, expected %s\n", wine_dbgstr_w(result), wine_dbgstr_w(buf2));
579 SysFreeString(result);
580
581 ok(CreateDirectoryW(dir1, NULL), "CreateDirectory(%s) failed\n", wine_dbgstr_w(dir1));
582 hr = IFileSystem3_GetAbsolutePathName(fs3, path, &result);
583 ok(hr == S_OK, "GetAbsolutePathName returned %x, expected S_OK\n", hr);
584 GetFullPathNameW(dir1, MAX_PATH, buf, NULL);
585 ok(!lstrcmpiW(buf, result) || broken(!lstrcmpiW(buf2, result)), "result = %s, expected %s\n",
586 wine_dbgstr_w(result), wine_dbgstr_w(buf));
587 SysFreeString(result);
588
589 ok(CreateDirectoryW(dir2, NULL), "CreateDirectory(%s) failed\n", wine_dbgstr_w(dir2));
590 hr = IFileSystem3_GetAbsolutePathName(fs3, path, &result);
591 ok(hr == S_OK, "GetAbsolutePathName returned %x, expected S_OK\n", hr);
592 if(!lstrcmpiW(buf, result) || !lstrcmpiW(buf2, result)) {
593 ok(!lstrcmpiW(buf, result) || broken(!lstrcmpiW(buf2, result)), "result = %s, expected %s\n",
594 wine_dbgstr_w(result), wine_dbgstr_w(buf));
595 }else {
596 GetFullPathNameW(dir2, MAX_PATH, buf, NULL);
597 ok(!lstrcmpiW(buf, result), "result = %s, expected %s\n",
598 wine_dbgstr_w(result), wine_dbgstr_w(buf));
599 }
600 SysFreeString(result);
601
602 SysFreeString(path);
603 path = SysAllocString(dir_match2);
604 hr = IFileSystem3_GetAbsolutePathName(fs3, path, &result);
605 ok(hr == S_OK, "GetAbsolutePathName returned %x, expected S_OK\n", hr);
606 GetFullPathNameW(dir_match2, MAX_PATH, buf, NULL);
607 ok(!lstrcmpiW(buf, result), "result = %s, expected %s\n", wine_dbgstr_w(result), wine_dbgstr_w(buf));
608 SysFreeString(result);
609 SysFreeString(path);
610
611 RemoveDirectoryW(dir1);
612 RemoveDirectoryW(dir2);
613 }
614
615 static void test_GetFile(void)
616 {
617 static const WCHAR slW[] = {'\\',0};
618 BSTR path, str;
619 WCHAR pathW[MAX_PATH];
620 FileAttribute fa;
621 VARIANT size;
622 DWORD gfa, new_gfa;
623 IFile *file;
624 HRESULT hr;
625 HANDLE hf;
626 BOOL ret;
627 DATE date;
628
629 get_temp_path(NULL, pathW);
630
631 path = SysAllocString(pathW);
632 hr = IFileSystem3_GetFile(fs3, path, NULL);
633 ok(hr == E_POINTER, "GetFile returned %x, expected E_POINTER\n", hr);
634 hr = IFileSystem3_GetFile(fs3, NULL, &file);
635 ok(hr == E_INVALIDARG, "GetFile returned %x, expected E_INVALIDARG\n", hr);
636
637 file = (IFile*)0xdeadbeef;
638 hr = IFileSystem3_GetFile(fs3, path, &file);
639 ok(!file, "file != NULL\n");
640 ok(hr == CTL_E_FILENOTFOUND, "GetFile returned %x, expected CTL_E_FILENOTFOUND\n", hr);
641
642 hf = CreateFileW(pathW, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_READONLY, NULL);
643 if(hf == INVALID_HANDLE_VALUE) {
644 skip("Can't create temporary file\n");
645 SysFreeString(path);
646 return;
647 }
648 CloseHandle(hf);
649
650 hr = IFileSystem3_GetFile(fs3, path, &file);
651 ok(hr == S_OK, "GetFile returned %x, expected S_OK\n", hr);
652
653 hr = IFile_get_DateLastModified(file, NULL);
654 ok(hr == E_POINTER, "got 0x%08x\n", hr);
655
656 date = 0.0;
657 hr = IFile_get_DateLastModified(file, &date);
658 ok(hr == S_OK, "got 0x%08x\n", hr);
659 ok(date > 0.0, "got %f\n", date);
660
661 hr = IFile_get_Path(file, NULL);
662 ok(hr == E_POINTER, "got 0x%08x\n", hr);
663
664 hr = IFile_get_Path(file, &str);
665 ok(hr == S_OK, "got 0x%08x\n", hr);
666 ok(!lstrcmpiW(str, pathW), "got %s\n", wine_dbgstr_w(str));
667 SysFreeString(str);
668
669 #define FILE_ATTR_MASK (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
670 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE | \
671 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED)
672
673 hr = IFile_get_Attributes(file, &fa);
674 gfa = GetFileAttributesW(pathW) & FILE_ATTR_MASK;
675 ok(hr == S_OK, "get_Attributes returned %x, expected S_OK\n", hr);
676 ok(fa == gfa, "fa = %x, expected %x\n", fa, gfa);
677
678 hr = IFile_put_Attributes(file, gfa | FILE_ATTRIBUTE_READONLY);
679 ok(hr == S_OK, "put_Attributes failed: %08x\n", hr);
680 new_gfa = GetFileAttributesW(pathW) & FILE_ATTR_MASK;
681 ok(new_gfa == (gfa|FILE_ATTRIBUTE_READONLY), "new_gfa = %x, expected %x\n", new_gfa, gfa|FILE_ATTRIBUTE_READONLY);
682
683 hr = IFile_get_Attributes(file, &fa);
684 ok(hr == S_OK, "get_Attributes returned %x, expected S_OK\n", hr);
685 ok(fa == new_gfa, "fa = %x, expected %x\n", fa, new_gfa);
686
687 hr = IFile_put_Attributes(file, gfa);
688 ok(hr == S_OK, "put_Attributes failed: %08x\n", hr);
689 new_gfa = GetFileAttributesW(pathW) & FILE_ATTR_MASK;
690 ok(new_gfa == gfa, "new_gfa = %x, expected %x\n", new_gfa, gfa);
691
692 hr = IFile_get_Attributes(file, &fa);
693 ok(hr == S_OK, "get_Attributes returned %x, expected S_OK\n", hr);
694 ok(fa == gfa, "fa = %x, expected %x\n", fa, gfa);
695
696 hr = IFile_get_Size(file, &size);
697 ok(hr == S_OK, "get_Size returned %x, expected S_OK\n", hr);
698 ok(V_VT(&size) == VT_I4, "V_VT(&size) = %d, expected VT_I4\n", V_VT(&size));
699 ok(V_I4(&size) == 0, "V_I4(&size) = %d, expected 0\n", V_I4(&size));
700 IFile_Release(file);
701
702 hr = IFileSystem3_DeleteFile(fs3, path, FALSE);
703 ok(hr==CTL_E_PERMISSIONDENIED || broken(hr==S_OK),
704 "DeleteFile returned %x, expected CTL_E_PERMISSIONDENIED\n", hr);
705 if(hr != S_OK) {
706 hr = IFileSystem3_DeleteFile(fs3, path, TRUE);
707 ok(hr == S_OK, "DeleteFile returned %x, expected S_OK\n", hr);
708 }
709 hr = IFileSystem3_DeleteFile(fs3, path, TRUE);
710 ok(hr == CTL_E_FILENOTFOUND, "DeleteFile returned %x, expected CTL_E_FILENOTFOUND\n", hr);
711
712 SysFreeString(path);
713
714 /* try with directory */
715 lstrcatW(pathW, slW);
716 ret = CreateDirectoryW(pathW, NULL);
717 ok(ret, "got %d, error %d\n", ret, GetLastError());
718
719 path = SysAllocString(pathW);
720 hr = IFileSystem3_GetFile(fs3, path, &file);
721 ok(hr == CTL_E_FILENOTFOUND, "GetFile returned %x, expected S_OK\n", hr);
722 SysFreeString(path);
723
724 RemoveDirectoryW(pathW);
725 }
726
727 static inline BOOL create_file(const WCHAR *name)
728 {
729 HANDLE f = CreateFileW(name, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
730 CloseHandle(f);
731 return f != INVALID_HANDLE_VALUE;
732 }
733
734 static inline void create_path(const WCHAR *folder, const WCHAR *name, WCHAR *ret)
735 {
736 DWORD len = lstrlenW(folder);
737 memmove(ret, folder, len*sizeof(WCHAR));
738 ret[len] = '\\';
739 memmove(ret+len+1, name, (lstrlenW(name)+1)*sizeof(WCHAR));
740 }
741
742 static void test_CopyFolder(void)
743 {
744 static const WCHAR filesystem3_dir[] = {'f','i','l','e','s','y','s','t','e','m','3','_','t','e','s','t',0};
745 static const WCHAR s1[] = {'s','r','c','1',0};
746 static const WCHAR s[] = {'s','r','c','*',0};
747 static const WCHAR d[] = {'d','s','t',0};
748 static const WCHAR empty[] = {0};
749
750 WCHAR tmp[MAX_PATH];
751 BSTR bsrc, bdst;
752 HRESULT hr;
753
754 if(!CreateDirectoryW(filesystem3_dir, NULL)) {
755 skip("can't create temporary directory\n");
756 return;
757 }
758
759 create_path(filesystem3_dir, s1, tmp);
760 bsrc = SysAllocString(tmp);
761 create_path(filesystem3_dir, d, tmp);
762 bdst = SysAllocString(tmp);
763 hr = IFileSystem3_CopyFile(fs3, bsrc, bdst, VARIANT_TRUE);
764 ok(hr == CTL_E_FILENOTFOUND, "CopyFile returned %x, expected CTL_E_FILENOTFOUND\n", hr);
765
766 hr = IFileSystem3_CopyFolder(fs3, bsrc, bdst, VARIANT_TRUE);
767 ok(hr == CTL_E_PATHNOTFOUND, "CopyFolder returned %x, expected CTL_E_PATHNOTFOUND\n", hr);
768
769 ok(create_file(bsrc), "can't create %s file\n", wine_dbgstr_w(bsrc));
770 hr = IFileSystem3_CopyFile(fs3, bsrc, bdst, VARIANT_TRUE);
771 ok(hr == S_OK, "CopyFile returned %x, expected S_OK\n", hr);
772
773 hr = IFileSystem3_CopyFolder(fs3, bsrc, bdst, VARIANT_TRUE);
774 ok(hr == CTL_E_PATHNOTFOUND, "CopyFolder returned %x, expected CTL_E_PATHNOTFOUND\n", hr);
775
776 hr = IFileSystem3_DeleteFile(fs3, bsrc, VARIANT_FALSE);
777 ok(hr == S_OK, "DeleteFile returned %x, expected S_OK\n", hr);
778
779 ok(CreateDirectoryW(bsrc, NULL), "can't create %s\n", wine_dbgstr_w(bsrc));
780 hr = IFileSystem3_CopyFile(fs3, bsrc, bdst, VARIANT_TRUE);
781 ok(hr == CTL_E_FILENOTFOUND, "CopyFile returned %x, expected CTL_E_FILENOTFOUND\n", hr);
782
783 hr = IFileSystem3_CopyFolder(fs3, bsrc, bdst, VARIANT_TRUE);
784 ok(hr == CTL_E_FILEALREADYEXISTS, "CopyFolder returned %x, expected CTL_E_FILEALREADYEXISTS\n", hr);
785
786 hr = IFileSystem3_DeleteFile(fs3, bdst, VARIANT_TRUE);
787 ok(hr == S_OK, "DeleteFile returned %x, expected S_OK\n", hr);
788
789 hr = IFileSystem3_CopyFolder(fs3, bsrc, bdst, VARIANT_TRUE);
790 ok(hr == S_OK, "CopyFolder returned %x, expected S_OK\n", hr);
791
792 hr = IFileSystem3_CopyFolder(fs3, bsrc, bdst, VARIANT_TRUE);
793 ok(hr == S_OK, "CopyFolder returned %x, expected S_OK\n", hr);
794 create_path(tmp, s1, tmp);
795 ok(GetFileAttributesW(tmp) == INVALID_FILE_ATTRIBUTES,
796 "%s file exists\n", wine_dbgstr_w(tmp));
797
798 create_path(filesystem3_dir, d, tmp);
799 create_path(tmp, empty, tmp);
800 SysFreeString(bdst);
801 bdst = SysAllocString(tmp);
802 hr = IFileSystem3_CopyFolder(fs3, bsrc, bdst, VARIANT_TRUE);
803 ok(hr == S_OK, "CopyFolder returned %x, expected S_OK\n", hr);
804 create_path(tmp, s1, tmp);
805 ok(GetFileAttributesW(tmp) != INVALID_FILE_ATTRIBUTES,
806 "%s directory doesn't exist\n", wine_dbgstr_w(tmp));
807 ok(RemoveDirectoryW(tmp), "can't remove %s directory\n", wine_dbgstr_w(tmp));
808 create_path(filesystem3_dir, d, tmp);
809 SysFreeString(bdst);
810 bdst = SysAllocString(tmp);
811
812
813 create_path(filesystem3_dir, s, tmp);
814 SysFreeString(bsrc);
815 bsrc = SysAllocString(tmp);
816 hr = IFileSystem3_CopyFolder(fs3, bsrc, bdst, VARIANT_TRUE);
817 ok(hr == S_OK, "CopyFolder returned %x, expected S_OK\n", hr);
818 create_path(filesystem3_dir, d, tmp);
819 create_path(tmp, s1, tmp);
820 ok(GetFileAttributesW(tmp) != INVALID_FILE_ATTRIBUTES,
821 "%s directory doesn't exist\n", wine_dbgstr_w(tmp));
822
823 hr = IFileSystem3_DeleteFolder(fs3, bdst, VARIANT_FALSE);
824 ok(hr == S_OK, "DeleteFolder returned %x, expected S_OK\n", hr);
825
826 hr = IFileSystem3_CopyFolder(fs3, bsrc, bdst, VARIANT_TRUE);
827 ok(hr == CTL_E_PATHNOTFOUND, "CopyFolder returned %x, expected CTL_E_PATHNOTFOUND\n", hr);
828
829 create_path(filesystem3_dir, s1, tmp);
830 SysFreeString(bsrc);
831 bsrc = SysAllocString(tmp);
832 create_path(tmp, s1, tmp);
833 ok(create_file(tmp), "can't create %s file\n", wine_dbgstr_w(tmp));
834 hr = IFileSystem3_CopyFolder(fs3, bsrc, bdst, VARIANT_FALSE);
835 ok(hr == S_OK, "CopyFolder returned %x, expected S_OK\n", hr);
836
837 hr = IFileSystem3_CopyFolder(fs3, bsrc, bdst, VARIANT_FALSE);
838 ok(hr == CTL_E_FILEALREADYEXISTS, "CopyFolder returned %x, expected CTL_E_FILEALREADYEXISTS\n", hr);
839
840 hr = IFileSystem3_CopyFolder(fs3, bsrc, bdst, VARIANT_TRUE);
841 ok(hr == S_OK, "CopyFolder returned %x, expected S_OK\n", hr);
842 SysFreeString(bsrc);
843 SysFreeString(bdst);
844
845 bsrc = SysAllocString(filesystem3_dir);
846 hr = IFileSystem3_DeleteFolder(fs3, bsrc, VARIANT_FALSE);
847 ok(hr == S_OK, "DeleteFolder returned %x, expected S_OK\n", hr);
848 SysFreeString(bsrc);
849 }
850
851 static BSTR bstr_from_str(const char *str)
852 {
853 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
854 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
855 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
856 return ret;
857 }
858
859 struct buildpath_test
860 {
861 const char *path;
862 const char *name;
863 const char *result;
864 };
865
866 static struct buildpath_test buildpath_data[] =
867 {
868 { "C:\\path", "..\\name.tmp", "C:\\path\\..\\name.tmp" },
869 { "C:\\path", "\\name.tmp", "C:\\path\\name.tmp" },
870 { "C:\\path", "name.tmp", "C:\\path\\name.tmp" },
871 { "C:\\path\\", "name.tmp", "C:\\path\\name.tmp" },
872 { "C:\\path", "\\\\name.tmp", "C:\\path\\\\name.tmp" },
873 { "C:\\path\\", "\\name.tmp", "C:\\path\\name.tmp" },
874 { "C:\\path\\", "\\\\name.tmp", "C:\\path\\\\name.tmp" },
875 { "C:\\path\\\\", "\\\\name.tmp", "C:\\path\\\\\\name.tmp" },
876 { "C:\\\\", "\\name.tmp", "C:\\\\name.tmp" },
877 { "C:", "name.tmp", "C:name.tmp" },
878 { "C:", "\\\\name.tmp", "C:\\\\name.tmp" },
879 { NULL }
880 };
881
882 static void test_BuildPath(void)
883 {
884 struct buildpath_test *ptr = buildpath_data;
885 BSTR ret, path;
886 HRESULT hr;
887 int i = 0;
888
889 hr = IFileSystem3_BuildPath(fs3, NULL, NULL, NULL);
890 ok(hr == E_POINTER, "got 0x%08x\n", hr);
891
892 ret = (BSTR)0xdeadbeef;
893 hr = IFileSystem3_BuildPath(fs3, NULL, NULL, &ret);
894 ok(hr == S_OK, "got 0x%08x\n", hr);
895 ok(*ret == 0, "got %p\n", ret);
896 SysFreeString(ret);
897
898 ret = (BSTR)0xdeadbeef;
899 path = bstr_from_str("path");
900 hr = IFileSystem3_BuildPath(fs3, path, NULL, &ret);
901 ok(hr == S_OK, "got 0x%08x\n", hr);
902 ok(!lstrcmpW(ret, path), "got %s\n", wine_dbgstr_w(ret));
903 SysFreeString(ret);
904 SysFreeString(path);
905
906 ret = (BSTR)0xdeadbeef;
907 path = bstr_from_str("path");
908 hr = IFileSystem3_BuildPath(fs3, NULL, path, &ret);
909 ok(hr == S_OK, "got 0x%08x\n", hr);
910 ok(!lstrcmpW(ret, path), "got %s\n", wine_dbgstr_w(ret));
911 SysFreeString(ret);
912 SysFreeString(path);
913
914 while (ptr->path)
915 {
916 BSTR name, result;
917
918 ret = NULL;
919 path = bstr_from_str(ptr->path);
920 name = bstr_from_str(ptr->name);
921 result = bstr_from_str(ptr->result);
922 hr = IFileSystem3_BuildPath(fs3, path, name, &ret);
923 ok(hr == S_OK, "%d: got 0x%08x\n", i, hr);
924 if (hr == S_OK)
925 {
926 ok(!lstrcmpW(ret, result), "%d: got wrong path %s, expected %s\n", i, wine_dbgstr_w(ret),
927 wine_dbgstr_w(result));
928 SysFreeString(ret);
929 }
930 SysFreeString(path);
931 SysFreeString(name);
932 SysFreeString(result);
933
934 i++;
935 ptr++;
936 }
937 }
938
939 static void test_GetFolder(void)
940 {
941 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
942 WCHAR buffW[MAX_PATH];
943 IFolder *folder;
944 HRESULT hr;
945 BSTR str;
946
947 folder = (void*)0xdeadbeef;
948 hr = IFileSystem3_GetFolder(fs3, NULL, &folder);
949 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
950 ok(folder == NULL, "got %p\n", folder);
951
952 hr = IFileSystem3_GetFolder(fs3, NULL, NULL);
953 ok(hr == E_POINTER, "got 0x%08x\n", hr);
954
955 /* something that doesn't exist */
956 str = SysAllocString(dummyW);
957
958 hr = IFileSystem3_GetFolder(fs3, str, NULL);
959 ok(hr == E_POINTER, "got 0x%08x\n", hr);
960
961 folder = (void*)0xdeadbeef;
962 hr = IFileSystem3_GetFolder(fs3, str, &folder);
963 ok(hr == CTL_E_PATHNOTFOUND, "got 0x%08x\n", hr);
964 ok(folder == NULL, "got %p\n", folder);
965 SysFreeString(str);
966
967 GetWindowsDirectoryW(buffW, MAX_PATH);
968 str = SysAllocString(buffW);
969 hr = IFileSystem3_GetFolder(fs3, str, &folder);
970 ok(hr == S_OK, "got 0x%08x\n", hr);
971 SysFreeString(str);
972 test_provideclassinfo(folder, &CLSID_Folder);
973 IFolder_Release(folder);
974 }
975
976 /* Please keep the tests for IFolderCollection and IFileCollection in sync */
977 static void test_FolderCollection(void)
978 {
979 static const WCHAR fooW[] = {'f','o','o',0};
980 static const WCHAR aW[] = {'\\','a',0};
981 static const WCHAR bW[] = {'\\','b',0};
982 static const WCHAR cW[] = {'\\','c',0};
983 IFolderCollection *folders;
984 WCHAR buffW[MAX_PATH], pathW[MAX_PATH];
985 IEnumVARIANT *enumvar, *clone;
986 LONG count, ref, ref2, i;
987 IUnknown *unk, *unk2;
988 IFolder *folder;
989 ULONG fetched;
990 VARIANT var, var2[2];
991 HRESULT hr;
992 BSTR str;
993 int found_a = 0, found_b = 0, found_c = 0;
994
995 get_temp_path(fooW, buffW);
996 CreateDirectoryW(buffW, NULL);
997
998 str = SysAllocString(buffW);
999 hr = IFileSystem3_GetFolder(fs3, str, &folder);
1000 ok(hr == S_OK, "got 0x%08x\n", hr);
1001 SysFreeString(str);
1002
1003 hr = IFolder_get_SubFolders(folder, NULL);
1004 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1005
1006 hr = IFolder_get_Path(folder, NULL);
1007 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1008
1009 hr = IFolder_get_Path(folder, &str);
1010 ok(hr == S_OK, "got 0x%08x\n", hr);
1011 ok(!lstrcmpiW(buffW, str), "got %s, expected %s\n", wine_dbgstr_w(str), wine_dbgstr_w(buffW));
1012 SysFreeString(str);
1013
1014 lstrcpyW(pathW, buffW);
1015 lstrcatW(pathW, aW);
1016 CreateDirectoryW(pathW, NULL);
1017
1018 lstrcpyW(pathW, buffW);
1019 lstrcatW(pathW, bW);
1020 CreateDirectoryW(pathW, NULL);
1021
1022 hr = IFolder_get_SubFolders(folder, &folders);
1023 ok(hr == S_OK, "got 0x%08x\n", hr);
1024 test_provideclassinfo(folders, &CLSID_Folders);
1025 IFolder_Release(folder);
1026
1027 count = 0;
1028 hr = IFolderCollection_get_Count(folders, &count);
1029 ok(hr == S_OK, "got 0x%08x\n", hr);
1030 ok(count == 2, "got %d\n", count);
1031
1032 lstrcpyW(pathW, buffW);
1033 lstrcatW(pathW, cW);
1034 CreateDirectoryW(pathW, NULL);
1035
1036 /* every time property is requested it scans directory */
1037 count = 0;
1038 hr = IFolderCollection_get_Count(folders, &count);
1039 ok(hr == S_OK, "got 0x%08x\n", hr);
1040 ok(count == 3, "got %d\n", count);
1041
1042 hr = IFolderCollection_get__NewEnum(folders, NULL);
1043 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1044
1045 hr = IFolderCollection_QueryInterface(folders, &IID_IEnumVARIANT, (void**)&unk);
1046 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1047
1048 /* NewEnum creates new instance each time it's called */
1049 ref = GET_REFCOUNT(folders);
1050
1051 unk = NULL;
1052 hr = IFolderCollection_get__NewEnum(folders, &unk);
1053 ok(hr == S_OK, "got 0x%08x\n", hr);
1054
1055 ref2 = GET_REFCOUNT(folders);
1056 ok(ref2 == ref + 1, "got %d, %d\n", ref2, ref);
1057
1058 unk2 = NULL;
1059 hr = IFolderCollection_get__NewEnum(folders, &unk2);
1060 ok(hr == S_OK, "got 0x%08x\n", hr);
1061 ok(unk != unk2, "got %p, %p\n", unk2, unk);
1062 IUnknown_Release(unk2);
1063
1064 /* now get IEnumVARIANT */
1065 ref = GET_REFCOUNT(folders);
1066 hr = IUnknown_QueryInterface(unk, &IID_IEnumVARIANT, (void**)&enumvar);
1067 ok(hr == S_OK, "got 0x%08x\n", hr);
1068 ref2 = GET_REFCOUNT(folders);
1069 ok(ref2 == ref, "got %d, %d\n", ref2, ref);
1070
1071 /* clone enumerator */
1072 hr = IEnumVARIANT_Clone(enumvar, &clone);
1073 ok(hr == S_OK, "got 0x%08x\n", hr);
1074 ok(clone != enumvar, "got %p, %p\n", enumvar, clone);
1075 IEnumVARIANT_Release(clone);
1076
1077 hr = IEnumVARIANT_Reset(enumvar);
1078 ok(hr == S_OK, "got 0x%08x\n", hr);
1079
1080 for (i = 0; i < 3; i++)
1081 {
1082 VariantInit(&var);
1083 fetched = 0;
1084 hr = IEnumVARIANT_Next(enumvar, 1, &var, &fetched);
1085 ok(hr == S_OK, "%d: got 0x%08x\n", i, hr);
1086 ok(fetched == 1, "%d: got %d\n", i, fetched);
1087 ok(V_VT(&var) == VT_DISPATCH, "%d: got type %d\n", i, V_VT(&var));
1088
1089 hr = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IFolder, (void**)&folder);
1090 ok(hr == S_OK, "got 0x%08x\n", hr);
1091
1092 str = NULL;
1093 hr = IFolder_get_Name(folder, &str);
1094 ok(hr == S_OK, "got 0x%08x\n", hr);
1095 if (!lstrcmpW(str, aW + 1))
1096 found_a++;
1097 else if (!lstrcmpW(str, bW + 1))
1098 found_b++;
1099 else if (!lstrcmpW(str, cW + 1))
1100 found_c++;
1101 else
1102 ok(0, "unexpected folder %s was found\n", wine_dbgstr_w(str));
1103 SysFreeString(str);
1104
1105 IFolder_Release(folder);
1106 VariantClear(&var);
1107 }
1108
1109 ok(found_a == 1 && found_b == 1 && found_c == 1,
1110 "each folder should be found 1 time instead of %d/%d/%d\n",
1111 found_a, found_b, found_c);
1112
1113 VariantInit(&var);
1114 fetched = -1;
1115 hr = IEnumVARIANT_Next(enumvar, 1, &var, &fetched);
1116 ok(hr == S_FALSE, "got 0x%08x\n", hr);
1117 ok(fetched == 0, "got %d\n", fetched);
1118
1119 hr = IEnumVARIANT_Reset(enumvar);
1120 ok(hr == S_OK, "got 0x%08x\n", hr);
1121 hr = IEnumVARIANT_Skip(enumvar, 2);
1122 ok(hr == S_OK, "got 0x%08x\n", hr);
1123 hr = IEnumVARIANT_Skip(enumvar, 0);
1124 ok(hr == S_OK, "got 0x%08x\n", hr);
1125
1126 VariantInit(&var2[0]);
1127 VariantInit(&var2[1]);
1128 fetched = -1;
1129 hr = IEnumVARIANT_Next(enumvar, 0, var2, &fetched);
1130 ok(hr == S_OK, "got 0x%08x\n", hr);
1131 ok(fetched == 0, "got %d\n", fetched);
1132 fetched = -1;
1133 hr = IEnumVARIANT_Next(enumvar, 2, var2, &fetched);
1134 ok(hr == S_FALSE, "got 0x%08x\n", hr);
1135 ok(fetched == 1, "got %d\n", fetched);
1136 ok(V_VT(&var2[0]) == VT_DISPATCH, "got type %d\n", V_VT(&var2[0]));
1137 VariantClear(&var2[0]);
1138 VariantClear(&var2[1]);
1139
1140 IEnumVARIANT_Release(enumvar);
1141 IUnknown_Release(unk);
1142
1143 lstrcpyW(pathW, buffW);
1144 lstrcatW(pathW, aW);
1145 RemoveDirectoryW(pathW);
1146 lstrcpyW(pathW, buffW);
1147 lstrcatW(pathW, bW);
1148 RemoveDirectoryW(pathW);
1149 lstrcpyW(pathW, buffW);
1150 lstrcatW(pathW, cW);
1151 RemoveDirectoryW(pathW);
1152 RemoveDirectoryW(buffW);
1153
1154 IFolderCollection_Release(folders);
1155 }
1156
1157 /* Please keep the tests for IFolderCollection and IFileCollection in sync */
1158 static void test_FileCollection(void)
1159 {
1160 static const WCHAR fooW[] = {'\\','f','o','o',0};
1161 static const WCHAR aW[] = {'\\','a',0};
1162 static const WCHAR bW[] = {'\\','b',0};
1163 static const WCHAR cW[] = {'\\','c',0};
1164 WCHAR buffW[MAX_PATH], pathW[MAX_PATH];
1165 IFolder *folder;
1166 IFileCollection *files;
1167 IFile *file;
1168 IEnumVARIANT *enumvar, *clone;
1169 LONG count, ref, ref2, i;
1170 IUnknown *unk, *unk2;
1171 ULONG fetched;
1172 VARIANT var, var2[2];
1173 HRESULT hr;
1174 BSTR str;
1175 HANDLE file_a, file_b, file_c;
1176 int found_a = 0, found_b = 0, found_c = 0;
1177
1178 get_temp_path(fooW, buffW);
1179 CreateDirectoryW(buffW, NULL);
1180
1181 str = SysAllocString(buffW);
1182 hr = IFileSystem3_GetFolder(fs3, str, &folder);
1183 ok(hr == S_OK, "got 0x%08x\n", hr);
1184 SysFreeString(str);
1185
1186 hr = IFolder_get_Files(folder, NULL);
1187 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1188
1189 lstrcpyW(pathW, buffW);
1190 lstrcatW(pathW, aW);
1191 file_a = CreateFileW(pathW, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1192 FILE_FLAG_DELETE_ON_CLOSE, 0);
1193 lstrcpyW(pathW, buffW);
1194 lstrcatW(pathW, bW);
1195 file_b = CreateFileW(pathW, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1196 FILE_FLAG_DELETE_ON_CLOSE, 0);
1197
1198 hr = IFolder_get_Files(folder, &files);
1199 ok(hr == S_OK, "got 0x%08x\n", hr);
1200 test_provideclassinfo(files, &CLSID_Files);
1201 IFolder_Release(folder);
1202
1203 count = 0;
1204 hr = IFileCollection_get_Count(files, &count);
1205 ok(hr == S_OK, "got 0x%08x\n", hr);
1206 ok(count == 2, "got %d\n", count);
1207
1208 lstrcpyW(pathW, buffW);
1209 lstrcatW(pathW, cW);
1210 file_c = CreateFileW(pathW, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
1211 FILE_FLAG_DELETE_ON_CLOSE, 0);
1212
1213 /* every time property is requested it scans directory */
1214 count = 0;
1215 hr = IFileCollection_get_Count(files, &count);
1216 ok(hr == S_OK, "got 0x%08x\n", hr);
1217 ok(count == 3, "got %d\n", count);
1218
1219 hr = IFileCollection_get__NewEnum(files, NULL);
1220 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1221
1222 hr = IFileCollection_QueryInterface(files, &IID_IEnumVARIANT, (void**)&unk);
1223 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1224
1225 /* NewEnum creates new instance each time it's called */
1226 ref = GET_REFCOUNT(files);
1227
1228 unk = NULL;
1229 hr = IFileCollection_get__NewEnum(files, &unk);
1230 ok(hr == S_OK, "got 0x%08x\n", hr);
1231
1232 ref2 = GET_REFCOUNT(files);
1233 ok(ref2 == ref + 1, "got %d, %d\n", ref2, ref);
1234
1235 unk2 = NULL;
1236 hr = IFileCollection_get__NewEnum(files, &unk2);
1237 ok(hr == S_OK, "got 0x%08x\n", hr);
1238 ok(unk != unk2, "got %p, %p\n", unk2, unk);
1239 IUnknown_Release(unk2);
1240
1241 /* now get IEnumVARIANT */
1242 ref = GET_REFCOUNT(files);
1243 hr = IUnknown_QueryInterface(unk, &IID_IEnumVARIANT, (void**)&enumvar);
1244 ok(hr == S_OK, "got 0x%08x\n", hr);
1245 ref2 = GET_REFCOUNT(files);
1246 ok(ref2 == ref, "got %d, %d\n", ref2, ref);
1247
1248 /* clone enumerator */
1249 hr = IEnumVARIANT_Clone(enumvar, &clone);
1250 ok(hr == S_OK, "got 0x%08x\n", hr);
1251 ok(clone != enumvar, "got %p, %p\n", enumvar, clone);
1252 IEnumVARIANT_Release(clone);
1253
1254 hr = IEnumVARIANT_Reset(enumvar);
1255 ok(hr == S_OK, "got 0x%08x\n", hr);
1256
1257 for (i = 0; i < 3; i++)
1258 {
1259 VariantInit(&var);
1260 fetched = 0;
1261 hr = IEnumVARIANT_Next(enumvar, 1, &var, &fetched);
1262 ok(hr == S_OK, "%d: got 0x%08x\n", i, hr);
1263 ok(fetched == 1, "%d: got %d\n", i, fetched);
1264 ok(V_VT(&var) == VT_DISPATCH, "%d: got type %d\n", i, V_VT(&var));
1265
1266 hr = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IFile, (void **)&file);
1267 ok(hr == S_OK, "got 0x%08x\n", hr);
1268 test_provideclassinfo(file, &CLSID_File);
1269
1270 str = NULL;
1271 hr = IFile_get_Name(file, &str);
1272 ok(hr == S_OK, "got 0x%08x\n", hr);
1273 if (!lstrcmpW(str, aW + 1))
1274 found_a++;
1275 else if (!lstrcmpW(str, bW + 1))
1276 found_b++;
1277 else if (!lstrcmpW(str, cW + 1))
1278 found_c++;
1279 else
1280 ok(0, "unexpected file %s was found\n", wine_dbgstr_w(str));
1281 SysFreeString(str);
1282
1283 IFile_Release(file);
1284 VariantClear(&var);
1285 }
1286
1287 ok(found_a == 1 && found_b == 1 && found_c == 1,
1288 "each file should be found 1 time instead of %d/%d/%d\n",
1289 found_a, found_b, found_c);
1290
1291 VariantInit(&var);
1292 fetched = -1;
1293 hr = IEnumVARIANT_Next(enumvar, 1, &var, &fetched);
1294 ok(hr == S_FALSE, "got 0x%08x\n", hr);
1295 ok(fetched == 0, "got %d\n", fetched);
1296
1297 hr = IEnumVARIANT_Reset(enumvar);
1298 ok(hr == S_OK, "got 0x%08x\n", hr);
1299 hr = IEnumVARIANT_Skip(enumvar, 2);
1300 ok(hr == S_OK, "got 0x%08x\n", hr);
1301 hr = IEnumVARIANT_Skip(enumvar, 0);
1302 ok(hr == S_OK, "got 0x%08x\n", hr);
1303
1304 VariantInit(&var2[0]);
1305 VariantInit(&var2[1]);
1306 fetched = -1;
1307 hr = IEnumVARIANT_Next(enumvar, 0, var2, &fetched);
1308 ok(hr == S_OK, "got 0x%08x\n", hr);
1309 ok(fetched == 0, "got %d\n", fetched);
1310 fetched = -1;
1311 hr = IEnumVARIANT_Next(enumvar, 2, var2, &fetched);
1312 ok(hr == S_FALSE, "got 0x%08x\n", hr);
1313 ok(fetched == 1, "got %d\n", fetched);
1314 ok(V_VT(&var2[0]) == VT_DISPATCH, "got type %d\n", V_VT(&var2[0]));
1315 VariantClear(&var2[0]);
1316 VariantClear(&var2[1]);
1317
1318 IEnumVARIANT_Release(enumvar);
1319 IUnknown_Release(unk);
1320
1321 CloseHandle(file_a);
1322 CloseHandle(file_b);
1323 CloseHandle(file_c);
1324 RemoveDirectoryW(buffW);
1325
1326 IFileCollection_Release(files);
1327 }
1328
1329 static void test_DriveCollection(void)
1330 {
1331 IDriveCollection *drives;
1332 IEnumVARIANT *enumvar;
1333 ULONG fetched;
1334 VARIANT var;
1335 HRESULT hr;
1336 LONG count;
1337
1338 hr = IFileSystem3_get_Drives(fs3, &drives);
1339 ok(hr == S_OK, "got 0x%08x\n", hr);
1340
1341 test_provideclassinfo(drives, &CLSID_Drives);
1342
1343 hr = IDriveCollection_get__NewEnum(drives, (IUnknown**)&enumvar);
1344 ok(hr == S_OK, "got 0x%08x\n", hr);
1345
1346 hr = IDriveCollection_get_Count(drives, NULL);
1347 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1348
1349 count = 0;
1350 hr = IDriveCollection_get_Count(drives, &count);
1351 ok(hr == S_OK, "got 0x%08x\n", hr);
1352 ok(count > 0, "got %d\n", count);
1353
1354 V_VT(&var) = VT_EMPTY;
1355 fetched = -1;
1356 hr = IEnumVARIANT_Next(enumvar, 0, &var, &fetched);
1357 ok(hr == S_OK, "got 0x%08x\n", hr);
1358 ok(fetched == 0, "got %d\n", fetched);
1359
1360 hr = IEnumVARIANT_Skip(enumvar, 0);
1361 ok(hr == S_OK, "got 0x%08x\n", hr);
1362
1363 hr = IEnumVARIANT_Skip(enumvar, count);
1364 ok(hr == S_OK, "got 0x%08x\n", hr);
1365
1366 hr = IEnumVARIANT_Skip(enumvar, 1);
1367 ok(hr == S_FALSE, "got 0x%08x\n", hr);
1368
1369 /* reset and iterate again */
1370 hr = IEnumVARIANT_Reset(enumvar);
1371 ok(hr == S_OK, "got 0x%08x\n", hr);
1372
1373 while (IEnumVARIANT_Next(enumvar, 1, &var, &fetched) == S_OK) {
1374 IDrive *drive = (IDrive*)V_DISPATCH(&var);
1375 DriveTypeConst type;
1376 BSTR str;
1377
1378 hr = IDrive_get_DriveType(drive, &type);
1379 ok(hr == S_OK, "got 0x%08x\n", hr);
1380
1381 hr = IDrive_get_DriveLetter(drive, NULL);
1382 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1383
1384 hr = IDrive_get_DriveLetter(drive, &str);
1385 ok(hr == S_OK, "got 0x%08x\n", hr);
1386 ok(SysStringLen(str) == 1, "got string %s\n", wine_dbgstr_w(str));
1387 SysFreeString(str);
1388
1389 hr = IDrive_get_IsReady(drive, NULL);
1390 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1391
1392 hr = IDrive_get_TotalSize(drive, NULL);
1393 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1394
1395 hr = IDrive_get_AvailableSpace(drive, NULL);
1396 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1397
1398 hr = IDrive_get_FreeSpace(drive, NULL);
1399 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1400
1401 if (type == Fixed) {
1402 VARIANT_BOOL ready = VARIANT_FALSE;
1403 VARIANT size;
1404
1405 hr = IDrive_get_IsReady(drive, &ready);
1406 ok(hr == S_OK, "got 0x%08x\n", hr);
1407 ok(ready == VARIANT_TRUE, "got %x\n", ready);
1408
1409 if (ready != VARIANT_TRUE) {
1410 hr = IDrive_get_DriveLetter(drive, &str);
1411 ok(hr == S_OK, "got 0x%08x\n", hr);
1412
1413 skip("Drive %s is not ready, skipping some tests\n", wine_dbgstr_w(str));
1414
1415 VariantClear(&var);
1416 SysFreeString(str);
1417 continue;
1418 }
1419
1420 V_VT(&size) = VT_EMPTY;
1421 hr = IDrive_get_TotalSize(drive, &size);
1422 ok(hr == S_OK, "got 0x%08x\n", hr);
1423 ok(V_VT(&size) == VT_R8 || V_VT(&size) == VT_I4, "got %d\n", V_VT(&size));
1424 if (V_VT(&size) == VT_R8)
1425 ok(V_R8(&size) > 0, "got %f\n", V_R8(&size));
1426 else
1427 ok(V_I4(&size) > 0, "got %d\n", V_I4(&size));
1428
1429 V_VT(&size) = VT_EMPTY;
1430 hr = IDrive_get_AvailableSpace(drive, &size);
1431 ok(hr == S_OK, "got 0x%08x\n", hr);
1432 ok(V_VT(&size) == VT_R8 || V_VT(&size) == VT_I4, "got %d\n", V_VT(&size));
1433 if (V_VT(&size) == VT_R8)
1434 ok(V_R8(&size) > (double)INT_MAX, "got %f\n", V_R8(&size));
1435 else
1436 ok(V_I4(&size) > 0, "got %d\n", V_I4(&size));
1437
1438 V_VT(&size) = VT_EMPTY;
1439 hr = IDrive_get_FreeSpace(drive, &size);
1440 ok(hr == S_OK, "got 0x%08x\n", hr);
1441 ok(V_VT(&size) == VT_R8 || V_VT(&size) == VT_I4, "got %d\n", V_VT(&size));
1442 if (V_VT(&size) == VT_R8)
1443 ok(V_R8(&size) > 0, "got %f\n", V_R8(&size));
1444 else
1445 ok(V_I4(&size) > 0, "got %d\n", V_I4(&size));
1446 }
1447 VariantClear(&var);
1448 }
1449
1450 IEnumVARIANT_Release(enumvar);
1451 IDriveCollection_Release(drives);
1452 }
1453
1454 static void test_CreateTextFile(void)
1455 {
1456 static const WCHAR scrrunW[] = {'s','c','r','r','u','n','\\',0};
1457 static const WCHAR testfileW[] = {'t','e','s','t','.','t','x','t',0};
1458 WCHAR pathW[MAX_PATH], dirW[MAX_PATH], buffW[10];
1459 ITextStream *stream;
1460 BSTR nameW, str;
1461 HANDLE file;
1462 HRESULT hr;
1463 BOOL ret;
1464
1465 GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
1466 lstrcatW(pathW, scrrunW);
1467 lstrcpyW(dirW, pathW);
1468 lstrcatW(pathW, testfileW);
1469
1470 /* dir doesn't exist */
1471 nameW = SysAllocString(pathW);
1472 hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_FALSE, VARIANT_FALSE, &stream);
1473 ok(hr == CTL_E_PATHNOTFOUND, "got 0x%08x\n", hr);
1474
1475 ret = CreateDirectoryW(dirW, NULL);
1476 ok(ret, "got %d, %d\n", ret, GetLastError());
1477
1478 hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_FALSE, VARIANT_FALSE, &stream);
1479 ok(hr == S_OK, "got 0x%08x\n", hr);
1480
1481 test_provideclassinfo(stream, &CLSID_TextStream);
1482
1483 hr = ITextStream_Read(stream, 1, &str);
1484 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
1485
1486 hr = ITextStream_Close(stream);
1487 ok(hr == S_OK, "got 0x%08x\n", hr);
1488
1489 hr = ITextStream_Read(stream, 1, &str);
1490 ok(hr == CTL_E_BADFILEMODE || hr == E_VAR_NOT_SET, "got 0x%08x\n", hr);
1491
1492 hr = ITextStream_Close(stream);
1493 ok(hr == S_FALSE || hr == E_VAR_NOT_SET, "got 0x%08x\n", hr);
1494
1495 ITextStream_Release(stream);
1496
1497 /* check it's created */
1498 file = CreateFileW(pathW, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1499 ok(file != INVALID_HANDLE_VALUE, "got %p\n", file);
1500 CloseHandle(file);
1501
1502 /* try to create again with no-overwrite mode */
1503 hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_FALSE, VARIANT_FALSE, &stream);
1504 ok(hr == CTL_E_FILEALREADYEXISTS, "got 0x%08x\n", hr);
1505
1506 /* now overwrite */
1507 hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_TRUE, VARIANT_FALSE, &stream);
1508 ok(hr == S_OK, "got 0x%08x\n", hr);
1509 ITextStream_Release(stream);
1510
1511 /* overwrite in Unicode mode, check for BOM */
1512 hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_TRUE, VARIANT_TRUE, &stream);
1513 ok(hr == S_OK, "got 0x%08x\n", hr);
1514 ITextStream_Release(stream);
1515
1516 /* File was created in Unicode mode, it contains 0xfffe BOM. Opening it in non-Unicode mode
1517 treats BOM like a valuable data with appropriate CP_ACP -> WCHAR conversion. */
1518 buffW[0] = 0;
1519 MultiByteToWideChar(CP_ACP, 0, utf16bom, -1, buffW, sizeof(buffW)/sizeof(WCHAR));
1520
1521 hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateFalse, &stream);
1522 ok(hr == S_OK, "got 0x%08x\n", hr);
1523 hr = ITextStream_ReadAll(stream, &str);
1524 ok(hr == S_FALSE || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr);
1525 ok(!lstrcmpW(str, buffW), "got %s, expected %s\n", wine_dbgstr_w(str), wine_dbgstr_w(buffW));
1526 SysFreeString(str);
1527 ITextStream_Release(stream);
1528
1529 DeleteFileW(nameW);
1530 RemoveDirectoryW(dirW);
1531 SysFreeString(nameW);
1532 }
1533
1534 static void test_WriteLine(void)
1535 {
1536 static const WCHAR scrrunW[] = {'s','c','r','r','u','n','\\',0};
1537 static const WCHAR testfileW[] = {'t','e','s','t','.','t','x','t',0};
1538 WCHAR pathW[MAX_PATH], dirW[MAX_PATH];
1539 WCHAR buffW[MAX_PATH], buff2W[MAX_PATH];
1540 char buffA[MAX_PATH];
1541 ITextStream *stream;
1542 DWORD r, len;
1543 HANDLE file;
1544 BSTR nameW;
1545 HRESULT hr;
1546 BOOL ret;
1547
1548 GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
1549 lstrcatW(pathW, scrrunW);
1550 lstrcpyW(dirW, pathW);
1551 lstrcatW(pathW, testfileW);
1552
1553 ret = CreateDirectoryW(dirW, NULL);
1554 ok(ret, "got %d, %d\n", ret, GetLastError());
1555
1556 /* create as ASCII file first */
1557 nameW = SysAllocString(pathW);
1558 hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_FALSE, VARIANT_FALSE, &stream);
1559 ok(hr == S_OK, "got 0x%08x\n", hr);
1560
1561 hr = ITextStream_WriteLine(stream, nameW);
1562 ok(hr == S_OK, "got 0x%08x\n", hr);
1563 ITextStream_Release(stream);
1564
1565 /* check contents */
1566 file = CreateFileW(pathW, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1567 ok(file != INVALID_HANDLE_VALUE, "got %p\n", file);
1568 r = 0;
1569 ret = ReadFile(file, buffA, sizeof(buffA), &r, NULL);
1570 ok(ret && r, "read %d, got %d, %d\n", r, ret, GetLastError());
1571
1572 len = MultiByteToWideChar(CP_ACP, 0, buffA, r, buffW, sizeof(buffW)/sizeof(WCHAR));
1573 buffW[len] = 0;
1574 lstrcpyW(buff2W, nameW);
1575 lstrcatW(buff2W, crlfW);
1576 ok(!lstrcmpW(buff2W, buffW), "got %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(buff2W));
1577 CloseHandle(file);
1578 DeleteFileW(nameW);
1579
1580 /* same for unicode file */
1581 hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_FALSE, VARIANT_TRUE, &stream);
1582 ok(hr == S_OK, "got 0x%08x\n", hr);
1583
1584 hr = ITextStream_WriteLine(stream, nameW);
1585 ok(hr == S_OK, "got 0x%08x\n", hr);
1586 ITextStream_Release(stream);
1587
1588 /* check contents */
1589 file = CreateFileW(pathW, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1590 ok(file != INVALID_HANDLE_VALUE, "got %p\n", file);
1591 r = 0;
1592 ret = ReadFile(file, buffW, sizeof(buffW), &r, NULL);
1593 ok(ret && r, "read %d, got %d, %d\n", r, ret, GetLastError());
1594 buffW[r/sizeof(WCHAR)] = 0;
1595
1596 buff2W[0] = 0xfeff;
1597 buff2W[1] = 0;
1598 lstrcatW(buff2W, nameW);
1599 lstrcatW(buff2W, crlfW);
1600 ok(!lstrcmpW(buff2W, buffW), "got %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(buff2W));
1601 CloseHandle(file);
1602 DeleteFileW(nameW);
1603
1604 RemoveDirectoryW(dirW);
1605 SysFreeString(nameW);
1606 }
1607
1608 static void test_ReadAll(void)
1609 {
1610 static const WCHAR scrrunW[] = {'s','c','r','r','u','n','\\',0};
1611 static const WCHAR testfileW[] = {'t','e','s','t','.','t','x','t',0};
1612 static const WCHAR secondlineW[] = {'s','e','c','o','n','d',0};
1613 static const WCHAR aW[] = {'A',0};
1614 WCHAR pathW[MAX_PATH], dirW[MAX_PATH], buffW[500];
1615 ITextStream *stream;
1616 BSTR nameW;
1617 HRESULT hr;
1618 BOOL ret;
1619 BSTR str;
1620
1621 GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
1622 lstrcatW(pathW, scrrunW);
1623 lstrcpyW(dirW, pathW);
1624 lstrcatW(pathW, testfileW);
1625
1626 ret = CreateDirectoryW(dirW, NULL);
1627 ok(ret, "got %d, %d\n", ret, GetLastError());
1628
1629 /* Unicode file -> read with ascii stream */
1630 nameW = SysAllocString(pathW);
1631 hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_FALSE, VARIANT_TRUE, &stream);
1632 ok(hr == S_OK, "got 0x%08x\n", hr);
1633
1634 hr = ITextStream_WriteLine(stream, nameW);
1635 ok(hr == S_OK, "got 0x%08x\n", hr);
1636
1637 str = SysAllocString(secondlineW);
1638 hr = ITextStream_WriteLine(stream, str);
1639 ok(hr == S_OK, "got 0x%08x\n", hr);
1640 SysFreeString(str);
1641
1642 hr = ITextStream_ReadAll(stream, NULL);
1643 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1644
1645 str = (void*)0xdeadbeef;
1646 hr = ITextStream_ReadAll(stream, &str);
1647 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
1648 ok(str == NULL || broken(str == (void*)0xdeadbeef) /* win2k */, "got %p\n", str);
1649
1650 ITextStream_Release(stream);
1651
1652 hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateFalse, &stream);
1653 ok(hr == S_OK, "got 0x%08x\n", hr);
1654
1655 hr = ITextStream_ReadAll(stream, NULL);
1656 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1657
1658 /* Buffer content is not interpreted - BOM is kept, all data is converted to WCHARs */
1659 str = NULL;
1660 hr = ITextStream_ReadAll(stream, &str);
1661 ok(hr == S_FALSE || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr);
1662 buffW[0] = 0;
1663 MultiByteToWideChar(CP_ACP, 0, utf16bom, -1, buffW, sizeof(buffW)/sizeof(WCHAR));
1664 ok(str[0] == buffW[0] && str[1] == buffW[1], "got %s, %d\n", wine_dbgstr_w(str), SysStringLen(str));
1665 SysFreeString(str);
1666 ITextStream_Release(stream);
1667
1668 /* Unicode file -> read with unicode stream */
1669 hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateTrue, &stream);
1670 ok(hr == S_OK, "got 0x%08x\n", hr);
1671
1672 lstrcpyW(buffW, nameW);
1673 lstrcatW(buffW, crlfW);
1674 lstrcatW(buffW, secondlineW);
1675 lstrcatW(buffW, crlfW);
1676 str = NULL;
1677 hr = ITextStream_ReadAll(stream, &str);
1678 ok(hr == S_FALSE || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr);
1679 ok(!lstrcmpW(buffW, str), "got %s\n", wine_dbgstr_w(str));
1680 SysFreeString(str);
1681
1682 /* ReadAll one more time */
1683 str = (void*)0xdeadbeef;
1684 hr = ITextStream_ReadAll(stream, &str);
1685 ok(hr == CTL_E_ENDOFFILE, "got 0x%08x\n", hr);
1686 ok(str == NULL || broken(str == (void*)0xdeadbeef) /* win2k */, "got %p\n", str);
1687
1688 /* ReadLine fails the same way */
1689 str = (void*)0xdeadbeef;
1690 hr = ITextStream_ReadLine(stream, &str);
1691 ok(hr == CTL_E_ENDOFFILE, "got 0x%08x\n", hr);
1692 ok(str == NULL || broken(str == (void*)0xdeadbeef) /* win2k */, "got %p\n", str);
1693 ITextStream_Release(stream);
1694
1695 /* Open again and skip first line before ReadAll */
1696 hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateTrue, &stream);
1697 ok(hr == S_OK, "got 0x%08x\n", hr);
1698
1699 str = NULL;
1700 hr = ITextStream_ReadLine(stream, &str);
1701 todo_wine {
1702 ok(hr == S_OK, "got 0x%08x\n", hr);
1703 ok(str != NULL, "got %p\n", str);
1704 }
1705 SysFreeString(str);
1706
1707 lstrcpyW(buffW, secondlineW);
1708 lstrcatW(buffW, crlfW);
1709 str = NULL;
1710 hr = ITextStream_ReadAll(stream, &str);
1711 ok(hr == S_FALSE || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr);
1712 todo_wine
1713 ok(!lstrcmpW(buffW, str), "got %s\n", wine_dbgstr_w(str));
1714 SysFreeString(str);
1715 ITextStream_Release(stream);
1716
1717 /* ASCII file, read with Unicode stream */
1718 /* 1. one byte content, not enough for Unicode read */
1719 hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_TRUE, VARIANT_FALSE, &stream);
1720 ok(hr == S_OK, "got 0x%08x\n", hr);
1721 str = SysAllocString(aW);
1722 hr = ITextStream_Write(stream, str);
1723 ok(hr == S_OK, "got 0x%08x\n", hr);
1724 SysFreeString(str);
1725 ITextStream_Release(stream);
1726
1727 hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateTrue, &stream);
1728 ok(hr == S_OK, "got 0x%08x\n", hr);
1729
1730 str = (void*)0xdeadbeef;
1731 hr = ITextStream_ReadAll(stream, &str);
1732 ok(hr == CTL_E_ENDOFFILE, "got 0x%08x\n", hr);
1733 ok(str == NULL || broken(str == (void*)0xdeadbeef) /* win2k */, "got %p\n", str);
1734
1735 ITextStream_Release(stream);
1736
1737 DeleteFileW(nameW);
1738 RemoveDirectoryW(dirW);
1739 SysFreeString(nameW);
1740 }
1741
1742 static void test_Read(void)
1743 {
1744 static const WCHAR scrrunW[] = {'s','c','r','r','u','n','\\',0};
1745 static const WCHAR testfileW[] = {'t','e','s','t','.','t','x','t',0};
1746 static const WCHAR secondlineW[] = {'s','e','c','o','n','d',0};
1747 static const WCHAR aW[] = {'A',0};
1748 WCHAR pathW[MAX_PATH], dirW[MAX_PATH], buffW[500];
1749 ITextStream *stream;
1750 BSTR nameW;
1751 HRESULT hr;
1752 BOOL ret;
1753 BSTR str;
1754
1755 GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
1756 lstrcatW(pathW, scrrunW);
1757 lstrcpyW(dirW, pathW);
1758 lstrcatW(pathW, testfileW);
1759
1760 ret = CreateDirectoryW(dirW, NULL);
1761 ok(ret, "got %d, %d\n", ret, GetLastError());
1762
1763 /* Unicode file -> read with ascii stream */
1764 nameW = SysAllocString(pathW);
1765 hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_FALSE, VARIANT_TRUE, &stream);
1766 ok(hr == S_OK, "got 0x%08x\n", hr);
1767
1768 hr = ITextStream_WriteLine(stream, nameW);
1769 ok(hr == S_OK, "got 0x%08x\n", hr);
1770
1771 str = SysAllocString(secondlineW);
1772 hr = ITextStream_WriteLine(stream, str);
1773 ok(hr == S_OK, "got 0x%08x\n", hr);
1774 SysFreeString(str);
1775
1776 hr = ITextStream_Read(stream, 0, NULL);
1777 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1778
1779 hr = ITextStream_Read(stream, 1, NULL);
1780 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1781
1782 hr = ITextStream_Read(stream, -1, NULL);
1783 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1784
1785 str = (void*)0xdeadbeef;
1786 hr = ITextStream_Read(stream, 1, &str);
1787 ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr);
1788 ok(str == NULL, "got %p\n", str);
1789
1790 ITextStream_Release(stream);
1791
1792 hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateFalse, &stream);
1793 ok(hr == S_OK, "got 0x%08x\n", hr);
1794
1795 hr = ITextStream_Read(stream, 1, NULL);
1796 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1797
1798 str = (void*)0xdeadbeef;
1799 hr = ITextStream_Read(stream, -1, &str);
1800 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1801 ok(str == NULL, "got %p\n", str);
1802
1803 str = (void*)0xdeadbeef;
1804 hr = ITextStream_Read(stream, 0, &str);
1805 ok(hr == S_OK, "got 0x%08x\n", hr);
1806 ok(str == NULL, "got %p\n", str);
1807
1808 /* Buffer content is not interpreted - BOM is kept, all data is converted to WCHARs */
1809 str = NULL;
1810 hr = ITextStream_Read(stream, 2, &str);
1811 ok(hr == S_OK, "got 0x%08x\n", hr);
1812
1813 buffW[0] = 0;
1814 MultiByteToWideChar(CP_ACP, 0, utf16bom, -1, buffW, sizeof(buffW)/sizeof(WCHAR));
1815
1816 ok(!lstrcmpW(str, buffW), "got %s, expected %s\n", wine_dbgstr_w(str), wine_dbgstr_w(buffW));
1817 ok(SysStringLen(str) == 2, "got %d\n", SysStringLen(str));
1818 SysFreeString(str);
1819 ITextStream_Release(stream);
1820
1821 /* Unicode file -> read with unicode stream */
1822 hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateTrue, &stream);
1823 ok(hr == S_OK, "got 0x%08x\n", hr);
1824
1825 lstrcpyW(buffW, nameW);
1826 lstrcatW(buffW, crlfW);
1827 lstrcatW(buffW, secondlineW);
1828 lstrcatW(buffW, crlfW);
1829 str = NULL;
1830 hr = ITextStream_Read(stream, 500, &str);
1831 ok(hr == S_FALSE || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr);
1832 ok(!lstrcmpW(buffW, str), "got %s\n", wine_dbgstr_w(str));
1833 SysFreeString(str);
1834
1835 /* ReadAll one more time */
1836 str = (void*)0xdeadbeef;
1837 hr = ITextStream_Read(stream, 10, &str);
1838 ok(hr == CTL_E_ENDOFFILE, "got 0x%08x\n", hr);
1839 ok(str == NULL, "got %p\n", str);
1840
1841 /* ReadLine fails the same way */
1842 str = (void*)0xdeadbeef;
1843 hr = ITextStream_ReadLine(stream, &str);
1844 ok(hr == CTL_E_ENDOFFILE, "got 0x%08x\n", hr);
1845 ok(str == NULL || broken(str == (void*)0xdeadbeef), "got %p\n", str);
1846 ITextStream_Release(stream);
1847
1848 /* Open again and skip first line before ReadAll */
1849 hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateTrue, &stream);
1850 ok(hr == S_OK, "got 0x%08x\n", hr);
1851
1852 str = NULL;
1853 hr = ITextStream_ReadLine(stream, &str);
1854 todo_wine {
1855 ok(hr == S_OK, "got 0x%08x\n", hr);
1856 ok(str != NULL, "got %p\n", str);
1857 }
1858 SysFreeString(str);
1859
1860 lstrcpyW(buffW, secondlineW);
1861 lstrcatW(buffW, crlfW);
1862 str = NULL;
1863 hr = ITextStream_Read(stream, 100, &str);
1864 ok(hr == S_FALSE || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr);
1865 todo_wine
1866 ok(!lstrcmpW(buffW, str), "got %s\n", wine_dbgstr_w(str));
1867 SysFreeString(str);
1868 ITextStream_Release(stream);
1869
1870 /* ASCII file, read with Unicode stream */
1871 /* 1. one byte content, not enough for Unicode read */
1872 hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_TRUE, VARIANT_FALSE, &stream);
1873 ok(hr == S_OK, "got 0x%08x\n", hr);
1874 str = SysAllocString(aW);
1875 hr = ITextStream_Write(stream, str);
1876 ok(hr == S_OK, "got 0x%08x\n", hr);
1877 SysFreeString(str);
1878 ITextStream_Release(stream);
1879
1880 hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateTrue, &stream);
1881 ok(hr == S_OK, "got 0x%08x\n", hr);
1882
1883 str = (void*)0xdeadbeef;
1884 hr = ITextStream_Read(stream, 500, &str);
1885 ok(hr == CTL_E_ENDOFFILE, "got 0x%08x\n", hr);
1886 ok(str == NULL, "got %p\n", str);
1887
1888 ITextStream_Release(stream);
1889
1890 DeleteFileW(nameW);
1891 RemoveDirectoryW(dirW);
1892 SysFreeString(nameW);
1893 }
1894
1895 struct driveexists_test {
1896 const WCHAR drivespec[10];
1897 const INT drivetype;
1898 const VARIANT_BOOL expected_ret;
1899 };
1900
1901 /* If 'drivetype' != -1, the first character of 'drivespec' will be replaced
1902 * with the drive letter of a drive of this type. If such a drive does not exist,
1903 * the test will be skipped. */
1904 static const struct driveexists_test driveexiststestdata[] = {
1905 { {'N',':','\\',0}, DRIVE_NO_ROOT_DIR, VARIANT_FALSE },
1906 { {'R',':','\\',0}, DRIVE_REMOVABLE, VARIANT_TRUE },
1907 { {'F',':','\\',0}, DRIVE_FIXED, VARIANT_TRUE },
1908 { {'F',':',0}, DRIVE_FIXED, VARIANT_TRUE },
1909 { {'F','?',0}, DRIVE_FIXED, VARIANT_FALSE },
1910 { {'F',0}, DRIVE_FIXED, VARIANT_TRUE },
1911 { {'?',0}, -1, VARIANT_FALSE },
1912 { { 0 } }
1913 };
1914
1915 static void test_DriveExists(void)
1916 {
1917 const struct driveexists_test *ptr = driveexiststestdata;
1918 HRESULT hr;
1919 VARIANT_BOOL ret;
1920 BSTR drivespec;
1921 WCHAR root[] = {'?',':','\\',0};
1922
1923 hr = IFileSystem3_DriveExists(fs3, NULL, NULL);
1924 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1925
1926 ret = VARIANT_TRUE;
1927 hr = IFileSystem3_DriveExists(fs3, NULL, &ret);
1928 ok(hr == S_OK, "got 0x%08x\n", hr);
1929 ok(ret == VARIANT_FALSE, "got %x\n", ret);
1930
1931 drivespec = SysAllocString(root);
1932 hr = IFileSystem3_DriveExists(fs3, drivespec, NULL);
1933 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1934 SysFreeString(drivespec);
1935
1936 for (; *ptr->drivespec; ptr++) {
1937 drivespec = SysAllocString(ptr->drivespec);
1938 if (ptr->drivetype != -1) {
1939 for (root[0] = 'A'; root[0] <= 'Z'; root[0]++)
1940 if (GetDriveTypeW(root) == ptr->drivetype)
1941 break;
1942 if (root[0] > 'Z') {
1943 skip("No drive with type 0x%x found, skipping test %s.\n",
1944 ptr->drivetype, wine_dbgstr_w(ptr->drivespec));
1945 SysFreeString(drivespec);
1946 continue;
1947 }
1948
1949 /* Test both upper and lower case drive letters. */
1950 drivespec[0] = root[0];
1951 ret = ptr->expected_ret == VARIANT_TRUE ? VARIANT_FALSE : VARIANT_TRUE;
1952 hr = IFileSystem3_DriveExists(fs3, drivespec, &ret);
1953 ok(hr == S_OK, "got 0x%08x for drive spec %s (%s)\n",
1954 hr, wine_dbgstr_w(drivespec), wine_dbgstr_w(ptr->drivespec));
1955 ok(ret == ptr->expected_ret, "got %d, expected %d for drive spec %s (%s)\n",
1956 ret, ptr->expected_ret, wine_dbgstr_w(drivespec), wine_dbgstr_w(ptr->drivespec));
1957
1958 drivespec[0] = tolower(root[0]);
1959 }
1960
1961 ret = ptr->expected_ret == VARIANT_TRUE ? VARIANT_FALSE : VARIANT_TRUE;
1962 hr = IFileSystem3_DriveExists(fs3, drivespec, &ret);
1963 ok(hr == S_OK, "got 0x%08x for drive spec %s (%s)\n",
1964 hr, wine_dbgstr_w(drivespec), wine_dbgstr_w(ptr->drivespec));
1965 ok(ret == ptr->expected_ret, "got %d, expected %d for drive spec %s (%s)\n",
1966 ret, ptr->expected_ret, wine_dbgstr_w(drivespec), wine_dbgstr_w(ptr->drivespec));
1967
1968 SysFreeString(drivespec);
1969 }
1970 }
1971
1972 struct getdrivename_test {
1973 const WCHAR path[10];
1974 const WCHAR drive[5];
1975 };
1976
1977 static const struct getdrivename_test getdrivenametestdata[] = {
1978 { {'C',':','\\','1','.','t','s','t',0}, {'C',':',0} },
1979 { {'O',':','\\','1','.','t','s','t',0}, {'O',':',0} },
1980 { {'O',':',0}, {'O',':',0} },
1981 { {'o',':',0}, {'o',':',0} },
1982 { {'O','O',':',0} },
1983 { {':',0} },
1984 { {'O',0} },
1985 { { 0 } }
1986 };
1987
1988 static void test_GetDriveName(void)
1989 {
1990 const struct getdrivename_test *ptr = getdrivenametestdata;
1991 HRESULT hr;
1992 BSTR name;
1993
1994 hr = IFileSystem3_GetDriveName(fs3, NULL, NULL);
1995 ok(hr == E_POINTER, "got 0x%08x\n", hr);
1996
1997 name = (void*)0xdeadbeef;
1998 hr = IFileSystem3_GetDriveName(fs3, NULL, &name);
1999 ok(hr == S_OK, "got 0x%08x\n", hr);
2000 ok(name == NULL, "got %p\n", name);
2001
2002 while (*ptr->path) {
2003 BSTR path = SysAllocString(ptr->path);
2004 name = (void*)0xdeadbeef;
2005 hr = IFileSystem3_GetDriveName(fs3, path, &name);
2006 ok(hr == S_OK, "got 0x%08x\n", hr);
2007 if (name)
2008 ok(!lstrcmpW(ptr->drive, name), "got %s, expected %s\n", wine_dbgstr_w(name), wine_dbgstr_w(ptr->drive));
2009 else
2010 ok(!*ptr->drive, "got %s, expected %s\n", wine_dbgstr_w(name), wine_dbgstr_w(ptr->drive));
2011 SysFreeString(path);
2012 SysFreeString(name);
2013 ptr++;
2014 }
2015 }
2016
2017 struct getdrive_test {
2018 const WCHAR drivespec[12];
2019 HRESULT res;
2020 const WCHAR driveletter[2];
2021 };
2022
2023 static void test_GetDrive(void)
2024 {
2025 HRESULT hr;
2026 IDrive *drive_fixed, *drive;
2027 BSTR dl_fixed, drivespec;
2028 WCHAR root[] = {'?',':','\\',0};
2029
2030 drive = (void*)0xdeadbeef;
2031 hr = IFileSystem3_GetDrive(fs3, NULL, NULL);
2032 ok(hr == E_POINTER, "got 0x%08x\n", hr);
2033 ok(drive == (void*)0xdeadbeef, "got %p\n", drive);
2034
2035 for (root[0] = 'A'; root[0] <= 'Z'; root[0]++)
2036 if (GetDriveTypeW(root) == DRIVE_NO_ROOT_DIR)
2037 break;
2038
2039 if (root[0] > 'Z')
2040 skip("All drive letters are occupied, skipping test for nonexisting drive.\n");
2041 else {
2042 drivespec = SysAllocString(root);
2043 drive = (void*)0xdeadbeef;
2044 hr = IFileSystem3_GetDrive(fs3, drivespec, &drive);
2045 ok(hr == CTL_E_DEVICEUNAVAILABLE, "got 0x%08x\n", hr);
2046 ok(drive == NULL, "got %p\n", drive);
2047 SysFreeString(drivespec);
2048 }
2049
2050 drive_fixed = get_fixed_drive();
2051 if (!drive_fixed) {
2052 skip("No fixed drive found, skipping test.\n");
2053 return;
2054 }
2055
2056 hr = IDrive_get_DriveLetter(drive_fixed, &dl_fixed);
2057 ok(hr == S_OK, "got 0x%08x\n", hr);
2058
2059 if (FAILED(hr))
2060 skip("Could not retrieve drive letter of fixed drive, skipping test.\n");
2061 else {
2062 WCHAR dl_upper = toupper(dl_fixed[0]);
2063 WCHAR dl_lower = tolower(dl_fixed[0]);
2064 struct getdrive_test testdata[] = {
2065 { {dl_upper,0}, S_OK, {dl_upper,0} },
2066 { {dl_upper,':',0}, S_OK, {dl_upper,0} },
2067 { {dl_upper,':','\\',0}, S_OK, {dl_upper,0} },
2068 { {dl_lower,':','\\',0}, S_OK, {dl_upper,0} },
2069 { {dl_upper,'\\',0}, E_INVALIDARG, { 0 } },
2070 { {dl_lower,'\\',0}, E_INVALIDARG, { 0 } },
2071 { {'$',':','\\',0}, E_INVALIDARG, { 0 } },
2072 { {'\\','h','o','s','t','\\','s','h','a','r','e',0}, E_INVALIDARG, { 0 } },
2073 { {'h','o','s','t','\\','s','h','a','r','e',0}, E_INVALIDARG, { 0 } },
2074 { { 0 } },
2075 };
2076 struct getdrive_test *ptr = &testdata[0];
2077
2078 for (; *ptr->drivespec; ptr++) {
2079 drivespec = SysAllocString(ptr->drivespec);
2080 drive = (void*)0xdeadbeef;
2081 hr = IFileSystem3_GetDrive(fs3, drivespec, &drive);
2082 ok(hr == ptr->res, "got 0x%08x, expected 0x%08x for drive spec %s\n",
2083 hr, ptr->res, wine_dbgstr_w(ptr->drivespec));
2084 ok(!lstrcmpW(ptr->drivespec, drivespec), "GetDrive modified its DriveSpec argument\n");
2085 SysFreeString(drivespec);
2086
2087 if (*ptr->driveletter) {
2088 BSTR driveletter;
2089 hr = IDrive_get_DriveLetter(drive, &driveletter);
2090 ok(hr == S_OK, "got 0x%08x for drive spec %s\n", hr, wine_dbgstr_w(ptr->drivespec));
2091 if (SUCCEEDED(hr)) {
2092 ok(!lstrcmpW(ptr->driveletter, driveletter), "got %s, expected %s for drive spec %s\n",
2093 wine_dbgstr_w(driveletter), wine_dbgstr_w(ptr->driveletter),
2094 wine_dbgstr_w(ptr->drivespec));
2095 SysFreeString(driveletter);
2096 }
2097 test_provideclassinfo(drive, &CLSID_Drive);
2098 IDrive_Release(drive);
2099 } else
2100 ok(drive == NULL, "got %p for drive spec %s\n", drive, wine_dbgstr_w(ptr->drivespec));
2101 }
2102 SysFreeString(dl_fixed);
2103 }
2104 }
2105
2106 static void test_SerialNumber(void)
2107 {
2108 IDrive *drive;
2109 LONG serial;
2110 HRESULT hr;
2111 BSTR name;
2112
2113 drive = get_fixed_drive();
2114 if (!drive) {
2115 skip("No fixed drive found, skipping test.\n");
2116 return;
2117 }
2118
2119 hr = IDrive_get_SerialNumber(drive, NULL);
2120 ok(hr == E_POINTER, "got 0x%08x\n", hr);
2121
2122 serial = 0xdeadbeef;
2123 hr = IDrive_get_SerialNumber(drive, &serial);
2124 ok(hr == S_OK, "got 0x%08x\n", hr);
2125 ok(serial != 0xdeadbeef, "got %x\n", serial);
2126
2127 hr = IDrive_get_FileSystem(drive, NULL);
2128 ok(hr == E_POINTER, "got 0x%08x\n", hr);
2129
2130 name = NULL;
2131 hr = IDrive_get_FileSystem(drive, &name);
2132 ok(hr == S_OK, "got 0x%08x\n", hr);
2133 ok(name != NULL, "got %p\n", name);
2134 SysFreeString(name);
2135
2136 hr = IDrive_get_VolumeName(drive, NULL);
2137 ok(hr == E_POINTER, "got 0x%08x\n", hr);
2138
2139 name = NULL;
2140 hr = IDrive_get_VolumeName(drive, &name);
2141 ok(hr == S_OK, "got 0x%08x\n", hr);
2142 ok(name != NULL, "got %p\n", name);
2143 SysFreeString(name);
2144
2145 IDrive_Release(drive);
2146 }
2147
2148 static const struct extension_test {
2149 WCHAR path[20];
2150 WCHAR ext[10];
2151 } extension_tests[] = {
2152 { {'n','o','e','x','t',0}, {0} },
2153 { {'n','.','o','.','e','x','t',0}, {'e','x','t',0} },
2154 { {'n','.','o','.','e','X','t',0}, {'e','X','t',0} },
2155 { { 0 } }
2156 };
2157
2158 static void test_GetExtensionName(void)
2159 {
2160 BSTR path, ext;
2161 HRESULT hr;
2162 int i;
2163
2164 for (i = 0; i < sizeof(extension_tests)/sizeof(extension_tests[0]); i++) {
2165
2166 path = SysAllocString(extension_tests[i].path);
2167 ext = NULL;
2168 hr = IFileSystem3_GetExtensionName(fs3, path, &ext);
2169 ok(hr == S_OK, "got 0x%08x\n", hr);
2170 if (*extension_tests[i].ext)
2171 ok(!lstrcmpW(ext, extension_tests[i].ext), "%d: path %s, got %s, expected %s\n", i,
2172 wine_dbgstr_w(path), wine_dbgstr_w(ext), wine_dbgstr_w(extension_tests[i].ext));
2173 else
2174 ok(ext == NULL, "%d: path %s, got %s, expected %s\n", i,
2175 wine_dbgstr_w(path), wine_dbgstr_w(ext), wine_dbgstr_w(extension_tests[i].ext));
2176
2177 SysFreeString(path);
2178 SysFreeString(ext);
2179 }
2180 }
2181
2182 static void test_GetSpecialFolder(void)
2183 {
2184 WCHAR pathW[MAX_PATH];
2185 IFolder *folder;
2186 HRESULT hr;
2187 DWORD ret;
2188 BSTR path;
2189
2190 hr = IFileSystem3_GetSpecialFolder(fs3, WindowsFolder, NULL);
2191 ok(hr == E_POINTER, "got 0x%08x\n", hr);
2192
2193 hr = IFileSystem3_GetSpecialFolder(fs3, TemporaryFolder+1, NULL);
2194 ok(hr == E_POINTER, "got 0x%08x\n", hr);
2195
2196 hr = IFileSystem3_GetSpecialFolder(fs3, TemporaryFolder+1, &folder);
2197 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2198
2199 hr = IFileSystem3_GetSpecialFolder(fs3, WindowsFolder, &folder);
2200 ok(hr == S_OK, "got 0x%08x\n", hr);
2201 hr = IFolder_get_Path(folder, &path);
2202 ok(hr == S_OK, "got 0x%08x\n", hr);
2203 GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
2204 ok(!lstrcmpiW(pathW, path), "got %s, expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(pathW));
2205 SysFreeString(path);
2206 IFolder_Release(folder);
2207
2208 hr = IFileSystem3_GetSpecialFolder(fs3, SystemFolder, &folder);
2209 ok(hr == S_OK, "got 0x%08x\n", hr);
2210 hr = IFolder_get_Path(folder, &path);
2211 ok(hr == S_OK, "got 0x%08x\n", hr);
2212 GetSystemDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
2213 ok(!lstrcmpiW(pathW, path), "got %s, expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(pathW));
2214 SysFreeString(path);
2215 IFolder_Release(folder);
2216
2217 hr = IFileSystem3_GetSpecialFolder(fs3, TemporaryFolder, &folder);
2218 ok(hr == S_OK, "got 0x%08x\n", hr);
2219 hr = IFolder_get_Path(folder, &path);
2220 ok(hr == S_OK, "got 0x%08x\n", hr);
2221 ret = GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
2222 if (ret && pathW[ret-1] == '\\')
2223 pathW[ret-1] = 0;
2224
2225 ok(!lstrcmpiW(pathW, path), "got %s, expected %s\n", wine_dbgstr_w(path), wine_dbgstr_w(pathW));
2226 SysFreeString(path);
2227 IFolder_Release(folder);
2228 }
2229
2230 START_TEST(filesystem)
2231 {
2232 HRESULT hr;
2233
2234 CoInitialize(NULL);
2235
2236 hr = CoCreateInstance(&CLSID_FileSystemObject, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
2237 &IID_IFileSystem3, (void**)&fs3);
2238 if(FAILED(hr)) {
2239 win_skip("Could not create FileSystem object: %08x\n", hr);
2240 return;
2241 }
2242
2243 test_interfaces();
2244 test_createfolder();
2245 test_textstream();
2246 test_GetFileVersion();
2247 test_GetParentFolderName();
2248 test_GetFileName();
2249 test_GetBaseName();
2250 test_GetAbsolutePathName();
2251 test_GetFile();
2252 test_CopyFolder();
2253 test_BuildPath();
2254 test_GetFolder();
2255 test_FolderCollection();
2256 test_FileCollection();
2257 test_DriveCollection();
2258 test_CreateTextFile();
2259 test_WriteLine();
2260 test_ReadAll();
2261 test_Read();
2262 test_DriveExists();
2263 test_GetDriveName();
2264 test_GetDrive();
2265 test_SerialNumber();
2266 test_GetExtensionName();
2267 test_GetSpecialFolder();
2268
2269 IFileSystem3_Release(fs3);
2270
2271 CoUninitialize();
2272 }