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