user32/tests: Test DDE end to end with Chinese text that starts with Latin characters.
[wine.git] / dlls / scrrun / filesystem.c
blob818079ef14f87b543f4fdb4c064c12f05212069d
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 HRESULT hr = S_OK;
638 TRACE("(%p)\n", This);
640 if(!CloseHandle(This->file))
641 hr = S_FALSE;
643 This->file = NULL;
645 return hr;
648 static const ITextStreamVtbl textstreamvtbl = {
649 textstream_QueryInterface,
650 textstream_AddRef,
651 textstream_Release,
652 textstream_GetTypeInfoCount,
653 textstream_GetTypeInfo,
654 textstream_GetIDsOfNames,
655 textstream_Invoke,
656 textstream_get_Line,
657 textstream_get_Column,
658 textstream_get_AtEndOfStream,
659 textstream_get_AtEndOfLine,
660 textstream_Read,
661 textstream_ReadLine,
662 textstream_ReadAll,
663 textstream_Write,
664 textstream_WriteLine,
665 textstream_WriteBlankLines,
666 textstream_Skip,
667 textstream_SkipLine,
668 textstream_Close
671 static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMode mode, BOOL unicode, ITextStream **ret)
673 struct textstream *stream;
674 DWORD access = 0;
676 /* map access mode */
677 switch (mode)
679 case ForReading:
680 access = GENERIC_READ;
681 break;
682 case ForWriting:
683 access = GENERIC_WRITE;
684 break;
685 case ForAppending:
686 access = FILE_APPEND_DATA;
687 break;
688 default:
689 return E_INVALIDARG;
692 stream = heap_alloc(sizeof(struct textstream));
693 if (!stream) return E_OUTOFMEMORY;
695 stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
696 stream->ref = 1;
697 stream->mode = mode;
698 stream->unicode = unicode;
699 stream->first_read = TRUE;
701 stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
702 if (stream->file == INVALID_HANDLE_VALUE)
704 HRESULT hr = create_error(GetLastError());
705 heap_free(stream);
706 return hr;
709 if (mode == ForReading)
710 GetFileSizeEx(stream->file, &stream->size);
711 else
712 stream->size.QuadPart = 0;
714 /* Write Unicode BOM */
715 if (unicode && mode == ForWriting && (disposition == CREATE_ALWAYS || disposition == CREATE_NEW)) {
716 DWORD written = 0;
717 BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL);
718 if (!ret || written != sizeof(utf16bom)) {
719 ITextStream_Release(&stream->ITextStream_iface);
720 return create_error(GetLastError());
724 *ret = &stream->ITextStream_iface;
725 return S_OK;
728 static HRESULT WINAPI drive_QueryInterface(IDrive *iface, REFIID riid, void **obj)
730 struct drive *This = impl_from_IDrive(iface);
732 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
734 *obj = NULL;
736 if (IsEqualIID( riid, &IID_IDrive ) ||
737 IsEqualIID( riid, &IID_IDispatch ) ||
738 IsEqualIID( riid, &IID_IUnknown))
740 *obj = iface;
741 IDrive_AddRef(iface);
743 else
744 return E_NOINTERFACE;
746 return S_OK;
749 static ULONG WINAPI drive_AddRef(IDrive *iface)
751 struct drive *This = impl_from_IDrive(iface);
752 ULONG ref = InterlockedIncrement(&This->ref);
753 TRACE("(%p)->(%d)\n", This, ref);
754 return ref;
757 static ULONG WINAPI drive_Release(IDrive *iface)
759 struct drive *This = impl_from_IDrive(iface);
760 ULONG ref = InterlockedDecrement(&This->ref);
761 TRACE("(%p)->(%d)\n", This, ref);
763 if (!ref)
765 SysFreeString(This->root);
766 heap_free(This);
769 return ref;
772 static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo)
774 struct drive *This = impl_from_IDrive(iface);
775 TRACE("(%p)->(%p)\n", This, pctinfo);
776 *pctinfo = 1;
777 return S_OK;
780 static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo,
781 LCID lcid, ITypeInfo **ppTInfo)
783 struct drive *This = impl_from_IDrive(iface);
784 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
785 return get_typeinfo(IDrive_tid, ppTInfo);
788 static HRESULT WINAPI drive_GetIDsOfNames(IDrive *iface, REFIID riid,
789 LPOLESTR *rgszNames, UINT cNames,
790 LCID lcid, DISPID *rgDispId)
792 struct drive *This = impl_from_IDrive(iface);
793 ITypeInfo *typeinfo;
794 HRESULT hr;
796 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
798 hr = get_typeinfo(IDrive_tid, &typeinfo);
799 if(SUCCEEDED(hr))
801 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
802 ITypeInfo_Release(typeinfo);
805 return hr;
808 static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember,
809 REFIID riid, LCID lcid, WORD wFlags,
810 DISPPARAMS *pDispParams, VARIANT *pVarResult,
811 EXCEPINFO *pExcepInfo, UINT *puArgErr)
813 struct drive *This = impl_from_IDrive(iface);
814 ITypeInfo *typeinfo;
815 HRESULT hr;
817 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
818 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
820 hr = get_typeinfo(IDrive_tid, &typeinfo);
821 if(SUCCEEDED(hr))
823 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
824 pDispParams, pVarResult, pExcepInfo, puArgErr);
825 ITypeInfo_Release(typeinfo);
828 return hr;
831 static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path)
833 struct drive *This = impl_from_IDrive(iface);
834 FIXME("(%p)->(%p): stub\n", This, path);
835 return E_NOTIMPL;
838 static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter)
840 struct drive *This = impl_from_IDrive(iface);
842 TRACE("(%p)->(%p)\n", This, letter);
844 if (!letter)
845 return E_POINTER;
847 *letter = SysAllocStringLen(This->root, 1);
848 if (!*letter)
849 return E_OUTOFMEMORY;
851 return S_OK;
854 static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name)
856 struct drive *This = impl_from_IDrive(iface);
857 FIXME("(%p)->(%p): stub\n", This, share_name);
858 return E_NOTIMPL;
861 static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type)
863 struct drive *This = impl_from_IDrive(iface);
865 TRACE("(%p)->(%p)\n", This, type);
867 switch (GetDriveTypeW(This->root))
869 case DRIVE_REMOVABLE:
870 *type = Removable;
871 break;
872 case DRIVE_FIXED:
873 *type = Fixed;
874 break;
875 case DRIVE_REMOTE:
876 *type = Remote;
877 break;
878 case DRIVE_CDROM:
879 *type = CDRom;
880 break;
881 case DRIVE_RAMDISK:
882 *type = RamDisk;
883 break;
884 default:
885 *type = UnknownType;
886 break;
889 return S_OK;
892 static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder)
894 struct drive *This = impl_from_IDrive(iface);
895 FIXME("(%p)->(%p): stub\n", This, folder);
896 return E_NOTIMPL;
899 static HRESULT variant_from_largeint(const ULARGE_INTEGER *src, VARIANT *v)
901 HRESULT hr = S_OK;
903 if (src->u.HighPart || src->u.LowPart > INT_MAX)
905 V_VT(v) = VT_R8;
906 hr = VarR8FromUI8(src->QuadPart, &V_R8(v));
908 else
910 V_VT(v) = VT_I4;
911 V_I4(v) = src->u.LowPart;
914 return hr;
917 static HRESULT WINAPI drive_get_AvailableSpace(IDrive *iface, VARIANT *v)
919 struct drive *This = impl_from_IDrive(iface);
920 ULARGE_INTEGER avail;
922 TRACE("(%p)->(%p)\n", This, v);
924 if (!v)
925 return E_POINTER;
927 if (!GetDiskFreeSpaceExW(This->root, &avail, NULL, NULL))
928 return E_FAIL;
930 return variant_from_largeint(&avail, v);
933 static HRESULT WINAPI drive_get_FreeSpace(IDrive *iface, VARIANT *v)
935 struct drive *This = impl_from_IDrive(iface);
936 ULARGE_INTEGER freespace;
938 TRACE("(%p)->(%p)\n", This, v);
940 if (!v)
941 return E_POINTER;
943 if (!GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL))
944 return E_FAIL;
946 return variant_from_largeint(&freespace, v);
949 static HRESULT WINAPI drive_get_TotalSize(IDrive *iface, VARIANT *v)
951 struct drive *This = impl_from_IDrive(iface);
952 ULARGE_INTEGER total;
954 TRACE("(%p)->(%p)\n", This, v);
956 if (!v)
957 return E_POINTER;
959 if (!GetDiskFreeSpaceExW(This->root, NULL, &total, NULL))
960 return E_FAIL;
962 return variant_from_largeint(&total, v);
965 static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name)
967 struct drive *This = impl_from_IDrive(iface);
968 WCHAR nameW[MAX_PATH+1];
969 BOOL ret;
971 TRACE("(%p)->(%p)\n", This, name);
973 if (!name)
974 return E_POINTER;
976 *name = NULL;
977 ret = GetVolumeInformationW(This->root, nameW, sizeof(nameW)/sizeof(WCHAR), NULL, NULL, NULL, NULL, 0);
978 if (ret)
979 *name = SysAllocString(nameW);
980 return ret ? S_OK : E_FAIL;
983 static HRESULT WINAPI drive_put_VolumeName(IDrive *iface, BSTR name)
985 struct drive *This = impl_from_IDrive(iface);
986 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
987 return E_NOTIMPL;
990 static HRESULT WINAPI drive_get_FileSystem(IDrive *iface, BSTR *fs)
992 struct drive *This = impl_from_IDrive(iface);
993 WCHAR nameW[MAX_PATH+1];
994 BOOL ret;
996 TRACE("(%p)->(%p)\n", This, fs);
998 if (!fs)
999 return E_POINTER;
1001 *fs = NULL;
1002 ret = GetVolumeInformationW(This->root, NULL, 0, NULL, NULL, NULL, nameW, sizeof(nameW)/sizeof(WCHAR));
1003 if (ret)
1004 *fs = SysAllocString(nameW);
1005 return ret ? S_OK : E_FAIL;
1008 static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial)
1010 struct drive *This = impl_from_IDrive(iface);
1011 BOOL ret;
1013 TRACE("(%p)->(%p)\n", This, serial);
1015 if (!serial)
1016 return E_POINTER;
1018 ret = GetVolumeInformationW(This->root, NULL, 0, (DWORD*)serial, NULL, NULL, NULL, 0);
1019 return ret ? S_OK : E_FAIL;
1022 static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
1024 struct drive *This = impl_from_IDrive(iface);
1025 ULARGE_INTEGER freespace;
1026 BOOL ret;
1028 TRACE("(%p)->(%p)\n", This, ready);
1030 if (!ready)
1031 return E_POINTER;
1033 ret = GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL);
1034 *ready = ret ? VARIANT_TRUE : VARIANT_FALSE;
1035 return S_OK;
1038 static const IDriveVtbl drivevtbl = {
1039 drive_QueryInterface,
1040 drive_AddRef,
1041 drive_Release,
1042 drive_GetTypeInfoCount,
1043 drive_GetTypeInfo,
1044 drive_GetIDsOfNames,
1045 drive_Invoke,
1046 drive_get_Path,
1047 drive_get_DriveLetter,
1048 drive_get_ShareName,
1049 drive_get_DriveType,
1050 drive_get_RootFolder,
1051 drive_get_AvailableSpace,
1052 drive_get_FreeSpace,
1053 drive_get_TotalSize,
1054 drive_get_VolumeName,
1055 drive_put_VolumeName,
1056 drive_get_FileSystem,
1057 drive_get_SerialNumber,
1058 drive_get_IsReady
1061 static HRESULT create_drive(WCHAR letter, IDrive **drive)
1063 struct drive *This;
1065 *drive = NULL;
1067 This = heap_alloc(sizeof(*This));
1068 if (!This) return E_OUTOFMEMORY;
1070 This->IDrive_iface.lpVtbl = &drivevtbl;
1071 This->ref = 1;
1072 This->root = SysAllocStringLen(NULL, 3);
1073 if (!This->root)
1075 heap_free(This);
1076 return E_OUTOFMEMORY;
1078 This->root[0] = letter;
1079 This->root[1] = ':';
1080 This->root[2] = '\\';
1081 This->root[3] = 0;
1083 *drive = &This->IDrive_iface;
1084 return S_OK;
1087 static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
1089 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1091 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1093 *obj = NULL;
1095 if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
1096 IsEqualIID( riid, &IID_IUnknown ))
1098 *obj = iface;
1099 IEnumVARIANT_AddRef(iface);
1101 else
1102 return E_NOINTERFACE;
1104 return S_OK;
1107 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
1109 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1110 ULONG ref = InterlockedIncrement(&This->ref);
1111 TRACE("(%p)->(%d)\n", This, ref);
1112 return ref;
1115 static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
1117 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1118 ULONG ref = InterlockedDecrement(&This->ref);
1120 TRACE("(%p)->(%d)\n", This, ref);
1122 if (!ref)
1124 IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
1125 FindClose(This->data.u.foldercoll.find);
1126 heap_free(This);
1129 return ref;
1132 static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file)
1134 static const WCHAR allW[] = {'*',0};
1135 WCHAR pathW[MAX_PATH];
1136 int len;
1137 HANDLE handle;
1139 strcpyW(pathW, path);
1140 len = strlenW(pathW);
1141 if (len && pathW[len-1] != '\\')
1142 strcatW(pathW, bsW);
1143 strcatW(pathW, allW);
1144 handle = FindFirstFileW(pathW, data);
1145 if (handle == INVALID_HANDLE_VALUE) return 0;
1147 /* find first dir/file */
1148 while (1)
1150 if (file ? is_file_data(data) : is_dir_data(data))
1151 break;
1153 if (!FindNextFileW(handle, data))
1155 FindClose(handle);
1156 return 0;
1159 return handle;
1162 static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1164 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1165 HANDLE handle = This->data.u.foldercoll.find;
1166 WIN32_FIND_DATAW data;
1167 ULONG count = 0;
1169 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1171 if (fetched)
1172 *fetched = 0;
1174 if (!celt) return S_OK;
1176 if (!handle)
1178 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1179 if (!handle) return S_FALSE;
1181 This->data.u.foldercoll.find = handle;
1183 else
1185 if (!FindNextFileW(handle, &data))
1186 return S_FALSE;
1191 if (is_dir_data(&data))
1193 IFolder *folder;
1194 HRESULT hr;
1195 BSTR str;
1197 str = get_full_path(This->data.u.foldercoll.coll->path, &data);
1198 hr = create_folder(str, &folder);
1199 SysFreeString(str);
1200 if (FAILED(hr)) return hr;
1202 V_VT(&var[count]) = VT_DISPATCH;
1203 V_DISPATCH(&var[count]) = (IDispatch*)folder;
1204 count++;
1206 if (count >= celt) break;
1208 } while (FindNextFileW(handle, &data));
1210 if (fetched)
1211 *fetched = count;
1213 return (count < celt) ? S_FALSE : S_OK;
1216 static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1218 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1219 HANDLE handle = This->data.u.foldercoll.find;
1220 WIN32_FIND_DATAW data;
1222 TRACE("(%p)->(%d)\n", This, celt);
1224 if (!celt) return S_OK;
1226 if (!handle)
1228 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1229 if (!handle) return S_FALSE;
1231 This->data.u.foldercoll.find = handle;
1233 else
1235 if (!FindNextFileW(handle, &data))
1236 return S_FALSE;
1241 if (is_dir_data(&data))
1242 --celt;
1244 if (!celt) break;
1245 } while (FindNextFileW(handle, &data));
1247 return celt ? S_FALSE : S_OK;
1250 static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
1252 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1254 TRACE("(%p)\n", This);
1256 FindClose(This->data.u.foldercoll.find);
1257 This->data.u.foldercoll.find = NULL;
1259 return S_OK;
1262 static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1264 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1265 TRACE("(%p)->(%p)\n", This, pclone);
1266 return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
1269 static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
1270 enumvariant_QueryInterface,
1271 enumvariant_AddRef,
1272 foldercoll_enumvariant_Release,
1273 foldercoll_enumvariant_Next,
1274 foldercoll_enumvariant_Skip,
1275 foldercoll_enumvariant_Reset,
1276 foldercoll_enumvariant_Clone
1279 static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
1281 struct enumvariant *This;
1283 *newenum = NULL;
1285 This = heap_alloc(sizeof(*This));
1286 if (!This) return E_OUTOFMEMORY;
1288 This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
1289 This->ref = 1;
1290 This->data.u.foldercoll.find = NULL;
1291 This->data.u.foldercoll.coll = collection;
1292 IFolderCollection_AddRef(&collection->IFolderCollection_iface);
1294 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1296 return S_OK;
1299 static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface)
1301 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1302 ULONG ref = InterlockedDecrement(&This->ref);
1304 TRACE("(%p)->(%d)\n", This, ref);
1306 if (!ref)
1308 IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
1309 FindClose(This->data.u.filecoll.find);
1310 heap_free(This);
1313 return ref;
1316 static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1318 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1319 HANDLE handle = This->data.u.filecoll.find;
1320 WIN32_FIND_DATAW data;
1321 ULONG count = 0;
1323 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1325 if (fetched)
1326 *fetched = 0;
1328 if (!celt) return S_OK;
1330 if (!handle)
1332 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1333 if (!handle) return S_FALSE;
1334 This->data.u.filecoll.find = handle;
1336 else if (!FindNextFileW(handle, &data))
1337 return S_FALSE;
1341 if (is_file_data(&data))
1343 IFile *file;
1344 HRESULT hr;
1345 BSTR str;
1347 str = get_full_path(This->data.u.filecoll.coll->path, &data);
1348 hr = create_file(str, &file);
1349 SysFreeString(str);
1350 if (FAILED(hr)) return hr;
1352 V_VT(&var[count]) = VT_DISPATCH;
1353 V_DISPATCH(&var[count]) = (IDispatch*)file;
1354 if (++count >= celt) break;
1356 } while (FindNextFileW(handle, &data));
1358 if (fetched)
1359 *fetched = count;
1361 return (count < celt) ? S_FALSE : S_OK;
1364 static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1366 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1367 HANDLE handle = This->data.u.filecoll.find;
1368 WIN32_FIND_DATAW data;
1370 TRACE("(%p)->(%d)\n", This, celt);
1372 if (!celt) return S_OK;
1374 if (!handle)
1376 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1377 if (!handle) return S_FALSE;
1378 This->data.u.filecoll.find = handle;
1380 else if (!FindNextFileW(handle, &data))
1381 return S_FALSE;
1385 if (is_file_data(&data))
1386 --celt;
1387 } while (celt && FindNextFileW(handle, &data));
1389 return celt ? S_FALSE : S_OK;
1392 static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface)
1394 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1396 TRACE("(%p)\n", This);
1398 FindClose(This->data.u.filecoll.find);
1399 This->data.u.filecoll.find = NULL;
1401 return S_OK;
1404 static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1406 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1407 TRACE("(%p)->(%p)\n", This, pclone);
1408 return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
1411 static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
1412 enumvariant_QueryInterface,
1413 enumvariant_AddRef,
1414 filecoll_enumvariant_Release,
1415 filecoll_enumvariant_Next,
1416 filecoll_enumvariant_Skip,
1417 filecoll_enumvariant_Reset,
1418 filecoll_enumvariant_Clone
1421 static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum)
1423 struct enumvariant *This;
1425 *newenum = NULL;
1427 This = heap_alloc(sizeof(*This));
1428 if (!This) return E_OUTOFMEMORY;
1430 This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
1431 This->ref = 1;
1432 This->data.u.filecoll.find = NULL;
1433 This->data.u.filecoll.coll = collection;
1434 IFileCollection_AddRef(&collection->IFileCollection_iface);
1436 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1438 return S_OK;
1441 static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface)
1443 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1444 ULONG ref = InterlockedDecrement(&This->ref);
1446 TRACE("(%p)->(%d)\n", This, ref);
1448 if (!ref)
1450 IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
1451 heap_free(This);
1454 return ref;
1457 static HRESULT find_next_drive(struct enumvariant *penum)
1459 int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
1461 for (; i < 32; i++)
1462 if (penum->data.u.drivecoll.coll->drives & (1 << i))
1464 penum->data.u.drivecoll.cur = i;
1465 return S_OK;
1468 return S_FALSE;
1471 static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1473 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1474 ULONG count = 0;
1476 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1478 if (fetched)
1479 *fetched = 0;
1481 if (!celt) return S_OK;
1483 while (find_next_drive(This) == S_OK)
1485 IDrive *drive;
1486 HRESULT hr;
1488 hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
1489 if (FAILED(hr)) return hr;
1491 V_VT(&var[count]) = VT_DISPATCH;
1492 V_DISPATCH(&var[count]) = (IDispatch*)drive;
1494 if (++count >= celt) break;
1497 if (fetched)
1498 *fetched = count;
1500 return (count < celt) ? S_FALSE : S_OK;
1503 static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1505 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1507 TRACE("(%p)->(%d)\n", This, celt);
1509 if (!celt) return S_OK;
1511 while (celt && find_next_drive(This) == S_OK)
1512 celt--;
1514 return celt ? S_FALSE : S_OK;
1517 static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface)
1519 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1521 TRACE("(%p)\n", This);
1523 This->data.u.drivecoll.cur = -1;
1524 return S_OK;
1527 static HRESULT WINAPI drivecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1529 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1530 FIXME("(%p)->(%p): stub\n", This, pclone);
1531 return E_NOTIMPL;
1534 static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
1535 enumvariant_QueryInterface,
1536 enumvariant_AddRef,
1537 drivecoll_enumvariant_Release,
1538 drivecoll_enumvariant_Next,
1539 drivecoll_enumvariant_Skip,
1540 drivecoll_enumvariant_Reset,
1541 drivecoll_enumvariant_Clone
1544 static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum)
1546 struct enumvariant *This;
1548 *newenum = NULL;
1550 This = heap_alloc(sizeof(*This));
1551 if (!This) return E_OUTOFMEMORY;
1553 This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
1554 This->ref = 1;
1555 This->data.u.drivecoll.coll = collection;
1556 This->data.u.drivecoll.cur = -1;
1557 IDriveCollection_AddRef(&collection->IDriveCollection_iface);
1559 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1561 return S_OK;
1564 static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
1566 struct foldercollection *This = impl_from_IFolderCollection(iface);
1568 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1570 *obj = NULL;
1572 if (IsEqualIID( riid, &IID_IFolderCollection ) ||
1573 IsEqualIID( riid, &IID_IDispatch ) ||
1574 IsEqualIID( riid, &IID_IUnknown ))
1576 *obj = iface;
1577 IFolderCollection_AddRef(iface);
1579 else
1580 return E_NOINTERFACE;
1582 return S_OK;
1585 static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
1587 struct foldercollection *This = impl_from_IFolderCollection(iface);
1588 ULONG ref = InterlockedIncrement(&This->ref);
1589 TRACE("(%p)->(%d)\n", This, ref);
1590 return ref;
1593 static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
1595 struct foldercollection *This = impl_from_IFolderCollection(iface);
1596 ULONG ref = InterlockedDecrement(&This->ref);
1597 TRACE("(%p)->(%d)\n", This, ref);
1599 if (!ref)
1601 SysFreeString(This->path);
1602 heap_free(This);
1605 return ref;
1608 static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
1610 struct foldercollection *This = impl_from_IFolderCollection(iface);
1611 TRACE("(%p)->(%p)\n", This, pctinfo);
1612 *pctinfo = 1;
1613 return S_OK;
1616 static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
1617 LCID lcid, ITypeInfo **ppTInfo)
1619 struct foldercollection *This = impl_from_IFolderCollection(iface);
1620 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1621 return get_typeinfo(IFolderCollection_tid, ppTInfo);
1624 static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
1625 LPOLESTR *rgszNames, UINT cNames,
1626 LCID lcid, DISPID *rgDispId)
1628 struct foldercollection *This = impl_from_IFolderCollection(iface);
1629 ITypeInfo *typeinfo;
1630 HRESULT hr;
1632 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1634 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1635 if(SUCCEEDED(hr))
1637 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1638 ITypeInfo_Release(typeinfo);
1641 return hr;
1644 static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
1645 REFIID riid, LCID lcid, WORD wFlags,
1646 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1647 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1649 struct foldercollection *This = impl_from_IFolderCollection(iface);
1650 ITypeInfo *typeinfo;
1651 HRESULT hr;
1653 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1654 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1656 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1657 if(SUCCEEDED(hr))
1659 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1660 pDispParams, pVarResult, pExcepInfo, puArgErr);
1661 ITypeInfo_Release(typeinfo);
1664 return hr;
1667 static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
1669 struct foldercollection *This = impl_from_IFolderCollection(iface);
1670 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
1671 return E_NOTIMPL;
1674 static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
1676 struct foldercollection *This = impl_from_IFolderCollection(iface);
1677 FIXME("(%p)->(%p): stub\n", This, folder);
1678 return E_NOTIMPL;
1681 static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
1683 struct foldercollection *This = impl_from_IFolderCollection(iface);
1685 TRACE("(%p)->(%p)\n", This, newenum);
1687 if(!newenum)
1688 return E_POINTER;
1690 return create_foldercoll_enum(This, newenum);
1693 static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
1695 struct foldercollection *This = impl_from_IFolderCollection(iface);
1696 static const WCHAR allW[] = {'\\','*',0};
1697 WIN32_FIND_DATAW data;
1698 WCHAR pathW[MAX_PATH];
1699 HANDLE handle;
1701 TRACE("(%p)->(%p)\n", This, count);
1703 if(!count)
1704 return E_POINTER;
1706 *count = 0;
1708 strcpyW(pathW, This->path);
1709 strcatW(pathW, allW);
1710 handle = FindFirstFileW(pathW, &data);
1711 if (handle == INVALID_HANDLE_VALUE)
1712 return HRESULT_FROM_WIN32(GetLastError());
1716 if (is_dir_data(&data))
1717 *count += 1;
1718 } while (FindNextFileW(handle, &data));
1719 FindClose(handle);
1721 return S_OK;
1724 static const IFolderCollectionVtbl foldercollvtbl = {
1725 foldercoll_QueryInterface,
1726 foldercoll_AddRef,
1727 foldercoll_Release,
1728 foldercoll_GetTypeInfoCount,
1729 foldercoll_GetTypeInfo,
1730 foldercoll_GetIDsOfNames,
1731 foldercoll_Invoke,
1732 foldercoll_Add,
1733 foldercoll_get_Item,
1734 foldercoll_get__NewEnum,
1735 foldercoll_get_Count
1738 static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
1740 struct foldercollection *This;
1742 *folders = NULL;
1744 This = heap_alloc(sizeof(struct foldercollection));
1745 if (!This) return E_OUTOFMEMORY;
1747 This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
1748 This->ref = 1;
1749 This->path = SysAllocString(path);
1750 if (!This->path)
1752 heap_free(This);
1753 return E_OUTOFMEMORY;
1756 *folders = &This->IFolderCollection_iface;
1758 return S_OK;
1761 static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj)
1763 struct filecollection *This = impl_from_IFileCollection(iface);
1765 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1767 *obj = NULL;
1769 if (IsEqualIID( riid, &IID_IFileCollection ) ||
1770 IsEqualIID( riid, &IID_IDispatch ) ||
1771 IsEqualIID( riid, &IID_IUnknown ))
1773 *obj = iface;
1774 IFileCollection_AddRef(iface);
1776 else
1777 return E_NOINTERFACE;
1779 return S_OK;
1782 static ULONG WINAPI filecoll_AddRef(IFileCollection *iface)
1784 struct filecollection *This = impl_from_IFileCollection(iface);
1785 ULONG ref = InterlockedIncrement(&This->ref);
1786 TRACE("(%p)->(%d)\n", This, ref);
1787 return ref;
1790 static ULONG WINAPI filecoll_Release(IFileCollection *iface)
1792 struct filecollection *This = impl_from_IFileCollection(iface);
1793 ULONG ref = InterlockedDecrement(&This->ref);
1794 TRACE("(%p)->(%d)\n", This, ref);
1796 if (!ref)
1798 SysFreeString(This->path);
1799 heap_free(This);
1802 return ref;
1805 static HRESULT WINAPI filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo)
1807 struct filecollection *This = impl_from_IFileCollection(iface);
1808 TRACE("(%p)->(%p)\n", This, pctinfo);
1809 *pctinfo = 1;
1810 return S_OK;
1813 static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo,
1814 LCID lcid, ITypeInfo **ppTInfo)
1816 struct filecollection *This = impl_from_IFileCollection(iface);
1817 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1818 return get_typeinfo(IFileCollection_tid, ppTInfo);
1821 static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid,
1822 LPOLESTR *rgszNames, UINT cNames,
1823 LCID lcid, DISPID *rgDispId)
1825 struct filecollection *This = impl_from_IFileCollection(iface);
1826 ITypeInfo *typeinfo;
1827 HRESULT hr;
1829 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1831 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1832 if(SUCCEEDED(hr))
1834 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1835 ITypeInfo_Release(typeinfo);
1838 return hr;
1841 static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember,
1842 REFIID riid, LCID lcid, WORD wFlags,
1843 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1844 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1846 struct filecollection *This = impl_from_IFileCollection(iface);
1847 ITypeInfo *typeinfo;
1848 HRESULT hr;
1850 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1851 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1853 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1854 if(SUCCEEDED(hr))
1856 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1857 pDispParams, pVarResult, pExcepInfo, puArgErr);
1858 ITypeInfo_Release(typeinfo);
1861 return hr;
1864 static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file)
1866 struct filecollection *This = impl_from_IFileCollection(iface);
1867 FIXME("(%p)->(%p)\n", This, file);
1868 return E_NOTIMPL;
1871 static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum)
1873 struct filecollection *This = impl_from_IFileCollection(iface);
1875 TRACE("(%p)->(%p)\n", This, ppenum);
1877 if(!ppenum)
1878 return E_POINTER;
1880 return create_filecoll_enum(This, ppenum);
1883 static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count)
1885 struct filecollection *This = impl_from_IFileCollection(iface);
1886 static const WCHAR allW[] = {'\\','*',0};
1887 WIN32_FIND_DATAW data;
1888 WCHAR pathW[MAX_PATH];
1889 HANDLE handle;
1891 TRACE("(%p)->(%p)\n", This, count);
1893 if(!count)
1894 return E_POINTER;
1896 *count = 0;
1898 strcpyW(pathW, This->path);
1899 strcatW(pathW, allW);
1900 handle = FindFirstFileW(pathW, &data);
1901 if (handle == INVALID_HANDLE_VALUE)
1902 return HRESULT_FROM_WIN32(GetLastError());
1906 if (is_file_data(&data))
1907 *count += 1;
1908 } while (FindNextFileW(handle, &data));
1909 FindClose(handle);
1911 return S_OK;
1914 static const IFileCollectionVtbl filecollectionvtbl = {
1915 filecoll_QueryInterface,
1916 filecoll_AddRef,
1917 filecoll_Release,
1918 filecoll_GetTypeInfoCount,
1919 filecoll_GetTypeInfo,
1920 filecoll_GetIDsOfNames,
1921 filecoll_Invoke,
1922 filecoll_get_Item,
1923 filecoll_get__NewEnum,
1924 filecoll_get_Count
1927 static HRESULT create_filecoll(BSTR path, IFileCollection **files)
1929 struct filecollection *This;
1931 *files = NULL;
1933 This = heap_alloc(sizeof(*This));
1934 if (!This) return E_OUTOFMEMORY;
1936 This->IFileCollection_iface.lpVtbl = &filecollectionvtbl;
1937 This->ref = 1;
1938 This->path = SysAllocString(path);
1939 if (!This->path)
1941 heap_free(This);
1942 return E_OUTOFMEMORY;
1945 *files = &This->IFileCollection_iface;
1946 return S_OK;
1949 static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
1951 struct drivecollection *This = impl_from_IDriveCollection(iface);
1953 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1955 *obj = NULL;
1957 if (IsEqualIID( riid, &IID_IDriveCollection ) ||
1958 IsEqualIID( riid, &IID_IDispatch ) ||
1959 IsEqualIID( riid, &IID_IUnknown ))
1961 *obj = iface;
1962 IDriveCollection_AddRef(iface);
1964 else
1965 return E_NOINTERFACE;
1967 return S_OK;
1970 static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
1972 struct drivecollection *This = impl_from_IDriveCollection(iface);
1973 ULONG ref = InterlockedIncrement(&This->ref);
1974 TRACE("(%p)->(%d)\n", This, ref);
1975 return ref;
1978 static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
1980 struct drivecollection *This = impl_from_IDriveCollection(iface);
1981 ULONG ref = InterlockedDecrement(&This->ref);
1982 TRACE("(%p)->(%d)\n", This, ref);
1984 if (!ref)
1985 heap_free(This);
1987 return ref;
1990 static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
1992 struct drivecollection *This = impl_from_IDriveCollection(iface);
1993 TRACE("(%p)->(%p)\n", This, pctinfo);
1994 *pctinfo = 1;
1995 return S_OK;
1998 static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
1999 LCID lcid, ITypeInfo **ppTInfo)
2001 struct drivecollection *This = impl_from_IDriveCollection(iface);
2002 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2003 return get_typeinfo(IDriveCollection_tid, ppTInfo);
2006 static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
2007 LPOLESTR *rgszNames, UINT cNames,
2008 LCID lcid, DISPID *rgDispId)
2010 struct drivecollection *This = impl_from_IDriveCollection(iface);
2011 ITypeInfo *typeinfo;
2012 HRESULT hr;
2014 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2016 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2017 if(SUCCEEDED(hr))
2019 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2020 ITypeInfo_Release(typeinfo);
2023 return hr;
2026 static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
2027 REFIID riid, LCID lcid, WORD wFlags,
2028 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2029 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2031 struct drivecollection *This = impl_from_IDriveCollection(iface);
2032 ITypeInfo *typeinfo;
2033 HRESULT hr;
2035 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2036 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2038 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2039 if(SUCCEEDED(hr))
2041 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2042 pDispParams, pVarResult, pExcepInfo, puArgErr);
2043 ITypeInfo_Release(typeinfo);
2046 return hr;
2049 static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
2051 struct drivecollection *This = impl_from_IDriveCollection(iface);
2052 FIXME("(%p)->(%p): stub\n", This, drive);
2053 return E_NOTIMPL;
2056 static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
2058 struct drivecollection *This = impl_from_IDriveCollection(iface);
2060 TRACE("(%p)->(%p)\n", This, ppenum);
2062 if(!ppenum)
2063 return E_POINTER;
2065 return create_drivecoll_enum(This, ppenum);
2068 static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
2070 struct drivecollection *This = impl_from_IDriveCollection(iface);
2072 TRACE("(%p)->(%p)\n", This, count);
2074 if (!count) return E_POINTER;
2076 *count = This->count;
2077 return S_OK;
2080 static const IDriveCollectionVtbl drivecollectionvtbl = {
2081 drivecoll_QueryInterface,
2082 drivecoll_AddRef,
2083 drivecoll_Release,
2084 drivecoll_GetTypeInfoCount,
2085 drivecoll_GetTypeInfo,
2086 drivecoll_GetIDsOfNames,
2087 drivecoll_Invoke,
2088 drivecoll_get_Item,
2089 drivecoll_get__NewEnum,
2090 drivecoll_get_Count
2093 static HRESULT create_drivecoll(IDriveCollection **drives)
2095 struct drivecollection *This;
2096 DWORD mask;
2098 *drives = NULL;
2100 This = heap_alloc(sizeof(*This));
2101 if (!This) return E_OUTOFMEMORY;
2103 This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl;
2104 This->ref = 1;
2105 This->drives = mask = GetLogicalDrives();
2106 /* count set bits */
2107 for (This->count = 0; mask; This->count++)
2108 mask &= mask - 1;
2110 *drives = &This->IDriveCollection_iface;
2111 return S_OK;
2114 static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
2116 struct folder *This = impl_from_IFolder(iface);
2118 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2120 *obj = NULL;
2122 if (IsEqualIID( riid, &IID_IFolder ) ||
2123 IsEqualIID( riid, &IID_IDispatch ) ||
2124 IsEqualIID( riid, &IID_IUnknown))
2126 *obj = iface;
2127 IFolder_AddRef(iface);
2129 else
2130 return E_NOINTERFACE;
2132 return S_OK;
2135 static ULONG WINAPI folder_AddRef(IFolder *iface)
2137 struct folder *This = impl_from_IFolder(iface);
2138 ULONG ref = InterlockedIncrement(&This->ref);
2139 TRACE("(%p)->(%d)\n", This, ref);
2140 return ref;
2143 static ULONG WINAPI folder_Release(IFolder *iface)
2145 struct folder *This = impl_from_IFolder(iface);
2146 ULONG ref = InterlockedDecrement(&This->ref);
2147 TRACE("(%p)->(%d)\n", This, ref);
2149 if (!ref)
2151 SysFreeString(This->path);
2152 heap_free(This);
2155 return ref;
2158 static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
2160 struct folder *This = impl_from_IFolder(iface);
2161 TRACE("(%p)->(%p)\n", This, pctinfo);
2162 *pctinfo = 1;
2163 return S_OK;
2166 static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
2167 LCID lcid, ITypeInfo **ppTInfo)
2169 struct folder *This = impl_from_IFolder(iface);
2170 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2171 return get_typeinfo(IFolder_tid, ppTInfo);
2174 static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
2175 LPOLESTR *rgszNames, UINT cNames,
2176 LCID lcid, DISPID *rgDispId)
2178 struct folder *This = impl_from_IFolder(iface);
2179 ITypeInfo *typeinfo;
2180 HRESULT hr;
2182 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2184 hr = get_typeinfo(IFolder_tid, &typeinfo);
2185 if(SUCCEEDED(hr))
2187 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2188 ITypeInfo_Release(typeinfo);
2191 return hr;
2194 static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
2195 REFIID riid, LCID lcid, WORD wFlags,
2196 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2197 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2199 struct folder *This = impl_from_IFolder(iface);
2200 ITypeInfo *typeinfo;
2201 HRESULT hr;
2203 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2204 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2206 hr = get_typeinfo(IFolder_tid, &typeinfo);
2207 if(SUCCEEDED(hr))
2209 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2210 pDispParams, pVarResult, pExcepInfo, puArgErr);
2211 ITypeInfo_Release(typeinfo);
2214 return hr;
2217 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
2219 struct folder *This = impl_from_IFolder(iface);
2221 TRACE("(%p)->(%p)\n", This, path);
2223 if(!path)
2224 return E_POINTER;
2226 *path = SysAllocString(This->path);
2227 return *path ? S_OK : E_OUTOFMEMORY;
2230 static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
2232 struct folder *This = impl_from_IFolder(iface);
2233 WCHAR *ptr;
2235 TRACE("(%p)->(%p)\n", This, name);
2237 if(!name)
2238 return E_POINTER;
2240 *name = NULL;
2242 ptr = strrchrW(This->path, '\\');
2243 if (ptr)
2245 *name = SysAllocString(ptr+1);
2246 TRACE("%s\n", debugstr_w(*name));
2247 if (!*name) return E_OUTOFMEMORY;
2249 else
2250 return E_FAIL;
2252 return S_OK;
2255 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
2257 struct folder *This = impl_from_IFolder(iface);
2258 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
2259 return E_NOTIMPL;
2262 static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
2264 struct folder *This = impl_from_IFolder(iface);
2265 FIXME("(%p)->(%p): stub\n", This, path);
2266 return E_NOTIMPL;
2269 static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
2271 struct folder *This = impl_from_IFolder(iface);
2272 FIXME("(%p)->(%p): stub\n", This, name);
2273 return E_NOTIMPL;
2276 static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
2278 struct folder *This = impl_from_IFolder(iface);
2279 FIXME("(%p)->(%p): stub\n", This, drive);
2280 return E_NOTIMPL;
2283 static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
2285 struct folder *This = impl_from_IFolder(iface);
2286 FIXME("(%p)->(%p): stub\n", This, parent);
2287 return E_NOTIMPL;
2290 static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
2292 struct folder *This = impl_from_IFolder(iface);
2293 FIXME("(%p)->(%p): stub\n", This, attr);
2294 return E_NOTIMPL;
2297 static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
2299 struct folder *This = impl_from_IFolder(iface);
2300 FIXME("(%p)->(0x%x): stub\n", This, attr);
2301 return E_NOTIMPL;
2304 static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
2306 struct folder *This = impl_from_IFolder(iface);
2307 FIXME("(%p)->(%p): stub\n", This, date);
2308 return E_NOTIMPL;
2311 static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
2313 struct folder *This = impl_from_IFolder(iface);
2314 FIXME("(%p)->(%p): stub\n", This, date);
2315 return E_NOTIMPL;
2318 static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
2320 struct folder *This = impl_from_IFolder(iface);
2321 FIXME("(%p)->(%p): stub\n", This, date);
2322 return E_NOTIMPL;
2325 static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
2327 struct folder *This = impl_from_IFolder(iface);
2328 FIXME("(%p)->(%p): stub\n", This, type);
2329 return E_NOTIMPL;
2332 static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
2334 struct folder *This = impl_from_IFolder(iface);
2335 FIXME("(%p)->(%x): stub\n", This, force);
2336 return E_NOTIMPL;
2339 static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
2341 struct folder *This = impl_from_IFolder(iface);
2342 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
2343 return E_NOTIMPL;
2346 static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
2348 struct folder *This = impl_from_IFolder(iface);
2349 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
2350 return E_NOTIMPL;
2353 static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
2355 struct folder *This = impl_from_IFolder(iface);
2356 FIXME("(%p)->(%p): stub\n", This, isroot);
2357 return E_NOTIMPL;
2360 static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
2362 struct folder *This = impl_from_IFolder(iface);
2363 FIXME("(%p)->(%p): stub\n", This, size);
2364 return E_NOTIMPL;
2367 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
2369 struct folder *This = impl_from_IFolder(iface);
2371 TRACE("(%p)->(%p)\n", This, folders);
2373 if(!folders)
2374 return E_POINTER;
2376 return create_foldercoll(This->path, folders);
2379 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
2381 struct folder *This = impl_from_IFolder(iface);
2383 TRACE("(%p)->(%p)\n", This, files);
2385 if(!files)
2386 return E_POINTER;
2388 return create_filecoll(This->path, files);
2391 static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
2392 VARIANT_BOOL unicode, ITextStream **stream)
2394 struct folder *This = impl_from_IFolder(iface);
2395 FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
2396 return E_NOTIMPL;
2399 static const IFolderVtbl foldervtbl = {
2400 folder_QueryInterface,
2401 folder_AddRef,
2402 folder_Release,
2403 folder_GetTypeInfoCount,
2404 folder_GetTypeInfo,
2405 folder_GetIDsOfNames,
2406 folder_Invoke,
2407 folder_get_Path,
2408 folder_get_Name,
2409 folder_put_Name,
2410 folder_get_ShortPath,
2411 folder_get_ShortName,
2412 folder_get_Drive,
2413 folder_get_ParentFolder,
2414 folder_get_Attributes,
2415 folder_put_Attributes,
2416 folder_get_DateCreated,
2417 folder_get_DateLastModified,
2418 folder_get_DateLastAccessed,
2419 folder_get_Type,
2420 folder_Delete,
2421 folder_Copy,
2422 folder_Move,
2423 folder_get_IsRootFolder,
2424 folder_get_Size,
2425 folder_get_SubFolders,
2426 folder_get_Files,
2427 folder_CreateTextFile
2430 HRESULT create_folder(const WCHAR *path, IFolder **folder)
2432 struct folder *This;
2434 *folder = NULL;
2436 TRACE("%s\n", debugstr_w(path));
2438 This = heap_alloc(sizeof(struct folder));
2439 if (!This) return E_OUTOFMEMORY;
2441 This->IFolder_iface.lpVtbl = &foldervtbl;
2442 This->ref = 1;
2443 This->path = SysAllocString(path);
2444 if (!This->path)
2446 heap_free(This);
2447 return E_OUTOFMEMORY;
2450 *folder = &This->IFolder_iface;
2452 return S_OK;
2455 static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
2457 struct file *This = impl_from_IFile(iface);
2459 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2461 if (IsEqualIID(riid, &IID_IFile) ||
2462 IsEqualIID(riid, &IID_IDispatch) ||
2463 IsEqualIID(riid, &IID_IUnknown))
2465 *obj = iface;
2466 IFile_AddRef(iface);
2467 return S_OK;
2470 *obj = NULL;
2471 return E_NOINTERFACE;
2474 static ULONG WINAPI file_AddRef(IFile *iface)
2476 struct file *This = impl_from_IFile(iface);
2477 LONG ref = InterlockedIncrement(&This->ref);
2479 TRACE("(%p) ref=%d\n", This, ref);
2481 return ref;
2484 static ULONG WINAPI file_Release(IFile *iface)
2486 struct file *This = impl_from_IFile(iface);
2487 LONG ref = InterlockedDecrement(&This->ref);
2489 TRACE("(%p) ref=%d\n", This, ref);
2491 if(!ref)
2493 heap_free(This->path);
2494 heap_free(This);
2497 return ref;
2500 static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
2502 struct file *This = impl_from_IFile(iface);
2504 TRACE("(%p)->(%p)\n", This, pctinfo);
2506 *pctinfo = 1;
2507 return S_OK;
2510 static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
2511 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
2513 struct file *This = impl_from_IFile(iface);
2515 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2517 return get_typeinfo(IFile_tid, ppTInfo);
2520 static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
2521 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2523 struct file *This = impl_from_IFile(iface);
2524 ITypeInfo *typeinfo;
2525 HRESULT hr;
2527 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
2528 rgszNames, cNames, lcid, rgDispId);
2530 hr = get_typeinfo(IFile_tid, &typeinfo);
2531 if(SUCCEEDED(hr)) {
2532 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2533 ITypeInfo_Release(typeinfo);
2535 return hr;
2538 static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2540 struct file *This = impl_from_IFile(iface);
2541 ITypeInfo *typeinfo;
2542 HRESULT hr;
2544 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2545 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2547 hr = get_typeinfo(IFile_tid, &typeinfo);
2548 if(SUCCEEDED(hr))
2550 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2551 pDispParams, pVarResult, pExcepInfo, puArgErr);
2552 ITypeInfo_Release(typeinfo);
2554 return hr;
2557 static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *path)
2559 struct file *This = impl_from_IFile(iface);
2561 TRACE("(%p)->(%p)\n", This, path);
2563 if (!path)
2564 return E_POINTER;
2566 *path = SysAllocString(This->path);
2567 if (!*path)
2568 return E_OUTOFMEMORY;
2570 return S_OK;
2573 static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
2575 struct file *This = impl_from_IFile(iface);
2576 WCHAR *ptr;
2578 TRACE("(%p)->(%p)\n", This, name);
2580 if(!name)
2581 return E_POINTER;
2583 *name = NULL;
2585 ptr = strrchrW(This->path, '\\');
2586 if (ptr)
2588 *name = SysAllocString(ptr+1);
2589 TRACE("%s\n", debugstr_w(*name));
2590 if (!*name) return E_OUTOFMEMORY;
2592 else
2593 return E_FAIL;
2595 return S_OK;
2598 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
2600 struct file *This = impl_from_IFile(iface);
2601 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
2602 return E_NOTIMPL;
2605 static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
2607 struct file *This = impl_from_IFile(iface);
2608 FIXME("(%p)->(%p)\n", This, pbstrPath);
2609 return E_NOTIMPL;
2612 static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
2614 struct file *This = impl_from_IFile(iface);
2615 FIXME("(%p)->(%p)\n", This, pbstrName);
2616 return E_NOTIMPL;
2619 static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
2621 struct file *This = impl_from_IFile(iface);
2622 FIXME("(%p)->(%p)\n", This, ppdrive);
2623 return E_NOTIMPL;
2626 static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
2628 struct file *This = impl_from_IFile(iface);
2629 FIXME("(%p)->(%p)\n", This, ppfolder);
2630 return E_NOTIMPL;
2633 static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
2635 struct file *This = impl_from_IFile(iface);
2636 DWORD fa;
2638 TRACE("(%p)->(%p)\n", This, pfa);
2640 if(!pfa)
2641 return E_POINTER;
2643 fa = GetFileAttributesW(This->path);
2644 if(fa == INVALID_FILE_ATTRIBUTES)
2645 return create_error(GetLastError());
2647 *pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2648 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
2649 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
2650 return S_OK;
2653 static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
2655 struct file *This = impl_from_IFile(iface);
2657 TRACE("(%p)->(%x)\n", This, pfa);
2659 return SetFileAttributesW(This->path, pfa) ? S_OK : create_error(GetLastError());
2662 static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
2664 struct file *This = impl_from_IFile(iface);
2665 FIXME("(%p)->(%p)\n", This, pdate);
2666 return E_NOTIMPL;
2669 static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *pdate)
2671 struct file *This = impl_from_IFile(iface);
2672 FIXME("(%p)->(%p)\n", This, pdate);
2673 return E_NOTIMPL;
2676 static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
2678 struct file *This = impl_from_IFile(iface);
2679 FIXME("(%p)->(%p)\n", This, pdate);
2680 return E_NOTIMPL;
2683 static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
2685 struct file *This = impl_from_IFile(iface);
2686 ULARGE_INTEGER size;
2687 WIN32_FIND_DATAW fd;
2688 HANDLE f;
2690 TRACE("(%p)->(%p)\n", This, pvarSize);
2692 if(!pvarSize)
2693 return E_POINTER;
2695 f = FindFirstFileW(This->path, &fd);
2696 if(f == INVALID_HANDLE_VALUE)
2697 return create_error(GetLastError());
2698 FindClose(f);
2700 size.u.LowPart = fd.nFileSizeLow;
2701 size.u.HighPart = fd.nFileSizeHigh;
2703 return variant_from_largeint(&size, pvarSize);
2706 static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
2708 struct file *This = impl_from_IFile(iface);
2709 FIXME("(%p)->(%p)\n", This, pbstrType);
2710 return E_NOTIMPL;
2713 static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
2715 struct file *This = impl_from_IFile(iface);
2716 FIXME("(%p)->(%x)\n", This, Force);
2717 return E_NOTIMPL;
2720 static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
2722 struct file *This = impl_from_IFile(iface);
2723 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
2724 return E_NOTIMPL;
2727 static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
2729 struct file *This = impl_from_IFile(iface);
2730 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
2731 return E_NOTIMPL;
2734 static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode mode, Tristate format, ITextStream **stream)
2736 struct file *This = impl_from_IFile(iface);
2738 TRACE("(%p)->(%d %d %p)\n", This, mode, format, stream);
2740 if (format == TristateUseDefault) {
2741 FIXME("default format not handled, defaulting to unicode\n");
2742 format = TristateTrue;
2745 return create_textstream(This->path, OPEN_EXISTING, mode, format == TristateTrue, stream);
2748 static const IFileVtbl file_vtbl = {
2749 file_QueryInterface,
2750 file_AddRef,
2751 file_Release,
2752 file_GetTypeInfoCount,
2753 file_GetTypeInfo,
2754 file_GetIDsOfNames,
2755 file_Invoke,
2756 file_get_Path,
2757 file_get_Name,
2758 file_put_Name,
2759 file_get_ShortPath,
2760 file_get_ShortName,
2761 file_get_Drive,
2762 file_get_ParentFolder,
2763 file_get_Attributes,
2764 file_put_Attributes,
2765 file_get_DateCreated,
2766 file_get_DateLastModified,
2767 file_get_DateLastAccessed,
2768 file_get_Size,
2769 file_get_Type,
2770 file_Delete,
2771 file_Copy,
2772 file_Move,
2773 file_OpenAsTextStream
2776 static HRESULT create_file(BSTR path, IFile **file)
2778 struct file *f;
2779 DWORD len, attrs;
2781 *file = NULL;
2783 f = heap_alloc(sizeof(struct file));
2784 if(!f)
2785 return E_OUTOFMEMORY;
2787 f->IFile_iface.lpVtbl = &file_vtbl;
2788 f->ref = 1;
2790 len = GetFullPathNameW(path, 0, NULL, NULL);
2791 if(!len) {
2792 heap_free(f);
2793 return E_FAIL;
2796 f->path = heap_alloc(len*sizeof(WCHAR));
2797 if(!f->path) {
2798 heap_free(f);
2799 return E_OUTOFMEMORY;
2802 if(!GetFullPathNameW(path, len, f->path, NULL)) {
2803 heap_free(f->path);
2804 heap_free(f);
2805 return E_FAIL;
2808 attrs = GetFileAttributesW(f->path);
2809 if(attrs==INVALID_FILE_ATTRIBUTES ||
2810 (attrs&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))) {
2811 heap_free(f->path);
2812 heap_free(f);
2813 return create_error(GetLastError());
2816 *file = &f->IFile_iface;
2817 return S_OK;
2820 static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
2822 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
2824 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
2825 IsEqualGUID( riid, &IID_IFileSystem ) ||
2826 IsEqualGUID( riid, &IID_IDispatch ) ||
2827 IsEqualGUID( riid, &IID_IUnknown ) )
2829 *ppvObject = iface;
2831 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
2833 TRACE("Interface IDispatchEx not supported - returning NULL\n");
2834 *ppvObject = NULL;
2835 return E_NOINTERFACE;
2837 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
2839 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
2840 *ppvObject = NULL;
2841 return E_NOINTERFACE;
2843 else
2845 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
2846 return E_NOINTERFACE;
2849 IFileSystem3_AddRef(iface);
2851 return S_OK;
2854 static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
2856 TRACE("%p\n", iface);
2858 return 2;
2861 static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
2863 TRACE("%p\n", iface);
2865 return 1;
2868 static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
2870 TRACE("(%p)->(%p)\n", iface, pctinfo);
2872 *pctinfo = 1;
2873 return S_OK;
2876 static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
2877 LCID lcid, ITypeInfo **ppTInfo)
2879 TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
2880 return get_typeinfo(IFileSystem3_tid, ppTInfo);
2883 static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
2884 LPOLESTR *rgszNames, UINT cNames,
2885 LCID lcid, DISPID *rgDispId)
2887 ITypeInfo *typeinfo;
2888 HRESULT hr;
2890 TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2892 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2893 if(SUCCEEDED(hr))
2895 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2896 ITypeInfo_Release(typeinfo);
2899 return hr;
2902 static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
2903 REFIID riid, LCID lcid, WORD wFlags,
2904 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2905 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2907 ITypeInfo *typeinfo;
2908 HRESULT hr;
2910 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
2911 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2913 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2914 if(SUCCEEDED(hr))
2916 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2917 pDispParams, pVarResult, pExcepInfo, puArgErr);
2918 ITypeInfo_Release(typeinfo);
2921 return hr;
2924 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
2926 TRACE("%p %p\n", iface, ppdrives);
2927 return create_drivecoll(ppdrives);
2930 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
2931 BSTR Name, BSTR *Result)
2933 BSTR ret;
2935 TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
2937 if (!Result) return E_POINTER;
2939 if (Path && Name)
2941 int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
2943 /* if both parts have backslashes strip one from Path */
2944 if (Path[path_len-1] == '\\' && Name[0] == '\\')
2946 path_len -= 1;
2948 ret = SysAllocStringLen(NULL, path_len + name_len);
2949 if (ret)
2951 strcpyW(ret, Path);
2952 ret[path_len] = 0;
2953 strcatW(ret, Name);
2956 else if (Path[path_len-1] != '\\' && Name[0] != '\\')
2958 ret = SysAllocStringLen(NULL, path_len + name_len + 1);
2959 if (ret)
2961 strcpyW(ret, Path);
2962 if (Path[path_len-1] != ':')
2963 strcatW(ret, bsW);
2964 strcatW(ret, Name);
2967 else
2969 ret = SysAllocStringLen(NULL, path_len + name_len);
2970 if (ret)
2972 strcpyW(ret, Path);
2973 strcatW(ret, Name);
2977 else if (Path || Name)
2978 ret = SysAllocString(Path ? Path : Name);
2979 else
2980 ret = SysAllocStringLen(NULL, 0);
2982 if (!ret) return E_OUTOFMEMORY;
2983 *Result = ret;
2985 return S_OK;
2988 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR path, BSTR *drive)
2990 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), drive);
2992 if (!drive)
2993 return E_POINTER;
2995 *drive = NULL;
2997 if (path && strlenW(path) > 1 && path[1] == ':')
2998 *drive = SysAllocStringLen(path, 2);
3000 return S_OK;
3003 static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
3005 int i;
3007 if(!path)
3008 return 0;
3010 for(i=len-1; i>=0; i--)
3011 if(path[i]!='/' && path[i]!='\\')
3012 break;
3014 for(; i>=0; i--)
3015 if(path[i]=='/' || path[i]=='\\')
3016 break;
3018 for(; i>=0; i--)
3019 if(path[i]!='/' && path[i]!='\\')
3020 break;
3022 if(i < 0)
3023 return 0;
3025 if(path[i]==':' && i==1)
3026 i++;
3027 return i+1;
3030 static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
3031 BSTR *pbstrResult)
3033 DWORD len;
3035 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3037 if(!pbstrResult)
3038 return E_POINTER;
3040 len = get_parent_folder_name(Path, SysStringLen(Path));
3041 if(!len) {
3042 *pbstrResult = NULL;
3043 return S_OK;
3046 *pbstrResult = SysAllocStringLen(Path, len);
3047 if(!*pbstrResult)
3048 return E_OUTOFMEMORY;
3049 return S_OK;
3052 static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
3053 BSTR *pbstrResult)
3055 int i, end;
3057 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3059 if(!pbstrResult)
3060 return E_POINTER;
3062 if(!Path) {
3063 *pbstrResult = NULL;
3064 return S_OK;
3067 for(end=strlenW(Path)-1; end>=0; end--)
3068 if(Path[end]!='/' && Path[end]!='\\')
3069 break;
3071 for(i=end; i>=0; i--)
3072 if(Path[i]=='/' || Path[i]=='\\')
3073 break;
3074 i++;
3076 if(i>end || (i==0 && end==1 && Path[1]==':')) {
3077 *pbstrResult = NULL;
3078 return S_OK;
3081 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3082 if(!*pbstrResult)
3083 return E_OUTOFMEMORY;
3084 return S_OK;
3087 static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
3088 BSTR *pbstrResult)
3090 int i, end;
3092 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3094 if(!pbstrResult)
3095 return E_POINTER;
3097 if(!Path) {
3098 *pbstrResult = NULL;
3099 return S_OK;
3102 for(end=strlenW(Path)-1; end>=0; end--)
3103 if(Path[end]!='/' && Path[end]!='\\')
3104 break;
3106 for(i=end; i>=0; i--) {
3107 if(Path[i]=='.' && Path[end+1]!='.')
3108 end = i-1;
3109 if(Path[i]=='/' || Path[i]=='\\')
3110 break;
3112 i++;
3114 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
3115 *pbstrResult = NULL;
3116 return S_OK;
3119 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3120 if(!*pbstrResult)
3121 return E_OUTOFMEMORY;
3122 return S_OK;
3125 static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR path,
3126 BSTR *ext)
3128 INT len;
3130 TRACE("%p %s %p\n", iface, debugstr_w(path), ext);
3132 *ext = NULL;
3133 len = SysStringLen(path);
3134 while (len) {
3135 if (path[len-1] == '.') {
3136 *ext = SysAllocString(&path[len]);
3137 if (!*ext)
3138 return E_OUTOFMEMORY;
3139 break;
3141 len--;
3144 return S_OK;
3147 static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR Path,
3148 BSTR *pbstrResult)
3150 static const WCHAR cur_path[] = {'.',0};
3152 WCHAR buf[MAX_PATH], ch;
3153 const WCHAR *path;
3154 DWORD i, beg, len, exp_len;
3155 WIN32_FIND_DATAW fdata;
3156 HANDLE fh;
3158 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3160 if(!pbstrResult)
3161 return E_POINTER;
3163 if(!Path)
3164 path = cur_path;
3165 else
3166 path = Path;
3168 len = GetFullPathNameW(path, MAX_PATH, buf, NULL);
3169 if(!len)
3170 return E_FAIL;
3172 buf[0] = toupperW(buf[0]);
3173 if(len>3 && buf[len-1] == '\\')
3174 buf[--len] = 0;
3176 for(beg=3, i=3; i<=len; i++) {
3177 if(buf[i]!='\\' && buf[i])
3178 continue;
3180 ch = buf[i];
3181 buf[i] = 0;
3182 fh = FindFirstFileW(buf, &fdata);
3183 if(fh == INVALID_HANDLE_VALUE)
3184 break;
3186 exp_len = strlenW(fdata.cFileName);
3187 if(exp_len == i-beg)
3188 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
3189 FindClose(fh);
3190 buf[i] = ch;
3191 beg = i+1;
3194 *pbstrResult = SysAllocString(buf);
3195 if(!*pbstrResult)
3196 return E_OUTOFMEMORY;
3197 return S_OK;
3200 static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
3202 static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
3204 DWORD random;
3206 TRACE("%p %p\n", iface, pbstrResult);
3208 if(!pbstrResult)
3209 return E_POINTER;
3211 *pbstrResult = SysAllocStringLen(NULL, 12);
3212 if(!*pbstrResult)
3213 return E_OUTOFMEMORY;
3215 if(!RtlGenRandom(&random, sizeof(random)))
3216 return E_FAIL;
3217 sprintfW(*pbstrResult, fmt, random & 0xfffff);
3218 return S_OK;
3221 static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
3222 VARIANT_BOOL *pfExists)
3224 UINT len;
3225 WCHAR driveletter;
3226 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
3228 if (!pfExists) return E_POINTER;
3230 *pfExists = VARIANT_FALSE;
3231 len = SysStringLen(DriveSpec);
3233 if (len >= 1) {
3234 driveletter = toupperW(DriveSpec[0]);
3235 if (driveletter >= 'A' && driveletter <= 'Z'
3236 && (len < 2 || DriveSpec[1] == ':')
3237 && (len < 3 || DriveSpec[2] == '\\')) {
3238 const WCHAR root[] = {driveletter, ':', '\\', 0};
3239 UINT drivetype = GetDriveTypeW(root);
3240 *pfExists = drivetype != DRIVE_NO_ROOT_DIR && drivetype != DRIVE_UNKNOWN ? VARIANT_TRUE : VARIANT_FALSE;
3244 return S_OK;
3247 static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3249 DWORD attrs;
3250 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3252 if (!ret) return E_POINTER;
3254 attrs = GetFileAttributesW(path);
3255 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3256 return S_OK;
3259 static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3261 DWORD attrs;
3262 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3264 if (!ret) return E_POINTER;
3266 attrs = GetFileAttributesW(path);
3267 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3269 return S_OK;
3272 static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
3273 IDrive **ppdrive)
3275 UINT len;
3276 HRESULT hr;
3277 WCHAR driveletter;
3278 VARIANT_BOOL drive_exists;
3280 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
3282 if (!ppdrive)
3283 return E_POINTER;
3285 *ppdrive = NULL;
3287 /* DriveSpec may be one of: 'x', 'x:', 'x:\', '\\computer\share' */
3288 len = SysStringLen(DriveSpec);
3289 if (!len)
3290 return E_INVALIDARG;
3291 else if (len <= 3) {
3292 driveletter = toupperW(DriveSpec[0]);
3293 if (driveletter < 'A' || driveletter > 'Z'
3294 || (len >= 2 && DriveSpec[1] != ':')
3295 || (len == 3 && DriveSpec[2] != '\\'))
3296 return E_INVALIDARG;
3297 hr = IFileSystem3_DriveExists(iface, DriveSpec, &drive_exists);
3298 if (FAILED(hr))
3299 return hr;
3300 if (drive_exists == VARIANT_FALSE)
3301 return CTL_E_DEVICEUNAVAILABLE;
3302 return create_drive(driveletter, ppdrive);
3303 } else {
3304 if (DriveSpec[0] != '\\' || DriveSpec[1] != '\\')
3305 return E_INVALIDARG;
3306 FIXME("%s not implemented yet\n", debugstr_w(DriveSpec));
3307 return E_NOTIMPL;
3311 static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
3312 IFile **ppfile)
3314 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
3316 if(!ppfile)
3317 return E_POINTER;
3318 if(!FilePath)
3319 return E_INVALIDARG;
3321 return create_file(FilePath, ppfile);
3324 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
3325 IFolder **folder)
3327 DWORD attrs;
3329 TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
3331 if(!folder)
3332 return E_POINTER;
3334 *folder = NULL;
3335 if(!FolderPath)
3336 return E_INVALIDARG;
3338 attrs = GetFileAttributesW(FolderPath);
3339 if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
3340 return CTL_E_PATHNOTFOUND;
3342 return create_folder(FolderPath, folder);
3345 static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
3346 SpecialFolderConst SpecialFolder,
3347 IFolder **folder)
3349 WCHAR pathW[MAX_PATH];
3350 DWORD ret;
3352 TRACE("%p %d %p\n", iface, SpecialFolder, folder);
3354 if (!folder)
3355 return E_POINTER;
3357 *folder = NULL;
3359 switch (SpecialFolder)
3361 case WindowsFolder:
3362 ret = GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
3363 break;
3364 case SystemFolder:
3365 ret = GetSystemDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
3366 break;
3367 case TemporaryFolder:
3368 ret = GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
3369 /* we don't want trailing backslash */
3370 if (ret && pathW[ret-1] == '\\')
3371 pathW[ret-1] = 0;
3372 break;
3373 default:
3374 FIXME("unknown special folder type, %d\n", SpecialFolder);
3375 return E_INVALIDARG;
3378 if (!ret)
3379 return HRESULT_FROM_WIN32(GetLastError());
3381 return create_folder(pathW, folder);
3384 static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
3386 WCHAR path[MAX_PATH];
3387 DWORD len, name_len;
3388 WIN32_FIND_DATAW ffd;
3389 HANDLE f;
3391 f = FindFirstFileW(file, &ffd);
3392 if(f == INVALID_HANDLE_VALUE)
3393 return create_error(GetLastError());
3395 len = get_parent_folder_name(file, file_len);
3396 if(len+1 >= MAX_PATH) {
3397 FindClose(f);
3398 return E_FAIL;
3400 if(len) {
3401 memcpy(path, file, len*sizeof(WCHAR));
3402 path[len++] = '\\';
3405 do {
3406 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3407 continue;
3409 name_len = strlenW(ffd.cFileName);
3410 if(len+name_len+1 >= MAX_PATH) {
3411 FindClose(f);
3412 return E_FAIL;
3414 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3416 TRACE("deleting %s\n", debugstr_w(path));
3418 if(!DeleteFileW(path)) {
3419 if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
3420 || !DeleteFileW(path)) {
3421 FindClose(f);
3422 return create_error(GetLastError());
3425 } while(FindNextFileW(f, &ffd));
3426 FindClose(f);
3428 return S_OK;
3431 static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
3432 VARIANT_BOOL Force)
3434 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
3436 if(!FileSpec)
3437 return E_POINTER;
3439 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
3442 static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
3444 WCHAR path[MAX_PATH];
3445 DWORD len, name_len;
3446 WIN32_FIND_DATAW ffd;
3447 HANDLE f;
3448 HRESULT hr;
3450 f = FindFirstFileW(folder, &ffd);
3451 if(f == INVALID_HANDLE_VALUE)
3452 return create_error(GetLastError());
3454 len = get_parent_folder_name(folder, folder_len);
3455 if(len+1 >= MAX_PATH) {
3456 FindClose(f);
3457 return E_FAIL;
3459 if(len) {
3460 memcpy(path, folder, len*sizeof(WCHAR));
3461 path[len++] = '\\';
3464 do {
3465 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3466 continue;
3467 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3468 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3469 continue;
3471 name_len = strlenW(ffd.cFileName);
3472 if(len+name_len+3 >= MAX_PATH) {
3473 FindClose(f);
3474 return E_FAIL;
3476 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
3477 path[len+name_len] = '\\';
3478 path[len+name_len+1] = '*';
3479 path[len+name_len+2] = 0;
3481 hr = delete_file(path, len+name_len+2, force);
3482 if(FAILED(hr)) {
3483 FindClose(f);
3484 return hr;
3487 hr = delete_folder(path, len+name_len+2, force);
3488 if(FAILED(hr)) {
3489 FindClose(f);
3490 return hr;
3493 path[len+name_len] = 0;
3494 TRACE("deleting %s\n", debugstr_w(path));
3496 if(!RemoveDirectoryW(path)) {
3497 FindClose(f);
3498 return create_error(GetLastError());
3500 } while(FindNextFileW(f, &ffd));
3501 FindClose(f);
3503 return S_OK;
3506 static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
3507 VARIANT_BOOL Force)
3509 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
3511 if(!FolderSpec)
3512 return E_POINTER;
3514 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
3517 static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR Source,
3518 BSTR Destination)
3520 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3522 return E_NOTIMPL;
3525 static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
3526 BSTR Destination)
3528 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3530 return E_NOTIMPL;
3533 static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
3534 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
3536 DWORD attrs;
3537 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
3538 DWORD src_len, dst_len, name_len;
3539 WIN32_FIND_DATAW ffd;
3540 HANDLE f;
3541 HRESULT hr;
3543 if(!source[0] || !destination[0])
3544 return E_INVALIDARG;
3546 attrs = GetFileAttributesW(destination);
3547 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
3548 attrs = GetFileAttributesW(source);
3549 if(attrs == INVALID_FILE_ATTRIBUTES)
3550 return create_error(GetLastError());
3551 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
3552 return CTL_E_FILENOTFOUND;
3554 if(!CopyFileW(source, destination, !overwrite))
3555 return create_error(GetLastError());
3556 return S_OK;
3559 f = FindFirstFileW(source, &ffd);
3560 if(f == INVALID_HANDLE_VALUE)
3561 return CTL_E_FILENOTFOUND;
3563 src_len = get_parent_folder_name(source, source_len);
3564 if(src_len+1 >= MAX_PATH) {
3565 FindClose(f);
3566 return E_FAIL;
3568 if(src_len) {
3569 memcpy(src_path, source, src_len*sizeof(WCHAR));
3570 src_path[src_len++] = '\\';
3573 dst_len = destination_len;
3574 if(dst_len+1 >= MAX_PATH) {
3575 FindClose(f);
3576 return E_FAIL;
3578 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
3579 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
3580 dst_path[dst_len++] = '\\';
3582 hr = CTL_E_FILENOTFOUND;
3583 do {
3584 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3585 continue;
3587 name_len = strlenW(ffd.cFileName);
3588 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
3589 FindClose(f);
3590 return E_FAIL;
3592 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3593 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3595 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
3597 if(!CopyFileW(src_path, dst_path, !overwrite)) {
3598 FindClose(f);
3599 return create_error(GetLastError());
3600 }else {
3601 hr = S_OK;
3603 } while(FindNextFileW(f, &ffd));
3604 FindClose(f);
3606 return hr;
3609 static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
3610 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3612 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3614 if(!Source || !Destination)
3615 return E_POINTER;
3617 return copy_file(Source, SysStringLen(Source), Destination,
3618 SysStringLen(Destination), OverWriteFiles);
3621 static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
3622 DWORD destination_len, VARIANT_BOOL overwrite)
3624 DWORD tmp, src_len, dst_len, name_len;
3625 WCHAR src[MAX_PATH], dst[MAX_PATH];
3626 WIN32_FIND_DATAW ffd;
3627 HANDLE f;
3628 HRESULT hr;
3629 BOOL copied = FALSE;
3631 if(!source[0] || !destination[0])
3632 return E_INVALIDARG;
3634 dst_len = destination_len;
3635 if(dst_len+1 >= MAX_PATH)
3636 return E_FAIL;
3637 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
3639 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
3640 (tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
3641 tmp&FILE_ATTRIBUTE_DIRECTORY) {
3642 if(!CreateDirectoryW(dst, NULL)) {
3643 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3644 tmp = GetFileAttributesW(dst);
3645 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
3646 return CTL_E_FILEALREADYEXISTS;
3647 }else {
3648 return create_error(GetLastError());
3651 copied = TRUE;
3653 src_len = source_len;
3654 if(src_len+2 >= MAX_PATH)
3655 return E_FAIL;
3656 memcpy(src, source, src_len*sizeof(WCHAR));
3657 src[src_len++] = '\\';
3658 src[src_len] = '*';
3659 src[src_len+1] = 0;
3661 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
3662 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
3663 return create_error(GetLastError());
3665 f = FindFirstFileW(src, &ffd);
3666 }else {
3667 src_len = get_parent_folder_name(source, source_len);
3668 if(src_len+2 >= MAX_PATH)
3669 return E_FAIL;
3670 memcpy(src, source, src_len*sizeof(WCHAR));
3671 if(src_len)
3672 src[src_len++] = '\\';
3674 f = FindFirstFileW(source, &ffd);
3676 if(f == INVALID_HANDLE_VALUE)
3677 return CTL_E_PATHNOTFOUND;
3679 dst[dst_len++] = '\\';
3680 dst[dst_len] = 0;
3682 do {
3683 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3684 continue;
3685 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3686 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3687 continue;
3689 name_len = strlenW(ffd.cFileName);
3690 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
3691 FindClose(f);
3692 return E_FAIL;
3694 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
3695 dst[dst_len+name_len] = 0;
3696 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
3697 src[src_len+name_len] = '\\';
3698 src[src_len+name_len+1] = '*';
3699 src[src_len+name_len+2] = 0;
3701 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
3703 if(!CreateDirectoryW(dst, NULL)) {
3704 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3705 tmp = GetFileAttributesW(dst);
3706 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
3707 FindClose(f);
3708 return CTL_E_FILEALREADYEXISTS;
3712 FindClose(f);
3713 return create_error(GetLastError());
3715 copied = TRUE;
3717 hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3718 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
3719 FindClose(f);
3720 return hr;
3723 hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3724 if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
3725 FindClose(f);
3726 return hr;
3728 } while(FindNextFileW(f, &ffd));
3729 FindClose(f);
3731 return copied ? S_OK : CTL_E_PATHNOTFOUND;
3734 static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
3735 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3737 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3739 if(!Source || !Destination)
3740 return E_POINTER;
3742 return copy_folder(Source, SysStringLen(Source), Destination,
3743 SysStringLen(Destination), OverWriteFiles);
3746 static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
3747 IFolder **folder)
3749 BOOL ret;
3751 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
3753 ret = CreateDirectoryW(path, NULL);
3754 if (!ret)
3756 *folder = NULL;
3757 if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
3758 return HRESULT_FROM_WIN32(GetLastError());
3761 return create_folder(path, folder);
3764 static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR filename,
3765 VARIANT_BOOL overwrite, VARIANT_BOOL unicode,
3766 ITextStream **stream)
3768 DWORD disposition;
3770 TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
3772 disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
3773 return create_textstream(filename, disposition, ForWriting, !!unicode, stream);
3776 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
3777 IOMode mode, VARIANT_BOOL create,
3778 Tristate format, ITextStream **stream)
3780 DWORD disposition;
3782 TRACE("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
3783 disposition = create == VARIANT_TRUE ? OPEN_ALWAYS : OPEN_EXISTING;
3785 if (format == TristateUseDefault) {
3786 FIXME("default format not handled, defaulting to unicode\n");
3787 format = TristateTrue;
3790 return create_textstream(filename, disposition, mode, format == TristateTrue, stream);
3793 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
3794 StandardStreamTypes StandardStreamType,
3795 VARIANT_BOOL Unicode,
3796 ITextStream **ppts)
3798 FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
3800 return E_NOTIMPL;
3803 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
3805 static const WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
3806 DWORDLONG version;
3807 WORD a, b, c, d;
3809 version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
3810 a = (WORD)( version >> 48);
3811 b = (WORD)((version >> 32) & 0xffff);
3812 c = (WORD)((version >> 16) & 0xffff);
3813 d = (WORD)( version & 0xffff);
3815 sprintfW(ver, fmtW, a, b, c, d);
3818 static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
3820 static const WCHAR rootW[] = {'\\',0};
3821 VS_FIXEDFILEINFO *info;
3822 WCHAR ver[30];
3823 void *ptr;
3824 DWORD len;
3825 BOOL ret;
3827 TRACE("%p %s %p\n", iface, debugstr_w(name), version);
3829 len = GetFileVersionInfoSizeW(name, NULL);
3830 if (!len)
3831 return HRESULT_FROM_WIN32(GetLastError());
3833 ptr = heap_alloc(len);
3834 if (!GetFileVersionInfoW(name, 0, len, ptr))
3836 heap_free(ptr);
3837 return HRESULT_FROM_WIN32(GetLastError());
3840 ret = VerQueryValueW(ptr, rootW, (void**)&info, &len);
3841 if (!ret)
3843 heap_free(ptr);
3844 return HRESULT_FROM_WIN32(GetLastError());
3847 get_versionstring(info, ver);
3848 heap_free(ptr);
3850 *version = SysAllocString(ver);
3851 TRACE("version=%s\n", debugstr_w(ver));
3853 return S_OK;
3856 static const struct IFileSystem3Vtbl filesys_vtbl =
3858 filesys_QueryInterface,
3859 filesys_AddRef,
3860 filesys_Release,
3861 filesys_GetTypeInfoCount,
3862 filesys_GetTypeInfo,
3863 filesys_GetIDsOfNames,
3864 filesys_Invoke,
3865 filesys_get_Drives,
3866 filesys_BuildPath,
3867 filesys_GetDriveName,
3868 filesys_GetParentFolderName,
3869 filesys_GetFileName,
3870 filesys_GetBaseName,
3871 filesys_GetExtensionName,
3872 filesys_GetAbsolutePathName,
3873 filesys_GetTempName,
3874 filesys_DriveExists,
3875 filesys_FileExists,
3876 filesys_FolderExists,
3877 filesys_GetDrive,
3878 filesys_GetFile,
3879 filesys_GetFolder,
3880 filesys_GetSpecialFolder,
3881 filesys_DeleteFile,
3882 filesys_DeleteFolder,
3883 filesys_MoveFile,
3884 filesys_MoveFolder,
3885 filesys_CopyFile,
3886 filesys_CopyFolder,
3887 filesys_CreateFolder,
3888 filesys_CreateTextFile,
3889 filesys_OpenTextFile,
3890 filesys_GetStandardStream,
3891 filesys_GetFileVersion
3894 static IFileSystem3 filesystem = { &filesys_vtbl };
3896 HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
3898 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
3900 return IFileSystem3_QueryInterface(&filesystem, riid, ppv);