ddraw/tests: Rewrite StructSizeTest().
[wine.git] / dlls / scrrun / filesystem.c
blob45040b36a12003fcb770bf714280e3aed25efcd0
1 /*
2 * Copyright 2012 Alistair Leslie-Hughes
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include "config.h"
22 #include <stdarg.h>
23 #include <limits.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "ole2.h"
28 #include "olectl.h"
29 #include "dispex.h"
30 #include "ntsecapi.h"
31 #include "scrrun.h"
32 #include "scrrun_private.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
39 static const WCHAR bsW[] = {'\\',0};
40 static const WCHAR utf16bom = 0xfeff;
42 struct filesystem {
43 struct provideclassinfo classinfo;
44 IFileSystem3 IFileSystem3_iface;
47 struct foldercollection {
48 struct provideclassinfo classinfo;
49 IFolderCollection IFolderCollection_iface;
50 LONG ref;
51 BSTR path;
54 struct filecollection {
55 struct provideclassinfo classinfo;
56 IFileCollection IFileCollection_iface;
57 LONG ref;
58 BSTR path;
61 struct drivecollection {
62 struct provideclassinfo classinfo;
63 IDriveCollection IDriveCollection_iface;
64 LONG ref;
65 DWORD drives;
66 LONG count;
69 struct enumdata {
70 union
72 struct
74 struct foldercollection *coll;
75 HANDLE find;
76 } foldercoll;
77 struct
79 struct filecollection *coll;
80 HANDLE find;
81 } filecoll;
82 struct
84 struct drivecollection *coll;
85 INT cur;
86 } drivecoll;
87 } u;
90 struct enumvariant {
91 IEnumVARIANT IEnumVARIANT_iface;
92 LONG ref;
94 struct enumdata data;
97 struct drive {
98 struct provideclassinfo classinfo;
99 IDrive IDrive_iface;
100 LONG ref;
101 BSTR root;
104 struct folder {
105 struct provideclassinfo classinfo;
106 IFolder IFolder_iface;
107 LONG ref;
108 BSTR path;
111 struct file {
112 struct provideclassinfo classinfo;
113 IFile IFile_iface;
114 LONG ref;
116 WCHAR *path;
119 struct textstream {
120 struct provideclassinfo classinfo;
121 ITextStream ITextStream_iface;
122 LONG ref;
124 IOMode mode;
125 BOOL unicode;
126 BOOL first_read;
127 LARGE_INTEGER size;
128 HANDLE file;
131 enum iotype {
132 IORead,
133 IOWrite
136 static inline struct filesystem *impl_from_IFileSystem3(IFileSystem3 *iface)
138 return CONTAINING_RECORD(iface, struct filesystem, IFileSystem3_iface);
141 static inline struct drive *impl_from_IDrive(IDrive *iface)
143 return CONTAINING_RECORD(iface, struct drive, IDrive_iface);
146 static inline struct folder *impl_from_IFolder(IFolder *iface)
148 return CONTAINING_RECORD(iface, struct folder, IFolder_iface);
151 static inline struct file *impl_from_IFile(IFile *iface)
153 return CONTAINING_RECORD(iface, struct file, IFile_iface);
156 static inline struct textstream *impl_from_ITextStream(ITextStream *iface)
158 return CONTAINING_RECORD(iface, struct textstream, ITextStream_iface);
161 static inline struct foldercollection *impl_from_IFolderCollection(IFolderCollection *iface)
163 return CONTAINING_RECORD(iface, struct foldercollection, IFolderCollection_iface);
166 static inline struct filecollection *impl_from_IFileCollection(IFileCollection *iface)
168 return CONTAINING_RECORD(iface, struct filecollection, IFileCollection_iface);
171 static inline struct drivecollection *impl_from_IDriveCollection(IDriveCollection *iface)
173 return CONTAINING_RECORD(iface, struct drivecollection, IDriveCollection_iface);
176 static inline struct enumvariant *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
178 return CONTAINING_RECORD(iface, struct enumvariant, IEnumVARIANT_iface);
181 static inline HRESULT create_error(DWORD err)
183 switch(err) {
184 case ERROR_FILE_NOT_FOUND: return CTL_E_FILENOTFOUND;
185 case ERROR_PATH_NOT_FOUND: return CTL_E_PATHNOTFOUND;
186 case ERROR_ACCESS_DENIED: return CTL_E_PERMISSIONDENIED;
187 case ERROR_FILE_EXISTS: return CTL_E_FILEALREADYEXISTS;
188 case ERROR_ALREADY_EXISTS: return CTL_E_FILEALREADYEXISTS;
189 default:
190 FIXME("Unsupported error code: %d\n", err);
191 return E_FAIL;
195 static HRESULT create_folder(const WCHAR*, IFolder**);
196 static HRESULT create_file(BSTR, IFile**);
197 static HRESULT create_foldercoll_enum(struct foldercollection*, IUnknown**);
198 static HRESULT create_filecoll_enum(struct filecollection*, IUnknown**);
200 static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data)
202 static const WCHAR dotdotW[] = {'.','.',0};
203 static const WCHAR dotW[] = {'.',0};
205 return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
206 strcmpW(data->cFileName, dotdotW) &&
207 strcmpW(data->cFileName, dotW);
210 static inline BOOL is_file_data(const WIN32_FIND_DATAW *data)
212 return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
215 static BSTR get_full_path(BSTR path, const WIN32_FIND_DATAW *data)
217 int len = SysStringLen(path);
218 WCHAR buffW[MAX_PATH];
220 strcpyW(buffW, path);
221 if (path[len-1] != '\\')
222 strcatW(buffW, bsW);
223 strcatW(buffW, data->cFileName);
225 return SysAllocString(buffW);
228 static BOOL textstream_check_iomode(struct textstream *This, enum iotype type)
230 if (type == IORead)
231 return This->mode == ForWriting || This->mode == ForAppending;
232 else
233 return This->mode == ForReading;
236 static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
238 struct textstream *This = impl_from_ITextStream(iface);
240 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
242 if (IsEqualIID(riid, &IID_ITextStream) ||
243 IsEqualIID(riid, &IID_IDispatch) ||
244 IsEqualIID(riid, &IID_IUnknown))
246 *obj = &This->ITextStream_iface;
248 else if (IsEqualIID(riid, &IID_IProvideClassInfo))
250 *obj = &This->classinfo.IProvideClassInfo_iface;
252 else
253 return E_NOINTERFACE;
255 IUnknown_AddRef((IUnknown*)*obj);
256 return S_OK;
259 static ULONG WINAPI textstream_AddRef(ITextStream *iface)
261 struct textstream *This = impl_from_ITextStream(iface);
262 ULONG ref = InterlockedIncrement(&This->ref);
263 TRACE("(%p)->(%d)\n", This, ref);
264 return ref;
267 static ULONG WINAPI textstream_Release(ITextStream *iface)
269 struct textstream *This = impl_from_ITextStream(iface);
270 ULONG ref = InterlockedDecrement(&This->ref);
271 TRACE("(%p)->(%d)\n", This, ref);
273 if (!ref)
275 CloseHandle(This->file);
276 heap_free(This);
279 return ref;
282 static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
284 struct textstream *This = impl_from_ITextStream(iface);
285 TRACE("(%p)->(%p)\n", This, pctinfo);
286 *pctinfo = 1;
287 return S_OK;
290 static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
291 LCID lcid, ITypeInfo **ppTInfo)
293 struct textstream *This = impl_from_ITextStream(iface);
294 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
295 return get_typeinfo(ITextStream_tid, ppTInfo);
298 static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
299 LPOLESTR *rgszNames, UINT cNames,
300 LCID lcid, DISPID *rgDispId)
302 struct textstream *This = impl_from_ITextStream(iface);
303 ITypeInfo *typeinfo;
304 HRESULT hr;
306 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
308 hr = get_typeinfo(ITextStream_tid, &typeinfo);
309 if(SUCCEEDED(hr))
311 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
312 ITypeInfo_Release(typeinfo);
315 return hr;
318 static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
319 REFIID riid, LCID lcid, WORD wFlags,
320 DISPPARAMS *pDispParams, VARIANT *pVarResult,
321 EXCEPINFO *pExcepInfo, UINT *puArgErr)
323 struct textstream *This = impl_from_ITextStream(iface);
324 ITypeInfo *typeinfo;
325 HRESULT hr;
327 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
328 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
330 hr = get_typeinfo(ITextStream_tid, &typeinfo);
331 if(SUCCEEDED(hr))
333 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
334 pDispParams, pVarResult, pExcepInfo, puArgErr);
335 ITypeInfo_Release(typeinfo);
338 return hr;
341 static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
343 struct textstream *This = impl_from_ITextStream(iface);
344 FIXME("(%p)->(%p): stub\n", This, line);
345 return E_NOTIMPL;
348 static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
350 struct textstream *This = impl_from_ITextStream(iface);
351 FIXME("(%p)->(%p): stub\n", This, column);
352 return E_NOTIMPL;
355 static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
357 struct textstream *This = impl_from_ITextStream(iface);
358 LARGE_INTEGER pos, dist;
360 TRACE("(%p)->(%p)\n", This, eos);
362 if (!eos)
363 return E_POINTER;
365 if (textstream_check_iomode(This, IORead)) {
366 *eos = VARIANT_TRUE;
367 return CTL_E_BADFILEMODE;
370 dist.QuadPart = 0;
371 if (!SetFilePointerEx(This->file, dist, &pos, FILE_CURRENT))
372 return E_FAIL;
374 *eos = This->size.QuadPart == pos.QuadPart ? VARIANT_TRUE : VARIANT_FALSE;
375 return S_OK;
378 static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
380 struct textstream *This = impl_from_ITextStream(iface);
381 FIXME("(%p)->(%p): stub\n", This, eol);
382 return E_NOTIMPL;
386 Reads 'toread' bytes from a file, converts if needed
387 BOM is skipped if 'bof' is set.
389 static HRESULT textstream_read(struct textstream *stream, LONG toread, BOOL bof, BSTR *text)
391 HRESULT hr = S_OK;
392 DWORD read;
393 char *buff;
394 BOOL ret;
396 if (toread == 0) {
397 *text = SysAllocStringLen(NULL, 0);
398 return *text ? S_FALSE : E_OUTOFMEMORY;
401 if (toread < sizeof(WCHAR))
402 return CTL_E_ENDOFFILE;
404 buff = heap_alloc(toread);
405 if (!buff)
406 return E_OUTOFMEMORY;
408 ret = ReadFile(stream->file, buff, toread, &read, NULL);
409 if (!ret || toread != read) {
410 WARN("failed to read from file %d, %d, error %d\n", read, toread, GetLastError());
411 heap_free(buff);
412 return E_FAIL;
415 if (stream->unicode) {
416 int i = 0;
418 /* skip BOM */
419 if (bof && *(WCHAR*)buff == utf16bom) {
420 read -= sizeof(WCHAR);
421 i += sizeof(WCHAR);
424 *text = SysAllocStringLen(read ? (WCHAR*)&buff[i] : NULL, read/sizeof(WCHAR));
425 if (!*text) hr = E_OUTOFMEMORY;
427 else {
428 INT len = MultiByteToWideChar(CP_ACP, 0, buff, read, NULL, 0);
429 *text = SysAllocStringLen(NULL, len);
430 if (*text)
431 MultiByteToWideChar(CP_ACP, 0, buff, read, *text, len);
432 else
433 hr = E_OUTOFMEMORY;
435 heap_free(buff);
437 return hr;
440 static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
442 struct textstream *This = impl_from_ITextStream(iface);
443 LARGE_INTEGER start, end, dist;
444 DWORD toread;
445 HRESULT hr;
447 TRACE("(%p)->(%d %p)\n", This, len, text);
449 if (!text)
450 return E_POINTER;
452 *text = NULL;
453 if (len <= 0)
454 return len == 0 ? S_OK : E_INVALIDARG;
456 if (textstream_check_iomode(This, IORead))
457 return CTL_E_BADFILEMODE;
459 if (!This->first_read) {
460 VARIANT_BOOL eos;
462 /* check for EOF */
463 hr = ITextStream_get_AtEndOfStream(iface, &eos);
464 if (FAILED(hr))
465 return hr;
467 if (eos == VARIANT_TRUE)
468 return CTL_E_ENDOFFILE;
471 /* read everything from current position */
472 dist.QuadPart = 0;
473 SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
474 SetFilePointerEx(This->file, dist, &end, FILE_END);
475 toread = end.QuadPart - start.QuadPart;
476 /* rewind back */
477 dist.QuadPart = start.QuadPart;
478 SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
480 This->first_read = FALSE;
481 if (This->unicode) len *= sizeof(WCHAR);
483 hr = textstream_read(This, min(toread, len), start.QuadPart == 0, text);
484 if (FAILED(hr))
485 return hr;
486 else
487 return toread <= len ? S_FALSE : S_OK;
490 static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
492 struct textstream *This = impl_from_ITextStream(iface);
493 VARIANT_BOOL eos;
494 HRESULT hr;
496 FIXME("(%p)->(%p): stub\n", This, text);
498 if (!text)
499 return E_POINTER;
501 *text = NULL;
502 if (textstream_check_iomode(This, IORead))
503 return CTL_E_BADFILEMODE;
505 /* check for EOF */
506 hr = ITextStream_get_AtEndOfStream(iface, &eos);
507 if (FAILED(hr))
508 return hr;
510 if (eos == VARIANT_TRUE)
511 return CTL_E_ENDOFFILE;
513 return E_NOTIMPL;
516 static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
518 struct textstream *This = impl_from_ITextStream(iface);
519 LARGE_INTEGER start, end, dist;
520 DWORD toread;
521 HRESULT hr;
523 TRACE("(%p)->(%p)\n", This, text);
525 if (!text)
526 return E_POINTER;
528 *text = NULL;
529 if (textstream_check_iomode(This, IORead))
530 return CTL_E_BADFILEMODE;
532 if (!This->first_read) {
533 VARIANT_BOOL eos;
535 /* check for EOF */
536 hr = ITextStream_get_AtEndOfStream(iface, &eos);
537 if (FAILED(hr))
538 return hr;
540 if (eos == VARIANT_TRUE)
541 return CTL_E_ENDOFFILE;
544 /* read everything from current position */
545 dist.QuadPart = 0;
546 SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
547 SetFilePointerEx(This->file, dist, &end, FILE_END);
548 toread = end.QuadPart - start.QuadPart;
549 /* rewind back */
550 dist.QuadPart = start.QuadPart;
551 SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
553 This->first_read = FALSE;
555 hr = textstream_read(This, toread, start.QuadPart == 0, text);
556 return FAILED(hr) ? hr : S_FALSE;
559 static HRESULT textstream_writestr(struct textstream *stream, BSTR text)
561 DWORD written = 0;
562 BOOL ret;
564 if (stream->unicode) {
565 ret = WriteFile(stream->file, text, SysStringByteLen(text), &written, NULL);
566 return (ret && written == SysStringByteLen(text)) ? S_OK : create_error(GetLastError());
567 } else {
568 DWORD len = WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), NULL, 0, NULL, NULL);
569 char *buffA;
570 HRESULT hr;
572 buffA = heap_alloc(len);
573 if (!buffA)
574 return E_OUTOFMEMORY;
576 WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), buffA, len, NULL, NULL);
577 ret = WriteFile(stream->file, buffA, len, &written, NULL);
578 hr = (ret && written == len) ? S_OK : create_error(GetLastError());
579 heap_free(buffA);
580 return hr;
584 static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
586 struct textstream *This = impl_from_ITextStream(iface);
588 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
590 if (textstream_check_iomode(This, IOWrite))
591 return CTL_E_BADFILEMODE;
593 return textstream_writestr(This, text);
596 static HRESULT textstream_writecrlf(struct textstream *stream)
598 static const WCHAR crlfW[] = {'\r','\n'};
599 static const char crlfA[] = {'\r','\n'};
600 DWORD written = 0, len;
601 const void *ptr;
602 BOOL ret;
604 if (stream->unicode) {
605 ptr = crlfW;
606 len = sizeof(crlfW);
608 else {
609 ptr = crlfA;
610 len = sizeof(crlfA);
613 ret = WriteFile(stream->file, ptr, len, &written, NULL);
614 return (ret && written == len) ? S_OK : create_error(GetLastError());
617 static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
619 struct textstream *This = impl_from_ITextStream(iface);
620 HRESULT hr;
622 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
624 if (textstream_check_iomode(This, IOWrite))
625 return CTL_E_BADFILEMODE;
627 hr = textstream_writestr(This, text);
628 if (SUCCEEDED(hr))
629 hr = textstream_writecrlf(This);
630 return hr;
633 static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
635 struct textstream *This = impl_from_ITextStream(iface);
636 FIXME("(%p)->(%d): stub\n", This, lines);
637 return E_NOTIMPL;
640 static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
642 struct textstream *This = impl_from_ITextStream(iface);
643 FIXME("(%p)->(%d): stub\n", This, count);
644 return E_NOTIMPL;
647 static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
649 struct textstream *This = impl_from_ITextStream(iface);
650 FIXME("(%p): stub\n", This);
651 return E_NOTIMPL;
654 static HRESULT WINAPI textstream_Close(ITextStream *iface)
656 struct textstream *This = impl_from_ITextStream(iface);
657 HRESULT hr = S_OK;
659 TRACE("(%p)\n", This);
661 if(!CloseHandle(This->file))
662 hr = S_FALSE;
664 This->file = NULL;
666 return hr;
669 static const ITextStreamVtbl textstreamvtbl = {
670 textstream_QueryInterface,
671 textstream_AddRef,
672 textstream_Release,
673 textstream_GetTypeInfoCount,
674 textstream_GetTypeInfo,
675 textstream_GetIDsOfNames,
676 textstream_Invoke,
677 textstream_get_Line,
678 textstream_get_Column,
679 textstream_get_AtEndOfStream,
680 textstream_get_AtEndOfLine,
681 textstream_Read,
682 textstream_ReadLine,
683 textstream_ReadAll,
684 textstream_Write,
685 textstream_WriteLine,
686 textstream_WriteBlankLines,
687 textstream_Skip,
688 textstream_SkipLine,
689 textstream_Close
692 static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMode mode, BOOL unicode, ITextStream **ret)
694 struct textstream *stream;
695 DWORD access = 0;
697 /* map access mode */
698 switch (mode)
700 case ForReading:
701 access = GENERIC_READ;
702 break;
703 case ForWriting:
704 access = GENERIC_WRITE;
705 break;
706 case ForAppending:
707 access = FILE_APPEND_DATA;
708 break;
709 default:
710 return E_INVALIDARG;
713 stream = heap_alloc(sizeof(struct textstream));
714 if (!stream) return E_OUTOFMEMORY;
716 stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
717 stream->ref = 1;
718 stream->mode = mode;
719 stream->unicode = unicode;
720 stream->first_read = TRUE;
722 stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
723 if (stream->file == INVALID_HANDLE_VALUE)
725 HRESULT hr = create_error(GetLastError());
726 heap_free(stream);
727 return hr;
730 if (mode == ForReading)
731 GetFileSizeEx(stream->file, &stream->size);
732 else
733 stream->size.QuadPart = 0;
735 /* Write Unicode BOM */
736 if (unicode && mode == ForWriting && (disposition == CREATE_ALWAYS || disposition == CREATE_NEW)) {
737 DWORD written = 0;
738 BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL);
739 if (!ret || written != sizeof(utf16bom)) {
740 ITextStream_Release(&stream->ITextStream_iface);
741 return create_error(GetLastError());
745 init_classinfo(&CLSID_TextStream, (IUnknown *)&stream->ITextStream_iface, &stream->classinfo);
746 *ret = &stream->ITextStream_iface;
747 return S_OK;
750 static HRESULT WINAPI drive_QueryInterface(IDrive *iface, REFIID riid, void **obj)
752 struct drive *This = impl_from_IDrive(iface);
754 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
756 *obj = NULL;
758 if (IsEqualIID( riid, &IID_IDrive ) ||
759 IsEqualIID( riid, &IID_IDispatch ) ||
760 IsEqualIID( riid, &IID_IUnknown))
762 *obj = &This->IDrive_iface;
764 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
766 *obj = &This->classinfo.IProvideClassInfo_iface;
768 else
769 return E_NOINTERFACE;
771 IUnknown_AddRef((IUnknown*)*obj);
772 return S_OK;
775 static ULONG WINAPI drive_AddRef(IDrive *iface)
777 struct drive *This = impl_from_IDrive(iface);
778 ULONG ref = InterlockedIncrement(&This->ref);
779 TRACE("(%p)->(%d)\n", This, ref);
780 return ref;
783 static ULONG WINAPI drive_Release(IDrive *iface)
785 struct drive *This = impl_from_IDrive(iface);
786 ULONG ref = InterlockedDecrement(&This->ref);
787 TRACE("(%p)->(%d)\n", This, ref);
789 if (!ref)
791 SysFreeString(This->root);
792 heap_free(This);
795 return ref;
798 static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo)
800 struct drive *This = impl_from_IDrive(iface);
801 TRACE("(%p)->(%p)\n", This, pctinfo);
802 *pctinfo = 1;
803 return S_OK;
806 static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo,
807 LCID lcid, ITypeInfo **ppTInfo)
809 struct drive *This = impl_from_IDrive(iface);
810 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
811 return get_typeinfo(IDrive_tid, ppTInfo);
814 static HRESULT WINAPI drive_GetIDsOfNames(IDrive *iface, REFIID riid,
815 LPOLESTR *rgszNames, UINT cNames,
816 LCID lcid, DISPID *rgDispId)
818 struct drive *This = impl_from_IDrive(iface);
819 ITypeInfo *typeinfo;
820 HRESULT hr;
822 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
824 hr = get_typeinfo(IDrive_tid, &typeinfo);
825 if(SUCCEEDED(hr))
827 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
828 ITypeInfo_Release(typeinfo);
831 return hr;
834 static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember,
835 REFIID riid, LCID lcid, WORD wFlags,
836 DISPPARAMS *pDispParams, VARIANT *pVarResult,
837 EXCEPINFO *pExcepInfo, UINT *puArgErr)
839 struct drive *This = impl_from_IDrive(iface);
840 ITypeInfo *typeinfo;
841 HRESULT hr;
843 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
844 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
846 hr = get_typeinfo(IDrive_tid, &typeinfo);
847 if(SUCCEEDED(hr))
849 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
850 pDispParams, pVarResult, pExcepInfo, puArgErr);
851 ITypeInfo_Release(typeinfo);
854 return hr;
857 static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path)
859 struct drive *This = impl_from_IDrive(iface);
860 FIXME("(%p)->(%p): stub\n", This, path);
861 return E_NOTIMPL;
864 static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter)
866 struct drive *This = impl_from_IDrive(iface);
868 TRACE("(%p)->(%p)\n", This, letter);
870 if (!letter)
871 return E_POINTER;
873 *letter = SysAllocStringLen(This->root, 1);
874 if (!*letter)
875 return E_OUTOFMEMORY;
877 return S_OK;
880 static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name)
882 struct drive *This = impl_from_IDrive(iface);
883 FIXME("(%p)->(%p): stub\n", This, share_name);
884 return E_NOTIMPL;
887 static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type)
889 struct drive *This = impl_from_IDrive(iface);
891 TRACE("(%p)->(%p)\n", This, type);
893 switch (GetDriveTypeW(This->root))
895 case DRIVE_REMOVABLE:
896 *type = Removable;
897 break;
898 case DRIVE_FIXED:
899 *type = Fixed;
900 break;
901 case DRIVE_REMOTE:
902 *type = Remote;
903 break;
904 case DRIVE_CDROM:
905 *type = CDRom;
906 break;
907 case DRIVE_RAMDISK:
908 *type = RamDisk;
909 break;
910 default:
911 *type = UnknownType;
912 break;
915 return S_OK;
918 static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder)
920 struct drive *This = impl_from_IDrive(iface);
921 FIXME("(%p)->(%p): stub\n", This, folder);
922 return E_NOTIMPL;
925 static HRESULT variant_from_largeint(const ULARGE_INTEGER *src, VARIANT *v)
927 HRESULT hr = S_OK;
929 if (src->u.HighPart || src->u.LowPart > INT_MAX)
931 V_VT(v) = VT_R8;
932 hr = VarR8FromUI8(src->QuadPart, &V_R8(v));
934 else
936 V_VT(v) = VT_I4;
937 V_I4(v) = src->u.LowPart;
940 return hr;
943 static HRESULT WINAPI drive_get_AvailableSpace(IDrive *iface, VARIANT *v)
945 struct drive *This = impl_from_IDrive(iface);
946 ULARGE_INTEGER avail;
948 TRACE("(%p)->(%p)\n", This, v);
950 if (!v)
951 return E_POINTER;
953 if (!GetDiskFreeSpaceExW(This->root, &avail, NULL, NULL))
954 return E_FAIL;
956 return variant_from_largeint(&avail, v);
959 static HRESULT WINAPI drive_get_FreeSpace(IDrive *iface, VARIANT *v)
961 struct drive *This = impl_from_IDrive(iface);
962 ULARGE_INTEGER freespace;
964 TRACE("(%p)->(%p)\n", This, v);
966 if (!v)
967 return E_POINTER;
969 if (!GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL))
970 return E_FAIL;
972 return variant_from_largeint(&freespace, v);
975 static HRESULT WINAPI drive_get_TotalSize(IDrive *iface, VARIANT *v)
977 struct drive *This = impl_from_IDrive(iface);
978 ULARGE_INTEGER total;
980 TRACE("(%p)->(%p)\n", This, v);
982 if (!v)
983 return E_POINTER;
985 if (!GetDiskFreeSpaceExW(This->root, NULL, &total, NULL))
986 return E_FAIL;
988 return variant_from_largeint(&total, v);
991 static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name)
993 struct drive *This = impl_from_IDrive(iface);
994 WCHAR nameW[MAX_PATH+1];
995 BOOL ret;
997 TRACE("(%p)->(%p)\n", This, name);
999 if (!name)
1000 return E_POINTER;
1002 *name = NULL;
1003 ret = GetVolumeInformationW(This->root, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, NULL, NULL, NULL, 0);
1004 if (ret)
1005 *name = SysAllocString(nameW);
1006 return ret ? S_OK : E_FAIL;
1009 static HRESULT WINAPI drive_put_VolumeName(IDrive *iface, BSTR name)
1011 struct drive *This = impl_from_IDrive(iface);
1012 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
1013 return E_NOTIMPL;
1016 static HRESULT WINAPI drive_get_FileSystem(IDrive *iface, BSTR *fs)
1018 struct drive *This = impl_from_IDrive(iface);
1019 WCHAR nameW[MAX_PATH+1];
1020 BOOL ret;
1022 TRACE("(%p)->(%p)\n", This, fs);
1024 if (!fs)
1025 return E_POINTER;
1027 *fs = NULL;
1028 ret = GetVolumeInformationW(This->root, NULL, 0, NULL, NULL, NULL, nameW, sizeof(nameW)/sizeof(WCHAR));
1029 if (ret)
1030 *fs = SysAllocString(nameW);
1031 return ret ? S_OK : E_FAIL;
1034 static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial)
1036 struct drive *This = impl_from_IDrive(iface);
1037 BOOL ret;
1039 TRACE("(%p)->(%p)\n", This, serial);
1041 if (!serial)
1042 return E_POINTER;
1044 ret = GetVolumeInformationW(This->root, NULL, 0, (DWORD*)serial, NULL, NULL, NULL, 0);
1045 return ret ? S_OK : E_FAIL;
1048 static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
1050 struct drive *This = impl_from_IDrive(iface);
1051 ULARGE_INTEGER freespace;
1052 BOOL ret;
1054 TRACE("(%p)->(%p)\n", This, ready);
1056 if (!ready)
1057 return E_POINTER;
1059 ret = GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL);
1060 *ready = ret ? VARIANT_TRUE : VARIANT_FALSE;
1061 return S_OK;
1064 static const IDriveVtbl drivevtbl = {
1065 drive_QueryInterface,
1066 drive_AddRef,
1067 drive_Release,
1068 drive_GetTypeInfoCount,
1069 drive_GetTypeInfo,
1070 drive_GetIDsOfNames,
1071 drive_Invoke,
1072 drive_get_Path,
1073 drive_get_DriveLetter,
1074 drive_get_ShareName,
1075 drive_get_DriveType,
1076 drive_get_RootFolder,
1077 drive_get_AvailableSpace,
1078 drive_get_FreeSpace,
1079 drive_get_TotalSize,
1080 drive_get_VolumeName,
1081 drive_put_VolumeName,
1082 drive_get_FileSystem,
1083 drive_get_SerialNumber,
1084 drive_get_IsReady
1087 static HRESULT create_drive(WCHAR letter, IDrive **drive)
1089 struct drive *This;
1091 *drive = NULL;
1093 This = heap_alloc(sizeof(*This));
1094 if (!This) return E_OUTOFMEMORY;
1096 This->IDrive_iface.lpVtbl = &drivevtbl;
1097 This->ref = 1;
1098 This->root = SysAllocStringLen(NULL, 3);
1099 if (!This->root)
1101 heap_free(This);
1102 return E_OUTOFMEMORY;
1104 This->root[0] = letter;
1105 This->root[1] = ':';
1106 This->root[2] = '\\';
1107 This->root[3] = 0;
1109 init_classinfo(&CLSID_Drive, (IUnknown *)&This->IDrive_iface, &This->classinfo);
1110 *drive = &This->IDrive_iface;
1111 return S_OK;
1114 static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
1116 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1118 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1120 *obj = NULL;
1122 if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
1123 IsEqualIID( riid, &IID_IUnknown ))
1125 *obj = iface;
1126 IEnumVARIANT_AddRef(iface);
1128 else
1129 return E_NOINTERFACE;
1131 return S_OK;
1134 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
1136 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1137 ULONG ref = InterlockedIncrement(&This->ref);
1138 TRACE("(%p)->(%d)\n", This, ref);
1139 return ref;
1142 static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
1144 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1145 ULONG ref = InterlockedDecrement(&This->ref);
1147 TRACE("(%p)->(%d)\n", This, ref);
1149 if (!ref)
1151 IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
1152 FindClose(This->data.u.foldercoll.find);
1153 heap_free(This);
1156 return ref;
1159 static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file)
1161 static const WCHAR allW[] = {'*',0};
1162 WCHAR pathW[MAX_PATH];
1163 int len;
1164 HANDLE handle;
1166 strcpyW(pathW, path);
1167 len = strlenW(pathW);
1168 if (len && pathW[len-1] != '\\')
1169 strcatW(pathW, bsW);
1170 strcatW(pathW, allW);
1171 handle = FindFirstFileW(pathW, data);
1172 if (handle == INVALID_HANDLE_VALUE) return 0;
1174 /* find first dir/file */
1175 while (1)
1177 if (file ? is_file_data(data) : is_dir_data(data))
1178 break;
1180 if (!FindNextFileW(handle, data))
1182 FindClose(handle);
1183 return 0;
1186 return handle;
1189 static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1191 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1192 HANDLE handle = This->data.u.foldercoll.find;
1193 WIN32_FIND_DATAW data;
1194 ULONG count = 0;
1196 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1198 if (fetched)
1199 *fetched = 0;
1201 if (!celt) return S_OK;
1203 if (!handle)
1205 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1206 if (!handle) return S_FALSE;
1208 This->data.u.foldercoll.find = handle;
1210 else
1212 if (!FindNextFileW(handle, &data))
1213 return S_FALSE;
1218 if (is_dir_data(&data))
1220 IFolder *folder;
1221 HRESULT hr;
1222 BSTR str;
1224 str = get_full_path(This->data.u.foldercoll.coll->path, &data);
1225 hr = create_folder(str, &folder);
1226 SysFreeString(str);
1227 if (FAILED(hr)) return hr;
1229 V_VT(&var[count]) = VT_DISPATCH;
1230 V_DISPATCH(&var[count]) = (IDispatch*)folder;
1231 count++;
1233 if (count >= celt) break;
1235 } while (FindNextFileW(handle, &data));
1237 if (fetched)
1238 *fetched = count;
1240 return (count < celt) ? S_FALSE : S_OK;
1243 static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1245 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1246 HANDLE handle = This->data.u.foldercoll.find;
1247 WIN32_FIND_DATAW data;
1249 TRACE("(%p)->(%d)\n", This, celt);
1251 if (!celt) return S_OK;
1253 if (!handle)
1255 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1256 if (!handle) return S_FALSE;
1258 This->data.u.foldercoll.find = handle;
1260 else
1262 if (!FindNextFileW(handle, &data))
1263 return S_FALSE;
1268 if (is_dir_data(&data))
1269 --celt;
1271 if (!celt) break;
1272 } while (FindNextFileW(handle, &data));
1274 return celt ? S_FALSE : S_OK;
1277 static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
1279 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1281 TRACE("(%p)\n", This);
1283 FindClose(This->data.u.foldercoll.find);
1284 This->data.u.foldercoll.find = NULL;
1286 return S_OK;
1289 static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1291 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1292 TRACE("(%p)->(%p)\n", This, pclone);
1293 return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
1296 static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
1297 enumvariant_QueryInterface,
1298 enumvariant_AddRef,
1299 foldercoll_enumvariant_Release,
1300 foldercoll_enumvariant_Next,
1301 foldercoll_enumvariant_Skip,
1302 foldercoll_enumvariant_Reset,
1303 foldercoll_enumvariant_Clone
1306 static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
1308 struct enumvariant *This;
1310 *newenum = NULL;
1312 This = heap_alloc(sizeof(*This));
1313 if (!This) return E_OUTOFMEMORY;
1315 This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
1316 This->ref = 1;
1317 This->data.u.foldercoll.find = NULL;
1318 This->data.u.foldercoll.coll = collection;
1319 IFolderCollection_AddRef(&collection->IFolderCollection_iface);
1321 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1323 return S_OK;
1326 static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface)
1328 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1329 ULONG ref = InterlockedDecrement(&This->ref);
1331 TRACE("(%p)->(%d)\n", This, ref);
1333 if (!ref)
1335 IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
1336 FindClose(This->data.u.filecoll.find);
1337 heap_free(This);
1340 return ref;
1343 static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1345 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1346 HANDLE handle = This->data.u.filecoll.find;
1347 WIN32_FIND_DATAW data;
1348 ULONG count = 0;
1350 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1352 if (fetched)
1353 *fetched = 0;
1355 if (!celt) return S_OK;
1357 if (!handle)
1359 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1360 if (!handle) return S_FALSE;
1361 This->data.u.filecoll.find = handle;
1363 else if (!FindNextFileW(handle, &data))
1364 return S_FALSE;
1368 if (is_file_data(&data))
1370 IFile *file;
1371 HRESULT hr;
1372 BSTR str;
1374 str = get_full_path(This->data.u.filecoll.coll->path, &data);
1375 hr = create_file(str, &file);
1376 SysFreeString(str);
1377 if (FAILED(hr)) return hr;
1379 V_VT(&var[count]) = VT_DISPATCH;
1380 V_DISPATCH(&var[count]) = (IDispatch*)file;
1381 if (++count >= celt) break;
1383 } while (FindNextFileW(handle, &data));
1385 if (fetched)
1386 *fetched = count;
1388 return (count < celt) ? S_FALSE : S_OK;
1391 static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1393 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1394 HANDLE handle = This->data.u.filecoll.find;
1395 WIN32_FIND_DATAW data;
1397 TRACE("(%p)->(%d)\n", This, celt);
1399 if (!celt) return S_OK;
1401 if (!handle)
1403 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1404 if (!handle) return S_FALSE;
1405 This->data.u.filecoll.find = handle;
1407 else if (!FindNextFileW(handle, &data))
1408 return S_FALSE;
1412 if (is_file_data(&data))
1413 --celt;
1414 } while (celt && FindNextFileW(handle, &data));
1416 return celt ? S_FALSE : S_OK;
1419 static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface)
1421 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1423 TRACE("(%p)\n", This);
1425 FindClose(This->data.u.filecoll.find);
1426 This->data.u.filecoll.find = NULL;
1428 return S_OK;
1431 static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1433 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1434 TRACE("(%p)->(%p)\n", This, pclone);
1435 return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
1438 static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
1439 enumvariant_QueryInterface,
1440 enumvariant_AddRef,
1441 filecoll_enumvariant_Release,
1442 filecoll_enumvariant_Next,
1443 filecoll_enumvariant_Skip,
1444 filecoll_enumvariant_Reset,
1445 filecoll_enumvariant_Clone
1448 static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum)
1450 struct enumvariant *This;
1452 *newenum = NULL;
1454 This = heap_alloc(sizeof(*This));
1455 if (!This) return E_OUTOFMEMORY;
1457 This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
1458 This->ref = 1;
1459 This->data.u.filecoll.find = NULL;
1460 This->data.u.filecoll.coll = collection;
1461 IFileCollection_AddRef(&collection->IFileCollection_iface);
1463 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1465 return S_OK;
1468 static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface)
1470 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1471 ULONG ref = InterlockedDecrement(&This->ref);
1473 TRACE("(%p)->(%d)\n", This, ref);
1475 if (!ref)
1477 IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
1478 heap_free(This);
1481 return ref;
1484 static HRESULT find_next_drive(struct enumvariant *penum)
1486 int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
1488 for (; i < 32; i++)
1489 if (penum->data.u.drivecoll.coll->drives & (1 << i))
1491 penum->data.u.drivecoll.cur = i;
1492 return S_OK;
1495 return S_FALSE;
1498 static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1500 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1501 ULONG count = 0;
1503 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1505 if (fetched)
1506 *fetched = 0;
1508 if (!celt) return S_OK;
1510 while (find_next_drive(This) == S_OK)
1512 IDrive *drive;
1513 HRESULT hr;
1515 hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
1516 if (FAILED(hr)) return hr;
1518 V_VT(&var[count]) = VT_DISPATCH;
1519 V_DISPATCH(&var[count]) = (IDispatch*)drive;
1521 if (++count >= celt) break;
1524 if (fetched)
1525 *fetched = count;
1527 return (count < celt) ? S_FALSE : S_OK;
1530 static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1532 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1534 TRACE("(%p)->(%d)\n", This, celt);
1536 if (!celt) return S_OK;
1538 while (celt && find_next_drive(This) == S_OK)
1539 celt--;
1541 return celt ? S_FALSE : S_OK;
1544 static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface)
1546 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1548 TRACE("(%p)\n", This);
1550 This->data.u.drivecoll.cur = -1;
1551 return S_OK;
1554 static HRESULT WINAPI drivecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1556 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1557 FIXME("(%p)->(%p): stub\n", This, pclone);
1558 return E_NOTIMPL;
1561 static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
1562 enumvariant_QueryInterface,
1563 enumvariant_AddRef,
1564 drivecoll_enumvariant_Release,
1565 drivecoll_enumvariant_Next,
1566 drivecoll_enumvariant_Skip,
1567 drivecoll_enumvariant_Reset,
1568 drivecoll_enumvariant_Clone
1571 static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum)
1573 struct enumvariant *This;
1575 *newenum = NULL;
1577 This = heap_alloc(sizeof(*This));
1578 if (!This) return E_OUTOFMEMORY;
1580 This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
1581 This->ref = 1;
1582 This->data.u.drivecoll.coll = collection;
1583 This->data.u.drivecoll.cur = -1;
1584 IDriveCollection_AddRef(&collection->IDriveCollection_iface);
1586 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1588 return S_OK;
1591 static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
1593 struct foldercollection *This = impl_from_IFolderCollection(iface);
1595 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1597 *obj = NULL;
1599 if (IsEqualIID( riid, &IID_IFolderCollection ) ||
1600 IsEqualIID( riid, &IID_IDispatch ) ||
1601 IsEqualIID( riid, &IID_IUnknown ))
1603 *obj = &This->IFolderCollection_iface;
1605 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
1607 *obj = &This->classinfo.IProvideClassInfo_iface;
1609 else
1610 return E_NOINTERFACE;
1612 IUnknown_AddRef((IUnknown*)*obj);
1613 return S_OK;
1616 static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
1618 struct foldercollection *This = impl_from_IFolderCollection(iface);
1619 ULONG ref = InterlockedIncrement(&This->ref);
1620 TRACE("(%p)->(%d)\n", This, ref);
1621 return ref;
1624 static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
1626 struct foldercollection *This = impl_from_IFolderCollection(iface);
1627 ULONG ref = InterlockedDecrement(&This->ref);
1628 TRACE("(%p)->(%d)\n", This, ref);
1630 if (!ref)
1632 SysFreeString(This->path);
1633 heap_free(This);
1636 return ref;
1639 static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
1641 struct foldercollection *This = impl_from_IFolderCollection(iface);
1642 TRACE("(%p)->(%p)\n", This, pctinfo);
1643 *pctinfo = 1;
1644 return S_OK;
1647 static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
1648 LCID lcid, ITypeInfo **ppTInfo)
1650 struct foldercollection *This = impl_from_IFolderCollection(iface);
1651 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1652 return get_typeinfo(IFolderCollection_tid, ppTInfo);
1655 static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
1656 LPOLESTR *rgszNames, UINT cNames,
1657 LCID lcid, DISPID *rgDispId)
1659 struct foldercollection *This = impl_from_IFolderCollection(iface);
1660 ITypeInfo *typeinfo;
1661 HRESULT hr;
1663 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1665 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1666 if(SUCCEEDED(hr))
1668 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1669 ITypeInfo_Release(typeinfo);
1672 return hr;
1675 static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
1676 REFIID riid, LCID lcid, WORD wFlags,
1677 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1678 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1680 struct foldercollection *This = impl_from_IFolderCollection(iface);
1681 ITypeInfo *typeinfo;
1682 HRESULT hr;
1684 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1685 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1687 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1688 if(SUCCEEDED(hr))
1690 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1691 pDispParams, pVarResult, pExcepInfo, puArgErr);
1692 ITypeInfo_Release(typeinfo);
1695 return hr;
1698 static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
1700 struct foldercollection *This = impl_from_IFolderCollection(iface);
1701 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
1702 return E_NOTIMPL;
1705 static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
1707 struct foldercollection *This = impl_from_IFolderCollection(iface);
1708 FIXME("(%p)->(%p): stub\n", This, folder);
1709 return E_NOTIMPL;
1712 static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
1714 struct foldercollection *This = impl_from_IFolderCollection(iface);
1716 TRACE("(%p)->(%p)\n", This, newenum);
1718 if(!newenum)
1719 return E_POINTER;
1721 return create_foldercoll_enum(This, newenum);
1724 static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
1726 struct foldercollection *This = impl_from_IFolderCollection(iface);
1727 static const WCHAR allW[] = {'\\','*',0};
1728 WIN32_FIND_DATAW data;
1729 WCHAR pathW[MAX_PATH];
1730 HANDLE handle;
1732 TRACE("(%p)->(%p)\n", This, count);
1734 if(!count)
1735 return E_POINTER;
1737 *count = 0;
1739 strcpyW(pathW, This->path);
1740 strcatW(pathW, allW);
1741 handle = FindFirstFileW(pathW, &data);
1742 if (handle == INVALID_HANDLE_VALUE)
1743 return HRESULT_FROM_WIN32(GetLastError());
1747 if (is_dir_data(&data))
1748 *count += 1;
1749 } while (FindNextFileW(handle, &data));
1750 FindClose(handle);
1752 return S_OK;
1755 static const IFolderCollectionVtbl foldercollvtbl = {
1756 foldercoll_QueryInterface,
1757 foldercoll_AddRef,
1758 foldercoll_Release,
1759 foldercoll_GetTypeInfoCount,
1760 foldercoll_GetTypeInfo,
1761 foldercoll_GetIDsOfNames,
1762 foldercoll_Invoke,
1763 foldercoll_Add,
1764 foldercoll_get_Item,
1765 foldercoll_get__NewEnum,
1766 foldercoll_get_Count
1769 static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
1771 struct foldercollection *This;
1773 *folders = NULL;
1775 This = heap_alloc(sizeof(struct foldercollection));
1776 if (!This) return E_OUTOFMEMORY;
1778 This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
1779 This->ref = 1;
1780 This->path = SysAllocString(path);
1781 if (!This->path)
1783 heap_free(This);
1784 return E_OUTOFMEMORY;
1787 init_classinfo(&CLSID_Folders, (IUnknown *)&This->IFolderCollection_iface, &This->classinfo);
1788 *folders = &This->IFolderCollection_iface;
1790 return S_OK;
1793 static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj)
1795 struct filecollection *This = impl_from_IFileCollection(iface);
1797 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1799 *obj = NULL;
1801 if (IsEqualIID( riid, &IID_IFileCollection ) ||
1802 IsEqualIID( riid, &IID_IDispatch ) ||
1803 IsEqualIID( riid, &IID_IUnknown ))
1805 *obj = &This->IFileCollection_iface;
1807 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
1809 *obj = &This->classinfo.IProvideClassInfo_iface;
1811 else
1812 return E_NOINTERFACE;
1814 IUnknown_AddRef((IUnknown*)*obj);
1815 return S_OK;
1818 static ULONG WINAPI filecoll_AddRef(IFileCollection *iface)
1820 struct filecollection *This = impl_from_IFileCollection(iface);
1821 ULONG ref = InterlockedIncrement(&This->ref);
1822 TRACE("(%p)->(%d)\n", This, ref);
1823 return ref;
1826 static ULONG WINAPI filecoll_Release(IFileCollection *iface)
1828 struct filecollection *This = impl_from_IFileCollection(iface);
1829 ULONG ref = InterlockedDecrement(&This->ref);
1830 TRACE("(%p)->(%d)\n", This, ref);
1832 if (!ref)
1834 SysFreeString(This->path);
1835 heap_free(This);
1838 return ref;
1841 static HRESULT WINAPI filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo)
1843 struct filecollection *This = impl_from_IFileCollection(iface);
1844 TRACE("(%p)->(%p)\n", This, pctinfo);
1845 *pctinfo = 1;
1846 return S_OK;
1849 static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo,
1850 LCID lcid, ITypeInfo **ppTInfo)
1852 struct filecollection *This = impl_from_IFileCollection(iface);
1853 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1854 return get_typeinfo(IFileCollection_tid, ppTInfo);
1857 static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid,
1858 LPOLESTR *rgszNames, UINT cNames,
1859 LCID lcid, DISPID *rgDispId)
1861 struct filecollection *This = impl_from_IFileCollection(iface);
1862 ITypeInfo *typeinfo;
1863 HRESULT hr;
1865 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1867 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1868 if(SUCCEEDED(hr))
1870 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1871 ITypeInfo_Release(typeinfo);
1874 return hr;
1877 static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember,
1878 REFIID riid, LCID lcid, WORD wFlags,
1879 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1880 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1882 struct filecollection *This = impl_from_IFileCollection(iface);
1883 ITypeInfo *typeinfo;
1884 HRESULT hr;
1886 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1887 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1889 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1890 if(SUCCEEDED(hr))
1892 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1893 pDispParams, pVarResult, pExcepInfo, puArgErr);
1894 ITypeInfo_Release(typeinfo);
1897 return hr;
1900 static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file)
1902 struct filecollection *This = impl_from_IFileCollection(iface);
1903 FIXME("(%p)->(%p)\n", This, file);
1904 return E_NOTIMPL;
1907 static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum)
1909 struct filecollection *This = impl_from_IFileCollection(iface);
1911 TRACE("(%p)->(%p)\n", This, ppenum);
1913 if(!ppenum)
1914 return E_POINTER;
1916 return create_filecoll_enum(This, ppenum);
1919 static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count)
1921 struct filecollection *This = impl_from_IFileCollection(iface);
1922 static const WCHAR allW[] = {'\\','*',0};
1923 WIN32_FIND_DATAW data;
1924 WCHAR pathW[MAX_PATH];
1925 HANDLE handle;
1927 TRACE("(%p)->(%p)\n", This, count);
1929 if(!count)
1930 return E_POINTER;
1932 *count = 0;
1934 strcpyW(pathW, This->path);
1935 strcatW(pathW, allW);
1936 handle = FindFirstFileW(pathW, &data);
1937 if (handle == INVALID_HANDLE_VALUE)
1938 return HRESULT_FROM_WIN32(GetLastError());
1942 if (is_file_data(&data))
1943 *count += 1;
1944 } while (FindNextFileW(handle, &data));
1945 FindClose(handle);
1947 return S_OK;
1950 static const IFileCollectionVtbl filecollectionvtbl = {
1951 filecoll_QueryInterface,
1952 filecoll_AddRef,
1953 filecoll_Release,
1954 filecoll_GetTypeInfoCount,
1955 filecoll_GetTypeInfo,
1956 filecoll_GetIDsOfNames,
1957 filecoll_Invoke,
1958 filecoll_get_Item,
1959 filecoll_get__NewEnum,
1960 filecoll_get_Count
1963 static HRESULT create_filecoll(BSTR path, IFileCollection **files)
1965 struct filecollection *This;
1967 *files = NULL;
1969 This = heap_alloc(sizeof(*This));
1970 if (!This) return E_OUTOFMEMORY;
1972 This->IFileCollection_iface.lpVtbl = &filecollectionvtbl;
1973 This->ref = 1;
1974 This->path = SysAllocString(path);
1975 if (!This->path)
1977 heap_free(This);
1978 return E_OUTOFMEMORY;
1981 init_classinfo(&CLSID_Files, (IUnknown *)&This->IFileCollection_iface, &This->classinfo);
1982 *files = &This->IFileCollection_iface;
1983 return S_OK;
1986 static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
1988 struct drivecollection *This = impl_from_IDriveCollection(iface);
1990 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1992 *obj = NULL;
1994 if (IsEqualIID( riid, &IID_IDriveCollection ) ||
1995 IsEqualIID( riid, &IID_IDispatch ) ||
1996 IsEqualIID( riid, &IID_IUnknown ))
1998 *obj = &This->IDriveCollection_iface;
2000 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2002 *obj = &This->classinfo.IProvideClassInfo_iface;
2004 else
2005 return E_NOINTERFACE;
2007 IUnknown_AddRef((IUnknown*)*obj);
2008 return S_OK;
2011 static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
2013 struct drivecollection *This = impl_from_IDriveCollection(iface);
2014 ULONG ref = InterlockedIncrement(&This->ref);
2015 TRACE("(%p)->(%d)\n", This, ref);
2016 return ref;
2019 static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
2021 struct drivecollection *This = impl_from_IDriveCollection(iface);
2022 ULONG ref = InterlockedDecrement(&This->ref);
2023 TRACE("(%p)->(%d)\n", This, ref);
2025 if (!ref)
2026 heap_free(This);
2028 return ref;
2031 static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
2033 struct drivecollection *This = impl_from_IDriveCollection(iface);
2034 TRACE("(%p)->(%p)\n", This, pctinfo);
2035 *pctinfo = 1;
2036 return S_OK;
2039 static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
2040 LCID lcid, ITypeInfo **ppTInfo)
2042 struct drivecollection *This = impl_from_IDriveCollection(iface);
2043 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2044 return get_typeinfo(IDriveCollection_tid, ppTInfo);
2047 static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
2048 LPOLESTR *rgszNames, UINT cNames,
2049 LCID lcid, DISPID *rgDispId)
2051 struct drivecollection *This = impl_from_IDriveCollection(iface);
2052 ITypeInfo *typeinfo;
2053 HRESULT hr;
2055 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2057 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2058 if(SUCCEEDED(hr))
2060 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2061 ITypeInfo_Release(typeinfo);
2064 return hr;
2067 static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
2068 REFIID riid, LCID lcid, WORD wFlags,
2069 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2070 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2072 struct drivecollection *This = impl_from_IDriveCollection(iface);
2073 ITypeInfo *typeinfo;
2074 HRESULT hr;
2076 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2077 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2079 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2080 if(SUCCEEDED(hr))
2082 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2083 pDispParams, pVarResult, pExcepInfo, puArgErr);
2084 ITypeInfo_Release(typeinfo);
2087 return hr;
2090 static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
2092 struct drivecollection *This = impl_from_IDriveCollection(iface);
2093 FIXME("(%p)->(%p): stub\n", This, drive);
2094 return E_NOTIMPL;
2097 static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
2099 struct drivecollection *This = impl_from_IDriveCollection(iface);
2101 TRACE("(%p)->(%p)\n", This, ppenum);
2103 if(!ppenum)
2104 return E_POINTER;
2106 return create_drivecoll_enum(This, ppenum);
2109 static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
2111 struct drivecollection *This = impl_from_IDriveCollection(iface);
2113 TRACE("(%p)->(%p)\n", This, count);
2115 if (!count) return E_POINTER;
2117 *count = This->count;
2118 return S_OK;
2121 static const IDriveCollectionVtbl drivecollectionvtbl = {
2122 drivecoll_QueryInterface,
2123 drivecoll_AddRef,
2124 drivecoll_Release,
2125 drivecoll_GetTypeInfoCount,
2126 drivecoll_GetTypeInfo,
2127 drivecoll_GetIDsOfNames,
2128 drivecoll_Invoke,
2129 drivecoll_get_Item,
2130 drivecoll_get__NewEnum,
2131 drivecoll_get_Count
2134 static HRESULT create_drivecoll(IDriveCollection **drives)
2136 struct drivecollection *This;
2137 DWORD mask;
2139 *drives = NULL;
2141 This = heap_alloc(sizeof(*This));
2142 if (!This) return E_OUTOFMEMORY;
2144 This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl;
2145 This->ref = 1;
2146 This->drives = mask = GetLogicalDrives();
2147 /* count set bits */
2148 for (This->count = 0; mask; This->count++)
2149 mask &= mask - 1;
2151 init_classinfo(&CLSID_Drives, (IUnknown *)&This->IDriveCollection_iface, &This->classinfo);
2152 *drives = &This->IDriveCollection_iface;
2153 return S_OK;
2156 static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
2158 struct folder *This = impl_from_IFolder(iface);
2160 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2162 *obj = NULL;
2164 if (IsEqualIID( riid, &IID_IFolder ) ||
2165 IsEqualIID( riid, &IID_IDispatch ) ||
2166 IsEqualIID( riid, &IID_IUnknown))
2168 *obj = &This->IFolder_iface;
2170 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2172 *obj = &This->classinfo.IProvideClassInfo_iface;
2174 else
2175 return E_NOINTERFACE;
2177 IUnknown_AddRef((IUnknown*)*obj);
2178 return S_OK;
2181 static ULONG WINAPI folder_AddRef(IFolder *iface)
2183 struct folder *This = impl_from_IFolder(iface);
2184 ULONG ref = InterlockedIncrement(&This->ref);
2185 TRACE("(%p)->(%d)\n", This, ref);
2186 return ref;
2189 static ULONG WINAPI folder_Release(IFolder *iface)
2191 struct folder *This = impl_from_IFolder(iface);
2192 ULONG ref = InterlockedDecrement(&This->ref);
2193 TRACE("(%p)->(%d)\n", This, ref);
2195 if (!ref)
2197 SysFreeString(This->path);
2198 heap_free(This);
2201 return ref;
2204 static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
2206 struct folder *This = impl_from_IFolder(iface);
2207 TRACE("(%p)->(%p)\n", This, pctinfo);
2208 *pctinfo = 1;
2209 return S_OK;
2212 static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
2213 LCID lcid, ITypeInfo **ppTInfo)
2215 struct folder *This = impl_from_IFolder(iface);
2216 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2217 return get_typeinfo(IFolder_tid, ppTInfo);
2220 static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
2221 LPOLESTR *rgszNames, UINT cNames,
2222 LCID lcid, DISPID *rgDispId)
2224 struct folder *This = impl_from_IFolder(iface);
2225 ITypeInfo *typeinfo;
2226 HRESULT hr;
2228 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2230 hr = get_typeinfo(IFolder_tid, &typeinfo);
2231 if(SUCCEEDED(hr))
2233 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2234 ITypeInfo_Release(typeinfo);
2237 return hr;
2240 static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
2241 REFIID riid, LCID lcid, WORD wFlags,
2242 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2243 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2245 struct folder *This = impl_from_IFolder(iface);
2246 ITypeInfo *typeinfo;
2247 HRESULT hr;
2249 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2250 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2252 hr = get_typeinfo(IFolder_tid, &typeinfo);
2253 if(SUCCEEDED(hr))
2255 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2256 pDispParams, pVarResult, pExcepInfo, puArgErr);
2257 ITypeInfo_Release(typeinfo);
2260 return hr;
2263 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
2265 struct folder *This = impl_from_IFolder(iface);
2267 TRACE("(%p)->(%p)\n", This, path);
2269 if(!path)
2270 return E_POINTER;
2272 *path = SysAllocString(This->path);
2273 return *path ? S_OK : E_OUTOFMEMORY;
2276 static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
2278 struct folder *This = impl_from_IFolder(iface);
2279 WCHAR *ptr;
2281 TRACE("(%p)->(%p)\n", This, name);
2283 if(!name)
2284 return E_POINTER;
2286 *name = NULL;
2288 ptr = strrchrW(This->path, '\\');
2289 if (ptr)
2291 *name = SysAllocString(ptr+1);
2292 TRACE("%s\n", debugstr_w(*name));
2293 if (!*name) return E_OUTOFMEMORY;
2295 else
2296 return E_FAIL;
2298 return S_OK;
2301 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
2303 struct folder *This = impl_from_IFolder(iface);
2304 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
2305 return E_NOTIMPL;
2308 static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
2310 struct folder *This = impl_from_IFolder(iface);
2311 FIXME("(%p)->(%p): stub\n", This, path);
2312 return E_NOTIMPL;
2315 static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
2317 struct folder *This = impl_from_IFolder(iface);
2318 FIXME("(%p)->(%p): stub\n", This, name);
2319 return E_NOTIMPL;
2322 static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
2324 struct folder *This = impl_from_IFolder(iface);
2325 FIXME("(%p)->(%p): stub\n", This, drive);
2326 return E_NOTIMPL;
2329 static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
2331 struct folder *This = impl_from_IFolder(iface);
2332 FIXME("(%p)->(%p): stub\n", This, parent);
2333 return E_NOTIMPL;
2336 static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
2338 struct folder *This = impl_from_IFolder(iface);
2339 FIXME("(%p)->(%p): stub\n", This, attr);
2340 return E_NOTIMPL;
2343 static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
2345 struct folder *This = impl_from_IFolder(iface);
2346 FIXME("(%p)->(0x%x): stub\n", This, attr);
2347 return E_NOTIMPL;
2350 static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
2352 struct folder *This = impl_from_IFolder(iface);
2353 FIXME("(%p)->(%p): stub\n", This, date);
2354 return E_NOTIMPL;
2357 static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
2359 struct folder *This = impl_from_IFolder(iface);
2360 FIXME("(%p)->(%p): stub\n", This, date);
2361 return E_NOTIMPL;
2364 static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
2366 struct folder *This = impl_from_IFolder(iface);
2367 FIXME("(%p)->(%p): stub\n", This, date);
2368 return E_NOTIMPL;
2371 static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
2373 struct folder *This = impl_from_IFolder(iface);
2374 FIXME("(%p)->(%p): stub\n", This, type);
2375 return E_NOTIMPL;
2378 static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
2380 struct folder *This = impl_from_IFolder(iface);
2381 FIXME("(%p)->(%x): stub\n", This, force);
2382 return E_NOTIMPL;
2385 static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
2387 struct folder *This = impl_from_IFolder(iface);
2388 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
2389 return E_NOTIMPL;
2392 static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
2394 struct folder *This = impl_from_IFolder(iface);
2395 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
2396 return E_NOTIMPL;
2399 static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
2401 struct folder *This = impl_from_IFolder(iface);
2402 FIXME("(%p)->(%p): stub\n", This, isroot);
2403 return E_NOTIMPL;
2406 static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
2408 struct folder *This = impl_from_IFolder(iface);
2409 FIXME("(%p)->(%p): stub\n", This, size);
2410 return E_NOTIMPL;
2413 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
2415 struct folder *This = impl_from_IFolder(iface);
2417 TRACE("(%p)->(%p)\n", This, folders);
2419 if(!folders)
2420 return E_POINTER;
2422 return create_foldercoll(This->path, folders);
2425 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
2427 struct folder *This = impl_from_IFolder(iface);
2429 TRACE("(%p)->(%p)\n", This, files);
2431 if(!files)
2432 return E_POINTER;
2434 return create_filecoll(This->path, files);
2437 static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
2438 VARIANT_BOOL unicode, ITextStream **stream)
2440 struct folder *This = impl_from_IFolder(iface);
2441 FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
2442 return E_NOTIMPL;
2445 static const IFolderVtbl foldervtbl = {
2446 folder_QueryInterface,
2447 folder_AddRef,
2448 folder_Release,
2449 folder_GetTypeInfoCount,
2450 folder_GetTypeInfo,
2451 folder_GetIDsOfNames,
2452 folder_Invoke,
2453 folder_get_Path,
2454 folder_get_Name,
2455 folder_put_Name,
2456 folder_get_ShortPath,
2457 folder_get_ShortName,
2458 folder_get_Drive,
2459 folder_get_ParentFolder,
2460 folder_get_Attributes,
2461 folder_put_Attributes,
2462 folder_get_DateCreated,
2463 folder_get_DateLastModified,
2464 folder_get_DateLastAccessed,
2465 folder_get_Type,
2466 folder_Delete,
2467 folder_Copy,
2468 folder_Move,
2469 folder_get_IsRootFolder,
2470 folder_get_Size,
2471 folder_get_SubFolders,
2472 folder_get_Files,
2473 folder_CreateTextFile
2476 HRESULT create_folder(const WCHAR *path, IFolder **folder)
2478 struct folder *This;
2480 *folder = NULL;
2482 TRACE("%s\n", debugstr_w(path));
2484 This = heap_alloc(sizeof(struct folder));
2485 if (!This) return E_OUTOFMEMORY;
2487 This->IFolder_iface.lpVtbl = &foldervtbl;
2488 This->ref = 1;
2489 This->path = SysAllocString(path);
2490 if (!This->path)
2492 heap_free(This);
2493 return E_OUTOFMEMORY;
2496 init_classinfo(&CLSID_Folder, (IUnknown *)&This->IFolder_iface, &This->classinfo);
2497 *folder = &This->IFolder_iface;
2499 return S_OK;
2502 static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
2504 struct file *This = impl_from_IFile(iface);
2506 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2508 *obj = NULL;
2510 if (IsEqualIID(riid, &IID_IFile) ||
2511 IsEqualIID(riid, &IID_IDispatch) ||
2512 IsEqualIID(riid, &IID_IUnknown))
2514 *obj = &This->IFile_iface;
2516 else if (IsEqualIID( riid, &IID_IProvideClassInfo ))
2518 *obj = &This->classinfo.IProvideClassInfo_iface;
2520 else
2521 return E_NOINTERFACE;
2523 IUnknown_AddRef((IUnknown*)*obj);
2524 return S_OK;
2527 static ULONG WINAPI file_AddRef(IFile *iface)
2529 struct file *This = impl_from_IFile(iface);
2530 LONG ref = InterlockedIncrement(&This->ref);
2532 TRACE("(%p) ref=%d\n", This, ref);
2534 return ref;
2537 static ULONG WINAPI file_Release(IFile *iface)
2539 struct file *This = impl_from_IFile(iface);
2540 LONG ref = InterlockedDecrement(&This->ref);
2542 TRACE("(%p) ref=%d\n", This, ref);
2544 if(!ref)
2546 heap_free(This->path);
2547 heap_free(This);
2550 return ref;
2553 static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
2555 struct file *This = impl_from_IFile(iface);
2557 TRACE("(%p)->(%p)\n", This, pctinfo);
2559 *pctinfo = 1;
2560 return S_OK;
2563 static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
2564 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
2566 struct file *This = impl_from_IFile(iface);
2568 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2570 return get_typeinfo(IFile_tid, ppTInfo);
2573 static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
2574 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2576 struct file *This = impl_from_IFile(iface);
2577 ITypeInfo *typeinfo;
2578 HRESULT hr;
2580 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
2581 rgszNames, cNames, lcid, rgDispId);
2583 hr = get_typeinfo(IFile_tid, &typeinfo);
2584 if(SUCCEEDED(hr)) {
2585 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2586 ITypeInfo_Release(typeinfo);
2588 return hr;
2591 static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2593 struct file *This = impl_from_IFile(iface);
2594 ITypeInfo *typeinfo;
2595 HRESULT hr;
2597 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2598 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2600 hr = get_typeinfo(IFile_tid, &typeinfo);
2601 if(SUCCEEDED(hr))
2603 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2604 pDispParams, pVarResult, pExcepInfo, puArgErr);
2605 ITypeInfo_Release(typeinfo);
2607 return hr;
2610 static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *path)
2612 struct file *This = impl_from_IFile(iface);
2614 TRACE("(%p)->(%p)\n", This, path);
2616 if (!path)
2617 return E_POINTER;
2619 *path = SysAllocString(This->path);
2620 if (!*path)
2621 return E_OUTOFMEMORY;
2623 return S_OK;
2626 static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
2628 struct file *This = impl_from_IFile(iface);
2629 WCHAR *ptr;
2631 TRACE("(%p)->(%p)\n", This, name);
2633 if(!name)
2634 return E_POINTER;
2636 *name = NULL;
2638 ptr = strrchrW(This->path, '\\');
2639 if (ptr)
2641 *name = SysAllocString(ptr+1);
2642 TRACE("%s\n", debugstr_w(*name));
2643 if (!*name) return E_OUTOFMEMORY;
2645 else
2646 return E_FAIL;
2648 return S_OK;
2651 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
2653 struct file *This = impl_from_IFile(iface);
2654 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
2655 return E_NOTIMPL;
2658 static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
2660 struct file *This = impl_from_IFile(iface);
2661 FIXME("(%p)->(%p)\n", This, pbstrPath);
2662 return E_NOTIMPL;
2665 static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
2667 struct file *This = impl_from_IFile(iface);
2668 FIXME("(%p)->(%p)\n", This, pbstrName);
2669 return E_NOTIMPL;
2672 static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
2674 struct file *This = impl_from_IFile(iface);
2675 FIXME("(%p)->(%p)\n", This, ppdrive);
2676 return E_NOTIMPL;
2679 static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
2681 struct file *This = impl_from_IFile(iface);
2682 FIXME("(%p)->(%p)\n", This, ppfolder);
2683 return E_NOTIMPL;
2686 static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
2688 struct file *This = impl_from_IFile(iface);
2689 DWORD fa;
2691 TRACE("(%p)->(%p)\n", This, pfa);
2693 if(!pfa)
2694 return E_POINTER;
2696 fa = GetFileAttributesW(This->path);
2697 if(fa == INVALID_FILE_ATTRIBUTES)
2698 return create_error(GetLastError());
2700 *pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2701 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
2702 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
2703 return S_OK;
2706 static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
2708 struct file *This = impl_from_IFile(iface);
2710 TRACE("(%p)->(%x)\n", This, pfa);
2712 return SetFileAttributesW(This->path, pfa) ? S_OK : create_error(GetLastError());
2715 static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
2717 struct file *This = impl_from_IFile(iface);
2718 FIXME("(%p)->(%p)\n", This, pdate);
2719 return E_NOTIMPL;
2722 static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *pdate)
2724 struct file *This = impl_from_IFile(iface);
2725 FIXME("(%p)->(%p)\n", This, pdate);
2726 return E_NOTIMPL;
2729 static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
2731 struct file *This = impl_from_IFile(iface);
2732 FIXME("(%p)->(%p)\n", This, pdate);
2733 return E_NOTIMPL;
2736 static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
2738 struct file *This = impl_from_IFile(iface);
2739 ULARGE_INTEGER size;
2740 WIN32_FIND_DATAW fd;
2741 HANDLE f;
2743 TRACE("(%p)->(%p)\n", This, pvarSize);
2745 if(!pvarSize)
2746 return E_POINTER;
2748 f = FindFirstFileW(This->path, &fd);
2749 if(f == INVALID_HANDLE_VALUE)
2750 return create_error(GetLastError());
2751 FindClose(f);
2753 size.u.LowPart = fd.nFileSizeLow;
2754 size.u.HighPart = fd.nFileSizeHigh;
2756 return variant_from_largeint(&size, pvarSize);
2759 static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
2761 struct file *This = impl_from_IFile(iface);
2762 FIXME("(%p)->(%p)\n", This, pbstrType);
2763 return E_NOTIMPL;
2766 static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
2768 struct file *This = impl_from_IFile(iface);
2769 FIXME("(%p)->(%x)\n", This, Force);
2770 return E_NOTIMPL;
2773 static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
2775 struct file *This = impl_from_IFile(iface);
2776 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
2777 return E_NOTIMPL;
2780 static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
2782 struct file *This = impl_from_IFile(iface);
2783 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
2784 return E_NOTIMPL;
2787 static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode mode, Tristate format, ITextStream **stream)
2789 struct file *This = impl_from_IFile(iface);
2791 TRACE("(%p)->(%d %d %p)\n", This, mode, format, stream);
2793 if (format == TristateUseDefault) {
2794 FIXME("default format not handled, defaulting to unicode\n");
2795 format = TristateTrue;
2798 return create_textstream(This->path, OPEN_EXISTING, mode, format == TristateTrue, stream);
2801 static const IFileVtbl file_vtbl = {
2802 file_QueryInterface,
2803 file_AddRef,
2804 file_Release,
2805 file_GetTypeInfoCount,
2806 file_GetTypeInfo,
2807 file_GetIDsOfNames,
2808 file_Invoke,
2809 file_get_Path,
2810 file_get_Name,
2811 file_put_Name,
2812 file_get_ShortPath,
2813 file_get_ShortName,
2814 file_get_Drive,
2815 file_get_ParentFolder,
2816 file_get_Attributes,
2817 file_put_Attributes,
2818 file_get_DateCreated,
2819 file_get_DateLastModified,
2820 file_get_DateLastAccessed,
2821 file_get_Size,
2822 file_get_Type,
2823 file_Delete,
2824 file_Copy,
2825 file_Move,
2826 file_OpenAsTextStream
2829 static HRESULT create_file(BSTR path, IFile **file)
2831 struct file *f;
2832 DWORD len, attrs;
2834 *file = NULL;
2836 f = heap_alloc(sizeof(struct file));
2837 if(!f)
2838 return E_OUTOFMEMORY;
2840 f->IFile_iface.lpVtbl = &file_vtbl;
2841 f->ref = 1;
2843 len = GetFullPathNameW(path, 0, NULL, NULL);
2844 if(!len) {
2845 heap_free(f);
2846 return E_FAIL;
2849 f->path = heap_alloc(len*sizeof(WCHAR));
2850 if(!f->path) {
2851 heap_free(f);
2852 return E_OUTOFMEMORY;
2855 if(!GetFullPathNameW(path, len, f->path, NULL)) {
2856 heap_free(f->path);
2857 heap_free(f);
2858 return E_FAIL;
2861 attrs = GetFileAttributesW(f->path);
2862 if(attrs==INVALID_FILE_ATTRIBUTES ||
2863 (attrs&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))) {
2864 heap_free(f->path);
2865 heap_free(f);
2866 return create_error(GetLastError());
2869 init_classinfo(&CLSID_File, (IUnknown *)&f->IFile_iface, &f->classinfo);
2870 *file = &f->IFile_iface;
2871 return S_OK;
2874 static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
2876 struct filesystem *This = impl_from_IFileSystem3(iface);
2878 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
2880 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
2881 IsEqualGUID( riid, &IID_IFileSystem ) ||
2882 IsEqualGUID( riid, &IID_IDispatch ) ||
2883 IsEqualGUID( riid, &IID_IUnknown ) )
2885 *ppvObject = &This->IFileSystem3_iface;
2887 else if (IsEqualGUID( riid, &IID_IProvideClassInfo ))
2889 *ppvObject = &This->classinfo.IProvideClassInfo_iface;
2891 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
2893 TRACE("Interface IDispatchEx not supported - returning NULL\n");
2894 *ppvObject = NULL;
2895 return E_NOINTERFACE;
2897 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
2899 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
2900 *ppvObject = NULL;
2901 return E_NOINTERFACE;
2903 else
2905 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
2906 return E_NOINTERFACE;
2909 IUnknown_AddRef((IUnknown*)*ppvObject);
2911 return S_OK;
2914 static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
2916 TRACE("%p\n", iface);
2918 return 2;
2921 static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
2923 TRACE("%p\n", iface);
2925 return 1;
2928 static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
2930 TRACE("(%p)->(%p)\n", iface, pctinfo);
2932 *pctinfo = 1;
2933 return S_OK;
2936 static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
2937 LCID lcid, ITypeInfo **ppTInfo)
2939 TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
2940 return get_typeinfo(IFileSystem3_tid, ppTInfo);
2943 static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
2944 LPOLESTR *rgszNames, UINT cNames,
2945 LCID lcid, DISPID *rgDispId)
2947 ITypeInfo *typeinfo;
2948 HRESULT hr;
2950 TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2952 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2953 if(SUCCEEDED(hr))
2955 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2956 ITypeInfo_Release(typeinfo);
2959 return hr;
2962 static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
2963 REFIID riid, LCID lcid, WORD wFlags,
2964 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2965 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2967 ITypeInfo *typeinfo;
2968 HRESULT hr;
2970 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
2971 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2973 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2974 if(SUCCEEDED(hr))
2976 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2977 pDispParams, pVarResult, pExcepInfo, puArgErr);
2978 ITypeInfo_Release(typeinfo);
2981 return hr;
2984 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
2986 TRACE("%p %p\n", iface, ppdrives);
2987 return create_drivecoll(ppdrives);
2990 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
2991 BSTR Name, BSTR *Result)
2993 BSTR ret;
2995 TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
2997 if (!Result) return E_POINTER;
2999 if (Path && Name)
3001 int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
3003 /* if both parts have backslashes strip one from Path */
3004 if (Path[path_len-1] == '\\' && Name[0] == '\\')
3006 path_len -= 1;
3008 ret = SysAllocStringLen(NULL, path_len + name_len);
3009 if (ret)
3011 strcpyW(ret, Path);
3012 ret[path_len] = 0;
3013 strcatW(ret, Name);
3016 else if (Path[path_len-1] != '\\' && Name[0] != '\\')
3018 ret = SysAllocStringLen(NULL, path_len + name_len + 1);
3019 if (ret)
3021 strcpyW(ret, Path);
3022 if (Path[path_len-1] != ':')
3023 strcatW(ret, bsW);
3024 strcatW(ret, Name);
3027 else
3029 ret = SysAllocStringLen(NULL, path_len + name_len);
3030 if (ret)
3032 strcpyW(ret, Path);
3033 strcatW(ret, Name);
3037 else if (Path || Name)
3038 ret = SysAllocString(Path ? Path : Name);
3039 else
3040 ret = SysAllocStringLen(NULL, 0);
3042 if (!ret) return E_OUTOFMEMORY;
3043 *Result = ret;
3045 return S_OK;
3048 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR path, BSTR *drive)
3050 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), drive);
3052 if (!drive)
3053 return E_POINTER;
3055 *drive = NULL;
3057 if (path && strlenW(path) > 1 && path[1] == ':')
3058 *drive = SysAllocStringLen(path, 2);
3060 return S_OK;
3063 static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
3065 int i;
3067 if(!path)
3068 return 0;
3070 for(i=len-1; i>=0; i--)
3071 if(path[i]!='/' && path[i]!='\\')
3072 break;
3074 for(; i>=0; i--)
3075 if(path[i]=='/' || path[i]=='\\')
3076 break;
3078 for(; i>=0; i--)
3079 if(path[i]!='/' && path[i]!='\\')
3080 break;
3082 if(i < 0)
3083 return 0;
3085 if(path[i]==':' && i==1)
3086 i++;
3087 return i+1;
3090 static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
3091 BSTR *pbstrResult)
3093 DWORD len;
3095 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3097 if(!pbstrResult)
3098 return E_POINTER;
3100 len = get_parent_folder_name(Path, SysStringLen(Path));
3101 if(!len) {
3102 *pbstrResult = NULL;
3103 return S_OK;
3106 *pbstrResult = SysAllocStringLen(Path, len);
3107 if(!*pbstrResult)
3108 return E_OUTOFMEMORY;
3109 return S_OK;
3112 static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
3113 BSTR *pbstrResult)
3115 int i, end;
3117 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3119 if(!pbstrResult)
3120 return E_POINTER;
3122 if(!Path) {
3123 *pbstrResult = NULL;
3124 return S_OK;
3127 for(end=strlenW(Path)-1; end>=0; end--)
3128 if(Path[end]!='/' && Path[end]!='\\')
3129 break;
3131 for(i=end; i>=0; i--)
3132 if(Path[i]=='/' || Path[i]=='\\')
3133 break;
3134 i++;
3136 if(i>end || (i==0 && end==1 && Path[1]==':')) {
3137 *pbstrResult = NULL;
3138 return S_OK;
3141 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3142 if(!*pbstrResult)
3143 return E_OUTOFMEMORY;
3144 return S_OK;
3147 static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
3148 BSTR *pbstrResult)
3150 int i, end;
3152 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3154 if(!pbstrResult)
3155 return E_POINTER;
3157 if(!Path) {
3158 *pbstrResult = NULL;
3159 return S_OK;
3162 for(end=strlenW(Path)-1; end>=0; end--)
3163 if(Path[end]!='/' && Path[end]!='\\')
3164 break;
3166 for(i=end; i>=0; i--) {
3167 if(Path[i]=='.' && Path[end+1]!='.')
3168 end = i-1;
3169 if(Path[i]=='/' || Path[i]=='\\')
3170 break;
3172 i++;
3174 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
3175 *pbstrResult = NULL;
3176 return S_OK;
3179 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3180 if(!*pbstrResult)
3181 return E_OUTOFMEMORY;
3182 return S_OK;
3185 static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR path,
3186 BSTR *ext)
3188 INT len;
3190 TRACE("%p %s %p\n", iface, debugstr_w(path), ext);
3192 *ext = NULL;
3193 len = SysStringLen(path);
3194 while (len) {
3195 if (path[len-1] == '.') {
3196 *ext = SysAllocString(&path[len]);
3197 if (!*ext)
3198 return E_OUTOFMEMORY;
3199 break;
3201 len--;
3204 return S_OK;
3207 static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR Path,
3208 BSTR *pbstrResult)
3210 static const WCHAR cur_path[] = {'.',0};
3212 WCHAR buf[MAX_PATH], ch;
3213 const WCHAR *path;
3214 DWORD i, beg, len, exp_len;
3215 WIN32_FIND_DATAW fdata;
3216 HANDLE fh;
3218 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3220 if(!pbstrResult)
3221 return E_POINTER;
3223 if(!Path)
3224 path = cur_path;
3225 else
3226 path = Path;
3228 len = GetFullPathNameW(path, MAX_PATH, buf, NULL);
3229 if(!len)
3230 return E_FAIL;
3232 buf[0] = toupperW(buf[0]);
3233 if(len>3 && buf[len-1] == '\\')
3234 buf[--len] = 0;
3236 for(beg=3, i=3; i<=len; i++) {
3237 if(buf[i]!='\\' && buf[i])
3238 continue;
3240 ch = buf[i];
3241 buf[i] = 0;
3242 fh = FindFirstFileW(buf, &fdata);
3243 if(fh == INVALID_HANDLE_VALUE)
3244 break;
3246 exp_len = strlenW(fdata.cFileName);
3247 if(exp_len == i-beg)
3248 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
3249 FindClose(fh);
3250 buf[i] = ch;
3251 beg = i+1;
3254 *pbstrResult = SysAllocString(buf);
3255 if(!*pbstrResult)
3256 return E_OUTOFMEMORY;
3257 return S_OK;
3260 static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
3262 static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
3264 DWORD random;
3266 TRACE("%p %p\n", iface, pbstrResult);
3268 if(!pbstrResult)
3269 return E_POINTER;
3271 *pbstrResult = SysAllocStringLen(NULL, 12);
3272 if(!*pbstrResult)
3273 return E_OUTOFMEMORY;
3275 if(!RtlGenRandom(&random, sizeof(random)))
3276 return E_FAIL;
3277 sprintfW(*pbstrResult, fmt, random & 0xfffff);
3278 return S_OK;
3281 static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
3282 VARIANT_BOOL *pfExists)
3284 UINT len;
3285 WCHAR driveletter;
3286 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
3288 if (!pfExists) return E_POINTER;
3290 *pfExists = VARIANT_FALSE;
3291 len = SysStringLen(DriveSpec);
3293 if (len >= 1) {
3294 driveletter = toupperW(DriveSpec[0]);
3295 if (driveletter >= 'A' && driveletter <= 'Z'
3296 && (len < 2 || DriveSpec[1] == ':')
3297 && (len < 3 || DriveSpec[2] == '\\')) {
3298 const WCHAR root[] = {driveletter, ':', '\\', 0};
3299 UINT drivetype = GetDriveTypeW(root);
3300 *pfExists = drivetype != DRIVE_NO_ROOT_DIR && drivetype != DRIVE_UNKNOWN ? VARIANT_TRUE : VARIANT_FALSE;
3304 return S_OK;
3307 static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3309 DWORD attrs;
3310 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3312 if (!ret) return E_POINTER;
3314 attrs = GetFileAttributesW(path);
3315 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3316 return S_OK;
3319 static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3321 DWORD attrs;
3322 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3324 if (!ret) return E_POINTER;
3326 attrs = GetFileAttributesW(path);
3327 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3329 return S_OK;
3332 static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
3333 IDrive **ppdrive)
3335 UINT len;
3336 HRESULT hr;
3337 WCHAR driveletter;
3338 VARIANT_BOOL drive_exists;
3340 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
3342 if (!ppdrive)
3343 return E_POINTER;
3345 *ppdrive = NULL;
3347 /* DriveSpec may be one of: 'x', 'x:', 'x:\', '\\computer\share' */
3348 len = SysStringLen(DriveSpec);
3349 if (!len)
3350 return E_INVALIDARG;
3351 else if (len <= 3) {
3352 driveletter = toupperW(DriveSpec[0]);
3353 if (driveletter < 'A' || driveletter > 'Z'
3354 || (len >= 2 && DriveSpec[1] != ':')
3355 || (len == 3 && DriveSpec[2] != '\\'))
3356 return E_INVALIDARG;
3357 hr = IFileSystem3_DriveExists(iface, DriveSpec, &drive_exists);
3358 if (FAILED(hr))
3359 return hr;
3360 if (drive_exists == VARIANT_FALSE)
3361 return CTL_E_DEVICEUNAVAILABLE;
3362 return create_drive(driveletter, ppdrive);
3363 } else {
3364 if (DriveSpec[0] != '\\' || DriveSpec[1] != '\\')
3365 return E_INVALIDARG;
3366 FIXME("%s not implemented yet\n", debugstr_w(DriveSpec));
3367 return E_NOTIMPL;
3371 static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
3372 IFile **ppfile)
3374 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
3376 if(!ppfile)
3377 return E_POINTER;
3378 if(!FilePath)
3379 return E_INVALIDARG;
3381 return create_file(FilePath, ppfile);
3384 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
3385 IFolder **folder)
3387 DWORD attrs;
3389 TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
3391 if(!folder)
3392 return E_POINTER;
3394 *folder = NULL;
3395 if(!FolderPath)
3396 return E_INVALIDARG;
3398 attrs = GetFileAttributesW(FolderPath);
3399 if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
3400 return CTL_E_PATHNOTFOUND;
3402 return create_folder(FolderPath, folder);
3405 static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
3406 SpecialFolderConst SpecialFolder,
3407 IFolder **folder)
3409 WCHAR pathW[MAX_PATH];
3410 DWORD ret;
3412 TRACE("%p %d %p\n", iface, SpecialFolder, folder);
3414 if (!folder)
3415 return E_POINTER;
3417 *folder = NULL;
3419 switch (SpecialFolder)
3421 case WindowsFolder:
3422 ret = GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
3423 break;
3424 case SystemFolder:
3425 ret = GetSystemDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
3426 break;
3427 case TemporaryFolder:
3428 ret = GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
3429 /* we don't want trailing backslash */
3430 if (ret && pathW[ret-1] == '\\')
3431 pathW[ret-1] = 0;
3432 break;
3433 default:
3434 FIXME("unknown special folder type, %d\n", SpecialFolder);
3435 return E_INVALIDARG;
3438 if (!ret)
3439 return HRESULT_FROM_WIN32(GetLastError());
3441 return create_folder(pathW, folder);
3444 static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
3446 WCHAR path[MAX_PATH];
3447 DWORD len, name_len;
3448 WIN32_FIND_DATAW ffd;
3449 HANDLE f;
3451 f = FindFirstFileW(file, &ffd);
3452 if(f == INVALID_HANDLE_VALUE)
3453 return create_error(GetLastError());
3455 len = get_parent_folder_name(file, file_len);
3456 if(len+1 >= MAX_PATH) {
3457 FindClose(f);
3458 return E_FAIL;
3460 if(len) {
3461 memcpy(path, file, len*sizeof(WCHAR));
3462 path[len++] = '\\';
3465 do {
3466 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3467 continue;
3469 name_len = strlenW(ffd.cFileName);
3470 if(len+name_len+1 >= MAX_PATH) {
3471 FindClose(f);
3472 return E_FAIL;
3474 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3476 TRACE("deleting %s\n", debugstr_w(path));
3478 if(!DeleteFileW(path)) {
3479 if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
3480 || !DeleteFileW(path)) {
3481 FindClose(f);
3482 return create_error(GetLastError());
3485 } while(FindNextFileW(f, &ffd));
3486 FindClose(f);
3488 return S_OK;
3491 static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
3492 VARIANT_BOOL Force)
3494 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
3496 if(!FileSpec)
3497 return E_POINTER;
3499 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
3502 static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
3504 WCHAR path[MAX_PATH];
3505 DWORD len, name_len;
3506 WIN32_FIND_DATAW ffd;
3507 HANDLE f;
3508 HRESULT hr;
3510 f = FindFirstFileW(folder, &ffd);
3511 if(f == INVALID_HANDLE_VALUE)
3512 return create_error(GetLastError());
3514 len = get_parent_folder_name(folder, folder_len);
3515 if(len+1 >= MAX_PATH) {
3516 FindClose(f);
3517 return E_FAIL;
3519 if(len) {
3520 memcpy(path, folder, len*sizeof(WCHAR));
3521 path[len++] = '\\';
3524 do {
3525 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3526 continue;
3527 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3528 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3529 continue;
3531 name_len = strlenW(ffd.cFileName);
3532 if(len+name_len+3 >= MAX_PATH) {
3533 FindClose(f);
3534 return E_FAIL;
3536 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
3537 path[len+name_len] = '\\';
3538 path[len+name_len+1] = '*';
3539 path[len+name_len+2] = 0;
3541 hr = delete_file(path, len+name_len+2, force);
3542 if(FAILED(hr)) {
3543 FindClose(f);
3544 return hr;
3547 hr = delete_folder(path, len+name_len+2, force);
3548 if(FAILED(hr)) {
3549 FindClose(f);
3550 return hr;
3553 path[len+name_len] = 0;
3554 TRACE("deleting %s\n", debugstr_w(path));
3556 if(!RemoveDirectoryW(path)) {
3557 FindClose(f);
3558 return create_error(GetLastError());
3560 } while(FindNextFileW(f, &ffd));
3561 FindClose(f);
3563 return S_OK;
3566 static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
3567 VARIANT_BOOL Force)
3569 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
3571 if(!FolderSpec)
3572 return E_POINTER;
3574 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
3577 static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR Source,
3578 BSTR Destination)
3580 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3582 return E_NOTIMPL;
3585 static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
3586 BSTR Destination)
3588 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3590 return E_NOTIMPL;
3593 static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
3594 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
3596 DWORD attrs;
3597 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
3598 DWORD src_len, dst_len, name_len;
3599 WIN32_FIND_DATAW ffd;
3600 HANDLE f;
3601 HRESULT hr;
3603 if(!source[0] || !destination[0])
3604 return E_INVALIDARG;
3606 attrs = GetFileAttributesW(destination);
3607 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
3608 attrs = GetFileAttributesW(source);
3609 if(attrs == INVALID_FILE_ATTRIBUTES)
3610 return create_error(GetLastError());
3611 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
3612 return CTL_E_FILENOTFOUND;
3614 if(!CopyFileW(source, destination, !overwrite))
3615 return create_error(GetLastError());
3616 return S_OK;
3619 f = FindFirstFileW(source, &ffd);
3620 if(f == INVALID_HANDLE_VALUE)
3621 return CTL_E_FILENOTFOUND;
3623 src_len = get_parent_folder_name(source, source_len);
3624 if(src_len+1 >= MAX_PATH) {
3625 FindClose(f);
3626 return E_FAIL;
3628 if(src_len) {
3629 memcpy(src_path, source, src_len*sizeof(WCHAR));
3630 src_path[src_len++] = '\\';
3633 dst_len = destination_len;
3634 if(dst_len+1 >= MAX_PATH) {
3635 FindClose(f);
3636 return E_FAIL;
3638 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
3639 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
3640 dst_path[dst_len++] = '\\';
3642 hr = CTL_E_FILENOTFOUND;
3643 do {
3644 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3645 continue;
3647 name_len = strlenW(ffd.cFileName);
3648 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
3649 FindClose(f);
3650 return E_FAIL;
3652 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3653 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3655 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
3657 if(!CopyFileW(src_path, dst_path, !overwrite)) {
3658 FindClose(f);
3659 return create_error(GetLastError());
3660 }else {
3661 hr = S_OK;
3663 } while(FindNextFileW(f, &ffd));
3664 FindClose(f);
3666 return hr;
3669 static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
3670 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3672 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3674 if(!Source || !Destination)
3675 return E_POINTER;
3677 return copy_file(Source, SysStringLen(Source), Destination,
3678 SysStringLen(Destination), OverWriteFiles);
3681 static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
3682 DWORD destination_len, VARIANT_BOOL overwrite)
3684 DWORD tmp, src_len, dst_len, name_len;
3685 WCHAR src[MAX_PATH], dst[MAX_PATH];
3686 WIN32_FIND_DATAW ffd;
3687 HANDLE f;
3688 HRESULT hr;
3689 BOOL copied = FALSE;
3691 if(!source[0] || !destination[0])
3692 return E_INVALIDARG;
3694 dst_len = destination_len;
3695 if(dst_len+1 >= MAX_PATH)
3696 return E_FAIL;
3697 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
3699 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
3700 (tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
3701 tmp&FILE_ATTRIBUTE_DIRECTORY) {
3702 if(!CreateDirectoryW(dst, NULL)) {
3703 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3704 tmp = GetFileAttributesW(dst);
3705 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
3706 return CTL_E_FILEALREADYEXISTS;
3707 }else {
3708 return create_error(GetLastError());
3711 copied = TRUE;
3713 src_len = source_len;
3714 if(src_len+2 >= MAX_PATH)
3715 return E_FAIL;
3716 memcpy(src, source, src_len*sizeof(WCHAR));
3717 src[src_len++] = '\\';
3718 src[src_len] = '*';
3719 src[src_len+1] = 0;
3721 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
3722 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
3723 return create_error(GetLastError());
3725 f = FindFirstFileW(src, &ffd);
3726 }else {
3727 src_len = get_parent_folder_name(source, source_len);
3728 if(src_len+2 >= MAX_PATH)
3729 return E_FAIL;
3730 memcpy(src, source, src_len*sizeof(WCHAR));
3731 if(src_len)
3732 src[src_len++] = '\\';
3734 f = FindFirstFileW(source, &ffd);
3736 if(f == INVALID_HANDLE_VALUE)
3737 return CTL_E_PATHNOTFOUND;
3739 dst[dst_len++] = '\\';
3740 dst[dst_len] = 0;
3742 do {
3743 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3744 continue;
3745 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3746 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3747 continue;
3749 name_len = strlenW(ffd.cFileName);
3750 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
3751 FindClose(f);
3752 return E_FAIL;
3754 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
3755 dst[dst_len+name_len] = 0;
3756 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
3757 src[src_len+name_len] = '\\';
3758 src[src_len+name_len+1] = '*';
3759 src[src_len+name_len+2] = 0;
3761 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
3763 if(!CreateDirectoryW(dst, NULL)) {
3764 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3765 tmp = GetFileAttributesW(dst);
3766 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
3767 FindClose(f);
3768 return CTL_E_FILEALREADYEXISTS;
3772 FindClose(f);
3773 return create_error(GetLastError());
3775 copied = TRUE;
3777 hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3778 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
3779 FindClose(f);
3780 return hr;
3783 hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3784 if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
3785 FindClose(f);
3786 return hr;
3788 } while(FindNextFileW(f, &ffd));
3789 FindClose(f);
3791 return copied ? S_OK : CTL_E_PATHNOTFOUND;
3794 static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
3795 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3797 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3799 if(!Source || !Destination)
3800 return E_POINTER;
3802 return copy_folder(Source, SysStringLen(Source), Destination,
3803 SysStringLen(Destination), OverWriteFiles);
3806 static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
3807 IFolder **folder)
3809 BOOL ret;
3811 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
3813 ret = CreateDirectoryW(path, NULL);
3814 if (!ret)
3816 *folder = NULL;
3817 if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
3818 return HRESULT_FROM_WIN32(GetLastError());
3821 return create_folder(path, folder);
3824 static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR filename,
3825 VARIANT_BOOL overwrite, VARIANT_BOOL unicode,
3826 ITextStream **stream)
3828 DWORD disposition;
3830 TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
3832 disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
3833 return create_textstream(filename, disposition, ForWriting, !!unicode, stream);
3836 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
3837 IOMode mode, VARIANT_BOOL create,
3838 Tristate format, ITextStream **stream)
3840 DWORD disposition;
3842 TRACE("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
3843 disposition = create == VARIANT_TRUE ? OPEN_ALWAYS : OPEN_EXISTING;
3845 if (format == TristateUseDefault) {
3846 FIXME("default format not handled, defaulting to unicode\n");
3847 format = TristateTrue;
3850 return create_textstream(filename, disposition, mode, format == TristateTrue, stream);
3853 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
3854 StandardStreamTypes StandardStreamType,
3855 VARIANT_BOOL Unicode,
3856 ITextStream **ppts)
3858 FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
3860 return E_NOTIMPL;
3863 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
3865 static const WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
3866 DWORDLONG version;
3867 WORD a, b, c, d;
3869 version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
3870 a = (WORD)( version >> 48);
3871 b = (WORD)((version >> 32) & 0xffff);
3872 c = (WORD)((version >> 16) & 0xffff);
3873 d = (WORD)( version & 0xffff);
3875 sprintfW(ver, fmtW, a, b, c, d);
3878 static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
3880 static const WCHAR rootW[] = {'\\',0};
3881 VS_FIXEDFILEINFO *info;
3882 WCHAR ver[30];
3883 void *ptr;
3884 DWORD len;
3885 BOOL ret;
3887 TRACE("%p %s %p\n", iface, debugstr_w(name), version);
3889 len = GetFileVersionInfoSizeW(name, NULL);
3890 if (!len)
3891 return HRESULT_FROM_WIN32(GetLastError());
3893 ptr = heap_alloc(len);
3894 if (!GetFileVersionInfoW(name, 0, len, ptr))
3896 heap_free(ptr);
3897 return HRESULT_FROM_WIN32(GetLastError());
3900 ret = VerQueryValueW(ptr, rootW, (void**)&info, &len);
3901 if (!ret)
3903 heap_free(ptr);
3904 return HRESULT_FROM_WIN32(GetLastError());
3907 get_versionstring(info, ver);
3908 heap_free(ptr);
3910 *version = SysAllocString(ver);
3911 TRACE("version=%s\n", debugstr_w(ver));
3913 return S_OK;
3916 static const struct IFileSystem3Vtbl filesys_vtbl =
3918 filesys_QueryInterface,
3919 filesys_AddRef,
3920 filesys_Release,
3921 filesys_GetTypeInfoCount,
3922 filesys_GetTypeInfo,
3923 filesys_GetIDsOfNames,
3924 filesys_Invoke,
3925 filesys_get_Drives,
3926 filesys_BuildPath,
3927 filesys_GetDriveName,
3928 filesys_GetParentFolderName,
3929 filesys_GetFileName,
3930 filesys_GetBaseName,
3931 filesys_GetExtensionName,
3932 filesys_GetAbsolutePathName,
3933 filesys_GetTempName,
3934 filesys_DriveExists,
3935 filesys_FileExists,
3936 filesys_FolderExists,
3937 filesys_GetDrive,
3938 filesys_GetFile,
3939 filesys_GetFolder,
3940 filesys_GetSpecialFolder,
3941 filesys_DeleteFile,
3942 filesys_DeleteFolder,
3943 filesys_MoveFile,
3944 filesys_MoveFolder,
3945 filesys_CopyFile,
3946 filesys_CopyFolder,
3947 filesys_CreateFolder,
3948 filesys_CreateTextFile,
3949 filesys_OpenTextFile,
3950 filesys_GetStandardStream,
3951 filesys_GetFileVersion
3954 static struct filesystem filesystem;
3956 HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
3958 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
3960 filesystem.IFileSystem3_iface.lpVtbl = &filesys_vtbl;
3961 init_classinfo(&CLSID_FileSystemObject, (IUnknown *)&filesystem.IFileSystem3_iface, &filesystem.classinfo);
3962 return IFileSystem3_QueryInterface(&filesystem.IFileSystem3_iface, riid, ppv);