reg: Stop parsing REG_SZ values containing NUL character sequences.
[wine/zf.git] / dlls / scrrun / filesystem.c
blobd537239b3a1630cb019a6dce2b597b0e974e3c07
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 <stdarg.h>
22 #include <limits.h>
23 #include <assert.h>
24 #include <wchar.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "ole2.h"
29 #include "olectl.h"
30 #include "dispex.h"
31 #include "ntsecapi.h"
32 #include "scrrun.h"
33 #include "scrrun_private.h"
35 #include "wine/debug.h"
36 #include "wine/heap.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
40 static const WCHAR bsW[] = {'\\',0};
41 static const WCHAR utf16bom = 0xfeff;
43 struct filesystem {
44 struct provideclassinfo classinfo;
45 IFileSystem3 IFileSystem3_iface;
48 struct foldercollection {
49 struct provideclassinfo classinfo;
50 IFolderCollection IFolderCollection_iface;
51 LONG ref;
52 BSTR path;
55 struct filecollection {
56 struct provideclassinfo classinfo;
57 IFileCollection IFileCollection_iface;
58 LONG ref;
59 BSTR path;
62 struct drivecollection {
63 struct provideclassinfo classinfo;
64 IDriveCollection IDriveCollection_iface;
65 LONG ref;
66 DWORD drives;
67 LONG count;
70 struct enumdata {
71 union
73 struct
75 struct foldercollection *coll;
76 HANDLE find;
77 } foldercoll;
78 struct
80 struct filecollection *coll;
81 HANDLE find;
82 } filecoll;
83 struct
85 struct drivecollection *coll;
86 INT cur;
87 } drivecoll;
88 } u;
91 struct enumvariant {
92 IEnumVARIANT IEnumVARIANT_iface;
93 LONG ref;
95 struct enumdata data;
98 struct drive {
99 struct provideclassinfo classinfo;
100 IDrive IDrive_iface;
101 LONG ref;
102 BSTR root;
105 struct folder {
106 struct provideclassinfo classinfo;
107 IFolder IFolder_iface;
108 LONG ref;
109 BSTR path;
112 struct file {
113 struct provideclassinfo classinfo;
114 IFile IFile_iface;
115 LONG ref;
117 WCHAR *path;
120 struct textstream {
121 struct provideclassinfo classinfo;
122 ITextStream ITextStream_iface;
123 LONG ref;
125 IOMode mode;
126 BOOL unicode;
127 LARGE_INTEGER size;
128 HANDLE file;
130 BOOL eof;
131 WCHAR *read_buf;
132 size_t read_buf_size;
135 enum iotype {
136 IORead,
137 IOWrite
140 static inline struct filesystem *impl_from_IFileSystem3(IFileSystem3 *iface)
142 return CONTAINING_RECORD(iface, struct filesystem, IFileSystem3_iface);
145 static inline struct drive *impl_from_IDrive(IDrive *iface)
147 return CONTAINING_RECORD(iface, struct drive, IDrive_iface);
150 static inline struct folder *impl_from_IFolder(IFolder *iface)
152 return CONTAINING_RECORD(iface, struct folder, IFolder_iface);
155 static inline struct file *impl_from_IFile(IFile *iface)
157 return CONTAINING_RECORD(iface, struct file, IFile_iface);
160 static inline struct textstream *impl_from_ITextStream(ITextStream *iface)
162 return CONTAINING_RECORD(iface, struct textstream, ITextStream_iface);
165 static inline struct foldercollection *impl_from_IFolderCollection(IFolderCollection *iface)
167 return CONTAINING_RECORD(iface, struct foldercollection, IFolderCollection_iface);
170 static inline struct filecollection *impl_from_IFileCollection(IFileCollection *iface)
172 return CONTAINING_RECORD(iface, struct filecollection, IFileCollection_iface);
175 static inline struct drivecollection *impl_from_IDriveCollection(IDriveCollection *iface)
177 return CONTAINING_RECORD(iface, struct drivecollection, IDriveCollection_iface);
180 static inline struct enumvariant *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
182 return CONTAINING_RECORD(iface, struct enumvariant, IEnumVARIANT_iface);
185 static inline HRESULT create_error(DWORD err)
187 switch(err) {
188 case ERROR_FILE_NOT_FOUND: return CTL_E_FILENOTFOUND;
189 case ERROR_PATH_NOT_FOUND: return CTL_E_PATHNOTFOUND;
190 case ERROR_ACCESS_DENIED: return CTL_E_PERMISSIONDENIED;
191 case ERROR_FILE_EXISTS: return CTL_E_FILEALREADYEXISTS;
192 case ERROR_ALREADY_EXISTS: return CTL_E_FILEALREADYEXISTS;
193 default:
194 FIXME("Unsupported error code: %d\n", err);
195 return E_FAIL;
199 static HRESULT create_folder(const WCHAR*, IFolder**);
200 static HRESULT create_file(BSTR, IFile**);
201 static HRESULT create_foldercoll_enum(struct foldercollection*, IUnknown**);
202 static HRESULT create_filecoll_enum(struct filecollection*, IUnknown**);
203 static HRESULT create_drivecoll_enum(struct drivecollection*, IUnknown**);
205 static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data)
207 static const WCHAR dotdotW[] = {'.','.',0};
208 static const WCHAR dotW[] = {'.',0};
210 return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
211 wcscmp(data->cFileName, dotdotW) &&
212 wcscmp(data->cFileName, dotW);
215 static inline BOOL is_file_data(const WIN32_FIND_DATAW *data)
217 return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
220 static BSTR get_full_path(BSTR path, const WIN32_FIND_DATAW *data)
222 int len = SysStringLen(path);
223 WCHAR buffW[MAX_PATH];
225 lstrcpyW(buffW, path);
226 if (path[len-1] != '\\')
227 lstrcatW(buffW, bsW);
228 lstrcatW(buffW, data->cFileName);
230 return SysAllocString(buffW);
233 static BOOL textstream_check_iomode(struct textstream *This, enum iotype type)
235 if (type == IORead)
236 return This->mode == ForWriting || This->mode == ForAppending;
237 else
238 return This->mode == ForReading;
241 static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
243 struct textstream *This = impl_from_ITextStream(iface);
245 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
247 if (IsEqualIID(riid, &IID_ITextStream) ||
248 IsEqualIID(riid, &IID_IDispatch) ||
249 IsEqualIID(riid, &IID_IUnknown))
251 *obj = &This->ITextStream_iface;
253 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
255 *obj = &This->classinfo.IProvideClassInfo_iface;
257 else
258 return E_NOINTERFACE;
260 IUnknown_AddRef((IUnknown*)*obj);
261 return S_OK;
264 static ULONG WINAPI textstream_AddRef(ITextStream *iface)
266 struct textstream *This = impl_from_ITextStream(iface);
267 ULONG ref = InterlockedIncrement(&This->ref);
268 TRACE("(%p)->(%d)\n", This, ref);
269 return ref;
272 static ULONG WINAPI textstream_Release(ITextStream *iface)
274 struct textstream *This = impl_from_ITextStream(iface);
275 ULONG ref = InterlockedDecrement(&This->ref);
276 TRACE("(%p)->(%d)\n", This, ref);
278 if (!ref)
280 if (This->read_buf_size) heap_free(This->read_buf);
281 CloseHandle(This->file);
282 heap_free(This);
285 return ref;
288 static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
290 struct textstream *This = impl_from_ITextStream(iface);
291 TRACE("(%p)->(%p)\n", This, pctinfo);
292 *pctinfo = 1;
293 return S_OK;
296 static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
297 LCID lcid, ITypeInfo **ppTInfo)
299 struct textstream *This = impl_from_ITextStream(iface);
300 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
301 return get_typeinfo(ITextStream_tid, ppTInfo);
304 static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
305 LPOLESTR *rgszNames, UINT cNames,
306 LCID lcid, DISPID *rgDispId)
308 struct textstream *This = impl_from_ITextStream(iface);
309 ITypeInfo *typeinfo;
310 HRESULT hr;
312 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
314 hr = get_typeinfo(ITextStream_tid, &typeinfo);
315 if(SUCCEEDED(hr))
317 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
318 ITypeInfo_Release(typeinfo);
321 return hr;
324 static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
325 REFIID riid, LCID lcid, WORD wFlags,
326 DISPPARAMS *pDispParams, VARIANT *pVarResult,
327 EXCEPINFO *pExcepInfo, UINT *puArgErr)
329 struct textstream *This = impl_from_ITextStream(iface);
330 ITypeInfo *typeinfo;
331 HRESULT hr;
333 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
334 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
336 hr = get_typeinfo(ITextStream_tid, &typeinfo);
337 if(SUCCEEDED(hr))
339 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
340 pDispParams, pVarResult, pExcepInfo, puArgErr);
341 ITypeInfo_Release(typeinfo);
344 return hr;
347 static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
349 struct textstream *This = impl_from_ITextStream(iface);
350 FIXME("(%p)->(%p): stub\n", This, line);
351 return E_NOTIMPL;
354 static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
356 struct textstream *This = impl_from_ITextStream(iface);
357 FIXME("(%p)->(%p): stub\n", This, column);
358 return E_NOTIMPL;
361 static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
363 struct textstream *This = impl_from_ITextStream(iface);
365 TRACE("(%p)->(%p)\n", This, eos);
367 if (!eos)
368 return E_POINTER;
370 if (textstream_check_iomode(This, IORead)) {
371 *eos = VARIANT_TRUE;
372 return CTL_E_BADFILEMODE;
375 *eos = (This->eof && !This->read_buf_size) ? VARIANT_TRUE : VARIANT_FALSE;
376 return S_OK;
379 static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
381 struct textstream *This = impl_from_ITextStream(iface);
382 FIXME("(%p)->(%p): stub\n", This, eol);
383 return E_NOTIMPL;
386 static HRESULT append_read_data(struct textstream *stream, const char *buf, size_t buf_size)
388 LARGE_INTEGER revert;
389 size_t len;
390 WCHAR *new_buf;
392 revert.QuadPart = 0;
393 if (stream->unicode)
395 len = buf_size / sizeof(WCHAR);
396 if (buf_size & 1) revert.QuadPart = -1;
398 else
400 for (len = 0; len < buf_size; len++)
402 if (!IsDBCSLeadByte(buf[len])) continue;
403 if (len + 1 == buf_size)
405 revert.QuadPart = -1;
406 buf_size--;
407 break;
409 len++;
411 len = MultiByteToWideChar(CP_ACP, 0, buf, buf_size, NULL, 0);
413 if (!len)
414 return S_OK;
415 if (revert.QuadPart)
416 SetFilePointerEx(stream->file, revert, NULL, FILE_CURRENT);
418 if (!stream->read_buf_size)
419 new_buf = heap_alloc(len * sizeof(WCHAR));
420 else
421 new_buf = heap_realloc(stream->read_buf, (len + stream->read_buf_size) * sizeof(WCHAR));
422 if (!new_buf) return E_OUTOFMEMORY;
424 if (stream->unicode)
425 memcpy(new_buf + stream->read_buf_size, buf, len * sizeof(WCHAR));
426 else
427 MultiByteToWideChar(CP_ACP, 0, buf, buf_size, new_buf + stream->read_buf_size, len);
428 stream->read_buf = new_buf;
429 stream->read_buf_size += len;
430 return S_OK;
433 static HRESULT read_more_data(struct textstream *stream)
435 char buf[256];
436 DWORD read;
438 if (stream->eof) return S_OK;
440 if (!ReadFile(stream->file, buf, sizeof(buf), &read, NULL))
442 ITextStream_Release(&stream->ITextStream_iface);
443 return create_error(GetLastError());
446 stream->eof = read != sizeof(buf);
447 return append_read_data(stream, buf, read);
450 static BOOL read_from_buffer(struct textstream *stream, size_t len, BSTR *ret, size_t skip)
452 assert(len + skip <= stream->read_buf_size);
454 if (!(*ret = SysAllocStringLen(stream->read_buf, len))) return FALSE;
456 len += skip;
457 stream->read_buf_size -= len;
458 if (stream->read_buf_size)
459 memmove(stream->read_buf, stream->read_buf + len, stream->read_buf_size * sizeof(WCHAR));
460 else
461 heap_free(stream->read_buf);
462 return TRUE;
465 static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
467 struct textstream *This = impl_from_ITextStream(iface);
468 HRESULT hr = S_OK;
470 TRACE("(%p)->(%d %p)\n", This, len, text);
472 if (!text)
473 return E_POINTER;
475 *text = NULL;
476 if (len <= 0)
477 return len == 0 ? S_OK : E_INVALIDARG;
479 if (textstream_check_iomode(This, IORead))
480 return CTL_E_BADFILEMODE;
482 while (!This->eof && len > This->read_buf_size)
484 if (FAILED(hr = read_more_data(This)))
485 return hr;
488 if (This->eof && !This->read_buf_size)
489 return CTL_E_ENDOFFILE;
491 if (len > This->read_buf_size)
493 len = This->read_buf_size;
494 hr = S_FALSE;
497 return read_from_buffer(This, len, text, 0) ? hr : E_OUTOFMEMORY;
500 static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
502 struct textstream *This = impl_from_ITextStream(iface);
503 unsigned int skip = 0;
504 const WCHAR *nl;
505 HRESULT hr = S_OK;
507 TRACE("(%p)->(%p)\n", This, text);
509 if (!text)
510 return E_POINTER;
512 *text = NULL;
513 if (textstream_check_iomode(This, IORead))
514 return CTL_E_BADFILEMODE;
516 while (!(nl = wmemchr(This->read_buf, '\n', This->read_buf_size)) && !This->eof)
518 if (FAILED(hr = read_more_data(This)))
519 return hr;
522 if (This->eof && !This->read_buf_size)
523 return CTL_E_ENDOFFILE;
525 if (!nl)
527 nl = This->read_buf + This->read_buf_size;
528 hr = S_FALSE;
530 else if (nl > This->read_buf && nl[-1] == '\r')
532 nl--;
533 skip = 2;
535 else skip = 1;
537 return read_from_buffer(This, nl - This->read_buf, text, skip) ? hr : E_OUTOFMEMORY;
540 static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
542 struct textstream *This = impl_from_ITextStream(iface);
543 HRESULT hr;
545 TRACE("(%p)->(%p)\n", This, text);
547 if (!text)
548 return E_POINTER;
550 *text = NULL;
551 if (textstream_check_iomode(This, IORead))
552 return CTL_E_BADFILEMODE;
554 while (!This->eof)
556 if (FAILED(hr = read_more_data(This)))
557 return hr;
560 if (This->eof && !This->read_buf_size)
561 return CTL_E_ENDOFFILE;
563 return read_from_buffer(This, This->read_buf_size, text, 0) ? S_FALSE : E_OUTOFMEMORY;
566 static HRESULT textstream_writestr(struct textstream *stream, BSTR text)
568 DWORD written = 0;
569 BOOL ret;
571 if (stream->unicode) {
572 ret = WriteFile(stream->file, text, SysStringByteLen(text), &written, NULL);
573 return (ret && written == SysStringByteLen(text)) ? S_OK : create_error(GetLastError());
574 } else {
575 DWORD len = WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), NULL, 0, NULL, NULL);
576 char *buffA;
577 HRESULT hr;
579 buffA = heap_alloc(len);
580 if (!buffA)
581 return E_OUTOFMEMORY;
583 WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), buffA, len, NULL, NULL);
584 ret = WriteFile(stream->file, buffA, len, &written, NULL);
585 hr = (ret && written == len) ? S_OK : create_error(GetLastError());
586 heap_free(buffA);
587 return hr;
591 static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
593 struct textstream *This = impl_from_ITextStream(iface);
595 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
597 if (textstream_check_iomode(This, IOWrite))
598 return CTL_E_BADFILEMODE;
600 return textstream_writestr(This, text);
603 static HRESULT textstream_writecrlf(struct textstream *stream)
605 static const WCHAR crlfW[] = {'\r','\n'};
606 static const char crlfA[] = {'\r','\n'};
607 DWORD written = 0, len;
608 const void *ptr;
609 BOOL ret;
611 if (stream->unicode) {
612 ptr = crlfW;
613 len = sizeof(crlfW);
615 else {
616 ptr = crlfA;
617 len = sizeof(crlfA);
620 ret = WriteFile(stream->file, ptr, len, &written, NULL);
621 return (ret && written == len) ? S_OK : create_error(GetLastError());
624 static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
626 struct textstream *This = impl_from_ITextStream(iface);
627 HRESULT hr;
629 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
631 if (textstream_check_iomode(This, IOWrite))
632 return CTL_E_BADFILEMODE;
634 hr = textstream_writestr(This, text);
635 if (SUCCEEDED(hr))
636 hr = textstream_writecrlf(This);
637 return hr;
640 static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
642 struct textstream *This = impl_from_ITextStream(iface);
643 FIXME("(%p)->(%d): stub\n", This, lines);
644 return E_NOTIMPL;
647 static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
649 struct textstream *This = impl_from_ITextStream(iface);
650 FIXME("(%p)->(%d): stub\n", This, count);
651 return E_NOTIMPL;
654 static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
656 struct textstream *This = impl_from_ITextStream(iface);
657 FIXME("(%p): stub\n", This);
658 return E_NOTIMPL;
661 static HRESULT WINAPI textstream_Close(ITextStream *iface)
663 struct textstream *This = impl_from_ITextStream(iface);
664 HRESULT hr = S_OK;
666 TRACE("(%p)\n", This);
668 if(!CloseHandle(This->file))
669 hr = S_FALSE;
671 This->file = NULL;
673 return hr;
676 static const ITextStreamVtbl textstreamvtbl = {
677 textstream_QueryInterface,
678 textstream_AddRef,
679 textstream_Release,
680 textstream_GetTypeInfoCount,
681 textstream_GetTypeInfo,
682 textstream_GetIDsOfNames,
683 textstream_Invoke,
684 textstream_get_Line,
685 textstream_get_Column,
686 textstream_get_AtEndOfStream,
687 textstream_get_AtEndOfLine,
688 textstream_Read,
689 textstream_ReadLine,
690 textstream_ReadAll,
691 textstream_Write,
692 textstream_WriteLine,
693 textstream_WriteBlankLines,
694 textstream_Skip,
695 textstream_SkipLine,
696 textstream_Close
699 static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMode mode, Tristate format, ITextStream **ret)
701 struct textstream *stream;
702 DWORD access = 0;
703 HRESULT hr;
705 /* map access mode */
706 switch (mode)
708 case ForReading:
709 access = GENERIC_READ;
710 break;
711 case ForWriting:
712 access = GENERIC_WRITE;
713 break;
714 case ForAppending:
715 access = GENERIC_READ | GENERIC_WRITE;
716 break;
717 default:
718 return E_INVALIDARG;
721 stream = heap_alloc(sizeof(struct textstream));
722 if (!stream) return E_OUTOFMEMORY;
724 stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
725 stream->ref = 1;
726 stream->mode = mode;
727 stream->eof = FALSE;
728 stream->read_buf = NULL;
729 stream->read_buf_size = 0;
731 stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
732 if (stream->file == INVALID_HANDLE_VALUE)
734 HRESULT hr = create_error(GetLastError());
735 heap_free(stream);
736 return hr;
739 if (mode == ForReading)
740 GetFileSizeEx(stream->file, &stream->size);
741 else
742 stream->size.QuadPart = 0;
744 if (mode == ForWriting)
746 stream->unicode = format == TristateTrue;
747 /* Write Unicode BOM */
748 if (stream->unicode && (disposition == CREATE_ALWAYS || disposition == CREATE_NEW)) {
749 DWORD written = 0;
750 BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL);
751 if (!ret || written != sizeof(utf16bom)) {
752 ITextStream_Release(&stream->ITextStream_iface);
753 return create_error(GetLastError());
757 else
759 DWORD read, buf_offset = 0;
760 BYTE buf[64];
762 if (format == TristateUseDefault || mode == ForReading)
764 if (!ReadFile(stream->file, buf, sizeof(buf), &read, NULL))
766 ITextStream_Release(&stream->ITextStream_iface);
767 return create_error(GetLastError());
771 if (format == TristateUseDefault)
772 stream->unicode = IsTextUnicode(buf, read, NULL);
773 else
774 stream->unicode = format != TristateFalse;
776 if (mode == ForReading)
778 if (stream->unicode && read >= 2 && buf[0] == 0xff && buf[1] == 0xfe)
779 buf_offset += 2; /* skip utf16 BOM */
781 hr = append_read_data(stream, (const char *)buf + buf_offset, read - buf_offset);
782 if (FAILED(hr))
784 ITextStream_Release(&stream->ITextStream_iface);
785 return hr;
788 stream->eof = read != sizeof(buf);
790 else SetFilePointer(stream->file, 0, 0, FILE_END);
793 init_classinfo(&CLSID_TextStream, (IUnknown *)&stream->ITextStream_iface, &stream->classinfo);
794 *ret = &stream->ITextStream_iface;
795 return S_OK;
798 static HRESULT WINAPI drive_QueryInterface(IDrive *iface, REFIID riid, void **obj)
800 struct drive *This = impl_from_IDrive(iface);
802 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
804 *obj = NULL;
806 if (IsEqualIID( riid, &IID_IDrive ) ||
807 IsEqualIID( riid, &IID_IDispatch ) ||
808 IsEqualIID( riid, &IID_IUnknown))
810 *obj = &This->IDrive_iface;
812 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
814 *obj = &This->classinfo.IProvideClassInfo_iface;
816 else
817 return E_NOINTERFACE;
819 IUnknown_AddRef((IUnknown*)*obj);
820 return S_OK;
823 static ULONG WINAPI drive_AddRef(IDrive *iface)
825 struct drive *This = impl_from_IDrive(iface);
826 ULONG ref = InterlockedIncrement(&This->ref);
827 TRACE("(%p)->(%d)\n", This, ref);
828 return ref;
831 static ULONG WINAPI drive_Release(IDrive *iface)
833 struct drive *This = impl_from_IDrive(iface);
834 ULONG ref = InterlockedDecrement(&This->ref);
835 TRACE("(%p)->(%d)\n", This, ref);
837 if (!ref)
839 SysFreeString(This->root);
840 heap_free(This);
843 return ref;
846 static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo)
848 struct drive *This = impl_from_IDrive(iface);
849 TRACE("(%p)->(%p)\n", This, pctinfo);
850 *pctinfo = 1;
851 return S_OK;
854 static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo,
855 LCID lcid, ITypeInfo **ppTInfo)
857 struct drive *This = impl_from_IDrive(iface);
858 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
859 return get_typeinfo(IDrive_tid, ppTInfo);
862 static HRESULT WINAPI drive_GetIDsOfNames(IDrive *iface, REFIID riid,
863 LPOLESTR *rgszNames, UINT cNames,
864 LCID lcid, DISPID *rgDispId)
866 struct drive *This = impl_from_IDrive(iface);
867 ITypeInfo *typeinfo;
868 HRESULT hr;
870 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
872 hr = get_typeinfo(IDrive_tid, &typeinfo);
873 if(SUCCEEDED(hr))
875 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
876 ITypeInfo_Release(typeinfo);
879 return hr;
882 static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember,
883 REFIID riid, LCID lcid, WORD wFlags,
884 DISPPARAMS *pDispParams, VARIANT *pVarResult,
885 EXCEPINFO *pExcepInfo, UINT *puArgErr)
887 struct drive *This = impl_from_IDrive(iface);
888 ITypeInfo *typeinfo;
889 HRESULT hr;
891 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
892 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
894 hr = get_typeinfo(IDrive_tid, &typeinfo);
895 if(SUCCEEDED(hr))
897 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
898 pDispParams, pVarResult, pExcepInfo, puArgErr);
899 ITypeInfo_Release(typeinfo);
902 return hr;
905 static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path)
907 struct drive *This = impl_from_IDrive(iface);
908 FIXME("(%p)->(%p): stub\n", This, path);
909 return E_NOTIMPL;
912 static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter)
914 struct drive *This = impl_from_IDrive(iface);
916 TRACE("(%p)->(%p)\n", This, letter);
918 if (!letter)
919 return E_POINTER;
921 *letter = SysAllocStringLen(This->root, 1);
922 if (!*letter)
923 return E_OUTOFMEMORY;
925 return S_OK;
928 static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name)
930 struct drive *This = impl_from_IDrive(iface);
931 FIXME("(%p)->(%p): stub\n", This, share_name);
932 return E_NOTIMPL;
935 static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type)
937 struct drive *This = impl_from_IDrive(iface);
939 TRACE("(%p)->(%p)\n", This, type);
941 switch (GetDriveTypeW(This->root))
943 case DRIVE_REMOVABLE:
944 *type = Removable;
945 break;
946 case DRIVE_FIXED:
947 *type = Fixed;
948 break;
949 case DRIVE_REMOTE:
950 *type = Remote;
951 break;
952 case DRIVE_CDROM:
953 *type = CDRom;
954 break;
955 case DRIVE_RAMDISK:
956 *type = RamDisk;
957 break;
958 default:
959 *type = UnknownType;
960 break;
963 return S_OK;
966 static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder)
968 struct drive *This = impl_from_IDrive(iface);
969 FIXME("(%p)->(%p): stub\n", This, folder);
970 return E_NOTIMPL;
973 static HRESULT variant_from_largeint(const ULARGE_INTEGER *src, VARIANT *v)
975 HRESULT hr = S_OK;
977 if (src->u.HighPart || src->u.LowPart > INT_MAX)
979 V_VT(v) = VT_R8;
980 hr = VarR8FromUI8(src->QuadPart, &V_R8(v));
982 else
984 V_VT(v) = VT_I4;
985 V_I4(v) = src->u.LowPart;
988 return hr;
991 static HRESULT WINAPI drive_get_AvailableSpace(IDrive *iface, VARIANT *v)
993 struct drive *This = impl_from_IDrive(iface);
994 ULARGE_INTEGER avail;
996 TRACE("(%p)->(%p)\n", This, v);
998 if (!v)
999 return E_POINTER;
1001 if (!GetDiskFreeSpaceExW(This->root, &avail, NULL, NULL))
1002 return E_FAIL;
1004 return variant_from_largeint(&avail, v);
1007 static HRESULT WINAPI drive_get_FreeSpace(IDrive *iface, VARIANT *v)
1009 struct drive *This = impl_from_IDrive(iface);
1010 ULARGE_INTEGER freespace;
1012 TRACE("(%p)->(%p)\n", This, v);
1014 if (!v)
1015 return E_POINTER;
1017 if (!GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL))
1018 return E_FAIL;
1020 return variant_from_largeint(&freespace, v);
1023 static HRESULT WINAPI drive_get_TotalSize(IDrive *iface, VARIANT *v)
1025 struct drive *This = impl_from_IDrive(iface);
1026 ULARGE_INTEGER total;
1028 TRACE("(%p)->(%p)\n", This, v);
1030 if (!v)
1031 return E_POINTER;
1033 if (!GetDiskFreeSpaceExW(This->root, NULL, &total, NULL))
1034 return E_FAIL;
1036 return variant_from_largeint(&total, v);
1039 static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name)
1041 struct drive *This = impl_from_IDrive(iface);
1042 WCHAR nameW[MAX_PATH+1];
1043 BOOL ret;
1045 TRACE("(%p)->(%p)\n", This, name);
1047 if (!name)
1048 return E_POINTER;
1050 *name = NULL;
1051 ret = GetVolumeInformationW(This->root, nameW, ARRAY_SIZE(nameW), NULL, NULL, NULL, NULL, 0);
1052 if (ret)
1053 *name = SysAllocString(nameW);
1054 return ret ? S_OK : E_FAIL;
1057 static HRESULT WINAPI drive_put_VolumeName(IDrive *iface, BSTR name)
1059 struct drive *This = impl_from_IDrive(iface);
1060 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
1061 return E_NOTIMPL;
1064 static HRESULT WINAPI drive_get_FileSystem(IDrive *iface, BSTR *fs)
1066 struct drive *This = impl_from_IDrive(iface);
1067 WCHAR nameW[MAX_PATH+1];
1068 BOOL ret;
1070 TRACE("(%p)->(%p)\n", This, fs);
1072 if (!fs)
1073 return E_POINTER;
1075 *fs = NULL;
1076 ret = GetVolumeInformationW(This->root, NULL, 0, NULL, NULL, NULL, nameW, ARRAY_SIZE(nameW));
1077 if (ret)
1078 *fs = SysAllocString(nameW);
1079 return ret ? S_OK : E_FAIL;
1082 static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial)
1084 struct drive *This = impl_from_IDrive(iface);
1085 BOOL ret;
1087 TRACE("(%p)->(%p)\n", This, serial);
1089 if (!serial)
1090 return E_POINTER;
1092 ret = GetVolumeInformationW(This->root, NULL, 0, (DWORD*)serial, NULL, NULL, NULL, 0);
1093 return ret ? S_OK : E_FAIL;
1096 static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
1098 struct drive *This = impl_from_IDrive(iface);
1099 ULARGE_INTEGER freespace;
1100 BOOL ret;
1102 TRACE("(%p)->(%p)\n", This, ready);
1104 if (!ready)
1105 return E_POINTER;
1107 ret = GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL);
1108 *ready = ret ? VARIANT_TRUE : VARIANT_FALSE;
1109 return S_OK;
1112 static const IDriveVtbl drivevtbl = {
1113 drive_QueryInterface,
1114 drive_AddRef,
1115 drive_Release,
1116 drive_GetTypeInfoCount,
1117 drive_GetTypeInfo,
1118 drive_GetIDsOfNames,
1119 drive_Invoke,
1120 drive_get_Path,
1121 drive_get_DriveLetter,
1122 drive_get_ShareName,
1123 drive_get_DriveType,
1124 drive_get_RootFolder,
1125 drive_get_AvailableSpace,
1126 drive_get_FreeSpace,
1127 drive_get_TotalSize,
1128 drive_get_VolumeName,
1129 drive_put_VolumeName,
1130 drive_get_FileSystem,
1131 drive_get_SerialNumber,
1132 drive_get_IsReady
1135 static HRESULT create_drive(WCHAR letter, IDrive **drive)
1137 struct drive *This;
1139 *drive = NULL;
1141 This = heap_alloc(sizeof(*This));
1142 if (!This) return E_OUTOFMEMORY;
1144 This->IDrive_iface.lpVtbl = &drivevtbl;
1145 This->ref = 1;
1146 This->root = SysAllocStringLen(NULL, 3);
1147 if (!This->root)
1149 heap_free(This);
1150 return E_OUTOFMEMORY;
1152 This->root[0] = letter;
1153 This->root[1] = ':';
1154 This->root[2] = '\\';
1155 This->root[3] = 0;
1157 init_classinfo(&CLSID_Drive, (IUnknown *)&This->IDrive_iface, &This->classinfo);
1158 *drive = &This->IDrive_iface;
1159 return S_OK;
1162 static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
1164 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1166 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1168 *obj = NULL;
1170 if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
1171 IsEqualIID( riid, &IID_IUnknown ))
1173 *obj = iface;
1174 IEnumVARIANT_AddRef(iface);
1176 else
1177 return E_NOINTERFACE;
1179 return S_OK;
1182 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
1184 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1185 ULONG ref = InterlockedIncrement(&This->ref);
1186 TRACE("(%p)->(%d)\n", This, ref);
1187 return ref;
1190 static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
1192 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1193 ULONG ref = InterlockedDecrement(&This->ref);
1195 TRACE("(%p)->(%d)\n", This, ref);
1197 if (!ref)
1199 IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
1200 FindClose(This->data.u.foldercoll.find);
1201 heap_free(This);
1204 return ref;
1207 static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file)
1209 static const WCHAR allW[] = {'*',0};
1210 WCHAR pathW[MAX_PATH];
1211 int len;
1212 HANDLE handle;
1214 lstrcpyW(pathW, path);
1215 len = lstrlenW(pathW);
1216 if (len && pathW[len-1] != '\\')
1217 lstrcatW(pathW, bsW);
1218 lstrcatW(pathW, allW);
1219 handle = FindFirstFileW(pathW, data);
1220 if (handle == INVALID_HANDLE_VALUE) return 0;
1222 /* find first dir/file */
1223 while (1)
1225 if (file ? is_file_data(data) : is_dir_data(data))
1226 break;
1228 if (!FindNextFileW(handle, data))
1230 FindClose(handle);
1231 return 0;
1234 return handle;
1237 static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1239 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1240 HANDLE handle = This->data.u.foldercoll.find;
1241 WIN32_FIND_DATAW data;
1242 ULONG count = 0;
1244 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1246 if (fetched)
1247 *fetched = 0;
1249 if (!celt) return S_OK;
1251 if (!handle)
1253 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1254 if (!handle) return S_FALSE;
1256 This->data.u.foldercoll.find = handle;
1258 else
1260 if (!FindNextFileW(handle, &data))
1261 return S_FALSE;
1266 if (is_dir_data(&data))
1268 IFolder *folder;
1269 HRESULT hr;
1270 BSTR str;
1272 str = get_full_path(This->data.u.foldercoll.coll->path, &data);
1273 hr = create_folder(str, &folder);
1274 SysFreeString(str);
1275 if (FAILED(hr)) return hr;
1277 V_VT(&var[count]) = VT_DISPATCH;
1278 V_DISPATCH(&var[count]) = (IDispatch*)folder;
1279 count++;
1281 if (count >= celt) break;
1283 } while (FindNextFileW(handle, &data));
1285 if (fetched)
1286 *fetched = count;
1288 return (count < celt) ? S_FALSE : S_OK;
1291 static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1293 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1294 HANDLE handle = This->data.u.foldercoll.find;
1295 WIN32_FIND_DATAW data;
1297 TRACE("(%p)->(%d)\n", This, celt);
1299 if (!celt) return S_OK;
1301 if (!handle)
1303 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1304 if (!handle) return S_FALSE;
1306 This->data.u.foldercoll.find = handle;
1308 else
1310 if (!FindNextFileW(handle, &data))
1311 return S_FALSE;
1316 if (is_dir_data(&data))
1317 --celt;
1319 if (!celt) break;
1320 } while (FindNextFileW(handle, &data));
1322 return celt ? S_FALSE : S_OK;
1325 static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
1327 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1329 TRACE("(%p)\n", This);
1331 FindClose(This->data.u.foldercoll.find);
1332 This->data.u.foldercoll.find = NULL;
1334 return S_OK;
1337 static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1339 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1340 TRACE("(%p)->(%p)\n", This, pclone);
1341 return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
1344 static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
1345 enumvariant_QueryInterface,
1346 enumvariant_AddRef,
1347 foldercoll_enumvariant_Release,
1348 foldercoll_enumvariant_Next,
1349 foldercoll_enumvariant_Skip,
1350 foldercoll_enumvariant_Reset,
1351 foldercoll_enumvariant_Clone
1354 static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
1356 struct enumvariant *This;
1358 *newenum = NULL;
1360 This = heap_alloc(sizeof(*This));
1361 if (!This) return E_OUTOFMEMORY;
1363 This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
1364 This->ref = 1;
1365 This->data.u.foldercoll.find = NULL;
1366 This->data.u.foldercoll.coll = collection;
1367 IFolderCollection_AddRef(&collection->IFolderCollection_iface);
1369 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1371 return S_OK;
1374 static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface)
1376 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1377 ULONG ref = InterlockedDecrement(&This->ref);
1379 TRACE("(%p)->(%d)\n", This, ref);
1381 if (!ref)
1383 IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
1384 FindClose(This->data.u.filecoll.find);
1385 heap_free(This);
1388 return ref;
1391 static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1393 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1394 HANDLE handle = This->data.u.filecoll.find;
1395 WIN32_FIND_DATAW data;
1396 ULONG count = 0;
1398 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1400 if (fetched)
1401 *fetched = 0;
1403 if (!celt) return S_OK;
1405 if (!handle)
1407 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1408 if (!handle) return S_FALSE;
1409 This->data.u.filecoll.find = handle;
1411 else if (!FindNextFileW(handle, &data))
1412 return S_FALSE;
1416 if (is_file_data(&data))
1418 IFile *file;
1419 HRESULT hr;
1420 BSTR str;
1422 str = get_full_path(This->data.u.filecoll.coll->path, &data);
1423 hr = create_file(str, &file);
1424 SysFreeString(str);
1425 if (FAILED(hr)) return hr;
1427 V_VT(&var[count]) = VT_DISPATCH;
1428 V_DISPATCH(&var[count]) = (IDispatch*)file;
1429 if (++count >= celt) break;
1431 } while (FindNextFileW(handle, &data));
1433 if (fetched)
1434 *fetched = count;
1436 return (count < celt) ? S_FALSE : S_OK;
1439 static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1441 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1442 HANDLE handle = This->data.u.filecoll.find;
1443 WIN32_FIND_DATAW data;
1445 TRACE("(%p)->(%d)\n", This, celt);
1447 if (!celt) return S_OK;
1449 if (!handle)
1451 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1452 if (!handle) return S_FALSE;
1453 This->data.u.filecoll.find = handle;
1455 else if (!FindNextFileW(handle, &data))
1456 return S_FALSE;
1460 if (is_file_data(&data))
1461 --celt;
1462 } while (celt && FindNextFileW(handle, &data));
1464 return celt ? S_FALSE : S_OK;
1467 static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface)
1469 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1471 TRACE("(%p)\n", This);
1473 FindClose(This->data.u.filecoll.find);
1474 This->data.u.filecoll.find = NULL;
1476 return S_OK;
1479 static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1481 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1482 TRACE("(%p)->(%p)\n", This, pclone);
1483 return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
1486 static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
1487 enumvariant_QueryInterface,
1488 enumvariant_AddRef,
1489 filecoll_enumvariant_Release,
1490 filecoll_enumvariant_Next,
1491 filecoll_enumvariant_Skip,
1492 filecoll_enumvariant_Reset,
1493 filecoll_enumvariant_Clone
1496 static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum)
1498 struct enumvariant *This;
1500 *newenum = NULL;
1502 This = heap_alloc(sizeof(*This));
1503 if (!This) return E_OUTOFMEMORY;
1505 This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
1506 This->ref = 1;
1507 This->data.u.filecoll.find = NULL;
1508 This->data.u.filecoll.coll = collection;
1509 IFileCollection_AddRef(&collection->IFileCollection_iface);
1511 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1513 return S_OK;
1516 static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface)
1518 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1519 ULONG ref = InterlockedDecrement(&This->ref);
1521 TRACE("(%p)->(%d)\n", This, ref);
1523 if (!ref)
1525 IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
1526 heap_free(This);
1529 return ref;
1532 static HRESULT find_next_drive(struct enumvariant *penum)
1534 int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
1536 for (; i < 32; i++)
1537 if (penum->data.u.drivecoll.coll->drives & (1 << i))
1539 penum->data.u.drivecoll.cur = i;
1540 return S_OK;
1543 return S_FALSE;
1546 static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1548 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1549 ULONG count = 0;
1551 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1553 if (fetched)
1554 *fetched = 0;
1556 if (!celt) return S_OK;
1558 while (find_next_drive(This) == S_OK)
1560 IDrive *drive;
1561 HRESULT hr;
1563 hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
1564 if (FAILED(hr)) return hr;
1566 V_VT(&var[count]) = VT_DISPATCH;
1567 V_DISPATCH(&var[count]) = (IDispatch*)drive;
1569 if (++count >= celt) break;
1572 if (fetched)
1573 *fetched = count;
1575 return (count < celt) ? S_FALSE : S_OK;
1578 static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1580 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1582 TRACE("(%p)->(%d)\n", This, celt);
1584 if (!celt) return S_OK;
1586 while (celt && find_next_drive(This) == S_OK)
1587 celt--;
1589 return celt ? S_FALSE : S_OK;
1592 static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface)
1594 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1596 TRACE("(%p)\n", This);
1598 This->data.u.drivecoll.cur = -1;
1599 return S_OK;
1602 static HRESULT WINAPI drivecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1604 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1605 TRACE("(%p)->(%p)\n", This, pclone);
1606 return create_drivecoll_enum(This->data.u.drivecoll.coll, (IUnknown**)pclone);
1609 static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
1610 enumvariant_QueryInterface,
1611 enumvariant_AddRef,
1612 drivecoll_enumvariant_Release,
1613 drivecoll_enumvariant_Next,
1614 drivecoll_enumvariant_Skip,
1615 drivecoll_enumvariant_Reset,
1616 drivecoll_enumvariant_Clone
1619 static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum)
1621 struct enumvariant *This;
1623 *newenum = NULL;
1625 This = heap_alloc(sizeof(*This));
1626 if (!This) return E_OUTOFMEMORY;
1628 This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
1629 This->ref = 1;
1630 This->data.u.drivecoll.coll = collection;
1631 This->data.u.drivecoll.cur = -1;
1632 IDriveCollection_AddRef(&collection->IDriveCollection_iface);
1634 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1636 return S_OK;
1639 static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
1641 struct foldercollection *This = impl_from_IFolderCollection(iface);
1643 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1645 *obj = NULL;
1647 if (IsEqualIID( riid, &IID_IFolderCollection ) ||
1648 IsEqualIID( riid, &IID_IDispatch ) ||
1649 IsEqualIID( riid, &IID_IUnknown ))
1651 *obj = &This->IFolderCollection_iface;
1653 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
1655 *obj = &This->classinfo.IProvideClassInfo_iface;
1657 else
1658 return E_NOINTERFACE;
1660 IUnknown_AddRef((IUnknown*)*obj);
1661 return S_OK;
1664 static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
1666 struct foldercollection *This = impl_from_IFolderCollection(iface);
1667 ULONG ref = InterlockedIncrement(&This->ref);
1668 TRACE("(%p)->(%d)\n", This, ref);
1669 return ref;
1672 static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
1674 struct foldercollection *This = impl_from_IFolderCollection(iface);
1675 ULONG ref = InterlockedDecrement(&This->ref);
1676 TRACE("(%p)->(%d)\n", This, ref);
1678 if (!ref)
1680 SysFreeString(This->path);
1681 heap_free(This);
1684 return ref;
1687 static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
1689 struct foldercollection *This = impl_from_IFolderCollection(iface);
1690 TRACE("(%p)->(%p)\n", This, pctinfo);
1691 *pctinfo = 1;
1692 return S_OK;
1695 static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
1696 LCID lcid, ITypeInfo **ppTInfo)
1698 struct foldercollection *This = impl_from_IFolderCollection(iface);
1699 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1700 return get_typeinfo(IFolderCollection_tid, ppTInfo);
1703 static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
1704 LPOLESTR *rgszNames, UINT cNames,
1705 LCID lcid, DISPID *rgDispId)
1707 struct foldercollection *This = impl_from_IFolderCollection(iface);
1708 ITypeInfo *typeinfo;
1709 HRESULT hr;
1711 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1713 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1714 if(SUCCEEDED(hr))
1716 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1717 ITypeInfo_Release(typeinfo);
1720 return hr;
1723 static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
1724 REFIID riid, LCID lcid, WORD wFlags,
1725 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1726 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1728 struct foldercollection *This = impl_from_IFolderCollection(iface);
1729 ITypeInfo *typeinfo;
1730 HRESULT hr;
1732 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1733 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1735 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1736 if(SUCCEEDED(hr))
1738 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1739 pDispParams, pVarResult, pExcepInfo, puArgErr);
1740 ITypeInfo_Release(typeinfo);
1743 return hr;
1746 static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
1748 struct foldercollection *This = impl_from_IFolderCollection(iface);
1749 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
1750 return E_NOTIMPL;
1753 static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
1755 struct foldercollection *This = impl_from_IFolderCollection(iface);
1756 FIXME("(%p)->(%p): stub\n", This, folder);
1757 return E_NOTIMPL;
1760 static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
1762 struct foldercollection *This = impl_from_IFolderCollection(iface);
1764 TRACE("(%p)->(%p)\n", This, newenum);
1766 if(!newenum)
1767 return E_POINTER;
1769 return create_foldercoll_enum(This, newenum);
1772 static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
1774 struct foldercollection *This = impl_from_IFolderCollection(iface);
1775 static const WCHAR allW[] = {'\\','*',0};
1776 WIN32_FIND_DATAW data;
1777 WCHAR pathW[MAX_PATH];
1778 HANDLE handle;
1780 TRACE("(%p)->(%p)\n", This, count);
1782 if(!count)
1783 return E_POINTER;
1785 *count = 0;
1787 lstrcpyW(pathW, This->path);
1788 lstrcatW(pathW, allW);
1789 handle = FindFirstFileW(pathW, &data);
1790 if (handle == INVALID_HANDLE_VALUE)
1791 return HRESULT_FROM_WIN32(GetLastError());
1795 if (is_dir_data(&data))
1796 *count += 1;
1797 } while (FindNextFileW(handle, &data));
1798 FindClose(handle);
1800 return S_OK;
1803 static const IFolderCollectionVtbl foldercollvtbl = {
1804 foldercoll_QueryInterface,
1805 foldercoll_AddRef,
1806 foldercoll_Release,
1807 foldercoll_GetTypeInfoCount,
1808 foldercoll_GetTypeInfo,
1809 foldercoll_GetIDsOfNames,
1810 foldercoll_Invoke,
1811 foldercoll_Add,
1812 foldercoll_get_Item,
1813 foldercoll_get__NewEnum,
1814 foldercoll_get_Count
1817 static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
1819 struct foldercollection *This;
1821 *folders = NULL;
1823 This = heap_alloc(sizeof(struct foldercollection));
1824 if (!This) return E_OUTOFMEMORY;
1826 This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
1827 This->ref = 1;
1828 This->path = SysAllocString(path);
1829 if (!This->path)
1831 heap_free(This);
1832 return E_OUTOFMEMORY;
1835 init_classinfo(&CLSID_Folders, (IUnknown *)&This->IFolderCollection_iface, &This->classinfo);
1836 *folders = &This->IFolderCollection_iface;
1838 return S_OK;
1841 static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj)
1843 struct filecollection *This = impl_from_IFileCollection(iface);
1845 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1847 *obj = NULL;
1849 if (IsEqualIID( riid, &IID_IFileCollection ) ||
1850 IsEqualIID( riid, &IID_IDispatch ) ||
1851 IsEqualIID( riid, &IID_IUnknown ))
1853 *obj = &This->IFileCollection_iface;
1855 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
1857 *obj = &This->classinfo.IProvideClassInfo_iface;
1859 else
1860 return E_NOINTERFACE;
1862 IUnknown_AddRef((IUnknown*)*obj);
1863 return S_OK;
1866 static ULONG WINAPI filecoll_AddRef(IFileCollection *iface)
1868 struct filecollection *This = impl_from_IFileCollection(iface);
1869 ULONG ref = InterlockedIncrement(&This->ref);
1870 TRACE("(%p)->(%d)\n", This, ref);
1871 return ref;
1874 static ULONG WINAPI filecoll_Release(IFileCollection *iface)
1876 struct filecollection *This = impl_from_IFileCollection(iface);
1877 ULONG ref = InterlockedDecrement(&This->ref);
1878 TRACE("(%p)->(%d)\n", This, ref);
1880 if (!ref)
1882 SysFreeString(This->path);
1883 heap_free(This);
1886 return ref;
1889 static HRESULT WINAPI filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo)
1891 struct filecollection *This = impl_from_IFileCollection(iface);
1892 TRACE("(%p)->(%p)\n", This, pctinfo);
1893 *pctinfo = 1;
1894 return S_OK;
1897 static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo,
1898 LCID lcid, ITypeInfo **ppTInfo)
1900 struct filecollection *This = impl_from_IFileCollection(iface);
1901 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1902 return get_typeinfo(IFileCollection_tid, ppTInfo);
1905 static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid,
1906 LPOLESTR *rgszNames, UINT cNames,
1907 LCID lcid, DISPID *rgDispId)
1909 struct filecollection *This = impl_from_IFileCollection(iface);
1910 ITypeInfo *typeinfo;
1911 HRESULT hr;
1913 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1915 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1916 if(SUCCEEDED(hr))
1918 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1919 ITypeInfo_Release(typeinfo);
1922 return hr;
1925 static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember,
1926 REFIID riid, LCID lcid, WORD wFlags,
1927 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1928 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1930 struct filecollection *This = impl_from_IFileCollection(iface);
1931 ITypeInfo *typeinfo;
1932 HRESULT hr;
1934 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1935 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1937 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1938 if(SUCCEEDED(hr))
1940 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1941 pDispParams, pVarResult, pExcepInfo, puArgErr);
1942 ITypeInfo_Release(typeinfo);
1945 return hr;
1948 static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file)
1950 struct filecollection *This = impl_from_IFileCollection(iface);
1951 FIXME("(%p)->(%p)\n", This, file);
1952 return E_NOTIMPL;
1955 static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum)
1957 struct filecollection *This = impl_from_IFileCollection(iface);
1959 TRACE("(%p)->(%p)\n", This, ppenum);
1961 if(!ppenum)
1962 return E_POINTER;
1964 return create_filecoll_enum(This, ppenum);
1967 static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count)
1969 struct filecollection *This = impl_from_IFileCollection(iface);
1970 static const WCHAR allW[] = {'\\','*',0};
1971 WIN32_FIND_DATAW data;
1972 WCHAR pathW[MAX_PATH];
1973 HANDLE handle;
1975 TRACE("(%p)->(%p)\n", This, count);
1977 if(!count)
1978 return E_POINTER;
1980 *count = 0;
1982 lstrcpyW(pathW, This->path);
1983 lstrcatW(pathW, allW);
1984 handle = FindFirstFileW(pathW, &data);
1985 if (handle == INVALID_HANDLE_VALUE)
1986 return HRESULT_FROM_WIN32(GetLastError());
1990 if (is_file_data(&data))
1991 *count += 1;
1992 } while (FindNextFileW(handle, &data));
1993 FindClose(handle);
1995 return S_OK;
1998 static const IFileCollectionVtbl filecollectionvtbl = {
1999 filecoll_QueryInterface,
2000 filecoll_AddRef,
2001 filecoll_Release,
2002 filecoll_GetTypeInfoCount,
2003 filecoll_GetTypeInfo,
2004 filecoll_GetIDsOfNames,
2005 filecoll_Invoke,
2006 filecoll_get_Item,
2007 filecoll_get__NewEnum,
2008 filecoll_get_Count
2011 static HRESULT create_filecoll(BSTR path, IFileCollection **files)
2013 struct filecollection *This;
2015 *files = NULL;
2017 This = heap_alloc(sizeof(*This));
2018 if (!This) return E_OUTOFMEMORY;
2020 This->IFileCollection_iface.lpVtbl = &filecollectionvtbl;
2021 This->ref = 1;
2022 This->path = SysAllocString(path);
2023 if (!This->path)
2025 heap_free(This);
2026 return E_OUTOFMEMORY;
2029 init_classinfo(&CLSID_Files, (IUnknown *)&This->IFileCollection_iface, &This->classinfo);
2030 *files = &This->IFileCollection_iface;
2031 return S_OK;
2034 static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
2036 struct drivecollection *This = impl_from_IDriveCollection(iface);
2038 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2040 *obj = NULL;
2042 if (IsEqualIID( riid, &IID_IDriveCollection ) ||
2043 IsEqualIID( riid, &IID_IDispatch ) ||
2044 IsEqualIID( riid, &IID_IUnknown ))
2046 *obj = &This->IDriveCollection_iface;
2048 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2050 *obj = &This->classinfo.IProvideClassInfo_iface;
2052 else
2053 return E_NOINTERFACE;
2055 IUnknown_AddRef((IUnknown*)*obj);
2056 return S_OK;
2059 static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
2061 struct drivecollection *This = impl_from_IDriveCollection(iface);
2062 ULONG ref = InterlockedIncrement(&This->ref);
2063 TRACE("(%p)->(%d)\n", This, ref);
2064 return ref;
2067 static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
2069 struct drivecollection *This = impl_from_IDriveCollection(iface);
2070 ULONG ref = InterlockedDecrement(&This->ref);
2071 TRACE("(%p)->(%d)\n", This, ref);
2073 if (!ref)
2074 heap_free(This);
2076 return ref;
2079 static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
2081 struct drivecollection *This = impl_from_IDriveCollection(iface);
2082 TRACE("(%p)->(%p)\n", This, pctinfo);
2083 *pctinfo = 1;
2084 return S_OK;
2087 static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
2088 LCID lcid, ITypeInfo **ppTInfo)
2090 struct drivecollection *This = impl_from_IDriveCollection(iface);
2091 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2092 return get_typeinfo(IDriveCollection_tid, ppTInfo);
2095 static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
2096 LPOLESTR *rgszNames, UINT cNames,
2097 LCID lcid, DISPID *rgDispId)
2099 struct drivecollection *This = impl_from_IDriveCollection(iface);
2100 ITypeInfo *typeinfo;
2101 HRESULT hr;
2103 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2105 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2106 if(SUCCEEDED(hr))
2108 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2109 ITypeInfo_Release(typeinfo);
2112 return hr;
2115 static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
2116 REFIID riid, LCID lcid, WORD wFlags,
2117 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2118 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2120 struct drivecollection *This = impl_from_IDriveCollection(iface);
2121 ITypeInfo *typeinfo;
2122 HRESULT hr;
2124 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2125 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2127 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2128 if(SUCCEEDED(hr))
2130 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2131 pDispParams, pVarResult, pExcepInfo, puArgErr);
2132 ITypeInfo_Release(typeinfo);
2135 return hr;
2138 static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
2140 struct drivecollection *This = impl_from_IDriveCollection(iface);
2141 FIXME("(%p)->(%p): stub\n", This, drive);
2142 return E_NOTIMPL;
2145 static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
2147 struct drivecollection *This = impl_from_IDriveCollection(iface);
2149 TRACE("(%p)->(%p)\n", This, ppenum);
2151 if(!ppenum)
2152 return E_POINTER;
2154 return create_drivecoll_enum(This, ppenum);
2157 static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
2159 struct drivecollection *This = impl_from_IDriveCollection(iface);
2161 TRACE("(%p)->(%p)\n", This, count);
2163 if (!count) return E_POINTER;
2165 *count = This->count;
2166 return S_OK;
2169 static const IDriveCollectionVtbl drivecollectionvtbl = {
2170 drivecoll_QueryInterface,
2171 drivecoll_AddRef,
2172 drivecoll_Release,
2173 drivecoll_GetTypeInfoCount,
2174 drivecoll_GetTypeInfo,
2175 drivecoll_GetIDsOfNames,
2176 drivecoll_Invoke,
2177 drivecoll_get_Item,
2178 drivecoll_get__NewEnum,
2179 drivecoll_get_Count
2182 static HRESULT create_drivecoll(IDriveCollection **drives)
2184 struct drivecollection *This;
2185 DWORD mask;
2187 *drives = NULL;
2189 This = heap_alloc(sizeof(*This));
2190 if (!This) return E_OUTOFMEMORY;
2192 This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl;
2193 This->ref = 1;
2194 This->drives = mask = GetLogicalDrives();
2195 /* count set bits */
2196 for (This->count = 0; mask; This->count++)
2197 mask &= mask - 1;
2199 init_classinfo(&CLSID_Drives, (IUnknown *)&This->IDriveCollection_iface, &This->classinfo);
2200 *drives = &This->IDriveCollection_iface;
2201 return S_OK;
2204 static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
2206 struct folder *This = impl_from_IFolder(iface);
2208 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2210 *obj = NULL;
2212 if (IsEqualIID( riid, &IID_IFolder ) ||
2213 IsEqualIID( riid, &IID_IDispatch ) ||
2214 IsEqualIID( riid, &IID_IUnknown))
2216 *obj = &This->IFolder_iface;
2218 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2220 *obj = &This->classinfo.IProvideClassInfo_iface;
2222 else
2223 return E_NOINTERFACE;
2225 IUnknown_AddRef((IUnknown*)*obj);
2226 return S_OK;
2229 static ULONG WINAPI folder_AddRef(IFolder *iface)
2231 struct folder *This = impl_from_IFolder(iface);
2232 ULONG ref = InterlockedIncrement(&This->ref);
2233 TRACE("(%p)->(%d)\n", This, ref);
2234 return ref;
2237 static ULONG WINAPI folder_Release(IFolder *iface)
2239 struct folder *This = impl_from_IFolder(iface);
2240 ULONG ref = InterlockedDecrement(&This->ref);
2241 TRACE("(%p)->(%d)\n", This, ref);
2243 if (!ref)
2245 SysFreeString(This->path);
2246 heap_free(This);
2249 return ref;
2252 static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
2254 struct folder *This = impl_from_IFolder(iface);
2255 TRACE("(%p)->(%p)\n", This, pctinfo);
2256 *pctinfo = 1;
2257 return S_OK;
2260 static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
2261 LCID lcid, ITypeInfo **ppTInfo)
2263 struct folder *This = impl_from_IFolder(iface);
2264 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2265 return get_typeinfo(IFolder_tid, ppTInfo);
2268 static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
2269 LPOLESTR *rgszNames, UINT cNames,
2270 LCID lcid, DISPID *rgDispId)
2272 struct folder *This = impl_from_IFolder(iface);
2273 ITypeInfo *typeinfo;
2274 HRESULT hr;
2276 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2278 hr = get_typeinfo(IFolder_tid, &typeinfo);
2279 if(SUCCEEDED(hr))
2281 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2282 ITypeInfo_Release(typeinfo);
2285 return hr;
2288 static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
2289 REFIID riid, LCID lcid, WORD wFlags,
2290 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2291 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2293 struct folder *This = impl_from_IFolder(iface);
2294 ITypeInfo *typeinfo;
2295 HRESULT hr;
2297 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2298 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2300 hr = get_typeinfo(IFolder_tid, &typeinfo);
2301 if(SUCCEEDED(hr))
2303 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2304 pDispParams, pVarResult, pExcepInfo, puArgErr);
2305 ITypeInfo_Release(typeinfo);
2308 return hr;
2311 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
2313 struct folder *This = impl_from_IFolder(iface);
2315 TRACE("(%p)->(%p)\n", This, path);
2317 if(!path)
2318 return E_POINTER;
2320 *path = SysAllocString(This->path);
2321 return *path ? S_OK : E_OUTOFMEMORY;
2324 static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
2326 struct folder *This = impl_from_IFolder(iface);
2327 WCHAR *ptr;
2329 TRACE("(%p)->(%p)\n", This, name);
2331 if(!name)
2332 return E_POINTER;
2334 *name = NULL;
2336 ptr = wcsrchr(This->path, '\\');
2337 if (ptr)
2339 *name = SysAllocString(ptr+1);
2340 TRACE("%s\n", debugstr_w(*name));
2341 if (!*name) return E_OUTOFMEMORY;
2343 else
2344 return E_FAIL;
2346 return S_OK;
2349 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
2351 struct folder *This = impl_from_IFolder(iface);
2352 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
2353 return E_NOTIMPL;
2356 static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
2358 struct folder *This = impl_from_IFolder(iface);
2359 FIXME("(%p)->(%p): stub\n", This, path);
2360 return E_NOTIMPL;
2363 static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
2365 struct folder *This = impl_from_IFolder(iface);
2366 FIXME("(%p)->(%p): stub\n", This, name);
2367 return E_NOTIMPL;
2370 static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
2372 struct folder *This = impl_from_IFolder(iface);
2373 FIXME("(%p)->(%p): stub\n", This, drive);
2374 return E_NOTIMPL;
2377 static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
2379 struct folder *This = impl_from_IFolder(iface);
2380 FIXME("(%p)->(%p): stub\n", This, parent);
2381 return E_NOTIMPL;
2384 static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
2386 struct folder *This = impl_from_IFolder(iface);
2387 FIXME("(%p)->(%p): stub\n", This, attr);
2388 return E_NOTIMPL;
2391 static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
2393 struct folder *This = impl_from_IFolder(iface);
2394 FIXME("(%p)->(0x%x): stub\n", This, attr);
2395 return E_NOTIMPL;
2398 static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
2400 struct folder *This = impl_from_IFolder(iface);
2401 FIXME("(%p)->(%p): stub\n", This, date);
2402 return E_NOTIMPL;
2405 static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
2407 struct folder *This = impl_from_IFolder(iface);
2408 FIXME("(%p)->(%p): stub\n", This, date);
2409 return E_NOTIMPL;
2412 static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
2414 struct folder *This = impl_from_IFolder(iface);
2415 FIXME("(%p)->(%p): stub\n", This, date);
2416 return E_NOTIMPL;
2419 static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
2421 struct folder *This = impl_from_IFolder(iface);
2422 FIXME("(%p)->(%p): stub\n", This, type);
2423 return E_NOTIMPL;
2426 static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
2428 struct folder *This = impl_from_IFolder(iface);
2429 FIXME("(%p)->(%x): stub\n", This, force);
2430 return E_NOTIMPL;
2433 static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
2435 struct folder *This = impl_from_IFolder(iface);
2436 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
2437 return E_NOTIMPL;
2440 static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
2442 struct folder *This = impl_from_IFolder(iface);
2443 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
2444 return E_NOTIMPL;
2447 static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
2449 struct folder *This = impl_from_IFolder(iface);
2450 FIXME("(%p)->(%p): stub\n", This, isroot);
2451 return E_NOTIMPL;
2454 static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
2456 struct folder *This = impl_from_IFolder(iface);
2457 FIXME("(%p)->(%p): stub\n", This, size);
2458 return E_NOTIMPL;
2461 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
2463 struct folder *This = impl_from_IFolder(iface);
2465 TRACE("(%p)->(%p)\n", This, folders);
2467 if(!folders)
2468 return E_POINTER;
2470 return create_foldercoll(This->path, folders);
2473 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
2475 struct folder *This = impl_from_IFolder(iface);
2477 TRACE("(%p)->(%p)\n", This, files);
2479 if(!files)
2480 return E_POINTER;
2482 return create_filecoll(This->path, files);
2485 static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
2486 VARIANT_BOOL unicode, ITextStream **stream)
2488 struct folder *This = impl_from_IFolder(iface);
2489 FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
2490 return E_NOTIMPL;
2493 static const IFolderVtbl foldervtbl = {
2494 folder_QueryInterface,
2495 folder_AddRef,
2496 folder_Release,
2497 folder_GetTypeInfoCount,
2498 folder_GetTypeInfo,
2499 folder_GetIDsOfNames,
2500 folder_Invoke,
2501 folder_get_Path,
2502 folder_get_Name,
2503 folder_put_Name,
2504 folder_get_ShortPath,
2505 folder_get_ShortName,
2506 folder_get_Drive,
2507 folder_get_ParentFolder,
2508 folder_get_Attributes,
2509 folder_put_Attributes,
2510 folder_get_DateCreated,
2511 folder_get_DateLastModified,
2512 folder_get_DateLastAccessed,
2513 folder_get_Type,
2514 folder_Delete,
2515 folder_Copy,
2516 folder_Move,
2517 folder_get_IsRootFolder,
2518 folder_get_Size,
2519 folder_get_SubFolders,
2520 folder_get_Files,
2521 folder_CreateTextFile
2524 HRESULT create_folder(const WCHAR *path, IFolder **folder)
2526 struct folder *This;
2528 *folder = NULL;
2530 TRACE("%s\n", debugstr_w(path));
2532 This = heap_alloc(sizeof(struct folder));
2533 if (!This) return E_OUTOFMEMORY;
2535 This->IFolder_iface.lpVtbl = &foldervtbl;
2536 This->ref = 1;
2537 This->path = SysAllocString(path);
2538 if (!This->path)
2540 heap_free(This);
2541 return E_OUTOFMEMORY;
2544 init_classinfo(&CLSID_Folder, (IUnknown *)&This->IFolder_iface, &This->classinfo);
2545 *folder = &This->IFolder_iface;
2547 return S_OK;
2550 static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
2552 struct file *This = impl_from_IFile(iface);
2554 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2556 *obj = NULL;
2558 if (IsEqualIID(riid, &IID_IFile) ||
2559 IsEqualIID(riid, &IID_IDispatch) ||
2560 IsEqualIID(riid, &IID_IUnknown))
2562 *obj = &This->IFile_iface;
2564 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2566 *obj = &This->classinfo.IProvideClassInfo_iface;
2568 else
2569 return E_NOINTERFACE;
2571 IUnknown_AddRef((IUnknown*)*obj);
2572 return S_OK;
2575 static ULONG WINAPI file_AddRef(IFile *iface)
2577 struct file *This = impl_from_IFile(iface);
2578 LONG ref = InterlockedIncrement(&This->ref);
2580 TRACE("(%p) ref=%d\n", This, ref);
2582 return ref;
2585 static ULONG WINAPI file_Release(IFile *iface)
2587 struct file *This = impl_from_IFile(iface);
2588 LONG ref = InterlockedDecrement(&This->ref);
2590 TRACE("(%p) ref=%d\n", This, ref);
2592 if(!ref)
2594 heap_free(This->path);
2595 heap_free(This);
2598 return ref;
2601 static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
2603 struct file *This = impl_from_IFile(iface);
2605 TRACE("(%p)->(%p)\n", This, pctinfo);
2607 *pctinfo = 1;
2608 return S_OK;
2611 static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
2612 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
2614 struct file *This = impl_from_IFile(iface);
2616 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2618 return get_typeinfo(IFile_tid, ppTInfo);
2621 static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
2622 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2624 struct file *This = impl_from_IFile(iface);
2625 ITypeInfo *typeinfo;
2626 HRESULT hr;
2628 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
2629 rgszNames, cNames, lcid, rgDispId);
2631 hr = get_typeinfo(IFile_tid, &typeinfo);
2632 if(SUCCEEDED(hr)) {
2633 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2634 ITypeInfo_Release(typeinfo);
2636 return hr;
2639 static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2641 struct file *This = impl_from_IFile(iface);
2642 ITypeInfo *typeinfo;
2643 HRESULT hr;
2645 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2646 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2648 hr = get_typeinfo(IFile_tid, &typeinfo);
2649 if(SUCCEEDED(hr))
2651 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2652 pDispParams, pVarResult, pExcepInfo, puArgErr);
2653 ITypeInfo_Release(typeinfo);
2655 return hr;
2658 static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *path)
2660 struct file *This = impl_from_IFile(iface);
2662 TRACE("(%p)->(%p)\n", This, path);
2664 if (!path)
2665 return E_POINTER;
2667 *path = SysAllocString(This->path);
2668 if (!*path)
2669 return E_OUTOFMEMORY;
2671 return S_OK;
2674 static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
2676 struct file *This = impl_from_IFile(iface);
2677 WCHAR *ptr;
2679 TRACE("(%p)->(%p)\n", This, name);
2681 if(!name)
2682 return E_POINTER;
2684 *name = NULL;
2686 ptr = wcsrchr(This->path, '\\');
2687 if (ptr)
2689 *name = SysAllocString(ptr+1);
2690 TRACE("%s\n", debugstr_w(*name));
2691 if (!*name) return E_OUTOFMEMORY;
2693 else
2694 return E_FAIL;
2696 return S_OK;
2699 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
2701 struct file *This = impl_from_IFile(iface);
2702 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
2703 return E_NOTIMPL;
2706 static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
2708 struct file *This = impl_from_IFile(iface);
2709 FIXME("(%p)->(%p)\n", This, pbstrPath);
2710 return E_NOTIMPL;
2713 static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
2715 struct file *This = impl_from_IFile(iface);
2716 FIXME("(%p)->(%p)\n", This, pbstrName);
2717 return E_NOTIMPL;
2720 static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
2722 struct file *This = impl_from_IFile(iface);
2723 FIXME("(%p)->(%p)\n", This, ppdrive);
2724 return E_NOTIMPL;
2727 static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
2729 struct file *This = impl_from_IFile(iface);
2730 FIXME("(%p)->(%p)\n", This, ppfolder);
2731 return E_NOTIMPL;
2734 static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
2736 struct file *This = impl_from_IFile(iface);
2737 DWORD fa;
2739 TRACE("(%p)->(%p)\n", This, pfa);
2741 if(!pfa)
2742 return E_POINTER;
2744 fa = GetFileAttributesW(This->path);
2745 if(fa == INVALID_FILE_ATTRIBUTES)
2746 return create_error(GetLastError());
2748 *pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2749 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
2750 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
2751 return S_OK;
2754 static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
2756 struct file *This = impl_from_IFile(iface);
2758 TRACE("(%p)->(%x)\n", This, pfa);
2760 return SetFileAttributesW(This->path, pfa) ? S_OK : create_error(GetLastError());
2763 static HRESULT get_date_from_filetime(const FILETIME *ft, DATE *date)
2765 FILETIME ftlocal;
2766 SYSTEMTIME st;
2768 if (!date)
2769 return E_POINTER;
2771 FileTimeToLocalFileTime(ft, &ftlocal);
2772 FileTimeToSystemTime(&ftlocal, &st);
2773 SystemTimeToVariantTime(&st, date);
2775 return S_OK;
2778 static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
2780 struct file *This = impl_from_IFile(iface);
2781 FIXME("(%p)->(%p)\n", This, pdate);
2782 return E_NOTIMPL;
2785 static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *date)
2787 struct file *This = impl_from_IFile(iface);
2788 WIN32_FILE_ATTRIBUTE_DATA attrs;
2790 TRACE("(%p)->(%p)\n", This, date);
2792 if (GetFileAttributesExW(This->path, GetFileExInfoStandard, &attrs))
2793 return get_date_from_filetime(&attrs.ftLastWriteTime, date);
2795 return E_FAIL;
2798 static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
2800 struct file *This = impl_from_IFile(iface);
2801 FIXME("(%p)->(%p)\n", This, pdate);
2802 return E_NOTIMPL;
2805 static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
2807 struct file *This = impl_from_IFile(iface);
2808 ULARGE_INTEGER size;
2809 WIN32_FIND_DATAW fd;
2810 HANDLE f;
2812 TRACE("(%p)->(%p)\n", This, pvarSize);
2814 if(!pvarSize)
2815 return E_POINTER;
2817 f = FindFirstFileW(This->path, &fd);
2818 if(f == INVALID_HANDLE_VALUE)
2819 return create_error(GetLastError());
2820 FindClose(f);
2822 size.u.LowPart = fd.nFileSizeLow;
2823 size.u.HighPart = fd.nFileSizeHigh;
2825 return variant_from_largeint(&size, pvarSize);
2828 static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
2830 struct file *This = impl_from_IFile(iface);
2831 FIXME("(%p)->(%p)\n", This, pbstrType);
2832 return E_NOTIMPL;
2835 static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
2837 struct file *This = impl_from_IFile(iface);
2838 FIXME("(%p)->(%x)\n", This, Force);
2839 return E_NOTIMPL;
2842 static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
2844 struct file *This = impl_from_IFile(iface);
2845 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
2846 return E_NOTIMPL;
2849 static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
2851 struct file *This = impl_from_IFile(iface);
2852 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
2853 return E_NOTIMPL;
2856 static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode mode, Tristate format, ITextStream **stream)
2858 struct file *This = impl_from_IFile(iface);
2860 TRACE("(%p)->(%d %d %p)\n", This, mode, format, stream);
2862 return create_textstream(This->path, OPEN_EXISTING, mode, format, stream);
2865 static const IFileVtbl file_vtbl = {
2866 file_QueryInterface,
2867 file_AddRef,
2868 file_Release,
2869 file_GetTypeInfoCount,
2870 file_GetTypeInfo,
2871 file_GetIDsOfNames,
2872 file_Invoke,
2873 file_get_Path,
2874 file_get_Name,
2875 file_put_Name,
2876 file_get_ShortPath,
2877 file_get_ShortName,
2878 file_get_Drive,
2879 file_get_ParentFolder,
2880 file_get_Attributes,
2881 file_put_Attributes,
2882 file_get_DateCreated,
2883 file_get_DateLastModified,
2884 file_get_DateLastAccessed,
2885 file_get_Size,
2886 file_get_Type,
2887 file_Delete,
2888 file_Copy,
2889 file_Move,
2890 file_OpenAsTextStream
2893 static HRESULT create_file(BSTR path, IFile **file)
2895 struct file *f;
2896 DWORD len, attrs;
2898 *file = NULL;
2900 f = heap_alloc(sizeof(struct file));
2901 if(!f)
2902 return E_OUTOFMEMORY;
2904 f->IFile_iface.lpVtbl = &file_vtbl;
2905 f->ref = 1;
2907 len = GetFullPathNameW(path, 0, NULL, NULL);
2908 if(!len) {
2909 heap_free(f);
2910 return E_FAIL;
2913 f->path = heap_alloc(len*sizeof(WCHAR));
2914 if(!f->path) {
2915 heap_free(f);
2916 return E_OUTOFMEMORY;
2919 if(!GetFullPathNameW(path, len, f->path, NULL)) {
2920 heap_free(f->path);
2921 heap_free(f);
2922 return E_FAIL;
2925 attrs = GetFileAttributesW(f->path);
2926 if(attrs==INVALID_FILE_ATTRIBUTES ||
2927 (attrs&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))) {
2928 heap_free(f->path);
2929 heap_free(f);
2930 return create_error(GetLastError());
2933 init_classinfo(&CLSID_File, (IUnknown *)&f->IFile_iface, &f->classinfo);
2934 *file = &f->IFile_iface;
2935 return S_OK;
2938 static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
2940 struct filesystem *This = impl_from_IFileSystem3(iface);
2942 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
2944 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
2945 IsEqualGUID( riid, &IID_IFileSystem ) ||
2946 IsEqualGUID( riid, &IID_IDispatch ) ||
2947 IsEqualGUID( riid, &IID_IUnknown ) )
2949 *ppvObject = &This->IFileSystem3_iface;
2951 else if (IsEqualGUID( riid, &IID_IProvideClassInfo ))
2953 *ppvObject = &This->classinfo.IProvideClassInfo_iface;
2955 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
2957 TRACE("Interface IDispatchEx not supported - returning NULL\n");
2958 *ppvObject = NULL;
2959 return E_NOINTERFACE;
2961 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
2963 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
2964 *ppvObject = NULL;
2965 return E_NOINTERFACE;
2967 else
2969 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
2970 return E_NOINTERFACE;
2973 IUnknown_AddRef((IUnknown*)*ppvObject);
2975 return S_OK;
2978 static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
2980 TRACE("%p\n", iface);
2982 return 2;
2985 static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
2987 TRACE("%p\n", iface);
2989 return 1;
2992 static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
2994 TRACE("(%p)->(%p)\n", iface, pctinfo);
2996 *pctinfo = 1;
2997 return S_OK;
3000 static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
3001 LCID lcid, ITypeInfo **ppTInfo)
3003 TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
3004 return get_typeinfo(IFileSystem3_tid, ppTInfo);
3007 static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
3008 LPOLESTR *rgszNames, UINT cNames,
3009 LCID lcid, DISPID *rgDispId)
3011 ITypeInfo *typeinfo;
3012 HRESULT hr;
3014 TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
3016 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
3017 if(SUCCEEDED(hr))
3019 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
3020 ITypeInfo_Release(typeinfo);
3023 return hr;
3026 static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
3027 REFIID riid, LCID lcid, WORD wFlags,
3028 DISPPARAMS *pDispParams, VARIANT *pVarResult,
3029 EXCEPINFO *pExcepInfo, UINT *puArgErr)
3031 ITypeInfo *typeinfo;
3032 HRESULT hr;
3034 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
3035 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
3037 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
3038 if(SUCCEEDED(hr))
3040 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
3041 pDispParams, pVarResult, pExcepInfo, puArgErr);
3042 ITypeInfo_Release(typeinfo);
3045 return hr;
3048 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
3050 TRACE("%p %p\n", iface, ppdrives);
3051 return create_drivecoll(ppdrives);
3054 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
3055 BSTR Name, BSTR *Result)
3057 BSTR ret;
3059 TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
3061 if (!Result) return E_POINTER;
3063 if (Path && Name)
3065 int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
3067 /* if both parts have backslashes strip one from Path */
3068 if (Path[path_len-1] == '\\' && Name[0] == '\\')
3070 path_len -= 1;
3072 ret = SysAllocStringLen(NULL, path_len + name_len);
3073 if (ret)
3075 lstrcpyW(ret, Path);
3076 ret[path_len] = 0;
3077 lstrcatW(ret, Name);
3080 else if (Path[path_len-1] != '\\' && Name[0] != '\\')
3082 ret = SysAllocStringLen(NULL, path_len + name_len + 1);
3083 if (ret)
3085 lstrcpyW(ret, Path);
3086 if (Path[path_len-1] != ':')
3087 lstrcatW(ret, bsW);
3088 lstrcatW(ret, Name);
3091 else
3093 ret = SysAllocStringLen(NULL, path_len + name_len);
3094 if (ret)
3096 lstrcpyW(ret, Path);
3097 lstrcatW(ret, Name);
3101 else if (Path || Name)
3102 ret = SysAllocString(Path ? Path : Name);
3103 else
3104 ret = SysAllocStringLen(NULL, 0);
3106 if (!ret) return E_OUTOFMEMORY;
3107 *Result = ret;
3109 return S_OK;
3112 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR path, BSTR *drive)
3114 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), drive);
3116 if (!drive)
3117 return E_POINTER;
3119 *drive = NULL;
3121 if (path && lstrlenW(path) > 1 && path[1] == ':')
3122 *drive = SysAllocStringLen(path, 2);
3124 return S_OK;
3127 static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
3129 int i;
3131 if(!path)
3132 return 0;
3134 for(i=len-1; i>=0; i--)
3135 if(path[i]!='/' && path[i]!='\\')
3136 break;
3138 for(; i>=0; i--)
3139 if(path[i]=='/' || path[i]=='\\')
3140 break;
3142 for(; i>=0; i--)
3143 if(path[i]!='/' && path[i]!='\\')
3144 break;
3146 if(i < 0)
3147 return 0;
3149 if(path[i]==':' && i==1)
3150 i++;
3151 return i+1;
3154 static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
3155 BSTR *pbstrResult)
3157 DWORD len;
3159 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3161 if(!pbstrResult)
3162 return E_POINTER;
3164 len = get_parent_folder_name(Path, SysStringLen(Path));
3165 if(!len) {
3166 *pbstrResult = NULL;
3167 return S_OK;
3170 *pbstrResult = SysAllocStringLen(Path, len);
3171 if(!*pbstrResult)
3172 return E_OUTOFMEMORY;
3173 return S_OK;
3176 static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
3177 BSTR *pbstrResult)
3179 int i, end;
3181 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3183 if(!pbstrResult)
3184 return E_POINTER;
3186 if(!Path) {
3187 *pbstrResult = NULL;
3188 return S_OK;
3191 for(end=lstrlenW(Path)-1; end>=0; end--)
3192 if(Path[end]!='/' && Path[end]!='\\')
3193 break;
3195 for(i=end; i>=0; i--)
3196 if(Path[i]=='/' || Path[i]=='\\')
3197 break;
3198 i++;
3200 if(i>end || (i==0 && end==1 && Path[1]==':')) {
3201 *pbstrResult = NULL;
3202 return S_OK;
3205 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3206 if(!*pbstrResult)
3207 return E_OUTOFMEMORY;
3208 return S_OK;
3211 static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
3212 BSTR *pbstrResult)
3214 int i, end;
3216 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3218 if(!pbstrResult)
3219 return E_POINTER;
3221 if(!Path) {
3222 *pbstrResult = NULL;
3223 return S_OK;
3226 for(end=lstrlenW(Path)-1; end>=0; end--)
3227 if(Path[end]!='/' && Path[end]!='\\')
3228 break;
3230 for(i=end; i>=0; i--) {
3231 if(Path[i]=='.' && Path[end+1]!='.')
3232 end = i-1;
3233 if(Path[i]=='/' || Path[i]=='\\')
3234 break;
3236 i++;
3238 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
3239 *pbstrResult = NULL;
3240 return S_OK;
3243 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3244 if(!*pbstrResult)
3245 return E_OUTOFMEMORY;
3246 return S_OK;
3249 static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR path,
3250 BSTR *ext)
3252 INT len;
3254 TRACE("%p %s %p\n", iface, debugstr_w(path), ext);
3256 *ext = NULL;
3257 len = SysStringLen(path);
3258 while (len) {
3259 if (path[len-1] == '.') {
3260 *ext = SysAllocString(&path[len]);
3261 if (!*ext)
3262 return E_OUTOFMEMORY;
3263 break;
3265 len--;
3268 return S_OK;
3271 static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR Path,
3272 BSTR *pbstrResult)
3274 static const WCHAR cur_path[] = {'.',0};
3276 WCHAR buf[MAX_PATH], ch;
3277 const WCHAR *path;
3278 DWORD i, beg, len, exp_len;
3279 WIN32_FIND_DATAW fdata;
3280 HANDLE fh;
3282 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3284 if(!pbstrResult)
3285 return E_POINTER;
3287 if(!Path)
3288 path = cur_path;
3289 else
3290 path = Path;
3292 len = GetFullPathNameW(path, MAX_PATH, buf, NULL);
3293 if(!len)
3294 return E_FAIL;
3296 buf[0] = towupper(buf[0]);
3297 if(len>3 && buf[len-1] == '\\')
3298 buf[--len] = 0;
3300 for(beg=3, i=3; i<=len; i++) {
3301 if(buf[i]!='\\' && buf[i])
3302 continue;
3304 ch = buf[i];
3305 buf[i] = 0;
3306 fh = FindFirstFileW(buf, &fdata);
3307 if(fh == INVALID_HANDLE_VALUE)
3308 break;
3310 exp_len = lstrlenW(fdata.cFileName);
3311 if(exp_len == i-beg)
3312 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
3313 FindClose(fh);
3314 buf[i] = ch;
3315 beg = i+1;
3318 *pbstrResult = SysAllocString(buf);
3319 if(!*pbstrResult)
3320 return E_OUTOFMEMORY;
3321 return S_OK;
3324 static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
3326 static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
3328 DWORD random;
3330 TRACE("%p %p\n", iface, pbstrResult);
3332 if(!pbstrResult)
3333 return E_POINTER;
3335 *pbstrResult = SysAllocStringLen(NULL, 12);
3336 if(!*pbstrResult)
3337 return E_OUTOFMEMORY;
3339 if(!RtlGenRandom(&random, sizeof(random)))
3340 return E_FAIL;
3341 swprintf(*pbstrResult, 12, fmt, random & 0xfffff);
3342 return S_OK;
3345 static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
3346 VARIANT_BOOL *pfExists)
3348 UINT len;
3349 WCHAR driveletter;
3350 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
3352 if (!pfExists) return E_POINTER;
3354 *pfExists = VARIANT_FALSE;
3355 len = SysStringLen(DriveSpec);
3357 if (len >= 1) {
3358 driveletter = towupper(DriveSpec[0]);
3359 if (driveletter >= 'A' && driveletter <= 'Z'
3360 && (len < 2 || DriveSpec[1] == ':')
3361 && (len < 3 || DriveSpec[2] == '\\')) {
3362 const WCHAR root[] = {driveletter, ':', '\\', 0};
3363 UINT drivetype = GetDriveTypeW(root);
3364 *pfExists = drivetype != DRIVE_NO_ROOT_DIR && drivetype != DRIVE_UNKNOWN ? VARIANT_TRUE : VARIANT_FALSE;
3368 return S_OK;
3371 static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3373 DWORD attrs;
3374 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3376 if (!ret) return E_POINTER;
3378 attrs = GetFileAttributesW(path);
3379 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3380 return S_OK;
3383 static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3385 DWORD attrs;
3386 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3388 if (!ret) return E_POINTER;
3390 attrs = GetFileAttributesW(path);
3391 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3393 return S_OK;
3396 static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
3397 IDrive **ppdrive)
3399 UINT len;
3400 HRESULT hr;
3401 WCHAR driveletter;
3402 VARIANT_BOOL drive_exists;
3404 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
3406 if (!ppdrive)
3407 return E_POINTER;
3409 *ppdrive = NULL;
3411 /* DriveSpec may be one of: 'x', 'x:', 'x:\', '\\computer\share' */
3412 len = SysStringLen(DriveSpec);
3413 if (!len)
3414 return E_INVALIDARG;
3415 else if (len <= 3) {
3416 driveletter = towupper(DriveSpec[0]);
3417 if (driveletter < 'A' || driveletter > 'Z'
3418 || (len >= 2 && DriveSpec[1] != ':')
3419 || (len == 3 && DriveSpec[2] != '\\'))
3420 return E_INVALIDARG;
3421 hr = IFileSystem3_DriveExists(iface, DriveSpec, &drive_exists);
3422 if (FAILED(hr))
3423 return hr;
3424 if (drive_exists == VARIANT_FALSE)
3425 return CTL_E_DEVICEUNAVAILABLE;
3426 return create_drive(driveletter, ppdrive);
3427 } else {
3428 if (DriveSpec[0] != '\\' || DriveSpec[1] != '\\')
3429 return E_INVALIDARG;
3430 FIXME("%s not implemented yet\n", debugstr_w(DriveSpec));
3431 return E_NOTIMPL;
3435 static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
3436 IFile **ppfile)
3438 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
3440 if(!ppfile)
3441 return E_POINTER;
3442 if(!FilePath)
3443 return E_INVALIDARG;
3445 return create_file(FilePath, ppfile);
3448 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
3449 IFolder **folder)
3451 DWORD attrs;
3453 TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
3455 if(!folder)
3456 return E_POINTER;
3458 *folder = NULL;
3459 if(!FolderPath)
3460 return E_INVALIDARG;
3462 attrs = GetFileAttributesW(FolderPath);
3463 if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
3464 return CTL_E_PATHNOTFOUND;
3466 return create_folder(FolderPath, folder);
3469 static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
3470 SpecialFolderConst SpecialFolder,
3471 IFolder **folder)
3473 WCHAR pathW[MAX_PATH];
3474 DWORD ret;
3476 TRACE("%p %d %p\n", iface, SpecialFolder, folder);
3478 if (!folder)
3479 return E_POINTER;
3481 *folder = NULL;
3483 switch (SpecialFolder)
3485 case WindowsFolder:
3486 ret = GetWindowsDirectoryW(pathW, ARRAY_SIZE(pathW));
3487 break;
3488 case SystemFolder:
3489 ret = GetSystemDirectoryW(pathW, ARRAY_SIZE(pathW));
3490 break;
3491 case TemporaryFolder:
3492 ret = GetTempPathW(ARRAY_SIZE(pathW), pathW);
3493 /* we don't want trailing backslash */
3494 if (ret && pathW[ret-1] == '\\')
3495 pathW[ret-1] = 0;
3496 break;
3497 default:
3498 FIXME("unknown special folder type, %d\n", SpecialFolder);
3499 return E_INVALIDARG;
3502 if (!ret)
3503 return HRESULT_FROM_WIN32(GetLastError());
3505 return create_folder(pathW, folder);
3508 static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
3510 WCHAR path[MAX_PATH];
3511 DWORD len, name_len;
3512 WIN32_FIND_DATAW ffd;
3513 HANDLE f;
3515 f = FindFirstFileW(file, &ffd);
3516 if(f == INVALID_HANDLE_VALUE)
3517 return create_error(GetLastError());
3519 len = get_parent_folder_name(file, file_len);
3520 if(len+1 >= MAX_PATH) {
3521 FindClose(f);
3522 return E_FAIL;
3524 if(len) {
3525 memcpy(path, file, len*sizeof(WCHAR));
3526 path[len++] = '\\';
3529 do {
3530 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3531 continue;
3533 name_len = lstrlenW(ffd.cFileName);
3534 if(len+name_len+1 >= MAX_PATH) {
3535 FindClose(f);
3536 return E_FAIL;
3538 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3540 TRACE("deleting %s\n", debugstr_w(path));
3542 if(!DeleteFileW(path)) {
3543 if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
3544 || !DeleteFileW(path)) {
3545 FindClose(f);
3546 return create_error(GetLastError());
3549 } while(FindNextFileW(f, &ffd));
3550 FindClose(f);
3552 return S_OK;
3555 static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
3556 VARIANT_BOOL Force)
3558 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
3560 if(!FileSpec)
3561 return E_POINTER;
3563 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
3566 static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
3568 WCHAR path[MAX_PATH];
3569 DWORD len, name_len;
3570 WIN32_FIND_DATAW ffd;
3571 HANDLE f;
3572 HRESULT hr;
3574 f = FindFirstFileW(folder, &ffd);
3575 if(f == INVALID_HANDLE_VALUE)
3576 return create_error(GetLastError());
3578 len = get_parent_folder_name(folder, folder_len);
3579 if(len+1 >= MAX_PATH) {
3580 FindClose(f);
3581 return E_FAIL;
3583 if(len) {
3584 memcpy(path, folder, len*sizeof(WCHAR));
3585 path[len++] = '\\';
3588 do {
3589 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3590 continue;
3591 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3592 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3593 continue;
3595 name_len = lstrlenW(ffd.cFileName);
3596 if(len+name_len+3 >= MAX_PATH) {
3597 FindClose(f);
3598 return E_FAIL;
3600 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
3601 path[len+name_len] = '\\';
3602 path[len+name_len+1] = '*';
3603 path[len+name_len+2] = 0;
3605 hr = delete_file(path, len+name_len+2, force);
3606 if(FAILED(hr)) {
3607 FindClose(f);
3608 return hr;
3611 hr = delete_folder(path, len+name_len+2, force);
3612 if(FAILED(hr)) {
3613 FindClose(f);
3614 return hr;
3617 path[len+name_len] = 0;
3618 TRACE("deleting %s\n", debugstr_w(path));
3620 if(!RemoveDirectoryW(path)) {
3621 FindClose(f);
3622 return create_error(GetLastError());
3624 } while(FindNextFileW(f, &ffd));
3625 FindClose(f);
3627 return S_OK;
3630 static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
3631 VARIANT_BOOL Force)
3633 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
3635 if(!FolderSpec)
3636 return E_POINTER;
3638 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
3641 static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR source, BSTR destination)
3643 TRACE("%p %s %s\n", iface, debugstr_w(source), debugstr_w(destination));
3645 return MoveFileW(source, destination) ? S_OK : create_error(GetLastError());
3648 static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
3649 BSTR Destination)
3651 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3653 return E_NOTIMPL;
3656 static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
3657 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
3659 DWORD attrs;
3660 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
3661 DWORD src_len, dst_len, name_len;
3662 WIN32_FIND_DATAW ffd;
3663 HANDLE f;
3664 HRESULT hr;
3666 if(!source[0] || !destination[0])
3667 return E_INVALIDARG;
3669 attrs = GetFileAttributesW(destination);
3670 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
3671 attrs = GetFileAttributesW(source);
3672 if(attrs == INVALID_FILE_ATTRIBUTES)
3673 return create_error(GetLastError());
3674 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
3675 return CTL_E_FILENOTFOUND;
3677 if(!CopyFileW(source, destination, !overwrite))
3678 return create_error(GetLastError());
3679 return S_OK;
3682 f = FindFirstFileW(source, &ffd);
3683 if(f == INVALID_HANDLE_VALUE)
3684 return CTL_E_FILENOTFOUND;
3686 src_len = get_parent_folder_name(source, source_len);
3687 if(src_len+1 >= MAX_PATH) {
3688 FindClose(f);
3689 return E_FAIL;
3691 if(src_len) {
3692 memcpy(src_path, source, src_len*sizeof(WCHAR));
3693 src_path[src_len++] = '\\';
3696 dst_len = destination_len;
3697 if(dst_len+1 >= MAX_PATH) {
3698 FindClose(f);
3699 return E_FAIL;
3701 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
3702 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
3703 dst_path[dst_len++] = '\\';
3705 hr = CTL_E_FILENOTFOUND;
3706 do {
3707 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3708 continue;
3710 name_len = lstrlenW(ffd.cFileName);
3711 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
3712 FindClose(f);
3713 return E_FAIL;
3715 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3716 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3718 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
3720 if(!CopyFileW(src_path, dst_path, !overwrite)) {
3721 FindClose(f);
3722 return create_error(GetLastError());
3723 }else {
3724 hr = S_OK;
3726 } while(FindNextFileW(f, &ffd));
3727 FindClose(f);
3729 return hr;
3732 static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
3733 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3735 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3737 if(!Source || !Destination)
3738 return E_POINTER;
3740 return copy_file(Source, SysStringLen(Source), Destination,
3741 SysStringLen(Destination), OverWriteFiles);
3744 static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
3745 DWORD destination_len, VARIANT_BOOL overwrite)
3747 DWORD tmp, src_len, dst_len, name_len;
3748 WCHAR src[MAX_PATH], dst[MAX_PATH];
3749 WIN32_FIND_DATAW ffd;
3750 HANDLE f;
3751 HRESULT hr;
3752 BOOL copied = FALSE;
3754 if(!source[0] || !destination[0])
3755 return E_INVALIDARG;
3757 dst_len = destination_len;
3758 if(dst_len+1 >= MAX_PATH)
3759 return E_FAIL;
3760 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
3762 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
3763 (tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
3764 tmp&FILE_ATTRIBUTE_DIRECTORY) {
3765 if(!CreateDirectoryW(dst, NULL)) {
3766 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3767 tmp = GetFileAttributesW(dst);
3768 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
3769 return CTL_E_FILEALREADYEXISTS;
3770 }else {
3771 return create_error(GetLastError());
3774 copied = TRUE;
3776 src_len = source_len;
3777 if(src_len+2 >= MAX_PATH)
3778 return E_FAIL;
3779 memcpy(src, source, src_len*sizeof(WCHAR));
3780 src[src_len++] = '\\';
3781 src[src_len] = '*';
3782 src[src_len+1] = 0;
3784 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
3785 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
3786 return create_error(GetLastError());
3788 f = FindFirstFileW(src, &ffd);
3789 }else {
3790 src_len = get_parent_folder_name(source, source_len);
3791 if(src_len+2 >= MAX_PATH)
3792 return E_FAIL;
3793 memcpy(src, source, src_len*sizeof(WCHAR));
3794 if(src_len)
3795 src[src_len++] = '\\';
3797 f = FindFirstFileW(source, &ffd);
3799 if(f == INVALID_HANDLE_VALUE)
3800 return CTL_E_PATHNOTFOUND;
3802 dst[dst_len++] = '\\';
3803 dst[dst_len] = 0;
3805 do {
3806 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3807 continue;
3808 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3809 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3810 continue;
3812 name_len = lstrlenW(ffd.cFileName);
3813 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
3814 FindClose(f);
3815 return E_FAIL;
3817 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
3818 dst[dst_len+name_len] = 0;
3819 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
3820 src[src_len+name_len] = '\\';
3821 src[src_len+name_len+1] = '*';
3822 src[src_len+name_len+2] = 0;
3824 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
3826 if(!CreateDirectoryW(dst, NULL)) {
3827 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3828 tmp = GetFileAttributesW(dst);
3829 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
3830 FindClose(f);
3831 return CTL_E_FILEALREADYEXISTS;
3835 FindClose(f);
3836 return create_error(GetLastError());
3838 copied = TRUE;
3840 hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3841 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
3842 FindClose(f);
3843 return hr;
3846 hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3847 if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
3848 FindClose(f);
3849 return hr;
3851 } while(FindNextFileW(f, &ffd));
3852 FindClose(f);
3854 return copied ? S_OK : CTL_E_PATHNOTFOUND;
3857 static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
3858 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3860 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3862 if(!Source || !Destination)
3863 return E_POINTER;
3865 return copy_folder(Source, SysStringLen(Source), Destination,
3866 SysStringLen(Destination), OverWriteFiles);
3869 static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
3870 IFolder **folder)
3872 BOOL ret;
3874 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
3876 ret = CreateDirectoryW(path, NULL);
3877 if (!ret)
3879 *folder = NULL;
3880 if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
3881 return HRESULT_FROM_WIN32(GetLastError());
3884 return create_folder(path, folder);
3887 static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR filename,
3888 VARIANT_BOOL overwrite, VARIANT_BOOL unicode,
3889 ITextStream **stream)
3891 DWORD disposition;
3893 TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
3895 disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
3896 return create_textstream(filename, disposition, ForWriting, unicode ? TristateTrue : TristateFalse, stream);
3899 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
3900 IOMode mode, VARIANT_BOOL create,
3901 Tristate format, ITextStream **stream)
3903 DWORD disposition;
3905 TRACE("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
3907 disposition = create == VARIANT_TRUE ? OPEN_ALWAYS : OPEN_EXISTING;
3908 return create_textstream(filename, disposition, mode, format, stream);
3911 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
3912 StandardStreamTypes StandardStreamType,
3913 VARIANT_BOOL Unicode,
3914 ITextStream **ppts)
3916 FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
3918 return E_NOTIMPL;
3921 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
3923 static const WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
3924 DWORDLONG version;
3925 WORD a, b, c, d;
3927 version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
3928 a = (WORD)( version >> 48);
3929 b = (WORD)((version >> 32) & 0xffff);
3930 c = (WORD)((version >> 16) & 0xffff);
3931 d = (WORD)( version & 0xffff);
3933 swprintf(ver, 30, fmtW, a, b, c, d);
3936 static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
3938 static const WCHAR rootW[] = {'\\',0};
3939 VS_FIXEDFILEINFO *info;
3940 WCHAR ver[30];
3941 void *ptr;
3942 DWORD len;
3943 BOOL ret;
3945 TRACE("%p %s %p\n", iface, debugstr_w(name), version);
3947 len = GetFileVersionInfoSizeW(name, NULL);
3948 if (!len)
3949 return HRESULT_FROM_WIN32(GetLastError());
3951 ptr = heap_alloc(len);
3952 if (!GetFileVersionInfoW(name, 0, len, ptr))
3954 heap_free(ptr);
3955 return HRESULT_FROM_WIN32(GetLastError());
3958 ret = VerQueryValueW(ptr, rootW, (void**)&info, &len);
3959 if (!ret)
3961 heap_free(ptr);
3962 return HRESULT_FROM_WIN32(GetLastError());
3965 get_versionstring(info, ver);
3966 heap_free(ptr);
3968 *version = SysAllocString(ver);
3969 TRACE("version=%s\n", debugstr_w(ver));
3971 return S_OK;
3974 static const struct IFileSystem3Vtbl filesys_vtbl =
3976 filesys_QueryInterface,
3977 filesys_AddRef,
3978 filesys_Release,
3979 filesys_GetTypeInfoCount,
3980 filesys_GetTypeInfo,
3981 filesys_GetIDsOfNames,
3982 filesys_Invoke,
3983 filesys_get_Drives,
3984 filesys_BuildPath,
3985 filesys_GetDriveName,
3986 filesys_GetParentFolderName,
3987 filesys_GetFileName,
3988 filesys_GetBaseName,
3989 filesys_GetExtensionName,
3990 filesys_GetAbsolutePathName,
3991 filesys_GetTempName,
3992 filesys_DriveExists,
3993 filesys_FileExists,
3994 filesys_FolderExists,
3995 filesys_GetDrive,
3996 filesys_GetFile,
3997 filesys_GetFolder,
3998 filesys_GetSpecialFolder,
3999 filesys_DeleteFile,
4000 filesys_DeleteFolder,
4001 filesys_MoveFile,
4002 filesys_MoveFolder,
4003 filesys_CopyFile,
4004 filesys_CopyFolder,
4005 filesys_CreateFolder,
4006 filesys_CreateTextFile,
4007 filesys_OpenTextFile,
4008 filesys_GetStandardStream,
4009 filesys_GetFileVersion
4012 static struct filesystem filesystem;
4014 HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
4016 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
4018 filesystem.IFileSystem3_iface.lpVtbl = &filesys_vtbl;
4019 init_classinfo(&CLSID_FileSystemObject, (IUnknown *)&filesystem.IFileSystem3_iface, &filesystem.classinfo);
4020 return IFileSystem3_QueryInterface(&filesystem.IFileSystem3_iface, riid, ppv);