scrrun: Implement Count() property for file collection.
[wine/multimedia.git] / dlls / scrrun / filesystem.c
blobf5afb9174c33d7630e837e31f7ae17d1107b1862
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 WINAPI drive_get_AvailableSpace(IDrive *iface, VARIANT *v)
893 struct drive *This = impl_from_IDrive(iface);
894 ULARGE_INTEGER avail;
896 TRACE("(%p)->(%p)\n", This, v);
898 if (!v)
899 return E_POINTER;
901 if (!GetDiskFreeSpaceExW(This->root, &avail, NULL, NULL))
902 return E_FAIL;
904 V_VT(v) = VT_R8;
905 return VarR8FromUI8(avail.QuadPart, &V_R8(v));
908 static HRESULT WINAPI drive_get_FreeSpace(IDrive *iface, VARIANT *v)
910 struct drive *This = impl_from_IDrive(iface);
911 ULARGE_INTEGER freespace;
913 TRACE("(%p)->(%p)\n", This, v);
915 if (!v)
916 return E_POINTER;
918 if (!GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL))
919 return E_FAIL;
921 V_VT(v) = VT_R8;
922 return VarR8FromUI8(freespace.QuadPart, &V_R8(v));
925 static HRESULT WINAPI drive_get_TotalSize(IDrive *iface, VARIANT *v)
927 struct drive *This = impl_from_IDrive(iface);
928 ULARGE_INTEGER total;
930 TRACE("(%p)->(%p)\n", This, v);
932 if (!v)
933 return E_POINTER;
935 if (!GetDiskFreeSpaceExW(This->root, NULL, &total, NULL))
936 return E_FAIL;
938 V_VT(v) = VT_R8;
939 return VarR8FromUI8(total.QuadPart, &V_R8(v));
942 static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name)
944 struct drive *This = impl_from_IDrive(iface);
945 FIXME("(%p)->(%p): stub\n", This, name);
946 return E_NOTIMPL;
949 static HRESULT WINAPI drive_put_VolumeName(IDrive *iface, BSTR name)
951 struct drive *This = impl_from_IDrive(iface);
952 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
953 return E_NOTIMPL;
956 static HRESULT WINAPI drive_get_FileSystem(IDrive *iface, BSTR *fs)
958 struct drive *This = impl_from_IDrive(iface);
959 FIXME("(%p)->(%p): stub\n", This, fs);
960 return E_NOTIMPL;
963 static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial)
965 struct drive *This = impl_from_IDrive(iface);
966 FIXME("(%p)->(%p): stub\n", This, serial);
967 return E_NOTIMPL;
970 static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
972 struct drive *This = impl_from_IDrive(iface);
973 ULARGE_INTEGER freespace;
974 BOOL ret;
976 TRACE("(%p)->(%p)\n", This, ready);
978 if (!ready)
979 return E_POINTER;
981 ret = GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL);
982 *ready = ret ? VARIANT_TRUE : VARIANT_FALSE;
983 return S_OK;
986 static const IDriveVtbl drivevtbl = {
987 drive_QueryInterface,
988 drive_AddRef,
989 drive_Release,
990 drive_GetTypeInfoCount,
991 drive_GetTypeInfo,
992 drive_GetIDsOfNames,
993 drive_Invoke,
994 drive_get_Path,
995 drive_get_DriveLetter,
996 drive_get_ShareName,
997 drive_get_DriveType,
998 drive_get_RootFolder,
999 drive_get_AvailableSpace,
1000 drive_get_FreeSpace,
1001 drive_get_TotalSize,
1002 drive_get_VolumeName,
1003 drive_put_VolumeName,
1004 drive_get_FileSystem,
1005 drive_get_SerialNumber,
1006 drive_get_IsReady
1009 static HRESULT create_drive(WCHAR letter, IDrive **drive)
1011 struct drive *This;
1013 *drive = NULL;
1015 This = heap_alloc(sizeof(*This));
1016 if (!This) return E_OUTOFMEMORY;
1018 This->IDrive_iface.lpVtbl = &drivevtbl;
1019 This->ref = 1;
1020 This->root = SysAllocStringLen(NULL, 3);
1021 if (!This->root)
1023 heap_free(This);
1024 return E_OUTOFMEMORY;
1026 This->root[0] = letter;
1027 This->root[1] = ':';
1028 This->root[2] = '\\';
1029 This->root[3] = 0;
1031 *drive = &This->IDrive_iface;
1032 return S_OK;
1035 static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
1037 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1039 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1041 *obj = NULL;
1043 if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
1044 IsEqualIID( riid, &IID_IUnknown ))
1046 *obj = iface;
1047 IEnumVARIANT_AddRef(iface);
1049 else
1050 return E_NOINTERFACE;
1052 return S_OK;
1055 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
1057 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1058 ULONG ref = InterlockedIncrement(&This->ref);
1059 TRACE("(%p)->(%d)\n", This, ref);
1060 return ref;
1063 static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
1065 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1066 ULONG ref = InterlockedDecrement(&This->ref);
1068 TRACE("(%p)->(%d)\n", This, ref);
1070 if (!ref)
1072 IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
1073 FindClose(This->data.u.foldercoll.find);
1074 heap_free(This);
1077 return ref;
1080 static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file)
1082 static const WCHAR allW[] = {'*',0};
1083 WCHAR pathW[MAX_PATH];
1084 int len;
1085 HANDLE handle;
1087 strcpyW(pathW, path);
1088 len = strlenW(pathW);
1089 if (pathW[len-1] != '\\')
1090 strcatW(pathW, bsW);
1091 strcatW(pathW, allW);
1092 handle = FindFirstFileW(pathW, data);
1093 if (handle == INVALID_HANDLE_VALUE) return 0;
1095 /* find first dir/file */
1096 while (1)
1098 if (file ? is_file_data(data) : is_dir_data(data))
1099 break;
1101 if (!FindNextFileW(handle, data))
1103 FindClose(handle);
1104 return 0;
1107 return handle;
1110 static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1112 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1113 HANDLE handle = This->data.u.foldercoll.find;
1114 WIN32_FIND_DATAW data;
1115 ULONG count = 0;
1117 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1119 if (fetched)
1120 *fetched = 0;
1122 if (!celt) return S_OK;
1124 if (!handle)
1126 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1127 if (!handle) return S_FALSE;
1129 This->data.u.foldercoll.find = handle;
1131 else
1133 if (!FindNextFileW(handle, &data))
1134 return S_FALSE;
1139 if (is_dir_data(&data))
1141 IFolder *folder;
1142 HRESULT hr;
1143 BSTR str;
1145 str = get_full_path(This->data.u.foldercoll.coll->path, &data);
1146 hr = create_folder(str, &folder);
1147 SysFreeString(str);
1148 if (FAILED(hr)) return hr;
1150 V_VT(&var[count]) = VT_DISPATCH;
1151 V_DISPATCH(&var[count]) = (IDispatch*)folder;
1152 count++;
1154 if (count >= celt) break;
1156 } while (FindNextFileW(handle, &data));
1158 if (fetched)
1159 *fetched = count;
1161 return (count < celt) ? S_FALSE : S_OK;
1164 static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1166 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1167 HANDLE handle = This->data.u.foldercoll.find;
1168 WIN32_FIND_DATAW data;
1170 TRACE("(%p)->(%d)\n", This, celt);
1172 if (!celt) return S_OK;
1174 if (!handle)
1176 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1177 if (!handle) return S_FALSE;
1179 This->data.u.foldercoll.find = handle;
1181 else
1183 if (!FindNextFileW(handle, &data))
1184 return S_FALSE;
1189 if (is_dir_data(&data))
1190 --celt;
1192 if (!celt) break;
1193 } while (FindNextFileW(handle, &data));
1195 return celt ? S_FALSE : S_OK;
1198 static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
1200 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1202 TRACE("(%p)\n", This);
1204 FindClose(This->data.u.foldercoll.find);
1205 This->data.u.foldercoll.find = NULL;
1207 return S_OK;
1210 static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1212 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1213 TRACE("(%p)->(%p)\n", This, pclone);
1214 return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
1217 static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
1218 enumvariant_QueryInterface,
1219 enumvariant_AddRef,
1220 foldercoll_enumvariant_Release,
1221 foldercoll_enumvariant_Next,
1222 foldercoll_enumvariant_Skip,
1223 foldercoll_enumvariant_Reset,
1224 foldercoll_enumvariant_Clone
1227 static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
1229 struct enumvariant *This;
1231 *newenum = NULL;
1233 This = heap_alloc(sizeof(*This));
1234 if (!This) return E_OUTOFMEMORY;
1236 This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
1237 This->ref = 1;
1238 This->data.u.foldercoll.find = NULL;
1239 This->data.u.foldercoll.coll = collection;
1240 IFolderCollection_AddRef(&collection->IFolderCollection_iface);
1242 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1244 return S_OK;
1247 static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface)
1249 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1250 ULONG ref = InterlockedDecrement(&This->ref);
1252 TRACE("(%p)->(%d)\n", This, ref);
1254 if (!ref)
1256 IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
1257 FindClose(This->data.u.filecoll.find);
1258 heap_free(This);
1261 return ref;
1264 static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1266 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1267 HANDLE handle = This->data.u.filecoll.find;
1268 WIN32_FIND_DATAW data;
1269 ULONG count = 0;
1271 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1273 if (fetched)
1274 *fetched = 0;
1276 if (!celt) return S_OK;
1278 if (!handle)
1280 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1281 if (!handle) return S_FALSE;
1282 This->data.u.filecoll.find = handle;
1284 else if (!FindNextFileW(handle, &data))
1285 return S_FALSE;
1289 if (is_file_data(&data))
1291 IFile *file;
1292 HRESULT hr;
1293 BSTR str;
1295 str = get_full_path(This->data.u.filecoll.coll->path, &data);
1296 hr = create_file(str, &file);
1297 SysFreeString(str);
1298 if (FAILED(hr)) return hr;
1300 V_VT(&var[count]) = VT_DISPATCH;
1301 V_DISPATCH(&var[count]) = (IDispatch*)file;
1302 if (++count >= celt) break;
1304 } while (FindNextFileW(handle, &data));
1306 if (fetched)
1307 *fetched = count;
1309 return (count < celt) ? S_FALSE : S_OK;
1312 static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1314 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1315 HANDLE handle = This->data.u.filecoll.find;
1316 WIN32_FIND_DATAW data;
1318 TRACE("(%p)->(%d)\n", This, celt);
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))
1334 --celt;
1335 } while (celt && FindNextFileW(handle, &data));
1337 return celt ? S_FALSE : S_OK;
1340 static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface)
1342 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1344 TRACE("(%p)\n", This);
1346 FindClose(This->data.u.filecoll.find);
1347 This->data.u.filecoll.find = NULL;
1349 return S_OK;
1352 static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1354 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1355 TRACE("(%p)->(%p)\n", This, pclone);
1356 return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
1359 static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
1360 enumvariant_QueryInterface,
1361 enumvariant_AddRef,
1362 filecoll_enumvariant_Release,
1363 filecoll_enumvariant_Next,
1364 filecoll_enumvariant_Skip,
1365 filecoll_enumvariant_Reset,
1366 filecoll_enumvariant_Clone
1369 static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum)
1371 struct enumvariant *This;
1373 *newenum = NULL;
1375 This = heap_alloc(sizeof(*This));
1376 if (!This) return E_OUTOFMEMORY;
1378 This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
1379 This->ref = 1;
1380 This->data.u.filecoll.find = NULL;
1381 This->data.u.filecoll.coll = collection;
1382 IFileCollection_AddRef(&collection->IFileCollection_iface);
1384 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1386 return S_OK;
1389 static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface)
1391 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1392 ULONG ref = InterlockedDecrement(&This->ref);
1394 TRACE("(%p)->(%d)\n", This, ref);
1396 if (!ref)
1398 IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
1399 heap_free(This);
1402 return ref;
1405 static HRESULT find_next_drive(struct enumvariant *penum)
1407 int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
1409 for (; i < 32; i++)
1410 if (penum->data.u.drivecoll.coll->drives & (1 << i))
1412 penum->data.u.drivecoll.cur = i;
1413 return S_OK;
1416 return S_FALSE;
1419 static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1421 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1422 ULONG count = 0;
1424 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1426 if (fetched)
1427 *fetched = 0;
1429 if (!celt) return S_OK;
1431 while (find_next_drive(This) == S_OK)
1433 IDrive *drive;
1434 HRESULT hr;
1436 hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
1437 if (FAILED(hr)) return hr;
1439 V_VT(&var[count]) = VT_DISPATCH;
1440 V_DISPATCH(&var[count]) = (IDispatch*)drive;
1442 if (++count >= celt) break;
1445 if (fetched)
1446 *fetched = count;
1448 return (count < celt) ? S_FALSE : S_OK;
1451 static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1453 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1455 TRACE("(%p)->(%d)\n", This, celt);
1457 if (!celt) return S_OK;
1459 while (celt && find_next_drive(This) == S_OK)
1460 celt--;
1462 return celt ? S_FALSE : S_OK;
1465 static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface)
1467 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1469 TRACE("(%p)\n", This);
1471 This->data.u.drivecoll.cur = -1;
1472 return S_OK;
1475 static HRESULT WINAPI drivecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1477 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1478 FIXME("(%p)->(%p): stub\n", This, pclone);
1479 return E_NOTIMPL;
1482 static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
1483 enumvariant_QueryInterface,
1484 enumvariant_AddRef,
1485 drivecoll_enumvariant_Release,
1486 drivecoll_enumvariant_Next,
1487 drivecoll_enumvariant_Skip,
1488 drivecoll_enumvariant_Reset,
1489 drivecoll_enumvariant_Clone
1492 static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum)
1494 struct enumvariant *This;
1496 *newenum = NULL;
1498 This = heap_alloc(sizeof(*This));
1499 if (!This) return E_OUTOFMEMORY;
1501 This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
1502 This->ref = 1;
1503 This->data.u.drivecoll.coll = collection;
1504 This->data.u.drivecoll.cur = -1;
1505 IDriveCollection_AddRef(&collection->IDriveCollection_iface);
1507 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1509 return S_OK;
1512 static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
1514 struct foldercollection *This = impl_from_IFolderCollection(iface);
1516 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1518 *obj = NULL;
1520 if (IsEqualIID( riid, &IID_IFolderCollection ) ||
1521 IsEqualIID( riid, &IID_IDispatch ) ||
1522 IsEqualIID( riid, &IID_IUnknown ))
1524 *obj = iface;
1525 IFolderCollection_AddRef(iface);
1527 else
1528 return E_NOINTERFACE;
1530 return S_OK;
1533 static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
1535 struct foldercollection *This = impl_from_IFolderCollection(iface);
1536 ULONG ref = InterlockedIncrement(&This->ref);
1537 TRACE("(%p)->(%d)\n", This, ref);
1538 return ref;
1541 static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
1543 struct foldercollection *This = impl_from_IFolderCollection(iface);
1544 ULONG ref = InterlockedDecrement(&This->ref);
1545 TRACE("(%p)->(%d)\n", This, ref);
1547 if (!ref)
1549 SysFreeString(This->path);
1550 heap_free(This);
1553 return ref;
1556 static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
1558 struct foldercollection *This = impl_from_IFolderCollection(iface);
1559 TRACE("(%p)->(%p)\n", This, pctinfo);
1560 *pctinfo = 1;
1561 return S_OK;
1564 static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
1565 LCID lcid, ITypeInfo **ppTInfo)
1567 struct foldercollection *This = impl_from_IFolderCollection(iface);
1568 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1569 return get_typeinfo(IFolderCollection_tid, ppTInfo);
1572 static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
1573 LPOLESTR *rgszNames, UINT cNames,
1574 LCID lcid, DISPID *rgDispId)
1576 struct foldercollection *This = impl_from_IFolderCollection(iface);
1577 ITypeInfo *typeinfo;
1578 HRESULT hr;
1580 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1582 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1583 if(SUCCEEDED(hr))
1585 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1586 ITypeInfo_Release(typeinfo);
1589 return hr;
1592 static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
1593 REFIID riid, LCID lcid, WORD wFlags,
1594 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1595 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1597 struct foldercollection *This = impl_from_IFolderCollection(iface);
1598 ITypeInfo *typeinfo;
1599 HRESULT hr;
1601 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1602 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1604 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1605 if(SUCCEEDED(hr))
1607 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1608 pDispParams, pVarResult, pExcepInfo, puArgErr);
1609 ITypeInfo_Release(typeinfo);
1612 return hr;
1615 static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
1617 struct foldercollection *This = impl_from_IFolderCollection(iface);
1618 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
1619 return E_NOTIMPL;
1622 static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
1624 struct foldercollection *This = impl_from_IFolderCollection(iface);
1625 FIXME("(%p)->(%p): stub\n", This, folder);
1626 return E_NOTIMPL;
1629 static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
1631 struct foldercollection *This = impl_from_IFolderCollection(iface);
1633 TRACE("(%p)->(%p)\n", This, newenum);
1635 if(!newenum)
1636 return E_POINTER;
1638 return create_foldercoll_enum(This, newenum);
1641 static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
1643 struct foldercollection *This = impl_from_IFolderCollection(iface);
1644 static const WCHAR allW[] = {'\\','*',0};
1645 WIN32_FIND_DATAW data;
1646 WCHAR pathW[MAX_PATH];
1647 HANDLE handle;
1649 TRACE("(%p)->(%p)\n", This, count);
1651 if(!count)
1652 return E_POINTER;
1654 *count = 0;
1656 strcpyW(pathW, This->path);
1657 strcatW(pathW, allW);
1658 handle = FindFirstFileW(pathW, &data);
1659 if (handle == INVALID_HANDLE_VALUE)
1660 return HRESULT_FROM_WIN32(GetLastError());
1664 if (is_dir_data(&data))
1665 *count += 1;
1666 } while (FindNextFileW(handle, &data));
1667 FindClose(handle);
1669 return S_OK;
1672 static const IFolderCollectionVtbl foldercollvtbl = {
1673 foldercoll_QueryInterface,
1674 foldercoll_AddRef,
1675 foldercoll_Release,
1676 foldercoll_GetTypeInfoCount,
1677 foldercoll_GetTypeInfo,
1678 foldercoll_GetIDsOfNames,
1679 foldercoll_Invoke,
1680 foldercoll_Add,
1681 foldercoll_get_Item,
1682 foldercoll_get__NewEnum,
1683 foldercoll_get_Count
1686 static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
1688 struct foldercollection *This;
1690 *folders = NULL;
1692 This = heap_alloc(sizeof(struct foldercollection));
1693 if (!This) return E_OUTOFMEMORY;
1695 This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
1696 This->ref = 1;
1697 This->path = SysAllocString(path);
1698 if (!This->path)
1700 heap_free(This);
1701 return E_OUTOFMEMORY;
1704 *folders = &This->IFolderCollection_iface;
1706 return S_OK;
1709 static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj)
1711 struct filecollection *This = impl_from_IFileCollection(iface);
1713 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1715 *obj = NULL;
1717 if (IsEqualIID( riid, &IID_IFileCollection ) ||
1718 IsEqualIID( riid, &IID_IDispatch ) ||
1719 IsEqualIID( riid, &IID_IUnknown ))
1721 *obj = iface;
1722 IFileCollection_AddRef(iface);
1724 else
1725 return E_NOINTERFACE;
1727 return S_OK;
1730 static ULONG WINAPI filecoll_AddRef(IFileCollection *iface)
1732 struct filecollection *This = impl_from_IFileCollection(iface);
1733 ULONG ref = InterlockedIncrement(&This->ref);
1734 TRACE("(%p)->(%d)\n", This, ref);
1735 return ref;
1738 static ULONG WINAPI filecoll_Release(IFileCollection *iface)
1740 struct filecollection *This = impl_from_IFileCollection(iface);
1741 ULONG ref = InterlockedDecrement(&This->ref);
1742 TRACE("(%p)->(%d)\n", This, ref);
1744 if (!ref)
1746 SysFreeString(This->path);
1747 heap_free(This);
1750 return ref;
1753 static HRESULT WINAPI filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo)
1755 struct filecollection *This = impl_from_IFileCollection(iface);
1756 TRACE("(%p)->(%p)\n", This, pctinfo);
1757 *pctinfo = 1;
1758 return S_OK;
1761 static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo,
1762 LCID lcid, ITypeInfo **ppTInfo)
1764 struct filecollection *This = impl_from_IFileCollection(iface);
1765 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1766 return get_typeinfo(IFileCollection_tid, ppTInfo);
1769 static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid,
1770 LPOLESTR *rgszNames, UINT cNames,
1771 LCID lcid, DISPID *rgDispId)
1773 struct filecollection *This = impl_from_IFileCollection(iface);
1774 ITypeInfo *typeinfo;
1775 HRESULT hr;
1777 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1779 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1780 if(SUCCEEDED(hr))
1782 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1783 ITypeInfo_Release(typeinfo);
1786 return hr;
1789 static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember,
1790 REFIID riid, LCID lcid, WORD wFlags,
1791 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1792 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1794 struct filecollection *This = impl_from_IFileCollection(iface);
1795 ITypeInfo *typeinfo;
1796 HRESULT hr;
1798 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1799 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1801 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1802 if(SUCCEEDED(hr))
1804 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1805 pDispParams, pVarResult, pExcepInfo, puArgErr);
1806 ITypeInfo_Release(typeinfo);
1809 return hr;
1812 static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file)
1814 struct filecollection *This = impl_from_IFileCollection(iface);
1815 FIXME("(%p)->(%p)\n", This, file);
1816 return E_NOTIMPL;
1819 static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum)
1821 struct filecollection *This = impl_from_IFileCollection(iface);
1823 TRACE("(%p)->(%p)\n", This, ppenum);
1825 if(!ppenum)
1826 return E_POINTER;
1828 return create_filecoll_enum(This, ppenum);
1831 static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count)
1833 struct filecollection *This = impl_from_IFileCollection(iface);
1834 static const WCHAR allW[] = {'\\','*',0};
1835 WIN32_FIND_DATAW data;
1836 WCHAR pathW[MAX_PATH];
1837 HANDLE handle;
1839 TRACE("(%p)->(%p)\n", This, count);
1841 if(!count)
1842 return E_POINTER;
1844 *count = 0;
1846 strcpyW(pathW, This->path);
1847 strcatW(pathW, allW);
1848 handle = FindFirstFileW(pathW, &data);
1849 if (handle == INVALID_HANDLE_VALUE)
1850 return HRESULT_FROM_WIN32(GetLastError());
1854 if (is_file_data(&data))
1855 *count += 1;
1856 } while (FindNextFileW(handle, &data));
1857 FindClose(handle);
1859 return S_OK;
1862 static const IFileCollectionVtbl filecollectionvtbl = {
1863 filecoll_QueryInterface,
1864 filecoll_AddRef,
1865 filecoll_Release,
1866 filecoll_GetTypeInfoCount,
1867 filecoll_GetTypeInfo,
1868 filecoll_GetIDsOfNames,
1869 filecoll_Invoke,
1870 filecoll_get_Item,
1871 filecoll_get__NewEnum,
1872 filecoll_get_Count
1875 static HRESULT create_filecoll(BSTR path, IFileCollection **files)
1877 struct filecollection *This;
1879 *files = NULL;
1881 This = heap_alloc(sizeof(*This));
1882 if (!This) return E_OUTOFMEMORY;
1884 This->IFileCollection_iface.lpVtbl = &filecollectionvtbl;
1885 This->ref = 1;
1886 This->path = SysAllocString(path);
1887 if (!This->path)
1889 heap_free(This);
1890 return E_OUTOFMEMORY;
1893 *files = &This->IFileCollection_iface;
1894 return S_OK;
1897 static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
1899 struct drivecollection *This = impl_from_IDriveCollection(iface);
1901 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1903 *obj = NULL;
1905 if (IsEqualIID( riid, &IID_IDriveCollection ) ||
1906 IsEqualIID( riid, &IID_IDispatch ) ||
1907 IsEqualIID( riid, &IID_IUnknown ))
1909 *obj = iface;
1910 IDriveCollection_AddRef(iface);
1912 else
1913 return E_NOINTERFACE;
1915 return S_OK;
1918 static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
1920 struct drivecollection *This = impl_from_IDriveCollection(iface);
1921 ULONG ref = InterlockedIncrement(&This->ref);
1922 TRACE("(%p)->(%d)\n", This, ref);
1923 return ref;
1926 static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
1928 struct drivecollection *This = impl_from_IDriveCollection(iface);
1929 ULONG ref = InterlockedDecrement(&This->ref);
1930 TRACE("(%p)->(%d)\n", This, ref);
1932 if (!ref)
1933 heap_free(This);
1935 return ref;
1938 static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
1940 struct drivecollection *This = impl_from_IDriveCollection(iface);
1941 TRACE("(%p)->(%p)\n", This, pctinfo);
1942 *pctinfo = 1;
1943 return S_OK;
1946 static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
1947 LCID lcid, ITypeInfo **ppTInfo)
1949 struct drivecollection *This = impl_from_IDriveCollection(iface);
1950 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1951 return get_typeinfo(IDriveCollection_tid, ppTInfo);
1954 static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
1955 LPOLESTR *rgszNames, UINT cNames,
1956 LCID lcid, DISPID *rgDispId)
1958 struct drivecollection *This = impl_from_IDriveCollection(iface);
1959 ITypeInfo *typeinfo;
1960 HRESULT hr;
1962 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1964 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
1965 if(SUCCEEDED(hr))
1967 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1968 ITypeInfo_Release(typeinfo);
1971 return hr;
1974 static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
1975 REFIID riid, LCID lcid, WORD wFlags,
1976 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1977 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1979 struct drivecollection *This = impl_from_IDriveCollection(iface);
1980 ITypeInfo *typeinfo;
1981 HRESULT hr;
1983 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1984 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1986 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
1987 if(SUCCEEDED(hr))
1989 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1990 pDispParams, pVarResult, pExcepInfo, puArgErr);
1991 ITypeInfo_Release(typeinfo);
1994 return hr;
1997 static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
1999 struct drivecollection *This = impl_from_IDriveCollection(iface);
2000 FIXME("(%p)->(%p): stub\n", This, drive);
2001 return E_NOTIMPL;
2004 static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
2006 struct drivecollection *This = impl_from_IDriveCollection(iface);
2008 TRACE("(%p)->(%p)\n", This, ppenum);
2010 if(!ppenum)
2011 return E_POINTER;
2013 return create_drivecoll_enum(This, ppenum);
2016 static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
2018 struct drivecollection *This = impl_from_IDriveCollection(iface);
2020 TRACE("(%p)->(%p)\n", This, count);
2022 if (!count) return E_POINTER;
2024 *count = This->count;
2025 return S_OK;
2028 static const IDriveCollectionVtbl drivecollectionvtbl = {
2029 drivecoll_QueryInterface,
2030 drivecoll_AddRef,
2031 drivecoll_Release,
2032 drivecoll_GetTypeInfoCount,
2033 drivecoll_GetTypeInfo,
2034 drivecoll_GetIDsOfNames,
2035 drivecoll_Invoke,
2036 drivecoll_get_Item,
2037 drivecoll_get__NewEnum,
2038 drivecoll_get_Count
2041 static HRESULT create_drivecoll(IDriveCollection **drives)
2043 struct drivecollection *This;
2044 DWORD mask;
2046 *drives = NULL;
2048 This = heap_alloc(sizeof(*This));
2049 if (!This) return E_OUTOFMEMORY;
2051 This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl;
2052 This->ref = 1;
2053 This->drives = mask = GetLogicalDrives();
2054 /* count set bits */
2055 for (This->count = 0; mask; This->count++)
2056 mask &= mask - 1;
2058 *drives = &This->IDriveCollection_iface;
2059 return S_OK;
2062 static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
2064 struct folder *This = impl_from_IFolder(iface);
2066 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2068 *obj = NULL;
2070 if (IsEqualIID( riid, &IID_IFolder ) ||
2071 IsEqualIID( riid, &IID_IDispatch ) ||
2072 IsEqualIID( riid, &IID_IUnknown))
2074 *obj = iface;
2075 IFolder_AddRef(iface);
2077 else
2078 return E_NOINTERFACE;
2080 return S_OK;
2083 static ULONG WINAPI folder_AddRef(IFolder *iface)
2085 struct folder *This = impl_from_IFolder(iface);
2086 ULONG ref = InterlockedIncrement(&This->ref);
2087 TRACE("(%p)->(%d)\n", This, ref);
2088 return ref;
2091 static ULONG WINAPI folder_Release(IFolder *iface)
2093 struct folder *This = impl_from_IFolder(iface);
2094 ULONG ref = InterlockedDecrement(&This->ref);
2095 TRACE("(%p)->(%d)\n", This, ref);
2097 if (!ref)
2099 SysFreeString(This->path);
2100 heap_free(This);
2103 return ref;
2106 static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
2108 struct folder *This = impl_from_IFolder(iface);
2109 TRACE("(%p)->(%p)\n", This, pctinfo);
2110 *pctinfo = 1;
2111 return S_OK;
2114 static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
2115 LCID lcid, ITypeInfo **ppTInfo)
2117 struct folder *This = impl_from_IFolder(iface);
2118 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2119 return get_typeinfo(IFolder_tid, ppTInfo);
2122 static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
2123 LPOLESTR *rgszNames, UINT cNames,
2124 LCID lcid, DISPID *rgDispId)
2126 struct folder *This = impl_from_IFolder(iface);
2127 ITypeInfo *typeinfo;
2128 HRESULT hr;
2130 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2132 hr = get_typeinfo(IFolder_tid, &typeinfo);
2133 if(SUCCEEDED(hr))
2135 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2136 ITypeInfo_Release(typeinfo);
2139 return hr;
2142 static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
2143 REFIID riid, LCID lcid, WORD wFlags,
2144 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2145 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2147 struct folder *This = impl_from_IFolder(iface);
2148 ITypeInfo *typeinfo;
2149 HRESULT hr;
2151 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2152 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2154 hr = get_typeinfo(IFolder_tid, &typeinfo);
2155 if(SUCCEEDED(hr))
2157 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2158 pDispParams, pVarResult, pExcepInfo, puArgErr);
2159 ITypeInfo_Release(typeinfo);
2162 return hr;
2165 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
2167 struct folder *This = impl_from_IFolder(iface);
2169 TRACE("(%p)->(%p)\n", This, path);
2171 if(!path)
2172 return E_POINTER;
2174 *path = SysAllocString(This->path);
2175 return *path ? S_OK : E_OUTOFMEMORY;
2178 static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
2180 struct folder *This = impl_from_IFolder(iface);
2181 WCHAR *ptr;
2183 TRACE("(%p)->(%p)\n", This, name);
2185 if(!name)
2186 return E_POINTER;
2188 *name = NULL;
2190 ptr = strrchrW(This->path, '\\');
2191 if (ptr)
2193 *name = SysAllocString(ptr+1);
2194 TRACE("%s\n", debugstr_w(*name));
2195 if (!*name) return E_OUTOFMEMORY;
2197 else
2198 return E_FAIL;
2200 return S_OK;
2203 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
2205 struct folder *This = impl_from_IFolder(iface);
2206 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
2207 return E_NOTIMPL;
2210 static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
2212 struct folder *This = impl_from_IFolder(iface);
2213 FIXME("(%p)->(%p): stub\n", This, path);
2214 return E_NOTIMPL;
2217 static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
2219 struct folder *This = impl_from_IFolder(iface);
2220 FIXME("(%p)->(%p): stub\n", This, name);
2221 return E_NOTIMPL;
2224 static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
2226 struct folder *This = impl_from_IFolder(iface);
2227 FIXME("(%p)->(%p): stub\n", This, drive);
2228 return E_NOTIMPL;
2231 static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
2233 struct folder *This = impl_from_IFolder(iface);
2234 FIXME("(%p)->(%p): stub\n", This, parent);
2235 return E_NOTIMPL;
2238 static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
2240 struct folder *This = impl_from_IFolder(iface);
2241 FIXME("(%p)->(%p): stub\n", This, attr);
2242 return E_NOTIMPL;
2245 static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
2247 struct folder *This = impl_from_IFolder(iface);
2248 FIXME("(%p)->(0x%x): stub\n", This, attr);
2249 return E_NOTIMPL;
2252 static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
2254 struct folder *This = impl_from_IFolder(iface);
2255 FIXME("(%p)->(%p): stub\n", This, date);
2256 return E_NOTIMPL;
2259 static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
2261 struct folder *This = impl_from_IFolder(iface);
2262 FIXME("(%p)->(%p): stub\n", This, date);
2263 return E_NOTIMPL;
2266 static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
2268 struct folder *This = impl_from_IFolder(iface);
2269 FIXME("(%p)->(%p): stub\n", This, date);
2270 return E_NOTIMPL;
2273 static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
2275 struct folder *This = impl_from_IFolder(iface);
2276 FIXME("(%p)->(%p): stub\n", This, type);
2277 return E_NOTIMPL;
2280 static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
2282 struct folder *This = impl_from_IFolder(iface);
2283 FIXME("(%p)->(%x): stub\n", This, force);
2284 return E_NOTIMPL;
2287 static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
2289 struct folder *This = impl_from_IFolder(iface);
2290 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
2291 return E_NOTIMPL;
2294 static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
2296 struct folder *This = impl_from_IFolder(iface);
2297 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
2298 return E_NOTIMPL;
2301 static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
2303 struct folder *This = impl_from_IFolder(iface);
2304 FIXME("(%p)->(%p): stub\n", This, isroot);
2305 return E_NOTIMPL;
2308 static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
2310 struct folder *This = impl_from_IFolder(iface);
2311 FIXME("(%p)->(%p): stub\n", This, size);
2312 return E_NOTIMPL;
2315 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
2317 struct folder *This = impl_from_IFolder(iface);
2319 TRACE("(%p)->(%p)\n", This, folders);
2321 if(!folders)
2322 return E_POINTER;
2324 return create_foldercoll(This->path, folders);
2327 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
2329 struct folder *This = impl_from_IFolder(iface);
2331 TRACE("(%p)->(%p)\n", This, files);
2333 if(!files)
2334 return E_POINTER;
2336 return create_filecoll(This->path, files);
2339 static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
2340 VARIANT_BOOL unicode, ITextStream **stream)
2342 struct folder *This = impl_from_IFolder(iface);
2343 FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
2344 return E_NOTIMPL;
2347 static const IFolderVtbl foldervtbl = {
2348 folder_QueryInterface,
2349 folder_AddRef,
2350 folder_Release,
2351 folder_GetTypeInfoCount,
2352 folder_GetTypeInfo,
2353 folder_GetIDsOfNames,
2354 folder_Invoke,
2355 folder_get_Path,
2356 folder_get_Name,
2357 folder_put_Name,
2358 folder_get_ShortPath,
2359 folder_get_ShortName,
2360 folder_get_Drive,
2361 folder_get_ParentFolder,
2362 folder_get_Attributes,
2363 folder_put_Attributes,
2364 folder_get_DateCreated,
2365 folder_get_DateLastModified,
2366 folder_get_DateLastAccessed,
2367 folder_get_Type,
2368 folder_Delete,
2369 folder_Copy,
2370 folder_Move,
2371 folder_get_IsRootFolder,
2372 folder_get_Size,
2373 folder_get_SubFolders,
2374 folder_get_Files,
2375 folder_CreateTextFile
2378 HRESULT create_folder(const WCHAR *path, IFolder **folder)
2380 struct folder *This;
2382 *folder = NULL;
2384 TRACE("%s\n", debugstr_w(path));
2386 This = heap_alloc(sizeof(struct folder));
2387 if (!This) return E_OUTOFMEMORY;
2389 This->IFolder_iface.lpVtbl = &foldervtbl;
2390 This->ref = 1;
2391 This->path = SysAllocString(path);
2392 if (!This->path)
2394 heap_free(This);
2395 return E_OUTOFMEMORY;
2398 *folder = &This->IFolder_iface;
2400 return S_OK;
2403 static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
2405 struct file *This = impl_from_IFile(iface);
2407 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2409 if (IsEqualIID(riid, &IID_IFile) ||
2410 IsEqualIID(riid, &IID_IDispatch) ||
2411 IsEqualIID(riid, &IID_IUnknown))
2413 *obj = iface;
2414 IFile_AddRef(iface);
2415 return S_OK;
2418 *obj = NULL;
2419 return E_NOINTERFACE;
2422 static ULONG WINAPI file_AddRef(IFile *iface)
2424 struct file *This = impl_from_IFile(iface);
2425 LONG ref = InterlockedIncrement(&This->ref);
2427 TRACE("(%p) ref=%d\n", This, ref);
2429 return ref;
2432 static ULONG WINAPI file_Release(IFile *iface)
2434 struct file *This = impl_from_IFile(iface);
2435 LONG ref = InterlockedDecrement(&This->ref);
2437 TRACE("(%p) ref=%d\n", This, ref);
2439 if(!ref)
2441 heap_free(This->path);
2442 heap_free(This);
2445 return ref;
2448 static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
2450 struct file *This = impl_from_IFile(iface);
2452 TRACE("(%p)->(%p)\n", This, pctinfo);
2454 *pctinfo = 1;
2455 return S_OK;
2458 static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
2459 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
2461 struct file *This = impl_from_IFile(iface);
2463 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2465 return get_typeinfo(IFile_tid, ppTInfo);
2468 static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
2469 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2471 struct file *This = impl_from_IFile(iface);
2472 ITypeInfo *typeinfo;
2473 HRESULT hr;
2475 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
2476 rgszNames, cNames, lcid, rgDispId);
2478 hr = get_typeinfo(IFile_tid, &typeinfo);
2479 if(SUCCEEDED(hr)) {
2480 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2481 ITypeInfo_Release(typeinfo);
2483 return hr;
2486 static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2488 struct file *This = impl_from_IFile(iface);
2489 ITypeInfo *typeinfo;
2490 HRESULT hr;
2492 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2493 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2495 hr = get_typeinfo(IFile_tid, &typeinfo);
2496 if(SUCCEEDED(hr))
2498 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2499 pDispParams, pVarResult, pExcepInfo, puArgErr);
2500 ITypeInfo_Release(typeinfo);
2502 return hr;
2505 static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *pbstrPath)
2507 struct file *This = impl_from_IFile(iface);
2508 FIXME("(%p)->(%p)\n", This, pbstrPath);
2509 return E_NOTIMPL;
2512 static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
2514 struct file *This = impl_from_IFile(iface);
2515 WCHAR *ptr;
2517 TRACE("(%p)->(%p)\n", This, name);
2519 if(!name)
2520 return E_POINTER;
2522 *name = NULL;
2524 ptr = strrchrW(This->path, '\\');
2525 if (ptr)
2527 *name = SysAllocString(ptr+1);
2528 TRACE("%s\n", debugstr_w(*name));
2529 if (!*name) return E_OUTOFMEMORY;
2531 else
2532 return E_FAIL;
2534 return S_OK;
2537 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
2539 struct file *This = impl_from_IFile(iface);
2540 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
2541 return E_NOTIMPL;
2544 static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
2546 struct file *This = impl_from_IFile(iface);
2547 FIXME("(%p)->(%p)\n", This, pbstrPath);
2548 return E_NOTIMPL;
2551 static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
2553 struct file *This = impl_from_IFile(iface);
2554 FIXME("(%p)->(%p)\n", This, pbstrName);
2555 return E_NOTIMPL;
2558 static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
2560 struct file *This = impl_from_IFile(iface);
2561 FIXME("(%p)->(%p)\n", This, ppdrive);
2562 return E_NOTIMPL;
2565 static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
2567 struct file *This = impl_from_IFile(iface);
2568 FIXME("(%p)->(%p)\n", This, ppfolder);
2569 return E_NOTIMPL;
2572 static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
2574 struct file *This = impl_from_IFile(iface);
2575 DWORD fa;
2577 TRACE("(%p)->(%p)\n", This, pfa);
2579 if(!pfa)
2580 return E_POINTER;
2582 fa = GetFileAttributesW(This->path);
2583 if(fa == INVALID_FILE_ATTRIBUTES)
2584 return create_error(GetLastError());
2586 *pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2587 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
2588 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
2589 return S_OK;
2592 static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
2594 struct file *This = impl_from_IFile(iface);
2595 FIXME("(%p)->(%x)\n", This, pfa);
2596 return E_NOTIMPL;
2599 static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
2601 struct file *This = impl_from_IFile(iface);
2602 FIXME("(%p)->(%p)\n", This, pdate);
2603 return E_NOTIMPL;
2606 static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *pdate)
2608 struct file *This = impl_from_IFile(iface);
2609 FIXME("(%p)->(%p)\n", This, pdate);
2610 return E_NOTIMPL;
2613 static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
2615 struct file *This = impl_from_IFile(iface);
2616 FIXME("(%p)->(%p)\n", This, pdate);
2617 return E_NOTIMPL;
2620 static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
2622 struct file *This = impl_from_IFile(iface);
2623 WIN32_FIND_DATAW fd;
2624 HANDLE f;
2626 TRACE("(%p)->(%p)\n", This, pvarSize);
2628 if(!pvarSize)
2629 return E_POINTER;
2631 f = FindFirstFileW(This->path, &fd);
2632 if(f == INVALID_HANDLE_VALUE)
2633 return create_error(GetLastError());
2634 FindClose(f);
2636 if(fd.nFileSizeHigh || fd.nFileSizeLow>INT_MAX) {
2637 V_VT(pvarSize) = VT_R8;
2638 V_R8(pvarSize) = ((ULONGLONG)fd.nFileSizeHigh<<32) + fd.nFileSizeLow;
2639 }else {
2640 V_VT(pvarSize) = VT_I4;
2641 V_I4(pvarSize) = fd.nFileSizeLow;
2643 return S_OK;
2646 static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
2648 struct file *This = impl_from_IFile(iface);
2649 FIXME("(%p)->(%p)\n", This, pbstrType);
2650 return E_NOTIMPL;
2653 static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
2655 struct file *This = impl_from_IFile(iface);
2656 FIXME("(%p)->(%x)\n", This, Force);
2657 return E_NOTIMPL;
2660 static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
2662 struct file *This = impl_from_IFile(iface);
2663 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
2664 return E_NOTIMPL;
2667 static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
2669 struct file *This = impl_from_IFile(iface);
2670 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
2671 return E_NOTIMPL;
2674 static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode mode, Tristate format, ITextStream **stream)
2676 struct file *This = impl_from_IFile(iface);
2678 TRACE("(%p)->(%d %d %p)\n", This, mode, format, stream);
2680 if (format == TristateUseDefault) {
2681 FIXME("default format not handled, defaulting to unicode\n");
2682 format = TristateTrue;
2685 return create_textstream(This->path, OPEN_EXISTING, mode, format == TristateTrue, stream);
2688 static const IFileVtbl file_vtbl = {
2689 file_QueryInterface,
2690 file_AddRef,
2691 file_Release,
2692 file_GetTypeInfoCount,
2693 file_GetTypeInfo,
2694 file_GetIDsOfNames,
2695 file_Invoke,
2696 file_get_Path,
2697 file_get_Name,
2698 file_put_Name,
2699 file_get_ShortPath,
2700 file_get_ShortName,
2701 file_get_Drive,
2702 file_get_ParentFolder,
2703 file_get_Attributes,
2704 file_put_Attributes,
2705 file_get_DateCreated,
2706 file_get_DateLastModified,
2707 file_get_DateLastAccessed,
2708 file_get_Size,
2709 file_get_Type,
2710 file_Delete,
2711 file_Copy,
2712 file_Move,
2713 file_OpenAsTextStream
2716 static HRESULT create_file(BSTR path, IFile **file)
2718 struct file *f;
2719 DWORD len, attrs;
2721 *file = NULL;
2723 f = heap_alloc(sizeof(struct file));
2724 if(!f)
2725 return E_OUTOFMEMORY;
2727 f->IFile_iface.lpVtbl = &file_vtbl;
2728 f->ref = 1;
2730 len = GetFullPathNameW(path, 0, NULL, NULL);
2731 if(!len) {
2732 heap_free(f);
2733 return E_FAIL;
2736 f->path = heap_alloc(len*sizeof(WCHAR));
2737 if(!f->path) {
2738 heap_free(f);
2739 return E_OUTOFMEMORY;
2742 if(!GetFullPathNameW(path, len, f->path, NULL)) {
2743 heap_free(f->path);
2744 heap_free(f);
2745 return E_FAIL;
2748 attrs = GetFileAttributesW(f->path);
2749 if(attrs==INVALID_FILE_ATTRIBUTES ||
2750 (attrs&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))) {
2751 heap_free(f->path);
2752 heap_free(f);
2753 return create_error(GetLastError());
2756 *file = &f->IFile_iface;
2757 return S_OK;
2760 static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
2762 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
2764 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
2765 IsEqualGUID( riid, &IID_IFileSystem ) ||
2766 IsEqualGUID( riid, &IID_IDispatch ) ||
2767 IsEqualGUID( riid, &IID_IUnknown ) )
2769 *ppvObject = iface;
2771 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
2773 TRACE("Interface IDispatchEx not supported - returning NULL\n");
2774 *ppvObject = NULL;
2775 return E_NOINTERFACE;
2777 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
2779 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
2780 *ppvObject = NULL;
2781 return E_NOINTERFACE;
2783 else
2785 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
2786 return E_NOINTERFACE;
2789 IFileSystem3_AddRef(iface);
2791 return S_OK;
2794 static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
2796 TRACE("%p\n", iface);
2798 return 2;
2801 static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
2803 TRACE("%p\n", iface);
2805 return 1;
2808 static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
2810 TRACE("(%p)->(%p)\n", iface, pctinfo);
2812 *pctinfo = 1;
2813 return S_OK;
2816 static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
2817 LCID lcid, ITypeInfo **ppTInfo)
2819 TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
2820 return get_typeinfo(IFileSystem3_tid, ppTInfo);
2823 static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
2824 LPOLESTR *rgszNames, UINT cNames,
2825 LCID lcid, DISPID *rgDispId)
2827 ITypeInfo *typeinfo;
2828 HRESULT hr;
2830 TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2832 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2833 if(SUCCEEDED(hr))
2835 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2836 ITypeInfo_Release(typeinfo);
2839 return hr;
2842 static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
2843 REFIID riid, LCID lcid, WORD wFlags,
2844 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2845 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2847 ITypeInfo *typeinfo;
2848 HRESULT hr;
2850 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
2851 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2853 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2854 if(SUCCEEDED(hr))
2856 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2857 pDispParams, pVarResult, pExcepInfo, puArgErr);
2858 ITypeInfo_Release(typeinfo);
2861 return hr;
2864 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
2866 TRACE("%p %p\n", iface, ppdrives);
2867 return create_drivecoll(ppdrives);
2870 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
2871 BSTR Name, BSTR *Result)
2873 BSTR ret;
2875 TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
2877 if (!Result) return E_POINTER;
2879 if (Path && Name)
2881 int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
2883 /* if both parts have backslashes strip one from Path */
2884 if (Path[path_len-1] == '\\' && Name[0] == '\\')
2886 path_len -= 1;
2888 ret = SysAllocStringLen(NULL, path_len + name_len);
2889 if (ret)
2891 strcpyW(ret, Path);
2892 ret[path_len] = 0;
2893 strcatW(ret, Name);
2896 else if (Path[path_len-1] != '\\' && Name[0] != '\\')
2898 ret = SysAllocStringLen(NULL, path_len + name_len + 1);
2899 if (ret)
2901 strcpyW(ret, Path);
2902 if (Path[path_len-1] != ':')
2903 strcatW(ret, bsW);
2904 strcatW(ret, Name);
2907 else
2909 ret = SysAllocStringLen(NULL, path_len + name_len);
2910 if (ret)
2912 strcpyW(ret, Path);
2913 strcatW(ret, Name);
2917 else if (Path || Name)
2918 ret = SysAllocString(Path ? Path : Name);
2919 else
2920 ret = SysAllocStringLen(NULL, 0);
2922 if (!ret) return E_OUTOFMEMORY;
2923 *Result = ret;
2925 return S_OK;
2928 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR Path,
2929 BSTR *pbstrResult)
2931 FIXME("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2933 return E_NOTIMPL;
2936 static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
2938 int i;
2940 if(!path)
2941 return 0;
2943 for(i=len-1; i>=0; i--)
2944 if(path[i]!='/' && path[i]!='\\')
2945 break;
2947 for(; i>=0; i--)
2948 if(path[i]=='/' || path[i]=='\\')
2949 break;
2951 for(; i>=0; i--)
2952 if(path[i]!='/' && path[i]!='\\')
2953 break;
2955 if(i < 0)
2956 return 0;
2958 if(path[i]==':' && i==1)
2959 i++;
2960 return i+1;
2963 static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
2964 BSTR *pbstrResult)
2966 DWORD len;
2968 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2970 if(!pbstrResult)
2971 return E_POINTER;
2973 len = get_parent_folder_name(Path, SysStringLen(Path));
2974 if(!len) {
2975 *pbstrResult = NULL;
2976 return S_OK;
2979 *pbstrResult = SysAllocStringLen(Path, len);
2980 if(!*pbstrResult)
2981 return E_OUTOFMEMORY;
2982 return S_OK;
2985 static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
2986 BSTR *pbstrResult)
2988 int i, end;
2990 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2992 if(!pbstrResult)
2993 return E_POINTER;
2995 if(!Path) {
2996 *pbstrResult = NULL;
2997 return S_OK;
3000 for(end=strlenW(Path)-1; end>=0; end--)
3001 if(Path[end]!='/' && Path[end]!='\\')
3002 break;
3004 for(i=end; i>=0; i--)
3005 if(Path[i]=='/' || Path[i]=='\\')
3006 break;
3007 i++;
3009 if(i>end || (i==0 && end==1 && Path[1]==':')) {
3010 *pbstrResult = NULL;
3011 return S_OK;
3014 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3015 if(!*pbstrResult)
3016 return E_OUTOFMEMORY;
3017 return S_OK;
3020 static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
3021 BSTR *pbstrResult)
3023 int i, end;
3025 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3027 if(!pbstrResult)
3028 return E_POINTER;
3030 if(!Path) {
3031 *pbstrResult = NULL;
3032 return S_OK;
3035 for(end=strlenW(Path)-1; end>=0; end--)
3036 if(Path[end]!='/' && Path[end]!='\\')
3037 break;
3039 for(i=end; i>=0; i--) {
3040 if(Path[i]=='.' && Path[end+1]!='.')
3041 end = i-1;
3042 if(Path[i]=='/' || Path[i]=='\\')
3043 break;
3045 i++;
3047 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
3048 *pbstrResult = NULL;
3049 return S_OK;
3052 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3053 if(!*pbstrResult)
3054 return E_OUTOFMEMORY;
3055 return S_OK;
3058 static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR Path,
3059 BSTR *pbstrResult)
3061 FIXME("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3063 return E_NOTIMPL;
3066 static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR Path,
3067 BSTR *pbstrResult)
3069 static const WCHAR cur_path[] = {'.',0};
3071 WCHAR buf[MAX_PATH], ch;
3072 const WCHAR *path;
3073 DWORD i, beg, len, exp_len;
3074 WIN32_FIND_DATAW fdata;
3075 HANDLE fh;
3077 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3079 if(!pbstrResult)
3080 return E_POINTER;
3082 if(!Path)
3083 path = cur_path;
3084 else
3085 path = Path;
3087 len = GetFullPathNameW(path, MAX_PATH, buf, NULL);
3088 if(!len)
3089 return E_FAIL;
3091 buf[0] = toupperW(buf[0]);
3092 if(len>3 && buf[len-1] == '\\')
3093 buf[--len] = 0;
3095 for(beg=3, i=3; i<=len; i++) {
3096 if(buf[i]!='\\' && buf[i])
3097 continue;
3099 ch = buf[i];
3100 buf[i] = 0;
3101 fh = FindFirstFileW(buf, &fdata);
3102 if(fh == INVALID_HANDLE_VALUE)
3103 break;
3105 exp_len = strlenW(fdata.cFileName);
3106 if(exp_len == i-beg)
3107 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
3108 FindClose(fh);
3109 buf[i] = ch;
3110 beg = i+1;
3113 *pbstrResult = SysAllocString(buf);
3114 if(!*pbstrResult)
3115 return E_OUTOFMEMORY;
3116 return S_OK;
3119 static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
3121 static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
3123 DWORD random;
3125 TRACE("%p %p\n", iface, pbstrResult);
3127 if(!pbstrResult)
3128 return E_POINTER;
3130 *pbstrResult = SysAllocStringLen(NULL, 12);
3131 if(!*pbstrResult)
3132 return E_OUTOFMEMORY;
3134 if(!RtlGenRandom(&random, sizeof(random)))
3135 return E_FAIL;
3136 sprintfW(*pbstrResult, fmt, random & 0xfffff);
3137 return S_OK;
3140 static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
3141 VARIANT_BOOL *pfExists)
3143 FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
3145 return E_NOTIMPL;
3148 static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3150 DWORD attrs;
3151 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3153 if (!ret) return E_POINTER;
3155 attrs = GetFileAttributesW(path);
3156 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3157 return S_OK;
3160 static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3162 DWORD attrs;
3163 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3165 if (!ret) return E_POINTER;
3167 attrs = GetFileAttributesW(path);
3168 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3170 return S_OK;
3173 static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
3174 IDrive **ppdrive)
3176 FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
3178 return E_NOTIMPL;
3181 static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
3182 IFile **ppfile)
3184 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
3186 if(!ppfile)
3187 return E_POINTER;
3188 if(!FilePath)
3189 return E_INVALIDARG;
3191 return create_file(FilePath, ppfile);
3194 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
3195 IFolder **folder)
3197 DWORD attrs;
3199 TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
3201 if(!folder)
3202 return E_POINTER;
3204 *folder = NULL;
3205 if(!FolderPath)
3206 return E_INVALIDARG;
3208 attrs = GetFileAttributesW(FolderPath);
3209 if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
3210 return CTL_E_PATHNOTFOUND;
3212 return create_folder(FolderPath, folder);
3215 static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
3216 SpecialFolderConst SpecialFolder,
3217 IFolder **ppfolder)
3219 FIXME("%p %d %p\n", iface, SpecialFolder, ppfolder);
3221 return E_NOTIMPL;
3224 static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
3226 WCHAR path[MAX_PATH];
3227 DWORD len, name_len;
3228 WIN32_FIND_DATAW ffd;
3229 HANDLE f;
3231 f = FindFirstFileW(file, &ffd);
3232 if(f == INVALID_HANDLE_VALUE)
3233 return create_error(GetLastError());
3235 len = get_parent_folder_name(file, file_len);
3236 if(len+1 >= MAX_PATH) {
3237 FindClose(f);
3238 return E_FAIL;
3240 if(len) {
3241 memcpy(path, file, len*sizeof(WCHAR));
3242 path[len++] = '\\';
3245 do {
3246 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3247 continue;
3249 name_len = strlenW(ffd.cFileName);
3250 if(len+name_len+1 >= MAX_PATH) {
3251 FindClose(f);
3252 return E_FAIL;
3254 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3256 TRACE("deleting %s\n", debugstr_w(path));
3258 if(!DeleteFileW(path)) {
3259 if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
3260 || !DeleteFileW(path)) {
3261 FindClose(f);
3262 return create_error(GetLastError());
3265 } while(FindNextFileW(f, &ffd));
3266 FindClose(f);
3268 return S_OK;
3271 static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
3272 VARIANT_BOOL Force)
3274 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
3276 if(!FileSpec)
3277 return E_POINTER;
3279 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
3282 static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
3284 WCHAR path[MAX_PATH];
3285 DWORD len, name_len;
3286 WIN32_FIND_DATAW ffd;
3287 HANDLE f;
3288 HRESULT hr;
3290 f = FindFirstFileW(folder, &ffd);
3291 if(f == INVALID_HANDLE_VALUE)
3292 return create_error(GetLastError());
3294 len = get_parent_folder_name(folder, folder_len);
3295 if(len+1 >= MAX_PATH) {
3296 FindClose(f);
3297 return E_FAIL;
3299 if(len) {
3300 memcpy(path, folder, len*sizeof(WCHAR));
3301 path[len++] = '\\';
3304 do {
3305 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3306 continue;
3307 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3308 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3309 continue;
3311 name_len = strlenW(ffd.cFileName);
3312 if(len+name_len+3 >= MAX_PATH) {
3313 FindClose(f);
3314 return E_FAIL;
3316 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
3317 path[len+name_len] = '\\';
3318 path[len+name_len+1] = '*';
3319 path[len+name_len+2] = 0;
3321 hr = delete_file(path, len+name_len+2, force);
3322 if(FAILED(hr)) {
3323 FindClose(f);
3324 return hr;
3327 hr = delete_folder(path, len+name_len+2, force);
3328 if(FAILED(hr)) {
3329 FindClose(f);
3330 return hr;
3333 path[len+name_len] = 0;
3334 TRACE("deleting %s\n", debugstr_w(path));
3336 if(!RemoveDirectoryW(path)) {
3337 FindClose(f);
3338 return create_error(GetLastError());
3340 } while(FindNextFileW(f, &ffd));
3341 FindClose(f);
3343 return S_OK;
3346 static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
3347 VARIANT_BOOL Force)
3349 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
3351 if(!FolderSpec)
3352 return E_POINTER;
3354 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
3357 static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR Source,
3358 BSTR Destination)
3360 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3362 return E_NOTIMPL;
3365 static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
3366 BSTR Destination)
3368 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3370 return E_NOTIMPL;
3373 static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
3374 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
3376 DWORD attrs;
3377 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
3378 DWORD src_len, dst_len, name_len;
3379 WIN32_FIND_DATAW ffd;
3380 HANDLE f;
3381 HRESULT hr;
3383 if(!source[0] || !destination[0])
3384 return E_INVALIDARG;
3386 attrs = GetFileAttributesW(destination);
3387 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
3388 attrs = GetFileAttributesW(source);
3389 if(attrs == INVALID_FILE_ATTRIBUTES)
3390 return create_error(GetLastError());
3391 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
3392 return CTL_E_FILENOTFOUND;
3394 if(!CopyFileW(source, destination, !overwrite))
3395 return create_error(GetLastError());
3396 return S_OK;
3399 f = FindFirstFileW(source, &ffd);
3400 if(f == INVALID_HANDLE_VALUE)
3401 return CTL_E_FILENOTFOUND;
3403 src_len = get_parent_folder_name(source, source_len);
3404 if(src_len+1 >= MAX_PATH) {
3405 FindClose(f);
3406 return E_FAIL;
3408 if(src_len) {
3409 memcpy(src_path, source, src_len*sizeof(WCHAR));
3410 src_path[src_len++] = '\\';
3413 dst_len = destination_len;
3414 if(dst_len+1 >= MAX_PATH) {
3415 FindClose(f);
3416 return E_FAIL;
3418 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
3419 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
3420 dst_path[dst_len++] = '\\';
3422 hr = CTL_E_FILENOTFOUND;
3423 do {
3424 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3425 continue;
3427 name_len = strlenW(ffd.cFileName);
3428 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
3429 FindClose(f);
3430 return E_FAIL;
3432 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3433 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3435 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
3437 if(!CopyFileW(src_path, dst_path, !overwrite)) {
3438 FindClose(f);
3439 return create_error(GetLastError());
3440 }else {
3441 hr = S_OK;
3443 } while(FindNextFileW(f, &ffd));
3444 FindClose(f);
3446 return hr;
3449 static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
3450 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3452 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3454 if(!Source || !Destination)
3455 return E_POINTER;
3457 return copy_file(Source, SysStringLen(Source), Destination,
3458 SysStringLen(Destination), OverWriteFiles);
3461 static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
3462 DWORD destination_len, VARIANT_BOOL overwrite)
3464 DWORD tmp, src_len, dst_len, name_len;
3465 WCHAR src[MAX_PATH], dst[MAX_PATH];
3466 WIN32_FIND_DATAW ffd;
3467 HANDLE f;
3468 HRESULT hr;
3469 BOOL copied = FALSE;
3471 if(!source[0] || !destination[0])
3472 return E_INVALIDARG;
3474 dst_len = destination_len;
3475 if(dst_len+1 >= MAX_PATH)
3476 return E_FAIL;
3477 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
3479 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
3480 (tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
3481 tmp&FILE_ATTRIBUTE_DIRECTORY) {
3482 if(!CreateDirectoryW(dst, NULL)) {
3483 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3484 tmp = GetFileAttributesW(dst);
3485 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
3486 return CTL_E_FILEALREADYEXISTS;
3487 }else {
3488 return create_error(GetLastError());
3491 copied = TRUE;
3493 src_len = source_len;
3494 if(src_len+2 >= MAX_PATH)
3495 return E_FAIL;
3496 memcpy(src, source, src_len*sizeof(WCHAR));
3497 src[src_len++] = '\\';
3498 src[src_len] = '*';
3499 src[src_len+1] = 0;
3501 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
3502 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
3503 return create_error(GetLastError());
3505 f = FindFirstFileW(src, &ffd);
3506 }else {
3507 src_len = get_parent_folder_name(source, source_len);
3508 if(src_len+2 >= MAX_PATH)
3509 return E_FAIL;
3510 memcpy(src, source, src_len*sizeof(WCHAR));
3511 if(src_len)
3512 src[src_len++] = '\\';
3514 f = FindFirstFileW(source, &ffd);
3516 if(f == INVALID_HANDLE_VALUE)
3517 return CTL_E_PATHNOTFOUND;
3519 dst[dst_len++] = '\\';
3520 dst[dst_len] = 0;
3522 do {
3523 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3524 continue;
3525 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3526 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3527 continue;
3529 name_len = strlenW(ffd.cFileName);
3530 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
3531 FindClose(f);
3532 return E_FAIL;
3534 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
3535 dst[dst_len+name_len] = 0;
3536 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
3537 src[src_len+name_len] = '\\';
3538 src[src_len+name_len+1] = '*';
3539 src[src_len+name_len+2] = 0;
3541 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
3543 if(!CreateDirectoryW(dst, NULL)) {
3544 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3545 tmp = GetFileAttributesW(dst);
3546 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
3547 FindClose(f);
3548 return CTL_E_FILEALREADYEXISTS;
3552 FindClose(f);
3553 return create_error(GetLastError());
3555 copied = TRUE;
3557 hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3558 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
3559 FindClose(f);
3560 return hr;
3563 hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3564 if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
3565 FindClose(f);
3566 return hr;
3568 } while(FindNextFileW(f, &ffd));
3569 FindClose(f);
3571 return copied ? S_OK : CTL_E_PATHNOTFOUND;
3574 static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
3575 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3577 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3579 if(!Source || !Destination)
3580 return E_POINTER;
3582 return copy_folder(Source, SysStringLen(Source), Destination,
3583 SysStringLen(Destination), OverWriteFiles);
3586 static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
3587 IFolder **folder)
3589 BOOL ret;
3591 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
3593 ret = CreateDirectoryW(path, NULL);
3594 if (!ret)
3596 *folder = NULL;
3597 if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
3598 return HRESULT_FROM_WIN32(GetLastError());
3601 return create_folder(path, folder);
3604 static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR filename,
3605 VARIANT_BOOL overwrite, VARIANT_BOOL unicode,
3606 ITextStream **stream)
3608 DWORD disposition;
3610 TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
3612 disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
3613 return create_textstream(filename, disposition, ForWriting, !!unicode, stream);
3616 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
3617 IOMode mode, VARIANT_BOOL create,
3618 Tristate format, ITextStream **stream)
3620 DWORD disposition;
3622 TRACE("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
3623 disposition = create == VARIANT_TRUE ? OPEN_ALWAYS : OPEN_EXISTING;
3625 if (format == TristateUseDefault) {
3626 FIXME("default format not handled, defaulting to unicode\n");
3627 format = TristateTrue;
3630 return create_textstream(filename, disposition, mode, format == TristateTrue, stream);
3633 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
3634 StandardStreamTypes StandardStreamType,
3635 VARIANT_BOOL Unicode,
3636 ITextStream **ppts)
3638 FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
3640 return E_NOTIMPL;
3643 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
3645 static const WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
3646 DWORDLONG version;
3647 WORD a, b, c, d;
3649 version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
3650 a = (WORD)( version >> 48);
3651 b = (WORD)((version >> 32) & 0xffff);
3652 c = (WORD)((version >> 16) & 0xffff);
3653 d = (WORD)( version & 0xffff);
3655 sprintfW(ver, fmtW, a, b, c, d);
3658 static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
3660 static const WCHAR rootW[] = {'\\',0};
3661 VS_FIXEDFILEINFO *info;
3662 WCHAR ver[30];
3663 void *ptr;
3664 DWORD len;
3665 BOOL ret;
3667 TRACE("%p %s %p\n", iface, debugstr_w(name), version);
3669 len = GetFileVersionInfoSizeW(name, NULL);
3670 if (!len)
3671 return HRESULT_FROM_WIN32(GetLastError());
3673 ptr = heap_alloc(len);
3674 if (!GetFileVersionInfoW(name, 0, len, ptr))
3676 heap_free(ptr);
3677 return HRESULT_FROM_WIN32(GetLastError());
3680 ret = VerQueryValueW(ptr, rootW, (void**)&info, &len);
3681 if (!ret)
3683 heap_free(ptr);
3684 return HRESULT_FROM_WIN32(GetLastError());
3687 get_versionstring(info, ver);
3688 heap_free(ptr);
3690 *version = SysAllocString(ver);
3691 TRACE("version=%s\n", debugstr_w(ver));
3693 return S_OK;
3696 static const struct IFileSystem3Vtbl filesys_vtbl =
3698 filesys_QueryInterface,
3699 filesys_AddRef,
3700 filesys_Release,
3701 filesys_GetTypeInfoCount,
3702 filesys_GetTypeInfo,
3703 filesys_GetIDsOfNames,
3704 filesys_Invoke,
3705 filesys_get_Drives,
3706 filesys_BuildPath,
3707 filesys_GetDriveName,
3708 filesys_GetParentFolderName,
3709 filesys_GetFileName,
3710 filesys_GetBaseName,
3711 filesys_GetExtensionName,
3712 filesys_GetAbsolutePathName,
3713 filesys_GetTempName,
3714 filesys_DriveExists,
3715 filesys_FileExists,
3716 filesys_FolderExists,
3717 filesys_GetDrive,
3718 filesys_GetFile,
3719 filesys_GetFolder,
3720 filesys_GetSpecialFolder,
3721 filesys_DeleteFile,
3722 filesys_DeleteFolder,
3723 filesys_MoveFile,
3724 filesys_MoveFolder,
3725 filesys_CopyFile,
3726 filesys_CopyFolder,
3727 filesys_CreateFolder,
3728 filesys_CreateTextFile,
3729 filesys_OpenTextFile,
3730 filesys_GetStandardStream,
3731 filesys_GetFileVersion
3734 static IFileSystem3 filesystem = { &filesys_vtbl };
3736 HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
3738 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
3740 return IFileSystem3_QueryInterface(&filesystem, riid, ppv);