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