kernel32: Added SetWaitableTimerEx().
[wine/multimedia.git] / dlls / scrrun / filesystem.c
blobc6dbb76510ca0c675f83408dd5ab32845ee57308
1 /*
2 * Copyright 2012 Alistair Leslie-Hughes
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include "config.h"
22 #include <stdarg.h>
23 #include <limits.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "ole2.h"
28 #include "olectl.h"
29 #include "dispex.h"
30 #include "ntsecapi.h"
31 #include "scrrun.h"
32 #include "scrrun_private.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
39 static const WCHAR bsW[] = {'\\',0};
41 struct foldercollection {
42 IFolderCollection IFolderCollection_iface;
43 LONG ref;
44 BSTR path;
47 struct filecollection {
48 IFileCollection IFileCollection_iface;
49 LONG ref;
50 BSTR path;
53 struct drivecollection {
54 IDriveCollection IDriveCollection_iface;
55 LONG ref;
56 DWORD drives;
57 LONG count;
60 struct enumdata {
61 union
63 struct
65 struct foldercollection *coll;
66 HANDLE find;
67 } foldercoll;
68 struct
70 struct filecollection *coll;
71 HANDLE find;
72 } filecoll;
73 struct
75 struct drivecollection *coll;
76 INT cur;
77 } drivecoll;
78 } u;
81 struct enumvariant {
82 IEnumVARIANT IEnumVARIANT_iface;
83 LONG ref;
85 struct enumdata data;
88 struct drive {
89 IDrive IDrive_iface;
90 LONG ref;
91 BSTR root;
94 struct folder {
95 IFolder IFolder_iface;
96 LONG ref;
97 BSTR path;
100 struct file {
101 IFile IFile_iface;
102 LONG ref;
104 WCHAR *path;
107 struct textstream {
108 ITextStream ITextStream_iface;
109 LONG ref;
111 IOMode mode;
112 BOOL unicode;
113 BOOL first_write;
114 LARGE_INTEGER size;
115 HANDLE file;
118 enum iotype {
119 IORead,
120 IOWrite
123 static inline struct drive *impl_from_IDrive(IDrive *iface)
125 return CONTAINING_RECORD(iface, struct drive, IDrive_iface);
128 static inline struct folder *impl_from_IFolder(IFolder *iface)
130 return CONTAINING_RECORD(iface, struct folder, IFolder_iface);
133 static inline struct file *impl_from_IFile(IFile *iface)
135 return CONTAINING_RECORD(iface, struct file, IFile_iface);
138 static inline struct textstream *impl_from_ITextStream(ITextStream *iface)
140 return CONTAINING_RECORD(iface, struct textstream, ITextStream_iface);
143 static inline struct foldercollection *impl_from_IFolderCollection(IFolderCollection *iface)
145 return CONTAINING_RECORD(iface, struct foldercollection, IFolderCollection_iface);
148 static inline struct filecollection *impl_from_IFileCollection(IFileCollection *iface)
150 return CONTAINING_RECORD(iface, struct filecollection, IFileCollection_iface);
153 static inline struct drivecollection *impl_from_IDriveCollection(IDriveCollection *iface)
155 return CONTAINING_RECORD(iface, struct drivecollection, IDriveCollection_iface);
158 static inline struct enumvariant *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
160 return CONTAINING_RECORD(iface, struct enumvariant, IEnumVARIANT_iface);
163 static inline HRESULT create_error(DWORD err)
165 switch(err) {
166 case ERROR_FILE_NOT_FOUND: return CTL_E_FILENOTFOUND;
167 case ERROR_PATH_NOT_FOUND: return CTL_E_PATHNOTFOUND;
168 case ERROR_ACCESS_DENIED: return CTL_E_PERMISSIONDENIED;
169 case ERROR_FILE_EXISTS: return CTL_E_FILEALREADYEXISTS;
170 case ERROR_ALREADY_EXISTS: return CTL_E_FILEALREADYEXISTS;
171 default:
172 FIXME("Unsupported error code: %d\n", err);
173 return E_FAIL;
177 static HRESULT create_folder(const WCHAR*, IFolder**);
178 static HRESULT create_file(BSTR, IFile**);
179 static HRESULT create_foldercoll_enum(struct foldercollection*, IUnknown**);
180 static HRESULT create_filecoll_enum(struct filecollection*, IUnknown**);
182 static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data)
184 static const WCHAR dotdotW[] = {'.','.',0};
185 static const WCHAR dotW[] = {'.',0};
187 return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
188 strcmpW(data->cFileName, dotdotW) &&
189 strcmpW(data->cFileName, dotW);
192 static inline BOOL is_file_data(const WIN32_FIND_DATAW *data)
194 return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
197 static BSTR get_full_path(BSTR path, const WIN32_FIND_DATAW *data)
199 int len = SysStringLen(path);
200 WCHAR buffW[MAX_PATH];
202 strcpyW(buffW, path);
203 if (path[len-1] != '\\')
204 strcatW(buffW, bsW);
205 strcatW(buffW, data->cFileName);
207 return SysAllocString(buffW);
210 static BOOL textstream_check_iomode(struct textstream *This, enum iotype type)
212 if (type == IORead)
213 return This->mode == ForWriting || This->mode == ForAppending;
214 else
215 return This->mode == ForReading;
218 static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
220 struct textstream *This = impl_from_ITextStream(iface);
222 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
224 if (IsEqualIID(riid, &IID_ITextStream) ||
225 IsEqualIID(riid, &IID_IDispatch) ||
226 IsEqualIID(riid, &IID_IUnknown))
228 *obj = iface;
229 ITextStream_AddRef(iface);
230 return S_OK;
233 *obj = NULL;
234 return E_NOINTERFACE;
237 static ULONG WINAPI textstream_AddRef(ITextStream *iface)
239 struct textstream *This = impl_from_ITextStream(iface);
240 ULONG ref = InterlockedIncrement(&This->ref);
241 TRACE("(%p)->(%d)\n", This, ref);
242 return ref;
245 static ULONG WINAPI textstream_Release(ITextStream *iface)
247 struct textstream *This = impl_from_ITextStream(iface);
248 ULONG ref = InterlockedDecrement(&This->ref);
249 TRACE("(%p)->(%d)\n", This, ref);
251 if (!ref)
253 CloseHandle(This->file);
254 heap_free(This);
257 return ref;
260 static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
262 struct textstream *This = impl_from_ITextStream(iface);
263 TRACE("(%p)->(%p)\n", This, pctinfo);
264 *pctinfo = 1;
265 return S_OK;
268 static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
269 LCID lcid, ITypeInfo **ppTInfo)
271 struct textstream *This = impl_from_ITextStream(iface);
272 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
273 return get_typeinfo(ITextStream_tid, ppTInfo);
276 static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
277 LPOLESTR *rgszNames, UINT cNames,
278 LCID lcid, DISPID *rgDispId)
280 struct textstream *This = impl_from_ITextStream(iface);
281 ITypeInfo *typeinfo;
282 HRESULT hr;
284 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
286 hr = get_typeinfo(ITextStream_tid, &typeinfo);
287 if(SUCCEEDED(hr))
289 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
290 ITypeInfo_Release(typeinfo);
293 return hr;
296 static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
297 REFIID riid, LCID lcid, WORD wFlags,
298 DISPPARAMS *pDispParams, VARIANT *pVarResult,
299 EXCEPINFO *pExcepInfo, UINT *puArgErr)
301 struct textstream *This = impl_from_ITextStream(iface);
302 ITypeInfo *typeinfo;
303 HRESULT hr;
305 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
306 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
308 hr = get_typeinfo(ITextStream_tid, &typeinfo);
309 if(SUCCEEDED(hr))
311 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
312 pDispParams, pVarResult, pExcepInfo, puArgErr);
313 ITypeInfo_Release(typeinfo);
316 return hr;
319 static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
321 struct textstream *This = impl_from_ITextStream(iface);
322 FIXME("(%p)->(%p): stub\n", This, line);
323 return E_NOTIMPL;
326 static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
328 struct textstream *This = impl_from_ITextStream(iface);
329 FIXME("(%p)->(%p): stub\n", This, column);
330 return E_NOTIMPL;
333 static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
335 struct textstream *This = impl_from_ITextStream(iface);
336 LARGE_INTEGER pos, dist;
338 TRACE("(%p)->(%p)\n", This, eos);
340 if (!eos)
341 return E_POINTER;
343 if (textstream_check_iomode(This, IORead)) {
344 *eos = VARIANT_TRUE;
345 return CTL_E_BADFILEMODE;
348 dist.QuadPart = 0;
349 if (!SetFilePointerEx(This->file, dist, &pos, FILE_CURRENT))
350 return E_FAIL;
352 *eos = This->size.QuadPart == pos.QuadPart ? VARIANT_TRUE : VARIANT_FALSE;
353 return S_OK;
356 static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
358 struct textstream *This = impl_from_ITextStream(iface);
359 FIXME("(%p)->(%p): stub\n", This, eol);
360 return E_NOTIMPL;
363 static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
365 struct textstream *This = impl_from_ITextStream(iface);
366 FIXME("(%p)->(%p): stub\n", This, text);
368 if (textstream_check_iomode(This, IORead))
369 return CTL_E_BADFILEMODE;
371 return E_NOTIMPL;
374 static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
376 struct textstream *This = impl_from_ITextStream(iface);
377 FIXME("(%p)->(%p): stub\n", This, text);
379 if (textstream_check_iomode(This, IORead))
380 return CTL_E_BADFILEMODE;
382 return E_NOTIMPL;
385 static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
387 struct textstream *This = impl_from_ITextStream(iface);
388 FIXME("(%p)->(%p): stub\n", This, text);
390 if (textstream_check_iomode(This, IORead))
391 return CTL_E_BADFILEMODE;
393 return E_NOTIMPL;
396 static HRESULT textstream_writestr(struct textstream *stream, BSTR text)
398 DWORD written = 0;
399 BOOL ret;
401 if (stream->unicode) {
402 if (stream->first_write) {
403 static const WCHAR utf16bom = 0xfeff;
404 DWORD written = 0;
405 BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL);
406 if (!ret || written != sizeof(utf16bom))
407 return create_error(GetLastError());
408 stream->first_write = FALSE;
411 ret = WriteFile(stream->file, text, SysStringByteLen(text), &written, NULL);
412 return (ret && written == SysStringByteLen(text)) ? S_OK : create_error(GetLastError());
413 } else {
414 DWORD len = WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), NULL, 0, NULL, NULL);
415 char *buffA;
416 HRESULT hr;
418 buffA = heap_alloc(len);
419 if (!buffA)
420 return E_OUTOFMEMORY;
422 WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), buffA, len, NULL, NULL);
423 ret = WriteFile(stream->file, buffA, len, &written, NULL);
424 hr = (ret && written == len) ? S_OK : create_error(GetLastError());
425 heap_free(buffA);
426 return hr;
430 static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
432 struct textstream *This = impl_from_ITextStream(iface);
434 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
436 if (textstream_check_iomode(This, IOWrite))
437 return CTL_E_BADFILEMODE;
439 return textstream_writestr(This, text);
442 static HRESULT textstream_writecrlf(struct textstream *stream)
444 static const WCHAR crlfW[] = {'\r','\n'};
445 static const char crlfA[] = {'\r','\n'};
446 DWORD written = 0, len;
447 const void *ptr;
448 BOOL ret;
450 if (stream->unicode) {
451 ptr = crlfW;
452 len = sizeof(crlfW);
454 else {
455 ptr = crlfA;
456 len = sizeof(crlfA);
459 ret = WriteFile(stream->file, ptr, len, &written, NULL);
460 return (ret && written == len) ? S_OK : create_error(GetLastError());
463 static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
465 struct textstream *This = impl_from_ITextStream(iface);
466 HRESULT hr;
468 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
470 if (textstream_check_iomode(This, IOWrite))
471 return CTL_E_BADFILEMODE;
473 hr = textstream_writestr(This, text);
474 if (SUCCEEDED(hr))
475 hr = textstream_writecrlf(This);
476 return hr;
479 static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
481 struct textstream *This = impl_from_ITextStream(iface);
482 FIXME("(%p)->(%d): stub\n", This, lines);
483 return E_NOTIMPL;
486 static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
488 struct textstream *This = impl_from_ITextStream(iface);
489 FIXME("(%p)->(%d): stub\n", This, count);
490 return E_NOTIMPL;
493 static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
495 struct textstream *This = impl_from_ITextStream(iface);
496 FIXME("(%p): stub\n", This);
497 return E_NOTIMPL;
500 static HRESULT WINAPI textstream_Close(ITextStream *iface)
502 struct textstream *This = impl_from_ITextStream(iface);
503 FIXME("(%p): stub\n", This);
504 return E_NOTIMPL;
507 static const ITextStreamVtbl textstreamvtbl = {
508 textstream_QueryInterface,
509 textstream_AddRef,
510 textstream_Release,
511 textstream_GetTypeInfoCount,
512 textstream_GetTypeInfo,
513 textstream_GetIDsOfNames,
514 textstream_Invoke,
515 textstream_get_Line,
516 textstream_get_Column,
517 textstream_get_AtEndOfStream,
518 textstream_get_AtEndOfLine,
519 textstream_Read,
520 textstream_ReadLine,
521 textstream_ReadAll,
522 textstream_Write,
523 textstream_WriteLine,
524 textstream_WriteBlankLines,
525 textstream_Skip,
526 textstream_SkipLine,
527 textstream_Close
530 static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMode mode, BOOL unicode, ITextStream **ret)
532 struct textstream *stream;
533 DWORD access = 0;
535 /* map access mode */
536 switch (mode)
538 case ForReading:
539 access = GENERIC_READ;
540 break;
541 case ForWriting:
542 access = GENERIC_WRITE;
543 break;
544 case ForAppending:
545 access = FILE_APPEND_DATA;
546 break;
547 default:
548 return E_INVALIDARG;
551 stream = heap_alloc(sizeof(struct textstream));
552 if (!stream) return E_OUTOFMEMORY;
554 stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
555 stream->ref = 1;
556 stream->mode = mode;
557 stream->unicode = unicode;
558 stream->first_write = TRUE;
560 stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
561 if (stream->file == INVALID_HANDLE_VALUE)
563 HRESULT hr = create_error(GetLastError());
564 heap_free(stream);
565 return hr;
568 if (mode == ForReading)
569 GetFileSizeEx(stream->file, &stream->size);
570 else
571 stream->size.QuadPart = 0;
573 *ret = &stream->ITextStream_iface;
574 return S_OK;
577 static HRESULT WINAPI drive_QueryInterface(IDrive *iface, REFIID riid, void **obj)
579 struct drive *This = impl_from_IDrive(iface);
581 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
583 *obj = NULL;
585 if (IsEqualIID( riid, &IID_IDrive ) ||
586 IsEqualIID( riid, &IID_IDispatch ) ||
587 IsEqualIID( riid, &IID_IUnknown))
589 *obj = iface;
590 IDrive_AddRef(iface);
592 else
593 return E_NOINTERFACE;
595 return S_OK;
598 static ULONG WINAPI drive_AddRef(IDrive *iface)
600 struct drive *This = impl_from_IDrive(iface);
601 ULONG ref = InterlockedIncrement(&This->ref);
602 TRACE("(%p)->(%d)\n", This, ref);
603 return ref;
606 static ULONG WINAPI drive_Release(IDrive *iface)
608 struct drive *This = impl_from_IDrive(iface);
609 ULONG ref = InterlockedDecrement(&This->ref);
610 TRACE("(%p)->(%d)\n", This, ref);
612 if (!ref)
614 SysFreeString(This->root);
615 heap_free(This);
618 return ref;
621 static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo)
623 struct drive *This = impl_from_IDrive(iface);
624 TRACE("(%p)->(%p)\n", This, pctinfo);
625 *pctinfo = 1;
626 return S_OK;
629 static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo,
630 LCID lcid, ITypeInfo **ppTInfo)
632 struct drive *This = impl_from_IDrive(iface);
633 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
634 return get_typeinfo(IDrive_tid, ppTInfo);
637 static HRESULT WINAPI drive_GetIDsOfNames(IDrive *iface, REFIID riid,
638 LPOLESTR *rgszNames, UINT cNames,
639 LCID lcid, DISPID *rgDispId)
641 struct drive *This = impl_from_IDrive(iface);
642 ITypeInfo *typeinfo;
643 HRESULT hr;
645 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
647 hr = get_typeinfo(IDrive_tid, &typeinfo);
648 if(SUCCEEDED(hr))
650 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
651 ITypeInfo_Release(typeinfo);
654 return hr;
657 static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember,
658 REFIID riid, LCID lcid, WORD wFlags,
659 DISPPARAMS *pDispParams, VARIANT *pVarResult,
660 EXCEPINFO *pExcepInfo, UINT *puArgErr)
662 struct drive *This = impl_from_IDrive(iface);
663 ITypeInfo *typeinfo;
664 HRESULT hr;
666 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
667 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
669 hr = get_typeinfo(IDrive_tid, &typeinfo);
670 if(SUCCEEDED(hr))
672 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
673 pDispParams, pVarResult, pExcepInfo, puArgErr);
674 ITypeInfo_Release(typeinfo);
677 return hr;
680 static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path)
682 struct drive *This = impl_from_IDrive(iface);
683 FIXME("(%p)->(%p): stub\n", This, path);
684 return E_NOTIMPL;
687 static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter)
689 struct drive *This = impl_from_IDrive(iface);
690 FIXME("(%p)->(%p): stub\n", This, letter);
691 return E_NOTIMPL;
694 static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name)
696 struct drive *This = impl_from_IDrive(iface);
697 FIXME("(%p)->(%p): stub\n", This, share_name);
698 return E_NOTIMPL;
701 static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type)
703 struct drive *This = impl_from_IDrive(iface);
705 TRACE("(%p)->(%p)\n", This, type);
707 switch (GetDriveTypeW(This->root))
709 case DRIVE_REMOVABLE:
710 *type = Removable;
711 break;
712 case DRIVE_FIXED:
713 *type = Fixed;
714 break;
715 case DRIVE_REMOTE:
716 *type = Remote;
717 break;
718 case DRIVE_CDROM:
719 *type = CDRom;
720 break;
721 case DRIVE_RAMDISK:
722 *type = RamDisk;
723 break;
724 default:
725 *type = UnknownType;
726 break;
729 return S_OK;
732 static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder)
734 struct drive *This = impl_from_IDrive(iface);
735 FIXME("(%p)->(%p): stub\n", This, folder);
736 return E_NOTIMPL;
739 static HRESULT WINAPI drive_get_AvailableSpace(IDrive *iface, VARIANT *avail)
741 struct drive *This = impl_from_IDrive(iface);
742 FIXME("(%p)->(%p): stub\n", This, avail);
743 return E_NOTIMPL;
746 static HRESULT WINAPI drive_get_FreeSpace(IDrive *iface, VARIANT *v)
748 struct drive *This = impl_from_IDrive(iface);
749 FIXME("(%p)->(%p): stub\n", This, v);
750 return E_NOTIMPL;
753 static HRESULT WINAPI drive_get_TotalSize(IDrive *iface, VARIANT *v)
755 struct drive *This = impl_from_IDrive(iface);
756 FIXME("(%p)->(%p): stub\n", This, v);
757 return E_NOTIMPL;
760 static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name)
762 struct drive *This = impl_from_IDrive(iface);
763 FIXME("(%p)->(%p): stub\n", This, name);
764 return E_NOTIMPL;
767 static HRESULT WINAPI drive_put_VolumeName(IDrive *iface, BSTR name)
769 struct drive *This = impl_from_IDrive(iface);
770 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
771 return E_NOTIMPL;
774 static HRESULT WINAPI drive_get_FileSystem(IDrive *iface, BSTR *fs)
776 struct drive *This = impl_from_IDrive(iface);
777 FIXME("(%p)->(%p): stub\n", This, fs);
778 return E_NOTIMPL;
781 static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial)
783 struct drive *This = impl_from_IDrive(iface);
784 FIXME("(%p)->(%p): stub\n", This, serial);
785 return E_NOTIMPL;
788 static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
790 struct drive *This = impl_from_IDrive(iface);
791 FIXME("(%p)->(%p): stub\n", This, ready);
792 return E_NOTIMPL;
795 static const IDriveVtbl drivevtbl = {
796 drive_QueryInterface,
797 drive_AddRef,
798 drive_Release,
799 drive_GetTypeInfoCount,
800 drive_GetTypeInfo,
801 drive_GetIDsOfNames,
802 drive_Invoke,
803 drive_get_Path,
804 drive_get_DriveLetter,
805 drive_get_ShareName,
806 drive_get_DriveType,
807 drive_get_RootFolder,
808 drive_get_AvailableSpace,
809 drive_get_FreeSpace,
810 drive_get_TotalSize,
811 drive_get_VolumeName,
812 drive_put_VolumeName,
813 drive_get_FileSystem,
814 drive_get_SerialNumber,
815 drive_get_IsReady
818 static HRESULT create_drive(WCHAR letter, IDrive **drive)
820 struct drive *This;
822 *drive = NULL;
824 This = heap_alloc(sizeof(*This));
825 if (!This) return E_OUTOFMEMORY;
827 This->IDrive_iface.lpVtbl = &drivevtbl;
828 This->ref = 1;
829 This->root = SysAllocStringLen(NULL, 3);
830 if (!This->root)
832 heap_free(This);
833 return E_OUTOFMEMORY;
835 This->root[0] = letter;
836 This->root[1] = ':';
837 This->root[2] = '\\';
838 This->root[3] = 0;
840 *drive = &This->IDrive_iface;
841 return S_OK;
844 static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
846 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
848 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
850 *obj = NULL;
852 if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
853 IsEqualIID( riid, &IID_IUnknown ))
855 *obj = iface;
856 IEnumVARIANT_AddRef(iface);
858 else
859 return E_NOINTERFACE;
861 return S_OK;
864 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
866 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
867 ULONG ref = InterlockedIncrement(&This->ref);
868 TRACE("(%p)->(%d)\n", This, ref);
869 return ref;
872 static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
874 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
875 ULONG ref = InterlockedDecrement(&This->ref);
877 TRACE("(%p)->(%d)\n", This, ref);
879 if (!ref)
881 IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
882 FindClose(This->data.u.foldercoll.find);
883 heap_free(This);
886 return ref;
889 static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file)
891 static const WCHAR allW[] = {'*',0};
892 WCHAR pathW[MAX_PATH];
893 int len;
894 HANDLE handle;
896 strcpyW(pathW, path);
897 len = strlenW(pathW);
898 if (pathW[len-1] != '\\')
899 strcatW(pathW, bsW);
900 strcatW(pathW, allW);
901 handle = FindFirstFileW(pathW, data);
902 if (handle == INVALID_HANDLE_VALUE) return 0;
904 /* find first dir/file */
905 while (1)
907 if (file ? is_file_data(data) : is_dir_data(data))
908 break;
910 if (!FindNextFileW(handle, data))
912 FindClose(handle);
913 return 0;
916 return handle;
919 static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
921 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
922 HANDLE handle = This->data.u.foldercoll.find;
923 WIN32_FIND_DATAW data;
924 ULONG count = 0;
926 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
928 if (fetched)
929 *fetched = 0;
931 if (!celt) return S_OK;
933 if (!handle)
935 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
936 if (!handle) return S_FALSE;
938 This->data.u.foldercoll.find = handle;
940 else
942 if (!FindNextFileW(handle, &data))
943 return S_FALSE;
948 if (is_dir_data(&data))
950 IFolder *folder;
951 HRESULT hr;
952 BSTR str;
954 str = get_full_path(This->data.u.foldercoll.coll->path, &data);
955 hr = create_folder(str, &folder);
956 SysFreeString(str);
957 if (FAILED(hr)) return hr;
959 V_VT(&var[count]) = VT_DISPATCH;
960 V_DISPATCH(&var[count]) = (IDispatch*)folder;
961 count++;
963 if (count >= celt) break;
965 } while (FindNextFileW(handle, &data));
967 if (fetched)
968 *fetched = count;
970 return (count < celt) ? S_FALSE : S_OK;
973 static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
975 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
976 HANDLE handle = This->data.u.foldercoll.find;
977 WIN32_FIND_DATAW data;
979 TRACE("(%p)->(%d)\n", This, celt);
981 if (!celt) return S_OK;
983 if (!handle)
985 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
986 if (!handle) return S_FALSE;
988 This->data.u.foldercoll.find = handle;
990 else
992 if (!FindNextFileW(handle, &data))
993 return S_FALSE;
998 if (is_dir_data(&data))
999 --celt;
1001 if (!celt) break;
1002 } while (FindNextFileW(handle, &data));
1004 return celt ? S_FALSE : S_OK;
1007 static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
1009 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1011 TRACE("(%p)\n", This);
1013 FindClose(This->data.u.foldercoll.find);
1014 This->data.u.foldercoll.find = NULL;
1016 return S_OK;
1019 static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1021 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1022 TRACE("(%p)->(%p)\n", This, pclone);
1023 return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
1026 static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
1027 enumvariant_QueryInterface,
1028 enumvariant_AddRef,
1029 foldercoll_enumvariant_Release,
1030 foldercoll_enumvariant_Next,
1031 foldercoll_enumvariant_Skip,
1032 foldercoll_enumvariant_Reset,
1033 foldercoll_enumvariant_Clone
1036 static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
1038 struct enumvariant *This;
1040 *newenum = NULL;
1042 This = heap_alloc(sizeof(*This));
1043 if (!This) return E_OUTOFMEMORY;
1045 This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
1046 This->ref = 1;
1047 This->data.u.foldercoll.find = NULL;
1048 This->data.u.foldercoll.coll = collection;
1049 IFolderCollection_AddRef(&collection->IFolderCollection_iface);
1051 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1053 return S_OK;
1056 static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface)
1058 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1059 ULONG ref = InterlockedDecrement(&This->ref);
1061 TRACE("(%p)->(%d)\n", This, ref);
1063 if (!ref)
1065 IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
1066 FindClose(This->data.u.filecoll.find);
1067 heap_free(This);
1070 return ref;
1073 static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1075 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1076 HANDLE handle = This->data.u.filecoll.find;
1077 WIN32_FIND_DATAW data;
1078 ULONG count = 0;
1080 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1082 if (fetched)
1083 *fetched = 0;
1085 if (!celt) return S_OK;
1087 if (!handle)
1089 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1090 if (!handle) return S_FALSE;
1091 This->data.u.filecoll.find = handle;
1093 else if (!FindNextFileW(handle, &data))
1094 return S_FALSE;
1098 if (is_file_data(&data))
1100 IFile *file;
1101 HRESULT hr;
1102 BSTR str;
1104 str = get_full_path(This->data.u.filecoll.coll->path, &data);
1105 hr = create_file(str, &file);
1106 SysFreeString(str);
1107 if (FAILED(hr)) return hr;
1109 V_VT(&var[count]) = VT_DISPATCH;
1110 V_DISPATCH(&var[count]) = (IDispatch*)file;
1111 if (++count >= celt) break;
1113 } while (FindNextFileW(handle, &data));
1115 if (fetched)
1116 *fetched = count;
1118 return (count < celt) ? S_FALSE : S_OK;
1121 static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1123 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1124 HANDLE handle = This->data.u.filecoll.find;
1125 WIN32_FIND_DATAW data;
1127 TRACE("(%p)->(%d)\n", This, celt);
1129 if (!celt) return S_OK;
1131 if (!handle)
1133 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1134 if (!handle) return S_FALSE;
1135 This->data.u.filecoll.find = handle;
1137 else if (!FindNextFileW(handle, &data))
1138 return S_FALSE;
1142 if (is_file_data(&data))
1143 --celt;
1144 } while (celt && FindNextFileW(handle, &data));
1146 return celt ? S_FALSE : S_OK;
1149 static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface)
1151 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1153 TRACE("(%p)\n", This);
1155 FindClose(This->data.u.filecoll.find);
1156 This->data.u.filecoll.find = NULL;
1158 return S_OK;
1161 static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1163 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1164 TRACE("(%p)->(%p)\n", This, pclone);
1165 return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
1168 static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
1169 enumvariant_QueryInterface,
1170 enumvariant_AddRef,
1171 filecoll_enumvariant_Release,
1172 filecoll_enumvariant_Next,
1173 filecoll_enumvariant_Skip,
1174 filecoll_enumvariant_Reset,
1175 filecoll_enumvariant_Clone
1178 static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum)
1180 struct enumvariant *This;
1182 *newenum = NULL;
1184 This = heap_alloc(sizeof(*This));
1185 if (!This) return E_OUTOFMEMORY;
1187 This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
1188 This->ref = 1;
1189 This->data.u.filecoll.find = NULL;
1190 This->data.u.filecoll.coll = collection;
1191 IFileCollection_AddRef(&collection->IFileCollection_iface);
1193 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1195 return S_OK;
1198 static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface)
1200 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1201 ULONG ref = InterlockedDecrement(&This->ref);
1203 TRACE("(%p)->(%d)\n", This, ref);
1205 if (!ref)
1207 IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
1208 heap_free(This);
1211 return ref;
1214 static HRESULT find_next_drive(struct enumvariant *penum)
1216 int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
1218 for (; i < 32; i++)
1219 if (penum->data.u.drivecoll.coll->drives & (1 << i))
1221 penum->data.u.drivecoll.cur = i;
1222 return S_OK;
1225 return S_FALSE;
1228 static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1230 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1231 ULONG count = 0;
1233 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1235 if (fetched)
1236 *fetched = 0;
1238 if (!celt) return S_OK;
1240 while (find_next_drive(This) == S_OK)
1242 IDrive *drive;
1243 HRESULT hr;
1245 hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
1246 if (FAILED(hr)) return hr;
1248 V_VT(&var[count]) = VT_DISPATCH;
1249 V_DISPATCH(&var[count]) = (IDispatch*)drive;
1251 if (++count >= celt) break;
1254 if (fetched)
1255 *fetched = count;
1257 return (count < celt) ? S_FALSE : S_OK;
1260 static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1262 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1264 TRACE("(%p)->(%d)\n", This, celt);
1266 if (!celt) return S_OK;
1268 while (celt && find_next_drive(This) == S_OK)
1269 celt--;
1271 return celt ? S_FALSE : S_OK;
1274 static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface)
1276 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1278 TRACE("(%p)\n", This);
1280 This->data.u.drivecoll.cur = -1;
1281 return S_OK;
1284 static HRESULT WINAPI drivecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1286 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1287 FIXME("(%p)->(%p): stub\n", This, pclone);
1288 return E_NOTIMPL;
1291 static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
1292 enumvariant_QueryInterface,
1293 enumvariant_AddRef,
1294 drivecoll_enumvariant_Release,
1295 drivecoll_enumvariant_Next,
1296 drivecoll_enumvariant_Skip,
1297 drivecoll_enumvariant_Reset,
1298 drivecoll_enumvariant_Clone
1301 static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum)
1303 struct enumvariant *This;
1305 *newenum = NULL;
1307 This = heap_alloc(sizeof(*This));
1308 if (!This) return E_OUTOFMEMORY;
1310 This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
1311 This->ref = 1;
1312 This->data.u.drivecoll.coll = collection;
1313 This->data.u.drivecoll.cur = -1;
1314 IDriveCollection_AddRef(&collection->IDriveCollection_iface);
1316 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1318 return S_OK;
1321 static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
1323 struct foldercollection *This = impl_from_IFolderCollection(iface);
1325 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1327 *obj = NULL;
1329 if (IsEqualIID( riid, &IID_IFolderCollection ) ||
1330 IsEqualIID( riid, &IID_IDispatch ) ||
1331 IsEqualIID( riid, &IID_IUnknown ))
1333 *obj = iface;
1334 IFolderCollection_AddRef(iface);
1336 else
1337 return E_NOINTERFACE;
1339 return S_OK;
1342 static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
1344 struct foldercollection *This = impl_from_IFolderCollection(iface);
1345 ULONG ref = InterlockedIncrement(&This->ref);
1346 TRACE("(%p)->(%d)\n", This, ref);
1347 return ref;
1350 static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
1352 struct foldercollection *This = impl_from_IFolderCollection(iface);
1353 ULONG ref = InterlockedDecrement(&This->ref);
1354 TRACE("(%p)->(%d)\n", This, ref);
1356 if (!ref)
1358 SysFreeString(This->path);
1359 heap_free(This);
1362 return ref;
1365 static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
1367 struct foldercollection *This = impl_from_IFolderCollection(iface);
1368 TRACE("(%p)->(%p)\n", This, pctinfo);
1369 *pctinfo = 1;
1370 return S_OK;
1373 static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
1374 LCID lcid, ITypeInfo **ppTInfo)
1376 struct foldercollection *This = impl_from_IFolderCollection(iface);
1377 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1378 return get_typeinfo(IFolderCollection_tid, ppTInfo);
1381 static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
1382 LPOLESTR *rgszNames, UINT cNames,
1383 LCID lcid, DISPID *rgDispId)
1385 struct foldercollection *This = impl_from_IFolderCollection(iface);
1386 ITypeInfo *typeinfo;
1387 HRESULT hr;
1389 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1391 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1392 if(SUCCEEDED(hr))
1394 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1395 ITypeInfo_Release(typeinfo);
1398 return hr;
1401 static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
1402 REFIID riid, LCID lcid, WORD wFlags,
1403 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1404 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1406 struct foldercollection *This = impl_from_IFolderCollection(iface);
1407 ITypeInfo *typeinfo;
1408 HRESULT hr;
1410 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1411 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1413 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1414 if(SUCCEEDED(hr))
1416 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1417 pDispParams, pVarResult, pExcepInfo, puArgErr);
1418 ITypeInfo_Release(typeinfo);
1421 return hr;
1424 static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
1426 struct foldercollection *This = impl_from_IFolderCollection(iface);
1427 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
1428 return E_NOTIMPL;
1431 static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
1433 struct foldercollection *This = impl_from_IFolderCollection(iface);
1434 FIXME("(%p)->(%p): stub\n", This, folder);
1435 return E_NOTIMPL;
1438 static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
1440 struct foldercollection *This = impl_from_IFolderCollection(iface);
1442 TRACE("(%p)->(%p)\n", This, newenum);
1444 if(!newenum)
1445 return E_POINTER;
1447 return create_foldercoll_enum(This, newenum);
1450 static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
1452 struct foldercollection *This = impl_from_IFolderCollection(iface);
1453 static const WCHAR allW[] = {'\\','*',0};
1454 WIN32_FIND_DATAW data;
1455 WCHAR pathW[MAX_PATH];
1456 HANDLE handle;
1458 TRACE("(%p)->(%p)\n", This, count);
1460 if(!count)
1461 return E_POINTER;
1463 *count = 0;
1465 strcpyW(pathW, This->path);
1466 strcatW(pathW, allW);
1467 handle = FindFirstFileW(pathW, &data);
1468 if (handle == INVALID_HANDLE_VALUE)
1469 return HRESULT_FROM_WIN32(GetLastError());
1473 if (is_dir_data(&data))
1474 *count += 1;
1475 } while (FindNextFileW(handle, &data));
1476 FindClose(handle);
1478 return S_OK;
1481 static const IFolderCollectionVtbl foldercollvtbl = {
1482 foldercoll_QueryInterface,
1483 foldercoll_AddRef,
1484 foldercoll_Release,
1485 foldercoll_GetTypeInfoCount,
1486 foldercoll_GetTypeInfo,
1487 foldercoll_GetIDsOfNames,
1488 foldercoll_Invoke,
1489 foldercoll_Add,
1490 foldercoll_get_Item,
1491 foldercoll_get__NewEnum,
1492 foldercoll_get_Count
1495 static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
1497 struct foldercollection *This;
1499 *folders = NULL;
1501 This = heap_alloc(sizeof(struct foldercollection));
1502 if (!This) return E_OUTOFMEMORY;
1504 This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
1505 This->ref = 1;
1506 This->path = SysAllocString(path);
1507 if (!This->path)
1509 heap_free(This);
1510 return E_OUTOFMEMORY;
1513 *folders = &This->IFolderCollection_iface;
1515 return S_OK;
1518 static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj)
1520 struct filecollection *This = impl_from_IFileCollection(iface);
1522 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1524 *obj = NULL;
1526 if (IsEqualIID( riid, &IID_IFileCollection ) ||
1527 IsEqualIID( riid, &IID_IDispatch ) ||
1528 IsEqualIID( riid, &IID_IUnknown ))
1530 *obj = iface;
1531 IFileCollection_AddRef(iface);
1533 else
1534 return E_NOINTERFACE;
1536 return S_OK;
1539 static ULONG WINAPI filecoll_AddRef(IFileCollection *iface)
1541 struct filecollection *This = impl_from_IFileCollection(iface);
1542 ULONG ref = InterlockedIncrement(&This->ref);
1543 TRACE("(%p)->(%d)\n", This, ref);
1544 return ref;
1547 static ULONG WINAPI filecoll_Release(IFileCollection *iface)
1549 struct filecollection *This = impl_from_IFileCollection(iface);
1550 ULONG ref = InterlockedDecrement(&This->ref);
1551 TRACE("(%p)->(%d)\n", This, ref);
1553 if (!ref)
1555 SysFreeString(This->path);
1556 heap_free(This);
1559 return ref;
1562 static HRESULT WINAPI filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo)
1564 struct filecollection *This = impl_from_IFileCollection(iface);
1565 TRACE("(%p)->(%p)\n", This, pctinfo);
1566 *pctinfo = 1;
1567 return S_OK;
1570 static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo,
1571 LCID lcid, ITypeInfo **ppTInfo)
1573 struct filecollection *This = impl_from_IFileCollection(iface);
1574 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1575 return get_typeinfo(IFileCollection_tid, ppTInfo);
1578 static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid,
1579 LPOLESTR *rgszNames, UINT cNames,
1580 LCID lcid, DISPID *rgDispId)
1582 struct filecollection *This = impl_from_IFileCollection(iface);
1583 ITypeInfo *typeinfo;
1584 HRESULT hr;
1586 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1588 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1589 if(SUCCEEDED(hr))
1591 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1592 ITypeInfo_Release(typeinfo);
1595 return hr;
1598 static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember,
1599 REFIID riid, LCID lcid, WORD wFlags,
1600 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1601 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1603 struct filecollection *This = impl_from_IFileCollection(iface);
1604 ITypeInfo *typeinfo;
1605 HRESULT hr;
1607 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1608 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1610 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1611 if(SUCCEEDED(hr))
1613 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1614 pDispParams, pVarResult, pExcepInfo, puArgErr);
1615 ITypeInfo_Release(typeinfo);
1618 return hr;
1621 static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file)
1623 struct filecollection *This = impl_from_IFileCollection(iface);
1624 FIXME("(%p)->(%p)\n", This, file);
1625 return E_NOTIMPL;
1628 static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum)
1630 struct filecollection *This = impl_from_IFileCollection(iface);
1632 TRACE("(%p)->(%p)\n", This, ppenum);
1634 if(!ppenum)
1635 return E_POINTER;
1637 return create_filecoll_enum(This, ppenum);
1640 static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count)
1642 struct filecollection *This = impl_from_IFileCollection(iface);
1643 FIXME("(%p)->(%p)\n", This, count);
1644 return E_NOTIMPL;
1647 static const IFileCollectionVtbl filecollectionvtbl = {
1648 filecoll_QueryInterface,
1649 filecoll_AddRef,
1650 filecoll_Release,
1651 filecoll_GetTypeInfoCount,
1652 filecoll_GetTypeInfo,
1653 filecoll_GetIDsOfNames,
1654 filecoll_Invoke,
1655 filecoll_get_Item,
1656 filecoll_get__NewEnum,
1657 filecoll_get_Count
1660 static HRESULT create_filecoll(BSTR path, IFileCollection **files)
1662 struct filecollection *This;
1664 *files = NULL;
1666 This = heap_alloc(sizeof(*This));
1667 if (!This) return E_OUTOFMEMORY;
1669 This->IFileCollection_iface.lpVtbl = &filecollectionvtbl;
1670 This->ref = 1;
1671 This->path = SysAllocString(path);
1672 if (!This->path)
1674 heap_free(This);
1675 return E_OUTOFMEMORY;
1678 *files = &This->IFileCollection_iface;
1679 return S_OK;
1682 static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
1684 struct drivecollection *This = impl_from_IDriveCollection(iface);
1686 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1688 *obj = NULL;
1690 if (IsEqualIID( riid, &IID_IDriveCollection ) ||
1691 IsEqualIID( riid, &IID_IDispatch ) ||
1692 IsEqualIID( riid, &IID_IUnknown ))
1694 *obj = iface;
1695 IDriveCollection_AddRef(iface);
1697 else
1698 return E_NOINTERFACE;
1700 return S_OK;
1703 static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
1705 struct drivecollection *This = impl_from_IDriveCollection(iface);
1706 ULONG ref = InterlockedIncrement(&This->ref);
1707 TRACE("(%p)->(%d)\n", This, ref);
1708 return ref;
1711 static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
1713 struct drivecollection *This = impl_from_IDriveCollection(iface);
1714 ULONG ref = InterlockedDecrement(&This->ref);
1715 TRACE("(%p)->(%d)\n", This, ref);
1717 if (!ref)
1718 heap_free(This);
1720 return ref;
1723 static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
1725 struct drivecollection *This = impl_from_IDriveCollection(iface);
1726 TRACE("(%p)->(%p)\n", This, pctinfo);
1727 *pctinfo = 1;
1728 return S_OK;
1731 static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
1732 LCID lcid, ITypeInfo **ppTInfo)
1734 struct drivecollection *This = impl_from_IDriveCollection(iface);
1735 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1736 return get_typeinfo(IDriveCollection_tid, ppTInfo);
1739 static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
1740 LPOLESTR *rgszNames, UINT cNames,
1741 LCID lcid, DISPID *rgDispId)
1743 struct drivecollection *This = impl_from_IDriveCollection(iface);
1744 ITypeInfo *typeinfo;
1745 HRESULT hr;
1747 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1749 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
1750 if(SUCCEEDED(hr))
1752 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1753 ITypeInfo_Release(typeinfo);
1756 return hr;
1759 static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
1760 REFIID riid, LCID lcid, WORD wFlags,
1761 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1762 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1764 struct drivecollection *This = impl_from_IDriveCollection(iface);
1765 ITypeInfo *typeinfo;
1766 HRESULT hr;
1768 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1769 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1771 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
1772 if(SUCCEEDED(hr))
1774 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1775 pDispParams, pVarResult, pExcepInfo, puArgErr);
1776 ITypeInfo_Release(typeinfo);
1779 return hr;
1782 static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
1784 struct drivecollection *This = impl_from_IDriveCollection(iface);
1785 FIXME("(%p)->(%p): stub\n", This, drive);
1786 return E_NOTIMPL;
1789 static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
1791 struct drivecollection *This = impl_from_IDriveCollection(iface);
1793 TRACE("(%p)->(%p)\n", This, ppenum);
1795 if(!ppenum)
1796 return E_POINTER;
1798 return create_drivecoll_enum(This, ppenum);
1801 static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
1803 struct drivecollection *This = impl_from_IDriveCollection(iface);
1805 TRACE("(%p)->(%p)\n", This, count);
1807 if (!count) return E_POINTER;
1809 *count = This->count;
1810 return S_OK;
1813 static const IDriveCollectionVtbl drivecollectionvtbl = {
1814 drivecoll_QueryInterface,
1815 drivecoll_AddRef,
1816 drivecoll_Release,
1817 drivecoll_GetTypeInfoCount,
1818 drivecoll_GetTypeInfo,
1819 drivecoll_GetIDsOfNames,
1820 drivecoll_Invoke,
1821 drivecoll_get_Item,
1822 drivecoll_get__NewEnum,
1823 drivecoll_get_Count
1826 static HRESULT create_drivecoll(IDriveCollection **drives)
1828 struct drivecollection *This;
1829 DWORD mask;
1831 *drives = NULL;
1833 This = heap_alloc(sizeof(*This));
1834 if (!This) return E_OUTOFMEMORY;
1836 This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl;
1837 This->ref = 1;
1838 This->drives = mask = GetLogicalDrives();
1839 /* count set bits */
1840 for (This->count = 0; mask; This->count++)
1841 mask &= mask - 1;
1843 *drives = &This->IDriveCollection_iface;
1844 return S_OK;
1847 static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
1849 struct folder *This = impl_from_IFolder(iface);
1851 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1853 *obj = NULL;
1855 if (IsEqualIID( riid, &IID_IFolder ) ||
1856 IsEqualIID( riid, &IID_IDispatch ) ||
1857 IsEqualIID( riid, &IID_IUnknown))
1859 *obj = iface;
1860 IFolder_AddRef(iface);
1862 else
1863 return E_NOINTERFACE;
1865 return S_OK;
1868 static ULONG WINAPI folder_AddRef(IFolder *iface)
1870 struct folder *This = impl_from_IFolder(iface);
1871 ULONG ref = InterlockedIncrement(&This->ref);
1872 TRACE("(%p)->(%d)\n", This, ref);
1873 return ref;
1876 static ULONG WINAPI folder_Release(IFolder *iface)
1878 struct folder *This = impl_from_IFolder(iface);
1879 ULONG ref = InterlockedDecrement(&This->ref);
1880 TRACE("(%p)->(%d)\n", This, ref);
1882 if (!ref)
1884 SysFreeString(This->path);
1885 heap_free(This);
1888 return ref;
1891 static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
1893 struct folder *This = impl_from_IFolder(iface);
1894 TRACE("(%p)->(%p)\n", This, pctinfo);
1895 *pctinfo = 1;
1896 return S_OK;
1899 static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
1900 LCID lcid, ITypeInfo **ppTInfo)
1902 struct folder *This = impl_from_IFolder(iface);
1903 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1904 return get_typeinfo(IFolder_tid, ppTInfo);
1907 static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
1908 LPOLESTR *rgszNames, UINT cNames,
1909 LCID lcid, DISPID *rgDispId)
1911 struct folder *This = impl_from_IFolder(iface);
1912 ITypeInfo *typeinfo;
1913 HRESULT hr;
1915 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1917 hr = get_typeinfo(IFolder_tid, &typeinfo);
1918 if(SUCCEEDED(hr))
1920 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1921 ITypeInfo_Release(typeinfo);
1924 return hr;
1927 static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
1928 REFIID riid, LCID lcid, WORD wFlags,
1929 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1930 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1932 struct folder *This = impl_from_IFolder(iface);
1933 ITypeInfo *typeinfo;
1934 HRESULT hr;
1936 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1937 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1939 hr = get_typeinfo(IFolder_tid, &typeinfo);
1940 if(SUCCEEDED(hr))
1942 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1943 pDispParams, pVarResult, pExcepInfo, puArgErr);
1944 ITypeInfo_Release(typeinfo);
1947 return hr;
1950 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
1952 struct folder *This = impl_from_IFolder(iface);
1954 TRACE("(%p)->(%p)\n", This, path);
1956 if(!path)
1957 return E_POINTER;
1959 *path = SysAllocString(This->path);
1960 return *path ? S_OK : E_OUTOFMEMORY;
1963 static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
1965 struct folder *This = impl_from_IFolder(iface);
1966 WCHAR *ptr;
1968 TRACE("(%p)->(%p)\n", This, name);
1970 if(!name)
1971 return E_POINTER;
1973 *name = NULL;
1975 ptr = strrchrW(This->path, '\\');
1976 if (ptr)
1978 *name = SysAllocString(ptr+1);
1979 TRACE("%s\n", debugstr_w(*name));
1980 if (!*name) return E_OUTOFMEMORY;
1982 else
1983 return E_FAIL;
1985 return S_OK;
1988 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
1990 struct folder *This = impl_from_IFolder(iface);
1991 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
1992 return E_NOTIMPL;
1995 static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
1997 struct folder *This = impl_from_IFolder(iface);
1998 FIXME("(%p)->(%p): stub\n", This, path);
1999 return E_NOTIMPL;
2002 static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
2004 struct folder *This = impl_from_IFolder(iface);
2005 FIXME("(%p)->(%p): stub\n", This, name);
2006 return E_NOTIMPL;
2009 static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
2011 struct folder *This = impl_from_IFolder(iface);
2012 FIXME("(%p)->(%p): stub\n", This, drive);
2013 return E_NOTIMPL;
2016 static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
2018 struct folder *This = impl_from_IFolder(iface);
2019 FIXME("(%p)->(%p): stub\n", This, parent);
2020 return E_NOTIMPL;
2023 static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
2025 struct folder *This = impl_from_IFolder(iface);
2026 FIXME("(%p)->(%p): stub\n", This, attr);
2027 return E_NOTIMPL;
2030 static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
2032 struct folder *This = impl_from_IFolder(iface);
2033 FIXME("(%p)->(0x%x): stub\n", This, attr);
2034 return E_NOTIMPL;
2037 static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
2039 struct folder *This = impl_from_IFolder(iface);
2040 FIXME("(%p)->(%p): stub\n", This, date);
2041 return E_NOTIMPL;
2044 static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
2046 struct folder *This = impl_from_IFolder(iface);
2047 FIXME("(%p)->(%p): stub\n", This, date);
2048 return E_NOTIMPL;
2051 static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
2053 struct folder *This = impl_from_IFolder(iface);
2054 FIXME("(%p)->(%p): stub\n", This, date);
2055 return E_NOTIMPL;
2058 static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
2060 struct folder *This = impl_from_IFolder(iface);
2061 FIXME("(%p)->(%p): stub\n", This, type);
2062 return E_NOTIMPL;
2065 static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
2067 struct folder *This = impl_from_IFolder(iface);
2068 FIXME("(%p)->(%x): stub\n", This, force);
2069 return E_NOTIMPL;
2072 static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
2074 struct folder *This = impl_from_IFolder(iface);
2075 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
2076 return E_NOTIMPL;
2079 static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
2081 struct folder *This = impl_from_IFolder(iface);
2082 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
2083 return E_NOTIMPL;
2086 static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
2088 struct folder *This = impl_from_IFolder(iface);
2089 FIXME("(%p)->(%p): stub\n", This, isroot);
2090 return E_NOTIMPL;
2093 static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
2095 struct folder *This = impl_from_IFolder(iface);
2096 FIXME("(%p)->(%p): stub\n", This, size);
2097 return E_NOTIMPL;
2100 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
2102 struct folder *This = impl_from_IFolder(iface);
2104 TRACE("(%p)->(%p)\n", This, folders);
2106 if(!folders)
2107 return E_POINTER;
2109 return create_foldercoll(This->path, folders);
2112 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
2114 struct folder *This = impl_from_IFolder(iface);
2116 TRACE("(%p)->(%p)\n", This, files);
2118 if(!files)
2119 return E_POINTER;
2121 return create_filecoll(This->path, files);
2124 static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
2125 VARIANT_BOOL unicode, ITextStream **stream)
2127 struct folder *This = impl_from_IFolder(iface);
2128 FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
2129 return E_NOTIMPL;
2132 static const IFolderVtbl foldervtbl = {
2133 folder_QueryInterface,
2134 folder_AddRef,
2135 folder_Release,
2136 folder_GetTypeInfoCount,
2137 folder_GetTypeInfo,
2138 folder_GetIDsOfNames,
2139 folder_Invoke,
2140 folder_get_Path,
2141 folder_get_Name,
2142 folder_put_Name,
2143 folder_get_ShortPath,
2144 folder_get_ShortName,
2145 folder_get_Drive,
2146 folder_get_ParentFolder,
2147 folder_get_Attributes,
2148 folder_put_Attributes,
2149 folder_get_DateCreated,
2150 folder_get_DateLastModified,
2151 folder_get_DateLastAccessed,
2152 folder_get_Type,
2153 folder_Delete,
2154 folder_Copy,
2155 folder_Move,
2156 folder_get_IsRootFolder,
2157 folder_get_Size,
2158 folder_get_SubFolders,
2159 folder_get_Files,
2160 folder_CreateTextFile
2163 HRESULT create_folder(const WCHAR *path, IFolder **folder)
2165 struct folder *This;
2167 *folder = NULL;
2169 TRACE("%s\n", debugstr_w(path));
2171 This = heap_alloc(sizeof(struct folder));
2172 if (!This) return E_OUTOFMEMORY;
2174 This->IFolder_iface.lpVtbl = &foldervtbl;
2175 This->ref = 1;
2176 This->path = SysAllocString(path);
2177 if (!This->path)
2179 heap_free(This);
2180 return E_OUTOFMEMORY;
2183 *folder = &This->IFolder_iface;
2185 return S_OK;
2188 static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
2190 struct file *This = impl_from_IFile(iface);
2192 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2194 if (IsEqualIID(riid, &IID_IFile) ||
2195 IsEqualIID(riid, &IID_IDispatch) ||
2196 IsEqualIID(riid, &IID_IUnknown))
2198 *obj = iface;
2199 IFile_AddRef(iface);
2200 return S_OK;
2203 *obj = NULL;
2204 return E_NOINTERFACE;
2207 static ULONG WINAPI file_AddRef(IFile *iface)
2209 struct file *This = impl_from_IFile(iface);
2210 LONG ref = InterlockedIncrement(&This->ref);
2212 TRACE("(%p) ref=%d\n", This, ref);
2214 return ref;
2217 static ULONG WINAPI file_Release(IFile *iface)
2219 struct file *This = impl_from_IFile(iface);
2220 LONG ref = InterlockedDecrement(&This->ref);
2222 TRACE("(%p) ref=%d\n", This, ref);
2224 if(!ref)
2226 heap_free(This->path);
2227 heap_free(This);
2230 return ref;
2233 static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
2235 struct file *This = impl_from_IFile(iface);
2237 TRACE("(%p)->(%p)\n", This, pctinfo);
2239 *pctinfo = 1;
2240 return S_OK;
2243 static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
2244 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
2246 struct file *This = impl_from_IFile(iface);
2248 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2250 return get_typeinfo(IFile_tid, ppTInfo);
2253 static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
2254 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2256 struct file *This = impl_from_IFile(iface);
2257 ITypeInfo *typeinfo;
2258 HRESULT hr;
2260 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
2261 rgszNames, cNames, lcid, rgDispId);
2263 hr = get_typeinfo(IFile_tid, &typeinfo);
2264 if(SUCCEEDED(hr)) {
2265 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2266 ITypeInfo_Release(typeinfo);
2268 return hr;
2271 static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2273 struct file *This = impl_from_IFile(iface);
2274 ITypeInfo *typeinfo;
2275 HRESULT hr;
2277 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2278 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2280 hr = get_typeinfo(IFile_tid, &typeinfo);
2281 if(SUCCEEDED(hr))
2283 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2284 pDispParams, pVarResult, pExcepInfo, puArgErr);
2285 ITypeInfo_Release(typeinfo);
2287 return hr;
2290 static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *pbstrPath)
2292 struct file *This = impl_from_IFile(iface);
2293 FIXME("(%p)->(%p)\n", This, pbstrPath);
2294 return E_NOTIMPL;
2297 static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
2299 struct file *This = impl_from_IFile(iface);
2300 WCHAR *ptr;
2302 TRACE("(%p)->(%p)\n", This, name);
2304 if(!name)
2305 return E_POINTER;
2307 *name = NULL;
2309 ptr = strrchrW(This->path, '\\');
2310 if (ptr)
2312 *name = SysAllocString(ptr+1);
2313 TRACE("%s\n", debugstr_w(*name));
2314 if (!*name) return E_OUTOFMEMORY;
2316 else
2317 return E_FAIL;
2319 return S_OK;
2322 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
2324 struct file *This = impl_from_IFile(iface);
2325 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
2326 return E_NOTIMPL;
2329 static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
2331 struct file *This = impl_from_IFile(iface);
2332 FIXME("(%p)->(%p)\n", This, pbstrPath);
2333 return E_NOTIMPL;
2336 static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
2338 struct file *This = impl_from_IFile(iface);
2339 FIXME("(%p)->(%p)\n", This, pbstrName);
2340 return E_NOTIMPL;
2343 static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
2345 struct file *This = impl_from_IFile(iface);
2346 FIXME("(%p)->(%p)\n", This, ppdrive);
2347 return E_NOTIMPL;
2350 static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
2352 struct file *This = impl_from_IFile(iface);
2353 FIXME("(%p)->(%p)\n", This, ppfolder);
2354 return E_NOTIMPL;
2357 static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
2359 struct file *This = impl_from_IFile(iface);
2360 DWORD fa;
2362 TRACE("(%p)->(%p)\n", This, pfa);
2364 if(!pfa)
2365 return E_POINTER;
2367 fa = GetFileAttributesW(This->path);
2368 if(fa == INVALID_FILE_ATTRIBUTES)
2369 return create_error(GetLastError());
2371 *pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2372 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
2373 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
2374 return S_OK;
2377 static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
2379 struct file *This = impl_from_IFile(iface);
2380 FIXME("(%p)->(%x)\n", This, pfa);
2381 return E_NOTIMPL;
2384 static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
2386 struct file *This = impl_from_IFile(iface);
2387 FIXME("(%p)->(%p)\n", This, pdate);
2388 return E_NOTIMPL;
2391 static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *pdate)
2393 struct file *This = impl_from_IFile(iface);
2394 FIXME("(%p)->(%p)\n", This, pdate);
2395 return E_NOTIMPL;
2398 static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
2400 struct file *This = impl_from_IFile(iface);
2401 FIXME("(%p)->(%p)\n", This, pdate);
2402 return E_NOTIMPL;
2405 static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
2407 struct file *This = impl_from_IFile(iface);
2408 WIN32_FIND_DATAW fd;
2409 HANDLE f;
2411 TRACE("(%p)->(%p)\n", This, pvarSize);
2413 if(!pvarSize)
2414 return E_POINTER;
2416 f = FindFirstFileW(This->path, &fd);
2417 if(f == INVALID_HANDLE_VALUE)
2418 return create_error(GetLastError());
2419 FindClose(f);
2421 if(fd.nFileSizeHigh || fd.nFileSizeLow>INT_MAX) {
2422 V_VT(pvarSize) = VT_R8;
2423 V_R8(pvarSize) = ((ULONGLONG)fd.nFileSizeHigh<<32) + fd.nFileSizeLow;
2424 }else {
2425 V_VT(pvarSize) = VT_I4;
2426 V_I4(pvarSize) = fd.nFileSizeLow;
2428 return S_OK;
2431 static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
2433 struct file *This = impl_from_IFile(iface);
2434 FIXME("(%p)->(%p)\n", This, pbstrType);
2435 return E_NOTIMPL;
2438 static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
2440 struct file *This = impl_from_IFile(iface);
2441 FIXME("(%p)->(%x)\n", This, Force);
2442 return E_NOTIMPL;
2445 static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
2447 struct file *This = impl_from_IFile(iface);
2448 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
2449 return E_NOTIMPL;
2452 static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
2454 struct file *This = impl_from_IFile(iface);
2455 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
2456 return E_NOTIMPL;
2459 static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode IOMode, Tristate Format, ITextStream **ppts)
2461 struct file *This = impl_from_IFile(iface);
2462 FIXME("(%p)->(%x %x %p)\n", This, IOMode, Format, ppts);
2463 return E_NOTIMPL;
2466 static const IFileVtbl file_vtbl = {
2467 file_QueryInterface,
2468 file_AddRef,
2469 file_Release,
2470 file_GetTypeInfoCount,
2471 file_GetTypeInfo,
2472 file_GetIDsOfNames,
2473 file_Invoke,
2474 file_get_Path,
2475 file_get_Name,
2476 file_put_Name,
2477 file_get_ShortPath,
2478 file_get_ShortName,
2479 file_get_Drive,
2480 file_get_ParentFolder,
2481 file_get_Attributes,
2482 file_put_Attributes,
2483 file_get_DateCreated,
2484 file_get_DateLastModified,
2485 file_get_DateLastAccessed,
2486 file_get_Size,
2487 file_get_Type,
2488 file_Delete,
2489 file_Copy,
2490 file_Move,
2491 file_OpenAsTextStream
2494 static HRESULT create_file(BSTR path, IFile **file)
2496 struct file *f;
2497 DWORD len, attrs;
2499 *file = NULL;
2501 f = heap_alloc(sizeof(struct file));
2502 if(!f)
2503 return E_OUTOFMEMORY;
2505 f->IFile_iface.lpVtbl = &file_vtbl;
2506 f->ref = 1;
2508 len = GetFullPathNameW(path, 0, NULL, NULL);
2509 if(!len) {
2510 heap_free(f);
2511 return E_FAIL;
2514 f->path = heap_alloc(len*sizeof(WCHAR));
2515 if(!f->path) {
2516 heap_free(f);
2517 return E_OUTOFMEMORY;
2520 if(!GetFullPathNameW(path, len, f->path, NULL)) {
2521 heap_free(f->path);
2522 heap_free(f);
2523 return E_FAIL;
2526 if(path[len-1]=='/' || path[len-1]=='\\')
2527 path[len-1] = 0;
2529 attrs = GetFileAttributesW(f->path);
2530 if(attrs==INVALID_FILE_ATTRIBUTES ||
2531 (attrs&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))) {
2532 heap_free(f->path);
2533 heap_free(f);
2534 return create_error(GetLastError());
2537 *file = &f->IFile_iface;
2538 return S_OK;
2541 static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
2543 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
2545 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
2546 IsEqualGUID( riid, &IID_IFileSystem ) ||
2547 IsEqualGUID( riid, &IID_IDispatch ) ||
2548 IsEqualGUID( riid, &IID_IUnknown ) )
2550 *ppvObject = iface;
2552 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
2554 TRACE("Interface IDispatchEx not supported - returning NULL\n");
2555 *ppvObject = NULL;
2556 return E_NOINTERFACE;
2558 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
2560 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
2561 *ppvObject = NULL;
2562 return E_NOINTERFACE;
2564 else
2566 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
2567 return E_NOINTERFACE;
2570 IFileSystem3_AddRef(iface);
2572 return S_OK;
2575 static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
2577 TRACE("%p\n", iface);
2579 return 2;
2582 static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
2584 TRACE("%p\n", iface);
2586 return 1;
2589 static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
2591 TRACE("(%p)->(%p)\n", iface, pctinfo);
2593 *pctinfo = 1;
2594 return S_OK;
2597 static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
2598 LCID lcid, ITypeInfo **ppTInfo)
2600 TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
2601 return get_typeinfo(IFileSystem3_tid, ppTInfo);
2604 static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
2605 LPOLESTR *rgszNames, UINT cNames,
2606 LCID lcid, DISPID *rgDispId)
2608 ITypeInfo *typeinfo;
2609 HRESULT hr;
2611 TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2613 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2614 if(SUCCEEDED(hr))
2616 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2617 ITypeInfo_Release(typeinfo);
2620 return hr;
2623 static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
2624 REFIID riid, LCID lcid, WORD wFlags,
2625 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2626 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2628 ITypeInfo *typeinfo;
2629 HRESULT hr;
2631 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
2632 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2634 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2635 if(SUCCEEDED(hr))
2637 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2638 pDispParams, pVarResult, pExcepInfo, puArgErr);
2639 ITypeInfo_Release(typeinfo);
2642 return hr;
2645 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
2647 TRACE("%p %p\n", iface, ppdrives);
2648 return create_drivecoll(ppdrives);
2651 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
2652 BSTR Name, BSTR *Result)
2654 BSTR ret;
2656 TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
2658 if (!Result) return E_POINTER;
2660 if (Path && Name)
2662 int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
2664 /* if both parts have backslashes strip one from Path */
2665 if (Path[path_len-1] == '\\' && Name[0] == '\\')
2667 path_len -= 1;
2669 ret = SysAllocStringLen(NULL, path_len + name_len);
2670 if (ret)
2672 strcpyW(ret, Path);
2673 ret[path_len] = 0;
2674 strcatW(ret, Name);
2677 else if (Path[path_len-1] != '\\' && Name[0] != '\\')
2679 ret = SysAllocStringLen(NULL, path_len + name_len + 1);
2680 if (ret)
2682 strcpyW(ret, Path);
2683 if (Path[path_len-1] != ':')
2684 strcatW(ret, bsW);
2685 strcatW(ret, Name);
2688 else
2690 ret = SysAllocStringLen(NULL, path_len + name_len);
2691 if (ret)
2693 strcpyW(ret, Path);
2694 strcatW(ret, Name);
2698 else if (Path || Name)
2699 ret = SysAllocString(Path ? Path : Name);
2700 else
2701 ret = SysAllocStringLen(NULL, 0);
2703 if (!ret) return E_OUTOFMEMORY;
2704 *Result = ret;
2706 return S_OK;
2709 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR Path,
2710 BSTR *pbstrResult)
2712 FIXME("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2714 return E_NOTIMPL;
2717 static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
2719 int i;
2721 if(!path)
2722 return 0;
2724 for(i=len-1; i>=0; i--)
2725 if(path[i]!='/' && path[i]!='\\')
2726 break;
2728 for(; i>=0; i--)
2729 if(path[i]=='/' || path[i]=='\\')
2730 break;
2732 for(; i>=0; i--)
2733 if(path[i]!='/' && path[i]!='\\')
2734 break;
2736 if(i < 0)
2737 return 0;
2739 if(path[i]==':' && i==1)
2740 i++;
2741 return i+1;
2744 static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
2745 BSTR *pbstrResult)
2747 DWORD len;
2749 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2751 if(!pbstrResult)
2752 return E_POINTER;
2754 len = get_parent_folder_name(Path, SysStringLen(Path));
2755 if(!len) {
2756 *pbstrResult = NULL;
2757 return S_OK;
2760 *pbstrResult = SysAllocStringLen(Path, len);
2761 if(!*pbstrResult)
2762 return E_OUTOFMEMORY;
2763 return S_OK;
2766 static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
2767 BSTR *pbstrResult)
2769 int i, end;
2771 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2773 if(!pbstrResult)
2774 return E_POINTER;
2776 if(!Path) {
2777 *pbstrResult = NULL;
2778 return S_OK;
2781 for(end=strlenW(Path)-1; end>=0; end--)
2782 if(Path[end]!='/' && Path[end]!='\\')
2783 break;
2785 for(i=end; i>=0; i--)
2786 if(Path[i]=='/' || Path[i]=='\\')
2787 break;
2788 i++;
2790 if(i>end || (i==0 && end==1 && Path[1]==':')) {
2791 *pbstrResult = NULL;
2792 return S_OK;
2795 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
2796 if(!*pbstrResult)
2797 return E_OUTOFMEMORY;
2798 return S_OK;
2801 static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
2802 BSTR *pbstrResult)
2804 int i, end;
2806 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2808 if(!pbstrResult)
2809 return E_POINTER;
2811 if(!Path) {
2812 *pbstrResult = NULL;
2813 return S_OK;
2816 for(end=strlenW(Path)-1; end>=0; end--)
2817 if(Path[end]!='/' && Path[end]!='\\')
2818 break;
2820 for(i=end; i>=0; i--) {
2821 if(Path[i]=='.' && Path[end+1]!='.')
2822 end = i-1;
2823 if(Path[i]=='/' || Path[i]=='\\')
2824 break;
2826 i++;
2828 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
2829 *pbstrResult = NULL;
2830 return S_OK;
2833 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
2834 if(!*pbstrResult)
2835 return E_OUTOFMEMORY;
2836 return S_OK;
2839 static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR Path,
2840 BSTR *pbstrResult)
2842 FIXME("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2844 return E_NOTIMPL;
2847 static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR Path,
2848 BSTR *pbstrResult)
2850 static const WCHAR cur_path[] = {'.',0};
2852 WCHAR buf[MAX_PATH], ch;
2853 const WCHAR *path;
2854 DWORD i, beg, len, exp_len;
2855 WIN32_FIND_DATAW fdata;
2856 HANDLE fh;
2858 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2860 if(!pbstrResult)
2861 return E_POINTER;
2863 if(!Path)
2864 path = cur_path;
2865 else
2866 path = Path;
2868 len = GetFullPathNameW(path, MAX_PATH, buf, NULL);
2869 if(!len)
2870 return E_FAIL;
2872 buf[0] = toupperW(buf[0]);
2873 if(len>3 && buf[len-1] == '\\')
2874 buf[--len] = 0;
2876 for(beg=3, i=3; i<=len; i++) {
2877 if(buf[i]!='\\' && buf[i])
2878 continue;
2880 ch = buf[i];
2881 buf[i] = 0;
2882 fh = FindFirstFileW(buf, &fdata);
2883 if(fh == INVALID_HANDLE_VALUE)
2884 break;
2886 exp_len = strlenW(fdata.cFileName);
2887 if(exp_len == i-beg)
2888 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
2889 FindClose(fh);
2890 buf[i] = ch;
2891 beg = i+1;
2894 *pbstrResult = SysAllocString(buf);
2895 if(!*pbstrResult)
2896 return E_OUTOFMEMORY;
2897 return S_OK;
2900 static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
2902 static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
2904 DWORD random;
2906 TRACE("%p %p\n", iface, pbstrResult);
2908 if(!pbstrResult)
2909 return E_POINTER;
2911 *pbstrResult = SysAllocStringLen(NULL, 12);
2912 if(!*pbstrResult)
2913 return E_OUTOFMEMORY;
2915 if(!RtlGenRandom(&random, sizeof(random)))
2916 return E_FAIL;
2917 sprintfW(*pbstrResult, fmt, random & 0xfffff);
2918 return S_OK;
2921 static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
2922 VARIANT_BOOL *pfExists)
2924 FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
2926 return E_NOTIMPL;
2929 static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
2931 DWORD attrs;
2932 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
2934 if (!ret) return E_POINTER;
2936 attrs = GetFileAttributesW(path);
2937 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
2938 return S_OK;
2941 static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
2943 DWORD attrs;
2944 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
2946 if (!ret) return E_POINTER;
2948 attrs = GetFileAttributesW(path);
2949 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
2951 return S_OK;
2954 static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
2955 IDrive **ppdrive)
2957 FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
2959 return E_NOTIMPL;
2962 static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
2963 IFile **ppfile)
2965 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
2967 if(!ppfile)
2968 return E_POINTER;
2969 if(!FilePath)
2970 return E_INVALIDARG;
2972 return create_file(FilePath, ppfile);
2975 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
2976 IFolder **folder)
2978 DWORD attrs;
2980 TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
2982 if(!folder)
2983 return E_POINTER;
2985 *folder = NULL;
2986 if(!FolderPath)
2987 return E_INVALIDARG;
2989 attrs = GetFileAttributesW(FolderPath);
2990 if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
2991 return CTL_E_PATHNOTFOUND;
2993 return create_folder(FolderPath, folder);
2996 static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
2997 SpecialFolderConst SpecialFolder,
2998 IFolder **ppfolder)
3000 FIXME("%p %d %p\n", iface, SpecialFolder, ppfolder);
3002 return E_NOTIMPL;
3005 static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
3007 WCHAR path[MAX_PATH];
3008 DWORD len, name_len;
3009 WIN32_FIND_DATAW ffd;
3010 HANDLE f;
3012 f = FindFirstFileW(file, &ffd);
3013 if(f == INVALID_HANDLE_VALUE)
3014 return create_error(GetLastError());
3016 len = get_parent_folder_name(file, file_len);
3017 if(len+1 >= MAX_PATH) {
3018 FindClose(f);
3019 return E_FAIL;
3021 if(len) {
3022 memcpy(path, file, len*sizeof(WCHAR));
3023 path[len++] = '\\';
3026 do {
3027 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3028 continue;
3030 name_len = strlenW(ffd.cFileName);
3031 if(len+name_len+1 >= MAX_PATH) {
3032 FindClose(f);
3033 return E_FAIL;
3035 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3037 TRACE("deleting %s\n", debugstr_w(path));
3039 if(!DeleteFileW(path)) {
3040 if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
3041 || !DeleteFileW(path)) {
3042 FindClose(f);
3043 return create_error(GetLastError());
3046 } while(FindNextFileW(f, &ffd));
3047 FindClose(f);
3049 return S_OK;
3052 static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
3053 VARIANT_BOOL Force)
3055 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
3057 if(!FileSpec)
3058 return E_POINTER;
3060 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
3063 static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
3065 WCHAR path[MAX_PATH];
3066 DWORD len, name_len;
3067 WIN32_FIND_DATAW ffd;
3068 HANDLE f;
3069 HRESULT hr;
3071 f = FindFirstFileW(folder, &ffd);
3072 if(f == INVALID_HANDLE_VALUE)
3073 return create_error(GetLastError());
3075 len = get_parent_folder_name(folder, folder_len);
3076 if(len+1 >= MAX_PATH) {
3077 FindClose(f);
3078 return E_FAIL;
3080 if(len) {
3081 memcpy(path, folder, len*sizeof(WCHAR));
3082 path[len++] = '\\';
3085 do {
3086 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3087 continue;
3088 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3089 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3090 continue;
3092 name_len = strlenW(ffd.cFileName);
3093 if(len+name_len+3 >= MAX_PATH) {
3094 FindClose(f);
3095 return E_FAIL;
3097 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
3098 path[len+name_len] = '\\';
3099 path[len+name_len+1] = '*';
3100 path[len+name_len+2] = 0;
3102 hr = delete_file(path, len+name_len+2, force);
3103 if(FAILED(hr)) {
3104 FindClose(f);
3105 return hr;
3108 hr = delete_folder(path, len+name_len+2, force);
3109 if(FAILED(hr)) {
3110 FindClose(f);
3111 return hr;
3114 path[len+name_len] = 0;
3115 TRACE("deleting %s\n", debugstr_w(path));
3117 if(!RemoveDirectoryW(path)) {
3118 FindClose(f);
3119 return create_error(GetLastError());
3121 } while(FindNextFileW(f, &ffd));
3122 FindClose(f);
3124 return S_OK;
3127 static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
3128 VARIANT_BOOL Force)
3130 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
3132 if(!FolderSpec)
3133 return E_POINTER;
3135 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
3138 static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR Source,
3139 BSTR Destination)
3141 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3143 return E_NOTIMPL;
3146 static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
3147 BSTR Destination)
3149 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3151 return E_NOTIMPL;
3154 static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
3155 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
3157 DWORD attrs;
3158 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
3159 DWORD src_len, dst_len, name_len;
3160 WIN32_FIND_DATAW ffd;
3161 HANDLE f;
3162 HRESULT hr;
3164 if(!source[0] || !destination[0])
3165 return E_INVALIDARG;
3167 attrs = GetFileAttributesW(destination);
3168 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
3169 attrs = GetFileAttributesW(source);
3170 if(attrs == INVALID_FILE_ATTRIBUTES)
3171 return create_error(GetLastError());
3172 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
3173 return CTL_E_FILENOTFOUND;
3175 if(!CopyFileW(source, destination, !overwrite))
3176 return create_error(GetLastError());
3177 return S_OK;
3180 f = FindFirstFileW(source, &ffd);
3181 if(f == INVALID_HANDLE_VALUE)
3182 return CTL_E_FILENOTFOUND;
3184 src_len = get_parent_folder_name(source, source_len);
3185 if(src_len+1 >= MAX_PATH)
3186 return E_FAIL;
3187 if(src_len) {
3188 memcpy(src_path, source, src_len*sizeof(WCHAR));
3189 src_path[src_len++] = '\\';
3192 dst_len = destination_len;
3193 if(dst_len+1 >= MAX_PATH) {
3194 FindClose(f);
3195 return E_FAIL;
3197 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
3198 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
3199 dst_path[dst_len++] = '\\';
3201 hr = CTL_E_FILENOTFOUND;
3202 do {
3203 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3204 continue;
3206 name_len = strlenW(ffd.cFileName);
3207 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
3208 FindClose(f);
3209 return E_FAIL;
3211 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3212 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3214 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
3216 if(!CopyFileW(src_path, dst_path, !overwrite)) {
3217 FindClose(f);
3218 return create_error(GetLastError());
3219 }else {
3220 hr = S_OK;
3222 } while(FindNextFileW(f, &ffd));
3223 FindClose(f);
3225 return hr;
3228 static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
3229 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3231 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3233 if(!Source || !Destination)
3234 return E_POINTER;
3236 return copy_file(Source, SysStringLen(Source), Destination,
3237 SysStringLen(Destination), OverWriteFiles);
3240 static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
3241 DWORD destination_len, VARIANT_BOOL overwrite)
3243 DWORD tmp, src_len, dst_len, name_len;
3244 WCHAR src[MAX_PATH], dst[MAX_PATH];
3245 WIN32_FIND_DATAW ffd;
3246 HANDLE f;
3247 HRESULT hr;
3248 BOOL copied = FALSE;
3250 if(!source[0] || !destination[0])
3251 return E_INVALIDARG;
3253 dst_len = destination_len;
3254 if(dst_len+1 >= MAX_PATH)
3255 return E_FAIL;
3256 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
3258 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
3259 (tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
3260 tmp&FILE_ATTRIBUTE_DIRECTORY) {
3261 if(!CreateDirectoryW(dst, NULL)) {
3262 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3263 tmp = GetFileAttributesW(dst);
3264 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
3265 return CTL_E_FILEALREADYEXISTS;
3266 }else {
3267 return create_error(GetLastError());
3270 copied = TRUE;
3272 src_len = source_len;
3273 if(src_len+2 >= MAX_PATH)
3274 return E_FAIL;
3275 memcpy(src, source, src_len*sizeof(WCHAR));
3276 src[src_len++] = '\\';
3277 src[src_len] = '*';
3278 src[src_len+1] = 0;
3280 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
3281 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
3282 return create_error(GetLastError());
3284 f = FindFirstFileW(src, &ffd);
3285 }else {
3286 src_len = get_parent_folder_name(source, source_len);
3287 if(src_len+2 >= MAX_PATH)
3288 return E_FAIL;
3289 memcpy(src, source, src_len*sizeof(WCHAR));
3290 if(src_len)
3291 src[src_len++] = '\\';
3293 f = FindFirstFileW(source, &ffd);
3295 if(f == INVALID_HANDLE_VALUE)
3296 return CTL_E_PATHNOTFOUND;
3298 dst[dst_len++] = '\\';
3299 dst[dst_len] = 0;
3301 do {
3302 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3303 continue;
3304 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3305 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3306 continue;
3308 name_len = strlenW(ffd.cFileName);
3309 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
3310 FindClose(f);
3311 return E_FAIL;
3313 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
3314 dst[dst_len+name_len] = 0;
3315 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
3316 src[src_len+name_len] = '\\';
3317 src[src_len+name_len+1] = '*';
3318 src[src_len+name_len+2] = 0;
3320 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
3322 if(!CreateDirectoryW(dst, NULL)) {
3323 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3324 tmp = GetFileAttributesW(dst);
3325 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
3326 FindClose(f);
3327 return CTL_E_FILEALREADYEXISTS;
3329 }else {
3330 FindClose(f);
3331 return create_error(GetLastError());
3333 return create_error(GetLastError());
3335 copied = TRUE;
3337 hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3338 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
3339 FindClose(f);
3340 return hr;
3343 hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3344 if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
3345 FindClose(f);
3346 return hr;
3348 } while(FindNextFileW(f, &ffd));
3349 FindClose(f);
3351 return copied ? S_OK : CTL_E_PATHNOTFOUND;
3354 static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
3355 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3357 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3359 if(!Source || !Destination)
3360 return E_POINTER;
3362 return copy_folder(Source, SysStringLen(Source), Destination,
3363 SysStringLen(Destination), OverWriteFiles);
3366 static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
3367 IFolder **folder)
3369 BOOL ret;
3371 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
3373 ret = CreateDirectoryW(path, NULL);
3374 if (!ret)
3376 *folder = NULL;
3377 if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
3378 return HRESULT_FROM_WIN32(GetLastError());
3381 return create_folder(path, folder);
3384 static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR filename,
3385 VARIANT_BOOL overwrite, VARIANT_BOOL unicode,
3386 ITextStream **stream)
3388 DWORD disposition;
3390 TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
3392 disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
3393 return create_textstream(filename, disposition, ForWriting, !!unicode, stream);
3396 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
3397 IOMode mode, VARIANT_BOOL create,
3398 Tristate format, ITextStream **stream)
3400 DWORD disposition;
3402 TRACE("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
3403 disposition = create == VARIANT_TRUE ? OPEN_ALWAYS : OPEN_EXISTING;
3405 if (format == TristateUseDefault) {
3406 FIXME("default format not handled, defaulting to unicode\n");
3407 format = TristateTrue;
3410 return create_textstream(filename, disposition, mode, format == TristateTrue, stream);
3413 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
3414 StandardStreamTypes StandardStreamType,
3415 VARIANT_BOOL Unicode,
3416 ITextStream **ppts)
3418 FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
3420 return E_NOTIMPL;
3423 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
3425 static const WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
3426 DWORDLONG version;
3427 WORD a, b, c, d;
3429 version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
3430 a = (WORD)( version >> 48);
3431 b = (WORD)((version >> 32) & 0xffff);
3432 c = (WORD)((version >> 16) & 0xffff);
3433 d = (WORD)( version & 0xffff);
3435 sprintfW(ver, fmtW, a, b, c, d);
3438 static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
3440 static const WCHAR rootW[] = {'\\',0};
3441 VS_FIXEDFILEINFO *info;
3442 WCHAR ver[30];
3443 void *ptr;
3444 DWORD len;
3445 BOOL ret;
3447 TRACE("%p %s %p\n", iface, debugstr_w(name), version);
3449 len = GetFileVersionInfoSizeW(name, NULL);
3450 if (!len)
3451 return HRESULT_FROM_WIN32(GetLastError());
3453 ptr = heap_alloc(len);
3454 if (!GetFileVersionInfoW(name, 0, len, ptr))
3456 heap_free(ptr);
3457 return HRESULT_FROM_WIN32(GetLastError());
3460 ret = VerQueryValueW(ptr, rootW, (void**)&info, &len);
3461 heap_free(ptr);
3462 if (!ret)
3463 return HRESULT_FROM_WIN32(GetLastError());
3465 get_versionstring(info, ver);
3466 *version = SysAllocString(ver);
3467 TRACE("version=%s\n", debugstr_w(ver));
3469 return S_OK;
3472 static const struct IFileSystem3Vtbl filesys_vtbl =
3474 filesys_QueryInterface,
3475 filesys_AddRef,
3476 filesys_Release,
3477 filesys_GetTypeInfoCount,
3478 filesys_GetTypeInfo,
3479 filesys_GetIDsOfNames,
3480 filesys_Invoke,
3481 filesys_get_Drives,
3482 filesys_BuildPath,
3483 filesys_GetDriveName,
3484 filesys_GetParentFolderName,
3485 filesys_GetFileName,
3486 filesys_GetBaseName,
3487 filesys_GetExtensionName,
3488 filesys_GetAbsolutePathName,
3489 filesys_GetTempName,
3490 filesys_DriveExists,
3491 filesys_FileExists,
3492 filesys_FolderExists,
3493 filesys_GetDrive,
3494 filesys_GetFile,
3495 filesys_GetFolder,
3496 filesys_GetSpecialFolder,
3497 filesys_DeleteFile,
3498 filesys_DeleteFolder,
3499 filesys_MoveFile,
3500 filesys_MoveFolder,
3501 filesys_CopyFile,
3502 filesys_CopyFolder,
3503 filesys_CreateFolder,
3504 filesys_CreateTextFile,
3505 filesys_OpenTextFile,
3506 filesys_GetStandardStream,
3507 filesys_GetFileVersion
3510 static IFileSystem3 filesystem = { &filesys_vtbl };
3512 HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
3514 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
3516 return IFileSystem3_QueryInterface(&filesystem, riid, ppv);