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