wined3d: Introduce a wined3d_state_get_ffp_texture() helper.
[wine.git] / dlls / scrrun / filesystem.c
blobe53355267db2e324049833e97c407ee9f85eabfe
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"
37 WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
39 struct filesystem {
40 struct provideclassinfo classinfo;
41 IFileSystem3 IFileSystem3_iface;
44 struct foldercollection {
45 struct provideclassinfo classinfo;
46 IFolderCollection IFolderCollection_iface;
47 LONG ref;
48 BSTR path;
51 struct filecollection {
52 struct provideclassinfo classinfo;
53 IFileCollection IFileCollection_iface;
54 LONG ref;
55 BSTR path;
58 struct drivecollection {
59 struct provideclassinfo classinfo;
60 IDriveCollection IDriveCollection_iface;
61 LONG ref;
62 DWORD drives;
63 LONG count;
66 struct enumdata {
67 union
69 struct
71 struct foldercollection *coll;
72 HANDLE find;
73 } foldercoll;
74 struct
76 struct filecollection *coll;
77 HANDLE find;
78 } filecoll;
79 struct
81 struct drivecollection *coll;
82 INT cur;
83 } drivecoll;
84 } u;
87 struct enumvariant {
88 IEnumVARIANT IEnumVARIANT_iface;
89 LONG ref;
91 struct enumdata data;
94 struct drive {
95 struct provideclassinfo classinfo;
96 IDrive IDrive_iface;
97 LONG ref;
98 WCHAR root[4];
101 struct folder {
102 struct provideclassinfo classinfo;
103 IFolder IFolder_iface;
104 LONG ref;
105 BSTR path;
108 struct file {
109 struct provideclassinfo classinfo;
110 IFile IFile_iface;
111 LONG ref;
113 WCHAR *path;
116 struct textstream {
117 struct provideclassinfo classinfo;
118 ITextStream ITextStream_iface;
119 LONG ref;
121 IOMode mode;
122 BOOL unicode;
123 LARGE_INTEGER size;
124 HANDLE file;
126 BOOL eof;
127 WCHAR *read_buf;
128 size_t read_buf_size;
131 enum iotype {
132 IORead,
133 IOWrite
136 static inline struct filesystem *impl_from_IFileSystem3(IFileSystem3 *iface)
138 return CONTAINING_RECORD(iface, struct filesystem, IFileSystem3_iface);
141 static inline struct drive *impl_from_IDrive(IDrive *iface)
143 return CONTAINING_RECORD(iface, struct drive, IDrive_iface);
146 static inline struct folder *impl_from_IFolder(IFolder *iface)
148 return CONTAINING_RECORD(iface, struct folder, IFolder_iface);
151 static inline struct file *impl_from_IFile(IFile *iface)
153 return CONTAINING_RECORD(iface, struct file, IFile_iface);
156 static inline struct textstream *impl_from_ITextStream(ITextStream *iface)
158 return CONTAINING_RECORD(iface, struct textstream, ITextStream_iface);
161 static inline struct foldercollection *impl_from_IFolderCollection(IFolderCollection *iface)
163 return CONTAINING_RECORD(iface, struct foldercollection, IFolderCollection_iface);
166 static inline struct filecollection *impl_from_IFileCollection(IFileCollection *iface)
168 return CONTAINING_RECORD(iface, struct filecollection, IFileCollection_iface);
171 static inline struct drivecollection *impl_from_IDriveCollection(IDriveCollection *iface)
173 return CONTAINING_RECORD(iface, struct drivecollection, IDriveCollection_iface);
176 static inline struct enumvariant *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
178 return CONTAINING_RECORD(iface, struct enumvariant, IEnumVARIANT_iface);
181 static inline HRESULT create_error(DWORD err)
183 switch(err) {
184 case ERROR_FILE_NOT_FOUND: return CTL_E_FILENOTFOUND;
185 case ERROR_PATH_NOT_FOUND: return CTL_E_PATHNOTFOUND;
186 case ERROR_ACCESS_DENIED: return CTL_E_PERMISSIONDENIED;
187 case ERROR_FILE_EXISTS: return CTL_E_FILEALREADYEXISTS;
188 case ERROR_ALREADY_EXISTS: return CTL_E_FILEALREADYEXISTS;
189 default:
190 FIXME("Unsupported error code: %ld\n", err);
191 return E_FAIL;
195 static HRESULT create_folder(const WCHAR*, IFolder**);
196 static HRESULT create_file(BSTR, IFile**);
197 static HRESULT create_foldercoll_enum(struct foldercollection*, IUnknown**);
198 static HRESULT create_filecoll_enum(struct filecollection*, IUnknown**);
199 static HRESULT create_drivecoll_enum(struct drivecollection*, IUnknown**);
201 static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data)
203 return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
204 wcscmp(data->cFileName, L"..") &&
205 wcscmp(data->cFileName, L".");
208 static inline BOOL is_file_data(const WIN32_FIND_DATAW *data)
210 return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
213 static BSTR get_full_path(BSTR path, const WIN32_FIND_DATAW *data)
215 int len = SysStringLen(path);
216 WCHAR buffW[MAX_PATH];
218 lstrcpyW(buffW, path);
219 if (path[len-1] != '\\') wcscat(buffW, L"\\");
220 lstrcatW(buffW, data->cFileName);
222 return SysAllocString(buffW);
225 static HRESULT build_path( BSTR Path, BSTR Name, BSTR *Result)
227 BSTR ret;
229 if (Path && Name)
231 int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
233 /* if both parts have backslashes strip one from Path */
234 if (Path[path_len-1] == '\\' && Name[0] == '\\')
236 path_len -= 1;
238 ret = SysAllocStringLen(NULL, path_len + name_len);
239 if (ret)
241 lstrcpyW(ret, Path);
242 ret[path_len] = 0;
243 lstrcatW(ret, Name);
246 else if (Path[path_len-1] != '\\' && Name[0] != '\\')
248 ret = SysAllocStringLen(NULL, path_len + name_len + 1);
249 if (ret)
251 lstrcpyW(ret, Path);
252 if (Path[path_len-1] != ':')
253 wcscat(ret, L"\\");
254 lstrcatW(ret, Name);
257 else
259 ret = SysAllocStringLen(NULL, path_len + name_len);
260 if (ret)
262 lstrcpyW(ret, Path);
263 lstrcatW(ret, Name);
267 else if (Path || Name)
268 ret = SysAllocString(Path ? Path : Name);
269 else
270 ret = SysAllocStringLen(NULL, 0);
272 if (!ret) return E_OUTOFMEMORY;
273 *Result = ret;
275 return S_OK;
278 static BOOL textstream_check_iomode(struct textstream *This, enum iotype type)
280 if (type == IORead)
281 return This->mode == ForWriting || This->mode == ForAppending;
282 else
283 return This->mode == ForReading;
286 static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
288 struct textstream *This = impl_from_ITextStream(iface);
290 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
292 if (IsEqualIID(riid, &IID_ITextStream) ||
293 IsEqualIID(riid, &IID_IDispatch) ||
294 IsEqualIID(riid, &IID_IUnknown))
296 *obj = &This->ITextStream_iface;
298 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
300 *obj = &This->classinfo.IProvideClassInfo_iface;
302 else
303 return E_NOINTERFACE;
305 IUnknown_AddRef((IUnknown*)*obj);
306 return S_OK;
309 static ULONG WINAPI textstream_AddRef(ITextStream *iface)
311 struct textstream *stream = impl_from_ITextStream(iface);
312 ULONG ref = InterlockedIncrement(&stream->ref);
314 TRACE("%p, refcount %ld.\n", iface, ref);
316 return ref;
319 static ULONG WINAPI textstream_Release(ITextStream *iface)
321 struct textstream *stream = impl_from_ITextStream(iface);
322 ULONG ref = InterlockedDecrement(&stream->ref);
324 TRACE("%p, refcount %ld.\n", iface, ref);
326 if (!ref)
328 if (stream->read_buf_size) free(stream->read_buf);
329 CloseHandle(stream->file);
330 free(stream);
333 return ref;
336 static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
338 struct textstream *This = impl_from_ITextStream(iface);
339 TRACE("(%p)->(%p)\n", This, pctinfo);
340 *pctinfo = 1;
341 return S_OK;
344 static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
345 LCID lcid, ITypeInfo **ppTInfo)
347 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
349 return get_typeinfo(ITextStream_tid, ppTInfo);
352 static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
353 LPOLESTR *rgszNames, UINT cNames,
354 LCID lcid, DISPID *rgDispId)
356 ITypeInfo *typeinfo;
357 HRESULT hr;
359 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
361 hr = get_typeinfo(ITextStream_tid, &typeinfo);
362 if(SUCCEEDED(hr))
364 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
365 ITypeInfo_Release(typeinfo);
368 return hr;
371 static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
372 REFIID riid, LCID lcid, WORD wFlags,
373 DISPPARAMS *pDispParams, VARIANT *pVarResult,
374 EXCEPINFO *pExcepInfo, UINT *puArgErr)
376 ITypeInfo *typeinfo;
377 HRESULT hr;
379 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
380 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
382 hr = get_typeinfo(ITextStream_tid, &typeinfo);
383 if(SUCCEEDED(hr))
385 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
386 pDispParams, pVarResult, pExcepInfo, puArgErr);
387 ITypeInfo_Release(typeinfo);
390 return hr;
393 static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
395 struct textstream *This = impl_from_ITextStream(iface);
396 FIXME("(%p)->(%p): stub\n", This, line);
397 return E_NOTIMPL;
400 static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
402 struct textstream *This = impl_from_ITextStream(iface);
403 FIXME("(%p)->(%p): stub\n", This, column);
404 return E_NOTIMPL;
407 static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
409 struct textstream *This = impl_from_ITextStream(iface);
411 TRACE("(%p)->(%p)\n", This, eos);
413 if (!eos)
414 return E_POINTER;
416 if (textstream_check_iomode(This, IORead)) {
417 *eos = VARIANT_TRUE;
418 return CTL_E_BADFILEMODE;
421 *eos = (This->eof && !This->read_buf_size) ? VARIANT_TRUE : VARIANT_FALSE;
422 return S_OK;
425 static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
427 struct textstream *This = impl_from_ITextStream(iface);
428 FIXME("(%p)->(%p): stub\n", This, eol);
429 return E_NOTIMPL;
432 static HRESULT append_read_data(struct textstream *stream, const char *buf, size_t buf_size)
434 LARGE_INTEGER revert;
435 size_t len;
436 WCHAR *new_buf;
438 revert.QuadPart = 0;
439 if (stream->unicode)
441 len = buf_size / sizeof(WCHAR);
442 if (buf_size & 1) revert.QuadPart = -1;
444 else
446 for (len = 0; len < buf_size; len++)
448 if (!IsDBCSLeadByte(buf[len])) continue;
449 if (len + 1 == buf_size)
451 revert.QuadPart = -1;
452 buf_size--;
453 break;
455 len++;
457 len = MultiByteToWideChar(CP_ACP, 0, buf, buf_size, NULL, 0);
459 if (!len)
460 return S_OK;
461 if (revert.QuadPart)
462 SetFilePointerEx(stream->file, revert, NULL, FILE_CURRENT);
464 if (!stream->read_buf_size)
465 new_buf = malloc(len * sizeof(WCHAR));
466 else
467 new_buf = realloc(stream->read_buf, (len + stream->read_buf_size) * sizeof(WCHAR));
468 if (!new_buf) return E_OUTOFMEMORY;
470 if (stream->unicode)
471 memcpy(new_buf + stream->read_buf_size, buf, len * sizeof(WCHAR));
472 else
473 MultiByteToWideChar(CP_ACP, 0, buf, buf_size, new_buf + stream->read_buf_size, len);
474 stream->read_buf = new_buf;
475 stream->read_buf_size += len;
476 return S_OK;
479 static HRESULT read_more_data(struct textstream *stream)
481 char buf[256];
482 DWORD read;
484 if (stream->eof) return S_OK;
486 if (!ReadFile(stream->file, buf, sizeof(buf), &read, NULL))
488 ITextStream_Release(&stream->ITextStream_iface);
489 return create_error(GetLastError());
492 stream->eof = read != sizeof(buf);
493 return append_read_data(stream, buf, read);
496 static BOOL read_from_buffer(struct textstream *stream, size_t len, BSTR *ret, size_t skip)
498 assert(len + skip <= stream->read_buf_size);
500 if (!(*ret = SysAllocStringLen(stream->read_buf, len))) return FALSE;
502 len += skip;
503 stream->read_buf_size -= len;
504 if (stream->read_buf_size)
505 memmove(stream->read_buf, stream->read_buf + len, stream->read_buf_size * sizeof(WCHAR));
506 else
507 free(stream->read_buf);
508 return TRUE;
511 static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
513 struct textstream *This = impl_from_ITextStream(iface);
514 HRESULT hr = S_OK;
516 TRACE("%p, %ld, %p.\n", iface, len, text);
518 if (!text)
519 return E_POINTER;
521 *text = NULL;
522 if (len <= 0)
523 return len == 0 ? S_OK : E_INVALIDARG;
525 if (textstream_check_iomode(This, IORead))
526 return CTL_E_BADFILEMODE;
528 while (!This->eof && len > This->read_buf_size)
530 if (FAILED(hr = read_more_data(This)))
531 return hr;
534 if (This->eof && !This->read_buf_size)
535 return CTL_E_ENDOFFILE;
537 if (len > This->read_buf_size)
539 len = This->read_buf_size;
540 hr = S_FALSE;
543 return read_from_buffer(This, len, text, 0) ? hr : E_OUTOFMEMORY;
546 static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
548 struct textstream *This = impl_from_ITextStream(iface);
549 unsigned int skip = 0;
550 const WCHAR *nl;
551 HRESULT hr = S_OK;
553 TRACE("(%p)->(%p)\n", This, text);
555 if (!text)
556 return E_POINTER;
558 *text = NULL;
559 if (textstream_check_iomode(This, IORead))
560 return CTL_E_BADFILEMODE;
562 while (!(nl = wmemchr(This->read_buf, '\n', This->read_buf_size)) && !This->eof)
564 if (FAILED(hr = read_more_data(This)))
565 return hr;
568 if (This->eof && !This->read_buf_size)
569 return CTL_E_ENDOFFILE;
571 if (!nl)
573 nl = This->read_buf + This->read_buf_size;
574 hr = S_FALSE;
576 else if (nl > This->read_buf && nl[-1] == '\r')
578 nl--;
579 skip = 2;
581 else skip = 1;
583 return read_from_buffer(This, nl - This->read_buf, text, skip) ? hr : E_OUTOFMEMORY;
586 static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
588 struct textstream *This = impl_from_ITextStream(iface);
589 HRESULT hr;
591 TRACE("(%p)->(%p)\n", This, text);
593 if (!text)
594 return E_POINTER;
596 *text = NULL;
597 if (textstream_check_iomode(This, IORead))
598 return CTL_E_BADFILEMODE;
600 while (!This->eof)
602 if (FAILED(hr = read_more_data(This)))
603 return hr;
606 if (This->eof && !This->read_buf_size)
607 return CTL_E_ENDOFFILE;
609 return read_from_buffer(This, This->read_buf_size, text, 0) ? S_FALSE : E_OUTOFMEMORY;
612 static HRESULT textstream_write(struct textstream *stream, BSTR text)
614 DWORD written = 0;
615 BOOL ret;
617 if (textstream_check_iomode(stream, IOWrite))
618 return CTL_E_BADFILEMODE;
620 if (stream->unicode) {
621 ret = WriteFile(stream->file, text, SysStringByteLen(text), &written, NULL);
622 return (ret && written == SysStringByteLen(text)) ? S_OK : create_error(GetLastError());
623 } else {
624 DWORD len = WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), NULL, 0, NULL, NULL);
625 char *buffA;
626 HRESULT hr;
628 buffA = malloc(len);
629 if (!buffA)
630 return E_OUTOFMEMORY;
632 WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), buffA, len, NULL, NULL);
633 ret = WriteFile(stream->file, buffA, len, &written, NULL);
634 hr = (ret && written == len) ? S_OK : create_error(GetLastError());
635 free(buffA);
636 return hr;
640 static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
642 struct textstream *stream = impl_from_ITextStream(iface);
644 TRACE("%p, %s.\n", iface, debugstr_w(text));
646 return textstream_write(stream, text);
649 static HRESULT textstream_writecrlf(struct textstream *stream)
651 static const WCHAR crlfW[] = {'\r','\n'};
652 static const char crlfA[] = {'\r','\n'};
653 DWORD written = 0, len;
654 const void *ptr;
655 BOOL ret;
657 if (stream->unicode) {
658 ptr = crlfW;
659 len = sizeof(crlfW);
661 else {
662 ptr = crlfA;
663 len = sizeof(crlfA);
666 ret = WriteFile(stream->file, ptr, len, &written, NULL);
667 return (ret && written == len) ? S_OK : create_error(GetLastError());
670 static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
672 struct textstream *stream = impl_from_ITextStream(iface);
673 HRESULT hr;
675 TRACE("%p, %s.\n", iface, debugstr_w(text));
677 hr = textstream_write(stream, text);
678 if (SUCCEEDED(hr))
679 hr = textstream_writecrlf(stream);
680 return hr;
683 static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
685 FIXME("%p, %ld stub\n", iface, lines);
687 return E_NOTIMPL;
690 static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
692 FIXME("%p, %ld stub\n", iface, count);
694 return E_NOTIMPL;
697 static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
699 struct textstream *This = impl_from_ITextStream(iface);
700 FIXME("(%p): stub\n", This);
701 return E_NOTIMPL;
704 static HRESULT WINAPI textstream_Close(ITextStream *iface)
706 struct textstream *stream = impl_from_ITextStream(iface);
707 HRESULT hr = S_OK;
709 TRACE("%p.\n", iface);
711 if (!CloseHandle(stream->file))
712 hr = S_FALSE;
714 stream->file = NULL;
716 return hr;
719 static const ITextStreamVtbl textstreamvtbl =
721 textstream_QueryInterface,
722 textstream_AddRef,
723 textstream_Release,
724 textstream_GetTypeInfoCount,
725 textstream_GetTypeInfo,
726 textstream_GetIDsOfNames,
727 textstream_Invoke,
728 textstream_get_Line,
729 textstream_get_Column,
730 textstream_get_AtEndOfStream,
731 textstream_get_AtEndOfLine,
732 textstream_Read,
733 textstream_ReadLine,
734 textstream_ReadAll,
735 textstream_Write,
736 textstream_WriteLine,
737 textstream_WriteBlankLines,
738 textstream_Skip,
739 textstream_SkipLine,
740 textstream_Close
743 static HRESULT WINAPI pipestream_get_Line(ITextStream *iface, LONG *line)
745 FIXME("%p, %p.\n", iface, line);
747 return E_NOTIMPL;
750 static HRESULT WINAPI pipestream_get_Column(ITextStream *iface, LONG *column)
752 FIXME("%p, %p.\n", iface, column);
754 return E_NOTIMPL;
757 static HRESULT WINAPI pipestream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
759 FIXME("%p, %p.\n", iface, eos);
761 return E_NOTIMPL;
764 static HRESULT WINAPI pipestream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
766 FIXME("%p, %p.\n", iface, eol);
768 return E_NOTIMPL;
771 static HRESULT WINAPI pipestream_Read(ITextStream *iface, LONG len, BSTR *text)
773 FIXME("%p, %ld, %p.\n", iface, len, text);
775 return E_NOTIMPL;
778 static HRESULT WINAPI pipestream_ReadLine(ITextStream *iface, BSTR *text)
780 FIXME("%p, %p.\n", iface, text);
782 return E_NOTIMPL;
785 static HRESULT WINAPI pipestream_ReadAll(ITextStream *iface, BSTR *text)
787 FIXME("%p, %p.\n", iface, text);
789 return E_NOTIMPL;
792 static HRESULT WINAPI pipestream_Write(ITextStream *iface, BSTR text)
794 struct textstream *stream = impl_from_ITextStream(iface);
796 TRACE("%p, %s.\n", iface, debugstr_w(text));
798 return textstream_write(stream, text);
801 static HRESULT WINAPI pipestream_WriteLine(ITextStream *iface, BSTR text)
803 FIXME("%p, %s.\n", iface, debugstr_w(text));
805 return E_NOTIMPL;
808 static HRESULT WINAPI pipestream_WriteBlankLines(ITextStream *iface, LONG lines)
810 FIXME("%p, %ld.\n", iface, lines);
812 return E_NOTIMPL;
815 static HRESULT WINAPI pipestream_Skip(ITextStream *iface, LONG count)
817 FIXME("%p, %ld.\n", iface, count);
819 return E_NOTIMPL;
822 static HRESULT WINAPI pipestream_SkipLine(ITextStream *iface)
824 FIXME("%p.\n", iface);
826 return E_NOTIMPL;
829 static const ITextStreamVtbl pipestreamvtbl =
831 textstream_QueryInterface,
832 textstream_AddRef,
833 textstream_Release,
834 textstream_GetTypeInfoCount,
835 textstream_GetTypeInfo,
836 textstream_GetIDsOfNames,
837 textstream_Invoke,
838 pipestream_get_Line,
839 pipestream_get_Column,
840 pipestream_get_AtEndOfStream,
841 pipestream_get_AtEndOfLine,
842 pipestream_Read,
843 pipestream_ReadLine,
844 pipestream_ReadAll,
845 pipestream_Write,
846 pipestream_WriteLine,
847 pipestream_WriteBlankLines,
848 pipestream_Skip,
849 pipestream_SkipLine,
850 textstream_Close
853 static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMode mode, Tristate format, ITextStream **ret)
855 static const unsigned short utf16bom = 0xfeff;
856 struct textstream *stream;
857 DWORD access = 0;
858 HRESULT hr;
860 /* map access mode */
861 switch (mode)
863 case ForReading:
864 access = GENERIC_READ;
865 break;
866 case ForWriting:
867 access = GENERIC_WRITE;
868 break;
869 case ForAppending:
870 access = GENERIC_READ | GENERIC_WRITE;
871 break;
872 default:
873 return E_INVALIDARG;
876 if (!(stream = calloc(1, sizeof(*stream))))
877 return E_OUTOFMEMORY;
879 stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
880 stream->ref = 1;
881 stream->mode = mode;
883 stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
884 if (stream->file == INVALID_HANDLE_VALUE)
886 HRESULT hr = create_error(GetLastError());
887 free(stream);
888 return hr;
891 if (mode == ForReading)
892 GetFileSizeEx(stream->file, &stream->size);
893 else
894 stream->size.QuadPart = 0;
896 if (mode == ForWriting)
898 stream->unicode = format == TristateTrue;
899 /* Write Unicode BOM */
900 if (stream->unicode && (disposition == CREATE_ALWAYS || disposition == CREATE_NEW || disposition == TRUNCATE_EXISTING)) {
901 DWORD written = 0;
902 BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL);
903 if (!ret || written != sizeof(utf16bom)) {
904 ITextStream_Release(&stream->ITextStream_iface);
905 return create_error(GetLastError());
909 else
911 DWORD read, buf_offset = 0;
912 BYTE buf[64];
914 if (format == TristateUseDefault || mode == ForReading)
916 if (!ReadFile(stream->file, buf, sizeof(buf), &read, NULL))
918 ITextStream_Release(&stream->ITextStream_iface);
919 return create_error(GetLastError());
923 if (format == TristateUseDefault)
924 stream->unicode = IsTextUnicode(buf, read, NULL);
925 else
926 stream->unicode = format != TristateFalse;
928 if (mode == ForReading)
930 if (stream->unicode && read >= 2 && buf[0] == 0xff && buf[1] == 0xfe)
931 buf_offset += 2; /* skip utf16 BOM */
933 hr = append_read_data(stream, (const char *)buf + buf_offset, read - buf_offset);
934 if (FAILED(hr))
936 ITextStream_Release(&stream->ITextStream_iface);
937 return hr;
940 stream->eof = read != sizeof(buf);
942 else
944 LONG filePosHigh = 0;
945 DWORD filePosLow = SetFilePointer(stream->file, 0, &filePosHigh, FILE_END);
946 if(stream->unicode && filePosHigh == 0 && filePosLow == 0) {
947 /* unicode ForAppending to an empty file, write BOM */
948 DWORD written = 0;
949 BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL);
950 if (!ret || written != sizeof(utf16bom)) {
951 ITextStream_Release(&stream->ITextStream_iface);
952 return create_error(GetLastError());
958 init_classinfo(&CLSID_TextStream, (IUnknown *)&stream->ITextStream_iface, &stream->classinfo);
959 *ret = &stream->ITextStream_iface;
960 return S_OK;
963 HRESULT WINAPI DoOpenPipeStream(HANDLE pipe, IOMode mode, ITextStream **ret)
965 struct textstream *stream;
967 TRACE("%p, %d, %p.\n", pipe, mode, ret);
969 if (!(stream = calloc(1, sizeof(*stream))))
970 return E_OUTOFMEMORY;
972 stream->ITextStream_iface.lpVtbl = &pipestreamvtbl;
973 stream->ref = 1;
974 stream->mode = mode;
975 stream->file = pipe;
977 init_classinfo(&CLSID_TextStream, (IUnknown *)&stream->ITextStream_iface, &stream->classinfo);
978 *ret = &stream->ITextStream_iface;
980 return S_OK;
983 static HRESULT WINAPI drive_QueryInterface(IDrive *iface, REFIID riid, void **obj)
985 struct drive *This = impl_from_IDrive(iface);
987 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
989 *obj = NULL;
991 if (IsEqualIID( riid, &IID_IDrive ) ||
992 IsEqualIID( riid, &IID_IDispatch ) ||
993 IsEqualIID( riid, &IID_IUnknown))
995 *obj = &This->IDrive_iface;
997 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
999 *obj = &This->classinfo.IProvideClassInfo_iface;
1001 else
1002 return E_NOINTERFACE;
1004 IUnknown_AddRef((IUnknown*)*obj);
1005 return S_OK;
1008 static ULONG WINAPI drive_AddRef(IDrive *iface)
1010 struct drive *drive = impl_from_IDrive(iface);
1011 ULONG ref = InterlockedIncrement(&drive->ref);
1013 TRACE("%p, refcount %ld.\n", iface, ref);
1015 return ref;
1018 static ULONG WINAPI drive_Release(IDrive *iface)
1020 struct drive *drive = impl_from_IDrive(iface);
1021 ULONG ref = InterlockedDecrement(&drive->ref);
1023 TRACE("%p, refcount %ld.\n", iface, ref);
1025 if (!ref)
1026 free(drive);
1028 return ref;
1031 static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo)
1033 struct drive *This = impl_from_IDrive(iface);
1034 TRACE("(%p)->(%p)\n", This, pctinfo);
1035 *pctinfo = 1;
1036 return S_OK;
1039 static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo,
1040 LCID lcid, ITypeInfo **ppTInfo)
1042 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
1044 return get_typeinfo(IDrive_tid, ppTInfo);
1047 static HRESULT WINAPI drive_GetIDsOfNames(IDrive *iface, REFIID riid,
1048 LPOLESTR *rgszNames, UINT cNames,
1049 LCID lcid, DISPID *rgDispId)
1051 ITypeInfo *typeinfo;
1052 HRESULT hr;
1054 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1056 hr = get_typeinfo(IDrive_tid, &typeinfo);
1057 if(SUCCEEDED(hr))
1059 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1060 ITypeInfo_Release(typeinfo);
1063 return hr;
1066 static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember,
1067 REFIID riid, LCID lcid, WORD wFlags,
1068 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1069 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1071 ITypeInfo *typeinfo;
1072 HRESULT hr;
1074 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
1075 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1077 hr = get_typeinfo(IDrive_tid, &typeinfo);
1078 if(SUCCEEDED(hr))
1080 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1081 pDispParams, pVarResult, pExcepInfo, puArgErr);
1082 ITypeInfo_Release(typeinfo);
1085 return hr;
1088 static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path)
1090 struct drive *This = impl_from_IDrive(iface);
1091 FIXME("(%p)->(%p): stub\n", This, path);
1092 return E_NOTIMPL;
1095 static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter)
1097 struct drive *This = impl_from_IDrive(iface);
1099 TRACE("(%p)->(%p)\n", This, letter);
1101 if (!letter)
1102 return E_POINTER;
1104 *letter = SysAllocStringLen(This->root, 1);
1105 if (!*letter)
1106 return E_OUTOFMEMORY;
1108 return S_OK;
1111 static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name)
1113 struct drive *This = impl_from_IDrive(iface);
1114 FIXME("(%p)->(%p): stub\n", This, share_name);
1115 return E_NOTIMPL;
1118 static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type)
1120 struct drive *This = impl_from_IDrive(iface);
1122 TRACE("(%p)->(%p)\n", This, type);
1124 switch (GetDriveTypeW(This->root))
1126 case DRIVE_REMOVABLE:
1127 *type = Removable;
1128 break;
1129 case DRIVE_FIXED:
1130 *type = Fixed;
1131 break;
1132 case DRIVE_REMOTE:
1133 *type = Remote;
1134 break;
1135 case DRIVE_CDROM:
1136 *type = CDRom;
1137 break;
1138 case DRIVE_RAMDISK:
1139 *type = RamDisk;
1140 break;
1141 default:
1142 *type = UnknownType;
1143 break;
1146 return S_OK;
1149 static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder)
1151 struct drive *This = impl_from_IDrive(iface);
1152 FIXME("(%p)->(%p): stub\n", This, folder);
1153 return E_NOTIMPL;
1156 static HRESULT variant_from_largeint(const ULARGE_INTEGER *src, VARIANT *v)
1158 HRESULT hr = S_OK;
1160 if (src->u.HighPart || src->u.LowPart > INT_MAX)
1162 V_VT(v) = VT_R8;
1163 hr = VarR8FromUI8(src->QuadPart, &V_R8(v));
1165 else
1167 V_VT(v) = VT_I4;
1168 V_I4(v) = src->u.LowPart;
1171 return hr;
1174 static HRESULT WINAPI drive_get_AvailableSpace(IDrive *iface, VARIANT *v)
1176 struct drive *This = impl_from_IDrive(iface);
1177 ULARGE_INTEGER avail;
1179 TRACE("(%p)->(%p)\n", This, v);
1181 if (!v)
1182 return E_POINTER;
1184 if (!GetDiskFreeSpaceExW(This->root, &avail, NULL, NULL))
1185 return E_FAIL;
1187 return variant_from_largeint(&avail, v);
1190 static HRESULT WINAPI drive_get_FreeSpace(IDrive *iface, VARIANT *v)
1192 struct drive *This = impl_from_IDrive(iface);
1193 ULARGE_INTEGER freespace;
1195 TRACE("(%p)->(%p)\n", This, v);
1197 if (!v)
1198 return E_POINTER;
1200 if (!GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL))
1201 return E_FAIL;
1203 return variant_from_largeint(&freespace, v);
1206 static HRESULT WINAPI drive_get_TotalSize(IDrive *iface, VARIANT *v)
1208 struct drive *This = impl_from_IDrive(iface);
1209 ULARGE_INTEGER total;
1211 TRACE("(%p)->(%p)\n", This, v);
1213 if (!v)
1214 return E_POINTER;
1216 if (!GetDiskFreeSpaceExW(This->root, NULL, &total, NULL))
1217 return E_FAIL;
1219 return variant_from_largeint(&total, v);
1222 static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name)
1224 struct drive *This = impl_from_IDrive(iface);
1225 WCHAR nameW[MAX_PATH+1];
1226 BOOL ret;
1228 TRACE("(%p)->(%p)\n", This, name);
1230 if (!name)
1231 return E_POINTER;
1233 *name = NULL;
1234 ret = GetVolumeInformationW(This->root, nameW, ARRAY_SIZE(nameW), NULL, NULL, NULL, NULL, 0);
1235 if (ret)
1236 *name = SysAllocString(nameW);
1237 return ret ? S_OK : E_FAIL;
1240 static HRESULT WINAPI drive_put_VolumeName(IDrive *iface, BSTR name)
1242 struct drive *This = impl_from_IDrive(iface);
1243 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
1244 return E_NOTIMPL;
1247 static HRESULT WINAPI drive_get_FileSystem(IDrive *iface, BSTR *fs)
1249 struct drive *This = impl_from_IDrive(iface);
1250 WCHAR nameW[MAX_PATH+1];
1251 BOOL ret;
1253 TRACE("(%p)->(%p)\n", This, fs);
1255 if (!fs)
1256 return E_POINTER;
1258 *fs = NULL;
1259 ret = GetVolumeInformationW(This->root, NULL, 0, NULL, NULL, NULL, nameW, ARRAY_SIZE(nameW));
1260 if (ret)
1261 *fs = SysAllocString(nameW);
1262 return ret ? S_OK : E_FAIL;
1265 static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial)
1267 struct drive *This = impl_from_IDrive(iface);
1268 BOOL ret;
1270 TRACE("(%p)->(%p)\n", This, serial);
1272 if (!serial)
1273 return E_POINTER;
1275 ret = GetVolumeInformationW(This->root, NULL, 0, (DWORD*)serial, NULL, NULL, NULL, 0);
1276 return ret ? S_OK : E_FAIL;
1279 static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
1281 struct drive *This = impl_from_IDrive(iface);
1282 ULARGE_INTEGER freespace;
1283 BOOL ret;
1285 TRACE("(%p)->(%p)\n", This, ready);
1287 if (!ready)
1288 return E_POINTER;
1290 ret = GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL);
1291 *ready = ret ? VARIANT_TRUE : VARIANT_FALSE;
1292 return S_OK;
1295 static const IDriveVtbl drivevtbl = {
1296 drive_QueryInterface,
1297 drive_AddRef,
1298 drive_Release,
1299 drive_GetTypeInfoCount,
1300 drive_GetTypeInfo,
1301 drive_GetIDsOfNames,
1302 drive_Invoke,
1303 drive_get_Path,
1304 drive_get_DriveLetter,
1305 drive_get_ShareName,
1306 drive_get_DriveType,
1307 drive_get_RootFolder,
1308 drive_get_AvailableSpace,
1309 drive_get_FreeSpace,
1310 drive_get_TotalSize,
1311 drive_get_VolumeName,
1312 drive_put_VolumeName,
1313 drive_get_FileSystem,
1314 drive_get_SerialNumber,
1315 drive_get_IsReady
1318 static HRESULT create_drive(WCHAR letter, IDrive **drive)
1320 struct drive *object;
1322 *drive = NULL;
1324 object = malloc(sizeof(*object));
1325 if (!object) return E_OUTOFMEMORY;
1327 object->IDrive_iface.lpVtbl = &drivevtbl;
1328 object->ref = 1;
1329 wcscpy(object->root, L"A:\\");
1330 *object->root = letter;
1332 init_classinfo(&CLSID_Drive, (IUnknown *)&object->IDrive_iface, &object->classinfo);
1333 *drive = &object->IDrive_iface;
1335 return S_OK;
1338 static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
1340 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1342 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1344 *obj = NULL;
1346 if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
1347 IsEqualIID( riid, &IID_IUnknown ))
1349 *obj = iface;
1350 IEnumVARIANT_AddRef(iface);
1352 else
1353 return E_NOINTERFACE;
1355 return S_OK;
1358 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
1360 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1361 ULONG ref = InterlockedIncrement(&This->ref);
1362 TRACE("%p, refcount %ld.\n", iface, ref);
1363 return ref;
1366 static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
1368 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1369 ULONG ref = InterlockedDecrement(&This->ref);
1371 TRACE("%p, refcount %ld.\n", iface, ref);
1373 if (!ref)
1375 IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
1376 FindClose(This->data.u.foldercoll.find);
1377 free(This);
1380 return ref;
1383 static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file)
1385 WCHAR pathW[MAX_PATH];
1386 int len;
1387 HANDLE handle;
1389 lstrcpyW(pathW, path);
1390 len = lstrlenW(pathW);
1391 if (len && pathW[len-1] != '\\') wcscat(pathW, L"\\");
1392 wcscat(pathW, L"*");
1393 handle = FindFirstFileW(pathW, data);
1394 if (handle == INVALID_HANDLE_VALUE) return 0;
1396 /* find first dir/file */
1397 while (1)
1399 if (file ? is_file_data(data) : is_dir_data(data))
1400 break;
1402 if (!FindNextFileW(handle, data))
1404 FindClose(handle);
1405 return 0;
1408 return handle;
1411 static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1413 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1414 HANDLE handle = This->data.u.foldercoll.find;
1415 WIN32_FIND_DATAW data;
1416 ULONG count = 0;
1418 TRACE("%p, %lu, %p, %p.\n", iface, celt, var, fetched);
1420 if (fetched)
1421 *fetched = 0;
1423 if (!celt) return S_OK;
1425 if (!handle)
1427 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1428 if (!handle) return S_FALSE;
1430 This->data.u.foldercoll.find = handle;
1432 else
1434 if (!FindNextFileW(handle, &data))
1435 return S_FALSE;
1440 if (is_dir_data(&data))
1442 IFolder *folder;
1443 HRESULT hr;
1444 BSTR str;
1446 str = get_full_path(This->data.u.foldercoll.coll->path, &data);
1447 hr = create_folder(str, &folder);
1448 SysFreeString(str);
1449 if (FAILED(hr)) return hr;
1451 V_VT(&var[count]) = VT_DISPATCH;
1452 V_DISPATCH(&var[count]) = (IDispatch*)folder;
1453 count++;
1455 if (count >= celt) break;
1457 } while (FindNextFileW(handle, &data));
1459 if (fetched)
1460 *fetched = count;
1462 return (count < celt) ? S_FALSE : S_OK;
1465 static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1467 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1468 HANDLE handle = This->data.u.foldercoll.find;
1469 WIN32_FIND_DATAW data;
1471 TRACE("%p, %lu.\n", iface, celt);
1473 if (!celt) return S_OK;
1475 if (!handle)
1477 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1478 if (!handle) return S_FALSE;
1480 This->data.u.foldercoll.find = handle;
1482 else
1484 if (!FindNextFileW(handle, &data))
1485 return S_FALSE;
1490 if (is_dir_data(&data))
1491 --celt;
1493 if (!celt) break;
1494 } while (FindNextFileW(handle, &data));
1496 return celt ? S_FALSE : S_OK;
1499 static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
1501 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1503 TRACE("(%p)\n", This);
1505 FindClose(This->data.u.foldercoll.find);
1506 This->data.u.foldercoll.find = NULL;
1508 return S_OK;
1511 static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1513 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1514 TRACE("(%p)->(%p)\n", This, pclone);
1515 return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
1518 static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
1519 enumvariant_QueryInterface,
1520 enumvariant_AddRef,
1521 foldercoll_enumvariant_Release,
1522 foldercoll_enumvariant_Next,
1523 foldercoll_enumvariant_Skip,
1524 foldercoll_enumvariant_Reset,
1525 foldercoll_enumvariant_Clone
1528 static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
1530 struct enumvariant *This;
1532 *newenum = NULL;
1534 This = malloc(sizeof(*This));
1535 if (!This) return E_OUTOFMEMORY;
1537 This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
1538 This->ref = 1;
1539 This->data.u.foldercoll.find = NULL;
1540 This->data.u.foldercoll.coll = collection;
1541 IFolderCollection_AddRef(&collection->IFolderCollection_iface);
1543 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1545 return S_OK;
1548 static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface)
1550 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1551 ULONG ref = InterlockedDecrement(&This->ref);
1553 TRACE("%p, refcount %ld.\n", iface, ref);
1555 if (!ref)
1557 IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
1558 FindClose(This->data.u.filecoll.find);
1559 free(This);
1562 return ref;
1565 static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1567 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1568 HANDLE handle = This->data.u.filecoll.find;
1569 WIN32_FIND_DATAW data;
1570 ULONG count = 0;
1572 TRACE("%p, %ld, %p, %p.\n", iface, celt, var, fetched);
1574 if (fetched)
1575 *fetched = 0;
1577 if (!celt) return S_OK;
1579 if (!handle)
1581 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1582 if (!handle) return S_FALSE;
1583 This->data.u.filecoll.find = handle;
1585 else if (!FindNextFileW(handle, &data))
1586 return S_FALSE;
1590 if (is_file_data(&data))
1592 IFile *file;
1593 HRESULT hr;
1594 BSTR str;
1596 str = get_full_path(This->data.u.filecoll.coll->path, &data);
1597 hr = create_file(str, &file);
1598 SysFreeString(str);
1599 if (FAILED(hr)) return hr;
1601 V_VT(&var[count]) = VT_DISPATCH;
1602 V_DISPATCH(&var[count]) = (IDispatch*)file;
1603 if (++count >= celt) break;
1605 } while (FindNextFileW(handle, &data));
1607 if (fetched)
1608 *fetched = count;
1610 return (count < celt) ? S_FALSE : S_OK;
1613 static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1615 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1616 HANDLE handle = This->data.u.filecoll.find;
1617 WIN32_FIND_DATAW data;
1619 TRACE("%p, %lu.\n", iface, celt);
1621 if (!celt) return S_OK;
1623 if (!handle)
1625 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1626 if (!handle) return S_FALSE;
1627 This->data.u.filecoll.find = handle;
1629 else if (!FindNextFileW(handle, &data))
1630 return S_FALSE;
1634 if (is_file_data(&data))
1635 --celt;
1636 } while (celt && FindNextFileW(handle, &data));
1638 return celt ? S_FALSE : S_OK;
1641 static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface)
1643 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1645 TRACE("(%p)\n", This);
1647 FindClose(This->data.u.filecoll.find);
1648 This->data.u.filecoll.find = NULL;
1650 return S_OK;
1653 static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1655 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1656 TRACE("(%p)->(%p)\n", This, pclone);
1657 return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
1660 static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
1661 enumvariant_QueryInterface,
1662 enumvariant_AddRef,
1663 filecoll_enumvariant_Release,
1664 filecoll_enumvariant_Next,
1665 filecoll_enumvariant_Skip,
1666 filecoll_enumvariant_Reset,
1667 filecoll_enumvariant_Clone
1670 static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum)
1672 struct enumvariant *This;
1674 *newenum = NULL;
1676 This = malloc(sizeof(*This));
1677 if (!This) return E_OUTOFMEMORY;
1679 This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
1680 This->ref = 1;
1681 This->data.u.filecoll.find = NULL;
1682 This->data.u.filecoll.coll = collection;
1683 IFileCollection_AddRef(&collection->IFileCollection_iface);
1685 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1687 return S_OK;
1690 static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface)
1692 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1693 ULONG ref = InterlockedDecrement(&This->ref);
1695 TRACE("%p, refcount %ld.\n", iface, ref);
1697 if (!ref)
1699 IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
1700 free(This);
1703 return ref;
1706 static HRESULT find_next_drive(struct enumvariant *penum)
1708 int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
1710 for (; i < 32; i++)
1711 if (penum->data.u.drivecoll.coll->drives & (1 << i))
1713 penum->data.u.drivecoll.cur = i;
1714 return S_OK;
1717 return S_FALSE;
1720 static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1722 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1723 ULONG count = 0;
1725 TRACE("%p, %lu, %p, %p.\n", iface, celt, var, fetched);
1727 if (fetched)
1728 *fetched = 0;
1730 if (!celt) return S_OK;
1732 while (find_next_drive(This) == S_OK)
1734 IDrive *drive;
1735 HRESULT hr;
1737 hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
1738 if (FAILED(hr)) return hr;
1740 V_VT(&var[count]) = VT_DISPATCH;
1741 V_DISPATCH(&var[count]) = (IDispatch*)drive;
1743 if (++count >= celt) break;
1746 if (fetched)
1747 *fetched = count;
1749 return (count < celt) ? S_FALSE : S_OK;
1752 static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1754 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1756 TRACE("%p, %lu.\n", iface, celt);
1758 if (!celt) return S_OK;
1760 while (celt && find_next_drive(This) == S_OK)
1761 celt--;
1763 return celt ? S_FALSE : S_OK;
1766 static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface)
1768 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1770 TRACE("(%p)\n", This);
1772 This->data.u.drivecoll.cur = -1;
1773 return S_OK;
1776 static HRESULT WINAPI drivecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1778 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1779 TRACE("(%p)->(%p)\n", This, pclone);
1780 return create_drivecoll_enum(This->data.u.drivecoll.coll, (IUnknown**)pclone);
1783 static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
1784 enumvariant_QueryInterface,
1785 enumvariant_AddRef,
1786 drivecoll_enumvariant_Release,
1787 drivecoll_enumvariant_Next,
1788 drivecoll_enumvariant_Skip,
1789 drivecoll_enumvariant_Reset,
1790 drivecoll_enumvariant_Clone
1793 static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum)
1795 struct enumvariant *This;
1797 *newenum = NULL;
1799 This = malloc(sizeof(*This));
1800 if (!This) return E_OUTOFMEMORY;
1802 This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
1803 This->ref = 1;
1804 This->data.u.drivecoll.coll = collection;
1805 This->data.u.drivecoll.cur = -1;
1806 IDriveCollection_AddRef(&collection->IDriveCollection_iface);
1808 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1810 return S_OK;
1813 static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
1815 struct foldercollection *This = impl_from_IFolderCollection(iface);
1817 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1819 *obj = NULL;
1821 if (IsEqualIID( riid, &IID_IFolderCollection ) ||
1822 IsEqualIID( riid, &IID_IDispatch ) ||
1823 IsEqualIID( riid, &IID_IUnknown ))
1825 *obj = &This->IFolderCollection_iface;
1827 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
1829 *obj = &This->classinfo.IProvideClassInfo_iface;
1831 else
1832 return E_NOINTERFACE;
1834 IUnknown_AddRef((IUnknown*)*obj);
1835 return S_OK;
1838 static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
1840 struct foldercollection *collection = impl_from_IFolderCollection(iface);
1841 ULONG ref = InterlockedIncrement(&collection->ref);
1843 TRACE("%p, refcount %ld.\n", iface, ref);
1845 return ref;
1848 static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
1850 struct foldercollection *collection = impl_from_IFolderCollection(iface);
1851 ULONG ref = InterlockedDecrement(&collection->ref);
1853 TRACE("%p, refcount %ld.\n", iface, ref);
1855 if (!ref)
1857 SysFreeString(collection->path);
1858 free(collection);
1861 return ref;
1864 static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
1866 struct foldercollection *This = impl_from_IFolderCollection(iface);
1867 TRACE("(%p)->(%p)\n", This, pctinfo);
1868 *pctinfo = 1;
1869 return S_OK;
1872 static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
1873 LCID lcid, ITypeInfo **ppTInfo)
1875 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
1877 return get_typeinfo(IFolderCollection_tid, ppTInfo);
1880 static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
1881 LPOLESTR *rgszNames, UINT cNames,
1882 LCID lcid, DISPID *rgDispId)
1884 ITypeInfo *typeinfo;
1885 HRESULT hr;
1887 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1889 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1890 if(SUCCEEDED(hr))
1892 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1893 ITypeInfo_Release(typeinfo);
1896 return hr;
1899 static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
1900 REFIID riid, LCID lcid, WORD wFlags,
1901 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1902 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1904 ITypeInfo *typeinfo;
1905 HRESULT hr;
1907 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
1908 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1910 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1911 if(SUCCEEDED(hr))
1913 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1914 pDispParams, pVarResult, pExcepInfo, puArgErr);
1915 ITypeInfo_Release(typeinfo);
1918 return hr;
1921 static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
1923 struct foldercollection *This = impl_from_IFolderCollection(iface);
1924 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
1925 return E_NOTIMPL;
1928 static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
1930 struct foldercollection *This = impl_from_IFolderCollection(iface);
1931 FIXME("(%p)->(%p): stub\n", This, folder);
1932 return E_NOTIMPL;
1935 static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
1937 struct foldercollection *This = impl_from_IFolderCollection(iface);
1939 TRACE("(%p)->(%p)\n", This, newenum);
1941 if(!newenum)
1942 return E_POINTER;
1944 return create_foldercoll_enum(This, newenum);
1947 static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
1949 struct foldercollection *This = impl_from_IFolderCollection(iface);
1950 WIN32_FIND_DATAW data;
1951 WCHAR pathW[MAX_PATH];
1952 HANDLE handle;
1954 TRACE("(%p)->(%p)\n", This, count);
1956 if(!count)
1957 return E_POINTER;
1959 *count = 0;
1961 wcscpy(pathW, This->path);
1962 wcscat(pathW, L"\\*");
1963 handle = FindFirstFileW(pathW, &data);
1964 if (handle == INVALID_HANDLE_VALUE)
1965 return HRESULT_FROM_WIN32(GetLastError());
1969 if (is_dir_data(&data))
1970 *count += 1;
1971 } while (FindNextFileW(handle, &data));
1972 FindClose(handle);
1974 return S_OK;
1977 static const IFolderCollectionVtbl foldercollvtbl = {
1978 foldercoll_QueryInterface,
1979 foldercoll_AddRef,
1980 foldercoll_Release,
1981 foldercoll_GetTypeInfoCount,
1982 foldercoll_GetTypeInfo,
1983 foldercoll_GetIDsOfNames,
1984 foldercoll_Invoke,
1985 foldercoll_Add,
1986 foldercoll_get_Item,
1987 foldercoll_get__NewEnum,
1988 foldercoll_get_Count
1991 static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
1993 struct foldercollection *This;
1995 *folders = NULL;
1997 This = malloc(sizeof(*This));
1998 if (!This) return E_OUTOFMEMORY;
2000 This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
2001 This->ref = 1;
2002 This->path = SysAllocString(path);
2003 if (!This->path)
2005 free(This);
2006 return E_OUTOFMEMORY;
2009 init_classinfo(&CLSID_Folders, (IUnknown *)&This->IFolderCollection_iface, &This->classinfo);
2010 *folders = &This->IFolderCollection_iface;
2012 return S_OK;
2015 static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj)
2017 struct filecollection *This = impl_from_IFileCollection(iface);
2019 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2021 *obj = NULL;
2023 if (IsEqualIID( riid, &IID_IFileCollection ) ||
2024 IsEqualIID( riid, &IID_IDispatch ) ||
2025 IsEqualIID( riid, &IID_IUnknown ))
2027 *obj = &This->IFileCollection_iface;
2029 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2031 *obj = &This->classinfo.IProvideClassInfo_iface;
2033 else
2034 return E_NOINTERFACE;
2036 IUnknown_AddRef((IUnknown*)*obj);
2037 return S_OK;
2040 static ULONG WINAPI filecoll_AddRef(IFileCollection *iface)
2042 struct filecollection *collection = impl_from_IFileCollection(iface);
2043 ULONG ref = InterlockedIncrement(&collection->ref);
2045 TRACE("%p, refcount %ld.\n", iface, ref);
2047 return ref;
2050 static ULONG WINAPI filecoll_Release(IFileCollection *iface)
2052 struct filecollection *collection = impl_from_IFileCollection(iface);
2053 ULONG ref = InterlockedDecrement(&collection->ref);
2055 TRACE("%p, refcount %ld.\n", iface, ref);
2057 if (!ref)
2059 SysFreeString(collection->path);
2060 free(collection);
2063 return ref;
2066 static HRESULT WINAPI filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo)
2068 struct filecollection *This = impl_from_IFileCollection(iface);
2069 TRACE("(%p)->(%p)\n", This, pctinfo);
2070 *pctinfo = 1;
2071 return S_OK;
2074 static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo,
2075 LCID lcid, ITypeInfo **ppTInfo)
2077 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
2079 return get_typeinfo(IFileCollection_tid, ppTInfo);
2082 static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid,
2083 LPOLESTR *rgszNames, UINT cNames,
2084 LCID lcid, DISPID *rgDispId)
2086 ITypeInfo *typeinfo;
2087 HRESULT hr;
2089 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2091 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
2092 if(SUCCEEDED(hr))
2094 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2095 ITypeInfo_Release(typeinfo);
2098 return hr;
2101 static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember,
2102 REFIID riid, LCID lcid, WORD wFlags,
2103 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2104 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2106 ITypeInfo *typeinfo;
2107 HRESULT hr;
2109 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
2110 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2112 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
2113 if(SUCCEEDED(hr))
2115 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2116 pDispParams, pVarResult, pExcepInfo, puArgErr);
2117 ITypeInfo_Release(typeinfo);
2120 return hr;
2123 static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file)
2125 struct filecollection *This = impl_from_IFileCollection(iface);
2126 FIXME("(%p)->(%p)\n", This, file);
2127 return E_NOTIMPL;
2130 static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum)
2132 struct filecollection *This = impl_from_IFileCollection(iface);
2134 TRACE("(%p)->(%p)\n", This, ppenum);
2136 if(!ppenum)
2137 return E_POINTER;
2139 return create_filecoll_enum(This, ppenum);
2142 static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count)
2144 struct filecollection *This = impl_from_IFileCollection(iface);
2145 WIN32_FIND_DATAW data;
2146 WCHAR pathW[MAX_PATH];
2147 HANDLE handle;
2149 TRACE("(%p)->(%p)\n", This, count);
2151 if(!count)
2152 return E_POINTER;
2154 *count = 0;
2156 wcscpy(pathW, This->path);
2157 wcscat(pathW, L"\\*");
2158 handle = FindFirstFileW(pathW, &data);
2159 if (handle == INVALID_HANDLE_VALUE)
2160 return HRESULT_FROM_WIN32(GetLastError());
2164 if (is_file_data(&data))
2165 *count += 1;
2166 } while (FindNextFileW(handle, &data));
2167 FindClose(handle);
2169 return S_OK;
2172 static const IFileCollectionVtbl filecollectionvtbl = {
2173 filecoll_QueryInterface,
2174 filecoll_AddRef,
2175 filecoll_Release,
2176 filecoll_GetTypeInfoCount,
2177 filecoll_GetTypeInfo,
2178 filecoll_GetIDsOfNames,
2179 filecoll_Invoke,
2180 filecoll_get_Item,
2181 filecoll_get__NewEnum,
2182 filecoll_get_Count
2185 static HRESULT create_filecoll(BSTR path, IFileCollection **files)
2187 struct filecollection *This;
2189 *files = NULL;
2191 This = malloc(sizeof(*This));
2192 if (!This) return E_OUTOFMEMORY;
2194 This->IFileCollection_iface.lpVtbl = &filecollectionvtbl;
2195 This->ref = 1;
2196 This->path = SysAllocString(path);
2197 if (!This->path)
2199 free(This);
2200 return E_OUTOFMEMORY;
2203 init_classinfo(&CLSID_Files, (IUnknown *)&This->IFileCollection_iface, &This->classinfo);
2204 *files = &This->IFileCollection_iface;
2205 return S_OK;
2208 static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
2210 struct drivecollection *This = impl_from_IDriveCollection(iface);
2212 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2214 *obj = NULL;
2216 if (IsEqualIID( riid, &IID_IDriveCollection ) ||
2217 IsEqualIID( riid, &IID_IDispatch ) ||
2218 IsEqualIID( riid, &IID_IUnknown ))
2220 *obj = &This->IDriveCollection_iface;
2222 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2224 *obj = &This->classinfo.IProvideClassInfo_iface;
2226 else
2227 return E_NOINTERFACE;
2229 IUnknown_AddRef((IUnknown*)*obj);
2230 return S_OK;
2233 static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
2235 struct drivecollection *collection = impl_from_IDriveCollection(iface);
2236 ULONG ref = InterlockedIncrement(&collection->ref);
2238 TRACE("%p, refcount %ld.\n", iface, ref);
2240 return ref;
2243 static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
2245 struct drivecollection *collection = impl_from_IDriveCollection(iface);
2246 ULONG ref = InterlockedDecrement(&collection->ref);
2248 TRACE("%p, refcount %ld.\n", iface, ref);
2250 if (!ref)
2251 free(collection);
2253 return ref;
2256 static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
2258 struct drivecollection *This = impl_from_IDriveCollection(iface);
2259 TRACE("(%p)->(%p)\n", This, pctinfo);
2260 *pctinfo = 1;
2261 return S_OK;
2264 static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
2265 LCID lcid, ITypeInfo **ppTInfo)
2267 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
2269 return get_typeinfo(IDriveCollection_tid, ppTInfo);
2272 static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
2273 LPOLESTR *rgszNames, UINT cNames,
2274 LCID lcid, DISPID *rgDispId)
2276 ITypeInfo *typeinfo;
2277 HRESULT hr;
2279 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2281 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2282 if(SUCCEEDED(hr))
2284 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2285 ITypeInfo_Release(typeinfo);
2288 return hr;
2291 static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
2292 REFIID riid, LCID lcid, WORD wFlags,
2293 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2294 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2296 ITypeInfo *typeinfo;
2297 HRESULT hr;
2299 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
2300 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2302 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2303 if(SUCCEEDED(hr))
2305 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2306 pDispParams, pVarResult, pExcepInfo, puArgErr);
2307 ITypeInfo_Release(typeinfo);
2310 return hr;
2313 static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
2315 struct drivecollection *This = impl_from_IDriveCollection(iface);
2316 FIXME("(%p)->(%p): stub\n", This, drive);
2317 return E_NOTIMPL;
2320 static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
2322 struct drivecollection *This = impl_from_IDriveCollection(iface);
2324 TRACE("(%p)->(%p)\n", This, ppenum);
2326 if(!ppenum)
2327 return E_POINTER;
2329 return create_drivecoll_enum(This, ppenum);
2332 static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
2334 struct drivecollection *This = impl_from_IDriveCollection(iface);
2336 TRACE("(%p)->(%p)\n", This, count);
2338 if (!count) return E_POINTER;
2340 *count = This->count;
2341 return S_OK;
2344 static const IDriveCollectionVtbl drivecollectionvtbl = {
2345 drivecoll_QueryInterface,
2346 drivecoll_AddRef,
2347 drivecoll_Release,
2348 drivecoll_GetTypeInfoCount,
2349 drivecoll_GetTypeInfo,
2350 drivecoll_GetIDsOfNames,
2351 drivecoll_Invoke,
2352 drivecoll_get_Item,
2353 drivecoll_get__NewEnum,
2354 drivecoll_get_Count
2357 static HRESULT create_drivecoll(IDriveCollection **drives)
2359 struct drivecollection *This;
2360 DWORD mask;
2362 *drives = NULL;
2364 This = malloc(sizeof(*This));
2365 if (!This) return E_OUTOFMEMORY;
2367 This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl;
2368 This->ref = 1;
2369 This->drives = mask = GetLogicalDrives();
2370 /* count set bits */
2371 for (This->count = 0; mask; This->count++)
2372 mask &= mask - 1;
2374 init_classinfo(&CLSID_Drives, (IUnknown *)&This->IDriveCollection_iface, &This->classinfo);
2375 *drives = &This->IDriveCollection_iface;
2376 return S_OK;
2379 static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
2381 struct folder *This = impl_from_IFolder(iface);
2383 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2385 *obj = NULL;
2387 if (IsEqualIID( riid, &IID_IFolder ) ||
2388 IsEqualIID( riid, &IID_IDispatch ) ||
2389 IsEqualIID( riid, &IID_IUnknown))
2391 *obj = &This->IFolder_iface;
2393 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2395 *obj = &This->classinfo.IProvideClassInfo_iface;
2397 else
2398 return E_NOINTERFACE;
2400 IUnknown_AddRef((IUnknown*)*obj);
2401 return S_OK;
2404 static ULONG WINAPI folder_AddRef(IFolder *iface)
2406 struct folder *folder = impl_from_IFolder(iface);
2407 ULONG ref = InterlockedIncrement(&folder->ref);
2409 TRACE("%p, refcount %ld.\n", iface, ref);
2411 return ref;
2414 static ULONG WINAPI folder_Release(IFolder *iface)
2416 struct folder *folder = impl_from_IFolder(iface);
2417 ULONG ref = InterlockedDecrement(&folder->ref);
2419 TRACE("%p, refcount %ld.\n", iface, ref);
2421 if (!ref)
2423 SysFreeString(folder->path);
2424 free(folder);
2427 return ref;
2430 static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
2432 struct folder *This = impl_from_IFolder(iface);
2433 TRACE("(%p)->(%p)\n", This, pctinfo);
2434 *pctinfo = 1;
2435 return S_OK;
2438 static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
2439 LCID lcid, ITypeInfo **ppTInfo)
2441 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
2443 return get_typeinfo(IFolder_tid, ppTInfo);
2446 static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
2447 LPOLESTR *rgszNames, UINT cNames,
2448 LCID lcid, DISPID *rgDispId)
2450 ITypeInfo *typeinfo;
2451 HRESULT hr;
2453 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2455 hr = get_typeinfo(IFolder_tid, &typeinfo);
2456 if(SUCCEEDED(hr))
2458 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2459 ITypeInfo_Release(typeinfo);
2462 return hr;
2465 static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
2466 REFIID riid, LCID lcid, WORD wFlags,
2467 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2468 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2470 ITypeInfo *typeinfo;
2471 HRESULT hr;
2473 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
2474 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2476 hr = get_typeinfo(IFolder_tid, &typeinfo);
2477 if(SUCCEEDED(hr))
2479 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2480 pDispParams, pVarResult, pExcepInfo, puArgErr);
2481 ITypeInfo_Release(typeinfo);
2484 return hr;
2487 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
2489 struct folder *This = impl_from_IFolder(iface);
2491 TRACE("(%p)->(%p)\n", This, path);
2493 if(!path)
2494 return E_POINTER;
2496 *path = SysAllocString(This->path);
2497 return *path ? S_OK : E_OUTOFMEMORY;
2500 static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
2502 struct folder *This = impl_from_IFolder(iface);
2503 WCHAR *ptr;
2505 TRACE("(%p)->(%p)\n", This, name);
2507 if(!name)
2508 return E_POINTER;
2510 *name = NULL;
2512 ptr = wcsrchr(This->path, '\\');
2513 if (ptr)
2515 *name = SysAllocString(ptr+1);
2516 TRACE("%s\n", debugstr_w(*name));
2517 if (!*name) return E_OUTOFMEMORY;
2519 else
2520 return E_FAIL;
2522 return S_OK;
2525 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
2527 struct folder *This = impl_from_IFolder(iface);
2528 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
2529 return E_NOTIMPL;
2532 static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
2534 struct folder *This = impl_from_IFolder(iface);
2535 FIXME("(%p)->(%p): stub\n", This, path);
2536 return E_NOTIMPL;
2539 static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
2541 struct folder *This = impl_from_IFolder(iface);
2542 FIXME("(%p)->(%p): stub\n", This, name);
2543 return E_NOTIMPL;
2546 static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
2548 struct folder *This = impl_from_IFolder(iface);
2549 FIXME("(%p)->(%p): stub\n", This, drive);
2550 return E_NOTIMPL;
2553 static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
2555 struct folder *This = impl_from_IFolder(iface);
2556 FIXME("(%p)->(%p): stub\n", This, parent);
2557 return E_NOTIMPL;
2560 static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
2562 struct folder *This = impl_from_IFolder(iface);
2563 FIXME("(%p)->(%p): stub\n", This, attr);
2564 return E_NOTIMPL;
2567 static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
2569 struct folder *This = impl_from_IFolder(iface);
2570 FIXME("(%p)->(0x%x): stub\n", This, attr);
2571 return E_NOTIMPL;
2574 static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
2576 struct folder *This = impl_from_IFolder(iface);
2577 FIXME("(%p)->(%p): stub\n", This, date);
2578 return E_NOTIMPL;
2581 static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
2583 struct folder *This = impl_from_IFolder(iface);
2584 FIXME("(%p)->(%p): stub\n", This, date);
2585 return E_NOTIMPL;
2588 static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
2590 struct folder *This = impl_from_IFolder(iface);
2591 FIXME("(%p)->(%p): stub\n", This, date);
2592 return E_NOTIMPL;
2595 static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
2597 struct folder *This = impl_from_IFolder(iface);
2598 FIXME("(%p)->(%p): stub\n", This, type);
2599 return E_NOTIMPL;
2602 static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
2604 struct folder *This = impl_from_IFolder(iface);
2605 FIXME("(%p)->(%x): stub\n", This, force);
2606 return E_NOTIMPL;
2609 static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
2611 struct folder *This = impl_from_IFolder(iface);
2612 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
2613 return E_NOTIMPL;
2616 static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
2618 struct folder *This = impl_from_IFolder(iface);
2619 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
2620 return E_NOTIMPL;
2623 static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
2625 struct folder *This = impl_from_IFolder(iface);
2626 FIXME("(%p)->(%p): stub\n", This, isroot);
2627 return E_NOTIMPL;
2630 static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
2632 struct folder *This = impl_from_IFolder(iface);
2633 FIXME("(%p)->(%p): stub\n", This, size);
2634 return E_NOTIMPL;
2637 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
2639 struct folder *This = impl_from_IFolder(iface);
2641 TRACE("(%p)->(%p)\n", This, folders);
2643 if(!folders)
2644 return E_POINTER;
2646 return create_foldercoll(This->path, folders);
2649 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
2651 struct folder *This = impl_from_IFolder(iface);
2653 TRACE("(%p)->(%p)\n", This, files);
2655 if(!files)
2656 return E_POINTER;
2658 return create_filecoll(This->path, files);
2661 static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
2662 VARIANT_BOOL unicode, ITextStream **stream)
2664 DWORD disposition;
2665 BSTR path;
2666 HRESULT hres;
2668 struct folder *This = impl_from_IFolder(iface);
2670 TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
2672 hres = build_path(This->path, filename, &path);
2673 if (FAILED(hres)) return hres;
2675 disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
2676 hres = create_textstream(path, disposition, ForWriting, unicode ? TristateTrue : TristateFalse, stream);
2677 SysFreeString(path);
2678 return hres;
2681 static const IFolderVtbl foldervtbl = {
2682 folder_QueryInterface,
2683 folder_AddRef,
2684 folder_Release,
2685 folder_GetTypeInfoCount,
2686 folder_GetTypeInfo,
2687 folder_GetIDsOfNames,
2688 folder_Invoke,
2689 folder_get_Path,
2690 folder_get_Name,
2691 folder_put_Name,
2692 folder_get_ShortPath,
2693 folder_get_ShortName,
2694 folder_get_Drive,
2695 folder_get_ParentFolder,
2696 folder_get_Attributes,
2697 folder_put_Attributes,
2698 folder_get_DateCreated,
2699 folder_get_DateLastModified,
2700 folder_get_DateLastAccessed,
2701 folder_get_Type,
2702 folder_Delete,
2703 folder_Copy,
2704 folder_Move,
2705 folder_get_IsRootFolder,
2706 folder_get_Size,
2707 folder_get_SubFolders,
2708 folder_get_Files,
2709 folder_CreateTextFile
2712 HRESULT create_folder(const WCHAR *path, IFolder **folder)
2714 struct folder *object;
2715 DWORD len;
2717 *folder = NULL;
2719 TRACE("%s\n", debugstr_w(path));
2721 if (!(object = malloc(sizeof(*object))))
2722 return E_OUTOFMEMORY;
2724 object->IFolder_iface.lpVtbl = &foldervtbl;
2725 object->ref = 1;
2727 len = GetFullPathNameW(path, 0, NULL, NULL);
2728 if (!len)
2730 free(object);
2731 return E_FAIL;
2734 object->path = SysAllocStringLen(NULL, len);
2735 if(!object->path)
2737 free(object);
2738 return E_OUTOFMEMORY;
2741 if (!GetFullPathNameW(path, len, object->path, NULL))
2743 SysFreeString(object->path);
2744 free(object);
2745 return E_FAIL;
2748 init_classinfo(&CLSID_Folder, (IUnknown *)&object->IFolder_iface, &object->classinfo);
2749 *folder = &object->IFolder_iface;
2751 return S_OK;
2754 static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
2756 struct file *This = impl_from_IFile(iface);
2758 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2760 *obj = NULL;
2762 if (IsEqualIID(riid, &IID_IFile) ||
2763 IsEqualIID(riid, &IID_IDispatch) ||
2764 IsEqualIID(riid, &IID_IUnknown))
2766 *obj = &This->IFile_iface;
2768 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2770 *obj = &This->classinfo.IProvideClassInfo_iface;
2772 else
2773 return E_NOINTERFACE;
2775 IUnknown_AddRef((IUnknown*)*obj);
2776 return S_OK;
2779 static ULONG WINAPI file_AddRef(IFile *iface)
2781 struct file *file = impl_from_IFile(iface);
2782 LONG ref = InterlockedIncrement(&file->ref);
2784 TRACE("%p, refcount %ld.\n", iface, ref);
2786 return ref;
2789 static ULONG WINAPI file_Release(IFile *iface)
2791 struct file *file = impl_from_IFile(iface);
2792 LONG ref = InterlockedDecrement(&file->ref);
2794 TRACE("%p, refcount %ld.\n", iface, ref);
2796 if (!ref)
2798 free(file->path);
2799 free(file);
2802 return ref;
2805 static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
2807 struct file *This = impl_from_IFile(iface);
2809 TRACE("(%p)->(%p)\n", This, pctinfo);
2811 *pctinfo = 1;
2812 return S_OK;
2815 static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
2816 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
2818 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
2820 return get_typeinfo(IFile_tid, ppTInfo);
2823 static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
2824 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2826 ITypeInfo *typeinfo;
2827 HRESULT hr;
2829 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid),
2830 rgszNames, cNames, lcid, rgDispId);
2832 hr = get_typeinfo(IFile_tid, &typeinfo);
2833 if(SUCCEEDED(hr)) {
2834 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2835 ITypeInfo_Release(typeinfo);
2837 return hr;
2840 static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
2841 DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2843 ITypeInfo *typeinfo;
2844 HRESULT hr;
2846 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
2847 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2849 hr = get_typeinfo(IFile_tid, &typeinfo);
2850 if(SUCCEEDED(hr))
2852 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2853 pDispParams, pVarResult, pExcepInfo, puArgErr);
2854 ITypeInfo_Release(typeinfo);
2856 return hr;
2859 static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *path)
2861 struct file *This = impl_from_IFile(iface);
2863 TRACE("(%p)->(%p)\n", This, path);
2865 if (!path)
2866 return E_POINTER;
2868 *path = SysAllocString(This->path);
2869 if (!*path)
2870 return E_OUTOFMEMORY;
2872 return S_OK;
2875 static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
2877 struct file *This = impl_from_IFile(iface);
2878 WCHAR *ptr;
2880 TRACE("(%p)->(%p)\n", This, name);
2882 if(!name)
2883 return E_POINTER;
2885 *name = NULL;
2887 ptr = wcsrchr(This->path, '\\');
2888 if (ptr)
2890 *name = SysAllocString(ptr+1);
2891 TRACE("%s\n", debugstr_w(*name));
2892 if (!*name) return E_OUTOFMEMORY;
2894 else
2895 return E_FAIL;
2897 return S_OK;
2900 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
2902 struct file *This = impl_from_IFile(iface);
2903 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
2904 return E_NOTIMPL;
2907 static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
2909 struct file *This = impl_from_IFile(iface);
2910 FIXME("(%p)->(%p)\n", This, pbstrPath);
2911 return E_NOTIMPL;
2914 static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
2916 struct file *This = impl_from_IFile(iface);
2917 FIXME("(%p)->(%p)\n", This, pbstrName);
2918 return E_NOTIMPL;
2921 static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
2923 struct file *This = impl_from_IFile(iface);
2924 FIXME("(%p)->(%p)\n", This, ppdrive);
2925 return E_NOTIMPL;
2928 static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
2930 struct file *This = impl_from_IFile(iface);
2931 FIXME("(%p)->(%p)\n", This, ppfolder);
2932 return E_NOTIMPL;
2935 static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
2937 struct file *This = impl_from_IFile(iface);
2938 DWORD fa;
2940 TRACE("(%p)->(%p)\n", This, pfa);
2942 if(!pfa)
2943 return E_POINTER;
2945 fa = GetFileAttributesW(This->path);
2946 if(fa == INVALID_FILE_ATTRIBUTES)
2947 return create_error(GetLastError());
2949 *pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2950 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
2951 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
2952 return S_OK;
2955 static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
2957 struct file *This = impl_from_IFile(iface);
2959 TRACE("(%p)->(%x)\n", This, pfa);
2961 return SetFileAttributesW(This->path, pfa) ? S_OK : create_error(GetLastError());
2964 static HRESULT get_date_from_filetime(const FILETIME *ft, DATE *date)
2966 FILETIME ftlocal;
2967 SYSTEMTIME st;
2969 if (!date)
2970 return E_POINTER;
2972 FileTimeToLocalFileTime(ft, &ftlocal);
2973 FileTimeToSystemTime(&ftlocal, &st);
2974 SystemTimeToVariantTime(&st, date);
2976 return S_OK;
2979 static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *date)
2981 struct file *This = impl_from_IFile(iface);
2982 WIN32_FILE_ATTRIBUTE_DATA attrs;
2984 TRACE("(%p)->(%p)\n", This, date);
2986 if (GetFileAttributesExW(This->path, GetFileExInfoStandard, &attrs))
2987 return get_date_from_filetime(&attrs.ftCreationTime, date);
2989 return E_FAIL;
2992 static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *date)
2994 struct file *This = impl_from_IFile(iface);
2995 WIN32_FILE_ATTRIBUTE_DATA attrs;
2997 TRACE("(%p)->(%p)\n", This, date);
2999 if (GetFileAttributesExW(This->path, GetFileExInfoStandard, &attrs))
3000 return get_date_from_filetime(&attrs.ftLastWriteTime, date);
3002 return E_FAIL;
3005 static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
3007 struct file *This = impl_from_IFile(iface);
3008 FIXME("(%p)->(%p)\n", This, pdate);
3009 return E_NOTIMPL;
3012 static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
3014 struct file *This = impl_from_IFile(iface);
3015 ULARGE_INTEGER size;
3016 WIN32_FIND_DATAW fd;
3017 HANDLE f;
3019 TRACE("(%p)->(%p)\n", This, pvarSize);
3021 if(!pvarSize)
3022 return E_POINTER;
3024 f = FindFirstFileW(This->path, &fd);
3025 if(f == INVALID_HANDLE_VALUE)
3026 return create_error(GetLastError());
3027 FindClose(f);
3029 size.u.LowPart = fd.nFileSizeLow;
3030 size.u.HighPart = fd.nFileSizeHigh;
3032 return variant_from_largeint(&size, pvarSize);
3035 static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
3037 struct file *This = impl_from_IFile(iface);
3038 FIXME("(%p)->(%p)\n", This, pbstrType);
3039 return E_NOTIMPL;
3042 static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
3044 struct file *This = impl_from_IFile(iface);
3045 FIXME("(%p)->(%x)\n", This, Force);
3046 return E_NOTIMPL;
3049 static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
3051 struct file *This = impl_from_IFile(iface);
3052 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
3053 return E_NOTIMPL;
3056 static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
3058 struct file *This = impl_from_IFile(iface);
3059 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
3060 return E_NOTIMPL;
3063 static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode mode, Tristate format, ITextStream **stream)
3065 struct file *This = impl_from_IFile(iface);
3067 TRACE("(%p)->(%d %d %p)\n", This, mode, format, stream);
3069 return create_textstream(This->path, OPEN_EXISTING, mode, format, stream);
3072 static const IFileVtbl file_vtbl = {
3073 file_QueryInterface,
3074 file_AddRef,
3075 file_Release,
3076 file_GetTypeInfoCount,
3077 file_GetTypeInfo,
3078 file_GetIDsOfNames,
3079 file_Invoke,
3080 file_get_Path,
3081 file_get_Name,
3082 file_put_Name,
3083 file_get_ShortPath,
3084 file_get_ShortName,
3085 file_get_Drive,
3086 file_get_ParentFolder,
3087 file_get_Attributes,
3088 file_put_Attributes,
3089 file_get_DateCreated,
3090 file_get_DateLastModified,
3091 file_get_DateLastAccessed,
3092 file_get_Size,
3093 file_get_Type,
3094 file_Delete,
3095 file_Copy,
3096 file_Move,
3097 file_OpenAsTextStream
3100 static HRESULT create_file(BSTR path, IFile **file)
3102 struct file *f;
3103 DWORD len, attrs;
3105 *file = NULL;
3107 f = malloc(sizeof(struct file));
3108 if(!f)
3109 return E_OUTOFMEMORY;
3111 f->IFile_iface.lpVtbl = &file_vtbl;
3112 f->ref = 1;
3114 len = GetFullPathNameW(path, 0, NULL, NULL);
3115 if (!len)
3117 free(f);
3118 return E_FAIL;
3121 f->path = malloc(len*sizeof(WCHAR));
3122 if(!f->path)
3124 free(f);
3125 return E_OUTOFMEMORY;
3128 if (!GetFullPathNameW(path, len, f->path, NULL))
3130 free(f->path);
3131 free(f);
3132 return E_FAIL;
3135 attrs = GetFileAttributesW(f->path);
3136 if (attrs == INVALID_FILE_ATTRIBUTES || (attrs & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)))
3138 free(f->path);
3139 free(f);
3140 return create_error(GetLastError());
3143 init_classinfo(&CLSID_File, (IUnknown *)&f->IFile_iface, &f->classinfo);
3144 *file = &f->IFile_iface;
3145 return S_OK;
3148 static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
3150 struct filesystem *This = impl_from_IFileSystem3(iface);
3152 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
3154 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
3155 IsEqualGUID( riid, &IID_IFileSystem ) ||
3156 IsEqualGUID( riid, &IID_IDispatch ) ||
3157 IsEqualGUID( riid, &IID_IUnknown ) )
3159 *ppvObject = &This->IFileSystem3_iface;
3161 else if (IsEqualGUID( riid, &IID_IProvideClassInfo ))
3163 *ppvObject = &This->classinfo.IProvideClassInfo_iface;
3165 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
3167 TRACE("Interface IDispatchEx not supported - returning NULL\n");
3168 *ppvObject = NULL;
3169 return E_NOINTERFACE;
3171 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
3173 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
3174 *ppvObject = NULL;
3175 return E_NOINTERFACE;
3177 else
3179 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
3180 return E_NOINTERFACE;
3183 IUnknown_AddRef((IUnknown*)*ppvObject);
3185 return S_OK;
3188 static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
3190 TRACE("%p\n", iface);
3192 return 2;
3195 static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
3197 TRACE("%p\n", iface);
3199 return 1;
3202 static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
3204 TRACE("(%p)->(%p)\n", iface, pctinfo);
3206 *pctinfo = 1;
3207 return S_OK;
3210 static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
3211 LCID lcid, ITypeInfo **ppTInfo)
3213 TRACE("%p, %u, %lx, %p.\n", iface, iTInfo, lcid, ppTInfo);
3215 return get_typeinfo(IFileSystem3_tid, ppTInfo);
3218 static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
3219 LPOLESTR *rgszNames, UINT cNames,
3220 LCID lcid, DISPID *rgDispId)
3222 ITypeInfo *typeinfo;
3223 HRESULT hr;
3225 TRACE("%p, %s, %p, %u, %lx, %p.\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
3227 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
3228 if(SUCCEEDED(hr))
3230 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
3231 ITypeInfo_Release(typeinfo);
3234 return hr;
3237 static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
3238 REFIID riid, LCID lcid, WORD wFlags,
3239 DISPPARAMS *pDispParams, VARIANT *pVarResult,
3240 EXCEPINFO *pExcepInfo, UINT *puArgErr)
3242 ITypeInfo *typeinfo;
3243 HRESULT hr;
3245 TRACE("%p, %ld, %s, %lx, %d, %p, %p, %p, %p.\n", iface, dispIdMember, debugstr_guid(riid),
3246 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
3248 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
3249 if(SUCCEEDED(hr))
3251 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
3252 pDispParams, pVarResult, pExcepInfo, puArgErr);
3253 ITypeInfo_Release(typeinfo);
3256 return hr;
3259 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
3261 TRACE("%p %p\n", iface, ppdrives);
3262 return create_drivecoll(ppdrives);
3265 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
3266 BSTR Name, BSTR *Result)
3268 TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
3270 if (!Result) return E_POINTER;
3272 return build_path(Path, Name, Result);
3275 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR path, BSTR *drive)
3277 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), drive);
3279 if (!drive)
3280 return E_POINTER;
3282 *drive = NULL;
3284 if (path && lstrlenW(path) > 1 && path[1] == ':')
3285 *drive = SysAllocStringLen(path, 2);
3287 return S_OK;
3290 static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
3292 int i;
3294 if(!path)
3295 return 0;
3297 for(i=len-1; i>=0; i--)
3298 if(path[i]!='/' && path[i]!='\\')
3299 break;
3301 for(; i>=0; i--)
3302 if(path[i]=='/' || path[i]=='\\')
3303 break;
3305 for(; i>=0; i--)
3306 if(path[i]!='/' && path[i]!='\\')
3307 break;
3309 if(i < 0)
3310 return 0;
3312 if(path[i]==':' && i==1)
3313 i++;
3314 return i+1;
3317 static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
3318 BSTR *pbstrResult)
3320 DWORD len;
3322 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3324 if(!pbstrResult)
3325 return E_POINTER;
3327 len = get_parent_folder_name(Path, SysStringLen(Path));
3328 if(!len) {
3329 *pbstrResult = NULL;
3330 return S_OK;
3333 *pbstrResult = SysAllocStringLen(Path, len);
3334 if(!*pbstrResult)
3335 return E_OUTOFMEMORY;
3336 return S_OK;
3339 static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
3340 BSTR *pbstrResult)
3342 int i, end;
3344 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3346 if(!pbstrResult)
3347 return E_POINTER;
3349 if(!Path) {
3350 *pbstrResult = NULL;
3351 return S_OK;
3354 for(end=lstrlenW(Path)-1; end>=0; end--)
3355 if(Path[end]!='/' && Path[end]!='\\')
3356 break;
3358 for(i=end; i>=0; i--)
3359 if(Path[i]=='/' || Path[i]=='\\')
3360 break;
3361 i++;
3363 if(i>end || (i==0 && end==1 && Path[1]==':')) {
3364 *pbstrResult = NULL;
3365 return S_OK;
3368 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3369 if(!*pbstrResult)
3370 return E_OUTOFMEMORY;
3371 return S_OK;
3374 static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
3375 BSTR *pbstrResult)
3377 int i, end;
3379 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3381 if(!pbstrResult)
3382 return E_POINTER;
3384 if(!Path) {
3385 *pbstrResult = NULL;
3386 return S_OK;
3389 for(end=lstrlenW(Path)-1; end>=0; end--)
3390 if(Path[end]!='/' && Path[end]!='\\')
3391 break;
3393 for(i=end; i>=0; i--) {
3394 if(Path[i]=='.' && Path[end+1]!='.')
3395 end = i-1;
3396 if(Path[i]=='/' || Path[i]=='\\')
3397 break;
3399 i++;
3401 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
3402 *pbstrResult = NULL;
3403 return S_OK;
3406 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3407 if(!*pbstrResult)
3408 return E_OUTOFMEMORY;
3409 return S_OK;
3412 static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR path,
3413 BSTR *ext)
3415 INT len;
3417 TRACE("%p %s %p\n", iface, debugstr_w(path), ext);
3419 *ext = NULL;
3420 len = SysStringLen(path);
3421 while (len) {
3422 if (path[len-1] == '.') {
3423 *ext = SysAllocString(&path[len]);
3424 if (!*ext)
3425 return E_OUTOFMEMORY;
3426 break;
3428 len--;
3431 return S_OK;
3434 static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR path, BSTR *pbstrResult)
3436 WCHAR buf[MAX_PATH], ch;
3437 DWORD i, beg, len, exp_len;
3438 WIN32_FIND_DATAW fdata;
3439 HANDLE fh;
3441 TRACE("%p, %s, %p.\n", iface, debugstr_w(path), pbstrResult);
3443 if(!pbstrResult)
3444 return E_POINTER;
3446 len = GetFullPathNameW(path ? path : L".", MAX_PATH, buf, NULL);
3447 if(!len)
3448 return E_FAIL;
3450 buf[0] = towupper(buf[0]);
3451 if(len>3 && buf[len-1] == '\\')
3452 buf[--len] = 0;
3454 for(beg=3, i=3; i<=len; i++) {
3455 if(buf[i]!='\\' && buf[i])
3456 continue;
3458 ch = buf[i];
3459 buf[i] = 0;
3460 fh = FindFirstFileW(buf, &fdata);
3461 if(fh == INVALID_HANDLE_VALUE)
3462 break;
3464 exp_len = lstrlenW(fdata.cFileName);
3465 if(exp_len == i-beg)
3466 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
3467 FindClose(fh);
3468 buf[i] = ch;
3469 beg = i+1;
3472 *pbstrResult = SysAllocString(buf);
3473 if(!*pbstrResult)
3474 return E_OUTOFMEMORY;
3475 return S_OK;
3478 static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *result)
3480 DWORD random;
3482 TRACE("%p, %p.\n", iface, result);
3484 if (!result)
3485 return E_POINTER;
3487 if (!(*result = SysAllocStringLen(NULL, 12)))
3488 return E_OUTOFMEMORY;
3490 if(!RtlGenRandom(&random, sizeof(random)))
3492 SysFreeString(*result);
3493 return E_FAIL;
3496 swprintf(*result, 13, L"rad%05X.tmp", random & 0xfffff);
3497 return S_OK;
3500 static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
3501 VARIANT_BOOL *pfExists)
3503 UINT len;
3504 WCHAR driveletter;
3505 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
3507 if (!pfExists) return E_POINTER;
3509 *pfExists = VARIANT_FALSE;
3510 len = SysStringLen(DriveSpec);
3512 if (len >= 1) {
3513 driveletter = towupper(DriveSpec[0]);
3514 if (driveletter >= 'A' && driveletter <= 'Z'
3515 && (len < 2 || DriveSpec[1] == ':')
3516 && (len < 3 || DriveSpec[2] == '\\')) {
3517 const WCHAR root[] = {driveletter, ':', '\\', 0};
3518 UINT drivetype = GetDriveTypeW(root);
3519 *pfExists = drivetype != DRIVE_NO_ROOT_DIR && drivetype != DRIVE_UNKNOWN ? VARIANT_TRUE : VARIANT_FALSE;
3523 return S_OK;
3526 static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3528 DWORD attrs;
3529 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3531 if (!ret) return E_POINTER;
3533 attrs = GetFileAttributesW(path);
3534 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3535 return S_OK;
3538 static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3540 DWORD attrs;
3541 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3543 if (!ret) return E_POINTER;
3545 attrs = GetFileAttributesW(path);
3546 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3548 return S_OK;
3551 static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
3552 IDrive **ppdrive)
3554 UINT len;
3555 HRESULT hr;
3556 WCHAR driveletter;
3557 VARIANT_BOOL drive_exists;
3559 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
3561 if (!ppdrive)
3562 return E_POINTER;
3564 *ppdrive = NULL;
3566 /* DriveSpec may be one of: 'x', 'x:', 'x:\', '\\computer\share' */
3567 len = SysStringLen(DriveSpec);
3568 if (!len)
3569 return E_INVALIDARG;
3570 else if (len <= 3) {
3571 driveletter = towupper(DriveSpec[0]);
3572 if (driveletter < 'A' || driveletter > 'Z'
3573 || (len >= 2 && DriveSpec[1] != ':')
3574 || (len == 3 && DriveSpec[2] != '\\'))
3575 return E_INVALIDARG;
3576 hr = IFileSystem3_DriveExists(iface, DriveSpec, &drive_exists);
3577 if (FAILED(hr))
3578 return hr;
3579 if (drive_exists == VARIANT_FALSE)
3580 return CTL_E_DEVICEUNAVAILABLE;
3581 return create_drive(driveletter, ppdrive);
3582 } else {
3583 if (DriveSpec[0] != '\\' || DriveSpec[1] != '\\')
3584 return E_INVALIDARG;
3585 FIXME("%s not implemented yet\n", debugstr_w(DriveSpec));
3586 return E_NOTIMPL;
3590 static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
3591 IFile **ppfile)
3593 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
3595 if(!ppfile)
3596 return E_POINTER;
3597 if(!FilePath)
3598 return E_INVALIDARG;
3600 return create_file(FilePath, ppfile);
3603 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
3604 IFolder **folder)
3606 DWORD attrs;
3608 TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
3610 if(!folder)
3611 return E_POINTER;
3613 *folder = NULL;
3614 if(!FolderPath)
3615 return E_INVALIDARG;
3617 attrs = GetFileAttributesW(FolderPath);
3618 if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
3619 return CTL_E_PATHNOTFOUND;
3621 return create_folder(FolderPath, folder);
3624 static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
3625 SpecialFolderConst SpecialFolder,
3626 IFolder **folder)
3628 WCHAR pathW[MAX_PATH];
3629 DWORD ret;
3631 TRACE("%p %d %p\n", iface, SpecialFolder, folder);
3633 if (!folder)
3634 return E_POINTER;
3636 *folder = NULL;
3638 switch (SpecialFolder)
3640 case WindowsFolder:
3641 ret = GetWindowsDirectoryW(pathW, ARRAY_SIZE(pathW));
3642 break;
3643 case SystemFolder:
3644 ret = GetSystemDirectoryW(pathW, ARRAY_SIZE(pathW));
3645 break;
3646 case TemporaryFolder:
3647 ret = GetTempPathW(ARRAY_SIZE(pathW), pathW);
3648 /* we don't want trailing backslash */
3649 if (ret && pathW[ret-1] == '\\')
3650 pathW[ret-1] = 0;
3651 break;
3652 default:
3653 FIXME("unknown special folder type, %d\n", SpecialFolder);
3654 return E_INVALIDARG;
3657 if (!ret)
3658 return HRESULT_FROM_WIN32(GetLastError());
3660 return create_folder(pathW, folder);
3663 static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
3665 WCHAR path[MAX_PATH];
3666 DWORD len, name_len;
3667 WIN32_FIND_DATAW ffd;
3668 HANDLE f;
3670 f = FindFirstFileW(file, &ffd);
3671 if(f == INVALID_HANDLE_VALUE)
3672 return create_error(GetLastError());
3674 len = get_parent_folder_name(file, file_len);
3675 if(len+1 >= MAX_PATH) {
3676 FindClose(f);
3677 return E_FAIL;
3679 if(len) {
3680 memcpy(path, file, len*sizeof(WCHAR));
3681 path[len++] = '\\';
3684 do {
3685 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3686 continue;
3688 name_len = lstrlenW(ffd.cFileName);
3689 if(len+name_len+1 >= MAX_PATH) {
3690 FindClose(f);
3691 return E_FAIL;
3693 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3695 TRACE("deleting %s\n", debugstr_w(path));
3697 if(!DeleteFileW(path)) {
3698 if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
3699 || !DeleteFileW(path)) {
3700 FindClose(f);
3701 return create_error(GetLastError());
3704 } while(FindNextFileW(f, &ffd));
3705 FindClose(f);
3707 return S_OK;
3710 static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
3711 VARIANT_BOOL Force)
3713 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
3715 if(!FileSpec)
3716 return E_POINTER;
3718 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
3721 static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
3723 WCHAR path[MAX_PATH];
3724 DWORD len, name_len;
3725 WIN32_FIND_DATAW ffd;
3726 HANDLE f;
3727 HRESULT hr;
3729 f = FindFirstFileW(folder, &ffd);
3730 if(f == INVALID_HANDLE_VALUE)
3731 return create_error(GetLastError());
3733 len = get_parent_folder_name(folder, folder_len);
3734 if(len+1 >= MAX_PATH) {
3735 FindClose(f);
3736 return E_FAIL;
3738 if(len) {
3739 memcpy(path, folder, len*sizeof(WCHAR));
3740 path[len++] = '\\';
3743 do {
3744 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3745 continue;
3746 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3747 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3748 continue;
3750 name_len = lstrlenW(ffd.cFileName);
3751 if(len+name_len+3 >= MAX_PATH) {
3752 FindClose(f);
3753 return E_FAIL;
3755 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
3756 path[len+name_len] = '\\';
3757 path[len+name_len+1] = '*';
3758 path[len+name_len+2] = 0;
3760 hr = delete_file(path, len+name_len+2, force);
3761 if(FAILED(hr)) {
3762 FindClose(f);
3763 return hr;
3766 hr = delete_folder(path, len+name_len+2, force);
3767 if(FAILED(hr)) {
3768 FindClose(f);
3769 return hr;
3772 path[len+name_len] = 0;
3773 TRACE("deleting %s\n", debugstr_w(path));
3775 if(!RemoveDirectoryW(path)) {
3776 FindClose(f);
3777 return create_error(GetLastError());
3779 } while(FindNextFileW(f, &ffd));
3780 FindClose(f);
3782 return S_OK;
3785 static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
3786 VARIANT_BOOL Force)
3788 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
3790 if(!FolderSpec)
3791 return E_POINTER;
3793 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
3796 static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR source, BSTR destination)
3798 TRACE("%p %s %s\n", iface, debugstr_w(source), debugstr_w(destination));
3800 if(!source || !destination)
3801 return E_INVALIDARG;
3803 return MoveFileW(source, destination) ? S_OK : create_error(GetLastError());
3806 static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
3807 BSTR Destination)
3809 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3811 return E_NOTIMPL;
3814 static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
3815 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
3817 DWORD attrs;
3818 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
3819 DWORD src_len, dst_len, name_len;
3820 WIN32_FIND_DATAW ffd;
3821 HANDLE f;
3822 HRESULT hr;
3824 if(!source[0] || !destination[0])
3825 return E_INVALIDARG;
3827 attrs = GetFileAttributesW(destination);
3828 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
3829 attrs = GetFileAttributesW(source);
3830 if(attrs == INVALID_FILE_ATTRIBUTES)
3831 return create_error(GetLastError());
3832 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
3833 return CTL_E_FILENOTFOUND;
3835 if(!CopyFileW(source, destination, !overwrite))
3836 return create_error(GetLastError());
3837 return S_OK;
3840 f = FindFirstFileW(source, &ffd);
3841 if(f == INVALID_HANDLE_VALUE)
3842 return CTL_E_FILENOTFOUND;
3844 src_len = get_parent_folder_name(source, source_len);
3845 if(src_len+1 >= MAX_PATH) {
3846 FindClose(f);
3847 return E_FAIL;
3849 if(src_len) {
3850 memcpy(src_path, source, src_len*sizeof(WCHAR));
3851 src_path[src_len++] = '\\';
3854 dst_len = destination_len;
3855 if(dst_len+1 >= MAX_PATH) {
3856 FindClose(f);
3857 return E_FAIL;
3859 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
3860 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
3861 dst_path[dst_len++] = '\\';
3863 hr = CTL_E_FILENOTFOUND;
3864 do {
3865 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3866 continue;
3868 name_len = lstrlenW(ffd.cFileName);
3869 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
3870 FindClose(f);
3871 return E_FAIL;
3873 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3874 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3876 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
3878 if(!CopyFileW(src_path, dst_path, !overwrite)) {
3879 FindClose(f);
3880 return create_error(GetLastError());
3881 }else {
3882 hr = S_OK;
3884 } while(FindNextFileW(f, &ffd));
3885 FindClose(f);
3887 return hr;
3890 static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
3891 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3893 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3895 if(!Source || !Destination)
3896 return E_POINTER;
3898 return copy_file(Source, SysStringLen(Source), Destination,
3899 SysStringLen(Destination), OverWriteFiles);
3902 static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
3903 DWORD destination_len, VARIANT_BOOL overwrite)
3905 DWORD tmp, src_len, dst_len, name_len;
3906 WCHAR src[MAX_PATH], dst[MAX_PATH];
3907 WIN32_FIND_DATAW ffd;
3908 HANDLE f;
3909 HRESULT hr;
3910 BOOL copied = FALSE;
3912 if(!source[0] || !destination[0])
3913 return E_INVALIDARG;
3915 dst_len = destination_len;
3916 if(dst_len+1 >= MAX_PATH)
3917 return E_FAIL;
3918 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
3920 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
3921 (tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
3922 tmp&FILE_ATTRIBUTE_DIRECTORY) {
3923 if(!CreateDirectoryW(dst, NULL)) {
3924 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3925 tmp = GetFileAttributesW(dst);
3926 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
3927 return CTL_E_FILEALREADYEXISTS;
3928 }else {
3929 return create_error(GetLastError());
3932 copied = TRUE;
3934 src_len = source_len;
3935 if(src_len+2 >= MAX_PATH)
3936 return E_FAIL;
3937 memcpy(src, source, src_len*sizeof(WCHAR));
3938 src[src_len++] = '\\';
3939 src[src_len] = '*';
3940 src[src_len+1] = 0;
3942 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
3943 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
3944 return create_error(GetLastError());
3946 f = FindFirstFileW(src, &ffd);
3947 }else {
3948 src_len = get_parent_folder_name(source, source_len);
3949 if(src_len+2 >= MAX_PATH)
3950 return E_FAIL;
3951 memcpy(src, source, src_len*sizeof(WCHAR));
3952 if(src_len)
3953 src[src_len++] = '\\';
3955 f = FindFirstFileW(source, &ffd);
3957 if(f == INVALID_HANDLE_VALUE)
3958 return CTL_E_PATHNOTFOUND;
3960 dst[dst_len++] = '\\';
3961 dst[dst_len] = 0;
3963 do {
3964 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3965 continue;
3966 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3967 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3968 continue;
3970 name_len = lstrlenW(ffd.cFileName);
3971 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
3972 FindClose(f);
3973 return E_FAIL;
3975 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
3976 dst[dst_len+name_len] = 0;
3977 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
3978 src[src_len+name_len] = '\\';
3979 src[src_len+name_len+1] = '*';
3980 src[src_len+name_len+2] = 0;
3982 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
3984 if(!CreateDirectoryW(dst, NULL)) {
3985 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3986 tmp = GetFileAttributesW(dst);
3987 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
3988 FindClose(f);
3989 return CTL_E_FILEALREADYEXISTS;
3993 FindClose(f);
3994 return create_error(GetLastError());
3996 copied = TRUE;
3998 hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3999 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
4000 FindClose(f);
4001 return hr;
4004 hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
4005 if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
4006 FindClose(f);
4007 return hr;
4009 } while(FindNextFileW(f, &ffd));
4010 FindClose(f);
4012 return copied ? S_OK : CTL_E_PATHNOTFOUND;
4015 static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
4016 BSTR Destination, VARIANT_BOOL OverWriteFiles)
4018 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
4020 if(!Source || !Destination)
4021 return E_POINTER;
4023 return copy_folder(Source, SysStringLen(Source), Destination,
4024 SysStringLen(Destination), OverWriteFiles);
4027 static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
4028 IFolder **folder)
4030 BOOL ret;
4032 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
4034 ret = CreateDirectoryW(path, NULL);
4035 if (!ret)
4037 *folder = NULL;
4038 if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
4039 return HRESULT_FROM_WIN32(GetLastError());
4042 return create_folder(path, folder);
4045 static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR filename,
4046 VARIANT_BOOL overwrite, VARIANT_BOOL unicode,
4047 ITextStream **stream)
4049 DWORD disposition;
4051 TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
4053 disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
4054 return create_textstream(filename, disposition, ForWriting, unicode ? TristateTrue : TristateFalse, stream);
4057 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
4058 IOMode mode, VARIANT_BOOL create,
4059 Tristate format, ITextStream **stream)
4061 DWORD disposition;
4063 TRACE("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
4065 if(mode == ForWriting) {
4066 disposition = create == VARIANT_TRUE ? CREATE_ALWAYS : TRUNCATE_EXISTING;
4067 } else {
4068 disposition = create == VARIANT_TRUE ? OPEN_ALWAYS : OPEN_EXISTING;
4070 return create_textstream(filename, disposition, mode, format, stream);
4073 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
4074 StandardStreamTypes StandardStreamType,
4075 VARIANT_BOOL Unicode,
4076 ITextStream **ppts)
4078 FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
4080 return E_NOTIMPL;
4083 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
4085 DWORDLONG version;
4086 WORD a, b, c, d;
4088 version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
4089 a = (WORD)( version >> 48);
4090 b = (WORD)((version >> 32) & 0xffff);
4091 c = (WORD)((version >> 16) & 0xffff);
4092 d = (WORD)( version & 0xffff);
4094 swprintf(ver, 30, L"%d.%d.%d.%d", a, b, c, d);
4097 static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
4099 VS_FIXEDFILEINFO *info;
4100 WCHAR ver[30];
4101 void *ptr;
4102 DWORD len;
4103 BOOL ret;
4105 TRACE("%p %s %p\n", iface, debugstr_w(name), version);
4107 len = GetFileVersionInfoSizeW(name, NULL);
4108 if (!len)
4109 return HRESULT_FROM_WIN32(GetLastError());
4111 ptr = malloc(len);
4112 if (!GetFileVersionInfoW(name, 0, len, ptr))
4114 free(ptr);
4115 return HRESULT_FROM_WIN32(GetLastError());
4118 ret = VerQueryValueW(ptr, L"\\", (void **)&info, NULL);
4119 if (!ret)
4121 free(ptr);
4122 return HRESULT_FROM_WIN32(GetLastError());
4125 get_versionstring(info, ver);
4126 free(ptr);
4128 *version = SysAllocString(ver);
4129 TRACE("version=%s\n", debugstr_w(ver));
4131 return S_OK;
4134 static const struct IFileSystem3Vtbl filesys_vtbl =
4136 filesys_QueryInterface,
4137 filesys_AddRef,
4138 filesys_Release,
4139 filesys_GetTypeInfoCount,
4140 filesys_GetTypeInfo,
4141 filesys_GetIDsOfNames,
4142 filesys_Invoke,
4143 filesys_get_Drives,
4144 filesys_BuildPath,
4145 filesys_GetDriveName,
4146 filesys_GetParentFolderName,
4147 filesys_GetFileName,
4148 filesys_GetBaseName,
4149 filesys_GetExtensionName,
4150 filesys_GetAbsolutePathName,
4151 filesys_GetTempName,
4152 filesys_DriveExists,
4153 filesys_FileExists,
4154 filesys_FolderExists,
4155 filesys_GetDrive,
4156 filesys_GetFile,
4157 filesys_GetFolder,
4158 filesys_GetSpecialFolder,
4159 filesys_DeleteFile,
4160 filesys_DeleteFolder,
4161 filesys_MoveFile,
4162 filesys_MoveFolder,
4163 filesys_CopyFile,
4164 filesys_CopyFolder,
4165 filesys_CreateFolder,
4166 filesys_CreateTextFile,
4167 filesys_OpenTextFile,
4168 filesys_GetStandardStream,
4169 filesys_GetFileVersion
4172 static struct filesystem filesystem;
4174 HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
4176 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
4178 filesystem.IFileSystem3_iface.lpVtbl = &filesys_vtbl;
4179 init_classinfo(&CLSID_FileSystemObject, (IUnknown *)&filesystem.IFileSystem3_iface, &filesystem.classinfo);
4180 return IFileSystem3_QueryInterface(&filesystem.IFileSystem3_iface, riid, ppv);