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