ddraw/tests: Show that a failing SetPrivateData call does not clear the old contents.
[wine.git] / dlls / scrrun / filesystem.c
bloba48b630af447f9d5b4e74b54cd3e4878be03bf5d
1 /*
2 * Copyright 2012 Alistair Leslie-Hughes
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.
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.
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
19 #define COBJMACROS
21 #include "config.h"
22 #include <stdarg.h>
23 #include <limits.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "ole2.h"
28 #include "olectl.h"
29 #include "dispex.h"
30 #include "ntsecapi.h"
31 #include "scrrun.h"
32 #include "scrrun_private.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
39 static const WCHAR bsW[] = {'\\',0};
41 struct foldercollection {
42 IFolderCollection IFolderCollection_iface;
43 LONG ref;
44 BSTR path;
47 struct filecollection {
48 IFileCollection IFileCollection_iface;
49 LONG ref;
50 BSTR path;
53 struct drivecollection {
54 IDriveCollection IDriveCollection_iface;
55 LONG ref;
56 DWORD drives;
57 LONG count;
60 struct enumdata {
61 union
63 struct
65 struct foldercollection *coll;
66 HANDLE find;
67 } foldercoll;
68 struct
70 struct filecollection *coll;
71 HANDLE find;
72 } filecoll;
73 struct
75 struct drivecollection *coll;
76 INT cur;
77 } drivecoll;
78 } u;
81 struct enumvariant {
82 IEnumVARIANT IEnumVARIANT_iface;
83 LONG ref;
85 struct enumdata data;
88 struct drive {
89 IDrive IDrive_iface;
90 LONG ref;
91 BSTR root;
94 struct folder {
95 IFolder IFolder_iface;
96 LONG ref;
97 BSTR path;
100 struct file {
101 IFile IFile_iface;
102 LONG ref;
104 WCHAR *path;
107 struct textstream {
108 ITextStream ITextStream_iface;
109 LONG ref;
111 IOMode mode;
114 enum iotype {
115 IORead,
116 IOWrite
119 static inline struct drive *impl_from_IDrive(IDrive *iface)
121 return CONTAINING_RECORD(iface, struct drive, IDrive_iface);
124 static inline struct folder *impl_from_IFolder(IFolder *iface)
126 return CONTAINING_RECORD(iface, struct folder, IFolder_iface);
129 static inline struct file *impl_from_IFile(IFile *iface)
131 return CONTAINING_RECORD(iface, struct file, IFile_iface);
134 static inline struct textstream *impl_from_ITextStream(ITextStream *iface)
136 return CONTAINING_RECORD(iface, struct textstream, ITextStream_iface);
139 static inline struct foldercollection *impl_from_IFolderCollection(IFolderCollection *iface)
141 return CONTAINING_RECORD(iface, struct foldercollection, IFolderCollection_iface);
144 static inline struct filecollection *impl_from_IFileCollection(IFileCollection *iface)
146 return CONTAINING_RECORD(iface, struct filecollection, IFileCollection_iface);
149 static inline struct drivecollection *impl_from_IDriveCollection(IDriveCollection *iface)
151 return CONTAINING_RECORD(iface, struct drivecollection, IDriveCollection_iface);
154 static inline struct enumvariant *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
156 return CONTAINING_RECORD(iface, struct enumvariant, IEnumVARIANT_iface);
159 static inline HRESULT create_error(DWORD err)
161 switch(err) {
162 case ERROR_FILE_NOT_FOUND: return CTL_E_FILENOTFOUND;
163 case ERROR_PATH_NOT_FOUND: return CTL_E_PATHNOTFOUND;
164 case ERROR_ACCESS_DENIED: return CTL_E_PERMISSIONDENIED;
165 case ERROR_FILE_EXISTS: return CTL_E_FILEALREADYEXISTS;
166 case ERROR_ALREADY_EXISTS: return CTL_E_FILEALREADYEXISTS;
167 default:
168 FIXME("Unsupported error code: %d\n", err);
169 return E_FAIL;
173 static HRESULT create_folder(const WCHAR*, IFolder**);
174 static HRESULT create_file(BSTR, IFile**);
175 static HRESULT create_foldercoll_enum(struct foldercollection*, IUnknown**);
176 static HRESULT create_filecoll_enum(struct filecollection*, IUnknown**);
178 static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data)
180 static const WCHAR dotdotW[] = {'.','.',0};
181 static const WCHAR dotW[] = {'.',0};
183 return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
184 strcmpW(data->cFileName, dotdotW) &&
185 strcmpW(data->cFileName, dotW);
188 static inline BOOL is_file_data(const WIN32_FIND_DATAW *data)
190 return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
193 static BSTR get_full_path(BSTR path, const WIN32_FIND_DATAW *data)
195 int len = SysStringLen(path);
196 WCHAR buffW[MAX_PATH];
198 strcpyW(buffW, path);
199 if (path[len-1] != '\\')
200 strcatW(buffW, bsW);
201 strcatW(buffW, data->cFileName);
203 return SysAllocString(buffW);
206 static BOOL textstream_check_iomode(struct textstream *This, enum iotype type)
208 if (type == IORead)
209 return This->mode == ForWriting || This->mode == ForAppending;
210 else
211 return TRUE;
214 static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
216 struct textstream *This = impl_from_ITextStream(iface);
218 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
220 if (IsEqualIID(riid, &IID_ITextStream) ||
221 IsEqualIID(riid, &IID_IDispatch) ||
222 IsEqualIID(riid, &IID_IUnknown))
224 *obj = iface;
225 ITextStream_AddRef(iface);
226 return S_OK;
229 *obj = NULL;
230 return E_NOINTERFACE;
233 static ULONG WINAPI textstream_AddRef(ITextStream *iface)
235 struct textstream *This = impl_from_ITextStream(iface);
236 ULONG ref = InterlockedIncrement(&This->ref);
237 TRACE("(%p)->(%d)\n", This, ref);
238 return ref;
241 static ULONG WINAPI textstream_Release(ITextStream *iface)
243 struct textstream *This = impl_from_ITextStream(iface);
244 ULONG ref = InterlockedDecrement(&This->ref);
245 TRACE("(%p)->(%d)\n", This, ref);
247 if (!ref)
248 heap_free(This);
250 return ref;
253 static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
255 struct textstream *This = impl_from_ITextStream(iface);
256 TRACE("(%p)->(%p)\n", This, pctinfo);
257 *pctinfo = 1;
258 return S_OK;
261 static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
262 LCID lcid, ITypeInfo **ppTInfo)
264 struct textstream *This = impl_from_ITextStream(iface);
265 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
266 return get_typeinfo(ITextStream_tid, ppTInfo);
269 static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
270 LPOLESTR *rgszNames, UINT cNames,
271 LCID lcid, DISPID *rgDispId)
273 struct textstream *This = impl_from_ITextStream(iface);
274 ITypeInfo *typeinfo;
275 HRESULT hr;
277 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
279 hr = get_typeinfo(ITextStream_tid, &typeinfo);
280 if(SUCCEEDED(hr))
282 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
283 ITypeInfo_Release(typeinfo);
286 return hr;
289 static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
290 REFIID riid, LCID lcid, WORD wFlags,
291 DISPPARAMS *pDispParams, VARIANT *pVarResult,
292 EXCEPINFO *pExcepInfo, UINT *puArgErr)
294 struct textstream *This = impl_from_ITextStream(iface);
295 ITypeInfo *typeinfo;
296 HRESULT hr;
298 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
299 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
301 hr = get_typeinfo(ITextStream_tid, &typeinfo);
302 if(SUCCEEDED(hr))
304 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
305 pDispParams, pVarResult, pExcepInfo, puArgErr);
306 ITypeInfo_Release(typeinfo);
309 return hr;
312 static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
314 struct textstream *This = impl_from_ITextStream(iface);
315 FIXME("(%p)->(%p): stub\n", This, line);
316 return E_NOTIMPL;
319 static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
321 struct textstream *This = impl_from_ITextStream(iface);
322 FIXME("(%p)->(%p): stub\n", This, column);
323 return E_NOTIMPL;
326 static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
328 struct textstream *This = impl_from_ITextStream(iface);
329 FIXME("(%p)->(%p): stub\n", This, eos);
330 return E_NOTIMPL;
333 static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
335 struct textstream *This = impl_from_ITextStream(iface);
336 FIXME("(%p)->(%p): stub\n", This, eol);
337 return E_NOTIMPL;
340 static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
342 struct textstream *This = impl_from_ITextStream(iface);
343 FIXME("(%p)->(%p): stub\n", This, text);
345 if (textstream_check_iomode(This, IORead))
346 return CTL_E_BADFILEMODE;
348 return E_NOTIMPL;
351 static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
353 struct textstream *This = impl_from_ITextStream(iface);
354 FIXME("(%p)->(%p): stub\n", This, text);
356 if (textstream_check_iomode(This, IORead))
357 return CTL_E_BADFILEMODE;
359 return E_NOTIMPL;
362 static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
364 struct textstream *This = impl_from_ITextStream(iface);
365 FIXME("(%p)->(%p): stub\n", This, text);
367 if (textstream_check_iomode(This, IORead))
368 return CTL_E_BADFILEMODE;
370 return E_NOTIMPL;
373 static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
375 struct textstream *This = impl_from_ITextStream(iface);
376 FIXME("(%p)->(%s): stub\n", This, debugstr_w(text));
377 return E_NOTIMPL;
380 static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
382 struct textstream *This = impl_from_ITextStream(iface);
383 FIXME("(%p)->(%s): stub\n", This, debugstr_w(text));
384 return E_NOTIMPL;
387 static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
389 struct textstream *This = impl_from_ITextStream(iface);
390 FIXME("(%p)->(%d): stub\n", This, lines);
391 return E_NOTIMPL;
394 static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
396 struct textstream *This = impl_from_ITextStream(iface);
397 FIXME("(%p)->(%d): stub\n", This, count);
398 return E_NOTIMPL;
401 static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
403 struct textstream *This = impl_from_ITextStream(iface);
404 FIXME("(%p): stub\n", This);
405 return E_NOTIMPL;
408 static HRESULT WINAPI textstream_Close(ITextStream *iface)
410 struct textstream *This = impl_from_ITextStream(iface);
411 FIXME("(%p): stub\n", This);
412 return E_NOTIMPL;
415 static const ITextStreamVtbl textstreamvtbl = {
416 textstream_QueryInterface,
417 textstream_AddRef,
418 textstream_Release,
419 textstream_GetTypeInfoCount,
420 textstream_GetTypeInfo,
421 textstream_GetIDsOfNames,
422 textstream_Invoke,
423 textstream_get_Line,
424 textstream_get_Column,
425 textstream_get_AtEndOfStream,
426 textstream_get_AtEndOfLine,
427 textstream_Read,
428 textstream_ReadLine,
429 textstream_ReadAll,
430 textstream_Write,
431 textstream_WriteLine,
432 textstream_WriteBlankLines,
433 textstream_Skip,
434 textstream_SkipLine,
435 textstream_Close
438 static HRESULT create_textstream(IOMode mode, ITextStream **ret)
440 struct textstream *stream;
442 stream = heap_alloc(sizeof(struct textstream));
443 if (!stream) return E_OUTOFMEMORY;
445 stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
446 stream->ref = 1;
447 stream->mode = mode;
449 *ret = &stream->ITextStream_iface;
450 return S_OK;
453 static HRESULT WINAPI drive_QueryInterface(IDrive *iface, REFIID riid, void **obj)
455 struct drive *This = impl_from_IDrive(iface);
457 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
459 *obj = NULL;
461 if (IsEqualIID( riid, &IID_IDrive ) ||
462 IsEqualIID( riid, &IID_IDispatch ) ||
463 IsEqualIID( riid, &IID_IUnknown))
465 *obj = iface;
466 IDrive_AddRef(iface);
468 else
469 return E_NOINTERFACE;
471 return S_OK;
474 static ULONG WINAPI drive_AddRef(IDrive *iface)
476 struct drive *This = impl_from_IDrive(iface);
477 ULONG ref = InterlockedIncrement(&This->ref);
478 TRACE("(%p)->(%d)\n", This, ref);
479 return ref;
482 static ULONG WINAPI drive_Release(IDrive *iface)
484 struct drive *This = impl_from_IDrive(iface);
485 ULONG ref = InterlockedDecrement(&This->ref);
486 TRACE("(%p)->(%d)\n", This, ref);
488 if (!ref)
490 SysFreeString(This->root);
491 heap_free(This);
494 return ref;
497 static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo)
499 struct drive *This = impl_from_IDrive(iface);
500 TRACE("(%p)->(%p)\n", This, pctinfo);
501 *pctinfo = 1;
502 return S_OK;
505 static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo,
506 LCID lcid, ITypeInfo **ppTInfo)
508 struct drive *This = impl_from_IDrive(iface);
509 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
510 return get_typeinfo(IDrive_tid, ppTInfo);
513 static HRESULT WINAPI drive_GetIDsOfNames(IDrive *iface, REFIID riid,
514 LPOLESTR *rgszNames, UINT cNames,
515 LCID lcid, DISPID *rgDispId)
517 struct drive *This = impl_from_IDrive(iface);
518 ITypeInfo *typeinfo;
519 HRESULT hr;
521 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
523 hr = get_typeinfo(IDrive_tid, &typeinfo);
524 if(SUCCEEDED(hr))
526 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
527 ITypeInfo_Release(typeinfo);
530 return hr;
533 static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember,
534 REFIID riid, LCID lcid, WORD wFlags,
535 DISPPARAMS *pDispParams, VARIANT *pVarResult,
536 EXCEPINFO *pExcepInfo, UINT *puArgErr)
538 struct drive *This = impl_from_IDrive(iface);
539 ITypeInfo *typeinfo;
540 HRESULT hr;
542 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
543 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
545 hr = get_typeinfo(IDrive_tid, &typeinfo);
546 if(SUCCEEDED(hr))
548 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
549 pDispParams, pVarResult, pExcepInfo, puArgErr);
550 ITypeInfo_Release(typeinfo);
553 return hr;
556 static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path)
558 struct drive *This = impl_from_IDrive(iface);
559 FIXME("(%p)->(%p): stub\n", This, path);
560 return E_NOTIMPL;
563 static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter)
565 struct drive *This = impl_from_IDrive(iface);
566 FIXME("(%p)->(%p): stub\n", This, letter);
567 return E_NOTIMPL;
570 static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name)
572 struct drive *This = impl_from_IDrive(iface);
573 FIXME("(%p)->(%p): stub\n", This, share_name);
574 return E_NOTIMPL;
577 static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type)
579 struct drive *This = impl_from_IDrive(iface);
581 TRACE("(%p)->(%p)\n", This, type);
583 switch (GetDriveTypeW(This->root))
585 case DRIVE_REMOVABLE:
586 *type = Removable;
587 break;
588 case DRIVE_FIXED:
589 *type = Fixed;
590 break;
591 case DRIVE_REMOTE:
592 *type = Remote;
593 break;
594 case DRIVE_CDROM:
595 *type = CDRom;
596 break;
597 case DRIVE_RAMDISK:
598 *type = RamDisk;
599 break;
600 default:
601 *type = UnknownType;
602 break;
605 return S_OK;
608 static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder)
610 struct drive *This = impl_from_IDrive(iface);
611 FIXME("(%p)->(%p): stub\n", This, folder);
612 return E_NOTIMPL;
615 static HRESULT WINAPI drive_get_AvailableSpace(IDrive *iface, VARIANT *avail)
617 struct drive *This = impl_from_IDrive(iface);
618 FIXME("(%p)->(%p): stub\n", This, avail);
619 return E_NOTIMPL;
622 static HRESULT WINAPI drive_get_FreeSpace(IDrive *iface, VARIANT *v)
624 struct drive *This = impl_from_IDrive(iface);
625 FIXME("(%p)->(%p): stub\n", This, v);
626 return E_NOTIMPL;
629 static HRESULT WINAPI drive_get_TotalSize(IDrive *iface, VARIANT *v)
631 struct drive *This = impl_from_IDrive(iface);
632 FIXME("(%p)->(%p): stub\n", This, v);
633 return E_NOTIMPL;
636 static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name)
638 struct drive *This = impl_from_IDrive(iface);
639 FIXME("(%p)->(%p): stub\n", This, name);
640 return E_NOTIMPL;
643 static HRESULT WINAPI drive_put_VolumeName(IDrive *iface, BSTR name)
645 struct drive *This = impl_from_IDrive(iface);
646 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
647 return E_NOTIMPL;
650 static HRESULT WINAPI drive_get_FileSystem(IDrive *iface, BSTR *fs)
652 struct drive *This = impl_from_IDrive(iface);
653 FIXME("(%p)->(%p): stub\n", This, fs);
654 return E_NOTIMPL;
657 static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial)
659 struct drive *This = impl_from_IDrive(iface);
660 FIXME("(%p)->(%p): stub\n", This, serial);
661 return E_NOTIMPL;
664 static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
666 struct drive *This = impl_from_IDrive(iface);
667 FIXME("(%p)->(%p): stub\n", This, ready);
668 return E_NOTIMPL;
671 static const IDriveVtbl drivevtbl = {
672 drive_QueryInterface,
673 drive_AddRef,
674 drive_Release,
675 drive_GetTypeInfoCount,
676 drive_GetTypeInfo,
677 drive_GetIDsOfNames,
678 drive_Invoke,
679 drive_get_Path,
680 drive_get_DriveLetter,
681 drive_get_ShareName,
682 drive_get_DriveType,
683 drive_get_RootFolder,
684 drive_get_AvailableSpace,
685 drive_get_FreeSpace,
686 drive_get_TotalSize,
687 drive_get_VolumeName,
688 drive_put_VolumeName,
689 drive_get_FileSystem,
690 drive_get_SerialNumber,
691 drive_get_IsReady
694 static HRESULT create_drive(WCHAR letter, IDrive **drive)
696 struct drive *This;
698 *drive = NULL;
700 This = heap_alloc(sizeof(*This));
701 if (!This) return E_OUTOFMEMORY;
703 This->IDrive_iface.lpVtbl = &drivevtbl;
704 This->ref = 1;
705 This->root = SysAllocStringLen(NULL, 3);
706 if (!This->root)
708 heap_free(This);
709 return E_OUTOFMEMORY;
711 This->root[0] = letter;
712 This->root[1] = ':';
713 This->root[2] = '\\';
714 This->root[3] = 0;
716 *drive = &This->IDrive_iface;
717 return S_OK;
720 static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
722 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
724 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
726 *obj = NULL;
728 if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
729 IsEqualIID( riid, &IID_IUnknown ))
731 *obj = iface;
732 IEnumVARIANT_AddRef(iface);
734 else
735 return E_NOINTERFACE;
737 return S_OK;
740 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
742 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
743 ULONG ref = InterlockedIncrement(&This->ref);
744 TRACE("(%p)->(%d)\n", This, ref);
745 return ref;
748 static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
750 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
751 ULONG ref = InterlockedDecrement(&This->ref);
753 TRACE("(%p)->(%d)\n", This, ref);
755 if (!ref)
757 IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
758 FindClose(This->data.u.foldercoll.find);
759 heap_free(This);
762 return ref;
765 static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file)
767 static const WCHAR allW[] = {'*',0};
768 WCHAR pathW[MAX_PATH];
769 int len;
770 HANDLE handle;
772 strcpyW(pathW, path);
773 len = strlenW(pathW);
774 if (pathW[len-1] != '\\')
775 strcatW(pathW, bsW);
776 strcatW(pathW, allW);
777 handle = FindFirstFileW(pathW, data);
778 if (handle == INVALID_HANDLE_VALUE) return 0;
780 /* find first dir/file */
781 while (1)
783 if (file ? is_file_data(data) : is_dir_data(data))
784 break;
786 if (!FindNextFileW(handle, data))
788 FindClose(handle);
789 return 0;
792 return handle;
795 static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
797 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
798 HANDLE handle = This->data.u.foldercoll.find;
799 WIN32_FIND_DATAW data;
800 ULONG count = 0;
802 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
804 if (fetched)
805 *fetched = 0;
807 if (!celt) return S_OK;
809 if (!handle)
811 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
812 if (!handle) return S_FALSE;
814 This->data.u.foldercoll.find = handle;
816 else
818 if (!FindNextFileW(handle, &data))
819 return S_FALSE;
824 if (is_dir_data(&data))
826 IFolder *folder;
827 HRESULT hr;
828 BSTR str;
830 str = get_full_path(This->data.u.foldercoll.coll->path, &data);
831 hr = create_folder(str, &folder);
832 SysFreeString(str);
833 if (FAILED(hr)) return hr;
835 V_VT(&var[count]) = VT_DISPATCH;
836 V_DISPATCH(&var[count]) = (IDispatch*)folder;
837 count++;
839 if (count >= celt) break;
841 } while (FindNextFileW(handle, &data));
843 if (fetched)
844 *fetched = count;
846 return (count < celt) ? S_FALSE : S_OK;
849 static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
851 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
852 HANDLE handle = This->data.u.foldercoll.find;
853 WIN32_FIND_DATAW data;
855 TRACE("(%p)->(%d)\n", This, celt);
857 if (!celt) return S_OK;
859 if (!handle)
861 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
862 if (!handle) return S_FALSE;
864 This->data.u.foldercoll.find = handle;
866 else
868 if (!FindNextFileW(handle, &data))
869 return S_FALSE;
874 if (is_dir_data(&data))
875 --celt;
877 if (!celt) break;
878 } while (FindNextFileW(handle, &data));
880 return celt ? S_FALSE : S_OK;
883 static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
885 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
887 TRACE("(%p)\n", This);
889 FindClose(This->data.u.foldercoll.find);
890 This->data.u.foldercoll.find = NULL;
892 return S_OK;
895 static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
897 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
898 TRACE("(%p)->(%p)\n", This, pclone);
899 return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
902 static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
903 enumvariant_QueryInterface,
904 enumvariant_AddRef,
905 foldercoll_enumvariant_Release,
906 foldercoll_enumvariant_Next,
907 foldercoll_enumvariant_Skip,
908 foldercoll_enumvariant_Reset,
909 foldercoll_enumvariant_Clone
912 static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
914 struct enumvariant *This;
916 *newenum = NULL;
918 This = heap_alloc(sizeof(*This));
919 if (!This) return E_OUTOFMEMORY;
921 This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
922 This->ref = 1;
923 This->data.u.foldercoll.find = NULL;
924 This->data.u.foldercoll.coll = collection;
925 IFolderCollection_AddRef(&collection->IFolderCollection_iface);
927 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
929 return S_OK;
932 static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface)
934 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
935 ULONG ref = InterlockedDecrement(&This->ref);
937 TRACE("(%p)->(%d)\n", This, ref);
939 if (!ref)
941 IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
942 FindClose(This->data.u.filecoll.find);
943 heap_free(This);
946 return ref;
949 static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
951 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
952 HANDLE handle = This->data.u.filecoll.find;
953 WIN32_FIND_DATAW data;
954 ULONG count = 0;
956 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
958 if (fetched)
959 *fetched = 0;
961 if (!celt) return S_OK;
963 if (!handle)
965 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
966 if (!handle) return S_FALSE;
967 This->data.u.filecoll.find = handle;
969 else if (!FindNextFileW(handle, &data))
970 return S_FALSE;
974 if (is_file_data(&data))
976 IFile *file;
977 HRESULT hr;
978 BSTR str;
980 str = get_full_path(This->data.u.filecoll.coll->path, &data);
981 hr = create_file(str, &file);
982 SysFreeString(str);
983 if (FAILED(hr)) return hr;
985 V_VT(&var[count]) = VT_DISPATCH;
986 V_DISPATCH(&var[count]) = (IDispatch*)file;
987 if (++count >= celt) break;
989 } while (FindNextFileW(handle, &data));
991 if (fetched)
992 *fetched = count;
994 return (count < celt) ? S_FALSE : S_OK;
997 static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
999 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1000 HANDLE handle = This->data.u.filecoll.find;
1001 WIN32_FIND_DATAW data;
1003 TRACE("(%p)->(%d)\n", This, celt);
1005 if (!celt) return S_OK;
1007 if (!handle)
1009 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1010 if (!handle) return S_FALSE;
1011 This->data.u.filecoll.find = handle;
1013 else if (!FindNextFileW(handle, &data))
1014 return S_FALSE;
1018 if (is_file_data(&data))
1019 --celt;
1020 } while (celt && FindNextFileW(handle, &data));
1022 return celt ? S_FALSE : S_OK;
1025 static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface)
1027 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1029 TRACE("(%p)\n", This);
1031 FindClose(This->data.u.filecoll.find);
1032 This->data.u.filecoll.find = NULL;
1034 return S_OK;
1037 static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1039 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1040 TRACE("(%p)->(%p)\n", This, pclone);
1041 return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
1044 static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
1045 enumvariant_QueryInterface,
1046 enumvariant_AddRef,
1047 filecoll_enumvariant_Release,
1048 filecoll_enumvariant_Next,
1049 filecoll_enumvariant_Skip,
1050 filecoll_enumvariant_Reset,
1051 filecoll_enumvariant_Clone
1054 static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum)
1056 struct enumvariant *This;
1058 *newenum = NULL;
1060 This = heap_alloc(sizeof(*This));
1061 if (!This) return E_OUTOFMEMORY;
1063 This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
1064 This->ref = 1;
1065 This->data.u.filecoll.find = NULL;
1066 This->data.u.filecoll.coll = collection;
1067 IFileCollection_AddRef(&collection->IFileCollection_iface);
1069 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1071 return S_OK;
1074 static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface)
1076 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1077 ULONG ref = InterlockedDecrement(&This->ref);
1079 TRACE("(%p)->(%d)\n", This, ref);
1081 if (!ref)
1083 IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
1084 heap_free(This);
1087 return ref;
1090 static HRESULT find_next_drive(struct enumvariant *penum)
1092 int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
1094 for (; i < 32; i++)
1095 if (penum->data.u.drivecoll.coll->drives & (1 << i))
1097 penum->data.u.drivecoll.cur = i;
1098 return S_OK;
1101 return S_FALSE;
1104 static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1106 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1107 ULONG count = 0;
1109 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1111 if (fetched)
1112 *fetched = 0;
1114 if (!celt) return S_OK;
1116 while (find_next_drive(This) == S_OK)
1118 IDrive *drive;
1119 HRESULT hr;
1121 hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
1122 if (FAILED(hr)) return hr;
1124 V_VT(&var[count]) = VT_DISPATCH;
1125 V_DISPATCH(&var[count]) = (IDispatch*)drive;
1127 if (++count >= celt) break;
1130 if (fetched)
1131 *fetched = count;
1133 return (count < celt) ? S_FALSE : S_OK;
1136 static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1138 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1140 TRACE("(%p)->(%d)\n", This, celt);
1142 if (!celt) return S_OK;
1144 while (celt && find_next_drive(This) == S_OK)
1145 celt--;
1147 return celt ? S_FALSE : S_OK;
1150 static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface)
1152 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1154 TRACE("(%p)\n", This);
1156 This->data.u.drivecoll.cur = -1;
1157 return S_OK;
1160 static HRESULT WINAPI drivecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1162 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1163 FIXME("(%p)->(%p): stub\n", This, pclone);
1164 return E_NOTIMPL;
1167 static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
1168 enumvariant_QueryInterface,
1169 enumvariant_AddRef,
1170 drivecoll_enumvariant_Release,
1171 drivecoll_enumvariant_Next,
1172 drivecoll_enumvariant_Skip,
1173 drivecoll_enumvariant_Reset,
1174 drivecoll_enumvariant_Clone
1177 static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum)
1179 struct enumvariant *This;
1181 *newenum = NULL;
1183 This = heap_alloc(sizeof(*This));
1184 if (!This) return E_OUTOFMEMORY;
1186 This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
1187 This->ref = 1;
1188 This->data.u.drivecoll.coll = collection;
1189 This->data.u.drivecoll.cur = -1;
1190 IDriveCollection_AddRef(&collection->IDriveCollection_iface);
1192 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1194 return S_OK;
1197 static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
1199 struct foldercollection *This = impl_from_IFolderCollection(iface);
1201 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1203 *obj = NULL;
1205 if (IsEqualIID( riid, &IID_IFolderCollection ) ||
1206 IsEqualIID( riid, &IID_IDispatch ) ||
1207 IsEqualIID( riid, &IID_IUnknown ))
1209 *obj = iface;
1210 IFolderCollection_AddRef(iface);
1212 else
1213 return E_NOINTERFACE;
1215 return S_OK;
1218 static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
1220 struct foldercollection *This = impl_from_IFolderCollection(iface);
1221 ULONG ref = InterlockedIncrement(&This->ref);
1222 TRACE("(%p)->(%d)\n", This, ref);
1223 return ref;
1226 static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
1228 struct foldercollection *This = impl_from_IFolderCollection(iface);
1229 ULONG ref = InterlockedDecrement(&This->ref);
1230 TRACE("(%p)->(%d)\n", This, ref);
1232 if (!ref)
1234 SysFreeString(This->path);
1235 heap_free(This);
1238 return ref;
1241 static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
1243 struct foldercollection *This = impl_from_IFolderCollection(iface);
1244 TRACE("(%p)->(%p)\n", This, pctinfo);
1245 *pctinfo = 1;
1246 return S_OK;
1249 static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
1250 LCID lcid, ITypeInfo **ppTInfo)
1252 struct foldercollection *This = impl_from_IFolderCollection(iface);
1253 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1254 return get_typeinfo(IFolderCollection_tid, ppTInfo);
1257 static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
1258 LPOLESTR *rgszNames, UINT cNames,
1259 LCID lcid, DISPID *rgDispId)
1261 struct foldercollection *This = impl_from_IFolderCollection(iface);
1262 ITypeInfo *typeinfo;
1263 HRESULT hr;
1265 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1267 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1268 if(SUCCEEDED(hr))
1270 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1271 ITypeInfo_Release(typeinfo);
1274 return hr;
1277 static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
1278 REFIID riid, LCID lcid, WORD wFlags,
1279 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1280 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1282 struct foldercollection *This = impl_from_IFolderCollection(iface);
1283 ITypeInfo *typeinfo;
1284 HRESULT hr;
1286 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1287 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1289 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1290 if(SUCCEEDED(hr))
1292 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1293 pDispParams, pVarResult, pExcepInfo, puArgErr);
1294 ITypeInfo_Release(typeinfo);
1297 return hr;
1300 static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
1302 struct foldercollection *This = impl_from_IFolderCollection(iface);
1303 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
1304 return E_NOTIMPL;
1307 static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
1309 struct foldercollection *This = impl_from_IFolderCollection(iface);
1310 FIXME("(%p)->(%p): stub\n", This, folder);
1311 return E_NOTIMPL;
1314 static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
1316 struct foldercollection *This = impl_from_IFolderCollection(iface);
1318 TRACE("(%p)->(%p)\n", This, newenum);
1320 if(!newenum)
1321 return E_POINTER;
1323 return create_foldercoll_enum(This, newenum);
1326 static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
1328 struct foldercollection *This = impl_from_IFolderCollection(iface);
1329 static const WCHAR allW[] = {'\\','*',0};
1330 WIN32_FIND_DATAW data;
1331 WCHAR pathW[MAX_PATH];
1332 HANDLE handle;
1334 TRACE("(%p)->(%p)\n", This, count);
1336 if(!count)
1337 return E_POINTER;
1339 *count = 0;
1341 strcpyW(pathW, This->path);
1342 strcatW(pathW, allW);
1343 handle = FindFirstFileW(pathW, &data);
1344 if (handle == INVALID_HANDLE_VALUE)
1345 return HRESULT_FROM_WIN32(GetLastError());
1349 if (is_dir_data(&data))
1350 *count += 1;
1351 } while (FindNextFileW(handle, &data));
1352 FindClose(handle);
1354 return S_OK;
1357 static const IFolderCollectionVtbl foldercollvtbl = {
1358 foldercoll_QueryInterface,
1359 foldercoll_AddRef,
1360 foldercoll_Release,
1361 foldercoll_GetTypeInfoCount,
1362 foldercoll_GetTypeInfo,
1363 foldercoll_GetIDsOfNames,
1364 foldercoll_Invoke,
1365 foldercoll_Add,
1366 foldercoll_get_Item,
1367 foldercoll_get__NewEnum,
1368 foldercoll_get_Count
1371 static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
1373 struct foldercollection *This;
1375 *folders = NULL;
1377 This = heap_alloc(sizeof(struct foldercollection));
1378 if (!This) return E_OUTOFMEMORY;
1380 This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
1381 This->ref = 1;
1382 This->path = SysAllocString(path);
1383 if (!This->path)
1385 heap_free(This);
1386 return E_OUTOFMEMORY;
1389 *folders = &This->IFolderCollection_iface;
1391 return S_OK;
1394 static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj)
1396 struct filecollection *This = impl_from_IFileCollection(iface);
1398 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1400 *obj = NULL;
1402 if (IsEqualIID( riid, &IID_IFileCollection ) ||
1403 IsEqualIID( riid, &IID_IDispatch ) ||
1404 IsEqualIID( riid, &IID_IUnknown ))
1406 *obj = iface;
1407 IFileCollection_AddRef(iface);
1409 else
1410 return E_NOINTERFACE;
1412 return S_OK;
1415 static ULONG WINAPI filecoll_AddRef(IFileCollection *iface)
1417 struct filecollection *This = impl_from_IFileCollection(iface);
1418 ULONG ref = InterlockedIncrement(&This->ref);
1419 TRACE("(%p)->(%d)\n", This, ref);
1420 return ref;
1423 static ULONG WINAPI filecoll_Release(IFileCollection *iface)
1425 struct filecollection *This = impl_from_IFileCollection(iface);
1426 ULONG ref = InterlockedDecrement(&This->ref);
1427 TRACE("(%p)->(%d)\n", This, ref);
1429 if (!ref)
1431 SysFreeString(This->path);
1432 heap_free(This);
1435 return ref;
1438 static HRESULT WINAPI filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo)
1440 struct filecollection *This = impl_from_IFileCollection(iface);
1441 TRACE("(%p)->(%p)\n", This, pctinfo);
1442 *pctinfo = 1;
1443 return S_OK;
1446 static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo,
1447 LCID lcid, ITypeInfo **ppTInfo)
1449 struct filecollection *This = impl_from_IFileCollection(iface);
1450 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1451 return get_typeinfo(IFileCollection_tid, ppTInfo);
1454 static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid,
1455 LPOLESTR *rgszNames, UINT cNames,
1456 LCID lcid, DISPID *rgDispId)
1458 struct filecollection *This = impl_from_IFileCollection(iface);
1459 ITypeInfo *typeinfo;
1460 HRESULT hr;
1462 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1464 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1465 if(SUCCEEDED(hr))
1467 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1468 ITypeInfo_Release(typeinfo);
1471 return hr;
1474 static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember,
1475 REFIID riid, LCID lcid, WORD wFlags,
1476 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1477 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1479 struct filecollection *This = impl_from_IFileCollection(iface);
1480 ITypeInfo *typeinfo;
1481 HRESULT hr;
1483 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1484 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1486 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1487 if(SUCCEEDED(hr))
1489 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1490 pDispParams, pVarResult, pExcepInfo, puArgErr);
1491 ITypeInfo_Release(typeinfo);
1494 return hr;
1497 static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file)
1499 struct filecollection *This = impl_from_IFileCollection(iface);
1500 FIXME("(%p)->(%p)\n", This, file);
1501 return E_NOTIMPL;
1504 static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum)
1506 struct filecollection *This = impl_from_IFileCollection(iface);
1508 TRACE("(%p)->(%p)\n", This, ppenum);
1510 if(!ppenum)
1511 return E_POINTER;
1513 return create_filecoll_enum(This, ppenum);
1516 static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count)
1518 struct filecollection *This = impl_from_IFileCollection(iface);
1519 FIXME("(%p)->(%p)\n", This, count);
1520 return E_NOTIMPL;
1523 static const IFileCollectionVtbl filecollectionvtbl = {
1524 filecoll_QueryInterface,
1525 filecoll_AddRef,
1526 filecoll_Release,
1527 filecoll_GetTypeInfoCount,
1528 filecoll_GetTypeInfo,
1529 filecoll_GetIDsOfNames,
1530 filecoll_Invoke,
1531 filecoll_get_Item,
1532 filecoll_get__NewEnum,
1533 filecoll_get_Count
1536 static HRESULT create_filecoll(BSTR path, IFileCollection **files)
1538 struct filecollection *This;
1540 *files = NULL;
1542 This = heap_alloc(sizeof(*This));
1543 if (!This) return E_OUTOFMEMORY;
1545 This->IFileCollection_iface.lpVtbl = &filecollectionvtbl;
1546 This->ref = 1;
1547 This->path = SysAllocString(path);
1548 if (!This->path)
1550 heap_free(This);
1551 return E_OUTOFMEMORY;
1554 *files = &This->IFileCollection_iface;
1555 return S_OK;
1558 static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
1560 struct drivecollection *This = impl_from_IDriveCollection(iface);
1562 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1564 *obj = NULL;
1566 if (IsEqualIID( riid, &IID_IDriveCollection ) ||
1567 IsEqualIID( riid, &IID_IDispatch ) ||
1568 IsEqualIID( riid, &IID_IUnknown ))
1570 *obj = iface;
1571 IDriveCollection_AddRef(iface);
1573 else
1574 return E_NOINTERFACE;
1576 return S_OK;
1579 static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
1581 struct drivecollection *This = impl_from_IDriveCollection(iface);
1582 ULONG ref = InterlockedIncrement(&This->ref);
1583 TRACE("(%p)->(%d)\n", This, ref);
1584 return ref;
1587 static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
1589 struct drivecollection *This = impl_from_IDriveCollection(iface);
1590 ULONG ref = InterlockedDecrement(&This->ref);
1591 TRACE("(%p)->(%d)\n", This, ref);
1593 if (!ref)
1594 heap_free(This);
1596 return ref;
1599 static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
1601 struct drivecollection *This = impl_from_IDriveCollection(iface);
1602 TRACE("(%p)->(%p)\n", This, pctinfo);
1603 *pctinfo = 1;
1604 return S_OK;
1607 static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
1608 LCID lcid, ITypeInfo **ppTInfo)
1610 struct drivecollection *This = impl_from_IDriveCollection(iface);
1611 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1612 return get_typeinfo(IDriveCollection_tid, ppTInfo);
1615 static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
1616 LPOLESTR *rgszNames, UINT cNames,
1617 LCID lcid, DISPID *rgDispId)
1619 struct drivecollection *This = impl_from_IDriveCollection(iface);
1620 ITypeInfo *typeinfo;
1621 HRESULT hr;
1623 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1625 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
1626 if(SUCCEEDED(hr))
1628 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1629 ITypeInfo_Release(typeinfo);
1632 return hr;
1635 static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
1636 REFIID riid, LCID lcid, WORD wFlags,
1637 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1638 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1640 struct drivecollection *This = impl_from_IDriveCollection(iface);
1641 ITypeInfo *typeinfo;
1642 HRESULT hr;
1644 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1645 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1647 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
1648 if(SUCCEEDED(hr))
1650 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1651 pDispParams, pVarResult, pExcepInfo, puArgErr);
1652 ITypeInfo_Release(typeinfo);
1655 return hr;
1658 static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
1660 struct drivecollection *This = impl_from_IDriveCollection(iface);
1661 FIXME("(%p)->(%p): stub\n", This, drive);
1662 return E_NOTIMPL;
1665 static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
1667 struct drivecollection *This = impl_from_IDriveCollection(iface);
1669 TRACE("(%p)->(%p)\n", This, ppenum);
1671 if(!ppenum)
1672 return E_POINTER;
1674 return create_drivecoll_enum(This, ppenum);
1677 static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
1679 struct drivecollection *This = impl_from_IDriveCollection(iface);
1681 TRACE("(%p)->(%p)\n", This, count);
1683 if (!count) return E_POINTER;
1685 *count = This->count;
1686 return S_OK;
1689 static const IDriveCollectionVtbl drivecollectionvtbl = {
1690 drivecoll_QueryInterface,
1691 drivecoll_AddRef,
1692 drivecoll_Release,
1693 drivecoll_GetTypeInfoCount,
1694 drivecoll_GetTypeInfo,
1695 drivecoll_GetIDsOfNames,
1696 drivecoll_Invoke,
1697 drivecoll_get_Item,
1698 drivecoll_get__NewEnum,
1699 drivecoll_get_Count
1702 static HRESULT create_drivecoll(IDriveCollection **drives)
1704 struct drivecollection *This;
1705 DWORD mask;
1707 *drives = NULL;
1709 This = heap_alloc(sizeof(*This));
1710 if (!This) return E_OUTOFMEMORY;
1712 This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl;
1713 This->ref = 1;
1714 This->drives = mask = GetLogicalDrives();
1715 /* count set bits */
1716 for (This->count = 0; mask; This->count++)
1717 mask &= mask - 1;
1719 *drives = &This->IDriveCollection_iface;
1720 return S_OK;
1723 static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
1725 struct folder *This = impl_from_IFolder(iface);
1727 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1729 *obj = NULL;
1731 if (IsEqualIID( riid, &IID_IFolder ) ||
1732 IsEqualIID( riid, &IID_IDispatch ) ||
1733 IsEqualIID( riid, &IID_IUnknown))
1735 *obj = iface;
1736 IFolder_AddRef(iface);
1738 else
1739 return E_NOINTERFACE;
1741 return S_OK;
1744 static ULONG WINAPI folder_AddRef(IFolder *iface)
1746 struct folder *This = impl_from_IFolder(iface);
1747 ULONG ref = InterlockedIncrement(&This->ref);
1748 TRACE("(%p)->(%d)\n", This, ref);
1749 return ref;
1752 static ULONG WINAPI folder_Release(IFolder *iface)
1754 struct folder *This = impl_from_IFolder(iface);
1755 ULONG ref = InterlockedDecrement(&This->ref);
1756 TRACE("(%p)->(%d)\n", This, ref);
1758 if (!ref)
1760 SysFreeString(This->path);
1761 heap_free(This);
1764 return ref;
1767 static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
1769 struct folder *This = impl_from_IFolder(iface);
1770 TRACE("(%p)->(%p)\n", This, pctinfo);
1771 *pctinfo = 1;
1772 return S_OK;
1775 static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
1776 LCID lcid, ITypeInfo **ppTInfo)
1778 struct folder *This = impl_from_IFolder(iface);
1779 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1780 return get_typeinfo(IFolder_tid, ppTInfo);
1783 static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
1784 LPOLESTR *rgszNames, UINT cNames,
1785 LCID lcid, DISPID *rgDispId)
1787 struct folder *This = impl_from_IFolder(iface);
1788 ITypeInfo *typeinfo;
1789 HRESULT hr;
1791 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1793 hr = get_typeinfo(IFolder_tid, &typeinfo);
1794 if(SUCCEEDED(hr))
1796 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1797 ITypeInfo_Release(typeinfo);
1800 return hr;
1803 static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
1804 REFIID riid, LCID lcid, WORD wFlags,
1805 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1806 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1808 struct folder *This = impl_from_IFolder(iface);
1809 ITypeInfo *typeinfo;
1810 HRESULT hr;
1812 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1813 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1815 hr = get_typeinfo(IFolder_tid, &typeinfo);
1816 if(SUCCEEDED(hr))
1818 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1819 pDispParams, pVarResult, pExcepInfo, puArgErr);
1820 ITypeInfo_Release(typeinfo);
1823 return hr;
1826 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
1828 struct folder *This = impl_from_IFolder(iface);
1829 FIXME("(%p)->(%p): stub\n", This, path);
1830 return E_NOTIMPL;
1833 static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
1835 struct folder *This = impl_from_IFolder(iface);
1836 WCHAR *ptr;
1838 TRACE("(%p)->(%p)\n", This, name);
1840 if(!name)
1841 return E_POINTER;
1843 *name = NULL;
1845 ptr = strrchrW(This->path, '\\');
1846 if (ptr)
1848 *name = SysAllocString(ptr+1);
1849 TRACE("%s\n", debugstr_w(*name));
1850 if (!*name) return E_OUTOFMEMORY;
1852 else
1853 return E_FAIL;
1855 return S_OK;
1858 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
1860 struct folder *This = impl_from_IFolder(iface);
1861 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
1862 return E_NOTIMPL;
1865 static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
1867 struct folder *This = impl_from_IFolder(iface);
1868 FIXME("(%p)->(%p): stub\n", This, path);
1869 return E_NOTIMPL;
1872 static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
1874 struct folder *This = impl_from_IFolder(iface);
1875 FIXME("(%p)->(%p): stub\n", This, name);
1876 return E_NOTIMPL;
1879 static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
1881 struct folder *This = impl_from_IFolder(iface);
1882 FIXME("(%p)->(%p): stub\n", This, drive);
1883 return E_NOTIMPL;
1886 static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
1888 struct folder *This = impl_from_IFolder(iface);
1889 FIXME("(%p)->(%p): stub\n", This, parent);
1890 return E_NOTIMPL;
1893 static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
1895 struct folder *This = impl_from_IFolder(iface);
1896 FIXME("(%p)->(%p): stub\n", This, attr);
1897 return E_NOTIMPL;
1900 static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
1902 struct folder *This = impl_from_IFolder(iface);
1903 FIXME("(%p)->(0x%x): stub\n", This, attr);
1904 return E_NOTIMPL;
1907 static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
1909 struct folder *This = impl_from_IFolder(iface);
1910 FIXME("(%p)->(%p): stub\n", This, date);
1911 return E_NOTIMPL;
1914 static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
1916 struct folder *This = impl_from_IFolder(iface);
1917 FIXME("(%p)->(%p): stub\n", This, date);
1918 return E_NOTIMPL;
1921 static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
1923 struct folder *This = impl_from_IFolder(iface);
1924 FIXME("(%p)->(%p): stub\n", This, date);
1925 return E_NOTIMPL;
1928 static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
1930 struct folder *This = impl_from_IFolder(iface);
1931 FIXME("(%p)->(%p): stub\n", This, type);
1932 return E_NOTIMPL;
1935 static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
1937 struct folder *This = impl_from_IFolder(iface);
1938 FIXME("(%p)->(%x): stub\n", This, force);
1939 return E_NOTIMPL;
1942 static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
1944 struct folder *This = impl_from_IFolder(iface);
1945 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
1946 return E_NOTIMPL;
1949 static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
1951 struct folder *This = impl_from_IFolder(iface);
1952 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
1953 return E_NOTIMPL;
1956 static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
1958 struct folder *This = impl_from_IFolder(iface);
1959 FIXME("(%p)->(%p): stub\n", This, isroot);
1960 return E_NOTIMPL;
1963 static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
1965 struct folder *This = impl_from_IFolder(iface);
1966 FIXME("(%p)->(%p): stub\n", This, size);
1967 return E_NOTIMPL;
1970 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
1972 struct folder *This = impl_from_IFolder(iface);
1974 TRACE("(%p)->(%p)\n", This, folders);
1976 if(!folders)
1977 return E_POINTER;
1979 return create_foldercoll(This->path, folders);
1982 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
1984 struct folder *This = impl_from_IFolder(iface);
1986 TRACE("(%p)->(%p)\n", This, files);
1988 if(!files)
1989 return E_POINTER;
1991 return create_filecoll(This->path, files);
1994 static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
1995 VARIANT_BOOL unicode, ITextStream **stream)
1997 struct folder *This = impl_from_IFolder(iface);
1998 FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
1999 return E_NOTIMPL;
2002 static const IFolderVtbl foldervtbl = {
2003 folder_QueryInterface,
2004 folder_AddRef,
2005 folder_Release,
2006 folder_GetTypeInfoCount,
2007 folder_GetTypeInfo,
2008 folder_GetIDsOfNames,
2009 folder_Invoke,
2010 folder_get_Path,
2011 folder_get_Name,
2012 folder_put_Name,
2013 folder_get_ShortPath,
2014 folder_get_ShortName,
2015 folder_get_Drive,
2016 folder_get_ParentFolder,
2017 folder_get_Attributes,
2018 folder_put_Attributes,
2019 folder_get_DateCreated,
2020 folder_get_DateLastModified,
2021 folder_get_DateLastAccessed,
2022 folder_get_Type,
2023 folder_Delete,
2024 folder_Copy,
2025 folder_Move,
2026 folder_get_IsRootFolder,
2027 folder_get_Size,
2028 folder_get_SubFolders,
2029 folder_get_Files,
2030 folder_CreateTextFile
2033 HRESULT create_folder(const WCHAR *path, IFolder **folder)
2035 struct folder *This;
2037 *folder = NULL;
2039 TRACE("%s\n", debugstr_w(path));
2041 This = heap_alloc(sizeof(struct folder));
2042 if (!This) return E_OUTOFMEMORY;
2044 This->IFolder_iface.lpVtbl = &foldervtbl;
2045 This->ref = 1;
2046 This->path = SysAllocString(path);
2047 if (!This->path)
2049 heap_free(This);
2050 return E_OUTOFMEMORY;
2053 *folder = &This->IFolder_iface;
2055 return S_OK;
2058 static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
2060 struct file *This = impl_from_IFile(iface);
2062 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2064 if (IsEqualIID(riid, &IID_IFile) ||
2065 IsEqualIID(riid, &IID_IDispatch) ||
2066 IsEqualIID(riid, &IID_IUnknown))
2068 *obj = iface;
2069 IFile_AddRef(iface);
2070 return S_OK;
2073 *obj = NULL;
2074 return E_NOINTERFACE;
2077 static ULONG WINAPI file_AddRef(IFile *iface)
2079 struct file *This = impl_from_IFile(iface);
2080 LONG ref = InterlockedIncrement(&This->ref);
2082 TRACE("(%p) ref=%d\n", This, ref);
2084 return ref;
2087 static ULONG WINAPI file_Release(IFile *iface)
2089 struct file *This = impl_from_IFile(iface);
2090 LONG ref = InterlockedDecrement(&This->ref);
2092 TRACE("(%p) ref=%d\n", This, ref);
2094 if(!ref)
2096 heap_free(This->path);
2097 heap_free(This);
2100 return ref;
2103 static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
2105 struct file *This = impl_from_IFile(iface);
2107 TRACE("(%p)->(%p)\n", This, pctinfo);
2109 *pctinfo = 1;
2110 return S_OK;
2113 static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
2114 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
2116 struct file *This = impl_from_IFile(iface);
2118 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2120 return get_typeinfo(IFile_tid, ppTInfo);
2123 static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
2124 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2126 struct file *This = impl_from_IFile(iface);
2127 ITypeInfo *typeinfo;
2128 HRESULT hr;
2130 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
2131 rgszNames, cNames, lcid, rgDispId);
2133 hr = get_typeinfo(IFile_tid, &typeinfo);
2134 if(SUCCEEDED(hr)) {
2135 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2136 ITypeInfo_Release(typeinfo);
2138 return hr;
2141 static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2143 struct file *This = impl_from_IFile(iface);
2144 ITypeInfo *typeinfo;
2145 HRESULT hr;
2147 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2148 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2150 hr = get_typeinfo(IFile_tid, &typeinfo);
2151 if(SUCCEEDED(hr))
2153 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2154 pDispParams, pVarResult, pExcepInfo, puArgErr);
2155 ITypeInfo_Release(typeinfo);
2157 return hr;
2160 static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *pbstrPath)
2162 struct file *This = impl_from_IFile(iface);
2163 FIXME("(%p)->(%p)\n", This, pbstrPath);
2164 return E_NOTIMPL;
2167 static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
2169 struct file *This = impl_from_IFile(iface);
2170 WCHAR *ptr;
2172 TRACE("(%p)->(%p)\n", This, name);
2174 if(!name)
2175 return E_POINTER;
2177 *name = NULL;
2179 ptr = strrchrW(This->path, '\\');
2180 if (ptr)
2182 *name = SysAllocString(ptr+1);
2183 TRACE("%s\n", debugstr_w(*name));
2184 if (!*name) return E_OUTOFMEMORY;
2186 else
2187 return E_FAIL;
2189 return S_OK;
2192 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
2194 struct file *This = impl_from_IFile(iface);
2195 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
2196 return E_NOTIMPL;
2199 static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
2201 struct file *This = impl_from_IFile(iface);
2202 FIXME("(%p)->(%p)\n", This, pbstrPath);
2203 return E_NOTIMPL;
2206 static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
2208 struct file *This = impl_from_IFile(iface);
2209 FIXME("(%p)->(%p)\n", This, pbstrName);
2210 return E_NOTIMPL;
2213 static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
2215 struct file *This = impl_from_IFile(iface);
2216 FIXME("(%p)->(%p)\n", This, ppdrive);
2217 return E_NOTIMPL;
2220 static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
2222 struct file *This = impl_from_IFile(iface);
2223 FIXME("(%p)->(%p)\n", This, ppfolder);
2224 return E_NOTIMPL;
2227 static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
2229 struct file *This = impl_from_IFile(iface);
2230 DWORD fa;
2232 TRACE("(%p)->(%p)\n", This, pfa);
2234 if(!pfa)
2235 return E_POINTER;
2237 fa = GetFileAttributesW(This->path);
2238 if(fa == INVALID_FILE_ATTRIBUTES)
2239 return create_error(GetLastError());
2241 *pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2242 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
2243 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
2244 return S_OK;
2247 static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
2249 struct file *This = impl_from_IFile(iface);
2250 FIXME("(%p)->(%x)\n", This, pfa);
2251 return E_NOTIMPL;
2254 static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
2256 struct file *This = impl_from_IFile(iface);
2257 FIXME("(%p)->(%p)\n", This, pdate);
2258 return E_NOTIMPL;
2261 static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *pdate)
2263 struct file *This = impl_from_IFile(iface);
2264 FIXME("(%p)->(%p)\n", This, pdate);
2265 return E_NOTIMPL;
2268 static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
2270 struct file *This = impl_from_IFile(iface);
2271 FIXME("(%p)->(%p)\n", This, pdate);
2272 return E_NOTIMPL;
2275 static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
2277 struct file *This = impl_from_IFile(iface);
2278 WIN32_FIND_DATAW fd;
2279 HANDLE f;
2281 TRACE("(%p)->(%p)\n", This, pvarSize);
2283 if(!pvarSize)
2284 return E_POINTER;
2286 f = FindFirstFileW(This->path, &fd);
2287 if(f == INVALID_HANDLE_VALUE)
2288 return create_error(GetLastError());
2289 FindClose(f);
2291 if(fd.nFileSizeHigh || fd.nFileSizeLow>INT_MAX) {
2292 V_VT(pvarSize) = VT_R8;
2293 V_R8(pvarSize) = ((ULONGLONG)fd.nFileSizeHigh<<32) + fd.nFileSizeLow;
2294 }else {
2295 V_VT(pvarSize) = VT_I4;
2296 V_I4(pvarSize) = fd.nFileSizeLow;
2298 return S_OK;
2301 static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
2303 struct file *This = impl_from_IFile(iface);
2304 FIXME("(%p)->(%p)\n", This, pbstrType);
2305 return E_NOTIMPL;
2308 static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
2310 struct file *This = impl_from_IFile(iface);
2311 FIXME("(%p)->(%x)\n", This, Force);
2312 return E_NOTIMPL;
2315 static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
2317 struct file *This = impl_from_IFile(iface);
2318 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
2319 return E_NOTIMPL;
2322 static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
2324 struct file *This = impl_from_IFile(iface);
2325 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
2326 return E_NOTIMPL;
2329 static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode IOMode, Tristate Format, ITextStream **ppts)
2331 struct file *This = impl_from_IFile(iface);
2332 FIXME("(%p)->(%x %x %p)\n", This, IOMode, Format, ppts);
2333 return E_NOTIMPL;
2336 static const IFileVtbl file_vtbl = {
2337 file_QueryInterface,
2338 file_AddRef,
2339 file_Release,
2340 file_GetTypeInfoCount,
2341 file_GetTypeInfo,
2342 file_GetIDsOfNames,
2343 file_Invoke,
2344 file_get_Path,
2345 file_get_Name,
2346 file_put_Name,
2347 file_get_ShortPath,
2348 file_get_ShortName,
2349 file_get_Drive,
2350 file_get_ParentFolder,
2351 file_get_Attributes,
2352 file_put_Attributes,
2353 file_get_DateCreated,
2354 file_get_DateLastModified,
2355 file_get_DateLastAccessed,
2356 file_get_Size,
2357 file_get_Type,
2358 file_Delete,
2359 file_Copy,
2360 file_Move,
2361 file_OpenAsTextStream
2364 static HRESULT create_file(BSTR path, IFile **file)
2366 struct file *f;
2367 DWORD len, attrs;
2369 *file = NULL;
2371 f = heap_alloc(sizeof(struct file));
2372 if(!f)
2373 return E_OUTOFMEMORY;
2375 f->IFile_iface.lpVtbl = &file_vtbl;
2376 f->ref = 1;
2378 len = GetFullPathNameW(path, 0, NULL, NULL);
2379 if(!len) {
2380 heap_free(f);
2381 return E_FAIL;
2384 f->path = heap_alloc(len*sizeof(WCHAR));
2385 if(!f->path) {
2386 heap_free(f);
2387 return E_OUTOFMEMORY;
2390 if(!GetFullPathNameW(path, len, f->path, NULL)) {
2391 heap_free(f->path);
2392 heap_free(f);
2393 return E_FAIL;
2396 if(path[len-1]=='/' || path[len-1]=='\\')
2397 path[len-1] = 0;
2399 attrs = GetFileAttributesW(f->path);
2400 if(attrs==INVALID_FILE_ATTRIBUTES ||
2401 (attrs&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))) {
2402 heap_free(f->path);
2403 heap_free(f);
2404 return create_error(GetLastError());
2407 *file = &f->IFile_iface;
2408 return S_OK;
2411 static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
2413 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
2415 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
2416 IsEqualGUID( riid, &IID_IFileSystem ) ||
2417 IsEqualGUID( riid, &IID_IDispatch ) ||
2418 IsEqualGUID( riid, &IID_IUnknown ) )
2420 *ppvObject = iface;
2422 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
2424 TRACE("Interface IDispatchEx not supported - returning NULL\n");
2425 *ppvObject = NULL;
2426 return E_NOINTERFACE;
2428 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
2430 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
2431 *ppvObject = NULL;
2432 return E_NOINTERFACE;
2434 else
2436 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
2437 return E_NOINTERFACE;
2440 IFileSystem3_AddRef(iface);
2442 return S_OK;
2445 static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
2447 TRACE("%p\n", iface);
2449 return 2;
2452 static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
2454 TRACE("%p\n", iface);
2456 return 1;
2459 static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
2461 TRACE("(%p)->(%p)\n", iface, pctinfo);
2463 *pctinfo = 1;
2464 return S_OK;
2467 static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
2468 LCID lcid, ITypeInfo **ppTInfo)
2470 TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
2471 return get_typeinfo(IFileSystem3_tid, ppTInfo);
2474 static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
2475 LPOLESTR *rgszNames, UINT cNames,
2476 LCID lcid, DISPID *rgDispId)
2478 ITypeInfo *typeinfo;
2479 HRESULT hr;
2481 TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2483 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2484 if(SUCCEEDED(hr))
2486 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2487 ITypeInfo_Release(typeinfo);
2490 return hr;
2493 static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
2494 REFIID riid, LCID lcid, WORD wFlags,
2495 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2496 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2498 ITypeInfo *typeinfo;
2499 HRESULT hr;
2501 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
2502 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2504 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2505 if(SUCCEEDED(hr))
2507 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2508 pDispParams, pVarResult, pExcepInfo, puArgErr);
2509 ITypeInfo_Release(typeinfo);
2512 return hr;
2515 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
2517 TRACE("%p %p\n", iface, ppdrives);
2518 return create_drivecoll(ppdrives);
2521 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
2522 BSTR Name, BSTR *Result)
2524 BSTR ret;
2526 TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
2528 if (!Result) return E_POINTER;
2530 if (Path && Name)
2532 int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
2534 /* if both parts have backslashes strip one from Path */
2535 if (Path[path_len-1] == '\\' && Name[0] == '\\')
2537 path_len -= 1;
2539 ret = SysAllocStringLen(NULL, path_len + name_len);
2540 if (ret)
2542 strcpyW(ret, Path);
2543 ret[path_len] = 0;
2544 strcatW(ret, Name);
2547 else if (Path[path_len-1] != '\\' && Name[0] != '\\')
2549 ret = SysAllocStringLen(NULL, path_len + name_len + 1);
2550 if (ret)
2552 strcpyW(ret, Path);
2553 if (Path[path_len-1] != ':')
2554 strcatW(ret, bsW);
2555 strcatW(ret, Name);
2558 else
2560 ret = SysAllocStringLen(NULL, path_len + name_len);
2561 if (ret)
2563 strcpyW(ret, Path);
2564 strcatW(ret, Name);
2568 else if (Path || Name)
2569 ret = SysAllocString(Path ? Path : Name);
2570 else
2571 ret = SysAllocStringLen(NULL, 0);
2573 if (!ret) return E_OUTOFMEMORY;
2574 *Result = ret;
2576 return S_OK;
2579 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR Path,
2580 BSTR *pbstrResult)
2582 FIXME("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2584 return E_NOTIMPL;
2587 static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
2589 int i;
2591 if(!path)
2592 return 0;
2594 for(i=len-1; i>=0; i--)
2595 if(path[i]!='/' && path[i]!='\\')
2596 break;
2598 for(; i>=0; i--)
2599 if(path[i]=='/' || path[i]=='\\')
2600 break;
2602 for(; i>=0; i--)
2603 if(path[i]!='/' && path[i]!='\\')
2604 break;
2606 if(i < 0)
2607 return 0;
2609 if(path[i]==':' && i==1)
2610 i++;
2611 return i+1;
2614 static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
2615 BSTR *pbstrResult)
2617 DWORD len;
2619 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2621 if(!pbstrResult)
2622 return E_POINTER;
2624 len = get_parent_folder_name(Path, SysStringLen(Path));
2625 if(!len) {
2626 *pbstrResult = NULL;
2627 return S_OK;
2630 *pbstrResult = SysAllocStringLen(Path, len);
2631 if(!*pbstrResult)
2632 return E_OUTOFMEMORY;
2633 return S_OK;
2636 static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
2637 BSTR *pbstrResult)
2639 int i, end;
2641 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2643 if(!pbstrResult)
2644 return E_POINTER;
2646 if(!Path) {
2647 *pbstrResult = NULL;
2648 return S_OK;
2651 for(end=strlenW(Path)-1; end>=0; end--)
2652 if(Path[end]!='/' && Path[end]!='\\')
2653 break;
2655 for(i=end; i>=0; i--)
2656 if(Path[i]=='/' || Path[i]=='\\')
2657 break;
2658 i++;
2660 if(i>end || (i==0 && end==1 && Path[1]==':')) {
2661 *pbstrResult = NULL;
2662 return S_OK;
2665 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
2666 if(!*pbstrResult)
2667 return E_OUTOFMEMORY;
2668 return S_OK;
2671 static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
2672 BSTR *pbstrResult)
2674 int i, end;
2676 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2678 if(!pbstrResult)
2679 return E_POINTER;
2681 if(!Path) {
2682 *pbstrResult = NULL;
2683 return S_OK;
2686 for(end=strlenW(Path)-1; end>=0; end--)
2687 if(Path[end]!='/' && Path[end]!='\\')
2688 break;
2690 for(i=end; i>=0; i--) {
2691 if(Path[i]=='.' && Path[end+1]!='.')
2692 end = i-1;
2693 if(Path[i]=='/' || Path[i]=='\\')
2694 break;
2696 i++;
2698 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
2699 *pbstrResult = NULL;
2700 return S_OK;
2703 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
2704 if(!*pbstrResult)
2705 return E_OUTOFMEMORY;
2706 return S_OK;
2709 static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR Path,
2710 BSTR *pbstrResult)
2712 FIXME("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2714 return E_NOTIMPL;
2717 static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR Path,
2718 BSTR *pbstrResult)
2720 static const WCHAR cur_path[] = {'.',0};
2722 WCHAR buf[MAX_PATH], ch;
2723 const WCHAR *path;
2724 DWORD i, beg, len, exp_len;
2725 WIN32_FIND_DATAW fdata;
2726 HANDLE fh;
2728 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2730 if(!pbstrResult)
2731 return E_POINTER;
2733 if(!Path)
2734 path = cur_path;
2735 else
2736 path = Path;
2738 len = GetFullPathNameW(path, MAX_PATH, buf, NULL);
2739 if(!len)
2740 return E_FAIL;
2742 buf[0] = toupperW(buf[0]);
2743 if(len>3 && buf[len-1] == '\\')
2744 buf[--len] = 0;
2746 for(beg=3, i=3; i<=len; i++) {
2747 if(buf[i]!='\\' && buf[i])
2748 continue;
2750 ch = buf[i];
2751 buf[i] = 0;
2752 fh = FindFirstFileW(buf, &fdata);
2753 if(fh == INVALID_HANDLE_VALUE)
2754 break;
2756 exp_len = strlenW(fdata.cFileName);
2757 if(exp_len == i-beg)
2758 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
2759 FindClose(fh);
2760 buf[i] = ch;
2761 beg = i+1;
2764 *pbstrResult = SysAllocString(buf);
2765 if(!*pbstrResult)
2766 return E_OUTOFMEMORY;
2767 return S_OK;
2770 static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
2772 static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
2774 DWORD random;
2776 TRACE("%p %p\n", iface, pbstrResult);
2778 if(!pbstrResult)
2779 return E_POINTER;
2781 *pbstrResult = SysAllocStringLen(NULL, 12);
2782 if(!*pbstrResult)
2783 return E_OUTOFMEMORY;
2785 if(!RtlGenRandom(&random, sizeof(random)))
2786 return E_FAIL;
2787 sprintfW(*pbstrResult, fmt, random & 0xfffff);
2788 return S_OK;
2791 static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
2792 VARIANT_BOOL *pfExists)
2794 FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
2796 return E_NOTIMPL;
2799 static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
2801 DWORD attrs;
2802 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
2804 if (!ret) return E_POINTER;
2806 attrs = GetFileAttributesW(path);
2807 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
2808 return S_OK;
2811 static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
2813 DWORD attrs;
2814 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
2816 if (!ret) return E_POINTER;
2818 attrs = GetFileAttributesW(path);
2819 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
2821 return S_OK;
2824 static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
2825 IDrive **ppdrive)
2827 FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
2829 return E_NOTIMPL;
2832 static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
2833 IFile **ppfile)
2835 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
2837 if(!ppfile)
2838 return E_POINTER;
2839 if(!FilePath)
2840 return E_INVALIDARG;
2842 return create_file(FilePath, ppfile);
2845 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
2846 IFolder **folder)
2848 DWORD attrs;
2850 TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
2852 if(!folder)
2853 return E_POINTER;
2855 *folder = NULL;
2856 if(!FolderPath)
2857 return E_INVALIDARG;
2859 attrs = GetFileAttributesW(FolderPath);
2860 if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
2861 return CTL_E_PATHNOTFOUND;
2863 return create_folder(FolderPath, folder);
2866 static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
2867 SpecialFolderConst SpecialFolder,
2868 IFolder **ppfolder)
2870 FIXME("%p %d %p\n", iface, SpecialFolder, ppfolder);
2872 return E_NOTIMPL;
2875 static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
2877 WCHAR path[MAX_PATH];
2878 DWORD len, name_len;
2879 WIN32_FIND_DATAW ffd;
2880 HANDLE f;
2882 f = FindFirstFileW(file, &ffd);
2883 if(f == INVALID_HANDLE_VALUE)
2884 return create_error(GetLastError());
2886 len = get_parent_folder_name(file, file_len);
2887 if(len+1 >= MAX_PATH) {
2888 FindClose(f);
2889 return E_FAIL;
2891 if(len) {
2892 memcpy(path, file, len*sizeof(WCHAR));
2893 path[len++] = '\\';
2896 do {
2897 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
2898 continue;
2900 name_len = strlenW(ffd.cFileName);
2901 if(len+name_len+1 >= MAX_PATH) {
2902 FindClose(f);
2903 return E_FAIL;
2905 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
2907 TRACE("deleting %s\n", debugstr_w(path));
2909 if(!DeleteFileW(path)) {
2910 if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
2911 || !DeleteFileW(path)) {
2912 FindClose(f);
2913 return create_error(GetLastError());
2916 } while(FindNextFileW(f, &ffd));
2917 FindClose(f);
2919 return S_OK;
2922 static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
2923 VARIANT_BOOL Force)
2925 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
2927 if(!FileSpec)
2928 return E_POINTER;
2930 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
2933 static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
2935 WCHAR path[MAX_PATH];
2936 DWORD len, name_len;
2937 WIN32_FIND_DATAW ffd;
2938 HANDLE f;
2939 HRESULT hr;
2941 f = FindFirstFileW(folder, &ffd);
2942 if(f == INVALID_HANDLE_VALUE)
2943 return create_error(GetLastError());
2945 len = get_parent_folder_name(folder, folder_len);
2946 if(len+1 >= MAX_PATH) {
2947 FindClose(f);
2948 return E_FAIL;
2950 if(len) {
2951 memcpy(path, folder, len*sizeof(WCHAR));
2952 path[len++] = '\\';
2955 do {
2956 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
2957 continue;
2958 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
2959 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
2960 continue;
2962 name_len = strlenW(ffd.cFileName);
2963 if(len+name_len+3 >= MAX_PATH) {
2964 FindClose(f);
2965 return E_FAIL;
2967 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
2968 path[len+name_len] = '\\';
2969 path[len+name_len+1] = '*';
2970 path[len+name_len+2] = 0;
2972 hr = delete_file(path, len+name_len+2, force);
2973 if(FAILED(hr)) {
2974 FindClose(f);
2975 return hr;
2978 hr = delete_folder(path, len+name_len+2, force);
2979 if(FAILED(hr)) {
2980 FindClose(f);
2981 return hr;
2984 path[len+name_len] = 0;
2985 TRACE("deleting %s\n", debugstr_w(path));
2987 if(!RemoveDirectoryW(path)) {
2988 FindClose(f);
2989 return create_error(GetLastError());
2991 } while(FindNextFileW(f, &ffd));
2992 FindClose(f);
2994 return S_OK;
2997 static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
2998 VARIANT_BOOL Force)
3000 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
3002 if(!FolderSpec)
3003 return E_POINTER;
3005 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
3008 static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR Source,
3009 BSTR Destination)
3011 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3013 return E_NOTIMPL;
3016 static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
3017 BSTR Destination)
3019 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3021 return E_NOTIMPL;
3024 static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
3025 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
3027 DWORD attrs;
3028 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
3029 DWORD src_len, dst_len, name_len;
3030 WIN32_FIND_DATAW ffd;
3031 HANDLE f;
3032 HRESULT hr;
3034 if(!source[0] || !destination[0])
3035 return E_INVALIDARG;
3037 attrs = GetFileAttributesW(destination);
3038 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
3039 attrs = GetFileAttributesW(source);
3040 if(attrs == INVALID_FILE_ATTRIBUTES)
3041 return create_error(GetLastError());
3042 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
3043 return CTL_E_FILENOTFOUND;
3045 if(!CopyFileW(source, destination, !overwrite))
3046 return create_error(GetLastError());
3047 return S_OK;
3050 f = FindFirstFileW(source, &ffd);
3051 if(f == INVALID_HANDLE_VALUE)
3052 return CTL_E_FILENOTFOUND;
3054 src_len = get_parent_folder_name(source, source_len);
3055 if(src_len+1 >= MAX_PATH)
3056 return E_FAIL;
3057 if(src_len) {
3058 memcpy(src_path, source, src_len*sizeof(WCHAR));
3059 src_path[src_len++] = '\\';
3062 dst_len = destination_len;
3063 if(dst_len+1 >= MAX_PATH) {
3064 FindClose(f);
3065 return E_FAIL;
3067 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
3068 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
3069 dst_path[dst_len++] = '\\';
3071 hr = CTL_E_FILENOTFOUND;
3072 do {
3073 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3074 continue;
3076 name_len = strlenW(ffd.cFileName);
3077 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
3078 FindClose(f);
3079 return E_FAIL;
3081 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3082 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3084 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
3086 if(!CopyFileW(src_path, dst_path, !overwrite)) {
3087 FindClose(f);
3088 return create_error(GetLastError());
3089 }else {
3090 hr = S_OK;
3092 } while(FindNextFileW(f, &ffd));
3093 FindClose(f);
3095 return hr;
3098 static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
3099 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3101 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3103 if(!Source || !Destination)
3104 return E_POINTER;
3106 return copy_file(Source, SysStringLen(Source), Destination,
3107 SysStringLen(Destination), OverWriteFiles);
3110 static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
3111 DWORD destination_len, VARIANT_BOOL overwrite)
3113 DWORD tmp, src_len, dst_len, name_len;
3114 WCHAR src[MAX_PATH], dst[MAX_PATH];
3115 WIN32_FIND_DATAW ffd;
3116 HANDLE f;
3117 HRESULT hr;
3118 BOOL copied = FALSE;
3120 if(!source[0] || !destination[0])
3121 return E_INVALIDARG;
3123 dst_len = destination_len;
3124 if(dst_len+1 >= MAX_PATH)
3125 return E_FAIL;
3126 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
3128 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
3129 (tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
3130 tmp&FILE_ATTRIBUTE_DIRECTORY) {
3131 if(!CreateDirectoryW(dst, NULL)) {
3132 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3133 tmp = GetFileAttributesW(dst);
3134 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
3135 return CTL_E_FILEALREADYEXISTS;
3136 }else {
3137 return create_error(GetLastError());
3140 copied = TRUE;
3142 src_len = source_len;
3143 if(src_len+2 >= MAX_PATH)
3144 return E_FAIL;
3145 memcpy(src, source, src_len*sizeof(WCHAR));
3146 src[src_len++] = '\\';
3147 src[src_len] = '*';
3148 src[src_len+1] = 0;
3150 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
3151 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
3152 return create_error(GetLastError());
3154 f = FindFirstFileW(src, &ffd);
3155 }else {
3156 src_len = get_parent_folder_name(source, source_len);
3157 if(src_len+2 >= MAX_PATH)
3158 return E_FAIL;
3159 memcpy(src, source, src_len*sizeof(WCHAR));
3160 if(src_len)
3161 src[src_len++] = '\\';
3163 f = FindFirstFileW(source, &ffd);
3165 if(f == INVALID_HANDLE_VALUE)
3166 return CTL_E_PATHNOTFOUND;
3168 dst[dst_len++] = '\\';
3169 dst[dst_len] = 0;
3171 do {
3172 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3173 continue;
3174 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3175 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3176 continue;
3178 name_len = strlenW(ffd.cFileName);
3179 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
3180 FindClose(f);
3181 return E_FAIL;
3183 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
3184 dst[dst_len+name_len] = 0;
3185 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
3186 src[src_len+name_len] = '\\';
3187 src[src_len+name_len+1] = '*';
3188 src[src_len+name_len+2] = 0;
3190 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
3192 if(!CreateDirectoryW(dst, NULL)) {
3193 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3194 tmp = GetFileAttributesW(dst);
3195 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
3196 FindClose(f);
3197 return CTL_E_FILEALREADYEXISTS;
3199 }else {
3200 FindClose(f);
3201 return create_error(GetLastError());
3203 return create_error(GetLastError());
3205 copied = TRUE;
3207 hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3208 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
3209 FindClose(f);
3210 return hr;
3213 hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3214 if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
3215 FindClose(f);
3216 return hr;
3218 } while(FindNextFileW(f, &ffd));
3219 FindClose(f);
3221 return copied ? S_OK : CTL_E_PATHNOTFOUND;
3224 static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
3225 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3227 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3229 if(!Source || !Destination)
3230 return E_POINTER;
3232 return copy_folder(Source, SysStringLen(Source), Destination,
3233 SysStringLen(Destination), OverWriteFiles);
3236 static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
3237 IFolder **folder)
3239 BOOL ret;
3241 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
3243 ret = CreateDirectoryW(path, NULL);
3244 if (!ret)
3246 *folder = NULL;
3247 if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
3248 return HRESULT_FROM_WIN32(GetLastError());
3251 return create_folder(path, folder);
3254 static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR FileName,
3255 VARIANT_BOOL Overwrite, VARIANT_BOOL Unicode,
3256 ITextStream **ppts)
3258 FIXME("%p %s %d %d %p\n", iface, debugstr_w(FileName), Overwrite, Unicode, ppts);
3260 return E_NOTIMPL;
3263 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
3264 IOMode mode, VARIANT_BOOL create,
3265 Tristate format, ITextStream **stream)
3267 FIXME("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
3268 return create_textstream(mode, stream);
3271 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
3272 StandardStreamTypes StandardStreamType,
3273 VARIANT_BOOL Unicode,
3274 ITextStream **ppts)
3276 FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
3278 return E_NOTIMPL;
3281 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
3283 static const WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
3284 DWORDLONG version;
3285 WORD a, b, c, d;
3287 version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
3288 a = (WORD)( version >> 48);
3289 b = (WORD)((version >> 32) & 0xffff);
3290 c = (WORD)((version >> 16) & 0xffff);
3291 d = (WORD)( version & 0xffff);
3293 sprintfW(ver, fmtW, a, b, c, d);
3296 static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
3298 static const WCHAR rootW[] = {'\\',0};
3299 VS_FIXEDFILEINFO *info;
3300 WCHAR ver[30];
3301 void *ptr;
3302 DWORD len;
3303 BOOL ret;
3305 TRACE("%p %s %p\n", iface, debugstr_w(name), version);
3307 len = GetFileVersionInfoSizeW(name, NULL);
3308 if (!len)
3309 return HRESULT_FROM_WIN32(GetLastError());
3311 ptr = heap_alloc(len);
3312 if (!GetFileVersionInfoW(name, 0, len, ptr))
3314 heap_free(ptr);
3315 return HRESULT_FROM_WIN32(GetLastError());
3318 ret = VerQueryValueW(ptr, rootW, (void**)&info, &len);
3319 heap_free(ptr);
3320 if (!ret)
3321 return HRESULT_FROM_WIN32(GetLastError());
3323 get_versionstring(info, ver);
3324 *version = SysAllocString(ver);
3325 TRACE("version=%s\n", debugstr_w(ver));
3327 return S_OK;
3330 static const struct IFileSystem3Vtbl filesys_vtbl =
3332 filesys_QueryInterface,
3333 filesys_AddRef,
3334 filesys_Release,
3335 filesys_GetTypeInfoCount,
3336 filesys_GetTypeInfo,
3337 filesys_GetIDsOfNames,
3338 filesys_Invoke,
3339 filesys_get_Drives,
3340 filesys_BuildPath,
3341 filesys_GetDriveName,
3342 filesys_GetParentFolderName,
3343 filesys_GetFileName,
3344 filesys_GetBaseName,
3345 filesys_GetExtensionName,
3346 filesys_GetAbsolutePathName,
3347 filesys_GetTempName,
3348 filesys_DriveExists,
3349 filesys_FileExists,
3350 filesys_FolderExists,
3351 filesys_GetDrive,
3352 filesys_GetFile,
3353 filesys_GetFolder,
3354 filesys_GetSpecialFolder,
3355 filesys_DeleteFile,
3356 filesys_DeleteFolder,
3357 filesys_MoveFile,
3358 filesys_MoveFolder,
3359 filesys_CopyFile,
3360 filesys_CopyFolder,
3361 filesys_CreateFolder,
3362 filesys_CreateTextFile,
3363 filesys_OpenTextFile,
3364 filesys_GetStandardStream,
3365 filesys_GetFileVersion
3368 static IFileSystem3 filesystem = { &filesys_vtbl };
3370 HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
3372 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
3374 return IFileSystem3_QueryInterface(&filesystem, riid, ppv);