wined3d: Enable the multi-threaded command stream by default.
[wine.git] / dlls / scrrun / filesystem.c
blob228a5e98a008cc759de7f4d8a2e4014299c4c269
1 /*
2 * Copyright 2012 Alistair Leslie-Hughes
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include "config.h"
22 #include <stdarg.h>
23 #include <limits.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "ole2.h"
28 #include "olectl.h"
29 #include "dispex.h"
30 #include "ntsecapi.h"
31 #include "scrrun.h"
32 #include "scrrun_private.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36 #include "wine/heap.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
40 static const WCHAR bsW[] = {'\\',0};
41 static const WCHAR utf16bom = 0xfeff;
43 struct filesystem {
44 struct provideclassinfo classinfo;
45 IFileSystem3 IFileSystem3_iface;
48 struct foldercollection {
49 struct provideclassinfo classinfo;
50 IFolderCollection IFolderCollection_iface;
51 LONG ref;
52 BSTR path;
55 struct filecollection {
56 struct provideclassinfo classinfo;
57 IFileCollection IFileCollection_iface;
58 LONG ref;
59 BSTR path;
62 struct drivecollection {
63 struct provideclassinfo classinfo;
64 IDriveCollection IDriveCollection_iface;
65 LONG ref;
66 DWORD drives;
67 LONG count;
70 struct enumdata {
71 union
73 struct
75 struct foldercollection *coll;
76 HANDLE find;
77 } foldercoll;
78 struct
80 struct filecollection *coll;
81 HANDLE find;
82 } filecoll;
83 struct
85 struct drivecollection *coll;
86 INT cur;
87 } drivecoll;
88 } u;
91 struct enumvariant {
92 IEnumVARIANT IEnumVARIANT_iface;
93 LONG ref;
95 struct enumdata data;
98 struct drive {
99 struct provideclassinfo classinfo;
100 IDrive IDrive_iface;
101 LONG ref;
102 BSTR root;
105 struct folder {
106 struct provideclassinfo classinfo;
107 IFolder IFolder_iface;
108 LONG ref;
109 BSTR path;
112 struct file {
113 struct provideclassinfo classinfo;
114 IFile IFile_iface;
115 LONG ref;
117 WCHAR *path;
120 struct textstream {
121 struct provideclassinfo classinfo;
122 ITextStream ITextStream_iface;
123 LONG ref;
125 IOMode mode;
126 BOOL unicode;
127 BOOL first_read;
128 LARGE_INTEGER size;
129 HANDLE file;
132 enum iotype {
133 IORead,
134 IOWrite
137 static inline struct filesystem *impl_from_IFileSystem3(IFileSystem3 *iface)
139 return CONTAINING_RECORD(iface, struct filesystem, IFileSystem3_iface);
142 static inline struct drive *impl_from_IDrive(IDrive *iface)
144 return CONTAINING_RECORD(iface, struct drive, IDrive_iface);
147 static inline struct folder *impl_from_IFolder(IFolder *iface)
149 return CONTAINING_RECORD(iface, struct folder, IFolder_iface);
152 static inline struct file *impl_from_IFile(IFile *iface)
154 return CONTAINING_RECORD(iface, struct file, IFile_iface);
157 static inline struct textstream *impl_from_ITextStream(ITextStream *iface)
159 return CONTAINING_RECORD(iface, struct textstream, ITextStream_iface);
162 static inline struct foldercollection *impl_from_IFolderCollection(IFolderCollection *iface)
164 return CONTAINING_RECORD(iface, struct foldercollection, IFolderCollection_iface);
167 static inline struct filecollection *impl_from_IFileCollection(IFileCollection *iface)
169 return CONTAINING_RECORD(iface, struct filecollection, IFileCollection_iface);
172 static inline struct drivecollection *impl_from_IDriveCollection(IDriveCollection *iface)
174 return CONTAINING_RECORD(iface, struct drivecollection, IDriveCollection_iface);
177 static inline struct enumvariant *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
179 return CONTAINING_RECORD(iface, struct enumvariant, IEnumVARIANT_iface);
182 static inline HRESULT create_error(DWORD err)
184 switch(err) {
185 case ERROR_FILE_NOT_FOUND: return CTL_E_FILENOTFOUND;
186 case ERROR_PATH_NOT_FOUND: return CTL_E_PATHNOTFOUND;
187 case ERROR_ACCESS_DENIED: return CTL_E_PERMISSIONDENIED;
188 case ERROR_FILE_EXISTS: return CTL_E_FILEALREADYEXISTS;
189 case ERROR_ALREADY_EXISTS: return CTL_E_FILEALREADYEXISTS;
190 default:
191 FIXME("Unsupported error code: %d\n", err);
192 return E_FAIL;
196 static HRESULT create_folder(const WCHAR*, IFolder**);
197 static HRESULT create_file(BSTR, IFile**);
198 static HRESULT create_foldercoll_enum(struct foldercollection*, IUnknown**);
199 static HRESULT create_filecoll_enum(struct filecollection*, IUnknown**);
201 static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data)
203 static const WCHAR dotdotW[] = {'.','.',0};
204 static const WCHAR dotW[] = {'.',0};
206 return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
207 strcmpW(data->cFileName, dotdotW) &&
208 strcmpW(data->cFileName, dotW);
211 static inline BOOL is_file_data(const WIN32_FIND_DATAW *data)
213 return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
216 static BSTR get_full_path(BSTR path, const WIN32_FIND_DATAW *data)
218 int len = SysStringLen(path);
219 WCHAR buffW[MAX_PATH];
221 strcpyW(buffW, path);
222 if (path[len-1] != '\\')
223 strcatW(buffW, bsW);
224 strcatW(buffW, data->cFileName);
226 return SysAllocString(buffW);
229 static BOOL textstream_check_iomode(struct textstream *This, enum iotype type)
231 if (type == IORead)
232 return This->mode == ForWriting || This->mode == ForAppending;
233 else
234 return This->mode == ForReading;
237 static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
239 struct textstream *This = impl_from_ITextStream(iface);
241 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
243 if (IsEqualIID(riid, &IID_ITextStream) ||
244 IsEqualIID(riid, &IID_IDispatch) ||
245 IsEqualIID(riid, &IID_IUnknown))
247 *obj = &This->ITextStream_iface;
249 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
251 *obj = &This->classinfo.IProvideClassInfo_iface;
253 else
254 return E_NOINTERFACE;
256 IUnknown_AddRef((IUnknown*)*obj);
257 return S_OK;
260 static ULONG WINAPI textstream_AddRef(ITextStream *iface)
262 struct textstream *This = impl_from_ITextStream(iface);
263 ULONG ref = InterlockedIncrement(&This->ref);
264 TRACE("(%p)->(%d)\n", This, ref);
265 return ref;
268 static ULONG WINAPI textstream_Release(ITextStream *iface)
270 struct textstream *This = impl_from_ITextStream(iface);
271 ULONG ref = InterlockedDecrement(&This->ref);
272 TRACE("(%p)->(%d)\n", This, ref);
274 if (!ref)
276 CloseHandle(This->file);
277 heap_free(This);
280 return ref;
283 static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
285 struct textstream *This = impl_from_ITextStream(iface);
286 TRACE("(%p)->(%p)\n", This, pctinfo);
287 *pctinfo = 1;
288 return S_OK;
291 static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
292 LCID lcid, ITypeInfo **ppTInfo)
294 struct textstream *This = impl_from_ITextStream(iface);
295 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
296 return get_typeinfo(ITextStream_tid, ppTInfo);
299 static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
300 LPOLESTR *rgszNames, UINT cNames,
301 LCID lcid, DISPID *rgDispId)
303 struct textstream *This = impl_from_ITextStream(iface);
304 ITypeInfo *typeinfo;
305 HRESULT hr;
307 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
309 hr = get_typeinfo(ITextStream_tid, &typeinfo);
310 if(SUCCEEDED(hr))
312 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
313 ITypeInfo_Release(typeinfo);
316 return hr;
319 static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
320 REFIID riid, LCID lcid, WORD wFlags,
321 DISPPARAMS *pDispParams, VARIANT *pVarResult,
322 EXCEPINFO *pExcepInfo, UINT *puArgErr)
324 struct textstream *This = impl_from_ITextStream(iface);
325 ITypeInfo *typeinfo;
326 HRESULT hr;
328 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
329 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
331 hr = get_typeinfo(ITextStream_tid, &typeinfo);
332 if(SUCCEEDED(hr))
334 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
335 pDispParams, pVarResult, pExcepInfo, puArgErr);
336 ITypeInfo_Release(typeinfo);
339 return hr;
342 static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
344 struct textstream *This = impl_from_ITextStream(iface);
345 FIXME("(%p)->(%p): stub\n", This, line);
346 return E_NOTIMPL;
349 static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
351 struct textstream *This = impl_from_ITextStream(iface);
352 FIXME("(%p)->(%p): stub\n", This, column);
353 return E_NOTIMPL;
356 static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
358 struct textstream *This = impl_from_ITextStream(iface);
359 LARGE_INTEGER pos, dist;
361 TRACE("(%p)->(%p)\n", This, eos);
363 if (!eos)
364 return E_POINTER;
366 if (textstream_check_iomode(This, IORead)) {
367 *eos = VARIANT_TRUE;
368 return CTL_E_BADFILEMODE;
371 dist.QuadPart = 0;
372 if (!SetFilePointerEx(This->file, dist, &pos, FILE_CURRENT))
373 return E_FAIL;
375 *eos = This->size.QuadPart == pos.QuadPart ? VARIANT_TRUE : VARIANT_FALSE;
376 return S_OK;
379 static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
381 struct textstream *This = impl_from_ITextStream(iface);
382 FIXME("(%p)->(%p): stub\n", This, eol);
383 return E_NOTIMPL;
387 Reads 'toread' bytes from a file, converts if needed
388 BOM is skipped if 'bof' is set.
390 static HRESULT textstream_read(struct textstream *stream, LONG toread, BOOL bof, BSTR *text)
392 HRESULT hr = S_OK;
393 DWORD read;
394 char *buff;
395 BOOL ret;
397 if (toread == 0) {
398 *text = SysAllocStringLen(NULL, 0);
399 return *text ? S_FALSE : E_OUTOFMEMORY;
402 if (toread < sizeof(WCHAR))
403 return CTL_E_ENDOFFILE;
405 buff = heap_alloc(toread);
406 if (!buff)
407 return E_OUTOFMEMORY;
409 ret = ReadFile(stream->file, buff, toread, &read, NULL);
410 if (!ret || toread != read) {
411 WARN("failed to read from file %d, %d, error %d\n", read, toread, GetLastError());
412 heap_free(buff);
413 return E_FAIL;
416 if (stream->unicode) {
417 int i = 0;
419 /* skip BOM */
420 if (bof && *(WCHAR*)buff == utf16bom) {
421 read -= sizeof(WCHAR);
422 i += sizeof(WCHAR);
425 *text = SysAllocStringLen(read ? (WCHAR*)&buff[i] : NULL, read/sizeof(WCHAR));
426 if (!*text) hr = E_OUTOFMEMORY;
428 else {
429 INT len = MultiByteToWideChar(CP_ACP, 0, buff, read, NULL, 0);
430 *text = SysAllocStringLen(NULL, len);
431 if (*text)
432 MultiByteToWideChar(CP_ACP, 0, buff, read, *text, len);
433 else
434 hr = E_OUTOFMEMORY;
436 heap_free(buff);
438 return hr;
441 static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
443 struct textstream *This = impl_from_ITextStream(iface);
444 LARGE_INTEGER start, end, dist;
445 DWORD toread;
446 HRESULT hr;
448 TRACE("(%p)->(%d %p)\n", This, len, text);
450 if (!text)
451 return E_POINTER;
453 *text = NULL;
454 if (len <= 0)
455 return len == 0 ? S_OK : E_INVALIDARG;
457 if (textstream_check_iomode(This, IORead))
458 return CTL_E_BADFILEMODE;
460 if (!This->first_read) {
461 VARIANT_BOOL eos;
463 /* check for EOF */
464 hr = ITextStream_get_AtEndOfStream(iface, &eos);
465 if (FAILED(hr))
466 return hr;
468 if (eos == VARIANT_TRUE)
469 return CTL_E_ENDOFFILE;
472 /* read everything from current position */
473 dist.QuadPart = 0;
474 SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
475 SetFilePointerEx(This->file, dist, &end, FILE_END);
476 toread = end.QuadPart - start.QuadPart;
477 /* rewind back */
478 dist.QuadPart = start.QuadPart;
479 SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
481 This->first_read = FALSE;
482 if (This->unicode) len *= sizeof(WCHAR);
484 hr = textstream_read(This, min(toread, len), start.QuadPart == 0, text);
485 if (FAILED(hr))
486 return hr;
487 else
488 return toread <= len ? S_FALSE : S_OK;
491 static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
493 struct textstream *This = impl_from_ITextStream(iface);
494 VARIANT_BOOL eos;
495 HRESULT hr;
497 FIXME("(%p)->(%p): stub\n", This, text);
499 if (!text)
500 return E_POINTER;
502 *text = NULL;
503 if (textstream_check_iomode(This, IORead))
504 return CTL_E_BADFILEMODE;
506 /* check for EOF */
507 hr = ITextStream_get_AtEndOfStream(iface, &eos);
508 if (FAILED(hr))
509 return hr;
511 if (eos == VARIANT_TRUE)
512 return CTL_E_ENDOFFILE;
514 return E_NOTIMPL;
517 static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
519 struct textstream *This = impl_from_ITextStream(iface);
520 LARGE_INTEGER start, end, dist;
521 DWORD toread;
522 HRESULT hr;
524 TRACE("(%p)->(%p)\n", This, text);
526 if (!text)
527 return E_POINTER;
529 *text = NULL;
530 if (textstream_check_iomode(This, IORead))
531 return CTL_E_BADFILEMODE;
533 if (!This->first_read) {
534 VARIANT_BOOL eos;
536 /* check for EOF */
537 hr = ITextStream_get_AtEndOfStream(iface, &eos);
538 if (FAILED(hr))
539 return hr;
541 if (eos == VARIANT_TRUE)
542 return CTL_E_ENDOFFILE;
545 /* read everything from current position */
546 dist.QuadPart = 0;
547 SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
548 SetFilePointerEx(This->file, dist, &end, FILE_END);
549 toread = end.QuadPart - start.QuadPart;
550 /* rewind back */
551 dist.QuadPart = start.QuadPart;
552 SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
554 This->first_read = FALSE;
556 hr = textstream_read(This, toread, start.QuadPart == 0, text);
557 return FAILED(hr) ? hr : S_FALSE;
560 static HRESULT textstream_writestr(struct textstream *stream, BSTR text)
562 DWORD written = 0;
563 BOOL ret;
565 if (stream->unicode) {
566 ret = WriteFile(stream->file, text, SysStringByteLen(text), &written, NULL);
567 return (ret && written == SysStringByteLen(text)) ? S_OK : create_error(GetLastError());
568 } else {
569 DWORD len = WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), NULL, 0, NULL, NULL);
570 char *buffA;
571 HRESULT hr;
573 buffA = heap_alloc(len);
574 if (!buffA)
575 return E_OUTOFMEMORY;
577 WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), buffA, len, NULL, NULL);
578 ret = WriteFile(stream->file, buffA, len, &written, NULL);
579 hr = (ret && written == len) ? S_OK : create_error(GetLastError());
580 heap_free(buffA);
581 return hr;
585 static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
587 struct textstream *This = impl_from_ITextStream(iface);
589 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
591 if (textstream_check_iomode(This, IOWrite))
592 return CTL_E_BADFILEMODE;
594 return textstream_writestr(This, text);
597 static HRESULT textstream_writecrlf(struct textstream *stream)
599 static const WCHAR crlfW[] = {'\r','\n'};
600 static const char crlfA[] = {'\r','\n'};
601 DWORD written = 0, len;
602 const void *ptr;
603 BOOL ret;
605 if (stream->unicode) {
606 ptr = crlfW;
607 len = sizeof(crlfW);
609 else {
610 ptr = crlfA;
611 len = sizeof(crlfA);
614 ret = WriteFile(stream->file, ptr, len, &written, NULL);
615 return (ret && written == len) ? S_OK : create_error(GetLastError());
618 static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
620 struct textstream *This = impl_from_ITextStream(iface);
621 HRESULT hr;
623 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
625 if (textstream_check_iomode(This, IOWrite))
626 return CTL_E_BADFILEMODE;
628 hr = textstream_writestr(This, text);
629 if (SUCCEEDED(hr))
630 hr = textstream_writecrlf(This);
631 return hr;
634 static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
636 struct textstream *This = impl_from_ITextStream(iface);
637 FIXME("(%p)->(%d): stub\n", This, lines);
638 return E_NOTIMPL;
641 static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
643 struct textstream *This = impl_from_ITextStream(iface);
644 FIXME("(%p)->(%d): stub\n", This, count);
645 return E_NOTIMPL;
648 static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
650 struct textstream *This = impl_from_ITextStream(iface);
651 FIXME("(%p): stub\n", This);
652 return E_NOTIMPL;
655 static HRESULT WINAPI textstream_Close(ITextStream *iface)
657 struct textstream *This = impl_from_ITextStream(iface);
658 HRESULT hr = S_OK;
660 TRACE("(%p)\n", This);
662 if(!CloseHandle(This->file))
663 hr = S_FALSE;
665 This->file = NULL;
667 return hr;
670 static const ITextStreamVtbl textstreamvtbl = {
671 textstream_QueryInterface,
672 textstream_AddRef,
673 textstream_Release,
674 textstream_GetTypeInfoCount,
675 textstream_GetTypeInfo,
676 textstream_GetIDsOfNames,
677 textstream_Invoke,
678 textstream_get_Line,
679 textstream_get_Column,
680 textstream_get_AtEndOfStream,
681 textstream_get_AtEndOfLine,
682 textstream_Read,
683 textstream_ReadLine,
684 textstream_ReadAll,
685 textstream_Write,
686 textstream_WriteLine,
687 textstream_WriteBlankLines,
688 textstream_Skip,
689 textstream_SkipLine,
690 textstream_Close
693 static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMode mode, BOOL unicode, ITextStream **ret)
695 struct textstream *stream;
696 DWORD access = 0;
698 /* map access mode */
699 switch (mode)
701 case ForReading:
702 access = GENERIC_READ;
703 break;
704 case ForWriting:
705 access = GENERIC_WRITE;
706 break;
707 case ForAppending:
708 access = FILE_APPEND_DATA;
709 break;
710 default:
711 return E_INVALIDARG;
714 stream = heap_alloc(sizeof(struct textstream));
715 if (!stream) return E_OUTOFMEMORY;
717 stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
718 stream->ref = 1;
719 stream->mode = mode;
720 stream->unicode = unicode;
721 stream->first_read = TRUE;
723 stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
724 if (stream->file == INVALID_HANDLE_VALUE)
726 HRESULT hr = create_error(GetLastError());
727 heap_free(stream);
728 return hr;
731 if (mode == ForReading)
732 GetFileSizeEx(stream->file, &stream->size);
733 else
734 stream->size.QuadPart = 0;
736 /* Write Unicode BOM */
737 if (unicode && mode == ForWriting && (disposition == CREATE_ALWAYS || disposition == CREATE_NEW)) {
738 DWORD written = 0;
739 BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL);
740 if (!ret || written != sizeof(utf16bom)) {
741 ITextStream_Release(&stream->ITextStream_iface);
742 return create_error(GetLastError());
746 init_classinfo(&CLSID_TextStream, (IUnknown *)&stream->ITextStream_iface, &stream->classinfo);
747 *ret = &stream->ITextStream_iface;
748 return S_OK;
751 static HRESULT WINAPI drive_QueryInterface(IDrive *iface, REFIID riid, void **obj)
753 struct drive *This = impl_from_IDrive(iface);
755 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
757 *obj = NULL;
759 if (IsEqualIID( riid, &IID_IDrive ) ||
760 IsEqualIID( riid, &IID_IDispatch ) ||
761 IsEqualIID( riid, &IID_IUnknown))
763 *obj = &This->IDrive_iface;
765 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
767 *obj = &This->classinfo.IProvideClassInfo_iface;
769 else
770 return E_NOINTERFACE;
772 IUnknown_AddRef((IUnknown*)*obj);
773 return S_OK;
776 static ULONG WINAPI drive_AddRef(IDrive *iface)
778 struct drive *This = impl_from_IDrive(iface);
779 ULONG ref = InterlockedIncrement(&This->ref);
780 TRACE("(%p)->(%d)\n", This, ref);
781 return ref;
784 static ULONG WINAPI drive_Release(IDrive *iface)
786 struct drive *This = impl_from_IDrive(iface);
787 ULONG ref = InterlockedDecrement(&This->ref);
788 TRACE("(%p)->(%d)\n", This, ref);
790 if (!ref)
792 SysFreeString(This->root);
793 heap_free(This);
796 return ref;
799 static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo)
801 struct drive *This = impl_from_IDrive(iface);
802 TRACE("(%p)->(%p)\n", This, pctinfo);
803 *pctinfo = 1;
804 return S_OK;
807 static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo,
808 LCID lcid, ITypeInfo **ppTInfo)
810 struct drive *This = impl_from_IDrive(iface);
811 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
812 return get_typeinfo(IDrive_tid, ppTInfo);
815 static HRESULT WINAPI drive_GetIDsOfNames(IDrive *iface, REFIID riid,
816 LPOLESTR *rgszNames, UINT cNames,
817 LCID lcid, DISPID *rgDispId)
819 struct drive *This = impl_from_IDrive(iface);
820 ITypeInfo *typeinfo;
821 HRESULT hr;
823 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
825 hr = get_typeinfo(IDrive_tid, &typeinfo);
826 if(SUCCEEDED(hr))
828 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
829 ITypeInfo_Release(typeinfo);
832 return hr;
835 static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember,
836 REFIID riid, LCID lcid, WORD wFlags,
837 DISPPARAMS *pDispParams, VARIANT *pVarResult,
838 EXCEPINFO *pExcepInfo, UINT *puArgErr)
840 struct drive *This = impl_from_IDrive(iface);
841 ITypeInfo *typeinfo;
842 HRESULT hr;
844 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
845 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
847 hr = get_typeinfo(IDrive_tid, &typeinfo);
848 if(SUCCEEDED(hr))
850 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
851 pDispParams, pVarResult, pExcepInfo, puArgErr);
852 ITypeInfo_Release(typeinfo);
855 return hr;
858 static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path)
860 struct drive *This = impl_from_IDrive(iface);
861 FIXME("(%p)->(%p): stub\n", This, path);
862 return E_NOTIMPL;
865 static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter)
867 struct drive *This = impl_from_IDrive(iface);
869 TRACE("(%p)->(%p)\n", This, letter);
871 if (!letter)
872 return E_POINTER;
874 *letter = SysAllocStringLen(This->root, 1);
875 if (!*letter)
876 return E_OUTOFMEMORY;
878 return S_OK;
881 static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name)
883 struct drive *This = impl_from_IDrive(iface);
884 FIXME("(%p)->(%p): stub\n", This, share_name);
885 return E_NOTIMPL;
888 static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type)
890 struct drive *This = impl_from_IDrive(iface);
892 TRACE("(%p)->(%p)\n", This, type);
894 switch (GetDriveTypeW(This->root))
896 case DRIVE_REMOVABLE:
897 *type = Removable;
898 break;
899 case DRIVE_FIXED:
900 *type = Fixed;
901 break;
902 case DRIVE_REMOTE:
903 *type = Remote;
904 break;
905 case DRIVE_CDROM:
906 *type = CDRom;
907 break;
908 case DRIVE_RAMDISK:
909 *type = RamDisk;
910 break;
911 default:
912 *type = UnknownType;
913 break;
916 return S_OK;
919 static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder)
921 struct drive *This = impl_from_IDrive(iface);
922 FIXME("(%p)->(%p): stub\n", This, folder);
923 return E_NOTIMPL;
926 static HRESULT variant_from_largeint(const ULARGE_INTEGER *src, VARIANT *v)
928 HRESULT hr = S_OK;
930 if (src->u.HighPart || src->u.LowPart > INT_MAX)
932 V_VT(v) = VT_R8;
933 hr = VarR8FromUI8(src->QuadPart, &V_R8(v));
935 else
937 V_VT(v) = VT_I4;
938 V_I4(v) = src->u.LowPart;
941 return hr;
944 static HRESULT WINAPI drive_get_AvailableSpace(IDrive *iface, VARIANT *v)
946 struct drive *This = impl_from_IDrive(iface);
947 ULARGE_INTEGER avail;
949 TRACE("(%p)->(%p)\n", This, v);
951 if (!v)
952 return E_POINTER;
954 if (!GetDiskFreeSpaceExW(This->root, &avail, NULL, NULL))
955 return E_FAIL;
957 return variant_from_largeint(&avail, v);
960 static HRESULT WINAPI drive_get_FreeSpace(IDrive *iface, VARIANT *v)
962 struct drive *This = impl_from_IDrive(iface);
963 ULARGE_INTEGER freespace;
965 TRACE("(%p)->(%p)\n", This, v);
967 if (!v)
968 return E_POINTER;
970 if (!GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL))
971 return E_FAIL;
973 return variant_from_largeint(&freespace, v);
976 static HRESULT WINAPI drive_get_TotalSize(IDrive *iface, VARIANT *v)
978 struct drive *This = impl_from_IDrive(iface);
979 ULARGE_INTEGER total;
981 TRACE("(%p)->(%p)\n", This, v);
983 if (!v)
984 return E_POINTER;
986 if (!GetDiskFreeSpaceExW(This->root, NULL, &total, NULL))
987 return E_FAIL;
989 return variant_from_largeint(&total, v);
992 static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name)
994 struct drive *This = impl_from_IDrive(iface);
995 WCHAR nameW[MAX_PATH+1];
996 BOOL ret;
998 TRACE("(%p)->(%p)\n", This, name);
1000 if (!name)
1001 return E_POINTER;
1003 *name = NULL;
1004 ret = GetVolumeInformationW(This->root, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, NULL, NULL, NULL, 0);
1005 if (ret)
1006 *name = SysAllocString(nameW);
1007 return ret ? S_OK : E_FAIL;
1010 static HRESULT WINAPI drive_put_VolumeName(IDrive *iface, BSTR name)
1012 struct drive *This = impl_from_IDrive(iface);
1013 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
1014 return E_NOTIMPL;
1017 static HRESULT WINAPI drive_get_FileSystem(IDrive *iface, BSTR *fs)
1019 struct drive *This = impl_from_IDrive(iface);
1020 WCHAR nameW[MAX_PATH+1];
1021 BOOL ret;
1023 TRACE("(%p)->(%p)\n", This, fs);
1025 if (!fs)
1026 return E_POINTER;
1028 *fs = NULL;
1029 ret = GetVolumeInformationW(This->root, NULL, 0, NULL, NULL, NULL, nameW, sizeof(nameW)/sizeof(WCHAR));
1030 if (ret)
1031 *fs = SysAllocString(nameW);
1032 return ret ? S_OK : E_FAIL;
1035 static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial)
1037 struct drive *This = impl_from_IDrive(iface);
1038 BOOL ret;
1040 TRACE("(%p)->(%p)\n", This, serial);
1042 if (!serial)
1043 return E_POINTER;
1045 ret = GetVolumeInformationW(This->root, NULL, 0, (DWORD*)serial, NULL, NULL, NULL, 0);
1046 return ret ? S_OK : E_FAIL;
1049 static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
1051 struct drive *This = impl_from_IDrive(iface);
1052 ULARGE_INTEGER freespace;
1053 BOOL ret;
1055 TRACE("(%p)->(%p)\n", This, ready);
1057 if (!ready)
1058 return E_POINTER;
1060 ret = GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL);
1061 *ready = ret ? VARIANT_TRUE : VARIANT_FALSE;
1062 return S_OK;
1065 static const IDriveVtbl drivevtbl = {
1066 drive_QueryInterface,
1067 drive_AddRef,
1068 drive_Release,
1069 drive_GetTypeInfoCount,
1070 drive_GetTypeInfo,
1071 drive_GetIDsOfNames,
1072 drive_Invoke,
1073 drive_get_Path,
1074 drive_get_DriveLetter,
1075 drive_get_ShareName,
1076 drive_get_DriveType,
1077 drive_get_RootFolder,
1078 drive_get_AvailableSpace,
1079 drive_get_FreeSpace,
1080 drive_get_TotalSize,
1081 drive_get_VolumeName,
1082 drive_put_VolumeName,
1083 drive_get_FileSystem,
1084 drive_get_SerialNumber,
1085 drive_get_IsReady
1088 static HRESULT create_drive(WCHAR letter, IDrive **drive)
1090 struct drive *This;
1092 *drive = NULL;
1094 This = heap_alloc(sizeof(*This));
1095 if (!This) return E_OUTOFMEMORY;
1097 This->IDrive_iface.lpVtbl = &drivevtbl;
1098 This->ref = 1;
1099 This->root = SysAllocStringLen(NULL, 3);
1100 if (!This->root)
1102 heap_free(This);
1103 return E_OUTOFMEMORY;
1105 This->root[0] = letter;
1106 This->root[1] = ':';
1107 This->root[2] = '\\';
1108 This->root[3] = 0;
1110 init_classinfo(&CLSID_Drive, (IUnknown *)&This->IDrive_iface, &This->classinfo);
1111 *drive = &This->IDrive_iface;
1112 return S_OK;
1115 static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
1117 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1119 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1121 *obj = NULL;
1123 if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
1124 IsEqualIID( riid, &IID_IUnknown ))
1126 *obj = iface;
1127 IEnumVARIANT_AddRef(iface);
1129 else
1130 return E_NOINTERFACE;
1132 return S_OK;
1135 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
1137 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1138 ULONG ref = InterlockedIncrement(&This->ref);
1139 TRACE("(%p)->(%d)\n", This, ref);
1140 return ref;
1143 static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
1145 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1146 ULONG ref = InterlockedDecrement(&This->ref);
1148 TRACE("(%p)->(%d)\n", This, ref);
1150 if (!ref)
1152 IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
1153 FindClose(This->data.u.foldercoll.find);
1154 heap_free(This);
1157 return ref;
1160 static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file)
1162 static const WCHAR allW[] = {'*',0};
1163 WCHAR pathW[MAX_PATH];
1164 int len;
1165 HANDLE handle;
1167 strcpyW(pathW, path);
1168 len = strlenW(pathW);
1169 if (len && pathW[len-1] != '\\')
1170 strcatW(pathW, bsW);
1171 strcatW(pathW, allW);
1172 handle = FindFirstFileW(pathW, data);
1173 if (handle == INVALID_HANDLE_VALUE) return 0;
1175 /* find first dir/file */
1176 while (1)
1178 if (file ? is_file_data(data) : is_dir_data(data))
1179 break;
1181 if (!FindNextFileW(handle, data))
1183 FindClose(handle);
1184 return 0;
1187 return handle;
1190 static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1192 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1193 HANDLE handle = This->data.u.foldercoll.find;
1194 WIN32_FIND_DATAW data;
1195 ULONG count = 0;
1197 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1199 if (fetched)
1200 *fetched = 0;
1202 if (!celt) return S_OK;
1204 if (!handle)
1206 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1207 if (!handle) return S_FALSE;
1209 This->data.u.foldercoll.find = handle;
1211 else
1213 if (!FindNextFileW(handle, &data))
1214 return S_FALSE;
1219 if (is_dir_data(&data))
1221 IFolder *folder;
1222 HRESULT hr;
1223 BSTR str;
1225 str = get_full_path(This->data.u.foldercoll.coll->path, &data);
1226 hr = create_folder(str, &folder);
1227 SysFreeString(str);
1228 if (FAILED(hr)) return hr;
1230 V_VT(&var[count]) = VT_DISPATCH;
1231 V_DISPATCH(&var[count]) = (IDispatch*)folder;
1232 count++;
1234 if (count >= celt) break;
1236 } while (FindNextFileW(handle, &data));
1238 if (fetched)
1239 *fetched = count;
1241 return (count < celt) ? S_FALSE : S_OK;
1244 static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1246 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1247 HANDLE handle = This->data.u.foldercoll.find;
1248 WIN32_FIND_DATAW data;
1250 TRACE("(%p)->(%d)\n", This, celt);
1252 if (!celt) return S_OK;
1254 if (!handle)
1256 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1257 if (!handle) return S_FALSE;
1259 This->data.u.foldercoll.find = handle;
1261 else
1263 if (!FindNextFileW(handle, &data))
1264 return S_FALSE;
1269 if (is_dir_data(&data))
1270 --celt;
1272 if (!celt) break;
1273 } while (FindNextFileW(handle, &data));
1275 return celt ? S_FALSE : S_OK;
1278 static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
1280 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1282 TRACE("(%p)\n", This);
1284 FindClose(This->data.u.foldercoll.find);
1285 This->data.u.foldercoll.find = NULL;
1287 return S_OK;
1290 static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1292 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1293 TRACE("(%p)->(%p)\n", This, pclone);
1294 return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
1297 static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
1298 enumvariant_QueryInterface,
1299 enumvariant_AddRef,
1300 foldercoll_enumvariant_Release,
1301 foldercoll_enumvariant_Next,
1302 foldercoll_enumvariant_Skip,
1303 foldercoll_enumvariant_Reset,
1304 foldercoll_enumvariant_Clone
1307 static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
1309 struct enumvariant *This;
1311 *newenum = NULL;
1313 This = heap_alloc(sizeof(*This));
1314 if (!This) return E_OUTOFMEMORY;
1316 This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
1317 This->ref = 1;
1318 This->data.u.foldercoll.find = NULL;
1319 This->data.u.foldercoll.coll = collection;
1320 IFolderCollection_AddRef(&collection->IFolderCollection_iface);
1322 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1324 return S_OK;
1327 static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface)
1329 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1330 ULONG ref = InterlockedDecrement(&This->ref);
1332 TRACE("(%p)->(%d)\n", This, ref);
1334 if (!ref)
1336 IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
1337 FindClose(This->data.u.filecoll.find);
1338 heap_free(This);
1341 return ref;
1344 static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1346 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1347 HANDLE handle = This->data.u.filecoll.find;
1348 WIN32_FIND_DATAW data;
1349 ULONG count = 0;
1351 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1353 if (fetched)
1354 *fetched = 0;
1356 if (!celt) return S_OK;
1358 if (!handle)
1360 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1361 if (!handle) return S_FALSE;
1362 This->data.u.filecoll.find = handle;
1364 else if (!FindNextFileW(handle, &data))
1365 return S_FALSE;
1369 if (is_file_data(&data))
1371 IFile *file;
1372 HRESULT hr;
1373 BSTR str;
1375 str = get_full_path(This->data.u.filecoll.coll->path, &data);
1376 hr = create_file(str, &file);
1377 SysFreeString(str);
1378 if (FAILED(hr)) return hr;
1380 V_VT(&var[count]) = VT_DISPATCH;
1381 V_DISPATCH(&var[count]) = (IDispatch*)file;
1382 if (++count >= celt) break;
1384 } while (FindNextFileW(handle, &data));
1386 if (fetched)
1387 *fetched = count;
1389 return (count < celt) ? S_FALSE : S_OK;
1392 static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1394 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1395 HANDLE handle = This->data.u.filecoll.find;
1396 WIN32_FIND_DATAW data;
1398 TRACE("(%p)->(%d)\n", This, celt);
1400 if (!celt) return S_OK;
1402 if (!handle)
1404 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1405 if (!handle) return S_FALSE;
1406 This->data.u.filecoll.find = handle;
1408 else if (!FindNextFileW(handle, &data))
1409 return S_FALSE;
1413 if (is_file_data(&data))
1414 --celt;
1415 } while (celt && FindNextFileW(handle, &data));
1417 return celt ? S_FALSE : S_OK;
1420 static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface)
1422 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1424 TRACE("(%p)\n", This);
1426 FindClose(This->data.u.filecoll.find);
1427 This->data.u.filecoll.find = NULL;
1429 return S_OK;
1432 static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1434 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1435 TRACE("(%p)->(%p)\n", This, pclone);
1436 return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
1439 static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
1440 enumvariant_QueryInterface,
1441 enumvariant_AddRef,
1442 filecoll_enumvariant_Release,
1443 filecoll_enumvariant_Next,
1444 filecoll_enumvariant_Skip,
1445 filecoll_enumvariant_Reset,
1446 filecoll_enumvariant_Clone
1449 static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum)
1451 struct enumvariant *This;
1453 *newenum = NULL;
1455 This = heap_alloc(sizeof(*This));
1456 if (!This) return E_OUTOFMEMORY;
1458 This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
1459 This->ref = 1;
1460 This->data.u.filecoll.find = NULL;
1461 This->data.u.filecoll.coll = collection;
1462 IFileCollection_AddRef(&collection->IFileCollection_iface);
1464 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1466 return S_OK;
1469 static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface)
1471 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1472 ULONG ref = InterlockedDecrement(&This->ref);
1474 TRACE("(%p)->(%d)\n", This, ref);
1476 if (!ref)
1478 IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
1479 heap_free(This);
1482 return ref;
1485 static HRESULT find_next_drive(struct enumvariant *penum)
1487 int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
1489 for (; i < 32; i++)
1490 if (penum->data.u.drivecoll.coll->drives & (1 << i))
1492 penum->data.u.drivecoll.cur = i;
1493 return S_OK;
1496 return S_FALSE;
1499 static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1501 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1502 ULONG count = 0;
1504 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1506 if (fetched)
1507 *fetched = 0;
1509 if (!celt) return S_OK;
1511 while (find_next_drive(This) == S_OK)
1513 IDrive *drive;
1514 HRESULT hr;
1516 hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
1517 if (FAILED(hr)) return hr;
1519 V_VT(&var[count]) = VT_DISPATCH;
1520 V_DISPATCH(&var[count]) = (IDispatch*)drive;
1522 if (++count >= celt) break;
1525 if (fetched)
1526 *fetched = count;
1528 return (count < celt) ? S_FALSE : S_OK;
1531 static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1533 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1535 TRACE("(%p)->(%d)\n", This, celt);
1537 if (!celt) return S_OK;
1539 while (celt && find_next_drive(This) == S_OK)
1540 celt--;
1542 return celt ? S_FALSE : S_OK;
1545 static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface)
1547 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1549 TRACE("(%p)\n", This);
1551 This->data.u.drivecoll.cur = -1;
1552 return S_OK;
1555 static HRESULT WINAPI drivecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1557 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1558 FIXME("(%p)->(%p): stub\n", This, pclone);
1559 return E_NOTIMPL;
1562 static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
1563 enumvariant_QueryInterface,
1564 enumvariant_AddRef,
1565 drivecoll_enumvariant_Release,
1566 drivecoll_enumvariant_Next,
1567 drivecoll_enumvariant_Skip,
1568 drivecoll_enumvariant_Reset,
1569 drivecoll_enumvariant_Clone
1572 static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum)
1574 struct enumvariant *This;
1576 *newenum = NULL;
1578 This = heap_alloc(sizeof(*This));
1579 if (!This) return E_OUTOFMEMORY;
1581 This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
1582 This->ref = 1;
1583 This->data.u.drivecoll.coll = collection;
1584 This->data.u.drivecoll.cur = -1;
1585 IDriveCollection_AddRef(&collection->IDriveCollection_iface);
1587 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1589 return S_OK;
1592 static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
1594 struct foldercollection *This = impl_from_IFolderCollection(iface);
1596 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1598 *obj = NULL;
1600 if (IsEqualIID( riid, &IID_IFolderCollection ) ||
1601 IsEqualIID( riid, &IID_IDispatch ) ||
1602 IsEqualIID( riid, &IID_IUnknown ))
1604 *obj = &This->IFolderCollection_iface;
1606 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
1608 *obj = &This->classinfo.IProvideClassInfo_iface;
1610 else
1611 return E_NOINTERFACE;
1613 IUnknown_AddRef((IUnknown*)*obj);
1614 return S_OK;
1617 static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
1619 struct foldercollection *This = impl_from_IFolderCollection(iface);
1620 ULONG ref = InterlockedIncrement(&This->ref);
1621 TRACE("(%p)->(%d)\n", This, ref);
1622 return ref;
1625 static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
1627 struct foldercollection *This = impl_from_IFolderCollection(iface);
1628 ULONG ref = InterlockedDecrement(&This->ref);
1629 TRACE("(%p)->(%d)\n", This, ref);
1631 if (!ref)
1633 SysFreeString(This->path);
1634 heap_free(This);
1637 return ref;
1640 static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
1642 struct foldercollection *This = impl_from_IFolderCollection(iface);
1643 TRACE("(%p)->(%p)\n", This, pctinfo);
1644 *pctinfo = 1;
1645 return S_OK;
1648 static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
1649 LCID lcid, ITypeInfo **ppTInfo)
1651 struct foldercollection *This = impl_from_IFolderCollection(iface);
1652 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1653 return get_typeinfo(IFolderCollection_tid, ppTInfo);
1656 static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
1657 LPOLESTR *rgszNames, UINT cNames,
1658 LCID lcid, DISPID *rgDispId)
1660 struct foldercollection *This = impl_from_IFolderCollection(iface);
1661 ITypeInfo *typeinfo;
1662 HRESULT hr;
1664 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1666 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1667 if(SUCCEEDED(hr))
1669 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1670 ITypeInfo_Release(typeinfo);
1673 return hr;
1676 static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
1677 REFIID riid, LCID lcid, WORD wFlags,
1678 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1679 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1681 struct foldercollection *This = impl_from_IFolderCollection(iface);
1682 ITypeInfo *typeinfo;
1683 HRESULT hr;
1685 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1686 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1688 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1689 if(SUCCEEDED(hr))
1691 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1692 pDispParams, pVarResult, pExcepInfo, puArgErr);
1693 ITypeInfo_Release(typeinfo);
1696 return hr;
1699 static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
1701 struct foldercollection *This = impl_from_IFolderCollection(iface);
1702 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
1703 return E_NOTIMPL;
1706 static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
1708 struct foldercollection *This = impl_from_IFolderCollection(iface);
1709 FIXME("(%p)->(%p): stub\n", This, folder);
1710 return E_NOTIMPL;
1713 static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
1715 struct foldercollection *This = impl_from_IFolderCollection(iface);
1717 TRACE("(%p)->(%p)\n", This, newenum);
1719 if(!newenum)
1720 return E_POINTER;
1722 return create_foldercoll_enum(This, newenum);
1725 static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
1727 struct foldercollection *This = impl_from_IFolderCollection(iface);
1728 static const WCHAR allW[] = {'\\','*',0};
1729 WIN32_FIND_DATAW data;
1730 WCHAR pathW[MAX_PATH];
1731 HANDLE handle;
1733 TRACE("(%p)->(%p)\n", This, count);
1735 if(!count)
1736 return E_POINTER;
1738 *count = 0;
1740 strcpyW(pathW, This->path);
1741 strcatW(pathW, allW);
1742 handle = FindFirstFileW(pathW, &data);
1743 if (handle == INVALID_HANDLE_VALUE)
1744 return HRESULT_FROM_WIN32(GetLastError());
1748 if (is_dir_data(&data))
1749 *count += 1;
1750 } while (FindNextFileW(handle, &data));
1751 FindClose(handle);
1753 return S_OK;
1756 static const IFolderCollectionVtbl foldercollvtbl = {
1757 foldercoll_QueryInterface,
1758 foldercoll_AddRef,
1759 foldercoll_Release,
1760 foldercoll_GetTypeInfoCount,
1761 foldercoll_GetTypeInfo,
1762 foldercoll_GetIDsOfNames,
1763 foldercoll_Invoke,
1764 foldercoll_Add,
1765 foldercoll_get_Item,
1766 foldercoll_get__NewEnum,
1767 foldercoll_get_Count
1770 static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
1772 struct foldercollection *This;
1774 *folders = NULL;
1776 This = heap_alloc(sizeof(struct foldercollection));
1777 if (!This) return E_OUTOFMEMORY;
1779 This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
1780 This->ref = 1;
1781 This->path = SysAllocString(path);
1782 if (!This->path)
1784 heap_free(This);
1785 return E_OUTOFMEMORY;
1788 init_classinfo(&CLSID_Folders, (IUnknown *)&This->IFolderCollection_iface, &This->classinfo);
1789 *folders = &This->IFolderCollection_iface;
1791 return S_OK;
1794 static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj)
1796 struct filecollection *This = impl_from_IFileCollection(iface);
1798 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1800 *obj = NULL;
1802 if (IsEqualIID( riid, &IID_IFileCollection ) ||
1803 IsEqualIID( riid, &IID_IDispatch ) ||
1804 IsEqualIID( riid, &IID_IUnknown ))
1806 *obj = &This->IFileCollection_iface;
1808 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
1810 *obj = &This->classinfo.IProvideClassInfo_iface;
1812 else
1813 return E_NOINTERFACE;
1815 IUnknown_AddRef((IUnknown*)*obj);
1816 return S_OK;
1819 static ULONG WINAPI filecoll_AddRef(IFileCollection *iface)
1821 struct filecollection *This = impl_from_IFileCollection(iface);
1822 ULONG ref = InterlockedIncrement(&This->ref);
1823 TRACE("(%p)->(%d)\n", This, ref);
1824 return ref;
1827 static ULONG WINAPI filecoll_Release(IFileCollection *iface)
1829 struct filecollection *This = impl_from_IFileCollection(iface);
1830 ULONG ref = InterlockedDecrement(&This->ref);
1831 TRACE("(%p)->(%d)\n", This, ref);
1833 if (!ref)
1835 SysFreeString(This->path);
1836 heap_free(This);
1839 return ref;
1842 static HRESULT WINAPI filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo)
1844 struct filecollection *This = impl_from_IFileCollection(iface);
1845 TRACE("(%p)->(%p)\n", This, pctinfo);
1846 *pctinfo = 1;
1847 return S_OK;
1850 static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo,
1851 LCID lcid, ITypeInfo **ppTInfo)
1853 struct filecollection *This = impl_from_IFileCollection(iface);
1854 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1855 return get_typeinfo(IFileCollection_tid, ppTInfo);
1858 static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid,
1859 LPOLESTR *rgszNames, UINT cNames,
1860 LCID lcid, DISPID *rgDispId)
1862 struct filecollection *This = impl_from_IFileCollection(iface);
1863 ITypeInfo *typeinfo;
1864 HRESULT hr;
1866 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1868 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1869 if(SUCCEEDED(hr))
1871 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1872 ITypeInfo_Release(typeinfo);
1875 return hr;
1878 static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember,
1879 REFIID riid, LCID lcid, WORD wFlags,
1880 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1881 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1883 struct filecollection *This = impl_from_IFileCollection(iface);
1884 ITypeInfo *typeinfo;
1885 HRESULT hr;
1887 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1888 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1890 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1891 if(SUCCEEDED(hr))
1893 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1894 pDispParams, pVarResult, pExcepInfo, puArgErr);
1895 ITypeInfo_Release(typeinfo);
1898 return hr;
1901 static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file)
1903 struct filecollection *This = impl_from_IFileCollection(iface);
1904 FIXME("(%p)->(%p)\n", This, file);
1905 return E_NOTIMPL;
1908 static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum)
1910 struct filecollection *This = impl_from_IFileCollection(iface);
1912 TRACE("(%p)->(%p)\n", This, ppenum);
1914 if(!ppenum)
1915 return E_POINTER;
1917 return create_filecoll_enum(This, ppenum);
1920 static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count)
1922 struct filecollection *This = impl_from_IFileCollection(iface);
1923 static const WCHAR allW[] = {'\\','*',0};
1924 WIN32_FIND_DATAW data;
1925 WCHAR pathW[MAX_PATH];
1926 HANDLE handle;
1928 TRACE("(%p)->(%p)\n", This, count);
1930 if(!count)
1931 return E_POINTER;
1933 *count = 0;
1935 strcpyW(pathW, This->path);
1936 strcatW(pathW, allW);
1937 handle = FindFirstFileW(pathW, &data);
1938 if (handle == INVALID_HANDLE_VALUE)
1939 return HRESULT_FROM_WIN32(GetLastError());
1943 if (is_file_data(&data))
1944 *count += 1;
1945 } while (FindNextFileW(handle, &data));
1946 FindClose(handle);
1948 return S_OK;
1951 static const IFileCollectionVtbl filecollectionvtbl = {
1952 filecoll_QueryInterface,
1953 filecoll_AddRef,
1954 filecoll_Release,
1955 filecoll_GetTypeInfoCount,
1956 filecoll_GetTypeInfo,
1957 filecoll_GetIDsOfNames,
1958 filecoll_Invoke,
1959 filecoll_get_Item,
1960 filecoll_get__NewEnum,
1961 filecoll_get_Count
1964 static HRESULT create_filecoll(BSTR path, IFileCollection **files)
1966 struct filecollection *This;
1968 *files = NULL;
1970 This = heap_alloc(sizeof(*This));
1971 if (!This) return E_OUTOFMEMORY;
1973 This->IFileCollection_iface.lpVtbl = &filecollectionvtbl;
1974 This->ref = 1;
1975 This->path = SysAllocString(path);
1976 if (!This->path)
1978 heap_free(This);
1979 return E_OUTOFMEMORY;
1982 init_classinfo(&CLSID_Files, (IUnknown *)&This->IFileCollection_iface, &This->classinfo);
1983 *files = &This->IFileCollection_iface;
1984 return S_OK;
1987 static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
1989 struct drivecollection *This = impl_from_IDriveCollection(iface);
1991 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1993 *obj = NULL;
1995 if (IsEqualIID( riid, &IID_IDriveCollection ) ||
1996 IsEqualIID( riid, &IID_IDispatch ) ||
1997 IsEqualIID( riid, &IID_IUnknown ))
1999 *obj = &This->IDriveCollection_iface;
2001 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2003 *obj = &This->classinfo.IProvideClassInfo_iface;
2005 else
2006 return E_NOINTERFACE;
2008 IUnknown_AddRef((IUnknown*)*obj);
2009 return S_OK;
2012 static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
2014 struct drivecollection *This = impl_from_IDriveCollection(iface);
2015 ULONG ref = InterlockedIncrement(&This->ref);
2016 TRACE("(%p)->(%d)\n", This, ref);
2017 return ref;
2020 static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
2022 struct drivecollection *This = impl_from_IDriveCollection(iface);
2023 ULONG ref = InterlockedDecrement(&This->ref);
2024 TRACE("(%p)->(%d)\n", This, ref);
2026 if (!ref)
2027 heap_free(This);
2029 return ref;
2032 static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
2034 struct drivecollection *This = impl_from_IDriveCollection(iface);
2035 TRACE("(%p)->(%p)\n", This, pctinfo);
2036 *pctinfo = 1;
2037 return S_OK;
2040 static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
2041 LCID lcid, ITypeInfo **ppTInfo)
2043 struct drivecollection *This = impl_from_IDriveCollection(iface);
2044 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2045 return get_typeinfo(IDriveCollection_tid, ppTInfo);
2048 static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
2049 LPOLESTR *rgszNames, UINT cNames,
2050 LCID lcid, DISPID *rgDispId)
2052 struct drivecollection *This = impl_from_IDriveCollection(iface);
2053 ITypeInfo *typeinfo;
2054 HRESULT hr;
2056 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2058 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2059 if(SUCCEEDED(hr))
2061 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2062 ITypeInfo_Release(typeinfo);
2065 return hr;
2068 static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
2069 REFIID riid, LCID lcid, WORD wFlags,
2070 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2071 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2073 struct drivecollection *This = impl_from_IDriveCollection(iface);
2074 ITypeInfo *typeinfo;
2075 HRESULT hr;
2077 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2078 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2080 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2081 if(SUCCEEDED(hr))
2083 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2084 pDispParams, pVarResult, pExcepInfo, puArgErr);
2085 ITypeInfo_Release(typeinfo);
2088 return hr;
2091 static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
2093 struct drivecollection *This = impl_from_IDriveCollection(iface);
2094 FIXME("(%p)->(%p): stub\n", This, drive);
2095 return E_NOTIMPL;
2098 static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
2100 struct drivecollection *This = impl_from_IDriveCollection(iface);
2102 TRACE("(%p)->(%p)\n", This, ppenum);
2104 if(!ppenum)
2105 return E_POINTER;
2107 return create_drivecoll_enum(This, ppenum);
2110 static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
2112 struct drivecollection *This = impl_from_IDriveCollection(iface);
2114 TRACE("(%p)->(%p)\n", This, count);
2116 if (!count) return E_POINTER;
2118 *count = This->count;
2119 return S_OK;
2122 static const IDriveCollectionVtbl drivecollectionvtbl = {
2123 drivecoll_QueryInterface,
2124 drivecoll_AddRef,
2125 drivecoll_Release,
2126 drivecoll_GetTypeInfoCount,
2127 drivecoll_GetTypeInfo,
2128 drivecoll_GetIDsOfNames,
2129 drivecoll_Invoke,
2130 drivecoll_get_Item,
2131 drivecoll_get__NewEnum,
2132 drivecoll_get_Count
2135 static HRESULT create_drivecoll(IDriveCollection **drives)
2137 struct drivecollection *This;
2138 DWORD mask;
2140 *drives = NULL;
2142 This = heap_alloc(sizeof(*This));
2143 if (!This) return E_OUTOFMEMORY;
2145 This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl;
2146 This->ref = 1;
2147 This->drives = mask = GetLogicalDrives();
2148 /* count set bits */
2149 for (This->count = 0; mask; This->count++)
2150 mask &= mask - 1;
2152 init_classinfo(&CLSID_Drives, (IUnknown *)&This->IDriveCollection_iface, &This->classinfo);
2153 *drives = &This->IDriveCollection_iface;
2154 return S_OK;
2157 static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
2159 struct folder *This = impl_from_IFolder(iface);
2161 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2163 *obj = NULL;
2165 if (IsEqualIID( riid, &IID_IFolder ) ||
2166 IsEqualIID( riid, &IID_IDispatch ) ||
2167 IsEqualIID( riid, &IID_IUnknown))
2169 *obj = &This->IFolder_iface;
2171 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2173 *obj = &This->classinfo.IProvideClassInfo_iface;
2175 else
2176 return E_NOINTERFACE;
2178 IUnknown_AddRef((IUnknown*)*obj);
2179 return S_OK;
2182 static ULONG WINAPI folder_AddRef(IFolder *iface)
2184 struct folder *This = impl_from_IFolder(iface);
2185 ULONG ref = InterlockedIncrement(&This->ref);
2186 TRACE("(%p)->(%d)\n", This, ref);
2187 return ref;
2190 static ULONG WINAPI folder_Release(IFolder *iface)
2192 struct folder *This = impl_from_IFolder(iface);
2193 ULONG ref = InterlockedDecrement(&This->ref);
2194 TRACE("(%p)->(%d)\n", This, ref);
2196 if (!ref)
2198 SysFreeString(This->path);
2199 heap_free(This);
2202 return ref;
2205 static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
2207 struct folder *This = impl_from_IFolder(iface);
2208 TRACE("(%p)->(%p)\n", This, pctinfo);
2209 *pctinfo = 1;
2210 return S_OK;
2213 static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
2214 LCID lcid, ITypeInfo **ppTInfo)
2216 struct folder *This = impl_from_IFolder(iface);
2217 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2218 return get_typeinfo(IFolder_tid, ppTInfo);
2221 static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
2222 LPOLESTR *rgszNames, UINT cNames,
2223 LCID lcid, DISPID *rgDispId)
2225 struct folder *This = impl_from_IFolder(iface);
2226 ITypeInfo *typeinfo;
2227 HRESULT hr;
2229 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2231 hr = get_typeinfo(IFolder_tid, &typeinfo);
2232 if(SUCCEEDED(hr))
2234 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2235 ITypeInfo_Release(typeinfo);
2238 return hr;
2241 static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
2242 REFIID riid, LCID lcid, WORD wFlags,
2243 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2244 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2246 struct folder *This = impl_from_IFolder(iface);
2247 ITypeInfo *typeinfo;
2248 HRESULT hr;
2250 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2251 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2253 hr = get_typeinfo(IFolder_tid, &typeinfo);
2254 if(SUCCEEDED(hr))
2256 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2257 pDispParams, pVarResult, pExcepInfo, puArgErr);
2258 ITypeInfo_Release(typeinfo);
2261 return hr;
2264 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
2266 struct folder *This = impl_from_IFolder(iface);
2268 TRACE("(%p)->(%p)\n", This, path);
2270 if(!path)
2271 return E_POINTER;
2273 *path = SysAllocString(This->path);
2274 return *path ? S_OK : E_OUTOFMEMORY;
2277 static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
2279 struct folder *This = impl_from_IFolder(iface);
2280 WCHAR *ptr;
2282 TRACE("(%p)->(%p)\n", This, name);
2284 if(!name)
2285 return E_POINTER;
2287 *name = NULL;
2289 ptr = strrchrW(This->path, '\\');
2290 if (ptr)
2292 *name = SysAllocString(ptr+1);
2293 TRACE("%s\n", debugstr_w(*name));
2294 if (!*name) return E_OUTOFMEMORY;
2296 else
2297 return E_FAIL;
2299 return S_OK;
2302 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
2304 struct folder *This = impl_from_IFolder(iface);
2305 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
2306 return E_NOTIMPL;
2309 static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
2311 struct folder *This = impl_from_IFolder(iface);
2312 FIXME("(%p)->(%p): stub\n", This, path);
2313 return E_NOTIMPL;
2316 static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
2318 struct folder *This = impl_from_IFolder(iface);
2319 FIXME("(%p)->(%p): stub\n", This, name);
2320 return E_NOTIMPL;
2323 static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
2325 struct folder *This = impl_from_IFolder(iface);
2326 FIXME("(%p)->(%p): stub\n", This, drive);
2327 return E_NOTIMPL;
2330 static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
2332 struct folder *This = impl_from_IFolder(iface);
2333 FIXME("(%p)->(%p): stub\n", This, parent);
2334 return E_NOTIMPL;
2337 static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
2339 struct folder *This = impl_from_IFolder(iface);
2340 FIXME("(%p)->(%p): stub\n", This, attr);
2341 return E_NOTIMPL;
2344 static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
2346 struct folder *This = impl_from_IFolder(iface);
2347 FIXME("(%p)->(0x%x): stub\n", This, attr);
2348 return E_NOTIMPL;
2351 static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
2353 struct folder *This = impl_from_IFolder(iface);
2354 FIXME("(%p)->(%p): stub\n", This, date);
2355 return E_NOTIMPL;
2358 static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
2360 struct folder *This = impl_from_IFolder(iface);
2361 FIXME("(%p)->(%p): stub\n", This, date);
2362 return E_NOTIMPL;
2365 static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
2367 struct folder *This = impl_from_IFolder(iface);
2368 FIXME("(%p)->(%p): stub\n", This, date);
2369 return E_NOTIMPL;
2372 static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
2374 struct folder *This = impl_from_IFolder(iface);
2375 FIXME("(%p)->(%p): stub\n", This, type);
2376 return E_NOTIMPL;
2379 static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
2381 struct folder *This = impl_from_IFolder(iface);
2382 FIXME("(%p)->(%x): stub\n", This, force);
2383 return E_NOTIMPL;
2386 static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
2388 struct folder *This = impl_from_IFolder(iface);
2389 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
2390 return E_NOTIMPL;
2393 static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
2395 struct folder *This = impl_from_IFolder(iface);
2396 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
2397 return E_NOTIMPL;
2400 static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
2402 struct folder *This = impl_from_IFolder(iface);
2403 FIXME("(%p)->(%p): stub\n", This, isroot);
2404 return E_NOTIMPL;
2407 static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
2409 struct folder *This = impl_from_IFolder(iface);
2410 FIXME("(%p)->(%p): stub\n", This, size);
2411 return E_NOTIMPL;
2414 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
2416 struct folder *This = impl_from_IFolder(iface);
2418 TRACE("(%p)->(%p)\n", This, folders);
2420 if(!folders)
2421 return E_POINTER;
2423 return create_foldercoll(This->path, folders);
2426 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
2428 struct folder *This = impl_from_IFolder(iface);
2430 TRACE("(%p)->(%p)\n", This, files);
2432 if(!files)
2433 return E_POINTER;
2435 return create_filecoll(This->path, files);
2438 static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
2439 VARIANT_BOOL unicode, ITextStream **stream)
2441 struct folder *This = impl_from_IFolder(iface);
2442 FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
2443 return E_NOTIMPL;
2446 static const IFolderVtbl foldervtbl = {
2447 folder_QueryInterface,
2448 folder_AddRef,
2449 folder_Release,
2450 folder_GetTypeInfoCount,
2451 folder_GetTypeInfo,
2452 folder_GetIDsOfNames,
2453 folder_Invoke,
2454 folder_get_Path,
2455 folder_get_Name,
2456 folder_put_Name,
2457 folder_get_ShortPath,
2458 folder_get_ShortName,
2459 folder_get_Drive,
2460 folder_get_ParentFolder,
2461 folder_get_Attributes,
2462 folder_put_Attributes,
2463 folder_get_DateCreated,
2464 folder_get_DateLastModified,
2465 folder_get_DateLastAccessed,
2466 folder_get_Type,
2467 folder_Delete,
2468 folder_Copy,
2469 folder_Move,
2470 folder_get_IsRootFolder,
2471 folder_get_Size,
2472 folder_get_SubFolders,
2473 folder_get_Files,
2474 folder_CreateTextFile
2477 HRESULT create_folder(const WCHAR *path, IFolder **folder)
2479 struct folder *This;
2481 *folder = NULL;
2483 TRACE("%s\n", debugstr_w(path));
2485 This = heap_alloc(sizeof(struct folder));
2486 if (!This) return E_OUTOFMEMORY;
2488 This->IFolder_iface.lpVtbl = &foldervtbl;
2489 This->ref = 1;
2490 This->path = SysAllocString(path);
2491 if (!This->path)
2493 heap_free(This);
2494 return E_OUTOFMEMORY;
2497 init_classinfo(&CLSID_Folder, (IUnknown *)&This->IFolder_iface, &This->classinfo);
2498 *folder = &This->IFolder_iface;
2500 return S_OK;
2503 static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
2505 struct file *This = impl_from_IFile(iface);
2507 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2509 *obj = NULL;
2511 if (IsEqualIID(riid, &IID_IFile) ||
2512 IsEqualIID(riid, &IID_IDispatch) ||
2513 IsEqualIID(riid, &IID_IUnknown))
2515 *obj = &This->IFile_iface;
2517 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2519 *obj = &This->classinfo.IProvideClassInfo_iface;
2521 else
2522 return E_NOINTERFACE;
2524 IUnknown_AddRef((IUnknown*)*obj);
2525 return S_OK;
2528 static ULONG WINAPI file_AddRef(IFile *iface)
2530 struct file *This = impl_from_IFile(iface);
2531 LONG ref = InterlockedIncrement(&This->ref);
2533 TRACE("(%p) ref=%d\n", This, ref);
2535 return ref;
2538 static ULONG WINAPI file_Release(IFile *iface)
2540 struct file *This = impl_from_IFile(iface);
2541 LONG ref = InterlockedDecrement(&This->ref);
2543 TRACE("(%p) ref=%d\n", This, ref);
2545 if(!ref)
2547 heap_free(This->path);
2548 heap_free(This);
2551 return ref;
2554 static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
2556 struct file *This = impl_from_IFile(iface);
2558 TRACE("(%p)->(%p)\n", This, pctinfo);
2560 *pctinfo = 1;
2561 return S_OK;
2564 static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
2565 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
2567 struct file *This = impl_from_IFile(iface);
2569 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2571 return get_typeinfo(IFile_tid, ppTInfo);
2574 static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
2575 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2577 struct file *This = impl_from_IFile(iface);
2578 ITypeInfo *typeinfo;
2579 HRESULT hr;
2581 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
2582 rgszNames, cNames, lcid, rgDispId);
2584 hr = get_typeinfo(IFile_tid, &typeinfo);
2585 if(SUCCEEDED(hr)) {
2586 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2587 ITypeInfo_Release(typeinfo);
2589 return hr;
2592 static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2594 struct file *This = impl_from_IFile(iface);
2595 ITypeInfo *typeinfo;
2596 HRESULT hr;
2598 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2599 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2601 hr = get_typeinfo(IFile_tid, &typeinfo);
2602 if(SUCCEEDED(hr))
2604 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2605 pDispParams, pVarResult, pExcepInfo, puArgErr);
2606 ITypeInfo_Release(typeinfo);
2608 return hr;
2611 static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *path)
2613 struct file *This = impl_from_IFile(iface);
2615 TRACE("(%p)->(%p)\n", This, path);
2617 if (!path)
2618 return E_POINTER;
2620 *path = SysAllocString(This->path);
2621 if (!*path)
2622 return E_OUTOFMEMORY;
2624 return S_OK;
2627 static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
2629 struct file *This = impl_from_IFile(iface);
2630 WCHAR *ptr;
2632 TRACE("(%p)->(%p)\n", This, name);
2634 if(!name)
2635 return E_POINTER;
2637 *name = NULL;
2639 ptr = strrchrW(This->path, '\\');
2640 if (ptr)
2642 *name = SysAllocString(ptr+1);
2643 TRACE("%s\n", debugstr_w(*name));
2644 if (!*name) return E_OUTOFMEMORY;
2646 else
2647 return E_FAIL;
2649 return S_OK;
2652 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
2654 struct file *This = impl_from_IFile(iface);
2655 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
2656 return E_NOTIMPL;
2659 static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
2661 struct file *This = impl_from_IFile(iface);
2662 FIXME("(%p)->(%p)\n", This, pbstrPath);
2663 return E_NOTIMPL;
2666 static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
2668 struct file *This = impl_from_IFile(iface);
2669 FIXME("(%p)->(%p)\n", This, pbstrName);
2670 return E_NOTIMPL;
2673 static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
2675 struct file *This = impl_from_IFile(iface);
2676 FIXME("(%p)->(%p)\n", This, ppdrive);
2677 return E_NOTIMPL;
2680 static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
2682 struct file *This = impl_from_IFile(iface);
2683 FIXME("(%p)->(%p)\n", This, ppfolder);
2684 return E_NOTIMPL;
2687 static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
2689 struct file *This = impl_from_IFile(iface);
2690 DWORD fa;
2692 TRACE("(%p)->(%p)\n", This, pfa);
2694 if(!pfa)
2695 return E_POINTER;
2697 fa = GetFileAttributesW(This->path);
2698 if(fa == INVALID_FILE_ATTRIBUTES)
2699 return create_error(GetLastError());
2701 *pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2702 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
2703 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
2704 return S_OK;
2707 static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
2709 struct file *This = impl_from_IFile(iface);
2711 TRACE("(%p)->(%x)\n", This, pfa);
2713 return SetFileAttributesW(This->path, pfa) ? S_OK : create_error(GetLastError());
2716 static HRESULT get_date_from_filetime(const FILETIME *ft, DATE *date)
2718 FILETIME ftlocal;
2719 SYSTEMTIME st;
2721 if (!date)
2722 return E_POINTER;
2724 FileTimeToLocalFileTime(ft, &ftlocal);
2725 FileTimeToSystemTime(&ftlocal, &st);
2726 SystemTimeToVariantTime(&st, date);
2728 return S_OK;
2731 static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
2733 struct file *This = impl_from_IFile(iface);
2734 FIXME("(%p)->(%p)\n", This, pdate);
2735 return E_NOTIMPL;
2738 static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *date)
2740 struct file *This = impl_from_IFile(iface);
2741 WIN32_FILE_ATTRIBUTE_DATA attrs;
2743 TRACE("(%p)->(%p)\n", This, date);
2745 if (GetFileAttributesExW(This->path, GetFileExInfoStandard, &attrs))
2746 return get_date_from_filetime(&attrs.ftLastWriteTime, date);
2748 return E_FAIL;
2751 static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
2753 struct file *This = impl_from_IFile(iface);
2754 FIXME("(%p)->(%p)\n", This, pdate);
2755 return E_NOTIMPL;
2758 static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
2760 struct file *This = impl_from_IFile(iface);
2761 ULARGE_INTEGER size;
2762 WIN32_FIND_DATAW fd;
2763 HANDLE f;
2765 TRACE("(%p)->(%p)\n", This, pvarSize);
2767 if(!pvarSize)
2768 return E_POINTER;
2770 f = FindFirstFileW(This->path, &fd);
2771 if(f == INVALID_HANDLE_VALUE)
2772 return create_error(GetLastError());
2773 FindClose(f);
2775 size.u.LowPart = fd.nFileSizeLow;
2776 size.u.HighPart = fd.nFileSizeHigh;
2778 return variant_from_largeint(&size, pvarSize);
2781 static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
2783 struct file *This = impl_from_IFile(iface);
2784 FIXME("(%p)->(%p)\n", This, pbstrType);
2785 return E_NOTIMPL;
2788 static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
2790 struct file *This = impl_from_IFile(iface);
2791 FIXME("(%p)->(%x)\n", This, Force);
2792 return E_NOTIMPL;
2795 static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
2797 struct file *This = impl_from_IFile(iface);
2798 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
2799 return E_NOTIMPL;
2802 static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
2804 struct file *This = impl_from_IFile(iface);
2805 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
2806 return E_NOTIMPL;
2809 static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode mode, Tristate format, ITextStream **stream)
2811 struct file *This = impl_from_IFile(iface);
2813 TRACE("(%p)->(%d %d %p)\n", This, mode, format, stream);
2815 if (format == TristateUseDefault) {
2816 FIXME("default format not handled, defaulting to unicode\n");
2817 format = TristateTrue;
2820 return create_textstream(This->path, OPEN_EXISTING, mode, format == TristateTrue, stream);
2823 static const IFileVtbl file_vtbl = {
2824 file_QueryInterface,
2825 file_AddRef,
2826 file_Release,
2827 file_GetTypeInfoCount,
2828 file_GetTypeInfo,
2829 file_GetIDsOfNames,
2830 file_Invoke,
2831 file_get_Path,
2832 file_get_Name,
2833 file_put_Name,
2834 file_get_ShortPath,
2835 file_get_ShortName,
2836 file_get_Drive,
2837 file_get_ParentFolder,
2838 file_get_Attributes,
2839 file_put_Attributes,
2840 file_get_DateCreated,
2841 file_get_DateLastModified,
2842 file_get_DateLastAccessed,
2843 file_get_Size,
2844 file_get_Type,
2845 file_Delete,
2846 file_Copy,
2847 file_Move,
2848 file_OpenAsTextStream
2851 static HRESULT create_file(BSTR path, IFile **file)
2853 struct file *f;
2854 DWORD len, attrs;
2856 *file = NULL;
2858 f = heap_alloc(sizeof(struct file));
2859 if(!f)
2860 return E_OUTOFMEMORY;
2862 f->IFile_iface.lpVtbl = &file_vtbl;
2863 f->ref = 1;
2865 len = GetFullPathNameW(path, 0, NULL, NULL);
2866 if(!len) {
2867 heap_free(f);
2868 return E_FAIL;
2871 f->path = heap_alloc(len*sizeof(WCHAR));
2872 if(!f->path) {
2873 heap_free(f);
2874 return E_OUTOFMEMORY;
2877 if(!GetFullPathNameW(path, len, f->path, NULL)) {
2878 heap_free(f->path);
2879 heap_free(f);
2880 return E_FAIL;
2883 attrs = GetFileAttributesW(f->path);
2884 if(attrs==INVALID_FILE_ATTRIBUTES ||
2885 (attrs&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))) {
2886 heap_free(f->path);
2887 heap_free(f);
2888 return create_error(GetLastError());
2891 init_classinfo(&CLSID_File, (IUnknown *)&f->IFile_iface, &f->classinfo);
2892 *file = &f->IFile_iface;
2893 return S_OK;
2896 static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
2898 struct filesystem *This = impl_from_IFileSystem3(iface);
2900 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
2902 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
2903 IsEqualGUID( riid, &IID_IFileSystem ) ||
2904 IsEqualGUID( riid, &IID_IDispatch ) ||
2905 IsEqualGUID( riid, &IID_IUnknown ) )
2907 *ppvObject = &This->IFileSystem3_iface;
2909 else if (IsEqualGUID( riid, &IID_IProvideClassInfo ))
2911 *ppvObject = &This->classinfo.IProvideClassInfo_iface;
2913 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
2915 TRACE("Interface IDispatchEx not supported - returning NULL\n");
2916 *ppvObject = NULL;
2917 return E_NOINTERFACE;
2919 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
2921 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
2922 *ppvObject = NULL;
2923 return E_NOINTERFACE;
2925 else
2927 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
2928 return E_NOINTERFACE;
2931 IUnknown_AddRef((IUnknown*)*ppvObject);
2933 return S_OK;
2936 static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
2938 TRACE("%p\n", iface);
2940 return 2;
2943 static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
2945 TRACE("%p\n", iface);
2947 return 1;
2950 static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
2952 TRACE("(%p)->(%p)\n", iface, pctinfo);
2954 *pctinfo = 1;
2955 return S_OK;
2958 static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
2959 LCID lcid, ITypeInfo **ppTInfo)
2961 TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
2962 return get_typeinfo(IFileSystem3_tid, ppTInfo);
2965 static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
2966 LPOLESTR *rgszNames, UINT cNames,
2967 LCID lcid, DISPID *rgDispId)
2969 ITypeInfo *typeinfo;
2970 HRESULT hr;
2972 TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2974 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2975 if(SUCCEEDED(hr))
2977 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2978 ITypeInfo_Release(typeinfo);
2981 return hr;
2984 static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
2985 REFIID riid, LCID lcid, WORD wFlags,
2986 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2987 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2989 ITypeInfo *typeinfo;
2990 HRESULT hr;
2992 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
2993 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2995 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2996 if(SUCCEEDED(hr))
2998 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2999 pDispParams, pVarResult, pExcepInfo, puArgErr);
3000 ITypeInfo_Release(typeinfo);
3003 return hr;
3006 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
3008 TRACE("%p %p\n", iface, ppdrives);
3009 return create_drivecoll(ppdrives);
3012 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
3013 BSTR Name, BSTR *Result)
3015 BSTR ret;
3017 TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
3019 if (!Result) return E_POINTER;
3021 if (Path && Name)
3023 int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
3025 /* if both parts have backslashes strip one from Path */
3026 if (Path[path_len-1] == '\\' && Name[0] == '\\')
3028 path_len -= 1;
3030 ret = SysAllocStringLen(NULL, path_len + name_len);
3031 if (ret)
3033 strcpyW(ret, Path);
3034 ret[path_len] = 0;
3035 strcatW(ret, Name);
3038 else if (Path[path_len-1] != '\\' && Name[0] != '\\')
3040 ret = SysAllocStringLen(NULL, path_len + name_len + 1);
3041 if (ret)
3043 strcpyW(ret, Path);
3044 if (Path[path_len-1] != ':')
3045 strcatW(ret, bsW);
3046 strcatW(ret, Name);
3049 else
3051 ret = SysAllocStringLen(NULL, path_len + name_len);
3052 if (ret)
3054 strcpyW(ret, Path);
3055 strcatW(ret, Name);
3059 else if (Path || Name)
3060 ret = SysAllocString(Path ? Path : Name);
3061 else
3062 ret = SysAllocStringLen(NULL, 0);
3064 if (!ret) return E_OUTOFMEMORY;
3065 *Result = ret;
3067 return S_OK;
3070 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR path, BSTR *drive)
3072 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), drive);
3074 if (!drive)
3075 return E_POINTER;
3077 *drive = NULL;
3079 if (path && strlenW(path) > 1 && path[1] == ':')
3080 *drive = SysAllocStringLen(path, 2);
3082 return S_OK;
3085 static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
3087 int i;
3089 if(!path)
3090 return 0;
3092 for(i=len-1; i>=0; i--)
3093 if(path[i]!='/' && path[i]!='\\')
3094 break;
3096 for(; i>=0; i--)
3097 if(path[i]=='/' || path[i]=='\\')
3098 break;
3100 for(; i>=0; i--)
3101 if(path[i]!='/' && path[i]!='\\')
3102 break;
3104 if(i < 0)
3105 return 0;
3107 if(path[i]==':' && i==1)
3108 i++;
3109 return i+1;
3112 static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
3113 BSTR *pbstrResult)
3115 DWORD len;
3117 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3119 if(!pbstrResult)
3120 return E_POINTER;
3122 len = get_parent_folder_name(Path, SysStringLen(Path));
3123 if(!len) {
3124 *pbstrResult = NULL;
3125 return S_OK;
3128 *pbstrResult = SysAllocStringLen(Path, len);
3129 if(!*pbstrResult)
3130 return E_OUTOFMEMORY;
3131 return S_OK;
3134 static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
3135 BSTR *pbstrResult)
3137 int i, end;
3139 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3141 if(!pbstrResult)
3142 return E_POINTER;
3144 if(!Path) {
3145 *pbstrResult = NULL;
3146 return S_OK;
3149 for(end=strlenW(Path)-1; end>=0; end--)
3150 if(Path[end]!='/' && Path[end]!='\\')
3151 break;
3153 for(i=end; i>=0; i--)
3154 if(Path[i]=='/' || Path[i]=='\\')
3155 break;
3156 i++;
3158 if(i>end || (i==0 && end==1 && Path[1]==':')) {
3159 *pbstrResult = NULL;
3160 return S_OK;
3163 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3164 if(!*pbstrResult)
3165 return E_OUTOFMEMORY;
3166 return S_OK;
3169 static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
3170 BSTR *pbstrResult)
3172 int i, end;
3174 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3176 if(!pbstrResult)
3177 return E_POINTER;
3179 if(!Path) {
3180 *pbstrResult = NULL;
3181 return S_OK;
3184 for(end=strlenW(Path)-1; end>=0; end--)
3185 if(Path[end]!='/' && Path[end]!='\\')
3186 break;
3188 for(i=end; i>=0; i--) {
3189 if(Path[i]=='.' && Path[end+1]!='.')
3190 end = i-1;
3191 if(Path[i]=='/' || Path[i]=='\\')
3192 break;
3194 i++;
3196 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
3197 *pbstrResult = NULL;
3198 return S_OK;
3201 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3202 if(!*pbstrResult)
3203 return E_OUTOFMEMORY;
3204 return S_OK;
3207 static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR path,
3208 BSTR *ext)
3210 INT len;
3212 TRACE("%p %s %p\n", iface, debugstr_w(path), ext);
3214 *ext = NULL;
3215 len = SysStringLen(path);
3216 while (len) {
3217 if (path[len-1] == '.') {
3218 *ext = SysAllocString(&path[len]);
3219 if (!*ext)
3220 return E_OUTOFMEMORY;
3221 break;
3223 len--;
3226 return S_OK;
3229 static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR Path,
3230 BSTR *pbstrResult)
3232 static const WCHAR cur_path[] = {'.',0};
3234 WCHAR buf[MAX_PATH], ch;
3235 const WCHAR *path;
3236 DWORD i, beg, len, exp_len;
3237 WIN32_FIND_DATAW fdata;
3238 HANDLE fh;
3240 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3242 if(!pbstrResult)
3243 return E_POINTER;
3245 if(!Path)
3246 path = cur_path;
3247 else
3248 path = Path;
3250 len = GetFullPathNameW(path, MAX_PATH, buf, NULL);
3251 if(!len)
3252 return E_FAIL;
3254 buf[0] = toupperW(buf[0]);
3255 if(len>3 && buf[len-1] == '\\')
3256 buf[--len] = 0;
3258 for(beg=3, i=3; i<=len; i++) {
3259 if(buf[i]!='\\' && buf[i])
3260 continue;
3262 ch = buf[i];
3263 buf[i] = 0;
3264 fh = FindFirstFileW(buf, &fdata);
3265 if(fh == INVALID_HANDLE_VALUE)
3266 break;
3268 exp_len = strlenW(fdata.cFileName);
3269 if(exp_len == i-beg)
3270 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
3271 FindClose(fh);
3272 buf[i] = ch;
3273 beg = i+1;
3276 *pbstrResult = SysAllocString(buf);
3277 if(!*pbstrResult)
3278 return E_OUTOFMEMORY;
3279 return S_OK;
3282 static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
3284 static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
3286 DWORD random;
3288 TRACE("%p %p\n", iface, pbstrResult);
3290 if(!pbstrResult)
3291 return E_POINTER;
3293 *pbstrResult = SysAllocStringLen(NULL, 12);
3294 if(!*pbstrResult)
3295 return E_OUTOFMEMORY;
3297 if(!RtlGenRandom(&random, sizeof(random)))
3298 return E_FAIL;
3299 sprintfW(*pbstrResult, fmt, random & 0xfffff);
3300 return S_OK;
3303 static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
3304 VARIANT_BOOL *pfExists)
3306 UINT len;
3307 WCHAR driveletter;
3308 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
3310 if (!pfExists) return E_POINTER;
3312 *pfExists = VARIANT_FALSE;
3313 len = SysStringLen(DriveSpec);
3315 if (len >= 1) {
3316 driveletter = toupperW(DriveSpec[0]);
3317 if (driveletter >= 'A' && driveletter <= 'Z'
3318 && (len < 2 || DriveSpec[1] == ':')
3319 && (len < 3 || DriveSpec[2] == '\\')) {
3320 const WCHAR root[] = {driveletter, ':', '\\', 0};
3321 UINT drivetype = GetDriveTypeW(root);
3322 *pfExists = drivetype != DRIVE_NO_ROOT_DIR && drivetype != DRIVE_UNKNOWN ? VARIANT_TRUE : VARIANT_FALSE;
3326 return S_OK;
3329 static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3331 DWORD attrs;
3332 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3334 if (!ret) return E_POINTER;
3336 attrs = GetFileAttributesW(path);
3337 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3338 return S_OK;
3341 static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3343 DWORD attrs;
3344 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3346 if (!ret) return E_POINTER;
3348 attrs = GetFileAttributesW(path);
3349 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3351 return S_OK;
3354 static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
3355 IDrive **ppdrive)
3357 UINT len;
3358 HRESULT hr;
3359 WCHAR driveletter;
3360 VARIANT_BOOL drive_exists;
3362 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
3364 if (!ppdrive)
3365 return E_POINTER;
3367 *ppdrive = NULL;
3369 /* DriveSpec may be one of: 'x', 'x:', 'x:\', '\\computer\share' */
3370 len = SysStringLen(DriveSpec);
3371 if (!len)
3372 return E_INVALIDARG;
3373 else if (len <= 3) {
3374 driveletter = toupperW(DriveSpec[0]);
3375 if (driveletter < 'A' || driveletter > 'Z'
3376 || (len >= 2 && DriveSpec[1] != ':')
3377 || (len == 3 && DriveSpec[2] != '\\'))
3378 return E_INVALIDARG;
3379 hr = IFileSystem3_DriveExists(iface, DriveSpec, &drive_exists);
3380 if (FAILED(hr))
3381 return hr;
3382 if (drive_exists == VARIANT_FALSE)
3383 return CTL_E_DEVICEUNAVAILABLE;
3384 return create_drive(driveletter, ppdrive);
3385 } else {
3386 if (DriveSpec[0] != '\\' || DriveSpec[1] != '\\')
3387 return E_INVALIDARG;
3388 FIXME("%s not implemented yet\n", debugstr_w(DriveSpec));
3389 return E_NOTIMPL;
3393 static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
3394 IFile **ppfile)
3396 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
3398 if(!ppfile)
3399 return E_POINTER;
3400 if(!FilePath)
3401 return E_INVALIDARG;
3403 return create_file(FilePath, ppfile);
3406 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
3407 IFolder **folder)
3409 DWORD attrs;
3411 TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
3413 if(!folder)
3414 return E_POINTER;
3416 *folder = NULL;
3417 if(!FolderPath)
3418 return E_INVALIDARG;
3420 attrs = GetFileAttributesW(FolderPath);
3421 if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
3422 return CTL_E_PATHNOTFOUND;
3424 return create_folder(FolderPath, folder);
3427 static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
3428 SpecialFolderConst SpecialFolder,
3429 IFolder **folder)
3431 WCHAR pathW[MAX_PATH];
3432 DWORD ret;
3434 TRACE("%p %d %p\n", iface, SpecialFolder, folder);
3436 if (!folder)
3437 return E_POINTER;
3439 *folder = NULL;
3441 switch (SpecialFolder)
3443 case WindowsFolder:
3444 ret = GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
3445 break;
3446 case SystemFolder:
3447 ret = GetSystemDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
3448 break;
3449 case TemporaryFolder:
3450 ret = GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
3451 /* we don't want trailing backslash */
3452 if (ret && pathW[ret-1] == '\\')
3453 pathW[ret-1] = 0;
3454 break;
3455 default:
3456 FIXME("unknown special folder type, %d\n", SpecialFolder);
3457 return E_INVALIDARG;
3460 if (!ret)
3461 return HRESULT_FROM_WIN32(GetLastError());
3463 return create_folder(pathW, folder);
3466 static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
3468 WCHAR path[MAX_PATH];
3469 DWORD len, name_len;
3470 WIN32_FIND_DATAW ffd;
3471 HANDLE f;
3473 f = FindFirstFileW(file, &ffd);
3474 if(f == INVALID_HANDLE_VALUE)
3475 return create_error(GetLastError());
3477 len = get_parent_folder_name(file, file_len);
3478 if(len+1 >= MAX_PATH) {
3479 FindClose(f);
3480 return E_FAIL;
3482 if(len) {
3483 memcpy(path, file, len*sizeof(WCHAR));
3484 path[len++] = '\\';
3487 do {
3488 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3489 continue;
3491 name_len = strlenW(ffd.cFileName);
3492 if(len+name_len+1 >= MAX_PATH) {
3493 FindClose(f);
3494 return E_FAIL;
3496 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3498 TRACE("deleting %s\n", debugstr_w(path));
3500 if(!DeleteFileW(path)) {
3501 if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
3502 || !DeleteFileW(path)) {
3503 FindClose(f);
3504 return create_error(GetLastError());
3507 } while(FindNextFileW(f, &ffd));
3508 FindClose(f);
3510 return S_OK;
3513 static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
3514 VARIANT_BOOL Force)
3516 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
3518 if(!FileSpec)
3519 return E_POINTER;
3521 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
3524 static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
3526 WCHAR path[MAX_PATH];
3527 DWORD len, name_len;
3528 WIN32_FIND_DATAW ffd;
3529 HANDLE f;
3530 HRESULT hr;
3532 f = FindFirstFileW(folder, &ffd);
3533 if(f == INVALID_HANDLE_VALUE)
3534 return create_error(GetLastError());
3536 len = get_parent_folder_name(folder, folder_len);
3537 if(len+1 >= MAX_PATH) {
3538 FindClose(f);
3539 return E_FAIL;
3541 if(len) {
3542 memcpy(path, folder, len*sizeof(WCHAR));
3543 path[len++] = '\\';
3546 do {
3547 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3548 continue;
3549 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3550 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3551 continue;
3553 name_len = strlenW(ffd.cFileName);
3554 if(len+name_len+3 >= MAX_PATH) {
3555 FindClose(f);
3556 return E_FAIL;
3558 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
3559 path[len+name_len] = '\\';
3560 path[len+name_len+1] = '*';
3561 path[len+name_len+2] = 0;
3563 hr = delete_file(path, len+name_len+2, force);
3564 if(FAILED(hr)) {
3565 FindClose(f);
3566 return hr;
3569 hr = delete_folder(path, len+name_len+2, force);
3570 if(FAILED(hr)) {
3571 FindClose(f);
3572 return hr;
3575 path[len+name_len] = 0;
3576 TRACE("deleting %s\n", debugstr_w(path));
3578 if(!RemoveDirectoryW(path)) {
3579 FindClose(f);
3580 return create_error(GetLastError());
3582 } while(FindNextFileW(f, &ffd));
3583 FindClose(f);
3585 return S_OK;
3588 static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
3589 VARIANT_BOOL Force)
3591 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
3593 if(!FolderSpec)
3594 return E_POINTER;
3596 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
3599 static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR Source,
3600 BSTR Destination)
3602 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3604 return E_NOTIMPL;
3607 static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
3608 BSTR Destination)
3610 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3612 return E_NOTIMPL;
3615 static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
3616 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
3618 DWORD attrs;
3619 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
3620 DWORD src_len, dst_len, name_len;
3621 WIN32_FIND_DATAW ffd;
3622 HANDLE f;
3623 HRESULT hr;
3625 if(!source[0] || !destination[0])
3626 return E_INVALIDARG;
3628 attrs = GetFileAttributesW(destination);
3629 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
3630 attrs = GetFileAttributesW(source);
3631 if(attrs == INVALID_FILE_ATTRIBUTES)
3632 return create_error(GetLastError());
3633 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
3634 return CTL_E_FILENOTFOUND;
3636 if(!CopyFileW(source, destination, !overwrite))
3637 return create_error(GetLastError());
3638 return S_OK;
3641 f = FindFirstFileW(source, &ffd);
3642 if(f == INVALID_HANDLE_VALUE)
3643 return CTL_E_FILENOTFOUND;
3645 src_len = get_parent_folder_name(source, source_len);
3646 if(src_len+1 >= MAX_PATH) {
3647 FindClose(f);
3648 return E_FAIL;
3650 if(src_len) {
3651 memcpy(src_path, source, src_len*sizeof(WCHAR));
3652 src_path[src_len++] = '\\';
3655 dst_len = destination_len;
3656 if(dst_len+1 >= MAX_PATH) {
3657 FindClose(f);
3658 return E_FAIL;
3660 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
3661 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
3662 dst_path[dst_len++] = '\\';
3664 hr = CTL_E_FILENOTFOUND;
3665 do {
3666 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3667 continue;
3669 name_len = strlenW(ffd.cFileName);
3670 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
3671 FindClose(f);
3672 return E_FAIL;
3674 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3675 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3677 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
3679 if(!CopyFileW(src_path, dst_path, !overwrite)) {
3680 FindClose(f);
3681 return create_error(GetLastError());
3682 }else {
3683 hr = S_OK;
3685 } while(FindNextFileW(f, &ffd));
3686 FindClose(f);
3688 return hr;
3691 static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
3692 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3694 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3696 if(!Source || !Destination)
3697 return E_POINTER;
3699 return copy_file(Source, SysStringLen(Source), Destination,
3700 SysStringLen(Destination), OverWriteFiles);
3703 static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
3704 DWORD destination_len, VARIANT_BOOL overwrite)
3706 DWORD tmp, src_len, dst_len, name_len;
3707 WCHAR src[MAX_PATH], dst[MAX_PATH];
3708 WIN32_FIND_DATAW ffd;
3709 HANDLE f;
3710 HRESULT hr;
3711 BOOL copied = FALSE;
3713 if(!source[0] || !destination[0])
3714 return E_INVALIDARG;
3716 dst_len = destination_len;
3717 if(dst_len+1 >= MAX_PATH)
3718 return E_FAIL;
3719 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
3721 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
3722 (tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
3723 tmp&FILE_ATTRIBUTE_DIRECTORY) {
3724 if(!CreateDirectoryW(dst, NULL)) {
3725 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3726 tmp = GetFileAttributesW(dst);
3727 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
3728 return CTL_E_FILEALREADYEXISTS;
3729 }else {
3730 return create_error(GetLastError());
3733 copied = TRUE;
3735 src_len = source_len;
3736 if(src_len+2 >= MAX_PATH)
3737 return E_FAIL;
3738 memcpy(src, source, src_len*sizeof(WCHAR));
3739 src[src_len++] = '\\';
3740 src[src_len] = '*';
3741 src[src_len+1] = 0;
3743 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
3744 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
3745 return create_error(GetLastError());
3747 f = FindFirstFileW(src, &ffd);
3748 }else {
3749 src_len = get_parent_folder_name(source, source_len);
3750 if(src_len+2 >= MAX_PATH)
3751 return E_FAIL;
3752 memcpy(src, source, src_len*sizeof(WCHAR));
3753 if(src_len)
3754 src[src_len++] = '\\';
3756 f = FindFirstFileW(source, &ffd);
3758 if(f == INVALID_HANDLE_VALUE)
3759 return CTL_E_PATHNOTFOUND;
3761 dst[dst_len++] = '\\';
3762 dst[dst_len] = 0;
3764 do {
3765 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3766 continue;
3767 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3768 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3769 continue;
3771 name_len = strlenW(ffd.cFileName);
3772 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
3773 FindClose(f);
3774 return E_FAIL;
3776 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
3777 dst[dst_len+name_len] = 0;
3778 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
3779 src[src_len+name_len] = '\\';
3780 src[src_len+name_len+1] = '*';
3781 src[src_len+name_len+2] = 0;
3783 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
3785 if(!CreateDirectoryW(dst, NULL)) {
3786 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3787 tmp = GetFileAttributesW(dst);
3788 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
3789 FindClose(f);
3790 return CTL_E_FILEALREADYEXISTS;
3794 FindClose(f);
3795 return create_error(GetLastError());
3797 copied = TRUE;
3799 hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3800 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
3801 FindClose(f);
3802 return hr;
3805 hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3806 if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
3807 FindClose(f);
3808 return hr;
3810 } while(FindNextFileW(f, &ffd));
3811 FindClose(f);
3813 return copied ? S_OK : CTL_E_PATHNOTFOUND;
3816 static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
3817 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3819 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3821 if(!Source || !Destination)
3822 return E_POINTER;
3824 return copy_folder(Source, SysStringLen(Source), Destination,
3825 SysStringLen(Destination), OverWriteFiles);
3828 static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
3829 IFolder **folder)
3831 BOOL ret;
3833 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
3835 ret = CreateDirectoryW(path, NULL);
3836 if (!ret)
3838 *folder = NULL;
3839 if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
3840 return HRESULT_FROM_WIN32(GetLastError());
3843 return create_folder(path, folder);
3846 static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR filename,
3847 VARIANT_BOOL overwrite, VARIANT_BOOL unicode,
3848 ITextStream **stream)
3850 DWORD disposition;
3852 TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
3854 disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
3855 return create_textstream(filename, disposition, ForWriting, !!unicode, stream);
3858 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
3859 IOMode mode, VARIANT_BOOL create,
3860 Tristate format, ITextStream **stream)
3862 DWORD disposition;
3864 TRACE("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
3865 disposition = create == VARIANT_TRUE ? OPEN_ALWAYS : OPEN_EXISTING;
3867 if (format == TristateUseDefault) {
3868 FIXME("default format not handled, defaulting to unicode\n");
3869 format = TristateTrue;
3872 return create_textstream(filename, disposition, mode, format == TristateTrue, stream);
3875 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
3876 StandardStreamTypes StandardStreamType,
3877 VARIANT_BOOL Unicode,
3878 ITextStream **ppts)
3880 FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
3882 return E_NOTIMPL;
3885 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
3887 static const WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
3888 DWORDLONG version;
3889 WORD a, b, c, d;
3891 version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
3892 a = (WORD)( version >> 48);
3893 b = (WORD)((version >> 32) & 0xffff);
3894 c = (WORD)((version >> 16) & 0xffff);
3895 d = (WORD)( version & 0xffff);
3897 sprintfW(ver, fmtW, a, b, c, d);
3900 static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
3902 static const WCHAR rootW[] = {'\\',0};
3903 VS_FIXEDFILEINFO *info;
3904 WCHAR ver[30];
3905 void *ptr;
3906 DWORD len;
3907 BOOL ret;
3909 TRACE("%p %s %p\n", iface, debugstr_w(name), version);
3911 len = GetFileVersionInfoSizeW(name, NULL);
3912 if (!len)
3913 return HRESULT_FROM_WIN32(GetLastError());
3915 ptr = heap_alloc(len);
3916 if (!GetFileVersionInfoW(name, 0, len, ptr))
3918 heap_free(ptr);
3919 return HRESULT_FROM_WIN32(GetLastError());
3922 ret = VerQueryValueW(ptr, rootW, (void**)&info, &len);
3923 if (!ret)
3925 heap_free(ptr);
3926 return HRESULT_FROM_WIN32(GetLastError());
3929 get_versionstring(info, ver);
3930 heap_free(ptr);
3932 *version = SysAllocString(ver);
3933 TRACE("version=%s\n", debugstr_w(ver));
3935 return S_OK;
3938 static const struct IFileSystem3Vtbl filesys_vtbl =
3940 filesys_QueryInterface,
3941 filesys_AddRef,
3942 filesys_Release,
3943 filesys_GetTypeInfoCount,
3944 filesys_GetTypeInfo,
3945 filesys_GetIDsOfNames,
3946 filesys_Invoke,
3947 filesys_get_Drives,
3948 filesys_BuildPath,
3949 filesys_GetDriveName,
3950 filesys_GetParentFolderName,
3951 filesys_GetFileName,
3952 filesys_GetBaseName,
3953 filesys_GetExtensionName,
3954 filesys_GetAbsolutePathName,
3955 filesys_GetTempName,
3956 filesys_DriveExists,
3957 filesys_FileExists,
3958 filesys_FolderExists,
3959 filesys_GetDrive,
3960 filesys_GetFile,
3961 filesys_GetFolder,
3962 filesys_GetSpecialFolder,
3963 filesys_DeleteFile,
3964 filesys_DeleteFolder,
3965 filesys_MoveFile,
3966 filesys_MoveFolder,
3967 filesys_CopyFile,
3968 filesys_CopyFolder,
3969 filesys_CreateFolder,
3970 filesys_CreateTextFile,
3971 filesys_OpenTextFile,
3972 filesys_GetStandardStream,
3973 filesys_GetFileVersion
3976 static struct filesystem filesystem;
3978 HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
3980 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
3982 filesystem.IFileSystem3_iface.lpVtbl = &filesys_vtbl;
3983 init_classinfo(&CLSID_FileSystemObject, (IUnknown *)&filesystem.IFileSystem3_iface, &filesystem.classinfo);
3984 return IFileSystem3_QueryInterface(&filesystem.IFileSystem3_iface, riid, ppv);