wined3d: Give tex_type and its values a better name.
[wine.git] / dlls / scrrun / filesystem.c
blob5e0fc28bc65e5cddc17458652cc9061c2aa8e94b
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 foldercollection {
43 IFolderCollection IFolderCollection_iface;
44 LONG ref;
45 BSTR path;
48 struct filecollection {
49 IFileCollection IFileCollection_iface;
50 LONG ref;
51 BSTR path;
54 struct drivecollection {
55 IDriveCollection IDriveCollection_iface;
56 LONG ref;
57 DWORD drives;
58 LONG count;
61 struct enumdata {
62 union
64 struct
66 struct foldercollection *coll;
67 HANDLE find;
68 } foldercoll;
69 struct
71 struct filecollection *coll;
72 HANDLE find;
73 } filecoll;
74 struct
76 struct drivecollection *coll;
77 INT cur;
78 } drivecoll;
79 } u;
82 struct enumvariant {
83 IEnumVARIANT IEnumVARIANT_iface;
84 LONG ref;
86 struct enumdata data;
89 struct drive {
90 IDrive IDrive_iface;
91 LONG ref;
92 BSTR root;
95 struct folder {
96 IFolder IFolder_iface;
97 LONG ref;
98 BSTR path;
101 struct file {
102 IFile IFile_iface;
103 LONG ref;
105 WCHAR *path;
108 struct textstream {
109 ITextStream ITextStream_iface;
110 LONG ref;
112 IOMode mode;
113 BOOL unicode;
114 BOOL first_read;
115 LARGE_INTEGER size;
116 HANDLE file;
119 enum iotype {
120 IORead,
121 IOWrite
124 static inline struct drive *impl_from_IDrive(IDrive *iface)
126 return CONTAINING_RECORD(iface, struct drive, IDrive_iface);
129 static inline struct folder *impl_from_IFolder(IFolder *iface)
131 return CONTAINING_RECORD(iface, struct folder, IFolder_iface);
134 static inline struct file *impl_from_IFile(IFile *iface)
136 return CONTAINING_RECORD(iface, struct file, IFile_iface);
139 static inline struct textstream *impl_from_ITextStream(ITextStream *iface)
141 return CONTAINING_RECORD(iface, struct textstream, ITextStream_iface);
144 static inline struct foldercollection *impl_from_IFolderCollection(IFolderCollection *iface)
146 return CONTAINING_RECORD(iface, struct foldercollection, IFolderCollection_iface);
149 static inline struct filecollection *impl_from_IFileCollection(IFileCollection *iface)
151 return CONTAINING_RECORD(iface, struct filecollection, IFileCollection_iface);
154 static inline struct drivecollection *impl_from_IDriveCollection(IDriveCollection *iface)
156 return CONTAINING_RECORD(iface, struct drivecollection, IDriveCollection_iface);
159 static inline struct enumvariant *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
161 return CONTAINING_RECORD(iface, struct enumvariant, IEnumVARIANT_iface);
164 static inline HRESULT create_error(DWORD err)
166 switch(err) {
167 case ERROR_FILE_NOT_FOUND: return CTL_E_FILENOTFOUND;
168 case ERROR_PATH_NOT_FOUND: return CTL_E_PATHNOTFOUND;
169 case ERROR_ACCESS_DENIED: return CTL_E_PERMISSIONDENIED;
170 case ERROR_FILE_EXISTS: return CTL_E_FILEALREADYEXISTS;
171 case ERROR_ALREADY_EXISTS: return CTL_E_FILEALREADYEXISTS;
172 default:
173 FIXME("Unsupported error code: %d\n", err);
174 return E_FAIL;
178 static HRESULT create_folder(const WCHAR*, IFolder**);
179 static HRESULT create_file(BSTR, IFile**);
180 static HRESULT create_foldercoll_enum(struct foldercollection*, IUnknown**);
181 static HRESULT create_filecoll_enum(struct filecollection*, IUnknown**);
183 static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data)
185 static const WCHAR dotdotW[] = {'.','.',0};
186 static const WCHAR dotW[] = {'.',0};
188 return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
189 strcmpW(data->cFileName, dotdotW) &&
190 strcmpW(data->cFileName, dotW);
193 static inline BOOL is_file_data(const WIN32_FIND_DATAW *data)
195 return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
198 static BSTR get_full_path(BSTR path, const WIN32_FIND_DATAW *data)
200 int len = SysStringLen(path);
201 WCHAR buffW[MAX_PATH];
203 strcpyW(buffW, path);
204 if (path[len-1] != '\\')
205 strcatW(buffW, bsW);
206 strcatW(buffW, data->cFileName);
208 return SysAllocString(buffW);
211 static BOOL textstream_check_iomode(struct textstream *This, enum iotype type)
213 if (type == IORead)
214 return This->mode == ForWriting || This->mode == ForAppending;
215 else
216 return This->mode == ForReading;
219 static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
221 struct textstream *This = impl_from_ITextStream(iface);
223 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
225 if (IsEqualIID(riid, &IID_ITextStream) ||
226 IsEqualIID(riid, &IID_IDispatch) ||
227 IsEqualIID(riid, &IID_IUnknown))
229 *obj = iface;
230 ITextStream_AddRef(iface);
231 return S_OK;
234 *obj = NULL;
235 return E_NOINTERFACE;
238 static ULONG WINAPI textstream_AddRef(ITextStream *iface)
240 struct textstream *This = impl_from_ITextStream(iface);
241 ULONG ref = InterlockedIncrement(&This->ref);
242 TRACE("(%p)->(%d)\n", This, ref);
243 return ref;
246 static ULONG WINAPI textstream_Release(ITextStream *iface)
248 struct textstream *This = impl_from_ITextStream(iface);
249 ULONG ref = InterlockedDecrement(&This->ref);
250 TRACE("(%p)->(%d)\n", This, ref);
252 if (!ref)
254 CloseHandle(This->file);
255 heap_free(This);
258 return ref;
261 static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
263 struct textstream *This = impl_from_ITextStream(iface);
264 TRACE("(%p)->(%p)\n", This, pctinfo);
265 *pctinfo = 1;
266 return S_OK;
269 static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
270 LCID lcid, ITypeInfo **ppTInfo)
272 struct textstream *This = impl_from_ITextStream(iface);
273 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
274 return get_typeinfo(ITextStream_tid, ppTInfo);
277 static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
278 LPOLESTR *rgszNames, UINT cNames,
279 LCID lcid, DISPID *rgDispId)
281 struct textstream *This = impl_from_ITextStream(iface);
282 ITypeInfo *typeinfo;
283 HRESULT hr;
285 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
287 hr = get_typeinfo(ITextStream_tid, &typeinfo);
288 if(SUCCEEDED(hr))
290 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
291 ITypeInfo_Release(typeinfo);
294 return hr;
297 static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
298 REFIID riid, LCID lcid, WORD wFlags,
299 DISPPARAMS *pDispParams, VARIANT *pVarResult,
300 EXCEPINFO *pExcepInfo, UINT *puArgErr)
302 struct textstream *This = impl_from_ITextStream(iface);
303 ITypeInfo *typeinfo;
304 HRESULT hr;
306 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
307 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
309 hr = get_typeinfo(ITextStream_tid, &typeinfo);
310 if(SUCCEEDED(hr))
312 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
313 pDispParams, pVarResult, pExcepInfo, puArgErr);
314 ITypeInfo_Release(typeinfo);
317 return hr;
320 static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
322 struct textstream *This = impl_from_ITextStream(iface);
323 FIXME("(%p)->(%p): stub\n", This, line);
324 return E_NOTIMPL;
327 static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
329 struct textstream *This = impl_from_ITextStream(iface);
330 FIXME("(%p)->(%p): stub\n", This, column);
331 return E_NOTIMPL;
334 static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
336 struct textstream *This = impl_from_ITextStream(iface);
337 LARGE_INTEGER pos, dist;
339 TRACE("(%p)->(%p)\n", This, eos);
341 if (!eos)
342 return E_POINTER;
344 if (textstream_check_iomode(This, IORead)) {
345 *eos = VARIANT_TRUE;
346 return CTL_E_BADFILEMODE;
349 dist.QuadPart = 0;
350 if (!SetFilePointerEx(This->file, dist, &pos, FILE_CURRENT))
351 return E_FAIL;
353 *eos = This->size.QuadPart == pos.QuadPart ? VARIANT_TRUE : VARIANT_FALSE;
354 return S_OK;
357 static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
359 struct textstream *This = impl_from_ITextStream(iface);
360 FIXME("(%p)->(%p): stub\n", This, eol);
361 return E_NOTIMPL;
365 Reads 'toread' bytes from a file, converts if needed
366 BOM is skipped if 'bof' is set.
368 static HRESULT textstream_read(struct textstream *stream, LONG toread, BOOL bof, BSTR *text)
370 HRESULT hr = S_OK;
371 DWORD read;
372 char *buff;
373 BOOL ret;
375 if (toread == 0) {
376 *text = SysAllocStringLen(NULL, 0);
377 return *text ? S_FALSE : E_OUTOFMEMORY;
380 if (toread < sizeof(WCHAR))
381 return CTL_E_ENDOFFILE;
383 buff = heap_alloc(toread);
384 if (!buff)
385 return E_OUTOFMEMORY;
387 ret = ReadFile(stream->file, buff, toread, &read, NULL);
388 if (!ret || toread != read) {
389 WARN("failed to read from file %d, %d, error %d\n", read, toread, GetLastError());
390 heap_free(buff);
391 return E_FAIL;
394 if (stream->unicode) {
395 int i = 0;
397 /* skip BOM */
398 if (bof && *(WCHAR*)buff == utf16bom) {
399 read -= sizeof(WCHAR);
400 i += sizeof(WCHAR);
403 *text = SysAllocStringLen(read ? (WCHAR*)&buff[i] : NULL, read/sizeof(WCHAR));
404 if (!*text) hr = E_OUTOFMEMORY;
406 else {
407 INT len = MultiByteToWideChar(CP_ACP, 0, buff, read, NULL, 0);
408 *text = SysAllocStringLen(NULL, len);
409 if (*text)
410 MultiByteToWideChar(CP_ACP, 0, buff, read, *text, len);
411 else
412 hr = E_OUTOFMEMORY;
414 heap_free(buff);
416 return hr;
419 static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
421 struct textstream *This = impl_from_ITextStream(iface);
422 LARGE_INTEGER start, end, dist;
423 DWORD toread;
424 HRESULT hr;
426 TRACE("(%p)->(%d %p)\n", This, len, text);
428 if (!text)
429 return E_POINTER;
431 *text = NULL;
432 if (len <= 0)
433 return len == 0 ? S_OK : E_INVALIDARG;
435 if (textstream_check_iomode(This, IORead))
436 return CTL_E_BADFILEMODE;
438 if (!This->first_read) {
439 VARIANT_BOOL eos;
441 /* check for EOF */
442 hr = ITextStream_get_AtEndOfStream(iface, &eos);
443 if (FAILED(hr))
444 return hr;
446 if (eos == VARIANT_TRUE)
447 return CTL_E_ENDOFFILE;
450 /* read everything from current position */
451 dist.QuadPart = 0;
452 SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
453 SetFilePointerEx(This->file, dist, &end, FILE_END);
454 toread = end.QuadPart - start.QuadPart;
455 /* rewind back */
456 dist.QuadPart = start.QuadPart;
457 SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
459 This->first_read = FALSE;
460 if (This->unicode) len *= sizeof(WCHAR);
462 hr = textstream_read(This, min(toread, len), start.QuadPart == 0, text);
463 if (FAILED(hr))
464 return hr;
465 else
466 return toread <= len ? S_FALSE : S_OK;
469 static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
471 struct textstream *This = impl_from_ITextStream(iface);
472 VARIANT_BOOL eos;
473 HRESULT hr;
475 FIXME("(%p)->(%p): stub\n", This, text);
477 if (!text)
478 return E_POINTER;
480 *text = NULL;
481 if (textstream_check_iomode(This, IORead))
482 return CTL_E_BADFILEMODE;
484 /* check for EOF */
485 hr = ITextStream_get_AtEndOfStream(iface, &eos);
486 if (FAILED(hr))
487 return hr;
489 if (eos == VARIANT_TRUE)
490 return CTL_E_ENDOFFILE;
492 return E_NOTIMPL;
495 static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
497 struct textstream *This = impl_from_ITextStream(iface);
498 LARGE_INTEGER start, end, dist;
499 DWORD toread;
500 HRESULT hr;
502 TRACE("(%p)->(%p)\n", This, text);
504 if (!text)
505 return E_POINTER;
507 *text = NULL;
508 if (textstream_check_iomode(This, IORead))
509 return CTL_E_BADFILEMODE;
511 if (!This->first_read) {
512 VARIANT_BOOL eos;
514 /* check for EOF */
515 hr = ITextStream_get_AtEndOfStream(iface, &eos);
516 if (FAILED(hr))
517 return hr;
519 if (eos == VARIANT_TRUE)
520 return CTL_E_ENDOFFILE;
523 /* read everything from current position */
524 dist.QuadPart = 0;
525 SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
526 SetFilePointerEx(This->file, dist, &end, FILE_END);
527 toread = end.QuadPart - start.QuadPart;
528 /* rewind back */
529 dist.QuadPart = start.QuadPart;
530 SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
532 This->first_read = FALSE;
534 hr = textstream_read(This, toread, start.QuadPart == 0, text);
535 return FAILED(hr) ? hr : S_FALSE;
538 static HRESULT textstream_writestr(struct textstream *stream, BSTR text)
540 DWORD written = 0;
541 BOOL ret;
543 if (stream->unicode) {
544 ret = WriteFile(stream->file, text, SysStringByteLen(text), &written, NULL);
545 return (ret && written == SysStringByteLen(text)) ? S_OK : create_error(GetLastError());
546 } else {
547 DWORD len = WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), NULL, 0, NULL, NULL);
548 char *buffA;
549 HRESULT hr;
551 buffA = heap_alloc(len);
552 if (!buffA)
553 return E_OUTOFMEMORY;
555 WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), buffA, len, NULL, NULL);
556 ret = WriteFile(stream->file, buffA, len, &written, NULL);
557 hr = (ret && written == len) ? S_OK : create_error(GetLastError());
558 heap_free(buffA);
559 return hr;
563 static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
565 struct textstream *This = impl_from_ITextStream(iface);
567 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
569 if (textstream_check_iomode(This, IOWrite))
570 return CTL_E_BADFILEMODE;
572 return textstream_writestr(This, text);
575 static HRESULT textstream_writecrlf(struct textstream *stream)
577 static const WCHAR crlfW[] = {'\r','\n'};
578 static const char crlfA[] = {'\r','\n'};
579 DWORD written = 0, len;
580 const void *ptr;
581 BOOL ret;
583 if (stream->unicode) {
584 ptr = crlfW;
585 len = sizeof(crlfW);
587 else {
588 ptr = crlfA;
589 len = sizeof(crlfA);
592 ret = WriteFile(stream->file, ptr, len, &written, NULL);
593 return (ret && written == len) ? S_OK : create_error(GetLastError());
596 static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
598 struct textstream *This = impl_from_ITextStream(iface);
599 HRESULT hr;
601 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
603 if (textstream_check_iomode(This, IOWrite))
604 return CTL_E_BADFILEMODE;
606 hr = textstream_writestr(This, text);
607 if (SUCCEEDED(hr))
608 hr = textstream_writecrlf(This);
609 return hr;
612 static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
614 struct textstream *This = impl_from_ITextStream(iface);
615 FIXME("(%p)->(%d): stub\n", This, lines);
616 return E_NOTIMPL;
619 static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
621 struct textstream *This = impl_from_ITextStream(iface);
622 FIXME("(%p)->(%d): stub\n", This, count);
623 return E_NOTIMPL;
626 static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
628 struct textstream *This = impl_from_ITextStream(iface);
629 FIXME("(%p): stub\n", This);
630 return E_NOTIMPL;
633 static HRESULT WINAPI textstream_Close(ITextStream *iface)
635 struct textstream *This = impl_from_ITextStream(iface);
636 FIXME("(%p): stub\n", This);
637 return E_NOTIMPL;
640 static const ITextStreamVtbl textstreamvtbl = {
641 textstream_QueryInterface,
642 textstream_AddRef,
643 textstream_Release,
644 textstream_GetTypeInfoCount,
645 textstream_GetTypeInfo,
646 textstream_GetIDsOfNames,
647 textstream_Invoke,
648 textstream_get_Line,
649 textstream_get_Column,
650 textstream_get_AtEndOfStream,
651 textstream_get_AtEndOfLine,
652 textstream_Read,
653 textstream_ReadLine,
654 textstream_ReadAll,
655 textstream_Write,
656 textstream_WriteLine,
657 textstream_WriteBlankLines,
658 textstream_Skip,
659 textstream_SkipLine,
660 textstream_Close
663 static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMode mode, BOOL unicode, ITextStream **ret)
665 struct textstream *stream;
666 DWORD access = 0;
668 /* map access mode */
669 switch (mode)
671 case ForReading:
672 access = GENERIC_READ;
673 break;
674 case ForWriting:
675 access = GENERIC_WRITE;
676 break;
677 case ForAppending:
678 access = FILE_APPEND_DATA;
679 break;
680 default:
681 return E_INVALIDARG;
684 stream = heap_alloc(sizeof(struct textstream));
685 if (!stream) return E_OUTOFMEMORY;
687 stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
688 stream->ref = 1;
689 stream->mode = mode;
690 stream->unicode = unicode;
691 stream->first_read = TRUE;
693 stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
694 if (stream->file == INVALID_HANDLE_VALUE)
696 HRESULT hr = create_error(GetLastError());
697 heap_free(stream);
698 return hr;
701 if (mode == ForReading)
702 GetFileSizeEx(stream->file, &stream->size);
703 else
704 stream->size.QuadPart = 0;
706 /* Write Unicode BOM */
707 if (unicode && mode == ForWriting && (disposition == CREATE_ALWAYS || disposition == CREATE_NEW)) {
708 DWORD written = 0;
709 BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL);
710 if (!ret || written != sizeof(utf16bom)) {
711 ITextStream_Release(&stream->ITextStream_iface);
712 return create_error(GetLastError());
716 *ret = &stream->ITextStream_iface;
717 return S_OK;
720 static HRESULT WINAPI drive_QueryInterface(IDrive *iface, REFIID riid, void **obj)
722 struct drive *This = impl_from_IDrive(iface);
724 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
726 *obj = NULL;
728 if (IsEqualIID( riid, &IID_IDrive ) ||
729 IsEqualIID( riid, &IID_IDispatch ) ||
730 IsEqualIID( riid, &IID_IUnknown))
732 *obj = iface;
733 IDrive_AddRef(iface);
735 else
736 return E_NOINTERFACE;
738 return S_OK;
741 static ULONG WINAPI drive_AddRef(IDrive *iface)
743 struct drive *This = impl_from_IDrive(iface);
744 ULONG ref = InterlockedIncrement(&This->ref);
745 TRACE("(%p)->(%d)\n", This, ref);
746 return ref;
749 static ULONG WINAPI drive_Release(IDrive *iface)
751 struct drive *This = impl_from_IDrive(iface);
752 ULONG ref = InterlockedDecrement(&This->ref);
753 TRACE("(%p)->(%d)\n", This, ref);
755 if (!ref)
757 SysFreeString(This->root);
758 heap_free(This);
761 return ref;
764 static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo)
766 struct drive *This = impl_from_IDrive(iface);
767 TRACE("(%p)->(%p)\n", This, pctinfo);
768 *pctinfo = 1;
769 return S_OK;
772 static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo,
773 LCID lcid, ITypeInfo **ppTInfo)
775 struct drive *This = impl_from_IDrive(iface);
776 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
777 return get_typeinfo(IDrive_tid, ppTInfo);
780 static HRESULT WINAPI drive_GetIDsOfNames(IDrive *iface, REFIID riid,
781 LPOLESTR *rgszNames, UINT cNames,
782 LCID lcid, DISPID *rgDispId)
784 struct drive *This = impl_from_IDrive(iface);
785 ITypeInfo *typeinfo;
786 HRESULT hr;
788 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
790 hr = get_typeinfo(IDrive_tid, &typeinfo);
791 if(SUCCEEDED(hr))
793 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
794 ITypeInfo_Release(typeinfo);
797 return hr;
800 static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember,
801 REFIID riid, LCID lcid, WORD wFlags,
802 DISPPARAMS *pDispParams, VARIANT *pVarResult,
803 EXCEPINFO *pExcepInfo, UINT *puArgErr)
805 struct drive *This = impl_from_IDrive(iface);
806 ITypeInfo *typeinfo;
807 HRESULT hr;
809 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
810 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
812 hr = get_typeinfo(IDrive_tid, &typeinfo);
813 if(SUCCEEDED(hr))
815 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
816 pDispParams, pVarResult, pExcepInfo, puArgErr);
817 ITypeInfo_Release(typeinfo);
820 return hr;
823 static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path)
825 struct drive *This = impl_from_IDrive(iface);
826 FIXME("(%p)->(%p): stub\n", This, path);
827 return E_NOTIMPL;
830 static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter)
832 struct drive *This = impl_from_IDrive(iface);
834 TRACE("(%p)->(%p)\n", This, letter);
836 if (!letter)
837 return E_POINTER;
839 *letter = SysAllocStringLen(This->root, 1);
840 if (!*letter)
841 return E_OUTOFMEMORY;
843 return S_OK;
846 static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name)
848 struct drive *This = impl_from_IDrive(iface);
849 FIXME("(%p)->(%p): stub\n", This, share_name);
850 return E_NOTIMPL;
853 static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type)
855 struct drive *This = impl_from_IDrive(iface);
857 TRACE("(%p)->(%p)\n", This, type);
859 switch (GetDriveTypeW(This->root))
861 case DRIVE_REMOVABLE:
862 *type = Removable;
863 break;
864 case DRIVE_FIXED:
865 *type = Fixed;
866 break;
867 case DRIVE_REMOTE:
868 *type = Remote;
869 break;
870 case DRIVE_CDROM:
871 *type = CDRom;
872 break;
873 case DRIVE_RAMDISK:
874 *type = RamDisk;
875 break;
876 default:
877 *type = UnknownType;
878 break;
881 return S_OK;
884 static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder)
886 struct drive *This = impl_from_IDrive(iface);
887 FIXME("(%p)->(%p): stub\n", This, folder);
888 return E_NOTIMPL;
891 static HRESULT variant_from_largeint(const ULARGE_INTEGER *src, VARIANT *v)
893 HRESULT hr = S_OK;
895 if (src->u.HighPart || src->u.LowPart > INT_MAX)
897 V_VT(v) = VT_R8;
898 hr = VarR8FromUI8(src->QuadPart, &V_R8(v));
900 else
902 V_VT(v) = VT_I4;
903 V_I4(v) = src->u.LowPart;
906 return hr;
909 static HRESULT WINAPI drive_get_AvailableSpace(IDrive *iface, VARIANT *v)
911 struct drive *This = impl_from_IDrive(iface);
912 ULARGE_INTEGER avail;
914 TRACE("(%p)->(%p)\n", This, v);
916 if (!v)
917 return E_POINTER;
919 if (!GetDiskFreeSpaceExW(This->root, &avail, NULL, NULL))
920 return E_FAIL;
922 return variant_from_largeint(&avail, v);
925 static HRESULT WINAPI drive_get_FreeSpace(IDrive *iface, VARIANT *v)
927 struct drive *This = impl_from_IDrive(iface);
928 ULARGE_INTEGER freespace;
930 TRACE("(%p)->(%p)\n", This, v);
932 if (!v)
933 return E_POINTER;
935 if (!GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL))
936 return E_FAIL;
938 return variant_from_largeint(&freespace, v);
941 static HRESULT WINAPI drive_get_TotalSize(IDrive *iface, VARIANT *v)
943 struct drive *This = impl_from_IDrive(iface);
944 ULARGE_INTEGER total;
946 TRACE("(%p)->(%p)\n", This, v);
948 if (!v)
949 return E_POINTER;
951 if (!GetDiskFreeSpaceExW(This->root, NULL, &total, NULL))
952 return E_FAIL;
954 return variant_from_largeint(&total, v);
957 static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name)
959 struct drive *This = impl_from_IDrive(iface);
960 WCHAR nameW[MAX_PATH+1];
961 BOOL ret;
963 TRACE("(%p)->(%p)\n", This, name);
965 if (!name)
966 return E_POINTER;
968 *name = NULL;
969 ret = GetVolumeInformationW(This->root, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, NULL, NULL, NULL, 0);
970 if (ret)
971 *name = SysAllocString(nameW);
972 return ret ? S_OK : E_FAIL;
975 static HRESULT WINAPI drive_put_VolumeName(IDrive *iface, BSTR name)
977 struct drive *This = impl_from_IDrive(iface);
978 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
979 return E_NOTIMPL;
982 static HRESULT WINAPI drive_get_FileSystem(IDrive *iface, BSTR *fs)
984 struct drive *This = impl_from_IDrive(iface);
985 WCHAR nameW[MAX_PATH+1];
986 BOOL ret;
988 TRACE("(%p)->(%p)\n", This, fs);
990 if (!fs)
991 return E_POINTER;
993 *fs = NULL;
994 ret = GetVolumeInformationW(This->root, NULL, 0, NULL, NULL, NULL, nameW, sizeof(nameW)/sizeof(WCHAR));
995 if (ret)
996 *fs = SysAllocString(nameW);
997 return ret ? S_OK : E_FAIL;
1000 static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial)
1002 struct drive *This = impl_from_IDrive(iface);
1003 BOOL ret;
1005 TRACE("(%p)->(%p)\n", This, serial);
1007 if (!serial)
1008 return E_POINTER;
1010 ret = GetVolumeInformationW(This->root, NULL, 0, (DWORD*)serial, NULL, NULL, NULL, 0);
1011 return ret ? S_OK : E_FAIL;
1014 static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
1016 struct drive *This = impl_from_IDrive(iface);
1017 ULARGE_INTEGER freespace;
1018 BOOL ret;
1020 TRACE("(%p)->(%p)\n", This, ready);
1022 if (!ready)
1023 return E_POINTER;
1025 ret = GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL);
1026 *ready = ret ? VARIANT_TRUE : VARIANT_FALSE;
1027 return S_OK;
1030 static const IDriveVtbl drivevtbl = {
1031 drive_QueryInterface,
1032 drive_AddRef,
1033 drive_Release,
1034 drive_GetTypeInfoCount,
1035 drive_GetTypeInfo,
1036 drive_GetIDsOfNames,
1037 drive_Invoke,
1038 drive_get_Path,
1039 drive_get_DriveLetter,
1040 drive_get_ShareName,
1041 drive_get_DriveType,
1042 drive_get_RootFolder,
1043 drive_get_AvailableSpace,
1044 drive_get_FreeSpace,
1045 drive_get_TotalSize,
1046 drive_get_VolumeName,
1047 drive_put_VolumeName,
1048 drive_get_FileSystem,
1049 drive_get_SerialNumber,
1050 drive_get_IsReady
1053 static HRESULT create_drive(WCHAR letter, IDrive **drive)
1055 struct drive *This;
1057 *drive = NULL;
1059 This = heap_alloc(sizeof(*This));
1060 if (!This) return E_OUTOFMEMORY;
1062 This->IDrive_iface.lpVtbl = &drivevtbl;
1063 This->ref = 1;
1064 This->root = SysAllocStringLen(NULL, 3);
1065 if (!This->root)
1067 heap_free(This);
1068 return E_OUTOFMEMORY;
1070 This->root[0] = letter;
1071 This->root[1] = ':';
1072 This->root[2] = '\\';
1073 This->root[3] = 0;
1075 *drive = &This->IDrive_iface;
1076 return S_OK;
1079 static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
1081 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1083 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1085 *obj = NULL;
1087 if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
1088 IsEqualIID( riid, &IID_IUnknown ))
1090 *obj = iface;
1091 IEnumVARIANT_AddRef(iface);
1093 else
1094 return E_NOINTERFACE;
1096 return S_OK;
1099 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
1101 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1102 ULONG ref = InterlockedIncrement(&This->ref);
1103 TRACE("(%p)->(%d)\n", This, ref);
1104 return ref;
1107 static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
1109 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1110 ULONG ref = InterlockedDecrement(&This->ref);
1112 TRACE("(%p)->(%d)\n", This, ref);
1114 if (!ref)
1116 IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
1117 FindClose(This->data.u.foldercoll.find);
1118 heap_free(This);
1121 return ref;
1124 static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file)
1126 static const WCHAR allW[] = {'*',0};
1127 WCHAR pathW[MAX_PATH];
1128 int len;
1129 HANDLE handle;
1131 strcpyW(pathW, path);
1132 len = strlenW(pathW);
1133 if (len && pathW[len-1] != '\\')
1134 strcatW(pathW, bsW);
1135 strcatW(pathW, allW);
1136 handle = FindFirstFileW(pathW, data);
1137 if (handle == INVALID_HANDLE_VALUE) return 0;
1139 /* find first dir/file */
1140 while (1)
1142 if (file ? is_file_data(data) : is_dir_data(data))
1143 break;
1145 if (!FindNextFileW(handle, data))
1147 FindClose(handle);
1148 return 0;
1151 return handle;
1154 static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1156 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1157 HANDLE handle = This->data.u.foldercoll.find;
1158 WIN32_FIND_DATAW data;
1159 ULONG count = 0;
1161 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1163 if (fetched)
1164 *fetched = 0;
1166 if (!celt) return S_OK;
1168 if (!handle)
1170 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1171 if (!handle) return S_FALSE;
1173 This->data.u.foldercoll.find = handle;
1175 else
1177 if (!FindNextFileW(handle, &data))
1178 return S_FALSE;
1183 if (is_dir_data(&data))
1185 IFolder *folder;
1186 HRESULT hr;
1187 BSTR str;
1189 str = get_full_path(This->data.u.foldercoll.coll->path, &data);
1190 hr = create_folder(str, &folder);
1191 SysFreeString(str);
1192 if (FAILED(hr)) return hr;
1194 V_VT(&var[count]) = VT_DISPATCH;
1195 V_DISPATCH(&var[count]) = (IDispatch*)folder;
1196 count++;
1198 if (count >= celt) break;
1200 } while (FindNextFileW(handle, &data));
1202 if (fetched)
1203 *fetched = count;
1205 return (count < celt) ? S_FALSE : S_OK;
1208 static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1210 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1211 HANDLE handle = This->data.u.foldercoll.find;
1212 WIN32_FIND_DATAW data;
1214 TRACE("(%p)->(%d)\n", This, celt);
1216 if (!celt) return S_OK;
1218 if (!handle)
1220 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1221 if (!handle) return S_FALSE;
1223 This->data.u.foldercoll.find = handle;
1225 else
1227 if (!FindNextFileW(handle, &data))
1228 return S_FALSE;
1233 if (is_dir_data(&data))
1234 --celt;
1236 if (!celt) break;
1237 } while (FindNextFileW(handle, &data));
1239 return celt ? S_FALSE : S_OK;
1242 static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
1244 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1246 TRACE("(%p)\n", This);
1248 FindClose(This->data.u.foldercoll.find);
1249 This->data.u.foldercoll.find = NULL;
1251 return S_OK;
1254 static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1256 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1257 TRACE("(%p)->(%p)\n", This, pclone);
1258 return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
1261 static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
1262 enumvariant_QueryInterface,
1263 enumvariant_AddRef,
1264 foldercoll_enumvariant_Release,
1265 foldercoll_enumvariant_Next,
1266 foldercoll_enumvariant_Skip,
1267 foldercoll_enumvariant_Reset,
1268 foldercoll_enumvariant_Clone
1271 static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
1273 struct enumvariant *This;
1275 *newenum = NULL;
1277 This = heap_alloc(sizeof(*This));
1278 if (!This) return E_OUTOFMEMORY;
1280 This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
1281 This->ref = 1;
1282 This->data.u.foldercoll.find = NULL;
1283 This->data.u.foldercoll.coll = collection;
1284 IFolderCollection_AddRef(&collection->IFolderCollection_iface);
1286 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1288 return S_OK;
1291 static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface)
1293 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1294 ULONG ref = InterlockedDecrement(&This->ref);
1296 TRACE("(%p)->(%d)\n", This, ref);
1298 if (!ref)
1300 IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
1301 FindClose(This->data.u.filecoll.find);
1302 heap_free(This);
1305 return ref;
1308 static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1310 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1311 HANDLE handle = This->data.u.filecoll.find;
1312 WIN32_FIND_DATAW data;
1313 ULONG count = 0;
1315 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1317 if (fetched)
1318 *fetched = 0;
1320 if (!celt) return S_OK;
1322 if (!handle)
1324 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1325 if (!handle) return S_FALSE;
1326 This->data.u.filecoll.find = handle;
1328 else if (!FindNextFileW(handle, &data))
1329 return S_FALSE;
1333 if (is_file_data(&data))
1335 IFile *file;
1336 HRESULT hr;
1337 BSTR str;
1339 str = get_full_path(This->data.u.filecoll.coll->path, &data);
1340 hr = create_file(str, &file);
1341 SysFreeString(str);
1342 if (FAILED(hr)) return hr;
1344 V_VT(&var[count]) = VT_DISPATCH;
1345 V_DISPATCH(&var[count]) = (IDispatch*)file;
1346 if (++count >= celt) break;
1348 } while (FindNextFileW(handle, &data));
1350 if (fetched)
1351 *fetched = count;
1353 return (count < celt) ? S_FALSE : S_OK;
1356 static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1358 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1359 HANDLE handle = This->data.u.filecoll.find;
1360 WIN32_FIND_DATAW data;
1362 TRACE("(%p)->(%d)\n", This, celt);
1364 if (!celt) return S_OK;
1366 if (!handle)
1368 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1369 if (!handle) return S_FALSE;
1370 This->data.u.filecoll.find = handle;
1372 else if (!FindNextFileW(handle, &data))
1373 return S_FALSE;
1377 if (is_file_data(&data))
1378 --celt;
1379 } while (celt && FindNextFileW(handle, &data));
1381 return celt ? S_FALSE : S_OK;
1384 static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface)
1386 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1388 TRACE("(%p)\n", This);
1390 FindClose(This->data.u.filecoll.find);
1391 This->data.u.filecoll.find = NULL;
1393 return S_OK;
1396 static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1398 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1399 TRACE("(%p)->(%p)\n", This, pclone);
1400 return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
1403 static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
1404 enumvariant_QueryInterface,
1405 enumvariant_AddRef,
1406 filecoll_enumvariant_Release,
1407 filecoll_enumvariant_Next,
1408 filecoll_enumvariant_Skip,
1409 filecoll_enumvariant_Reset,
1410 filecoll_enumvariant_Clone
1413 static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum)
1415 struct enumvariant *This;
1417 *newenum = NULL;
1419 This = heap_alloc(sizeof(*This));
1420 if (!This) return E_OUTOFMEMORY;
1422 This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
1423 This->ref = 1;
1424 This->data.u.filecoll.find = NULL;
1425 This->data.u.filecoll.coll = collection;
1426 IFileCollection_AddRef(&collection->IFileCollection_iface);
1428 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1430 return S_OK;
1433 static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface)
1435 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1436 ULONG ref = InterlockedDecrement(&This->ref);
1438 TRACE("(%p)->(%d)\n", This, ref);
1440 if (!ref)
1442 IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
1443 heap_free(This);
1446 return ref;
1449 static HRESULT find_next_drive(struct enumvariant *penum)
1451 int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
1453 for (; i < 32; i++)
1454 if (penum->data.u.drivecoll.coll->drives & (1 << i))
1456 penum->data.u.drivecoll.cur = i;
1457 return S_OK;
1460 return S_FALSE;
1463 static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1465 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1466 ULONG count = 0;
1468 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1470 if (fetched)
1471 *fetched = 0;
1473 if (!celt) return S_OK;
1475 while (find_next_drive(This) == S_OK)
1477 IDrive *drive;
1478 HRESULT hr;
1480 hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
1481 if (FAILED(hr)) return hr;
1483 V_VT(&var[count]) = VT_DISPATCH;
1484 V_DISPATCH(&var[count]) = (IDispatch*)drive;
1486 if (++count >= celt) break;
1489 if (fetched)
1490 *fetched = count;
1492 return (count < celt) ? S_FALSE : S_OK;
1495 static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1497 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1499 TRACE("(%p)->(%d)\n", This, celt);
1501 if (!celt) return S_OK;
1503 while (celt && find_next_drive(This) == S_OK)
1504 celt--;
1506 return celt ? S_FALSE : S_OK;
1509 static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface)
1511 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1513 TRACE("(%p)\n", This);
1515 This->data.u.drivecoll.cur = -1;
1516 return S_OK;
1519 static HRESULT WINAPI drivecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1521 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1522 FIXME("(%p)->(%p): stub\n", This, pclone);
1523 return E_NOTIMPL;
1526 static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
1527 enumvariant_QueryInterface,
1528 enumvariant_AddRef,
1529 drivecoll_enumvariant_Release,
1530 drivecoll_enumvariant_Next,
1531 drivecoll_enumvariant_Skip,
1532 drivecoll_enumvariant_Reset,
1533 drivecoll_enumvariant_Clone
1536 static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum)
1538 struct enumvariant *This;
1540 *newenum = NULL;
1542 This = heap_alloc(sizeof(*This));
1543 if (!This) return E_OUTOFMEMORY;
1545 This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
1546 This->ref = 1;
1547 This->data.u.drivecoll.coll = collection;
1548 This->data.u.drivecoll.cur = -1;
1549 IDriveCollection_AddRef(&collection->IDriveCollection_iface);
1551 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1553 return S_OK;
1556 static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
1558 struct foldercollection *This = impl_from_IFolderCollection(iface);
1560 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1562 *obj = NULL;
1564 if (IsEqualIID( riid, &IID_IFolderCollection ) ||
1565 IsEqualIID( riid, &IID_IDispatch ) ||
1566 IsEqualIID( riid, &IID_IUnknown ))
1568 *obj = iface;
1569 IFolderCollection_AddRef(iface);
1571 else
1572 return E_NOINTERFACE;
1574 return S_OK;
1577 static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
1579 struct foldercollection *This = impl_from_IFolderCollection(iface);
1580 ULONG ref = InterlockedIncrement(&This->ref);
1581 TRACE("(%p)->(%d)\n", This, ref);
1582 return ref;
1585 static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
1587 struct foldercollection *This = impl_from_IFolderCollection(iface);
1588 ULONG ref = InterlockedDecrement(&This->ref);
1589 TRACE("(%p)->(%d)\n", This, ref);
1591 if (!ref)
1593 SysFreeString(This->path);
1594 heap_free(This);
1597 return ref;
1600 static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
1602 struct foldercollection *This = impl_from_IFolderCollection(iface);
1603 TRACE("(%p)->(%p)\n", This, pctinfo);
1604 *pctinfo = 1;
1605 return S_OK;
1608 static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
1609 LCID lcid, ITypeInfo **ppTInfo)
1611 struct foldercollection *This = impl_from_IFolderCollection(iface);
1612 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1613 return get_typeinfo(IFolderCollection_tid, ppTInfo);
1616 static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
1617 LPOLESTR *rgszNames, UINT cNames,
1618 LCID lcid, DISPID *rgDispId)
1620 struct foldercollection *This = impl_from_IFolderCollection(iface);
1621 ITypeInfo *typeinfo;
1622 HRESULT hr;
1624 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1626 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1627 if(SUCCEEDED(hr))
1629 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1630 ITypeInfo_Release(typeinfo);
1633 return hr;
1636 static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
1637 REFIID riid, LCID lcid, WORD wFlags,
1638 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1639 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1641 struct foldercollection *This = impl_from_IFolderCollection(iface);
1642 ITypeInfo *typeinfo;
1643 HRESULT hr;
1645 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1646 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1648 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1649 if(SUCCEEDED(hr))
1651 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1652 pDispParams, pVarResult, pExcepInfo, puArgErr);
1653 ITypeInfo_Release(typeinfo);
1656 return hr;
1659 static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
1661 struct foldercollection *This = impl_from_IFolderCollection(iface);
1662 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
1663 return E_NOTIMPL;
1666 static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
1668 struct foldercollection *This = impl_from_IFolderCollection(iface);
1669 FIXME("(%p)->(%p): stub\n", This, folder);
1670 return E_NOTIMPL;
1673 static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
1675 struct foldercollection *This = impl_from_IFolderCollection(iface);
1677 TRACE("(%p)->(%p)\n", This, newenum);
1679 if(!newenum)
1680 return E_POINTER;
1682 return create_foldercoll_enum(This, newenum);
1685 static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
1687 struct foldercollection *This = impl_from_IFolderCollection(iface);
1688 static const WCHAR allW[] = {'\\','*',0};
1689 WIN32_FIND_DATAW data;
1690 WCHAR pathW[MAX_PATH];
1691 HANDLE handle;
1693 TRACE("(%p)->(%p)\n", This, count);
1695 if(!count)
1696 return E_POINTER;
1698 *count = 0;
1700 strcpyW(pathW, This->path);
1701 strcatW(pathW, allW);
1702 handle = FindFirstFileW(pathW, &data);
1703 if (handle == INVALID_HANDLE_VALUE)
1704 return HRESULT_FROM_WIN32(GetLastError());
1708 if (is_dir_data(&data))
1709 *count += 1;
1710 } while (FindNextFileW(handle, &data));
1711 FindClose(handle);
1713 return S_OK;
1716 static const IFolderCollectionVtbl foldercollvtbl = {
1717 foldercoll_QueryInterface,
1718 foldercoll_AddRef,
1719 foldercoll_Release,
1720 foldercoll_GetTypeInfoCount,
1721 foldercoll_GetTypeInfo,
1722 foldercoll_GetIDsOfNames,
1723 foldercoll_Invoke,
1724 foldercoll_Add,
1725 foldercoll_get_Item,
1726 foldercoll_get__NewEnum,
1727 foldercoll_get_Count
1730 static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
1732 struct foldercollection *This;
1734 *folders = NULL;
1736 This = heap_alloc(sizeof(struct foldercollection));
1737 if (!This) return E_OUTOFMEMORY;
1739 This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
1740 This->ref = 1;
1741 This->path = SysAllocString(path);
1742 if (!This->path)
1744 heap_free(This);
1745 return E_OUTOFMEMORY;
1748 *folders = &This->IFolderCollection_iface;
1750 return S_OK;
1753 static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj)
1755 struct filecollection *This = impl_from_IFileCollection(iface);
1757 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1759 *obj = NULL;
1761 if (IsEqualIID( riid, &IID_IFileCollection ) ||
1762 IsEqualIID( riid, &IID_IDispatch ) ||
1763 IsEqualIID( riid, &IID_IUnknown ))
1765 *obj = iface;
1766 IFileCollection_AddRef(iface);
1768 else
1769 return E_NOINTERFACE;
1771 return S_OK;
1774 static ULONG WINAPI filecoll_AddRef(IFileCollection *iface)
1776 struct filecollection *This = impl_from_IFileCollection(iface);
1777 ULONG ref = InterlockedIncrement(&This->ref);
1778 TRACE("(%p)->(%d)\n", This, ref);
1779 return ref;
1782 static ULONG WINAPI filecoll_Release(IFileCollection *iface)
1784 struct filecollection *This = impl_from_IFileCollection(iface);
1785 ULONG ref = InterlockedDecrement(&This->ref);
1786 TRACE("(%p)->(%d)\n", This, ref);
1788 if (!ref)
1790 SysFreeString(This->path);
1791 heap_free(This);
1794 return ref;
1797 static HRESULT WINAPI filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo)
1799 struct filecollection *This = impl_from_IFileCollection(iface);
1800 TRACE("(%p)->(%p)\n", This, pctinfo);
1801 *pctinfo = 1;
1802 return S_OK;
1805 static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo,
1806 LCID lcid, ITypeInfo **ppTInfo)
1808 struct filecollection *This = impl_from_IFileCollection(iface);
1809 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1810 return get_typeinfo(IFileCollection_tid, ppTInfo);
1813 static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid,
1814 LPOLESTR *rgszNames, UINT cNames,
1815 LCID lcid, DISPID *rgDispId)
1817 struct filecollection *This = impl_from_IFileCollection(iface);
1818 ITypeInfo *typeinfo;
1819 HRESULT hr;
1821 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1823 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1824 if(SUCCEEDED(hr))
1826 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1827 ITypeInfo_Release(typeinfo);
1830 return hr;
1833 static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember,
1834 REFIID riid, LCID lcid, WORD wFlags,
1835 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1836 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1838 struct filecollection *This = impl_from_IFileCollection(iface);
1839 ITypeInfo *typeinfo;
1840 HRESULT hr;
1842 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1843 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1845 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1846 if(SUCCEEDED(hr))
1848 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1849 pDispParams, pVarResult, pExcepInfo, puArgErr);
1850 ITypeInfo_Release(typeinfo);
1853 return hr;
1856 static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file)
1858 struct filecollection *This = impl_from_IFileCollection(iface);
1859 FIXME("(%p)->(%p)\n", This, file);
1860 return E_NOTIMPL;
1863 static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum)
1865 struct filecollection *This = impl_from_IFileCollection(iface);
1867 TRACE("(%p)->(%p)\n", This, ppenum);
1869 if(!ppenum)
1870 return E_POINTER;
1872 return create_filecoll_enum(This, ppenum);
1875 static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count)
1877 struct filecollection *This = impl_from_IFileCollection(iface);
1878 static const WCHAR allW[] = {'\\','*',0};
1879 WIN32_FIND_DATAW data;
1880 WCHAR pathW[MAX_PATH];
1881 HANDLE handle;
1883 TRACE("(%p)->(%p)\n", This, count);
1885 if(!count)
1886 return E_POINTER;
1888 *count = 0;
1890 strcpyW(pathW, This->path);
1891 strcatW(pathW, allW);
1892 handle = FindFirstFileW(pathW, &data);
1893 if (handle == INVALID_HANDLE_VALUE)
1894 return HRESULT_FROM_WIN32(GetLastError());
1898 if (is_file_data(&data))
1899 *count += 1;
1900 } while (FindNextFileW(handle, &data));
1901 FindClose(handle);
1903 return S_OK;
1906 static const IFileCollectionVtbl filecollectionvtbl = {
1907 filecoll_QueryInterface,
1908 filecoll_AddRef,
1909 filecoll_Release,
1910 filecoll_GetTypeInfoCount,
1911 filecoll_GetTypeInfo,
1912 filecoll_GetIDsOfNames,
1913 filecoll_Invoke,
1914 filecoll_get_Item,
1915 filecoll_get__NewEnum,
1916 filecoll_get_Count
1919 static HRESULT create_filecoll(BSTR path, IFileCollection **files)
1921 struct filecollection *This;
1923 *files = NULL;
1925 This = heap_alloc(sizeof(*This));
1926 if (!This) return E_OUTOFMEMORY;
1928 This->IFileCollection_iface.lpVtbl = &filecollectionvtbl;
1929 This->ref = 1;
1930 This->path = SysAllocString(path);
1931 if (!This->path)
1933 heap_free(This);
1934 return E_OUTOFMEMORY;
1937 *files = &This->IFileCollection_iface;
1938 return S_OK;
1941 static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
1943 struct drivecollection *This = impl_from_IDriveCollection(iface);
1945 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1947 *obj = NULL;
1949 if (IsEqualIID( riid, &IID_IDriveCollection ) ||
1950 IsEqualIID( riid, &IID_IDispatch ) ||
1951 IsEqualIID( riid, &IID_IUnknown ))
1953 *obj = iface;
1954 IDriveCollection_AddRef(iface);
1956 else
1957 return E_NOINTERFACE;
1959 return S_OK;
1962 static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
1964 struct drivecollection *This = impl_from_IDriveCollection(iface);
1965 ULONG ref = InterlockedIncrement(&This->ref);
1966 TRACE("(%p)->(%d)\n", This, ref);
1967 return ref;
1970 static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
1972 struct drivecollection *This = impl_from_IDriveCollection(iface);
1973 ULONG ref = InterlockedDecrement(&This->ref);
1974 TRACE("(%p)->(%d)\n", This, ref);
1976 if (!ref)
1977 heap_free(This);
1979 return ref;
1982 static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
1984 struct drivecollection *This = impl_from_IDriveCollection(iface);
1985 TRACE("(%p)->(%p)\n", This, pctinfo);
1986 *pctinfo = 1;
1987 return S_OK;
1990 static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
1991 LCID lcid, ITypeInfo **ppTInfo)
1993 struct drivecollection *This = impl_from_IDriveCollection(iface);
1994 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1995 return get_typeinfo(IDriveCollection_tid, ppTInfo);
1998 static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
1999 LPOLESTR *rgszNames, UINT cNames,
2000 LCID lcid, DISPID *rgDispId)
2002 struct drivecollection *This = impl_from_IDriveCollection(iface);
2003 ITypeInfo *typeinfo;
2004 HRESULT hr;
2006 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2008 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2009 if(SUCCEEDED(hr))
2011 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2012 ITypeInfo_Release(typeinfo);
2015 return hr;
2018 static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
2019 REFIID riid, LCID lcid, WORD wFlags,
2020 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2021 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2023 struct drivecollection *This = impl_from_IDriveCollection(iface);
2024 ITypeInfo *typeinfo;
2025 HRESULT hr;
2027 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2028 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2030 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2031 if(SUCCEEDED(hr))
2033 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2034 pDispParams, pVarResult, pExcepInfo, puArgErr);
2035 ITypeInfo_Release(typeinfo);
2038 return hr;
2041 static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
2043 struct drivecollection *This = impl_from_IDriveCollection(iface);
2044 FIXME("(%p)->(%p): stub\n", This, drive);
2045 return E_NOTIMPL;
2048 static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
2050 struct drivecollection *This = impl_from_IDriveCollection(iface);
2052 TRACE("(%p)->(%p)\n", This, ppenum);
2054 if(!ppenum)
2055 return E_POINTER;
2057 return create_drivecoll_enum(This, ppenum);
2060 static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
2062 struct drivecollection *This = impl_from_IDriveCollection(iface);
2064 TRACE("(%p)->(%p)\n", This, count);
2066 if (!count) return E_POINTER;
2068 *count = This->count;
2069 return S_OK;
2072 static const IDriveCollectionVtbl drivecollectionvtbl = {
2073 drivecoll_QueryInterface,
2074 drivecoll_AddRef,
2075 drivecoll_Release,
2076 drivecoll_GetTypeInfoCount,
2077 drivecoll_GetTypeInfo,
2078 drivecoll_GetIDsOfNames,
2079 drivecoll_Invoke,
2080 drivecoll_get_Item,
2081 drivecoll_get__NewEnum,
2082 drivecoll_get_Count
2085 static HRESULT create_drivecoll(IDriveCollection **drives)
2087 struct drivecollection *This;
2088 DWORD mask;
2090 *drives = NULL;
2092 This = heap_alloc(sizeof(*This));
2093 if (!This) return E_OUTOFMEMORY;
2095 This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl;
2096 This->ref = 1;
2097 This->drives = mask = GetLogicalDrives();
2098 /* count set bits */
2099 for (This->count = 0; mask; This->count++)
2100 mask &= mask - 1;
2102 *drives = &This->IDriveCollection_iface;
2103 return S_OK;
2106 static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
2108 struct folder *This = impl_from_IFolder(iface);
2110 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2112 *obj = NULL;
2114 if (IsEqualIID( riid, &IID_IFolder ) ||
2115 IsEqualIID( riid, &IID_IDispatch ) ||
2116 IsEqualIID( riid, &IID_IUnknown))
2118 *obj = iface;
2119 IFolder_AddRef(iface);
2121 else
2122 return E_NOINTERFACE;
2124 return S_OK;
2127 static ULONG WINAPI folder_AddRef(IFolder *iface)
2129 struct folder *This = impl_from_IFolder(iface);
2130 ULONG ref = InterlockedIncrement(&This->ref);
2131 TRACE("(%p)->(%d)\n", This, ref);
2132 return ref;
2135 static ULONG WINAPI folder_Release(IFolder *iface)
2137 struct folder *This = impl_from_IFolder(iface);
2138 ULONG ref = InterlockedDecrement(&This->ref);
2139 TRACE("(%p)->(%d)\n", This, ref);
2141 if (!ref)
2143 SysFreeString(This->path);
2144 heap_free(This);
2147 return ref;
2150 static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
2152 struct folder *This = impl_from_IFolder(iface);
2153 TRACE("(%p)->(%p)\n", This, pctinfo);
2154 *pctinfo = 1;
2155 return S_OK;
2158 static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
2159 LCID lcid, ITypeInfo **ppTInfo)
2161 struct folder *This = impl_from_IFolder(iface);
2162 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2163 return get_typeinfo(IFolder_tid, ppTInfo);
2166 static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
2167 LPOLESTR *rgszNames, UINT cNames,
2168 LCID lcid, DISPID *rgDispId)
2170 struct folder *This = impl_from_IFolder(iface);
2171 ITypeInfo *typeinfo;
2172 HRESULT hr;
2174 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2176 hr = get_typeinfo(IFolder_tid, &typeinfo);
2177 if(SUCCEEDED(hr))
2179 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2180 ITypeInfo_Release(typeinfo);
2183 return hr;
2186 static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
2187 REFIID riid, LCID lcid, WORD wFlags,
2188 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2189 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2191 struct folder *This = impl_from_IFolder(iface);
2192 ITypeInfo *typeinfo;
2193 HRESULT hr;
2195 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2196 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2198 hr = get_typeinfo(IFolder_tid, &typeinfo);
2199 if(SUCCEEDED(hr))
2201 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2202 pDispParams, pVarResult, pExcepInfo, puArgErr);
2203 ITypeInfo_Release(typeinfo);
2206 return hr;
2209 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
2211 struct folder *This = impl_from_IFolder(iface);
2213 TRACE("(%p)->(%p)\n", This, path);
2215 if(!path)
2216 return E_POINTER;
2218 *path = SysAllocString(This->path);
2219 return *path ? S_OK : E_OUTOFMEMORY;
2222 static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
2224 struct folder *This = impl_from_IFolder(iface);
2225 WCHAR *ptr;
2227 TRACE("(%p)->(%p)\n", This, name);
2229 if(!name)
2230 return E_POINTER;
2232 *name = NULL;
2234 ptr = strrchrW(This->path, '\\');
2235 if (ptr)
2237 *name = SysAllocString(ptr+1);
2238 TRACE("%s\n", debugstr_w(*name));
2239 if (!*name) return E_OUTOFMEMORY;
2241 else
2242 return E_FAIL;
2244 return S_OK;
2247 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
2249 struct folder *This = impl_from_IFolder(iface);
2250 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
2251 return E_NOTIMPL;
2254 static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
2256 struct folder *This = impl_from_IFolder(iface);
2257 FIXME("(%p)->(%p): stub\n", This, path);
2258 return E_NOTIMPL;
2261 static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
2263 struct folder *This = impl_from_IFolder(iface);
2264 FIXME("(%p)->(%p): stub\n", This, name);
2265 return E_NOTIMPL;
2268 static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
2270 struct folder *This = impl_from_IFolder(iface);
2271 FIXME("(%p)->(%p): stub\n", This, drive);
2272 return E_NOTIMPL;
2275 static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
2277 struct folder *This = impl_from_IFolder(iface);
2278 FIXME("(%p)->(%p): stub\n", This, parent);
2279 return E_NOTIMPL;
2282 static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
2284 struct folder *This = impl_from_IFolder(iface);
2285 FIXME("(%p)->(%p): stub\n", This, attr);
2286 return E_NOTIMPL;
2289 static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
2291 struct folder *This = impl_from_IFolder(iface);
2292 FIXME("(%p)->(0x%x): stub\n", This, attr);
2293 return E_NOTIMPL;
2296 static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
2298 struct folder *This = impl_from_IFolder(iface);
2299 FIXME("(%p)->(%p): stub\n", This, date);
2300 return E_NOTIMPL;
2303 static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
2305 struct folder *This = impl_from_IFolder(iface);
2306 FIXME("(%p)->(%p): stub\n", This, date);
2307 return E_NOTIMPL;
2310 static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
2312 struct folder *This = impl_from_IFolder(iface);
2313 FIXME("(%p)->(%p): stub\n", This, date);
2314 return E_NOTIMPL;
2317 static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
2319 struct folder *This = impl_from_IFolder(iface);
2320 FIXME("(%p)->(%p): stub\n", This, type);
2321 return E_NOTIMPL;
2324 static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
2326 struct folder *This = impl_from_IFolder(iface);
2327 FIXME("(%p)->(%x): stub\n", This, force);
2328 return E_NOTIMPL;
2331 static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
2333 struct folder *This = impl_from_IFolder(iface);
2334 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
2335 return E_NOTIMPL;
2338 static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
2340 struct folder *This = impl_from_IFolder(iface);
2341 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
2342 return E_NOTIMPL;
2345 static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
2347 struct folder *This = impl_from_IFolder(iface);
2348 FIXME("(%p)->(%p): stub\n", This, isroot);
2349 return E_NOTIMPL;
2352 static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
2354 struct folder *This = impl_from_IFolder(iface);
2355 FIXME("(%p)->(%p): stub\n", This, size);
2356 return E_NOTIMPL;
2359 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
2361 struct folder *This = impl_from_IFolder(iface);
2363 TRACE("(%p)->(%p)\n", This, folders);
2365 if(!folders)
2366 return E_POINTER;
2368 return create_foldercoll(This->path, folders);
2371 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
2373 struct folder *This = impl_from_IFolder(iface);
2375 TRACE("(%p)->(%p)\n", This, files);
2377 if(!files)
2378 return E_POINTER;
2380 return create_filecoll(This->path, files);
2383 static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
2384 VARIANT_BOOL unicode, ITextStream **stream)
2386 struct folder *This = impl_from_IFolder(iface);
2387 FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
2388 return E_NOTIMPL;
2391 static const IFolderVtbl foldervtbl = {
2392 folder_QueryInterface,
2393 folder_AddRef,
2394 folder_Release,
2395 folder_GetTypeInfoCount,
2396 folder_GetTypeInfo,
2397 folder_GetIDsOfNames,
2398 folder_Invoke,
2399 folder_get_Path,
2400 folder_get_Name,
2401 folder_put_Name,
2402 folder_get_ShortPath,
2403 folder_get_ShortName,
2404 folder_get_Drive,
2405 folder_get_ParentFolder,
2406 folder_get_Attributes,
2407 folder_put_Attributes,
2408 folder_get_DateCreated,
2409 folder_get_DateLastModified,
2410 folder_get_DateLastAccessed,
2411 folder_get_Type,
2412 folder_Delete,
2413 folder_Copy,
2414 folder_Move,
2415 folder_get_IsRootFolder,
2416 folder_get_Size,
2417 folder_get_SubFolders,
2418 folder_get_Files,
2419 folder_CreateTextFile
2422 HRESULT create_folder(const WCHAR *path, IFolder **folder)
2424 struct folder *This;
2426 *folder = NULL;
2428 TRACE("%s\n", debugstr_w(path));
2430 This = heap_alloc(sizeof(struct folder));
2431 if (!This) return E_OUTOFMEMORY;
2433 This->IFolder_iface.lpVtbl = &foldervtbl;
2434 This->ref = 1;
2435 This->path = SysAllocString(path);
2436 if (!This->path)
2438 heap_free(This);
2439 return E_OUTOFMEMORY;
2442 *folder = &This->IFolder_iface;
2444 return S_OK;
2447 static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
2449 struct file *This = impl_from_IFile(iface);
2451 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2453 if (IsEqualIID(riid, &IID_IFile) ||
2454 IsEqualIID(riid, &IID_IDispatch) ||
2455 IsEqualIID(riid, &IID_IUnknown))
2457 *obj = iface;
2458 IFile_AddRef(iface);
2459 return S_OK;
2462 *obj = NULL;
2463 return E_NOINTERFACE;
2466 static ULONG WINAPI file_AddRef(IFile *iface)
2468 struct file *This = impl_from_IFile(iface);
2469 LONG ref = InterlockedIncrement(&This->ref);
2471 TRACE("(%p) ref=%d\n", This, ref);
2473 return ref;
2476 static ULONG WINAPI file_Release(IFile *iface)
2478 struct file *This = impl_from_IFile(iface);
2479 LONG ref = InterlockedDecrement(&This->ref);
2481 TRACE("(%p) ref=%d\n", This, ref);
2483 if(!ref)
2485 heap_free(This->path);
2486 heap_free(This);
2489 return ref;
2492 static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
2494 struct file *This = impl_from_IFile(iface);
2496 TRACE("(%p)->(%p)\n", This, pctinfo);
2498 *pctinfo = 1;
2499 return S_OK;
2502 static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
2503 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
2505 struct file *This = impl_from_IFile(iface);
2507 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2509 return get_typeinfo(IFile_tid, ppTInfo);
2512 static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
2513 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2515 struct file *This = impl_from_IFile(iface);
2516 ITypeInfo *typeinfo;
2517 HRESULT hr;
2519 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
2520 rgszNames, cNames, lcid, rgDispId);
2522 hr = get_typeinfo(IFile_tid, &typeinfo);
2523 if(SUCCEEDED(hr)) {
2524 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2525 ITypeInfo_Release(typeinfo);
2527 return hr;
2530 static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2532 struct file *This = impl_from_IFile(iface);
2533 ITypeInfo *typeinfo;
2534 HRESULT hr;
2536 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2537 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2539 hr = get_typeinfo(IFile_tid, &typeinfo);
2540 if(SUCCEEDED(hr))
2542 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2543 pDispParams, pVarResult, pExcepInfo, puArgErr);
2544 ITypeInfo_Release(typeinfo);
2546 return hr;
2549 static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *path)
2551 struct file *This = impl_from_IFile(iface);
2553 TRACE("(%p)->(%p)\n", This, path);
2555 if (!path)
2556 return E_POINTER;
2558 *path = SysAllocString(This->path);
2559 if (!*path)
2560 return E_OUTOFMEMORY;
2562 return S_OK;
2565 static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
2567 struct file *This = impl_from_IFile(iface);
2568 WCHAR *ptr;
2570 TRACE("(%p)->(%p)\n", This, name);
2572 if(!name)
2573 return E_POINTER;
2575 *name = NULL;
2577 ptr = strrchrW(This->path, '\\');
2578 if (ptr)
2580 *name = SysAllocString(ptr+1);
2581 TRACE("%s\n", debugstr_w(*name));
2582 if (!*name) return E_OUTOFMEMORY;
2584 else
2585 return E_FAIL;
2587 return S_OK;
2590 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
2592 struct file *This = impl_from_IFile(iface);
2593 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
2594 return E_NOTIMPL;
2597 static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
2599 struct file *This = impl_from_IFile(iface);
2600 FIXME("(%p)->(%p)\n", This, pbstrPath);
2601 return E_NOTIMPL;
2604 static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
2606 struct file *This = impl_from_IFile(iface);
2607 FIXME("(%p)->(%p)\n", This, pbstrName);
2608 return E_NOTIMPL;
2611 static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
2613 struct file *This = impl_from_IFile(iface);
2614 FIXME("(%p)->(%p)\n", This, ppdrive);
2615 return E_NOTIMPL;
2618 static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
2620 struct file *This = impl_from_IFile(iface);
2621 FIXME("(%p)->(%p)\n", This, ppfolder);
2622 return E_NOTIMPL;
2625 static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
2627 struct file *This = impl_from_IFile(iface);
2628 DWORD fa;
2630 TRACE("(%p)->(%p)\n", This, pfa);
2632 if(!pfa)
2633 return E_POINTER;
2635 fa = GetFileAttributesW(This->path);
2636 if(fa == INVALID_FILE_ATTRIBUTES)
2637 return create_error(GetLastError());
2639 *pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2640 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
2641 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
2642 return S_OK;
2645 static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
2647 struct file *This = impl_from_IFile(iface);
2648 FIXME("(%p)->(%x)\n", This, pfa);
2649 return E_NOTIMPL;
2652 static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
2654 struct file *This = impl_from_IFile(iface);
2655 FIXME("(%p)->(%p)\n", This, pdate);
2656 return E_NOTIMPL;
2659 static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *pdate)
2661 struct file *This = impl_from_IFile(iface);
2662 FIXME("(%p)->(%p)\n", This, pdate);
2663 return E_NOTIMPL;
2666 static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
2668 struct file *This = impl_from_IFile(iface);
2669 FIXME("(%p)->(%p)\n", This, pdate);
2670 return E_NOTIMPL;
2673 static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
2675 struct file *This = impl_from_IFile(iface);
2676 ULARGE_INTEGER size;
2677 WIN32_FIND_DATAW fd;
2678 HANDLE f;
2680 TRACE("(%p)->(%p)\n", This, pvarSize);
2682 if(!pvarSize)
2683 return E_POINTER;
2685 f = FindFirstFileW(This->path, &fd);
2686 if(f == INVALID_HANDLE_VALUE)
2687 return create_error(GetLastError());
2688 FindClose(f);
2690 size.u.LowPart = fd.nFileSizeLow;
2691 size.u.HighPart = fd.nFileSizeHigh;
2693 return variant_from_largeint(&size, pvarSize);
2696 static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
2698 struct file *This = impl_from_IFile(iface);
2699 FIXME("(%p)->(%p)\n", This, pbstrType);
2700 return E_NOTIMPL;
2703 static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
2705 struct file *This = impl_from_IFile(iface);
2706 FIXME("(%p)->(%x)\n", This, Force);
2707 return E_NOTIMPL;
2710 static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
2712 struct file *This = impl_from_IFile(iface);
2713 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
2714 return E_NOTIMPL;
2717 static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
2719 struct file *This = impl_from_IFile(iface);
2720 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
2721 return E_NOTIMPL;
2724 static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode mode, Tristate format, ITextStream **stream)
2726 struct file *This = impl_from_IFile(iface);
2728 TRACE("(%p)->(%d %d %p)\n", This, mode, format, stream);
2730 if (format == TristateUseDefault) {
2731 FIXME("default format not handled, defaulting to unicode\n");
2732 format = TristateTrue;
2735 return create_textstream(This->path, OPEN_EXISTING, mode, format == TristateTrue, stream);
2738 static const IFileVtbl file_vtbl = {
2739 file_QueryInterface,
2740 file_AddRef,
2741 file_Release,
2742 file_GetTypeInfoCount,
2743 file_GetTypeInfo,
2744 file_GetIDsOfNames,
2745 file_Invoke,
2746 file_get_Path,
2747 file_get_Name,
2748 file_put_Name,
2749 file_get_ShortPath,
2750 file_get_ShortName,
2751 file_get_Drive,
2752 file_get_ParentFolder,
2753 file_get_Attributes,
2754 file_put_Attributes,
2755 file_get_DateCreated,
2756 file_get_DateLastModified,
2757 file_get_DateLastAccessed,
2758 file_get_Size,
2759 file_get_Type,
2760 file_Delete,
2761 file_Copy,
2762 file_Move,
2763 file_OpenAsTextStream
2766 static HRESULT create_file(BSTR path, IFile **file)
2768 struct file *f;
2769 DWORD len, attrs;
2771 *file = NULL;
2773 f = heap_alloc(sizeof(struct file));
2774 if(!f)
2775 return E_OUTOFMEMORY;
2777 f->IFile_iface.lpVtbl = &file_vtbl;
2778 f->ref = 1;
2780 len = GetFullPathNameW(path, 0, NULL, NULL);
2781 if(!len) {
2782 heap_free(f);
2783 return E_FAIL;
2786 f->path = heap_alloc(len*sizeof(WCHAR));
2787 if(!f->path) {
2788 heap_free(f);
2789 return E_OUTOFMEMORY;
2792 if(!GetFullPathNameW(path, len, f->path, NULL)) {
2793 heap_free(f->path);
2794 heap_free(f);
2795 return E_FAIL;
2798 attrs = GetFileAttributesW(f->path);
2799 if(attrs==INVALID_FILE_ATTRIBUTES ||
2800 (attrs&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))) {
2801 heap_free(f->path);
2802 heap_free(f);
2803 return create_error(GetLastError());
2806 *file = &f->IFile_iface;
2807 return S_OK;
2810 static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
2812 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
2814 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
2815 IsEqualGUID( riid, &IID_IFileSystem ) ||
2816 IsEqualGUID( riid, &IID_IDispatch ) ||
2817 IsEqualGUID( riid, &IID_IUnknown ) )
2819 *ppvObject = iface;
2821 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
2823 TRACE("Interface IDispatchEx not supported - returning NULL\n");
2824 *ppvObject = NULL;
2825 return E_NOINTERFACE;
2827 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
2829 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
2830 *ppvObject = NULL;
2831 return E_NOINTERFACE;
2833 else
2835 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
2836 return E_NOINTERFACE;
2839 IFileSystem3_AddRef(iface);
2841 return S_OK;
2844 static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
2846 TRACE("%p\n", iface);
2848 return 2;
2851 static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
2853 TRACE("%p\n", iface);
2855 return 1;
2858 static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
2860 TRACE("(%p)->(%p)\n", iface, pctinfo);
2862 *pctinfo = 1;
2863 return S_OK;
2866 static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
2867 LCID lcid, ITypeInfo **ppTInfo)
2869 TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
2870 return get_typeinfo(IFileSystem3_tid, ppTInfo);
2873 static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
2874 LPOLESTR *rgszNames, UINT cNames,
2875 LCID lcid, DISPID *rgDispId)
2877 ITypeInfo *typeinfo;
2878 HRESULT hr;
2880 TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2882 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2883 if(SUCCEEDED(hr))
2885 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2886 ITypeInfo_Release(typeinfo);
2889 return hr;
2892 static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
2893 REFIID riid, LCID lcid, WORD wFlags,
2894 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2895 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2897 ITypeInfo *typeinfo;
2898 HRESULT hr;
2900 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
2901 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2903 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2904 if(SUCCEEDED(hr))
2906 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2907 pDispParams, pVarResult, pExcepInfo, puArgErr);
2908 ITypeInfo_Release(typeinfo);
2911 return hr;
2914 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
2916 TRACE("%p %p\n", iface, ppdrives);
2917 return create_drivecoll(ppdrives);
2920 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
2921 BSTR Name, BSTR *Result)
2923 BSTR ret;
2925 TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
2927 if (!Result) return E_POINTER;
2929 if (Path && Name)
2931 int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
2933 /* if both parts have backslashes strip one from Path */
2934 if (Path[path_len-1] == '\\' && Name[0] == '\\')
2936 path_len -= 1;
2938 ret = SysAllocStringLen(NULL, path_len + name_len);
2939 if (ret)
2941 strcpyW(ret, Path);
2942 ret[path_len] = 0;
2943 strcatW(ret, Name);
2946 else if (Path[path_len-1] != '\\' && Name[0] != '\\')
2948 ret = SysAllocStringLen(NULL, path_len + name_len + 1);
2949 if (ret)
2951 strcpyW(ret, Path);
2952 if (Path[path_len-1] != ':')
2953 strcatW(ret, bsW);
2954 strcatW(ret, Name);
2957 else
2959 ret = SysAllocStringLen(NULL, path_len + name_len);
2960 if (ret)
2962 strcpyW(ret, Path);
2963 strcatW(ret, Name);
2967 else if (Path || Name)
2968 ret = SysAllocString(Path ? Path : Name);
2969 else
2970 ret = SysAllocStringLen(NULL, 0);
2972 if (!ret) return E_OUTOFMEMORY;
2973 *Result = ret;
2975 return S_OK;
2978 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR path, BSTR *drive)
2980 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), drive);
2982 if (!drive)
2983 return E_POINTER;
2985 *drive = NULL;
2987 if (path && strlenW(path) > 1 && path[1] == ':')
2988 *drive = SysAllocStringLen(path, 2);
2990 return S_OK;
2993 static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
2995 int i;
2997 if(!path)
2998 return 0;
3000 for(i=len-1; i>=0; i--)
3001 if(path[i]!='/' && path[i]!='\\')
3002 break;
3004 for(; i>=0; i--)
3005 if(path[i]=='/' || path[i]=='\\')
3006 break;
3008 for(; i>=0; i--)
3009 if(path[i]!='/' && path[i]!='\\')
3010 break;
3012 if(i < 0)
3013 return 0;
3015 if(path[i]==':' && i==1)
3016 i++;
3017 return i+1;
3020 static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
3021 BSTR *pbstrResult)
3023 DWORD len;
3025 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3027 if(!pbstrResult)
3028 return E_POINTER;
3030 len = get_parent_folder_name(Path, SysStringLen(Path));
3031 if(!len) {
3032 *pbstrResult = NULL;
3033 return S_OK;
3036 *pbstrResult = SysAllocStringLen(Path, len);
3037 if(!*pbstrResult)
3038 return E_OUTOFMEMORY;
3039 return S_OK;
3042 static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
3043 BSTR *pbstrResult)
3045 int i, end;
3047 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3049 if(!pbstrResult)
3050 return E_POINTER;
3052 if(!Path) {
3053 *pbstrResult = NULL;
3054 return S_OK;
3057 for(end=strlenW(Path)-1; end>=0; end--)
3058 if(Path[end]!='/' && Path[end]!='\\')
3059 break;
3061 for(i=end; i>=0; i--)
3062 if(Path[i]=='/' || Path[i]=='\\')
3063 break;
3064 i++;
3066 if(i>end || (i==0 && end==1 && Path[1]==':')) {
3067 *pbstrResult = NULL;
3068 return S_OK;
3071 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3072 if(!*pbstrResult)
3073 return E_OUTOFMEMORY;
3074 return S_OK;
3077 static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
3078 BSTR *pbstrResult)
3080 int i, end;
3082 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3084 if(!pbstrResult)
3085 return E_POINTER;
3087 if(!Path) {
3088 *pbstrResult = NULL;
3089 return S_OK;
3092 for(end=strlenW(Path)-1; end>=0; end--)
3093 if(Path[end]!='/' && Path[end]!='\\')
3094 break;
3096 for(i=end; i>=0; i--) {
3097 if(Path[i]=='.' && Path[end+1]!='.')
3098 end = i-1;
3099 if(Path[i]=='/' || Path[i]=='\\')
3100 break;
3102 i++;
3104 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
3105 *pbstrResult = NULL;
3106 return S_OK;
3109 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3110 if(!*pbstrResult)
3111 return E_OUTOFMEMORY;
3112 return S_OK;
3115 static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR path,
3116 BSTR *ext)
3118 INT len;
3120 TRACE("%p %s %p\n", iface, debugstr_w(path), ext);
3122 *ext = NULL;
3123 len = SysStringLen(path);
3124 while (len) {
3125 if (path[len-1] == '.') {
3126 *ext = SysAllocString(&path[len]);
3127 if (!*ext)
3128 return E_OUTOFMEMORY;
3129 break;
3131 len--;
3134 return S_OK;
3137 static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR Path,
3138 BSTR *pbstrResult)
3140 static const WCHAR cur_path[] = {'.',0};
3142 WCHAR buf[MAX_PATH], ch;
3143 const WCHAR *path;
3144 DWORD i, beg, len, exp_len;
3145 WIN32_FIND_DATAW fdata;
3146 HANDLE fh;
3148 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3150 if(!pbstrResult)
3151 return E_POINTER;
3153 if(!Path)
3154 path = cur_path;
3155 else
3156 path = Path;
3158 len = GetFullPathNameW(path, MAX_PATH, buf, NULL);
3159 if(!len)
3160 return E_FAIL;
3162 buf[0] = toupperW(buf[0]);
3163 if(len>3 && buf[len-1] == '\\')
3164 buf[--len] = 0;
3166 for(beg=3, i=3; i<=len; i++) {
3167 if(buf[i]!='\\' && buf[i])
3168 continue;
3170 ch = buf[i];
3171 buf[i] = 0;
3172 fh = FindFirstFileW(buf, &fdata);
3173 if(fh == INVALID_HANDLE_VALUE)
3174 break;
3176 exp_len = strlenW(fdata.cFileName);
3177 if(exp_len == i-beg)
3178 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
3179 FindClose(fh);
3180 buf[i] = ch;
3181 beg = i+1;
3184 *pbstrResult = SysAllocString(buf);
3185 if(!*pbstrResult)
3186 return E_OUTOFMEMORY;
3187 return S_OK;
3190 static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
3192 static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
3194 DWORD random;
3196 TRACE("%p %p\n", iface, pbstrResult);
3198 if(!pbstrResult)
3199 return E_POINTER;
3201 *pbstrResult = SysAllocStringLen(NULL, 12);
3202 if(!*pbstrResult)
3203 return E_OUTOFMEMORY;
3205 if(!RtlGenRandom(&random, sizeof(random)))
3206 return E_FAIL;
3207 sprintfW(*pbstrResult, fmt, random & 0xfffff);
3208 return S_OK;
3211 static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
3212 VARIANT_BOOL *pfExists)
3214 FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
3216 return E_NOTIMPL;
3219 static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3221 DWORD attrs;
3222 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3224 if (!ret) return E_POINTER;
3226 attrs = GetFileAttributesW(path);
3227 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3228 return S_OK;
3231 static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3233 DWORD attrs;
3234 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3236 if (!ret) return E_POINTER;
3238 attrs = GetFileAttributesW(path);
3239 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3241 return S_OK;
3244 static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
3245 IDrive **ppdrive)
3247 FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
3249 return E_NOTIMPL;
3252 static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
3253 IFile **ppfile)
3255 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
3257 if(!ppfile)
3258 return E_POINTER;
3259 if(!FilePath)
3260 return E_INVALIDARG;
3262 return create_file(FilePath, ppfile);
3265 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
3266 IFolder **folder)
3268 DWORD attrs;
3270 TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
3272 if(!folder)
3273 return E_POINTER;
3275 *folder = NULL;
3276 if(!FolderPath)
3277 return E_INVALIDARG;
3279 attrs = GetFileAttributesW(FolderPath);
3280 if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
3281 return CTL_E_PATHNOTFOUND;
3283 return create_folder(FolderPath, folder);
3286 static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
3287 SpecialFolderConst SpecialFolder,
3288 IFolder **ppfolder)
3290 FIXME("%p %d %p\n", iface, SpecialFolder, ppfolder);
3292 return E_NOTIMPL;
3295 static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
3297 WCHAR path[MAX_PATH];
3298 DWORD len, name_len;
3299 WIN32_FIND_DATAW ffd;
3300 HANDLE f;
3302 f = FindFirstFileW(file, &ffd);
3303 if(f == INVALID_HANDLE_VALUE)
3304 return create_error(GetLastError());
3306 len = get_parent_folder_name(file, file_len);
3307 if(len+1 >= MAX_PATH) {
3308 FindClose(f);
3309 return E_FAIL;
3311 if(len) {
3312 memcpy(path, file, len*sizeof(WCHAR));
3313 path[len++] = '\\';
3316 do {
3317 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3318 continue;
3320 name_len = strlenW(ffd.cFileName);
3321 if(len+name_len+1 >= MAX_PATH) {
3322 FindClose(f);
3323 return E_FAIL;
3325 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3327 TRACE("deleting %s\n", debugstr_w(path));
3329 if(!DeleteFileW(path)) {
3330 if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
3331 || !DeleteFileW(path)) {
3332 FindClose(f);
3333 return create_error(GetLastError());
3336 } while(FindNextFileW(f, &ffd));
3337 FindClose(f);
3339 return S_OK;
3342 static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
3343 VARIANT_BOOL Force)
3345 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
3347 if(!FileSpec)
3348 return E_POINTER;
3350 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
3353 static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
3355 WCHAR path[MAX_PATH];
3356 DWORD len, name_len;
3357 WIN32_FIND_DATAW ffd;
3358 HANDLE f;
3359 HRESULT hr;
3361 f = FindFirstFileW(folder, &ffd);
3362 if(f == INVALID_HANDLE_VALUE)
3363 return create_error(GetLastError());
3365 len = get_parent_folder_name(folder, folder_len);
3366 if(len+1 >= MAX_PATH) {
3367 FindClose(f);
3368 return E_FAIL;
3370 if(len) {
3371 memcpy(path, folder, len*sizeof(WCHAR));
3372 path[len++] = '\\';
3375 do {
3376 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3377 continue;
3378 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3379 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3380 continue;
3382 name_len = strlenW(ffd.cFileName);
3383 if(len+name_len+3 >= MAX_PATH) {
3384 FindClose(f);
3385 return E_FAIL;
3387 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
3388 path[len+name_len] = '\\';
3389 path[len+name_len+1] = '*';
3390 path[len+name_len+2] = 0;
3392 hr = delete_file(path, len+name_len+2, force);
3393 if(FAILED(hr)) {
3394 FindClose(f);
3395 return hr;
3398 hr = delete_folder(path, len+name_len+2, force);
3399 if(FAILED(hr)) {
3400 FindClose(f);
3401 return hr;
3404 path[len+name_len] = 0;
3405 TRACE("deleting %s\n", debugstr_w(path));
3407 if(!RemoveDirectoryW(path)) {
3408 FindClose(f);
3409 return create_error(GetLastError());
3411 } while(FindNextFileW(f, &ffd));
3412 FindClose(f);
3414 return S_OK;
3417 static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
3418 VARIANT_BOOL Force)
3420 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
3422 if(!FolderSpec)
3423 return E_POINTER;
3425 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
3428 static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR Source,
3429 BSTR Destination)
3431 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3433 return E_NOTIMPL;
3436 static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
3437 BSTR Destination)
3439 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3441 return E_NOTIMPL;
3444 static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
3445 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
3447 DWORD attrs;
3448 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
3449 DWORD src_len, dst_len, name_len;
3450 WIN32_FIND_DATAW ffd;
3451 HANDLE f;
3452 HRESULT hr;
3454 if(!source[0] || !destination[0])
3455 return E_INVALIDARG;
3457 attrs = GetFileAttributesW(destination);
3458 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
3459 attrs = GetFileAttributesW(source);
3460 if(attrs == INVALID_FILE_ATTRIBUTES)
3461 return create_error(GetLastError());
3462 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
3463 return CTL_E_FILENOTFOUND;
3465 if(!CopyFileW(source, destination, !overwrite))
3466 return create_error(GetLastError());
3467 return S_OK;
3470 f = FindFirstFileW(source, &ffd);
3471 if(f == INVALID_HANDLE_VALUE)
3472 return CTL_E_FILENOTFOUND;
3474 src_len = get_parent_folder_name(source, source_len);
3475 if(src_len+1 >= MAX_PATH) {
3476 FindClose(f);
3477 return E_FAIL;
3479 if(src_len) {
3480 memcpy(src_path, source, src_len*sizeof(WCHAR));
3481 src_path[src_len++] = '\\';
3484 dst_len = destination_len;
3485 if(dst_len+1 >= MAX_PATH) {
3486 FindClose(f);
3487 return E_FAIL;
3489 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
3490 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
3491 dst_path[dst_len++] = '\\';
3493 hr = CTL_E_FILENOTFOUND;
3494 do {
3495 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3496 continue;
3498 name_len = strlenW(ffd.cFileName);
3499 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
3500 FindClose(f);
3501 return E_FAIL;
3503 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3504 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3506 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
3508 if(!CopyFileW(src_path, dst_path, !overwrite)) {
3509 FindClose(f);
3510 return create_error(GetLastError());
3511 }else {
3512 hr = S_OK;
3514 } while(FindNextFileW(f, &ffd));
3515 FindClose(f);
3517 return hr;
3520 static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
3521 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3523 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3525 if(!Source || !Destination)
3526 return E_POINTER;
3528 return copy_file(Source, SysStringLen(Source), Destination,
3529 SysStringLen(Destination), OverWriteFiles);
3532 static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
3533 DWORD destination_len, VARIANT_BOOL overwrite)
3535 DWORD tmp, src_len, dst_len, name_len;
3536 WCHAR src[MAX_PATH], dst[MAX_PATH];
3537 WIN32_FIND_DATAW ffd;
3538 HANDLE f;
3539 HRESULT hr;
3540 BOOL copied = FALSE;
3542 if(!source[0] || !destination[0])
3543 return E_INVALIDARG;
3545 dst_len = destination_len;
3546 if(dst_len+1 >= MAX_PATH)
3547 return E_FAIL;
3548 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
3550 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
3551 (tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
3552 tmp&FILE_ATTRIBUTE_DIRECTORY) {
3553 if(!CreateDirectoryW(dst, NULL)) {
3554 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3555 tmp = GetFileAttributesW(dst);
3556 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
3557 return CTL_E_FILEALREADYEXISTS;
3558 }else {
3559 return create_error(GetLastError());
3562 copied = TRUE;
3564 src_len = source_len;
3565 if(src_len+2 >= MAX_PATH)
3566 return E_FAIL;
3567 memcpy(src, source, src_len*sizeof(WCHAR));
3568 src[src_len++] = '\\';
3569 src[src_len] = '*';
3570 src[src_len+1] = 0;
3572 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
3573 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
3574 return create_error(GetLastError());
3576 f = FindFirstFileW(src, &ffd);
3577 }else {
3578 src_len = get_parent_folder_name(source, source_len);
3579 if(src_len+2 >= MAX_PATH)
3580 return E_FAIL;
3581 memcpy(src, source, src_len*sizeof(WCHAR));
3582 if(src_len)
3583 src[src_len++] = '\\';
3585 f = FindFirstFileW(source, &ffd);
3587 if(f == INVALID_HANDLE_VALUE)
3588 return CTL_E_PATHNOTFOUND;
3590 dst[dst_len++] = '\\';
3591 dst[dst_len] = 0;
3593 do {
3594 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3595 continue;
3596 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3597 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3598 continue;
3600 name_len = strlenW(ffd.cFileName);
3601 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
3602 FindClose(f);
3603 return E_FAIL;
3605 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
3606 dst[dst_len+name_len] = 0;
3607 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
3608 src[src_len+name_len] = '\\';
3609 src[src_len+name_len+1] = '*';
3610 src[src_len+name_len+2] = 0;
3612 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
3614 if(!CreateDirectoryW(dst, NULL)) {
3615 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3616 tmp = GetFileAttributesW(dst);
3617 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
3618 FindClose(f);
3619 return CTL_E_FILEALREADYEXISTS;
3623 FindClose(f);
3624 return create_error(GetLastError());
3626 copied = TRUE;
3628 hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3629 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
3630 FindClose(f);
3631 return hr;
3634 hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3635 if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
3636 FindClose(f);
3637 return hr;
3639 } while(FindNextFileW(f, &ffd));
3640 FindClose(f);
3642 return copied ? S_OK : CTL_E_PATHNOTFOUND;
3645 static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
3646 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3648 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3650 if(!Source || !Destination)
3651 return E_POINTER;
3653 return copy_folder(Source, SysStringLen(Source), Destination,
3654 SysStringLen(Destination), OverWriteFiles);
3657 static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
3658 IFolder **folder)
3660 BOOL ret;
3662 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
3664 ret = CreateDirectoryW(path, NULL);
3665 if (!ret)
3667 *folder = NULL;
3668 if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
3669 return HRESULT_FROM_WIN32(GetLastError());
3672 return create_folder(path, folder);
3675 static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR filename,
3676 VARIANT_BOOL overwrite, VARIANT_BOOL unicode,
3677 ITextStream **stream)
3679 DWORD disposition;
3681 TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
3683 disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
3684 return create_textstream(filename, disposition, ForWriting, !!unicode, stream);
3687 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
3688 IOMode mode, VARIANT_BOOL create,
3689 Tristate format, ITextStream **stream)
3691 DWORD disposition;
3693 TRACE("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
3694 disposition = create == VARIANT_TRUE ? OPEN_ALWAYS : OPEN_EXISTING;
3696 if (format == TristateUseDefault) {
3697 FIXME("default format not handled, defaulting to unicode\n");
3698 format = TristateTrue;
3701 return create_textstream(filename, disposition, mode, format == TristateTrue, stream);
3704 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
3705 StandardStreamTypes StandardStreamType,
3706 VARIANT_BOOL Unicode,
3707 ITextStream **ppts)
3709 FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
3711 return E_NOTIMPL;
3714 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
3716 static const WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
3717 DWORDLONG version;
3718 WORD a, b, c, d;
3720 version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
3721 a = (WORD)( version >> 48);
3722 b = (WORD)((version >> 32) & 0xffff);
3723 c = (WORD)((version >> 16) & 0xffff);
3724 d = (WORD)( version & 0xffff);
3726 sprintfW(ver, fmtW, a, b, c, d);
3729 static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
3731 static const WCHAR rootW[] = {'\\',0};
3732 VS_FIXEDFILEINFO *info;
3733 WCHAR ver[30];
3734 void *ptr;
3735 DWORD len;
3736 BOOL ret;
3738 TRACE("%p %s %p\n", iface, debugstr_w(name), version);
3740 len = GetFileVersionInfoSizeW(name, NULL);
3741 if (!len)
3742 return HRESULT_FROM_WIN32(GetLastError());
3744 ptr = heap_alloc(len);
3745 if (!GetFileVersionInfoW(name, 0, len, ptr))
3747 heap_free(ptr);
3748 return HRESULT_FROM_WIN32(GetLastError());
3751 ret = VerQueryValueW(ptr, rootW, (void**)&info, &len);
3752 if (!ret)
3754 heap_free(ptr);
3755 return HRESULT_FROM_WIN32(GetLastError());
3758 get_versionstring(info, ver);
3759 heap_free(ptr);
3761 *version = SysAllocString(ver);
3762 TRACE("version=%s\n", debugstr_w(ver));
3764 return S_OK;
3767 static const struct IFileSystem3Vtbl filesys_vtbl =
3769 filesys_QueryInterface,
3770 filesys_AddRef,
3771 filesys_Release,
3772 filesys_GetTypeInfoCount,
3773 filesys_GetTypeInfo,
3774 filesys_GetIDsOfNames,
3775 filesys_Invoke,
3776 filesys_get_Drives,
3777 filesys_BuildPath,
3778 filesys_GetDriveName,
3779 filesys_GetParentFolderName,
3780 filesys_GetFileName,
3781 filesys_GetBaseName,
3782 filesys_GetExtensionName,
3783 filesys_GetAbsolutePathName,
3784 filesys_GetTempName,
3785 filesys_DriveExists,
3786 filesys_FileExists,
3787 filesys_FolderExists,
3788 filesys_GetDrive,
3789 filesys_GetFile,
3790 filesys_GetFolder,
3791 filesys_GetSpecialFolder,
3792 filesys_DeleteFile,
3793 filesys_DeleteFolder,
3794 filesys_MoveFile,
3795 filesys_MoveFolder,
3796 filesys_CopyFile,
3797 filesys_CopyFolder,
3798 filesys_CreateFolder,
3799 filesys_CreateTextFile,
3800 filesys_OpenTextFile,
3801 filesys_GetStandardStream,
3802 filesys_GetFileVersion
3805 static IFileSystem3 filesystem = { &filesys_vtbl };
3807 HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
3809 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
3811 return IFileSystem3_QueryInterface(&filesystem, riid, ppv);