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