45370e1e39096d819c77a88602b7a2a527f08995
[reactos.git] / dll / win32 / scrrun / filesystem.c
1 /*
2 * Copyright 2012 Alistair Leslie-Hughes
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "scrrun_private.h"
20
21 #include <winver.h>
22 #include <olectl.h>
23 #include <ntsecapi.h>
24 #include <wine/unicode.h>
25
26 static const WCHAR bsW[] = {'\\',0};
27 static const WCHAR utf16bom = 0xfeff;
28
29 struct filesystem {
30 struct provideclassinfo classinfo;
31 IFileSystem3 IFileSystem3_iface;
32 };
33
34 struct foldercollection {
35 struct provideclassinfo classinfo;
36 IFolderCollection IFolderCollection_iface;
37 LONG ref;
38 BSTR path;
39 };
40
41 struct filecollection {
42 struct provideclassinfo classinfo;
43 IFileCollection IFileCollection_iface;
44 LONG ref;
45 BSTR path;
46 };
47
48 struct drivecollection {
49 struct provideclassinfo classinfo;
50 IDriveCollection IDriveCollection_iface;
51 LONG ref;
52 DWORD drives;
53 LONG count;
54 };
55
56 struct enumdata {
57 union
58 {
59 struct
60 {
61 struct foldercollection *coll;
62 HANDLE find;
63 } foldercoll;
64 struct
65 {
66 struct filecollection *coll;
67 HANDLE find;
68 } filecoll;
69 struct
70 {
71 struct drivecollection *coll;
72 INT cur;
73 } drivecoll;
74 } u;
75 };
76
77 struct enumvariant {
78 IEnumVARIANT IEnumVARIANT_iface;
79 LONG ref;
80
81 struct enumdata data;
82 };
83
84 struct drive {
85 struct provideclassinfo classinfo;
86 IDrive IDrive_iface;
87 LONG ref;
88 BSTR root;
89 };
90
91 struct folder {
92 struct provideclassinfo classinfo;
93 IFolder IFolder_iface;
94 LONG ref;
95 BSTR path;
96 };
97
98 struct file {
99 struct provideclassinfo classinfo;
100 IFile IFile_iface;
101 LONG ref;
102
103 WCHAR *path;
104 };
105
106 struct textstream {
107 struct provideclassinfo classinfo;
108 ITextStream ITextStream_iface;
109 LONG ref;
110
111 IOMode mode;
112 BOOL unicode;
113 BOOL first_read;
114 LARGE_INTEGER size;
115 HANDLE file;
116 };
117
118 enum iotype {
119 IORead,
120 IOWrite
121 };
122
123 static inline struct filesystem *impl_from_IFileSystem3(IFileSystem3 *iface)
124 {
125 return CONTAINING_RECORD(iface, struct filesystem, IFileSystem3_iface);
126 }
127
128 static inline struct drive *impl_from_IDrive(IDrive *iface)
129 {
130 return CONTAINING_RECORD(iface, struct drive, IDrive_iface);
131 }
132
133 static inline struct folder *impl_from_IFolder(IFolder *iface)
134 {
135 return CONTAINING_RECORD(iface, struct folder, IFolder_iface);
136 }
137
138 static inline struct file *impl_from_IFile(IFile *iface)
139 {
140 return CONTAINING_RECORD(iface, struct file, IFile_iface);
141 }
142
143 static inline struct textstream *impl_from_ITextStream(ITextStream *iface)
144 {
145 return CONTAINING_RECORD(iface, struct textstream, ITextStream_iface);
146 }
147
148 static inline struct foldercollection *impl_from_IFolderCollection(IFolderCollection *iface)
149 {
150 return CONTAINING_RECORD(iface, struct foldercollection, IFolderCollection_iface);
151 }
152
153 static inline struct filecollection *impl_from_IFileCollection(IFileCollection *iface)
154 {
155 return CONTAINING_RECORD(iface, struct filecollection, IFileCollection_iface);
156 }
157
158 static inline struct drivecollection *impl_from_IDriveCollection(IDriveCollection *iface)
159 {
160 return CONTAINING_RECORD(iface, struct drivecollection, IDriveCollection_iface);
161 }
162
163 static inline struct enumvariant *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
164 {
165 return CONTAINING_RECORD(iface, struct enumvariant, IEnumVARIANT_iface);
166 }
167
168 static inline HRESULT create_error(DWORD err)
169 {
170 switch(err) {
171 case ERROR_FILE_NOT_FOUND: return CTL_E_FILENOTFOUND;
172 case ERROR_PATH_NOT_FOUND: return CTL_E_PATHNOTFOUND;
173 case ERROR_ACCESS_DENIED: return CTL_E_PERMISSIONDENIED;
174 case ERROR_FILE_EXISTS: return CTL_E_FILEALREADYEXISTS;
175 case ERROR_ALREADY_EXISTS: return CTL_E_FILEALREADYEXISTS;
176 default:
177 FIXME("Unsupported error code: %d\n", err);
178 return E_FAIL;
179 }
180 }
181
182 static HRESULT create_folder(const WCHAR*, IFolder**);
183 static HRESULT create_file(BSTR, IFile**);
184 static HRESULT create_foldercoll_enum(struct foldercollection*, IUnknown**);
185 static HRESULT create_filecoll_enum(struct filecollection*, IUnknown**);
186
187 static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data)
188 {
189 static const WCHAR dotdotW[] = {'.','.',0};
190 static const WCHAR dotW[] = {'.',0};
191
192 return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
193 strcmpW(data->cFileName, dotdotW) &&
194 strcmpW(data->cFileName, dotW);
195 }
196
197 static inline BOOL is_file_data(const WIN32_FIND_DATAW *data)
198 {
199 return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
200 }
201
202 static BSTR get_full_path(BSTR path, const WIN32_FIND_DATAW *data)
203 {
204 int len = SysStringLen(path);
205 WCHAR buffW[MAX_PATH];
206
207 strcpyW(buffW, path);
208 if (path[len-1] != '\\')
209 strcatW(buffW, bsW);
210 strcatW(buffW, data->cFileName);
211
212 return SysAllocString(buffW);
213 }
214
215 static BOOL textstream_check_iomode(struct textstream *This, enum iotype type)
216 {
217 if (type == IORead)
218 return This->mode == ForWriting || This->mode == ForAppending;
219 else
220 return This->mode == ForReading;
221 }
222
223 static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
224 {
225 struct textstream *This = impl_from_ITextStream(iface);
226
227 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
228
229 if (IsEqualIID(riid, &IID_ITextStream) ||
230 IsEqualIID(riid, &IID_IDispatch) ||
231 IsEqualIID(riid, &IID_IUnknown))
232 {
233 *obj = &This->ITextStream_iface;
234 }
235 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
236 {
237 *obj = &This->classinfo.IProvideClassInfo_iface;
238 }
239 else
240 return E_NOINTERFACE;
241
242 IUnknown_AddRef((IUnknown*)*obj);
243 return S_OK;
244 }
245
246 static ULONG WINAPI textstream_AddRef(ITextStream *iface)
247 {
248 struct textstream *This = impl_from_ITextStream(iface);
249 ULONG ref = InterlockedIncrement(&This->ref);
250 TRACE("(%p)->(%d)\n", This, ref);
251 return ref;
252 }
253
254 static ULONG WINAPI textstream_Release(ITextStream *iface)
255 {
256 struct textstream *This = impl_from_ITextStream(iface);
257 ULONG ref = InterlockedDecrement(&This->ref);
258 TRACE("(%p)->(%d)\n", This, ref);
259
260 if (!ref)
261 {
262 CloseHandle(This->file);
263 heap_free(This);
264 }
265
266 return ref;
267 }
268
269 static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
270 {
271 struct textstream *This = impl_from_ITextStream(iface);
272 TRACE("(%p)->(%p)\n", This, pctinfo);
273 *pctinfo = 1;
274 return S_OK;
275 }
276
277 static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
278 LCID lcid, ITypeInfo **ppTInfo)
279 {
280 struct textstream *This = impl_from_ITextStream(iface);
281 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
282 return get_typeinfo(ITextStream_tid, ppTInfo);
283 }
284
285 static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
286 LPOLESTR *rgszNames, UINT cNames,
287 LCID lcid, DISPID *rgDispId)
288 {
289 struct textstream *This = impl_from_ITextStream(iface);
290 ITypeInfo *typeinfo;
291 HRESULT hr;
292
293 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
294
295 hr = get_typeinfo(ITextStream_tid, &typeinfo);
296 if(SUCCEEDED(hr))
297 {
298 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
299 ITypeInfo_Release(typeinfo);
300 }
301
302 return hr;
303 }
304
305 static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
306 REFIID riid, LCID lcid, WORD wFlags,
307 DISPPARAMS *pDispParams, VARIANT *pVarResult,
308 EXCEPINFO *pExcepInfo, UINT *puArgErr)
309 {
310 struct textstream *This = impl_from_ITextStream(iface);
311 ITypeInfo *typeinfo;
312 HRESULT hr;
313
314 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
315 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
316
317 hr = get_typeinfo(ITextStream_tid, &typeinfo);
318 if(SUCCEEDED(hr))
319 {
320 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
321 pDispParams, pVarResult, pExcepInfo, puArgErr);
322 ITypeInfo_Release(typeinfo);
323 }
324
325 return hr;
326 }
327
328 static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
329 {
330 struct textstream *This = impl_from_ITextStream(iface);
331 FIXME("(%p)->(%p): stub\n", This, line);
332 return E_NOTIMPL;
333 }
334
335 static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
336 {
337 struct textstream *This = impl_from_ITextStream(iface);
338 FIXME("(%p)->(%p): stub\n", This, column);
339 return E_NOTIMPL;
340 }
341
342 static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
343 {
344 struct textstream *This = impl_from_ITextStream(iface);
345 LARGE_INTEGER pos, dist;
346
347 TRACE("(%p)->(%p)\n", This, eos);
348
349 if (!eos)
350 return E_POINTER;
351
352 if (textstream_check_iomode(This, IORead)) {
353 *eos = VARIANT_TRUE;
354 return CTL_E_BADFILEMODE;
355 }
356
357 dist.QuadPart = 0;
358 if (!SetFilePointerEx(This->file, dist, &pos, FILE_CURRENT))
359 return E_FAIL;
360
361 *eos = This->size.QuadPart == pos.QuadPart ? VARIANT_TRUE : VARIANT_FALSE;
362 return S_OK;
363 }
364
365 static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
366 {
367 struct textstream *This = impl_from_ITextStream(iface);
368 FIXME("(%p)->(%p): stub\n", This, eol);
369 return E_NOTIMPL;
370 }
371
372 /*
373 Reads 'toread' bytes from a file, converts if needed
374 BOM is skipped if 'bof' is set.
375 */
376 static HRESULT textstream_read(struct textstream *stream, LONG toread, BOOL bof, BSTR *text)
377 {
378 HRESULT hr = S_OK;
379 DWORD read;
380 char *buff;
381 BOOL ret;
382
383 if (toread == 0) {
384 *text = SysAllocStringLen(NULL, 0);
385 return *text ? S_FALSE : E_OUTOFMEMORY;
386 }
387
388 if (toread < sizeof(WCHAR))
389 return CTL_E_ENDOFFILE;
390
391 buff = heap_alloc(toread);
392 if (!buff)
393 return E_OUTOFMEMORY;
394
395 ret = ReadFile(stream->file, buff, toread, &read, NULL);
396 if (!ret || toread != read) {
397 WARN("failed to read from file %d, %d, error %d\n", read, toread, GetLastError());
398 heap_free(buff);
399 return E_FAIL;
400 }
401
402 if (stream->unicode) {
403 int i = 0;
404
405 /* skip BOM */
406 if (bof && *(WCHAR*)buff == utf16bom) {
407 read -= sizeof(WCHAR);
408 i += sizeof(WCHAR);
409 }
410
411 *text = SysAllocStringLen(read ? (WCHAR*)&buff[i] : NULL, read/sizeof(WCHAR));
412 if (!*text) hr = E_OUTOFMEMORY;
413 }
414 else {
415 INT len = MultiByteToWideChar(CP_ACP, 0, buff, read, NULL, 0);
416 *text = SysAllocStringLen(NULL, len);
417 if (*text)
418 MultiByteToWideChar(CP_ACP, 0, buff, read, *text, len);
419 else
420 hr = E_OUTOFMEMORY;
421 }
422 heap_free(buff);
423
424 return hr;
425 }
426
427 static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
428 {
429 struct textstream *This = impl_from_ITextStream(iface);
430 LARGE_INTEGER start, end, dist;
431 DWORD toread;
432 HRESULT hr;
433
434 TRACE("(%p)->(%d %p)\n", This, len, text);
435
436 if (!text)
437 return E_POINTER;
438
439 *text = NULL;
440 if (len <= 0)
441 return len == 0 ? S_OK : E_INVALIDARG;
442
443 if (textstream_check_iomode(This, IORead))
444 return CTL_E_BADFILEMODE;
445
446 if (!This->first_read) {
447 VARIANT_BOOL eos;
448
449 /* check for EOF */
450 hr = ITextStream_get_AtEndOfStream(iface, &eos);
451 if (FAILED(hr))
452 return hr;
453
454 if (eos == VARIANT_TRUE)
455 return CTL_E_ENDOFFILE;
456 }
457
458 /* read everything from current position */
459 dist.QuadPart = 0;
460 SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
461 SetFilePointerEx(This->file, dist, &end, FILE_END);
462 toread = end.QuadPart - start.QuadPart;
463 /* rewind back */
464 dist.QuadPart = start.QuadPart;
465 SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
466
467 This->first_read = FALSE;
468 if (This->unicode) len *= sizeof(WCHAR);
469
470 hr = textstream_read(This, min(toread, len), start.QuadPart == 0, text);
471 if (FAILED(hr))
472 return hr;
473 else
474 return toread <= len ? S_FALSE : S_OK;
475 }
476
477 static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
478 {
479 struct textstream *This = impl_from_ITextStream(iface);
480 VARIANT_BOOL eos;
481 HRESULT hr;
482
483 FIXME("(%p)->(%p): stub\n", This, text);
484
485 if (!text)
486 return E_POINTER;
487
488 *text = NULL;
489 if (textstream_check_iomode(This, IORead))
490 return CTL_E_BADFILEMODE;
491
492 /* check for EOF */
493 hr = ITextStream_get_AtEndOfStream(iface, &eos);
494 if (FAILED(hr))
495 return hr;
496
497 if (eos == VARIANT_TRUE)
498 return CTL_E_ENDOFFILE;
499
500 return E_NOTIMPL;
501 }
502
503 static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
504 {
505 struct textstream *This = impl_from_ITextStream(iface);
506 LARGE_INTEGER start, end, dist;
507 DWORD toread;
508 HRESULT hr;
509
510 TRACE("(%p)->(%p)\n", This, text);
511
512 if (!text)
513 return E_POINTER;
514
515 *text = NULL;
516 if (textstream_check_iomode(This, IORead))
517 return CTL_E_BADFILEMODE;
518
519 if (!This->first_read) {
520 VARIANT_BOOL eos;
521
522 /* check for EOF */
523 hr = ITextStream_get_AtEndOfStream(iface, &eos);
524 if (FAILED(hr))
525 return hr;
526
527 if (eos == VARIANT_TRUE)
528 return CTL_E_ENDOFFILE;
529 }
530
531 /* read everything from current position */
532 dist.QuadPart = 0;
533 SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
534 SetFilePointerEx(This->file, dist, &end, FILE_END);
535 toread = end.QuadPart - start.QuadPart;
536 /* rewind back */
537 dist.QuadPart = start.QuadPart;
538 SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
539
540 This->first_read = FALSE;
541
542 hr = textstream_read(This, toread, start.QuadPart == 0, text);
543 return FAILED(hr) ? hr : S_FALSE;
544 }
545
546 static HRESULT textstream_writestr(struct textstream *stream, BSTR text)
547 {
548 DWORD written = 0;
549 BOOL ret;
550
551 if (stream->unicode) {
552 ret = WriteFile(stream->file, text, SysStringByteLen(text), &written, NULL);
553 return (ret && written == SysStringByteLen(text)) ? S_OK : create_error(GetLastError());
554 } else {
555 DWORD len = WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), NULL, 0, NULL, NULL);
556 char *buffA;
557 HRESULT hr;
558
559 buffA = heap_alloc(len);
560 if (!buffA)
561 return E_OUTOFMEMORY;
562
563 WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), buffA, len, NULL, NULL);
564 ret = WriteFile(stream->file, buffA, len, &written, NULL);
565 hr = (ret && written == len) ? S_OK : create_error(GetLastError());
566 heap_free(buffA);
567 return hr;
568 }
569 }
570
571 static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
572 {
573 struct textstream *This = impl_from_ITextStream(iface);
574
575 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
576
577 if (textstream_check_iomode(This, IOWrite))
578 return CTL_E_BADFILEMODE;
579
580 return textstream_writestr(This, text);
581 }
582
583 static HRESULT textstream_writecrlf(struct textstream *stream)
584 {
585 static const WCHAR crlfW[] = {'\r','\n'};
586 static const char crlfA[] = {'\r','\n'};
587 DWORD written = 0, len;
588 const void *ptr;
589 BOOL ret;
590
591 if (stream->unicode) {
592 ptr = crlfW;
593 len = sizeof(crlfW);
594 }
595 else {
596 ptr = crlfA;
597 len = sizeof(crlfA);
598 }
599
600 ret = WriteFile(stream->file, ptr, len, &written, NULL);
601 return (ret && written == len) ? S_OK : create_error(GetLastError());
602 }
603
604 static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
605 {
606 struct textstream *This = impl_from_ITextStream(iface);
607 HRESULT hr;
608
609 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
610
611 if (textstream_check_iomode(This, IOWrite))
612 return CTL_E_BADFILEMODE;
613
614 hr = textstream_writestr(This, text);
615 if (SUCCEEDED(hr))
616 hr = textstream_writecrlf(This);
617 return hr;
618 }
619
620 static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
621 {
622 struct textstream *This = impl_from_ITextStream(iface);
623 FIXME("(%p)->(%d): stub\n", This, lines);
624 return E_NOTIMPL;
625 }
626
627 static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
628 {
629 struct textstream *This = impl_from_ITextStream(iface);
630 FIXME("(%p)->(%d): stub\n", This, count);
631 return E_NOTIMPL;
632 }
633
634 static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
635 {
636 struct textstream *This = impl_from_ITextStream(iface);
637 FIXME("(%p): stub\n", This);
638 return E_NOTIMPL;
639 }
640
641 static HRESULT WINAPI textstream_Close(ITextStream *iface)
642 {
643 struct textstream *This = impl_from_ITextStream(iface);
644 HRESULT hr = S_OK;
645
646 TRACE("(%p)\n", This);
647
648 if(!CloseHandle(This->file))
649 hr = S_FALSE;
650
651 This->file = NULL;
652
653 return hr;
654 }
655
656 static const ITextStreamVtbl textstreamvtbl = {
657 textstream_QueryInterface,
658 textstream_AddRef,
659 textstream_Release,
660 textstream_GetTypeInfoCount,
661 textstream_GetTypeInfo,
662 textstream_GetIDsOfNames,
663 textstream_Invoke,
664 textstream_get_Line,
665 textstream_get_Column,
666 textstream_get_AtEndOfStream,
667 textstream_get_AtEndOfLine,
668 textstream_Read,
669 textstream_ReadLine,
670 textstream_ReadAll,
671 textstream_Write,
672 textstream_WriteLine,
673 textstream_WriteBlankLines,
674 textstream_Skip,
675 textstream_SkipLine,
676 textstream_Close
677 };
678
679 static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMode mode, BOOL unicode, ITextStream **ret)
680 {
681 struct textstream *stream;
682 DWORD access = 0;
683
684 /* map access mode */
685 switch (mode)
686 {
687 case ForReading:
688 access = GENERIC_READ;
689 break;
690 case ForWriting:
691 access = GENERIC_WRITE;
692 break;
693 case ForAppending:
694 access = FILE_APPEND_DATA;
695 break;
696 default:
697 return E_INVALIDARG;
698 }
699
700 stream = heap_alloc(sizeof(struct textstream));
701 if (!stream) return E_OUTOFMEMORY;
702
703 stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
704 stream->ref = 1;
705 stream->mode = mode;
706 stream->unicode = unicode;
707 stream->first_read = TRUE;
708
709 stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
710 if (stream->file == INVALID_HANDLE_VALUE)
711 {
712 HRESULT hr = create_error(GetLastError());
713 heap_free(stream);
714 return hr;
715 }
716
717 if (mode == ForReading)
718 GetFileSizeEx(stream->file, &stream->size);
719 else
720 stream->size.QuadPart = 0;
721
722 /* Write Unicode BOM */
723 if (unicode && mode == ForWriting && (disposition == CREATE_ALWAYS || disposition == CREATE_NEW)) {
724 DWORD written = 0;
725 BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL);
726 if (!ret || written != sizeof(utf16bom)) {
727 ITextStream_Release(&stream->ITextStream_iface);
728 return create_error(GetLastError());
729 }
730 }
731
732 init_classinfo(&CLSID_TextStream, (IUnknown *)&stream->ITextStream_iface, &stream->classinfo);
733 *ret = &stream->ITextStream_iface;
734 return S_OK;
735 }
736
737 static HRESULT WINAPI drive_QueryInterface(IDrive *iface, REFIID riid, void **obj)
738 {
739 struct drive *This = impl_from_IDrive(iface);
740
741 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
742
743 *obj = NULL;
744
745 if (IsEqualIID( riid, &IID_IDrive ) ||
746 IsEqualIID( riid, &IID_IDispatch ) ||
747 IsEqualIID( riid, &IID_IUnknown))
748 {
749 *obj = &This->IDrive_iface;
750 }
751 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
752 {
753 *obj = &This->classinfo.IProvideClassInfo_iface;
754 }
755 else
756 return E_NOINTERFACE;
757
758 IUnknown_AddRef((IUnknown*)*obj);
759 return S_OK;
760 }
761
762 static ULONG WINAPI drive_AddRef(IDrive *iface)
763 {
764 struct drive *This = impl_from_IDrive(iface);
765 ULONG ref = InterlockedIncrement(&This->ref);
766 TRACE("(%p)->(%d)\n", This, ref);
767 return ref;
768 }
769
770 static ULONG WINAPI drive_Release(IDrive *iface)
771 {
772 struct drive *This = impl_from_IDrive(iface);
773 ULONG ref = InterlockedDecrement(&This->ref);
774 TRACE("(%p)->(%d)\n", This, ref);
775
776 if (!ref)
777 {
778 SysFreeString(This->root);
779 heap_free(This);
780 }
781
782 return ref;
783 }
784
785 static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo)
786 {
787 struct drive *This = impl_from_IDrive(iface);
788 TRACE("(%p)->(%p)\n", This, pctinfo);
789 *pctinfo = 1;
790 return S_OK;
791 }
792
793 static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo,
794 LCID lcid, ITypeInfo **ppTInfo)
795 {
796 struct drive *This = impl_from_IDrive(iface);
797 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
798 return get_typeinfo(IDrive_tid, ppTInfo);
799 }
800
801 static HRESULT WINAPI drive_GetIDsOfNames(IDrive *iface, REFIID riid,
802 LPOLESTR *rgszNames, UINT cNames,
803 LCID lcid, DISPID *rgDispId)
804 {
805 struct drive *This = impl_from_IDrive(iface);
806 ITypeInfo *typeinfo;
807 HRESULT hr;
808
809 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
810
811 hr = get_typeinfo(IDrive_tid, &typeinfo);
812 if(SUCCEEDED(hr))
813 {
814 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
815 ITypeInfo_Release(typeinfo);
816 }
817
818 return hr;
819 }
820
821 static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember,
822 REFIID riid, LCID lcid, WORD wFlags,
823 DISPPARAMS *pDispParams, VARIANT *pVarResult,
824 EXCEPINFO *pExcepInfo, UINT *puArgErr)
825 {
826 struct drive *This = impl_from_IDrive(iface);
827 ITypeInfo *typeinfo;
828 HRESULT hr;
829
830 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
831 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
832
833 hr = get_typeinfo(IDrive_tid, &typeinfo);
834 if(SUCCEEDED(hr))
835 {
836 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
837 pDispParams, pVarResult, pExcepInfo, puArgErr);
838 ITypeInfo_Release(typeinfo);
839 }
840
841 return hr;
842 }
843
844 static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path)
845 {
846 struct drive *This = impl_from_IDrive(iface);
847 FIXME("(%p)->(%p): stub\n", This, path);
848 return E_NOTIMPL;
849 }
850
851 static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter)
852 {
853 struct drive *This = impl_from_IDrive(iface);
854
855 TRACE("(%p)->(%p)\n", This, letter);
856
857 if (!letter)
858 return E_POINTER;
859
860 *letter = SysAllocStringLen(This->root, 1);
861 if (!*letter)
862 return E_OUTOFMEMORY;
863
864 return S_OK;
865 }
866
867 static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name)
868 {
869 struct drive *This = impl_from_IDrive(iface);
870 FIXME("(%p)->(%p): stub\n", This, share_name);
871 return E_NOTIMPL;
872 }
873
874 static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type)
875 {
876 struct drive *This = impl_from_IDrive(iface);
877
878 TRACE("(%p)->(%p)\n", This, type);
879
880 switch (GetDriveTypeW(This->root))
881 {
882 case DRIVE_REMOVABLE:
883 *type = Removable;
884 break;
885 case DRIVE_FIXED:
886 *type = Fixed;
887 break;
888 case DRIVE_REMOTE:
889 *type = Remote;
890 break;
891 case DRIVE_CDROM:
892 *type = CDRom;
893 break;
894 case DRIVE_RAMDISK:
895 *type = RamDisk;
896 break;
897 default:
898 *type = UnknownType;
899 break;
900 }
901
902 return S_OK;
903 }
904
905 static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder)
906 {
907 struct drive *This = impl_from_IDrive(iface);
908 FIXME("(%p)->(%p): stub\n", This, folder);
909 return E_NOTIMPL;
910 }
911
912 static HRESULT variant_from_largeint(const ULARGE_INTEGER *src, VARIANT *v)
913 {
914 HRESULT hr = S_OK;
915
916 if (src->u.HighPart || src->u.LowPart > INT_MAX)
917 {
918 V_VT(v) = VT_R8;
919 hr = VarR8FromUI8(src->QuadPart, &V_R8(v));
920 }
921 else
922 {
923 V_VT(v) = VT_I4;
924 V_I4(v) = src->u.LowPart;
925 }
926
927 return hr;
928 }
929
930 static HRESULT WINAPI drive_get_AvailableSpace(IDrive *iface, VARIANT *v)
931 {
932 struct drive *This = impl_from_IDrive(iface);
933 ULARGE_INTEGER avail;
934
935 TRACE("(%p)->(%p)\n", This, v);
936
937 if (!v)
938 return E_POINTER;
939
940 if (!GetDiskFreeSpaceExW(This->root, &avail, NULL, NULL))
941 return E_FAIL;
942
943 return variant_from_largeint(&avail, v);
944 }
945
946 static HRESULT WINAPI drive_get_FreeSpace(IDrive *iface, VARIANT *v)
947 {
948 struct drive *This = impl_from_IDrive(iface);
949 ULARGE_INTEGER freespace;
950
951 TRACE("(%p)->(%p)\n", This, v);
952
953 if (!v)
954 return E_POINTER;
955
956 if (!GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL))
957 return E_FAIL;
958
959 return variant_from_largeint(&freespace, v);
960 }
961
962 static HRESULT WINAPI drive_get_TotalSize(IDrive *iface, VARIANT *v)
963 {
964 struct drive *This = impl_from_IDrive(iface);
965 ULARGE_INTEGER total;
966
967 TRACE("(%p)->(%p)\n", This, v);
968
969 if (!v)
970 return E_POINTER;
971
972 if (!GetDiskFreeSpaceExW(This->root, NULL, &total, NULL))
973 return E_FAIL;
974
975 return variant_from_largeint(&total, v);
976 }
977
978 static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name)
979 {
980 struct drive *This = impl_from_IDrive(iface);
981 WCHAR nameW[MAX_PATH+1];
982 BOOL ret;
983
984 TRACE("(%p)->(%p)\n", This, name);
985
986 if (!name)
987 return E_POINTER;
988
989 *name = NULL;
990 ret = GetVolumeInformationW(This->root, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, NULL, NULL, NULL, 0);
991 if (ret)
992 *name = SysAllocString(nameW);
993 return ret ? S_OK : E_FAIL;
994 }
995
996 static HRESULT WINAPI drive_put_VolumeName(IDrive *iface, BSTR name)
997 {
998 struct drive *This = impl_from_IDrive(iface);
999 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
1000 return E_NOTIMPL;
1001 }
1002
1003 static HRESULT WINAPI drive_get_FileSystem(IDrive *iface, BSTR *fs)
1004 {
1005 struct drive *This = impl_from_IDrive(iface);
1006 WCHAR nameW[MAX_PATH+1];
1007 BOOL ret;
1008
1009 TRACE("(%p)->(%p)\n", This, fs);
1010
1011 if (!fs)
1012 return E_POINTER;
1013
1014 *fs = NULL;
1015 ret = GetVolumeInformationW(This->root, NULL, 0, NULL, NULL, NULL, nameW, sizeof(nameW)/sizeof(WCHAR));
1016 if (ret)
1017 *fs = SysAllocString(nameW);
1018 return ret ? S_OK : E_FAIL;
1019 }
1020
1021 static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial)
1022 {
1023 struct drive *This = impl_from_IDrive(iface);
1024 BOOL ret;
1025
1026 TRACE("(%p)->(%p)\n", This, serial);
1027
1028 if (!serial)
1029 return E_POINTER;
1030
1031 ret = GetVolumeInformationW(This->root, NULL, 0, (DWORD*)serial, NULL, NULL, NULL, 0);
1032 return ret ? S_OK : E_FAIL;
1033 }
1034
1035 static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
1036 {
1037 struct drive *This = impl_from_IDrive(iface);
1038 ULARGE_INTEGER freespace;
1039 BOOL ret;
1040
1041 TRACE("(%p)->(%p)\n", This, ready);
1042
1043 if (!ready)
1044 return E_POINTER;
1045
1046 ret = GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL);
1047 *ready = ret ? VARIANT_TRUE : VARIANT_FALSE;
1048 return S_OK;
1049 }
1050
1051 static const IDriveVtbl drivevtbl = {
1052 drive_QueryInterface,
1053 drive_AddRef,
1054 drive_Release,
1055 drive_GetTypeInfoCount,
1056 drive_GetTypeInfo,
1057 drive_GetIDsOfNames,
1058 drive_Invoke,
1059 drive_get_Path,
1060 drive_get_DriveLetter,
1061 drive_get_ShareName,
1062 drive_get_DriveType,
1063 drive_get_RootFolder,
1064 drive_get_AvailableSpace,
1065 drive_get_FreeSpace,
1066 drive_get_TotalSize,
1067 drive_get_VolumeName,
1068 drive_put_VolumeName,
1069 drive_get_FileSystem,
1070 drive_get_SerialNumber,
1071 drive_get_IsReady
1072 };
1073
1074 static HRESULT create_drive(WCHAR letter, IDrive **drive)
1075 {
1076 struct drive *This;
1077
1078 *drive = NULL;
1079
1080 This = heap_alloc(sizeof(*This));
1081 if (!This) return E_OUTOFMEMORY;
1082
1083 This->IDrive_iface.lpVtbl = &drivevtbl;
1084 This->ref = 1;
1085 This->root = SysAllocStringLen(NULL, 3);
1086 if (!This->root)
1087 {
1088 heap_free(This);
1089 return E_OUTOFMEMORY;
1090 }
1091 This->root[0] = letter;
1092 This->root[1] = ':';
1093 This->root[2] = '\\';
1094 This->root[3] = 0;
1095
1096 init_classinfo(&CLSID_Drive, (IUnknown *)&This->IDrive_iface, &This->classinfo);
1097 *drive = &This->IDrive_iface;
1098 return S_OK;
1099 }
1100
1101 static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
1102 {
1103 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1104
1105 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1106
1107 *obj = NULL;
1108
1109 if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
1110 IsEqualIID( riid, &IID_IUnknown ))
1111 {
1112 *obj = iface;
1113 IEnumVARIANT_AddRef(iface);
1114 }
1115 else
1116 return E_NOINTERFACE;
1117
1118 return S_OK;
1119 }
1120
1121 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
1122 {
1123 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1124 ULONG ref = InterlockedIncrement(&This->ref);
1125 TRACE("(%p)->(%d)\n", This, ref);
1126 return ref;
1127 }
1128
1129 static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
1130 {
1131 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1132 ULONG ref = InterlockedDecrement(&This->ref);
1133
1134 TRACE("(%p)->(%d)\n", This, ref);
1135
1136 if (!ref)
1137 {
1138 IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
1139 FindClose(This->data.u.foldercoll.find);
1140 heap_free(This);
1141 }
1142
1143 return ref;
1144 }
1145
1146 static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file)
1147 {
1148 static const WCHAR allW[] = {'*',0};
1149 WCHAR pathW[MAX_PATH];
1150 int len;
1151 HANDLE handle;
1152
1153 strcpyW(pathW, path);
1154 len = strlenW(pathW);
1155 if (len && pathW[len-1] != '\\')
1156 strcatW(pathW, bsW);
1157 strcatW(pathW, allW);
1158 handle = FindFirstFileW(pathW, data);
1159 if (handle == INVALID_HANDLE_VALUE) return 0;
1160
1161 /* find first dir/file */
1162 while (1)
1163 {
1164 if (file ? is_file_data(data) : is_dir_data(data))
1165 break;
1166
1167 if (!FindNextFileW(handle, data))
1168 {
1169 FindClose(handle);
1170 return 0;
1171 }
1172 }
1173 return handle;
1174 }
1175
1176 static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1177 {
1178 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1179 HANDLE handle = This->data.u.foldercoll.find;
1180 WIN32_FIND_DATAW data;
1181 ULONG count = 0;
1182
1183 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1184
1185 if (fetched)
1186 *fetched = 0;
1187
1188 if (!celt) return S_OK;
1189
1190 if (!handle)
1191 {
1192 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1193 if (!handle) return S_FALSE;
1194
1195 This->data.u.foldercoll.find = handle;
1196 }
1197 else
1198 {
1199 if (!FindNextFileW(handle, &data))
1200 return S_FALSE;
1201 }
1202
1203 do
1204 {
1205 if (is_dir_data(&data))
1206 {
1207 IFolder *folder;
1208 HRESULT hr;
1209 BSTR str;
1210
1211 str = get_full_path(This->data.u.foldercoll.coll->path, &data);
1212 hr = create_folder(str, &folder);
1213 SysFreeString(str);
1214 if (FAILED(hr)) return hr;
1215
1216 V_VT(&var[count]) = VT_DISPATCH;
1217 V_DISPATCH(&var[count]) = (IDispatch*)folder;
1218 count++;
1219
1220 if (count >= celt) break;
1221 }
1222 } while (FindNextFileW(handle, &data));
1223
1224 if (fetched)
1225 *fetched = count;
1226
1227 return (count < celt) ? S_FALSE : S_OK;
1228 }
1229
1230 static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1231 {
1232 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1233 HANDLE handle = This->data.u.foldercoll.find;
1234 WIN32_FIND_DATAW data;
1235
1236 TRACE("(%p)->(%d)\n", This, celt);
1237
1238 if (!celt) return S_OK;
1239
1240 if (!handle)
1241 {
1242 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1243 if (!handle) return S_FALSE;
1244
1245 This->data.u.foldercoll.find = handle;
1246 }
1247 else
1248 {
1249 if (!FindNextFileW(handle, &data))
1250 return S_FALSE;
1251 }
1252
1253 do
1254 {
1255 if (is_dir_data(&data))
1256 --celt;
1257
1258 if (!celt) break;
1259 } while (FindNextFileW(handle, &data));
1260
1261 return celt ? S_FALSE : S_OK;
1262 }
1263
1264 static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
1265 {
1266 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1267
1268 TRACE("(%p)\n", This);
1269
1270 FindClose(This->data.u.foldercoll.find);
1271 This->data.u.foldercoll.find = NULL;
1272
1273 return S_OK;
1274 }
1275
1276 static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1277 {
1278 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1279 TRACE("(%p)->(%p)\n", This, pclone);
1280 return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
1281 }
1282
1283 static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
1284 enumvariant_QueryInterface,
1285 enumvariant_AddRef,
1286 foldercoll_enumvariant_Release,
1287 foldercoll_enumvariant_Next,
1288 foldercoll_enumvariant_Skip,
1289 foldercoll_enumvariant_Reset,
1290 foldercoll_enumvariant_Clone
1291 };
1292
1293 static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
1294 {
1295 struct enumvariant *This;
1296
1297 *newenum = NULL;
1298
1299 This = heap_alloc(sizeof(*This));
1300 if (!This) return E_OUTOFMEMORY;
1301
1302 This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
1303 This->ref = 1;
1304 This->data.u.foldercoll.find = NULL;
1305 This->data.u.foldercoll.coll = collection;
1306 IFolderCollection_AddRef(&collection->IFolderCollection_iface);
1307
1308 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1309
1310 return S_OK;
1311 }
1312
1313 static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface)
1314 {
1315 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1316 ULONG ref = InterlockedDecrement(&This->ref);
1317
1318 TRACE("(%p)->(%d)\n", This, ref);
1319
1320 if (!ref)
1321 {
1322 IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
1323 FindClose(This->data.u.filecoll.find);
1324 heap_free(This);
1325 }
1326
1327 return ref;
1328 }
1329
1330 static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1331 {
1332 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1333 HANDLE handle = This->data.u.filecoll.find;
1334 WIN32_FIND_DATAW data;
1335 ULONG count = 0;
1336
1337 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1338
1339 if (fetched)
1340 *fetched = 0;
1341
1342 if (!celt) return S_OK;
1343
1344 if (!handle)
1345 {
1346 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1347 if (!handle) return S_FALSE;
1348 This->data.u.filecoll.find = handle;
1349 }
1350 else if (!FindNextFileW(handle, &data))
1351 return S_FALSE;
1352
1353 do
1354 {
1355 if (is_file_data(&data))
1356 {
1357 IFile *file;
1358 HRESULT hr;
1359 BSTR str;
1360
1361 str = get_full_path(This->data.u.filecoll.coll->path, &data);
1362 hr = create_file(str, &file);
1363 SysFreeString(str);
1364 if (FAILED(hr)) return hr;
1365
1366 V_VT(&var[count]) = VT_DISPATCH;
1367 V_DISPATCH(&var[count]) = (IDispatch*)file;
1368 if (++count >= celt) break;
1369 }
1370 } while (FindNextFileW(handle, &data));
1371
1372 if (fetched)
1373 *fetched = count;
1374
1375 return (count < celt) ? S_FALSE : S_OK;
1376 }
1377
1378 static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1379 {
1380 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1381 HANDLE handle = This->data.u.filecoll.find;
1382 WIN32_FIND_DATAW data;
1383
1384 TRACE("(%p)->(%d)\n", This, celt);
1385
1386 if (!celt) return S_OK;
1387
1388 if (!handle)
1389 {
1390 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1391 if (!handle) return S_FALSE;
1392 This->data.u.filecoll.find = handle;
1393 }
1394 else if (!FindNextFileW(handle, &data))
1395 return S_FALSE;
1396
1397 do
1398 {
1399 if (is_file_data(&data))
1400 --celt;
1401 } while (celt && FindNextFileW(handle, &data));
1402
1403 return celt ? S_FALSE : S_OK;
1404 }
1405
1406 static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface)
1407 {
1408 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1409
1410 TRACE("(%p)\n", This);
1411
1412 FindClose(This->data.u.filecoll.find);
1413 This->data.u.filecoll.find = NULL;
1414
1415 return S_OK;
1416 }
1417
1418 static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1419 {
1420 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1421 TRACE("(%p)->(%p)\n", This, pclone);
1422 return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
1423 }
1424
1425 static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
1426 enumvariant_QueryInterface,
1427 enumvariant_AddRef,
1428 filecoll_enumvariant_Release,
1429 filecoll_enumvariant_Next,
1430 filecoll_enumvariant_Skip,
1431 filecoll_enumvariant_Reset,
1432 filecoll_enumvariant_Clone
1433 };
1434
1435 static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum)
1436 {
1437 struct enumvariant *This;
1438
1439 *newenum = NULL;
1440
1441 This = heap_alloc(sizeof(*This));
1442 if (!This) return E_OUTOFMEMORY;
1443
1444 This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
1445 This->ref = 1;
1446 This->data.u.filecoll.find = NULL;
1447 This->data.u.filecoll.coll = collection;
1448 IFileCollection_AddRef(&collection->IFileCollection_iface);
1449
1450 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1451
1452 return S_OK;
1453 }
1454
1455 static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface)
1456 {
1457 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1458 ULONG ref = InterlockedDecrement(&This->ref);
1459
1460 TRACE("(%p)->(%d)\n", This, ref);
1461
1462 if (!ref)
1463 {
1464 IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
1465 heap_free(This);
1466 }
1467
1468 return ref;
1469 }
1470
1471 static HRESULT find_next_drive(struct enumvariant *penum)
1472 {
1473 int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
1474
1475 for (; i < 32; i++)
1476 if (penum->data.u.drivecoll.coll->drives & (1 << i))
1477 {
1478 penum->data.u.drivecoll.cur = i;
1479 return S_OK;
1480 }
1481
1482 return S_FALSE;
1483 }
1484
1485 static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1486 {
1487 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1488 ULONG count = 0;
1489
1490 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1491
1492 if (fetched)
1493 *fetched = 0;
1494
1495 if (!celt) return S_OK;
1496
1497 while (find_next_drive(This) == S_OK)
1498 {
1499 IDrive *drive;
1500 HRESULT hr;
1501
1502 hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
1503 if (FAILED(hr)) return hr;
1504
1505 V_VT(&var[count]) = VT_DISPATCH;
1506 V_DISPATCH(&var[count]) = (IDispatch*)drive;
1507
1508 if (++count >= celt) break;
1509 }
1510
1511 if (fetched)
1512 *fetched = count;
1513
1514 return (count < celt) ? S_FALSE : S_OK;
1515 }
1516
1517 static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1518 {
1519 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1520
1521 TRACE("(%p)->(%d)\n", This, celt);
1522
1523 if (!celt) return S_OK;
1524
1525 while (celt && find_next_drive(This) == S_OK)
1526 celt--;
1527
1528 return celt ? S_FALSE : S_OK;
1529 }
1530
1531 static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface)
1532 {
1533 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1534
1535 TRACE("(%p)\n", This);
1536
1537 This->data.u.drivecoll.cur = -1;
1538 return S_OK;
1539 }
1540
1541 static HRESULT WINAPI drivecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1542 {
1543 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1544 FIXME("(%p)->(%p): stub\n", This, pclone);
1545 return E_NOTIMPL;
1546 }
1547
1548 static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
1549 enumvariant_QueryInterface,
1550 enumvariant_AddRef,
1551 drivecoll_enumvariant_Release,
1552 drivecoll_enumvariant_Next,
1553 drivecoll_enumvariant_Skip,
1554 drivecoll_enumvariant_Reset,
1555 drivecoll_enumvariant_Clone
1556 };
1557
1558 static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum)
1559 {
1560 struct enumvariant *This;
1561
1562 *newenum = NULL;
1563
1564 This = heap_alloc(sizeof(*This));
1565 if (!This) return E_OUTOFMEMORY;
1566
1567 This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
1568 This->ref = 1;
1569 This->data.u.drivecoll.coll = collection;
1570 This->data.u.drivecoll.cur = -1;
1571 IDriveCollection_AddRef(&collection->IDriveCollection_iface);
1572
1573 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1574
1575 return S_OK;
1576 }
1577
1578 static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
1579 {
1580 struct foldercollection *This = impl_from_IFolderCollection(iface);
1581
1582 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1583
1584 *obj = NULL;
1585
1586 if (IsEqualIID( riid, &IID_IFolderCollection ) ||
1587 IsEqualIID( riid, &IID_IDispatch ) ||
1588 IsEqualIID( riid, &IID_IUnknown ))
1589 {
1590 *obj = &This->IFolderCollection_iface;
1591 }
1592 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
1593 {
1594 *obj = &This->classinfo.IProvideClassInfo_iface;
1595 }
1596 else
1597 return E_NOINTERFACE;
1598
1599 IUnknown_AddRef((IUnknown*)*obj);
1600 return S_OK;
1601 }
1602
1603 static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
1604 {
1605 struct foldercollection *This = impl_from_IFolderCollection(iface);
1606 ULONG ref = InterlockedIncrement(&This->ref);
1607 TRACE("(%p)->(%d)\n", This, ref);
1608 return ref;
1609 }
1610
1611 static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
1612 {
1613 struct foldercollection *This = impl_from_IFolderCollection(iface);
1614 ULONG ref = InterlockedDecrement(&This->ref);
1615 TRACE("(%p)->(%d)\n", This, ref);
1616
1617 if (!ref)
1618 {
1619 SysFreeString(This->path);
1620 heap_free(This);
1621 }
1622
1623 return ref;
1624 }
1625
1626 static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
1627 {
1628 struct foldercollection *This = impl_from_IFolderCollection(iface);
1629 TRACE("(%p)->(%p)\n", This, pctinfo);
1630 *pctinfo = 1;
1631 return S_OK;
1632 }
1633
1634 static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
1635 LCID lcid, ITypeInfo **ppTInfo)
1636 {
1637 struct foldercollection *This = impl_from_IFolderCollection(iface);
1638 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1639 return get_typeinfo(IFolderCollection_tid, ppTInfo);
1640 }
1641
1642 static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
1643 LPOLESTR *rgszNames, UINT cNames,
1644 LCID lcid, DISPID *rgDispId)
1645 {
1646 struct foldercollection *This = impl_from_IFolderCollection(iface);
1647 ITypeInfo *typeinfo;
1648 HRESULT hr;
1649
1650 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1651
1652 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1653 if(SUCCEEDED(hr))
1654 {
1655 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1656 ITypeInfo_Release(typeinfo);
1657 }
1658
1659 return hr;
1660 }
1661
1662 static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
1663 REFIID riid, LCID lcid, WORD wFlags,
1664 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1665 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1666 {
1667 struct foldercollection *This = impl_from_IFolderCollection(iface);
1668 ITypeInfo *typeinfo;
1669 HRESULT hr;
1670
1671 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1672 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1673
1674 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1675 if(SUCCEEDED(hr))
1676 {
1677 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1678 pDispParams, pVarResult, pExcepInfo, puArgErr);
1679 ITypeInfo_Release(typeinfo);
1680 }
1681
1682 return hr;
1683 }
1684
1685 static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
1686 {
1687 struct foldercollection *This = impl_from_IFolderCollection(iface);
1688 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
1689 return E_NOTIMPL;
1690 }
1691
1692 static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
1693 {
1694 struct foldercollection *This = impl_from_IFolderCollection(iface);
1695 FIXME("(%p)->(%p): stub\n", This, folder);
1696 return E_NOTIMPL;
1697 }
1698
1699 static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
1700 {
1701 struct foldercollection *This = impl_from_IFolderCollection(iface);
1702
1703 TRACE("(%p)->(%p)\n", This, newenum);
1704
1705 if(!newenum)
1706 return E_POINTER;
1707
1708 return create_foldercoll_enum(This, newenum);
1709 }
1710
1711 static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
1712 {
1713 struct foldercollection *This = impl_from_IFolderCollection(iface);
1714 static const WCHAR allW[] = {'\\','*',0};
1715 WIN32_FIND_DATAW data;
1716 WCHAR pathW[MAX_PATH];
1717 HANDLE handle;
1718
1719 TRACE("(%p)->(%p)\n", This, count);
1720
1721 if(!count)
1722 return E_POINTER;
1723
1724 *count = 0;
1725
1726 strcpyW(pathW, This->path);
1727 strcatW(pathW, allW);
1728 handle = FindFirstFileW(pathW, &data);
1729 if (handle == INVALID_HANDLE_VALUE)
1730 return HRESULT_FROM_WIN32(GetLastError());
1731
1732 do
1733 {
1734 if (is_dir_data(&data))
1735 *count += 1;
1736 } while (FindNextFileW(handle, &data));
1737 FindClose(handle);
1738
1739 return S_OK;
1740 }
1741
1742 static const IFolderCollectionVtbl foldercollvtbl = {
1743 foldercoll_QueryInterface,
1744 foldercoll_AddRef,
1745 foldercoll_Release,
1746 foldercoll_GetTypeInfoCount,
1747 foldercoll_GetTypeInfo,
1748 foldercoll_GetIDsOfNames,
1749 foldercoll_Invoke,
1750 foldercoll_Add,
1751 foldercoll_get_Item,
1752 foldercoll_get__NewEnum,
1753 foldercoll_get_Count
1754 };
1755
1756 static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
1757 {
1758 struct foldercollection *This;
1759
1760 *folders = NULL;
1761
1762 This = heap_alloc(sizeof(struct foldercollection));
1763 if (!This) return E_OUTOFMEMORY;
1764
1765 This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
1766 This->ref = 1;
1767 This->path = SysAllocString(path);
1768 if (!This->path)
1769 {
1770 heap_free(This);
1771 return E_OUTOFMEMORY;
1772 }
1773
1774 init_classinfo(&CLSID_Folders, (IUnknown *)&This->IFolderCollection_iface, &This->classinfo);
1775 *folders = &This->IFolderCollection_iface;
1776
1777 return S_OK;
1778 }
1779
1780 static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj)
1781 {
1782 struct filecollection *This = impl_from_IFileCollection(iface);
1783
1784 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1785
1786 *obj = NULL;
1787
1788 if (IsEqualIID( riid, &IID_IFileCollection ) ||
1789 IsEqualIID( riid, &IID_IDispatch ) ||
1790 IsEqualIID( riid, &IID_IUnknown ))
1791 {
1792 *obj = &This->IFileCollection_iface;
1793 }
1794 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
1795 {
1796 *obj = &This->classinfo.IProvideClassInfo_iface;
1797 }
1798 else
1799 return E_NOINTERFACE;
1800
1801 IUnknown_AddRef((IUnknown*)*obj);
1802 return S_OK;
1803 }
1804
1805 static ULONG WINAPI filecoll_AddRef(IFileCollection *iface)
1806 {
1807 struct filecollection *This = impl_from_IFileCollection(iface);
1808 ULONG ref = InterlockedIncrement(&This->ref);
1809 TRACE("(%p)->(%d)\n", This, ref);
1810 return ref;
1811 }
1812
1813 static ULONG WINAPI filecoll_Release(IFileCollection *iface)
1814 {
1815 struct filecollection *This = impl_from_IFileCollection(iface);
1816 ULONG ref = InterlockedDecrement(&This->ref);
1817 TRACE("(%p)->(%d)\n", This, ref);
1818
1819 if (!ref)
1820 {
1821 SysFreeString(This->path);
1822 heap_free(This);
1823 }
1824
1825 return ref;
1826 }
1827
1828 static HRESULT WINAPI filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo)
1829 {
1830 struct filecollection *This = impl_from_IFileCollection(iface);
1831 TRACE("(%p)->(%p)\n", This, pctinfo);
1832 *pctinfo = 1;
1833 return S_OK;
1834 }
1835
1836 static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo,
1837 LCID lcid, ITypeInfo **ppTInfo)
1838 {
1839 struct filecollection *This = impl_from_IFileCollection(iface);
1840 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1841 return get_typeinfo(IFileCollection_tid, ppTInfo);
1842 }
1843
1844 static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid,
1845 LPOLESTR *rgszNames, UINT cNames,
1846 LCID lcid, DISPID *rgDispId)
1847 {
1848 struct filecollection *This = impl_from_IFileCollection(iface);
1849 ITypeInfo *typeinfo;
1850 HRESULT hr;
1851
1852 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1853
1854 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1855 if(SUCCEEDED(hr))
1856 {
1857 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1858 ITypeInfo_Release(typeinfo);
1859 }
1860
1861 return hr;
1862 }
1863
1864 static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember,
1865 REFIID riid, LCID lcid, WORD wFlags,
1866 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1867 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1868 {
1869 struct filecollection *This = impl_from_IFileCollection(iface);
1870 ITypeInfo *typeinfo;
1871 HRESULT hr;
1872
1873 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1874 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1875
1876 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1877 if(SUCCEEDED(hr))
1878 {
1879 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1880 pDispParams, pVarResult, pExcepInfo, puArgErr);
1881 ITypeInfo_Release(typeinfo);
1882 }
1883
1884 return hr;
1885 }
1886
1887 static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file)
1888 {
1889 struct filecollection *This = impl_from_IFileCollection(iface);
1890 FIXME("(%p)->(%p)\n", This, file);
1891 return E_NOTIMPL;
1892 }
1893
1894 static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum)
1895 {
1896 struct filecollection *This = impl_from_IFileCollection(iface);
1897
1898 TRACE("(%p)->(%p)\n", This, ppenum);
1899
1900 if(!ppenum)
1901 return E_POINTER;
1902
1903 return create_filecoll_enum(This, ppenum);
1904 }
1905
1906 static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count)
1907 {
1908 struct filecollection *This = impl_from_IFileCollection(iface);
1909 static const WCHAR allW[] = {'\\','*',0};
1910 WIN32_FIND_DATAW data;
1911 WCHAR pathW[MAX_PATH];
1912 HANDLE handle;
1913
1914 TRACE("(%p)->(%p)\n", This, count);
1915
1916 if(!count)
1917 return E_POINTER;
1918
1919 *count = 0;
1920
1921 strcpyW(pathW, This->path);
1922 strcatW(pathW, allW);
1923 handle = FindFirstFileW(pathW, &data);
1924 if (handle == INVALID_HANDLE_VALUE)
1925 return HRESULT_FROM_WIN32(GetLastError());
1926
1927 do
1928 {
1929 if (is_file_data(&data))
1930 *count += 1;
1931 } while (FindNextFileW(handle, &data));
1932 FindClose(handle);
1933
1934 return S_OK;
1935 }
1936
1937 static const IFileCollectionVtbl filecollectionvtbl = {
1938 filecoll_QueryInterface,
1939 filecoll_AddRef,
1940 filecoll_Release,
1941 filecoll_GetTypeInfoCount,
1942 filecoll_GetTypeInfo,
1943 filecoll_GetIDsOfNames,
1944 filecoll_Invoke,
1945 filecoll_get_Item,
1946 filecoll_get__NewEnum,
1947 filecoll_get_Count
1948 };
1949
1950 static HRESULT create_filecoll(BSTR path, IFileCollection **files)
1951 {
1952 struct filecollection *This;
1953
1954 *files = NULL;
1955
1956 This = heap_alloc(sizeof(*This));
1957 if (!This) return E_OUTOFMEMORY;
1958
1959 This->IFileCollection_iface.lpVtbl = &filecollectionvtbl;
1960 This->ref = 1;
1961 This->path = SysAllocString(path);
1962 if (!This->path)
1963 {
1964 heap_free(This);
1965 return E_OUTOFMEMORY;
1966 }
1967
1968 init_classinfo(&CLSID_Files, (IUnknown *)&This->IFileCollection_iface, &This->classinfo);
1969 *files = &This->IFileCollection_iface;
1970 return S_OK;
1971 }
1972
1973 static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
1974 {
1975 struct drivecollection *This = impl_from_IDriveCollection(iface);
1976
1977 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1978
1979 *obj = NULL;
1980
1981 if (IsEqualIID( riid, &IID_IDriveCollection ) ||
1982 IsEqualIID( riid, &IID_IDispatch ) ||
1983 IsEqualIID( riid, &IID_IUnknown ))
1984 {
1985 *obj = &This->IDriveCollection_iface;
1986 }
1987 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
1988 {
1989 *obj = &This->classinfo.IProvideClassInfo_iface;
1990 }
1991 else
1992 return E_NOINTERFACE;
1993
1994 IUnknown_AddRef((IUnknown*)*obj);
1995 return S_OK;
1996 }
1997
1998 static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
1999 {
2000 struct drivecollection *This = impl_from_IDriveCollection(iface);
2001 ULONG ref = InterlockedIncrement(&This->ref);
2002 TRACE("(%p)->(%d)\n", This, ref);
2003 return ref;
2004 }
2005
2006 static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
2007 {
2008 struct drivecollection *This = impl_from_IDriveCollection(iface);
2009 ULONG ref = InterlockedDecrement(&This->ref);
2010 TRACE("(%p)->(%d)\n", This, ref);
2011
2012 if (!ref)
2013 heap_free(This);
2014
2015 return ref;
2016 }
2017
2018 static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
2019 {
2020 struct drivecollection *This = impl_from_IDriveCollection(iface);
2021 TRACE("(%p)->(%p)\n", This, pctinfo);
2022 *pctinfo = 1;
2023 return S_OK;
2024 }
2025
2026 static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
2027 LCID lcid, ITypeInfo **ppTInfo)
2028 {
2029 struct drivecollection *This = impl_from_IDriveCollection(iface);
2030 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2031 return get_typeinfo(IDriveCollection_tid, ppTInfo);
2032 }
2033
2034 static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
2035 LPOLESTR *rgszNames, UINT cNames,
2036 LCID lcid, DISPID *rgDispId)
2037 {
2038 struct drivecollection *This = impl_from_IDriveCollection(iface);
2039 ITypeInfo *typeinfo;
2040 HRESULT hr;
2041
2042 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2043
2044 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2045 if(SUCCEEDED(hr))
2046 {
2047 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2048 ITypeInfo_Release(typeinfo);
2049 }
2050
2051 return hr;
2052 }
2053
2054 static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
2055 REFIID riid, LCID lcid, WORD wFlags,
2056 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2057 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2058 {
2059 struct drivecollection *This = impl_from_IDriveCollection(iface);
2060 ITypeInfo *typeinfo;
2061 HRESULT hr;
2062
2063 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2064 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2065
2066 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2067 if(SUCCEEDED(hr))
2068 {
2069 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2070 pDispParams, pVarResult, pExcepInfo, puArgErr);
2071 ITypeInfo_Release(typeinfo);
2072 }
2073
2074 return hr;
2075 }
2076
2077 static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
2078 {
2079 struct drivecollection *This = impl_from_IDriveCollection(iface);
2080 FIXME("(%p)->(%p): stub\n", This, drive);
2081 return E_NOTIMPL;
2082 }
2083
2084 static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
2085 {
2086 struct drivecollection *This = impl_from_IDriveCollection(iface);
2087
2088 TRACE("(%p)->(%p)\n", This, ppenum);
2089
2090 if(!ppenum)
2091 return E_POINTER;
2092
2093 return create_drivecoll_enum(This, ppenum);
2094 }
2095
2096 static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
2097 {
2098 struct drivecollection *This = impl_from_IDriveCollection(iface);
2099
2100 TRACE("(%p)->(%p)\n", This, count);
2101
2102 if (!count) return E_POINTER;
2103
2104 *count = This->count;
2105 return S_OK;
2106 }
2107
2108 static const IDriveCollectionVtbl drivecollectionvtbl = {
2109 drivecoll_QueryInterface,
2110 drivecoll_AddRef,
2111 drivecoll_Release,
2112 drivecoll_GetTypeInfoCount,
2113 drivecoll_GetTypeInfo,
2114 drivecoll_GetIDsOfNames,
2115 drivecoll_Invoke,
2116 drivecoll_get_Item,
2117 drivecoll_get__NewEnum,
2118 drivecoll_get_Count
2119 };
2120
2121 static HRESULT create_drivecoll(IDriveCollection **drives)
2122 {
2123 struct drivecollection *This;
2124 DWORD mask;
2125
2126 *drives = NULL;
2127
2128 This = heap_alloc(sizeof(*This));
2129 if (!This) return E_OUTOFMEMORY;
2130
2131 This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl;
2132 This->ref = 1;
2133 This->drives = mask = GetLogicalDrives();
2134 /* count set bits */
2135 for (This->count = 0; mask; This->count++)
2136 mask &= mask - 1;
2137
2138 init_classinfo(&CLSID_Drives, (IUnknown *)&This->IDriveCollection_iface, &This->classinfo);
2139 *drives = &This->IDriveCollection_iface;
2140 return S_OK;
2141 }
2142
2143 static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
2144 {
2145 struct folder *This = impl_from_IFolder(iface);
2146
2147 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2148
2149 *obj = NULL;
2150
2151 if (IsEqualIID( riid, &IID_IFolder ) ||
2152 IsEqualIID( riid, &IID_IDispatch ) ||
2153 IsEqualIID( riid, &IID_IUnknown))
2154 {
2155 *obj = &This->IFolder_iface;
2156 }
2157 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2158 {
2159 *obj = &This->classinfo.IProvideClassInfo_iface;
2160 }
2161 else
2162 return E_NOINTERFACE;
2163
2164 IUnknown_AddRef((IUnknown*)*obj);
2165 return S_OK;
2166 }
2167
2168 static ULONG WINAPI folder_AddRef(IFolder *iface)
2169 {
2170 struct folder *This = impl_from_IFolder(iface);
2171 ULONG ref = InterlockedIncrement(&This->ref);
2172 TRACE("(%p)->(%d)\n", This, ref);
2173 return ref;
2174 }
2175
2176 static ULONG WINAPI folder_Release(IFolder *iface)
2177 {
2178 struct folder *This = impl_from_IFolder(iface);
2179 ULONG ref = InterlockedDecrement(&This->ref);
2180 TRACE("(%p)->(%d)\n", This, ref);
2181
2182 if (!ref)
2183 {
2184 SysFreeString(This->path);
2185 heap_free(This);
2186 }
2187
2188 return ref;
2189 }
2190
2191 static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
2192 {
2193 struct folder *This = impl_from_IFolder(iface);
2194 TRACE("(%p)->(%p)\n", This, pctinfo);
2195 *pctinfo = 1;
2196 return S_OK;
2197 }
2198
2199 static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
2200 LCID lcid, ITypeInfo **ppTInfo)
2201 {
2202 struct folder *This = impl_from_IFolder(iface);
2203 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2204 return get_typeinfo(IFolder_tid, ppTInfo);
2205 }
2206
2207 static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
2208 LPOLESTR *rgszNames, UINT cNames,
2209 LCID lcid, DISPID *rgDispId)
2210 {
2211 struct folder *This = impl_from_IFolder(iface);
2212 ITypeInfo *typeinfo;
2213 HRESULT hr;
2214
2215 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2216
2217 hr = get_typeinfo(IFolder_tid, &typeinfo);
2218 if(SUCCEEDED(hr))
2219 {
2220 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2221 ITypeInfo_Release(typeinfo);
2222 }
2223
2224 return hr;
2225 }
2226
2227 static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
2228 REFIID riid, LCID lcid, WORD wFlags,
2229 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2230 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2231 {
2232 struct folder *This = impl_from_IFolder(iface);
2233 ITypeInfo *typeinfo;
2234 HRESULT hr;
2235
2236 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2237 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2238
2239 hr = get_typeinfo(IFolder_tid, &typeinfo);
2240 if(SUCCEEDED(hr))
2241 {
2242 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2243 pDispParams, pVarResult, pExcepInfo, puArgErr);
2244 ITypeInfo_Release(typeinfo);
2245 }
2246
2247 return hr;
2248 }
2249
2250 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
2251 {
2252 struct folder *This = impl_from_IFolder(iface);
2253
2254 TRACE("(%p)->(%p)\n", This, path);
2255
2256 if(!path)
2257 return E_POINTER;
2258
2259 *path = SysAllocString(This->path);
2260 return *path ? S_OK : E_OUTOFMEMORY;
2261 }
2262
2263 static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
2264 {
2265 struct folder *This = impl_from_IFolder(iface);
2266 WCHAR *ptr;
2267
2268 TRACE("(%p)->(%p)\n", This, name);
2269
2270 if(!name)
2271 return E_POINTER;
2272
2273 *name = NULL;
2274
2275 ptr = strrchrW(This->path, '\\');
2276 if (ptr)
2277 {
2278 *name = SysAllocString(ptr+1);
2279 TRACE("%s\n", debugstr_w(*name));
2280 if (!*name) return E_OUTOFMEMORY;
2281 }
2282 else
2283 return E_FAIL;
2284
2285 return S_OK;
2286 }
2287
2288 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
2289 {
2290 struct folder *This = impl_from_IFolder(iface);
2291 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
2292 return E_NOTIMPL;
2293 }
2294
2295 static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
2296 {
2297 struct folder *This = impl_from_IFolder(iface);
2298 FIXME("(%p)->(%p): stub\n", This, path);
2299 return E_NOTIMPL;
2300 }
2301
2302 static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
2303 {
2304 struct folder *This = impl_from_IFolder(iface);
2305 FIXME("(%p)->(%p): stub\n", This, name);
2306 return E_NOTIMPL;
2307 }
2308
2309 static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
2310 {
2311 struct folder *This = impl_from_IFolder(iface);
2312 FIXME("(%p)->(%p): stub\n", This, drive);
2313 return E_NOTIMPL;
2314 }
2315
2316 static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
2317 {
2318 struct folder *This = impl_from_IFolder(iface);
2319 FIXME("(%p)->(%p): stub\n", This, parent);
2320 return E_NOTIMPL;
2321 }
2322
2323 static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
2324 {
2325 struct folder *This = impl_from_IFolder(iface);
2326 FIXME("(%p)->(%p): stub\n", This, attr);
2327 return E_NOTIMPL;
2328 }
2329
2330 static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
2331 {
2332 struct folder *This = impl_from_IFolder(iface);
2333 FIXME("(%p)->(0x%x): stub\n", This, attr);
2334 return E_NOTIMPL;
2335 }
2336
2337 static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
2338 {
2339 struct folder *This = impl_from_IFolder(iface);
2340 FIXME("(%p)->(%p): stub\n", This, date);
2341 return E_NOTIMPL;
2342 }
2343
2344 static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
2345 {
2346 struct folder *This = impl_from_IFolder(iface);
2347 FIXME("(%p)->(%p): stub\n", This, date);
2348 return E_NOTIMPL;
2349 }
2350
2351 static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
2352 {
2353 struct folder *This = impl_from_IFolder(iface);
2354 FIXME("(%p)->(%p): stub\n", This, date);
2355 return E_NOTIMPL;
2356 }
2357
2358 static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
2359 {
2360 struct folder *This = impl_from_IFolder(iface);
2361 FIXME("(%p)->(%p): stub\n", This, type);
2362 return E_NOTIMPL;
2363 }
2364
2365 static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
2366 {
2367 struct folder *This = impl_from_IFolder(iface);
2368 FIXME("(%p)->(%x): stub\n", This, force);
2369 return E_NOTIMPL;
2370 }
2371
2372 static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
2373 {
2374 struct folder *This = impl_from_IFolder(iface);
2375 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
2376 return E_NOTIMPL;
2377 }
2378
2379 static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
2380 {
2381 struct folder *This = impl_from_IFolder(iface);
2382 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
2383 return E_NOTIMPL;
2384 }
2385
2386 static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
2387 {
2388 struct folder *This = impl_from_IFolder(iface);
2389 FIXME("(%p)->(%p): stub\n", This, isroot);
2390 return E_NOTIMPL;
2391 }
2392
2393 static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
2394 {
2395 struct folder *This = impl_from_IFolder(iface);
2396 FIXME("(%p)->(%p): stub\n", This, size);
2397 return E_NOTIMPL;
2398 }
2399
2400 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
2401 {
2402 struct folder *This = impl_from_IFolder(iface);
2403
2404 TRACE("(%p)->(%p)\n", This, folders);
2405
2406 if(!folders)
2407 return E_POINTER;
2408
2409 return create_foldercoll(This->path, folders);
2410 }
2411
2412 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
2413 {
2414 struct folder *This = impl_from_IFolder(iface);
2415
2416 TRACE("(%p)->(%p)\n", This, files);
2417
2418 if(!files)
2419 return E_POINTER;
2420
2421 return create_filecoll(This->path, files);
2422 }
2423
2424 static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
2425 VARIANT_BOOL unicode, ITextStream **stream)
2426 {
2427 struct folder *This = impl_from_IFolder(iface);
2428 FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
2429 return E_NOTIMPL;
2430 }
2431
2432 static const IFolderVtbl foldervtbl = {
2433 folder_QueryInterface,
2434 folder_AddRef,
2435 folder_Release,
2436 folder_GetTypeInfoCount,
2437 folder_GetTypeInfo,
2438 folder_GetIDsOfNames,
2439 folder_Invoke,
2440 folder_get_Path,
2441 folder_get_Name,
2442 folder_put_Name,
2443 folder_get_ShortPath,
2444 folder_get_ShortName,
2445 folder_get_Drive,
2446 folder_get_ParentFolder,
2447 folder_get_Attributes,
2448 folder_put_Attributes,
2449 folder_get_DateCreated,
2450 folder_get_DateLastModified,
2451 folder_get_DateLastAccessed,
2452 folder_get_Type,
2453 folder_Delete,
2454 folder_Copy,
2455 folder_Move,
2456 folder_get_IsRootFolder,
2457 folder_get_Size,
2458 folder_get_SubFolders,
2459 folder_get_Files,
2460 folder_CreateTextFile
2461 };
2462
2463 HRESULT create_folder(const WCHAR *path, IFolder **folder)
2464 {
2465 struct folder *This;
2466
2467 *folder = NULL;
2468
2469 TRACE("%s\n", debugstr_w(path));
2470
2471 This = heap_alloc(sizeof(struct folder));
2472 if (!This) return E_OUTOFMEMORY;
2473
2474 This->IFolder_iface.lpVtbl = &foldervtbl;
2475 This->ref = 1;
2476 This->path = SysAllocString(path);
2477 if (!This->path)
2478 {
2479 heap_free(This);
2480 return E_OUTOFMEMORY;
2481 }
2482
2483 init_classinfo(&CLSID_Folder, (IUnknown *)&This->IFolder_iface, &This->classinfo);
2484 *folder = &This->IFolder_iface;
2485
2486 return S_OK;
2487 }
2488
2489 static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
2490 {
2491 struct file *This = impl_from_IFile(iface);
2492
2493 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2494
2495 *obj = NULL;
2496
2497 if (IsEqualIID(riid, &IID_IFile) ||
2498 IsEqualIID(riid, &IID_IDispatch) ||
2499 IsEqualIID(riid, &IID_IUnknown))
2500 {
2501 *obj = &This->IFile_iface;
2502 }
2503 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2504 {
2505 *obj = &This->classinfo.IProvideClassInfo_iface;
2506 }
2507 else
2508 return E_NOINTERFACE;
2509
2510 IUnknown_AddRef((IUnknown*)*obj);
2511 return S_OK;
2512 }
2513
2514 static ULONG WINAPI file_AddRef(IFile *iface)
2515 {
2516 struct file *This = impl_from_IFile(iface);
2517 LONG ref = InterlockedIncrement(&This->ref);
2518
2519 TRACE("(%p) ref=%d\n", This, ref);
2520
2521 return ref;
2522 }
2523
2524 static ULONG WINAPI file_Release(IFile *iface)
2525 {
2526 struct file *This = impl_from_IFile(iface);
2527 LONG ref = InterlockedDecrement(&This->ref);
2528
2529 TRACE("(%p) ref=%d\n", This, ref);
2530
2531 if(!ref)
2532 {
2533 heap_free(This->path);
2534 heap_free(This);
2535 }
2536
2537 return ref;
2538 }
2539
2540 static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
2541 {
2542 struct file *This = impl_from_IFile(iface);
2543
2544 TRACE("(%p)->(%p)\n", This, pctinfo);
2545
2546 *pctinfo = 1;
2547 return S_OK;
2548 }
2549
2550 static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
2551 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
2552 {
2553 struct file *This = impl_from_IFile(iface);
2554
2555 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2556
2557 return get_typeinfo(IFile_tid, ppTInfo);
2558 }
2559
2560 static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
2561 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2562 {
2563 struct file *This = impl_from_IFile(iface);
2564 ITypeInfo *typeinfo;
2565 HRESULT hr;
2566
2567 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
2568 rgszNames, cNames, lcid, rgDispId);
2569
2570 hr = get_typeinfo(IFile_tid, &typeinfo);
2571 if(SUCCEEDED(hr)) {
2572 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2573 ITypeInfo_Release(typeinfo);
2574 }
2575 return hr;
2576 }
2577
2578 static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2579 {
2580 struct file *This = impl_from_IFile(iface);
2581 ITypeInfo *typeinfo;
2582 HRESULT hr;
2583
2584 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2585 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2586
2587 hr = get_typeinfo(IFile_tid, &typeinfo);
2588 if(SUCCEEDED(hr))
2589 {
2590 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2591 pDispParams, pVarResult, pExcepInfo, puArgErr);
2592 ITypeInfo_Release(typeinfo);
2593 }
2594 return hr;
2595 }
2596
2597 static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *path)
2598 {
2599 struct file *This = impl_from_IFile(iface);
2600
2601 TRACE("(%p)->(%p)\n", This, path);
2602
2603 if (!path)
2604 return E_POINTER;
2605
2606 *path = SysAllocString(This->path);
2607 if (!*path)
2608 return E_OUTOFMEMORY;
2609
2610 return S_OK;
2611 }
2612
2613 static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
2614 {
2615 struct file *This = impl_from_IFile(iface);
2616 WCHAR *ptr;
2617
2618 TRACE("(%p)->(%p)\n", This, name);
2619
2620 if(!name)
2621 return E_POINTER;
2622
2623 *name = NULL;
2624
2625 ptr = strrchrW(This->path, '\\');
2626 if (ptr)
2627 {
2628 *name = SysAllocString(ptr+1);
2629 TRACE("%s\n", debugstr_w(*name));
2630 if (!*name) return E_OUTOFMEMORY;
2631 }
2632 else
2633 return E_FAIL;
2634
2635 return S_OK;
2636 }
2637
2638 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
2639 {
2640 struct file *This = impl_from_IFile(iface);
2641 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
2642 return E_NOTIMPL;
2643 }
2644
2645 static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
2646 {
2647 struct file *This = impl_from_IFile(iface);
2648 FIXME("(%p)->(%p)\n", This, pbstrPath);
2649 return E_NOTIMPL;
2650 }
2651
2652 static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
2653 {
2654 struct file *This = impl_from_IFile(iface);
2655 FIXME("(%p)->(%p)\n", This, pbstrName);
2656 return E_NOTIMPL;
2657 }
2658
2659 static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
2660 {
2661 struct file *This = impl_from_IFile(iface);
2662 FIXME("(%p)->(%p)\n", This, ppdrive);
2663 return E_NOTIMPL;
2664 }
2665
2666 static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
2667 {
2668 struct file *This = impl_from_IFile(iface);
2669 FIXME("(%p)->(%p)\n", This, ppfolder);
2670 return E_NOTIMPL;
2671 }
2672
2673 static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
2674 {
2675 struct file *This = impl_from_IFile(iface);
2676 DWORD fa;
2677
2678 TRACE("(%p)->(%p)\n", This, pfa);
2679
2680 if(!pfa)
2681 return E_POINTER;
2682
2683 fa = GetFileAttributesW(This->path);
2684 if(fa == INVALID_FILE_ATTRIBUTES)
2685 return create_error(GetLastError());
2686
2687 *pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2688 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
2689 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
2690 return S_OK;
2691 }
2692
2693 static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
2694 {
2695 struct file *This = impl_from_IFile(iface);
2696
2697 TRACE("(%p)->(%x)\n", This, pfa);
2698
2699 return SetFileAttributesW(This->path, pfa) ? S_OK : create_error(GetLastError());
2700 }
2701
2702 static HRESULT get_date_from_filetime(const FILETIME *ft, DATE *date)
2703 {
2704 FILETIME ftlocal;
2705 SYSTEMTIME st;
2706
2707 if (!date)
2708 return E_POINTER;
2709
2710 FileTimeToLocalFileTime(ft, &ftlocal);
2711 FileTimeToSystemTime(&ftlocal, &st);
2712 SystemTimeToVariantTime(&st, date);
2713
2714 return S_OK;
2715 }
2716
2717 static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
2718 {
2719 struct file *This = impl_from_IFile(iface);
2720 FIXME("(%p)->(%p)\n", This, pdate);
2721 return E_NOTIMPL;
2722 }
2723
2724 static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *date)
2725 {
2726 struct file *This = impl_from_IFile(iface);
2727 WIN32_FILE_ATTRIBUTE_DATA attrs;
2728
2729 TRACE("(%p)->(%p)\n", This, date);
2730
2731 if (GetFileAttributesExW(This->path, GetFileExInfoStandard, &attrs))
2732 return get_date_from_filetime(&attrs.ftLastWriteTime, date);
2733
2734 return E_FAIL;
2735 }
2736
2737 static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
2738 {
2739 struct file *This = impl_from_IFile(iface);
2740 FIXME("(%p)->(%p)\n", This, pdate);
2741 return E_NOTIMPL;
2742 }
2743
2744 static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
2745 {
2746 struct file *This = impl_from_IFile(iface);
2747 ULARGE_INTEGER size;
2748 WIN32_FIND_DATAW fd;
2749 HANDLE f;
2750
2751 TRACE("(%p)->(%p)\n", This, pvarSize);
2752
2753 if(!pvarSize)
2754 return E_POINTER;
2755
2756 f = FindFirstFileW(This->path, &fd);
2757 if(f == INVALID_HANDLE_VALUE)
2758 return create_error(GetLastError());
2759 FindClose(f);
2760
2761 size.u.LowPart = fd.nFileSizeLow;
2762 size.u.HighPart = fd.nFileSizeHigh;
2763
2764 return variant_from_largeint(&size, pvarSize);
2765 }
2766
2767 static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
2768 {
2769 struct file *This = impl_from_IFile(iface);
2770 FIXME("(%p)->(%p)\n", This, pbstrType);
2771 return E_NOTIMPL;
2772 }
2773
2774 static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
2775 {
2776 struct file *This = impl_from_IFile(iface);
2777 FIXME("(%p)->(%x)\n", This, Force);
2778 return E_NOTIMPL;
2779 }
2780
2781 static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
2782 {
2783 struct file *This = impl_from_IFile(iface);
2784 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
2785 return E_NOTIMPL;
2786 }
2787
2788 static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
2789 {
2790 struct file *This = impl_from_IFile(iface);
2791 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
2792 return E_NOTIMPL;
2793 }
2794
2795 static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode mode, Tristate format, ITextStream **stream)
2796 {
2797 struct file *This = impl_from_IFile(iface);
2798
2799 TRACE("(%p)->(%d %d %p)\n", This, mode, format, stream);
2800
2801 if (format == TristateUseDefault) {
2802 FIXME("default format not handled, defaulting to unicode\n");
2803 format = TristateTrue;
2804 }
2805
2806 return create_textstream(This->path, OPEN_EXISTING, mode, format == TristateTrue, stream);
2807 }
2808
2809 static const IFileVtbl file_vtbl = {
2810 file_QueryInterface,
2811 file_AddRef,
2812 file_Release,
2813 file_GetTypeInfoCount,
2814 file_GetTypeInfo,
2815 file_GetIDsOfNames,
2816 file_Invoke,
2817 file_get_Path,
2818 file_get_Name,
2819 file_put_Name,
2820 file_get_ShortPath,
2821 file_get_ShortName,
2822 file_get_Drive,
2823 file_get_ParentFolder,
2824 file_get_Attributes,
2825 file_put_Attributes,
2826 file_get_DateCreated,
2827 file_get_DateLastModified,
2828 file_get_DateLastAccessed,
2829 file_get_Size,
2830 file_get_Type,
2831 file_Delete,
2832 file_Copy,
2833 file_Move,
2834 file_OpenAsTextStream
2835 };
2836
2837 static HRESULT create_file(BSTR path, IFile **file)
2838 {
2839 struct file *f;
2840 DWORD len, attrs;
2841
2842 *file = NULL;
2843
2844 f = heap_alloc(sizeof(struct file));
2845 if(!f)
2846 return E_OUTOFMEMORY;
2847
2848 f->IFile_iface.lpVtbl = &file_vtbl;
2849 f->ref = 1;
2850
2851 len = GetFullPathNameW(path, 0, NULL, NULL);
2852 if(!len) {
2853 heap_free(f);
2854 return E_FAIL;
2855 }
2856
2857 f->path = heap_alloc(len*sizeof(WCHAR));
2858 if(!f->path) {
2859 heap_free(f);
2860 return E_OUTOFMEMORY;
2861 }
2862
2863 if(!GetFullPathNameW(path, len, f->path, NULL)) {
2864 heap_free(f->path);
2865 heap_free(f);
2866 return E_FAIL;
2867 }
2868
2869 attrs = GetFileAttributesW(f->path);
2870 if(attrs==INVALID_FILE_ATTRIBUTES ||
2871 (attrs&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))) {
2872 heap_free(f->path);
2873 heap_free(f);
2874 return create_error(GetLastError());
2875 }
2876
2877 init_classinfo(&CLSID_File, (IUnknown *)&f->IFile_iface, &f->classinfo);
2878 *file = &f->IFile_iface;
2879 return S_OK;
2880 }
2881
2882 static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
2883 {
2884 struct filesystem *This = impl_from_IFileSystem3(iface);
2885
2886 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
2887
2888 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
2889 IsEqualGUID( riid, &IID_IFileSystem ) ||
2890 IsEqualGUID( riid, &IID_IDispatch ) ||
2891 IsEqualGUID( riid, &IID_IUnknown ) )
2892 {
2893 *ppvObject = &This->IFileSystem3_iface;
2894 }
2895 else if (IsEqualGUID( riid, &IID_IProvideClassInfo ))
2896 {
2897 *ppvObject = &This->classinfo.IProvideClassInfo_iface;
2898 }
2899 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
2900 {
2901 TRACE("Interface IDispatchEx not supported - returning NULL\n");
2902 *ppvObject = NULL;
2903 return E_NOINTERFACE;
2904 }
2905 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
2906 {
2907 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
2908 *ppvObject = NULL;
2909 return E_NOINTERFACE;
2910 }
2911 else
2912 {
2913 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
2914 return E_NOINTERFACE;
2915 }
2916
2917 IUnknown_AddRef((IUnknown*)*ppvObject);
2918
2919 return S_OK;
2920 }
2921
2922 static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
2923 {
2924 TRACE("%p\n", iface);
2925
2926 return 2;
2927 }
2928
2929 static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
2930 {
2931 TRACE("%p\n", iface);
2932
2933 return 1;
2934 }
2935
2936 static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
2937 {
2938 TRACE("(%p)->(%p)\n", iface, pctinfo);
2939
2940 *pctinfo = 1;
2941 return S_OK;
2942 }
2943
2944 static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
2945 LCID lcid, ITypeInfo **ppTInfo)
2946 {
2947 TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
2948 return get_typeinfo(IFileSystem3_tid, ppTInfo);
2949 }
2950
2951 static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
2952 LPOLESTR *rgszNames, UINT cNames,
2953 LCID lcid, DISPID *rgDispId)
2954 {
2955 ITypeInfo *typeinfo;
2956 HRESULT hr;
2957
2958 TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2959
2960 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2961 if(SUCCEEDED(hr))
2962 {
2963 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2964 ITypeInfo_Release(typeinfo);
2965 }
2966
2967 return hr;
2968 }
2969
2970 static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
2971 REFIID riid, LCID lcid, WORD wFlags,
2972 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2973 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2974 {
2975 ITypeInfo *typeinfo;
2976 HRESULT hr;
2977
2978 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
2979 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2980
2981 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2982 if(SUCCEEDED(hr))
2983 {
2984 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2985 pDispParams, pVarResult, pExcepInfo, puArgErr);
2986 ITypeInfo_Release(typeinfo);
2987 }
2988
2989 return hr;
2990 }
2991
2992 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
2993 {
2994 TRACE("%p %p\n", iface, ppdrives);
2995 return create_drivecoll(ppdrives);
2996 }
2997
2998 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
2999 BSTR Name, BSTR *Result)
3000 {
3001 BSTR ret;
3002
3003 TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
3004
3005 if (!Result) return E_POINTER;
3006
3007 if (Path && Name)
3008 {
3009 int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
3010
3011 /* if both parts have backslashes strip one from Path */
3012 if (Path[path_len-1] == '\\' && Name[0] == '\\')
3013 {
3014 path_len -= 1;
3015
3016 ret = SysAllocStringLen(NULL, path_len + name_len);
3017 if (ret)
3018 {
3019 strcpyW(ret, Path);
3020 ret[path_len] = 0;
3021 strcatW(ret, Name);
3022 }
3023 }
3024 else if (Path[path_len-1] != '\\' && Name[0] != '\\')
3025 {
3026 ret = SysAllocStringLen(NULL, path_len + name_len + 1);
3027 if (ret)
3028 {
3029 strcpyW(ret, Path);
3030 if (Path[path_len-1] != ':')
3031 strcatW(ret, bsW);
3032 strcatW(ret, Name);
3033 }
3034 }
3035 else
3036 {
3037 ret = SysAllocStringLen(NULL, path_len + name_len);
3038 if (ret)
3039 {
3040 strcpyW(ret, Path);
3041 strcatW(ret, Name);
3042 }
3043 }
3044 }
3045 else if (Path || Name)
3046 ret = SysAllocString(Path ? Path : Name);
3047 else
3048 ret = SysAllocStringLen(NULL, 0);
3049
3050 if (!ret) return E_OUTOFMEMORY;
3051 *Result = ret;
3052
3053 return S_OK;
3054 }
3055
3056 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR path, BSTR *drive)
3057 {
3058 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), drive);
3059
3060 if (!drive)
3061 return E_POINTER;
3062
3063 *drive = NULL;
3064
3065 if (path && strlenW(path) > 1 && path[1] == ':')
3066 *drive = SysAllocStringLen(path, 2);
3067
3068 return S_OK;
3069 }
3070
3071 static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
3072 {
3073 int i;
3074
3075 if(!path)
3076 return 0;
3077
3078 for(i=len-1; i>=0; i--)
3079 if(path[i]!='/' && path[i]!='\\')
3080 break;
3081
3082 for(; i>=0; i--)
3083 if(path[i]=='/' || path[i]=='\\')
3084 break;
3085
3086 for(; i>=0; i--)
3087 if(path[i]!='/' && path[i]!='\\')
3088 break;
3089
3090 if(i < 0)
3091 return 0;
3092
3093 if(path[i]==':' && i==1)
3094 i++;
3095 return i+1;
3096 }
3097
3098 static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
3099 BSTR *pbstrResult)
3100 {
3101 DWORD len;
3102
3103 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3104
3105 if(!pbstrResult)
3106 return E_POINTER;
3107
3108 len = get_parent_folder_name(Path, SysStringLen(Path));
3109 if(!len) {
3110 *pbstrResult = NULL;
3111 return S_OK;
3112 }
3113
3114 *pbstrResult = SysAllocStringLen(Path, len);
3115 if(!*pbstrResult)
3116 return E_OUTOFMEMORY;
3117 return S_OK;
3118 }
3119
3120 static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
3121 BSTR *pbstrResult)
3122 {
3123 int i, end;
3124
3125 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3126
3127 if(!pbstrResult)
3128 return E_POINTER;
3129
3130 if(!Path) {
3131 *pbstrResult = NULL;
3132 return S_OK;
3133 }
3134
3135 for(end=strlenW(Path)-1; end>=0; end--)
3136 if(Path[end]!='/' && Path[end]!='\\')
3137 break;
3138
3139 for(i=end; i>=0; i--)
3140 if(Path[i]=='/' || Path[i]=='\\')
3141 break;
3142 i++;
3143
3144 if(i>end || (i==0 && end==1 && Path[1]==':')) {
3145 *pbstrResult = NULL;
3146 return S_OK;
3147 }
3148
3149 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3150 if(!*pbstrResult)
3151 return E_OUTOFMEMORY;
3152 return S_OK;
3153 }
3154
3155 static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
3156 BSTR *pbstrResult)
3157 {
3158 int i, end;
3159
3160 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3161
3162 if(!pbstrResult)
3163 return E_POINTER;
3164
3165 if(!Path) {
3166 *pbstrResult = NULL;
3167 return S_OK;
3168 }
3169
3170 for(end=strlenW(Path)-1; end>=0; end--)
3171 if(Path[end]!='/' && Path[end]!='\\')
3172 break;
3173
3174 for(i=end; i>=0; i--) {
3175 if(Path[i]=='.' && Path[end+1]!='.')
3176 end = i-1;
3177 if(Path[i]=='/' || Path[i]=='\\')
3178 break;
3179 }
3180 i++;
3181
3182 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
3183 *pbstrResult = NULL;
3184 return S_OK;
3185 }
3186
3187 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3188 if(!*pbstrResult)
3189 return E_OUTOFMEMORY;
3190 return S_OK;
3191 }
3192
3193 static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR path,
3194 BSTR *ext)
3195 {
3196 INT len;
3197
3198 TRACE("%p %s %p\n", iface, debugstr_w(path), ext);
3199
3200 *ext = NULL;
3201 len = SysStringLen(path);
3202 while (len) {
3203 if (path[len-1] == '.') {
3204 *ext = SysAllocString(&path[len]);
3205 if (!*ext)
3206 return E_OUTOFMEMORY;
3207 break;
3208 }
3209 len--;
3210 }
3211
3212 return S_OK;
3213 }
3214
3215 static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR Path,
3216 BSTR *pbstrResult)
3217 {
3218 static const WCHAR cur_path[] = {'.',0};
3219
3220 WCHAR buf[MAX_PATH], ch;
3221 const WCHAR *path;
3222 DWORD i, beg, len, exp_len;
3223 WIN32_FIND_DATAW fdata;
3224 HANDLE fh;
3225
3226 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3227
3228 if(!pbstrResult)
3229 return E_POINTER;
3230
3231 if(!Path)
3232 path = cur_path;
3233 else
3234 path = Path;
3235
3236 len = GetFullPathNameW(path, MAX_PATH, buf, NULL);
3237 if(!len)
3238 return E_FAIL;
3239
3240 buf[0] = toupperW(buf[0]);
3241 if(len>3 && buf[len-1] == '\\')
3242 buf[--len] = 0;
3243
3244 for(beg=3, i=3; i<=len; i++) {
3245 if(buf[i]!='\\' && buf[i])
3246 continue;
3247
3248 ch = buf[i];
3249 buf[i] = 0;
3250 fh = FindFirstFileW(buf, &fdata);
3251 if(fh == INVALID_HANDLE_VALUE)
3252 break;
3253
3254 exp_len = strlenW(fdata.cFileName);
3255 if(exp_len == i-beg)
3256 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
3257 FindClose(fh);
3258 buf[i] = ch;
3259 beg = i+1;
3260 }
3261
3262 *pbstrResult = SysAllocString(buf);
3263 if(!*pbstrResult)
3264 return E_OUTOFMEMORY;
3265 return S_OK;
3266 }
3267
3268 static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
3269 {
3270 static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
3271
3272 DWORD random;
3273
3274 TRACE("%p %p\n", iface, pbstrResult);
3275
3276 if(!pbstrResult)
3277 return E_POINTER;
3278
3279 *pbstrResult = SysAllocStringLen(NULL, 12);
3280 if(!*pbstrResult)
3281 return E_OUTOFMEMORY;
3282
3283 if(!RtlGenRandom(&random, sizeof(random)))
3284 return E_FAIL;
3285 sprintfW(*pbstrResult, fmt, random & 0xfffff);
3286 return S_OK;
3287 }
3288
3289 static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
3290 VARIANT_BOOL *pfExists)
3291 {
3292 UINT len;
3293 WCHAR driveletter;
3294 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
3295
3296 if (!pfExists) return E_POINTER;
3297
3298 *pfExists = VARIANT_FALSE;
3299 len = SysStringLen(DriveSpec);
3300
3301 if (len >= 1) {
3302 driveletter = toupperW(DriveSpec[0]);
3303 if (driveletter >= 'A' && driveletter <= 'Z'
3304 && (len < 2 || DriveSpec[1] == ':')
3305 && (len < 3 || DriveSpec[2] == '\\')) {
3306 const WCHAR root[] = {driveletter, ':', '\\', 0};
3307 UINT drivetype = GetDriveTypeW(root);
3308 *pfExists = drivetype != DRIVE_NO_ROOT_DIR && drivetype != DRIVE_UNKNOWN ? VARIANT_TRUE : VARIANT_FALSE;
3309 }
3310 }
3311
3312 return S_OK;
3313 }
3314
3315 static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3316 {
3317 DWORD attrs;
3318 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3319
3320 if (!ret) return E_POINTER;
3321
3322 attrs = GetFileAttributesW(path);
3323 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3324 return S_OK;
3325 }
3326
3327 static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3328 {
3329 DWORD attrs;
3330 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3331
3332 if (!ret) return E_POINTER;
3333
3334 attrs = GetFileAttributesW(path);
3335 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3336
3337 return S_OK;
3338 }
3339
3340 static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
3341 IDrive **ppdrive)
3342 {
3343 UINT len;
3344 HRESULT hr;
3345 WCHAR driveletter;
3346 VARIANT_BOOL drive_exists;
3347
3348 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
3349
3350 if (!ppdrive)
3351 return E_POINTER;
3352
3353 *ppdrive = NULL;
3354
3355 /* DriveSpec may be one of: 'x', 'x:', 'x:\', '\\computer\share' */
3356 len = SysStringLen(DriveSpec);
3357 if (!len)
3358 return E_INVALIDARG;
3359 else if (len <= 3) {
3360 driveletter = toupperW(DriveSpec[0]);
3361 if (driveletter < 'A' || driveletter > 'Z'
3362 || (len >= 2 && DriveSpec[1] != ':')
3363 || (len == 3 && DriveSpec[2] != '\\'))
3364 return E_INVALIDARG;
3365 hr = IFileSystem3_DriveExists(iface, DriveSpec, &drive_exists);
3366 if (FAILED(hr))
3367 return hr;
3368 if (drive_exists == VARIANT_FALSE)
3369 return CTL_E_DEVICEUNAVAILABLE;
3370 return create_drive(driveletter, ppdrive);
3371 } else {
3372 if (DriveSpec[0] != '\\' || DriveSpec[1] != '\\')
3373 return E_INVALIDARG;
3374 FIXME("%s not implemented yet\n", debugstr_w(DriveSpec));
3375 return E_NOTIMPL;
3376 }
3377 }
3378
3379 static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
3380 IFile **ppfile)
3381 {
3382 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
3383
3384 if(!ppfile)
3385 return E_POINTER;
3386 if(!FilePath)
3387 return E_INVALIDARG;
3388
3389 return create_file(FilePath, ppfile);
3390 }
3391
3392 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
3393 IFolder **folder)
3394 {
3395 DWORD attrs;
3396
3397 TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
3398
3399 if(!folder)
3400 return E_POINTER;
3401
3402 *folder = NULL;
3403 if(!FolderPath)
3404 return E_INVALIDARG;
3405
3406 attrs = GetFileAttributesW(FolderPath);
3407 if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
3408 return CTL_E_PATHNOTFOUND;
3409
3410 return create_folder(FolderPath, folder);
3411 }
3412
3413 static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
3414 SpecialFolderConst SpecialFolder,
3415 IFolder **folder)
3416 {
3417 WCHAR pathW[MAX_PATH];
3418 DWORD ret;
3419
3420 TRACE("%p %d %p\n", iface, SpecialFolder, folder);
3421
3422 if (!folder)
3423 return E_POINTER;
3424
3425 *folder = NULL;
3426
3427 switch (SpecialFolder)
3428 {
3429 case WindowsFolder:
3430 ret = GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
3431 break;
3432 case SystemFolder:
3433 ret = GetSystemDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
3434 break;
3435 case TemporaryFolder:
3436 ret = GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
3437 /* we don't want trailing backslash */
3438 if (ret && pathW[ret-1] == '\\')
3439 pathW[ret-1] = 0;
3440 break;
3441 default:
3442 FIXME("unknown special folder type, %d\n", SpecialFolder);
3443 return E_INVALIDARG;
3444 }
3445
3446 if (!ret)
3447 return HRESULT_FROM_WIN32(GetLastError());
3448
3449 return create_folder(pathW, folder);
3450 }
3451
3452 static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
3453 {
3454 WCHAR path[MAX_PATH];
3455 DWORD len, name_len;
3456 WIN32_FIND_DATAW ffd;
3457 HANDLE f;
3458
3459 f = FindFirstFileW(file, &ffd);
3460 if(f == INVALID_HANDLE_VALUE)
3461 return create_error(GetLastError());
3462
3463 len = get_parent_folder_name(file, file_len);
3464 if(len+1 >= MAX_PATH) {
3465 FindClose(f);
3466 return E_FAIL;
3467 }
3468 if(len) {
3469 memcpy(path, file, len*sizeof(WCHAR));
3470 path[len++] = '\\';
3471 }
3472
3473 do {
3474 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3475 continue;
3476
3477 name_len = strlenW(ffd.cFileName);
3478 if(len+name_len+1 >= MAX_PATH) {
3479 FindClose(f);
3480 return E_FAIL;
3481 }
3482 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3483
3484 TRACE("deleting %s\n", debugstr_w(path));
3485
3486 if(!DeleteFileW(path)) {
3487 if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
3488 || !DeleteFileW(path)) {
3489 FindClose(f);
3490 return create_error(GetLastError());
3491 }
3492 }
3493 } while(FindNextFileW(f, &ffd));
3494 FindClose(f);
3495
3496 return S_OK;
3497 }
3498
3499 static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
3500 VARIANT_BOOL Force)
3501 {
3502 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
3503
3504 if(!FileSpec)
3505 return E_POINTER;
3506
3507 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
3508 }
3509
3510 static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
3511 {
3512 WCHAR path[MAX_PATH];
3513 DWORD len, name_len;
3514 WIN32_FIND_DATAW ffd;
3515 HANDLE f;
3516 HRESULT hr;
3517
3518 f = FindFirstFileW(folder, &ffd);
3519 if(f == INVALID_HANDLE_VALUE)
3520 return create_error(GetLastError());
3521
3522 len = get_parent_folder_name(folder, folder_len);
3523 if(len+1 >= MAX_PATH) {
3524 FindClose(f);
3525 return E_FAIL;
3526 }
3527 if(len) {
3528 memcpy(path, folder, len*sizeof(WCHAR));
3529 path[len++] = '\\';
3530 }
3531
3532 do {
3533 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3534 continue;
3535 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3536 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3537 continue;
3538
3539 name_len = strlenW(ffd.cFileName);
3540 if(len+name_len+3 >= MAX_PATH) {
3541 FindClose(f);
3542 return E_FAIL;
3543 }
3544 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
3545 path[len+name_len] = '\\';
3546 path[len+name_len+1] = '*';
3547 path[len+name_len+2] = 0;
3548
3549 hr = delete_file(path, len+name_len+2, force);
3550 if(FAILED(hr)) {
3551 FindClose(f);
3552 return hr;
3553 }
3554
3555 hr = delete_folder(path, len+name_len+2, force);
3556 if(FAILED(hr)) {
3557 FindClose(f);
3558 return hr;
3559 }
3560
3561 path[len+name_len] = 0;
3562 TRACE("deleting %s\n", debugstr_w(path));
3563
3564 if(!RemoveDirectoryW(path)) {
3565 FindClose(f);
3566 return create_error(GetLastError());
3567 }
3568 } while(FindNextFileW(f, &ffd));
3569 FindClose(f);
3570
3571 return S_OK;
3572 }
3573
3574 static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
3575 VARIANT_BOOL Force)
3576 {
3577 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
3578
3579 if(!FolderSpec)
3580 return E_POINTER;
3581
3582 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
3583 }
3584
3585 static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR Source,
3586 BSTR Destination)
3587 {
3588 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3589
3590 return E_NOTIMPL;
3591 }
3592
3593 static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
3594 BSTR Destination)
3595 {
3596 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3597
3598 return E_NOTIMPL;
3599 }
3600
3601 static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
3602 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
3603 {
3604 DWORD attrs;
3605 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
3606 DWORD src_len, dst_len, name_len;
3607 WIN32_FIND_DATAW ffd;
3608 HANDLE f;
3609 HRESULT hr;
3610
3611 if(!source[0] || !destination[0])
3612 return E_INVALIDARG;
3613
3614 attrs = GetFileAttributesW(destination);
3615 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
3616 attrs = GetFileAttributesW(source);
3617 if(attrs == INVALID_FILE_ATTRIBUTES)
3618 return create_error(GetLastError());
3619 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
3620 return CTL_E_FILENOTFOUND;
3621
3622 if(!CopyFileW(source, destination, !overwrite))
3623 return create_error(GetLastError());
3624 return S_OK;
3625 }
3626
3627 f = FindFirstFileW(source, &ffd);
3628 if(f == INVALID_HANDLE_VALUE)
3629 return CTL_E_FILENOTFOUND;
3630
3631 src_len = get_parent_folder_name(source, source_len);
3632 if(src_len+1 >= MAX_PATH) {
3633 FindClose(f);
3634 return E_FAIL;
3635 }
3636 if(src_len) {
3637 memcpy(src_path, source, src_len*sizeof(WCHAR));
3638 src_path[src_len++] = '\\';
3639 }
3640
3641 dst_len = destination_len;
3642 if(dst_len+1 >= MAX_PATH) {
3643 FindClose(f);
3644 return E_FAIL;
3645 }
3646 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
3647 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
3648 dst_path[dst_len++] = '\\';
3649
3650 hr = CTL_E_FILENOTFOUND;
3651 do {
3652 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3653 continue;
3654
3655 name_len = strlenW(ffd.cFileName);
3656 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
3657 FindClose(f);
3658 return E_FAIL;
3659 }
3660 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3661 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3662
3663 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
3664
3665 if(!CopyFileW(src_path, dst_path, !overwrite)) {
3666 FindClose(f);
3667 return create_error(GetLastError());
3668 }else {
3669 hr = S_OK;
3670 }
3671 } while(FindNextFileW(f, &ffd));
3672 FindClose(f);
3673
3674 return hr;
3675 }
3676
3677 static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
3678 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3679 {
3680 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3681
3682 if(!Source || !Destination)
3683 return E_POINTER;
3684
3685 return copy_file(Source, SysStringLen(Source), Destination,
3686 SysStringLen(Destination), OverWriteFiles);
3687 }
3688
3689 static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
3690 DWORD destination_len, VARIANT_BOOL overwrite)
3691 {
3692 DWORD tmp, src_len, dst_len, name_len;
3693 WCHAR src[MAX_PATH], dst[MAX_PATH];
3694 WIN32_FIND_DATAW ffd;
3695 HANDLE f;
3696 HRESULT hr;
3697 BOOL copied = FALSE;
3698
3699 if(!source[0] || !destination[0])
3700 return E_INVALIDARG;
3701
3702 dst_len = destination_len;
3703 if(dst_len+1 >= MAX_PATH)
3704 return E_FAIL;
3705 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
3706
3707 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
3708 (tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
3709 tmp&FILE_ATTRIBUTE_DIRECTORY) {
3710 if(!CreateDirectoryW(dst, NULL)) {
3711 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3712 tmp = GetFileAttributesW(dst);
3713 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
3714 return CTL_E_FILEALREADYEXISTS;
3715 }else {
3716 return create_error(GetLastError());
3717 }
3718 }
3719 copied = TRUE;
3720
3721 src_len = source_len;
3722 if(src_len+2 >= MAX_PATH)
3723 return E_FAIL;
3724 memcpy(src, source, src_len*sizeof(WCHAR));
3725 src[src_len++] = '\\';
3726 src[src_len] = '*';
3727 src[src_len+1] = 0;
3728
3729 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
3730 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
3731 return create_error(GetLastError());
3732
3733 f = FindFirstFileW(src, &ffd);
3734 }else {
3735 src_len = get_parent_folder_name(source, source_len);
3736 if(src_len+2 >= MAX_PATH)
3737 return E_FAIL;
3738 memcpy(src, source, src_len*sizeof(WCHAR));
3739 if(src_len)
3740 src[src_len++] = '\\';
3741
3742 f = FindFirstFileW(source, &ffd);
3743 }
3744 if(f == INVALID_HANDLE_VALUE)
3745 return CTL_E_PATHNOTFOUND;
3746
3747 dst[dst_len++] = '\\';
3748 dst[dst_len] = 0;
3749
3750 do {
3751 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3752 continue;
3753 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3754 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3755 continue;
3756
3757 name_len = strlenW(ffd.cFileName);
3758 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
3759 FindClose(f);
3760 return E_FAIL;
3761 }
3762 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
3763 dst[dst_len+name_len] = 0;
3764 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
3765 src[src_len+name_len] = '\\';
3766 src[src_len+name_len+1] = '*';
3767 src[src_len+name_len+2] = 0;
3768
3769 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
3770
3771 if(!CreateDirectoryW(dst, NULL)) {
3772 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3773 tmp = GetFileAttributesW(dst);
3774 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
3775 FindClose(f);
3776 return CTL_E_FILEALREADYEXISTS;
3777 }
3778 }
3779
3780 FindClose(f);
3781 return create_error(GetLastError());
3782 }
3783 copied = TRUE;
3784
3785 hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3786 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
3787 FindClose(f);
3788 return hr;
3789 }
3790
3791 hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3792 if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
3793 FindClose(f);
3794 return hr;
3795 }
3796 } while(FindNextFileW(f, &ffd));
3797 FindClose(f);
3798
3799 return copied ? S_OK : CTL_E_PATHNOTFOUND;
3800 }
3801
3802 static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
3803 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3804 {
3805 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3806
3807 if(!Source || !Destination)
3808 return E_POINTER;
3809
3810 return copy_folder(Source, SysStringLen(Source), Destination,
3811 SysStringLen(Destination), OverWriteFiles);
3812 }
3813
3814 static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
3815 IFolder **folder)
3816 {
3817 BOOL ret;
3818
3819 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
3820
3821 ret = CreateDirectoryW(path, NULL);
3822 if (!ret)
3823 {
3824 *folder = NULL;
3825 if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
3826 return HRESULT_FROM_WIN32(GetLastError());
3827 }
3828
3829 return create_folder(path, folder);
3830 }
3831
3832 static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR filename,
3833 VARIANT_BOOL overwrite, VARIANT_BOOL unicode,
3834 ITextStream **stream)
3835 {
3836 DWORD disposition;
3837
3838 TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
3839
3840 disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
3841 return create_textstream(filename, disposition, ForWriting, !!unicode, stream);
3842 }
3843
3844 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
3845 IOMode mode, VARIANT_BOOL create,
3846 Tristate format, ITextStream **stream)
3847 {
3848 DWORD disposition;
3849
3850 TRACE("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
3851 disposition = create == VARIANT_TRUE ? OPEN_ALWAYS : OPEN_EXISTING;
3852
3853 if (format == TristateUseDefault) {
3854 FIXME("default format not handled, defaulting to unicode\n");
3855 format = TristateTrue;
3856 }
3857
3858 return create_textstream(filename, disposition, mode, format == TristateTrue, stream);
3859 }
3860
3861 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
3862 StandardStreamTypes StandardStreamType,
3863 VARIANT_BOOL Unicode,
3864 ITextStream **ppts)
3865 {
3866 FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
3867
3868 return E_NOTIMPL;
3869 }
3870
3871 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
3872 {
3873 static const WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
3874 DWORDLONG version;
3875 WORD a, b, c, d;
3876
3877 version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
3878 a = (WORD)( version >> 48);
3879 b = (WORD)((version >> 32) & 0xffff);
3880 c = (WORD)((version >> 16) & 0xffff);
3881 d = (WORD)( version & 0xffff);
3882
3883 sprintfW(ver, fmtW, a, b, c, d);
3884 }
3885
3886 static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
3887 {
3888 static const WCHAR rootW[] = {'\\',0};
3889 VS_FIXEDFILEINFO *info;
3890 WCHAR ver[30];
3891 void *ptr;
3892 DWORD len;
3893 BOOL ret;
3894
3895 TRACE("%p %s %p\n", iface, debugstr_w(name), version);
3896
3897 len = GetFileVersionInfoSizeW(name, NULL);
3898 if (!len)
3899 return HRESULT_FROM_WIN32(GetLastError());
3900
3901 ptr = heap_alloc(len);
3902 if (!GetFileVersionInfoW(name, 0, len, ptr))
3903 {
3904 heap_free(ptr);
3905 return HRESULT_FROM_WIN32(GetLastError());
3906 }
3907
3908 ret = VerQueryValueW(ptr, rootW, (void**)&info, &len);
3909 if (!ret)
3910 {
3911 heap_free(ptr);
3912 return HRESULT_FROM_WIN32(GetLastError());
3913 }
3914
3915 get_versionstring(info, ver);
3916 heap_free(ptr);
3917
3918 *version = SysAllocString(ver);
3919 TRACE("version=%s\n", debugstr_w(ver));
3920
3921 return S_OK;
3922 }
3923
3924 static const struct IFileSystem3Vtbl filesys_vtbl =
3925 {
3926 filesys_QueryInterface,
3927 filesys_AddRef,
3928 filesys_Release,
3929 filesys_GetTypeInfoCount,
3930 filesys_GetTypeInfo,
3931 filesys_GetIDsOfNames,
3932 filesys_Invoke,
3933 filesys_get_Drives,
3934 filesys_BuildPath,
3935 filesys_GetDriveName,
3936 filesys_GetParentFolderName,
3937 filesys_GetFileName,
3938 filesys_GetBaseName,
3939 filesys_GetExtensionName,
3940 filesys_GetAbsolutePathName,
3941 filesys_GetTempName,
3942 filesys_DriveExists,
3943 filesys_FileExists,
3944 filesys_FolderExists,
3945 filesys_GetDrive,
3946 filesys_GetFile,
3947 filesys_GetFolder,
3948 filesys_GetSpecialFolder,
3949 filesys_DeleteFile,
3950 filesys_DeleteFolder,
3951 filesys_MoveFile,
3952 filesys_MoveFolder,
3953 filesys_CopyFile,
3954 filesys_CopyFolder,
3955 filesys_CreateFolder,
3956 filesys_CreateTextFile,
3957 filesys_OpenTextFile,
3958 filesys_GetStandardStream,
3959 filesys_GetFileVersion
3960 };
3961
3962 static struct filesystem filesystem;
3963
3964 HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
3965 {
3966 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
3967
3968 filesystem.IFileSystem3_iface.lpVtbl = &filesys_vtbl;
3969 init_classinfo(&CLSID_FileSystemObject, (IUnknown *)&filesystem.IFileSystem3_iface, &filesystem.classinfo);
3970 return IFileSystem3_QueryInterface(&filesystem.IFileSystem3_iface, riid, ppv);
3971 }