scrrun: Implement GetDriveName().
[wine.git] / dlls / scrrun / filesystem.c
blobc85fe63e1c3293f177de1933c58cdafdf8e355d8
1 /*
2 * Copyright 2012 Alistair Leslie-Hughes
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include "config.h"
22 #include <stdarg.h>
23 #include <limits.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "ole2.h"
28 #include "olectl.h"
29 #include "dispex.h"
30 #include "ntsecapi.h"
31 #include "scrrun.h"
32 #include "scrrun_private.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(scrrun);
39 static const WCHAR bsW[] = {'\\',0};
40 static const WCHAR utf16bom = 0xfeff;
42 struct foldercollection {
43 IFolderCollection IFolderCollection_iface;
44 LONG ref;
45 BSTR path;
48 struct filecollection {
49 IFileCollection IFileCollection_iface;
50 LONG ref;
51 BSTR path;
54 struct drivecollection {
55 IDriveCollection IDriveCollection_iface;
56 LONG ref;
57 DWORD drives;
58 LONG count;
61 struct enumdata {
62 union
64 struct
66 struct foldercollection *coll;
67 HANDLE find;
68 } foldercoll;
69 struct
71 struct filecollection *coll;
72 HANDLE find;
73 } filecoll;
74 struct
76 struct drivecollection *coll;
77 INT cur;
78 } drivecoll;
79 } u;
82 struct enumvariant {
83 IEnumVARIANT IEnumVARIANT_iface;
84 LONG ref;
86 struct enumdata data;
89 struct drive {
90 IDrive IDrive_iface;
91 LONG ref;
92 BSTR root;
95 struct folder {
96 IFolder IFolder_iface;
97 LONG ref;
98 BSTR path;
101 struct file {
102 IFile IFile_iface;
103 LONG ref;
105 WCHAR *path;
108 struct textstream {
109 ITextStream ITextStream_iface;
110 LONG ref;
112 IOMode mode;
113 BOOL unicode;
114 BOOL first_read;
115 LARGE_INTEGER size;
116 HANDLE file;
119 enum iotype {
120 IORead,
121 IOWrite
124 static inline struct drive *impl_from_IDrive(IDrive *iface)
126 return CONTAINING_RECORD(iface, struct drive, IDrive_iface);
129 static inline struct folder *impl_from_IFolder(IFolder *iface)
131 return CONTAINING_RECORD(iface, struct folder, IFolder_iface);
134 static inline struct file *impl_from_IFile(IFile *iface)
136 return CONTAINING_RECORD(iface, struct file, IFile_iface);
139 static inline struct textstream *impl_from_ITextStream(ITextStream *iface)
141 return CONTAINING_RECORD(iface, struct textstream, ITextStream_iface);
144 static inline struct foldercollection *impl_from_IFolderCollection(IFolderCollection *iface)
146 return CONTAINING_RECORD(iface, struct foldercollection, IFolderCollection_iface);
149 static inline struct filecollection *impl_from_IFileCollection(IFileCollection *iface)
151 return CONTAINING_RECORD(iface, struct filecollection, IFileCollection_iface);
154 static inline struct drivecollection *impl_from_IDriveCollection(IDriveCollection *iface)
156 return CONTAINING_RECORD(iface, struct drivecollection, IDriveCollection_iface);
159 static inline struct enumvariant *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
161 return CONTAINING_RECORD(iface, struct enumvariant, IEnumVARIANT_iface);
164 static inline HRESULT create_error(DWORD err)
166 switch(err) {
167 case ERROR_FILE_NOT_FOUND: return CTL_E_FILENOTFOUND;
168 case ERROR_PATH_NOT_FOUND: return CTL_E_PATHNOTFOUND;
169 case ERROR_ACCESS_DENIED: return CTL_E_PERMISSIONDENIED;
170 case ERROR_FILE_EXISTS: return CTL_E_FILEALREADYEXISTS;
171 case ERROR_ALREADY_EXISTS: return CTL_E_FILEALREADYEXISTS;
172 default:
173 FIXME("Unsupported error code: %d\n", err);
174 return E_FAIL;
178 static HRESULT create_folder(const WCHAR*, IFolder**);
179 static HRESULT create_file(BSTR, IFile**);
180 static HRESULT create_foldercoll_enum(struct foldercollection*, IUnknown**);
181 static HRESULT create_filecoll_enum(struct filecollection*, IUnknown**);
183 static inline BOOL is_dir_data(const WIN32_FIND_DATAW *data)
185 static const WCHAR dotdotW[] = {'.','.',0};
186 static const WCHAR dotW[] = {'.',0};
188 return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
189 strcmpW(data->cFileName, dotdotW) &&
190 strcmpW(data->cFileName, dotW);
193 static inline BOOL is_file_data(const WIN32_FIND_DATAW *data)
195 return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
198 static BSTR get_full_path(BSTR path, const WIN32_FIND_DATAW *data)
200 int len = SysStringLen(path);
201 WCHAR buffW[MAX_PATH];
203 strcpyW(buffW, path);
204 if (path[len-1] != '\\')
205 strcatW(buffW, bsW);
206 strcatW(buffW, data->cFileName);
208 return SysAllocString(buffW);
211 static BOOL textstream_check_iomode(struct textstream *This, enum iotype type)
213 if (type == IORead)
214 return This->mode == ForWriting || This->mode == ForAppending;
215 else
216 return This->mode == ForReading;
219 static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
221 struct textstream *This = impl_from_ITextStream(iface);
223 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
225 if (IsEqualIID(riid, &IID_ITextStream) ||
226 IsEqualIID(riid, &IID_IDispatch) ||
227 IsEqualIID(riid, &IID_IUnknown))
229 *obj = iface;
230 ITextStream_AddRef(iface);
231 return S_OK;
234 *obj = NULL;
235 return E_NOINTERFACE;
238 static ULONG WINAPI textstream_AddRef(ITextStream *iface)
240 struct textstream *This = impl_from_ITextStream(iface);
241 ULONG ref = InterlockedIncrement(&This->ref);
242 TRACE("(%p)->(%d)\n", This, ref);
243 return ref;
246 static ULONG WINAPI textstream_Release(ITextStream *iface)
248 struct textstream *This = impl_from_ITextStream(iface);
249 ULONG ref = InterlockedDecrement(&This->ref);
250 TRACE("(%p)->(%d)\n", This, ref);
252 if (!ref)
254 CloseHandle(This->file);
255 heap_free(This);
258 return ref;
261 static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
263 struct textstream *This = impl_from_ITextStream(iface);
264 TRACE("(%p)->(%p)\n", This, pctinfo);
265 *pctinfo = 1;
266 return S_OK;
269 static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
270 LCID lcid, ITypeInfo **ppTInfo)
272 struct textstream *This = impl_from_ITextStream(iface);
273 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
274 return get_typeinfo(ITextStream_tid, ppTInfo);
277 static HRESULT WINAPI textstream_GetIDsOfNames(ITextStream *iface, REFIID riid,
278 LPOLESTR *rgszNames, UINT cNames,
279 LCID lcid, DISPID *rgDispId)
281 struct textstream *This = impl_from_ITextStream(iface);
282 ITypeInfo *typeinfo;
283 HRESULT hr;
285 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
287 hr = get_typeinfo(ITextStream_tid, &typeinfo);
288 if(SUCCEEDED(hr))
290 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
291 ITypeInfo_Release(typeinfo);
294 return hr;
297 static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
298 REFIID riid, LCID lcid, WORD wFlags,
299 DISPPARAMS *pDispParams, VARIANT *pVarResult,
300 EXCEPINFO *pExcepInfo, UINT *puArgErr)
302 struct textstream *This = impl_from_ITextStream(iface);
303 ITypeInfo *typeinfo;
304 HRESULT hr;
306 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
307 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
309 hr = get_typeinfo(ITextStream_tid, &typeinfo);
310 if(SUCCEEDED(hr))
312 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
313 pDispParams, pVarResult, pExcepInfo, puArgErr);
314 ITypeInfo_Release(typeinfo);
317 return hr;
320 static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
322 struct textstream *This = impl_from_ITextStream(iface);
323 FIXME("(%p)->(%p): stub\n", This, line);
324 return E_NOTIMPL;
327 static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
329 struct textstream *This = impl_from_ITextStream(iface);
330 FIXME("(%p)->(%p): stub\n", This, column);
331 return E_NOTIMPL;
334 static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
336 struct textstream *This = impl_from_ITextStream(iface);
337 LARGE_INTEGER pos, dist;
339 TRACE("(%p)->(%p)\n", This, eos);
341 if (!eos)
342 return E_POINTER;
344 if (textstream_check_iomode(This, IORead)) {
345 *eos = VARIANT_TRUE;
346 return CTL_E_BADFILEMODE;
349 dist.QuadPart = 0;
350 if (!SetFilePointerEx(This->file, dist, &pos, FILE_CURRENT))
351 return E_FAIL;
353 *eos = This->size.QuadPart == pos.QuadPart ? VARIANT_TRUE : VARIANT_FALSE;
354 return S_OK;
357 static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOOL *eol)
359 struct textstream *This = impl_from_ITextStream(iface);
360 FIXME("(%p)->(%p): stub\n", This, eol);
361 return E_NOTIMPL;
365 Reads 'toread' bytes from a file, converts if needed
366 BOM is skipped if 'bof' is set.
368 static HRESULT textstream_read(struct textstream *stream, LONG toread, BOOL bof, BSTR *text)
370 HRESULT hr = S_OK;
371 DWORD read;
372 char *buff;
373 BOOL ret;
375 if (toread == 0) {
376 *text = SysAllocStringLen(NULL, 0);
377 return *text ? S_FALSE : E_OUTOFMEMORY;
380 if (toread < sizeof(WCHAR))
381 return CTL_E_ENDOFFILE;
383 buff = heap_alloc(toread);
384 if (!buff)
385 return E_OUTOFMEMORY;
387 ret = ReadFile(stream->file, buff, toread, &read, NULL);
388 if (!ret || toread != read) {
389 WARN("failed to read from file %d, %d, error %d\n", read, toread, GetLastError());
390 heap_free(buff);
391 return E_FAIL;
394 if (stream->unicode) {
395 int i = 0;
397 /* skip BOM */
398 if (bof && *(WCHAR*)buff == utf16bom) {
399 read -= sizeof(WCHAR);
400 i += sizeof(WCHAR);
403 *text = SysAllocStringLen(read ? (WCHAR*)&buff[i] : NULL, read/sizeof(WCHAR));
404 if (!*text) hr = E_OUTOFMEMORY;
406 else {
407 INT len = MultiByteToWideChar(CP_ACP, 0, buff, read, NULL, 0);
408 *text = SysAllocStringLen(NULL, len);
409 if (*text)
410 MultiByteToWideChar(CP_ACP, 0, buff, read, *text, len);
411 else
412 hr = E_OUTOFMEMORY;
414 heap_free(buff);
416 return hr;
419 static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
421 struct textstream *This = impl_from_ITextStream(iface);
422 LARGE_INTEGER start, end, dist;
423 DWORD toread;
424 HRESULT hr;
426 TRACE("(%p)->(%d %p)\n", This, len, text);
428 if (!text)
429 return E_POINTER;
431 *text = NULL;
432 if (len <= 0)
433 return len == 0 ? S_OK : E_INVALIDARG;
435 if (textstream_check_iomode(This, IORead))
436 return CTL_E_BADFILEMODE;
438 if (!This->first_read) {
439 VARIANT_BOOL eos;
441 /* check for EOF */
442 hr = ITextStream_get_AtEndOfStream(iface, &eos);
443 if (FAILED(hr))
444 return hr;
446 if (eos == VARIANT_TRUE)
447 return CTL_E_ENDOFFILE;
450 /* read everything from current position */
451 dist.QuadPart = 0;
452 SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
453 SetFilePointerEx(This->file, dist, &end, FILE_END);
454 toread = end.QuadPart - start.QuadPart;
455 /* rewind back */
456 dist.QuadPart = start.QuadPart;
457 SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
459 This->first_read = FALSE;
460 if (This->unicode) len *= sizeof(WCHAR);
462 hr = textstream_read(This, min(toread, len), start.QuadPart == 0, text);
463 if (FAILED(hr))
464 return hr;
465 else
466 return toread <= len ? S_FALSE : S_OK;
469 static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
471 struct textstream *This = impl_from_ITextStream(iface);
472 VARIANT_BOOL eos;
473 HRESULT hr;
475 FIXME("(%p)->(%p): stub\n", This, text);
477 if (!text)
478 return E_POINTER;
480 *text = NULL;
481 if (textstream_check_iomode(This, IORead))
482 return CTL_E_BADFILEMODE;
484 /* check for EOF */
485 hr = ITextStream_get_AtEndOfStream(iface, &eos);
486 if (FAILED(hr))
487 return hr;
489 if (eos == VARIANT_TRUE)
490 return CTL_E_ENDOFFILE;
492 return E_NOTIMPL;
495 static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
497 struct textstream *This = impl_from_ITextStream(iface);
498 LARGE_INTEGER start, end, dist;
499 DWORD toread;
500 HRESULT hr;
502 TRACE("(%p)->(%p)\n", This, text);
504 if (!text)
505 return E_POINTER;
507 *text = NULL;
508 if (textstream_check_iomode(This, IORead))
509 return CTL_E_BADFILEMODE;
511 if (!This->first_read) {
512 VARIANT_BOOL eos;
514 /* check for EOF */
515 hr = ITextStream_get_AtEndOfStream(iface, &eos);
516 if (FAILED(hr))
517 return hr;
519 if (eos == VARIANT_TRUE)
520 return CTL_E_ENDOFFILE;
523 /* read everything from current position */
524 dist.QuadPart = 0;
525 SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
526 SetFilePointerEx(This->file, dist, &end, FILE_END);
527 toread = end.QuadPart - start.QuadPart;
528 /* rewind back */
529 dist.QuadPart = start.QuadPart;
530 SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
532 This->first_read = FALSE;
534 hr = textstream_read(This, toread, start.QuadPart == 0, text);
535 return FAILED(hr) ? hr : S_FALSE;
538 static HRESULT textstream_writestr(struct textstream *stream, BSTR text)
540 DWORD written = 0;
541 BOOL ret;
543 if (stream->unicode) {
544 ret = WriteFile(stream->file, text, SysStringByteLen(text), &written, NULL);
545 return (ret && written == SysStringByteLen(text)) ? S_OK : create_error(GetLastError());
546 } else {
547 DWORD len = WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), NULL, 0, NULL, NULL);
548 char *buffA;
549 HRESULT hr;
551 buffA = heap_alloc(len);
552 if (!buffA)
553 return E_OUTOFMEMORY;
555 WideCharToMultiByte(CP_ACP, 0, text, SysStringLen(text), buffA, len, NULL, NULL);
556 ret = WriteFile(stream->file, buffA, len, &written, NULL);
557 hr = (ret && written == len) ? S_OK : create_error(GetLastError());
558 heap_free(buffA);
559 return hr;
563 static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
565 struct textstream *This = impl_from_ITextStream(iface);
567 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
569 if (textstream_check_iomode(This, IOWrite))
570 return CTL_E_BADFILEMODE;
572 return textstream_writestr(This, text);
575 static HRESULT textstream_writecrlf(struct textstream *stream)
577 static const WCHAR crlfW[] = {'\r','\n'};
578 static const char crlfA[] = {'\r','\n'};
579 DWORD written = 0, len;
580 const void *ptr;
581 BOOL ret;
583 if (stream->unicode) {
584 ptr = crlfW;
585 len = sizeof(crlfW);
587 else {
588 ptr = crlfA;
589 len = sizeof(crlfA);
592 ret = WriteFile(stream->file, ptr, len, &written, NULL);
593 return (ret && written == len) ? S_OK : create_error(GetLastError());
596 static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
598 struct textstream *This = impl_from_ITextStream(iface);
599 HRESULT hr;
601 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
603 if (textstream_check_iomode(This, IOWrite))
604 return CTL_E_BADFILEMODE;
606 hr = textstream_writestr(This, text);
607 if (SUCCEEDED(hr))
608 hr = textstream_writecrlf(This);
609 return hr;
612 static HRESULT WINAPI textstream_WriteBlankLines(ITextStream *iface, LONG lines)
614 struct textstream *This = impl_from_ITextStream(iface);
615 FIXME("(%p)->(%d): stub\n", This, lines);
616 return E_NOTIMPL;
619 static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
621 struct textstream *This = impl_from_ITextStream(iface);
622 FIXME("(%p)->(%d): stub\n", This, count);
623 return E_NOTIMPL;
626 static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
628 struct textstream *This = impl_from_ITextStream(iface);
629 FIXME("(%p): stub\n", This);
630 return E_NOTIMPL;
633 static HRESULT WINAPI textstream_Close(ITextStream *iface)
635 struct textstream *This = impl_from_ITextStream(iface);
636 FIXME("(%p): stub\n", This);
637 return E_NOTIMPL;
640 static const ITextStreamVtbl textstreamvtbl = {
641 textstream_QueryInterface,
642 textstream_AddRef,
643 textstream_Release,
644 textstream_GetTypeInfoCount,
645 textstream_GetTypeInfo,
646 textstream_GetIDsOfNames,
647 textstream_Invoke,
648 textstream_get_Line,
649 textstream_get_Column,
650 textstream_get_AtEndOfStream,
651 textstream_get_AtEndOfLine,
652 textstream_Read,
653 textstream_ReadLine,
654 textstream_ReadAll,
655 textstream_Write,
656 textstream_WriteLine,
657 textstream_WriteBlankLines,
658 textstream_Skip,
659 textstream_SkipLine,
660 textstream_Close
663 static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMode mode, BOOL unicode, ITextStream **ret)
665 struct textstream *stream;
666 DWORD access = 0;
668 /* map access mode */
669 switch (mode)
671 case ForReading:
672 access = GENERIC_READ;
673 break;
674 case ForWriting:
675 access = GENERIC_WRITE;
676 break;
677 case ForAppending:
678 access = FILE_APPEND_DATA;
679 break;
680 default:
681 return E_INVALIDARG;
684 stream = heap_alloc(sizeof(struct textstream));
685 if (!stream) return E_OUTOFMEMORY;
687 stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
688 stream->ref = 1;
689 stream->mode = mode;
690 stream->unicode = unicode;
691 stream->first_read = TRUE;
693 stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
694 if (stream->file == INVALID_HANDLE_VALUE)
696 HRESULT hr = create_error(GetLastError());
697 heap_free(stream);
698 return hr;
701 if (mode == ForReading)
702 GetFileSizeEx(stream->file, &stream->size);
703 else
704 stream->size.QuadPart = 0;
706 /* Write Unicode BOM */
707 if (unicode && mode == ForWriting && (disposition == CREATE_ALWAYS || disposition == CREATE_NEW)) {
708 DWORD written = 0;
709 BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL);
710 if (!ret || written != sizeof(utf16bom)) {
711 ITextStream_Release(&stream->ITextStream_iface);
712 return create_error(GetLastError());
716 *ret = &stream->ITextStream_iface;
717 return S_OK;
720 static HRESULT WINAPI drive_QueryInterface(IDrive *iface, REFIID riid, void **obj)
722 struct drive *This = impl_from_IDrive(iface);
724 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
726 *obj = NULL;
728 if (IsEqualIID( riid, &IID_IDrive ) ||
729 IsEqualIID( riid, &IID_IDispatch ) ||
730 IsEqualIID( riid, &IID_IUnknown))
732 *obj = iface;
733 IDrive_AddRef(iface);
735 else
736 return E_NOINTERFACE;
738 return S_OK;
741 static ULONG WINAPI drive_AddRef(IDrive *iface)
743 struct drive *This = impl_from_IDrive(iface);
744 ULONG ref = InterlockedIncrement(&This->ref);
745 TRACE("(%p)->(%d)\n", This, ref);
746 return ref;
749 static ULONG WINAPI drive_Release(IDrive *iface)
751 struct drive *This = impl_from_IDrive(iface);
752 ULONG ref = InterlockedDecrement(&This->ref);
753 TRACE("(%p)->(%d)\n", This, ref);
755 if (!ref)
757 SysFreeString(This->root);
758 heap_free(This);
761 return ref;
764 static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo)
766 struct drive *This = impl_from_IDrive(iface);
767 TRACE("(%p)->(%p)\n", This, pctinfo);
768 *pctinfo = 1;
769 return S_OK;
772 static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo,
773 LCID lcid, ITypeInfo **ppTInfo)
775 struct drive *This = impl_from_IDrive(iface);
776 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
777 return get_typeinfo(IDrive_tid, ppTInfo);
780 static HRESULT WINAPI drive_GetIDsOfNames(IDrive *iface, REFIID riid,
781 LPOLESTR *rgszNames, UINT cNames,
782 LCID lcid, DISPID *rgDispId)
784 struct drive *This = impl_from_IDrive(iface);
785 ITypeInfo *typeinfo;
786 HRESULT hr;
788 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
790 hr = get_typeinfo(IDrive_tid, &typeinfo);
791 if(SUCCEEDED(hr))
793 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
794 ITypeInfo_Release(typeinfo);
797 return hr;
800 static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember,
801 REFIID riid, LCID lcid, WORD wFlags,
802 DISPPARAMS *pDispParams, VARIANT *pVarResult,
803 EXCEPINFO *pExcepInfo, UINT *puArgErr)
805 struct drive *This = impl_from_IDrive(iface);
806 ITypeInfo *typeinfo;
807 HRESULT hr;
809 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
810 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
812 hr = get_typeinfo(IDrive_tid, &typeinfo);
813 if(SUCCEEDED(hr))
815 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
816 pDispParams, pVarResult, pExcepInfo, puArgErr);
817 ITypeInfo_Release(typeinfo);
820 return hr;
823 static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path)
825 struct drive *This = impl_from_IDrive(iface);
826 FIXME("(%p)->(%p): stub\n", This, path);
827 return E_NOTIMPL;
830 static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter)
832 struct drive *This = impl_from_IDrive(iface);
834 TRACE("(%p)->(%p)\n", This, letter);
836 if (!letter)
837 return E_POINTER;
839 *letter = SysAllocStringLen(This->root, 1);
840 if (!*letter)
841 return E_OUTOFMEMORY;
843 return S_OK;
846 static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name)
848 struct drive *This = impl_from_IDrive(iface);
849 FIXME("(%p)->(%p): stub\n", This, share_name);
850 return E_NOTIMPL;
853 static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type)
855 struct drive *This = impl_from_IDrive(iface);
857 TRACE("(%p)->(%p)\n", This, type);
859 switch (GetDriveTypeW(This->root))
861 case DRIVE_REMOVABLE:
862 *type = Removable;
863 break;
864 case DRIVE_FIXED:
865 *type = Fixed;
866 break;
867 case DRIVE_REMOTE:
868 *type = Remote;
869 break;
870 case DRIVE_CDROM:
871 *type = CDRom;
872 break;
873 case DRIVE_RAMDISK:
874 *type = RamDisk;
875 break;
876 default:
877 *type = UnknownType;
878 break;
881 return S_OK;
884 static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder)
886 struct drive *This = impl_from_IDrive(iface);
887 FIXME("(%p)->(%p): stub\n", This, folder);
888 return E_NOTIMPL;
891 static HRESULT variant_from_largeint(const ULARGE_INTEGER *src, VARIANT *v)
893 HRESULT hr = S_OK;
895 if (src->u.HighPart || src->u.LowPart > INT_MAX)
897 V_VT(v) = VT_R8;
898 hr = VarR8FromUI8(src->QuadPart, &V_R8(v));
900 else
902 V_VT(v) = VT_I4;
903 V_I4(v) = src->u.LowPart;
906 return hr;
909 static HRESULT WINAPI drive_get_AvailableSpace(IDrive *iface, VARIANT *v)
911 struct drive *This = impl_from_IDrive(iface);
912 ULARGE_INTEGER avail;
914 TRACE("(%p)->(%p)\n", This, v);
916 if (!v)
917 return E_POINTER;
919 if (!GetDiskFreeSpaceExW(This->root, &avail, NULL, NULL))
920 return E_FAIL;
922 return variant_from_largeint(&avail, v);
925 static HRESULT WINAPI drive_get_FreeSpace(IDrive *iface, VARIANT *v)
927 struct drive *This = impl_from_IDrive(iface);
928 ULARGE_INTEGER freespace;
930 TRACE("(%p)->(%p)\n", This, v);
932 if (!v)
933 return E_POINTER;
935 if (!GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL))
936 return E_FAIL;
938 return variant_from_largeint(&freespace, v);
941 static HRESULT WINAPI drive_get_TotalSize(IDrive *iface, VARIANT *v)
943 struct drive *This = impl_from_IDrive(iface);
944 ULARGE_INTEGER total;
946 TRACE("(%p)->(%p)\n", This, v);
948 if (!v)
949 return E_POINTER;
951 if (!GetDiskFreeSpaceExW(This->root, NULL, &total, NULL))
952 return E_FAIL;
954 return variant_from_largeint(&total, v);
957 static HRESULT WINAPI drive_get_VolumeName(IDrive *iface, BSTR *name)
959 struct drive *This = impl_from_IDrive(iface);
960 FIXME("(%p)->(%p): stub\n", This, name);
961 return E_NOTIMPL;
964 static HRESULT WINAPI drive_put_VolumeName(IDrive *iface, BSTR name)
966 struct drive *This = impl_from_IDrive(iface);
967 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
968 return E_NOTIMPL;
971 static HRESULT WINAPI drive_get_FileSystem(IDrive *iface, BSTR *fs)
973 struct drive *This = impl_from_IDrive(iface);
974 FIXME("(%p)->(%p): stub\n", This, fs);
975 return E_NOTIMPL;
978 static HRESULT WINAPI drive_get_SerialNumber(IDrive *iface, LONG *serial)
980 struct drive *This = impl_from_IDrive(iface);
981 FIXME("(%p)->(%p): stub\n", This, serial);
982 return E_NOTIMPL;
985 static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
987 struct drive *This = impl_from_IDrive(iface);
988 ULARGE_INTEGER freespace;
989 BOOL ret;
991 TRACE("(%p)->(%p)\n", This, ready);
993 if (!ready)
994 return E_POINTER;
996 ret = GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL);
997 *ready = ret ? VARIANT_TRUE : VARIANT_FALSE;
998 return S_OK;
1001 static const IDriveVtbl drivevtbl = {
1002 drive_QueryInterface,
1003 drive_AddRef,
1004 drive_Release,
1005 drive_GetTypeInfoCount,
1006 drive_GetTypeInfo,
1007 drive_GetIDsOfNames,
1008 drive_Invoke,
1009 drive_get_Path,
1010 drive_get_DriveLetter,
1011 drive_get_ShareName,
1012 drive_get_DriveType,
1013 drive_get_RootFolder,
1014 drive_get_AvailableSpace,
1015 drive_get_FreeSpace,
1016 drive_get_TotalSize,
1017 drive_get_VolumeName,
1018 drive_put_VolumeName,
1019 drive_get_FileSystem,
1020 drive_get_SerialNumber,
1021 drive_get_IsReady
1024 static HRESULT create_drive(WCHAR letter, IDrive **drive)
1026 struct drive *This;
1028 *drive = NULL;
1030 This = heap_alloc(sizeof(*This));
1031 if (!This) return E_OUTOFMEMORY;
1033 This->IDrive_iface.lpVtbl = &drivevtbl;
1034 This->ref = 1;
1035 This->root = SysAllocStringLen(NULL, 3);
1036 if (!This->root)
1038 heap_free(This);
1039 return E_OUTOFMEMORY;
1041 This->root[0] = letter;
1042 This->root[1] = ':';
1043 This->root[2] = '\\';
1044 This->root[3] = 0;
1046 *drive = &This->IDrive_iface;
1047 return S_OK;
1050 static HRESULT WINAPI enumvariant_QueryInterface(IEnumVARIANT *iface, REFIID riid, void **obj)
1052 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1054 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1056 *obj = NULL;
1058 if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
1059 IsEqualIID( riid, &IID_IUnknown ))
1061 *obj = iface;
1062 IEnumVARIANT_AddRef(iface);
1064 else
1065 return E_NOINTERFACE;
1067 return S_OK;
1070 static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface)
1072 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1073 ULONG ref = InterlockedIncrement(&This->ref);
1074 TRACE("(%p)->(%d)\n", This, ref);
1075 return ref;
1078 static ULONG WINAPI foldercoll_enumvariant_Release(IEnumVARIANT *iface)
1080 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1081 ULONG ref = InterlockedDecrement(&This->ref);
1083 TRACE("(%p)->(%d)\n", This, ref);
1085 if (!ref)
1087 IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
1088 FindClose(This->data.u.foldercoll.find);
1089 heap_free(This);
1092 return ref;
1095 static HANDLE start_enumeration(const WCHAR *path, WIN32_FIND_DATAW *data, BOOL file)
1097 static const WCHAR allW[] = {'*',0};
1098 WCHAR pathW[MAX_PATH];
1099 int len;
1100 HANDLE handle;
1102 strcpyW(pathW, path);
1103 len = strlenW(pathW);
1104 if (pathW[len-1] != '\\')
1105 strcatW(pathW, bsW);
1106 strcatW(pathW, allW);
1107 handle = FindFirstFileW(pathW, data);
1108 if (handle == INVALID_HANDLE_VALUE) return 0;
1110 /* find first dir/file */
1111 while (1)
1113 if (file ? is_file_data(data) : is_dir_data(data))
1114 break;
1116 if (!FindNextFileW(handle, data))
1118 FindClose(handle);
1119 return 0;
1122 return handle;
1125 static HRESULT WINAPI foldercoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1127 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1128 HANDLE handle = This->data.u.foldercoll.find;
1129 WIN32_FIND_DATAW data;
1130 ULONG count = 0;
1132 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1134 if (fetched)
1135 *fetched = 0;
1137 if (!celt) return S_OK;
1139 if (!handle)
1141 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1142 if (!handle) return S_FALSE;
1144 This->data.u.foldercoll.find = handle;
1146 else
1148 if (!FindNextFileW(handle, &data))
1149 return S_FALSE;
1154 if (is_dir_data(&data))
1156 IFolder *folder;
1157 HRESULT hr;
1158 BSTR str;
1160 str = get_full_path(This->data.u.foldercoll.coll->path, &data);
1161 hr = create_folder(str, &folder);
1162 SysFreeString(str);
1163 if (FAILED(hr)) return hr;
1165 V_VT(&var[count]) = VT_DISPATCH;
1166 V_DISPATCH(&var[count]) = (IDispatch*)folder;
1167 count++;
1169 if (count >= celt) break;
1171 } while (FindNextFileW(handle, &data));
1173 if (fetched)
1174 *fetched = count;
1176 return (count < celt) ? S_FALSE : S_OK;
1179 static HRESULT WINAPI foldercoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1181 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1182 HANDLE handle = This->data.u.foldercoll.find;
1183 WIN32_FIND_DATAW data;
1185 TRACE("(%p)->(%d)\n", This, celt);
1187 if (!celt) return S_OK;
1189 if (!handle)
1191 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1192 if (!handle) return S_FALSE;
1194 This->data.u.foldercoll.find = handle;
1196 else
1198 if (!FindNextFileW(handle, &data))
1199 return S_FALSE;
1204 if (is_dir_data(&data))
1205 --celt;
1207 if (!celt) break;
1208 } while (FindNextFileW(handle, &data));
1210 return celt ? S_FALSE : S_OK;
1213 static HRESULT WINAPI foldercoll_enumvariant_Reset(IEnumVARIANT *iface)
1215 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1217 TRACE("(%p)\n", This);
1219 FindClose(This->data.u.foldercoll.find);
1220 This->data.u.foldercoll.find = NULL;
1222 return S_OK;
1225 static HRESULT WINAPI foldercoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1227 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1228 TRACE("(%p)->(%p)\n", This, pclone);
1229 return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
1232 static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
1233 enumvariant_QueryInterface,
1234 enumvariant_AddRef,
1235 foldercoll_enumvariant_Release,
1236 foldercoll_enumvariant_Next,
1237 foldercoll_enumvariant_Skip,
1238 foldercoll_enumvariant_Reset,
1239 foldercoll_enumvariant_Clone
1242 static HRESULT create_foldercoll_enum(struct foldercollection *collection, IUnknown **newenum)
1244 struct enumvariant *This;
1246 *newenum = NULL;
1248 This = heap_alloc(sizeof(*This));
1249 if (!This) return E_OUTOFMEMORY;
1251 This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
1252 This->ref = 1;
1253 This->data.u.foldercoll.find = NULL;
1254 This->data.u.foldercoll.coll = collection;
1255 IFolderCollection_AddRef(&collection->IFolderCollection_iface);
1257 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1259 return S_OK;
1262 static ULONG WINAPI filecoll_enumvariant_Release(IEnumVARIANT *iface)
1264 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1265 ULONG ref = InterlockedDecrement(&This->ref);
1267 TRACE("(%p)->(%d)\n", This, ref);
1269 if (!ref)
1271 IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
1272 FindClose(This->data.u.filecoll.find);
1273 heap_free(This);
1276 return ref;
1279 static HRESULT WINAPI filecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1281 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1282 HANDLE handle = This->data.u.filecoll.find;
1283 WIN32_FIND_DATAW data;
1284 ULONG count = 0;
1286 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1288 if (fetched)
1289 *fetched = 0;
1291 if (!celt) return S_OK;
1293 if (!handle)
1295 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1296 if (!handle) return S_FALSE;
1297 This->data.u.filecoll.find = handle;
1299 else if (!FindNextFileW(handle, &data))
1300 return S_FALSE;
1304 if (is_file_data(&data))
1306 IFile *file;
1307 HRESULT hr;
1308 BSTR str;
1310 str = get_full_path(This->data.u.filecoll.coll->path, &data);
1311 hr = create_file(str, &file);
1312 SysFreeString(str);
1313 if (FAILED(hr)) return hr;
1315 V_VT(&var[count]) = VT_DISPATCH;
1316 V_DISPATCH(&var[count]) = (IDispatch*)file;
1317 if (++count >= celt) break;
1319 } while (FindNextFileW(handle, &data));
1321 if (fetched)
1322 *fetched = count;
1324 return (count < celt) ? S_FALSE : S_OK;
1327 static HRESULT WINAPI filecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1329 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1330 HANDLE handle = This->data.u.filecoll.find;
1331 WIN32_FIND_DATAW data;
1333 TRACE("(%p)->(%d)\n", This, celt);
1335 if (!celt) return S_OK;
1337 if (!handle)
1339 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1340 if (!handle) return S_FALSE;
1341 This->data.u.filecoll.find = handle;
1343 else if (!FindNextFileW(handle, &data))
1344 return S_FALSE;
1348 if (is_file_data(&data))
1349 --celt;
1350 } while (celt && FindNextFileW(handle, &data));
1352 return celt ? S_FALSE : S_OK;
1355 static HRESULT WINAPI filecoll_enumvariant_Reset(IEnumVARIANT *iface)
1357 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1359 TRACE("(%p)\n", This);
1361 FindClose(This->data.u.filecoll.find);
1362 This->data.u.filecoll.find = NULL;
1364 return S_OK;
1367 static HRESULT WINAPI filecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1369 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1370 TRACE("(%p)->(%p)\n", This, pclone);
1371 return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
1374 static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
1375 enumvariant_QueryInterface,
1376 enumvariant_AddRef,
1377 filecoll_enumvariant_Release,
1378 filecoll_enumvariant_Next,
1379 filecoll_enumvariant_Skip,
1380 filecoll_enumvariant_Reset,
1381 filecoll_enumvariant_Clone
1384 static HRESULT create_filecoll_enum(struct filecollection *collection, IUnknown **newenum)
1386 struct enumvariant *This;
1388 *newenum = NULL;
1390 This = heap_alloc(sizeof(*This));
1391 if (!This) return E_OUTOFMEMORY;
1393 This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
1394 This->ref = 1;
1395 This->data.u.filecoll.find = NULL;
1396 This->data.u.filecoll.coll = collection;
1397 IFileCollection_AddRef(&collection->IFileCollection_iface);
1399 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1401 return S_OK;
1404 static ULONG WINAPI drivecoll_enumvariant_Release(IEnumVARIANT *iface)
1406 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1407 ULONG ref = InterlockedDecrement(&This->ref);
1409 TRACE("(%p)->(%d)\n", This, ref);
1411 if (!ref)
1413 IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
1414 heap_free(This);
1417 return ref;
1420 static HRESULT find_next_drive(struct enumvariant *penum)
1422 int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
1424 for (; i < 32; i++)
1425 if (penum->data.u.drivecoll.coll->drives & (1 << i))
1427 penum->data.u.drivecoll.cur = i;
1428 return S_OK;
1431 return S_FALSE;
1434 static HRESULT WINAPI drivecoll_enumvariant_Next(IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched)
1436 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1437 ULONG count = 0;
1439 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1441 if (fetched)
1442 *fetched = 0;
1444 if (!celt) return S_OK;
1446 while (find_next_drive(This) == S_OK)
1448 IDrive *drive;
1449 HRESULT hr;
1451 hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
1452 if (FAILED(hr)) return hr;
1454 V_VT(&var[count]) = VT_DISPATCH;
1455 V_DISPATCH(&var[count]) = (IDispatch*)drive;
1457 if (++count >= celt) break;
1460 if (fetched)
1461 *fetched = count;
1463 return (count < celt) ? S_FALSE : S_OK;
1466 static HRESULT WINAPI drivecoll_enumvariant_Skip(IEnumVARIANT *iface, ULONG celt)
1468 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1470 TRACE("(%p)->(%d)\n", This, celt);
1472 if (!celt) return S_OK;
1474 while (celt && find_next_drive(This) == S_OK)
1475 celt--;
1477 return celt ? S_FALSE : S_OK;
1480 static HRESULT WINAPI drivecoll_enumvariant_Reset(IEnumVARIANT *iface)
1482 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1484 TRACE("(%p)\n", This);
1486 This->data.u.drivecoll.cur = -1;
1487 return S_OK;
1490 static HRESULT WINAPI drivecoll_enumvariant_Clone(IEnumVARIANT *iface, IEnumVARIANT **pclone)
1492 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1493 FIXME("(%p)->(%p): stub\n", This, pclone);
1494 return E_NOTIMPL;
1497 static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
1498 enumvariant_QueryInterface,
1499 enumvariant_AddRef,
1500 drivecoll_enumvariant_Release,
1501 drivecoll_enumvariant_Next,
1502 drivecoll_enumvariant_Skip,
1503 drivecoll_enumvariant_Reset,
1504 drivecoll_enumvariant_Clone
1507 static HRESULT create_drivecoll_enum(struct drivecollection *collection, IUnknown **newenum)
1509 struct enumvariant *This;
1511 *newenum = NULL;
1513 This = heap_alloc(sizeof(*This));
1514 if (!This) return E_OUTOFMEMORY;
1516 This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
1517 This->ref = 1;
1518 This->data.u.drivecoll.coll = collection;
1519 This->data.u.drivecoll.cur = -1;
1520 IDriveCollection_AddRef(&collection->IDriveCollection_iface);
1522 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1524 return S_OK;
1527 static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
1529 struct foldercollection *This = impl_from_IFolderCollection(iface);
1531 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1533 *obj = NULL;
1535 if (IsEqualIID( riid, &IID_IFolderCollection ) ||
1536 IsEqualIID( riid, &IID_IDispatch ) ||
1537 IsEqualIID( riid, &IID_IUnknown ))
1539 *obj = iface;
1540 IFolderCollection_AddRef(iface);
1542 else
1543 return E_NOINTERFACE;
1545 return S_OK;
1548 static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
1550 struct foldercollection *This = impl_from_IFolderCollection(iface);
1551 ULONG ref = InterlockedIncrement(&This->ref);
1552 TRACE("(%p)->(%d)\n", This, ref);
1553 return ref;
1556 static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
1558 struct foldercollection *This = impl_from_IFolderCollection(iface);
1559 ULONG ref = InterlockedDecrement(&This->ref);
1560 TRACE("(%p)->(%d)\n", This, ref);
1562 if (!ref)
1564 SysFreeString(This->path);
1565 heap_free(This);
1568 return ref;
1571 static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
1573 struct foldercollection *This = impl_from_IFolderCollection(iface);
1574 TRACE("(%p)->(%p)\n", This, pctinfo);
1575 *pctinfo = 1;
1576 return S_OK;
1579 static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
1580 LCID lcid, ITypeInfo **ppTInfo)
1582 struct foldercollection *This = impl_from_IFolderCollection(iface);
1583 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1584 return get_typeinfo(IFolderCollection_tid, ppTInfo);
1587 static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
1588 LPOLESTR *rgszNames, UINT cNames,
1589 LCID lcid, DISPID *rgDispId)
1591 struct foldercollection *This = impl_from_IFolderCollection(iface);
1592 ITypeInfo *typeinfo;
1593 HRESULT hr;
1595 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1597 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1598 if(SUCCEEDED(hr))
1600 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1601 ITypeInfo_Release(typeinfo);
1604 return hr;
1607 static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
1608 REFIID riid, LCID lcid, WORD wFlags,
1609 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1610 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1612 struct foldercollection *This = impl_from_IFolderCollection(iface);
1613 ITypeInfo *typeinfo;
1614 HRESULT hr;
1616 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1617 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1619 hr = get_typeinfo(IFolderCollection_tid, &typeinfo);
1620 if(SUCCEEDED(hr))
1622 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1623 pDispParams, pVarResult, pExcepInfo, puArgErr);
1624 ITypeInfo_Release(typeinfo);
1627 return hr;
1630 static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
1632 struct foldercollection *This = impl_from_IFolderCollection(iface);
1633 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
1634 return E_NOTIMPL;
1637 static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
1639 struct foldercollection *This = impl_from_IFolderCollection(iface);
1640 FIXME("(%p)->(%p): stub\n", This, folder);
1641 return E_NOTIMPL;
1644 static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
1646 struct foldercollection *This = impl_from_IFolderCollection(iface);
1648 TRACE("(%p)->(%p)\n", This, newenum);
1650 if(!newenum)
1651 return E_POINTER;
1653 return create_foldercoll_enum(This, newenum);
1656 static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
1658 struct foldercollection *This = impl_from_IFolderCollection(iface);
1659 static const WCHAR allW[] = {'\\','*',0};
1660 WIN32_FIND_DATAW data;
1661 WCHAR pathW[MAX_PATH];
1662 HANDLE handle;
1664 TRACE("(%p)->(%p)\n", This, count);
1666 if(!count)
1667 return E_POINTER;
1669 *count = 0;
1671 strcpyW(pathW, This->path);
1672 strcatW(pathW, allW);
1673 handle = FindFirstFileW(pathW, &data);
1674 if (handle == INVALID_HANDLE_VALUE)
1675 return HRESULT_FROM_WIN32(GetLastError());
1679 if (is_dir_data(&data))
1680 *count += 1;
1681 } while (FindNextFileW(handle, &data));
1682 FindClose(handle);
1684 return S_OK;
1687 static const IFolderCollectionVtbl foldercollvtbl = {
1688 foldercoll_QueryInterface,
1689 foldercoll_AddRef,
1690 foldercoll_Release,
1691 foldercoll_GetTypeInfoCount,
1692 foldercoll_GetTypeInfo,
1693 foldercoll_GetIDsOfNames,
1694 foldercoll_Invoke,
1695 foldercoll_Add,
1696 foldercoll_get_Item,
1697 foldercoll_get__NewEnum,
1698 foldercoll_get_Count
1701 static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
1703 struct foldercollection *This;
1705 *folders = NULL;
1707 This = heap_alloc(sizeof(struct foldercollection));
1708 if (!This) return E_OUTOFMEMORY;
1710 This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
1711 This->ref = 1;
1712 This->path = SysAllocString(path);
1713 if (!This->path)
1715 heap_free(This);
1716 return E_OUTOFMEMORY;
1719 *folders = &This->IFolderCollection_iface;
1721 return S_OK;
1724 static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj)
1726 struct filecollection *This = impl_from_IFileCollection(iface);
1728 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1730 *obj = NULL;
1732 if (IsEqualIID( riid, &IID_IFileCollection ) ||
1733 IsEqualIID( riid, &IID_IDispatch ) ||
1734 IsEqualIID( riid, &IID_IUnknown ))
1736 *obj = iface;
1737 IFileCollection_AddRef(iface);
1739 else
1740 return E_NOINTERFACE;
1742 return S_OK;
1745 static ULONG WINAPI filecoll_AddRef(IFileCollection *iface)
1747 struct filecollection *This = impl_from_IFileCollection(iface);
1748 ULONG ref = InterlockedIncrement(&This->ref);
1749 TRACE("(%p)->(%d)\n", This, ref);
1750 return ref;
1753 static ULONG WINAPI filecoll_Release(IFileCollection *iface)
1755 struct filecollection *This = impl_from_IFileCollection(iface);
1756 ULONG ref = InterlockedDecrement(&This->ref);
1757 TRACE("(%p)->(%d)\n", This, ref);
1759 if (!ref)
1761 SysFreeString(This->path);
1762 heap_free(This);
1765 return ref;
1768 static HRESULT WINAPI filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo)
1770 struct filecollection *This = impl_from_IFileCollection(iface);
1771 TRACE("(%p)->(%p)\n", This, pctinfo);
1772 *pctinfo = 1;
1773 return S_OK;
1776 static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo,
1777 LCID lcid, ITypeInfo **ppTInfo)
1779 struct filecollection *This = impl_from_IFileCollection(iface);
1780 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1781 return get_typeinfo(IFileCollection_tid, ppTInfo);
1784 static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid,
1785 LPOLESTR *rgszNames, UINT cNames,
1786 LCID lcid, DISPID *rgDispId)
1788 struct filecollection *This = impl_from_IFileCollection(iface);
1789 ITypeInfo *typeinfo;
1790 HRESULT hr;
1792 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1794 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1795 if(SUCCEEDED(hr))
1797 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1798 ITypeInfo_Release(typeinfo);
1801 return hr;
1804 static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember,
1805 REFIID riid, LCID lcid, WORD wFlags,
1806 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1807 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1809 struct filecollection *This = impl_from_IFileCollection(iface);
1810 ITypeInfo *typeinfo;
1811 HRESULT hr;
1813 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1814 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1816 hr = get_typeinfo(IFileCollection_tid, &typeinfo);
1817 if(SUCCEEDED(hr))
1819 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1820 pDispParams, pVarResult, pExcepInfo, puArgErr);
1821 ITypeInfo_Release(typeinfo);
1824 return hr;
1827 static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file)
1829 struct filecollection *This = impl_from_IFileCollection(iface);
1830 FIXME("(%p)->(%p)\n", This, file);
1831 return E_NOTIMPL;
1834 static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum)
1836 struct filecollection *This = impl_from_IFileCollection(iface);
1838 TRACE("(%p)->(%p)\n", This, ppenum);
1840 if(!ppenum)
1841 return E_POINTER;
1843 return create_filecoll_enum(This, ppenum);
1846 static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count)
1848 struct filecollection *This = impl_from_IFileCollection(iface);
1849 static const WCHAR allW[] = {'\\','*',0};
1850 WIN32_FIND_DATAW data;
1851 WCHAR pathW[MAX_PATH];
1852 HANDLE handle;
1854 TRACE("(%p)->(%p)\n", This, count);
1856 if(!count)
1857 return E_POINTER;
1859 *count = 0;
1861 strcpyW(pathW, This->path);
1862 strcatW(pathW, allW);
1863 handle = FindFirstFileW(pathW, &data);
1864 if (handle == INVALID_HANDLE_VALUE)
1865 return HRESULT_FROM_WIN32(GetLastError());
1869 if (is_file_data(&data))
1870 *count += 1;
1871 } while (FindNextFileW(handle, &data));
1872 FindClose(handle);
1874 return S_OK;
1877 static const IFileCollectionVtbl filecollectionvtbl = {
1878 filecoll_QueryInterface,
1879 filecoll_AddRef,
1880 filecoll_Release,
1881 filecoll_GetTypeInfoCount,
1882 filecoll_GetTypeInfo,
1883 filecoll_GetIDsOfNames,
1884 filecoll_Invoke,
1885 filecoll_get_Item,
1886 filecoll_get__NewEnum,
1887 filecoll_get_Count
1890 static HRESULT create_filecoll(BSTR path, IFileCollection **files)
1892 struct filecollection *This;
1894 *files = NULL;
1896 This = heap_alloc(sizeof(*This));
1897 if (!This) return E_OUTOFMEMORY;
1899 This->IFileCollection_iface.lpVtbl = &filecollectionvtbl;
1900 This->ref = 1;
1901 This->path = SysAllocString(path);
1902 if (!This->path)
1904 heap_free(This);
1905 return E_OUTOFMEMORY;
1908 *files = &This->IFileCollection_iface;
1909 return S_OK;
1912 static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
1914 struct drivecollection *This = impl_from_IDriveCollection(iface);
1916 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1918 *obj = NULL;
1920 if (IsEqualIID( riid, &IID_IDriveCollection ) ||
1921 IsEqualIID( riid, &IID_IDispatch ) ||
1922 IsEqualIID( riid, &IID_IUnknown ))
1924 *obj = iface;
1925 IDriveCollection_AddRef(iface);
1927 else
1928 return E_NOINTERFACE;
1930 return S_OK;
1933 static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
1935 struct drivecollection *This = impl_from_IDriveCollection(iface);
1936 ULONG ref = InterlockedIncrement(&This->ref);
1937 TRACE("(%p)->(%d)\n", This, ref);
1938 return ref;
1941 static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
1943 struct drivecollection *This = impl_from_IDriveCollection(iface);
1944 ULONG ref = InterlockedDecrement(&This->ref);
1945 TRACE("(%p)->(%d)\n", This, ref);
1947 if (!ref)
1948 heap_free(This);
1950 return ref;
1953 static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
1955 struct drivecollection *This = impl_from_IDriveCollection(iface);
1956 TRACE("(%p)->(%p)\n", This, pctinfo);
1957 *pctinfo = 1;
1958 return S_OK;
1961 static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
1962 LCID lcid, ITypeInfo **ppTInfo)
1964 struct drivecollection *This = impl_from_IDriveCollection(iface);
1965 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1966 return get_typeinfo(IDriveCollection_tid, ppTInfo);
1969 static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
1970 LPOLESTR *rgszNames, UINT cNames,
1971 LCID lcid, DISPID *rgDispId)
1973 struct drivecollection *This = impl_from_IDriveCollection(iface);
1974 ITypeInfo *typeinfo;
1975 HRESULT hr;
1977 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1979 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
1980 if(SUCCEEDED(hr))
1982 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1983 ITypeInfo_Release(typeinfo);
1986 return hr;
1989 static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
1990 REFIID riid, LCID lcid, WORD wFlags,
1991 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1992 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1994 struct drivecollection *This = impl_from_IDriveCollection(iface);
1995 ITypeInfo *typeinfo;
1996 HRESULT hr;
1998 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1999 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2001 hr = get_typeinfo(IDriveCollection_tid, &typeinfo);
2002 if(SUCCEEDED(hr))
2004 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2005 pDispParams, pVarResult, pExcepInfo, puArgErr);
2006 ITypeInfo_Release(typeinfo);
2009 return hr;
2012 static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
2014 struct drivecollection *This = impl_from_IDriveCollection(iface);
2015 FIXME("(%p)->(%p): stub\n", This, drive);
2016 return E_NOTIMPL;
2019 static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
2021 struct drivecollection *This = impl_from_IDriveCollection(iface);
2023 TRACE("(%p)->(%p)\n", This, ppenum);
2025 if(!ppenum)
2026 return E_POINTER;
2028 return create_drivecoll_enum(This, ppenum);
2031 static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
2033 struct drivecollection *This = impl_from_IDriveCollection(iface);
2035 TRACE("(%p)->(%p)\n", This, count);
2037 if (!count) return E_POINTER;
2039 *count = This->count;
2040 return S_OK;
2043 static const IDriveCollectionVtbl drivecollectionvtbl = {
2044 drivecoll_QueryInterface,
2045 drivecoll_AddRef,
2046 drivecoll_Release,
2047 drivecoll_GetTypeInfoCount,
2048 drivecoll_GetTypeInfo,
2049 drivecoll_GetIDsOfNames,
2050 drivecoll_Invoke,
2051 drivecoll_get_Item,
2052 drivecoll_get__NewEnum,
2053 drivecoll_get_Count
2056 static HRESULT create_drivecoll(IDriveCollection **drives)
2058 struct drivecollection *This;
2059 DWORD mask;
2061 *drives = NULL;
2063 This = heap_alloc(sizeof(*This));
2064 if (!This) return E_OUTOFMEMORY;
2066 This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl;
2067 This->ref = 1;
2068 This->drives = mask = GetLogicalDrives();
2069 /* count set bits */
2070 for (This->count = 0; mask; This->count++)
2071 mask &= mask - 1;
2073 *drives = &This->IDriveCollection_iface;
2074 return S_OK;
2077 static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
2079 struct folder *This = impl_from_IFolder(iface);
2081 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2083 *obj = NULL;
2085 if (IsEqualIID( riid, &IID_IFolder ) ||
2086 IsEqualIID( riid, &IID_IDispatch ) ||
2087 IsEqualIID( riid, &IID_IUnknown))
2089 *obj = iface;
2090 IFolder_AddRef(iface);
2092 else
2093 return E_NOINTERFACE;
2095 return S_OK;
2098 static ULONG WINAPI folder_AddRef(IFolder *iface)
2100 struct folder *This = impl_from_IFolder(iface);
2101 ULONG ref = InterlockedIncrement(&This->ref);
2102 TRACE("(%p)->(%d)\n", This, ref);
2103 return ref;
2106 static ULONG WINAPI folder_Release(IFolder *iface)
2108 struct folder *This = impl_from_IFolder(iface);
2109 ULONG ref = InterlockedDecrement(&This->ref);
2110 TRACE("(%p)->(%d)\n", This, ref);
2112 if (!ref)
2114 SysFreeString(This->path);
2115 heap_free(This);
2118 return ref;
2121 static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
2123 struct folder *This = impl_from_IFolder(iface);
2124 TRACE("(%p)->(%p)\n", This, pctinfo);
2125 *pctinfo = 1;
2126 return S_OK;
2129 static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
2130 LCID lcid, ITypeInfo **ppTInfo)
2132 struct folder *This = impl_from_IFolder(iface);
2133 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2134 return get_typeinfo(IFolder_tid, ppTInfo);
2137 static HRESULT WINAPI folder_GetIDsOfNames(IFolder *iface, REFIID riid,
2138 LPOLESTR *rgszNames, UINT cNames,
2139 LCID lcid, DISPID *rgDispId)
2141 struct folder *This = impl_from_IFolder(iface);
2142 ITypeInfo *typeinfo;
2143 HRESULT hr;
2145 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2147 hr = get_typeinfo(IFolder_tid, &typeinfo);
2148 if(SUCCEEDED(hr))
2150 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2151 ITypeInfo_Release(typeinfo);
2154 return hr;
2157 static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
2158 REFIID riid, LCID lcid, WORD wFlags,
2159 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2160 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2162 struct folder *This = impl_from_IFolder(iface);
2163 ITypeInfo *typeinfo;
2164 HRESULT hr;
2166 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2167 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2169 hr = get_typeinfo(IFolder_tid, &typeinfo);
2170 if(SUCCEEDED(hr))
2172 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2173 pDispParams, pVarResult, pExcepInfo, puArgErr);
2174 ITypeInfo_Release(typeinfo);
2177 return hr;
2180 static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
2182 struct folder *This = impl_from_IFolder(iface);
2184 TRACE("(%p)->(%p)\n", This, path);
2186 if(!path)
2187 return E_POINTER;
2189 *path = SysAllocString(This->path);
2190 return *path ? S_OK : E_OUTOFMEMORY;
2193 static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
2195 struct folder *This = impl_from_IFolder(iface);
2196 WCHAR *ptr;
2198 TRACE("(%p)->(%p)\n", This, name);
2200 if(!name)
2201 return E_POINTER;
2203 *name = NULL;
2205 ptr = strrchrW(This->path, '\\');
2206 if (ptr)
2208 *name = SysAllocString(ptr+1);
2209 TRACE("%s\n", debugstr_w(*name));
2210 if (!*name) return E_OUTOFMEMORY;
2212 else
2213 return E_FAIL;
2215 return S_OK;
2218 static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
2220 struct folder *This = impl_from_IFolder(iface);
2221 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
2222 return E_NOTIMPL;
2225 static HRESULT WINAPI folder_get_ShortPath(IFolder *iface, BSTR *path)
2227 struct folder *This = impl_from_IFolder(iface);
2228 FIXME("(%p)->(%p): stub\n", This, path);
2229 return E_NOTIMPL;
2232 static HRESULT WINAPI folder_get_ShortName(IFolder *iface, BSTR *name)
2234 struct folder *This = impl_from_IFolder(iface);
2235 FIXME("(%p)->(%p): stub\n", This, name);
2236 return E_NOTIMPL;
2239 static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
2241 struct folder *This = impl_from_IFolder(iface);
2242 FIXME("(%p)->(%p): stub\n", This, drive);
2243 return E_NOTIMPL;
2246 static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
2248 struct folder *This = impl_from_IFolder(iface);
2249 FIXME("(%p)->(%p): stub\n", This, parent);
2250 return E_NOTIMPL;
2253 static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
2255 struct folder *This = impl_from_IFolder(iface);
2256 FIXME("(%p)->(%p): stub\n", This, attr);
2257 return E_NOTIMPL;
2260 static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
2262 struct folder *This = impl_from_IFolder(iface);
2263 FIXME("(%p)->(0x%x): stub\n", This, attr);
2264 return E_NOTIMPL;
2267 static HRESULT WINAPI folder_get_DateCreated(IFolder *iface, DATE *date)
2269 struct folder *This = impl_from_IFolder(iface);
2270 FIXME("(%p)->(%p): stub\n", This, date);
2271 return E_NOTIMPL;
2274 static HRESULT WINAPI folder_get_DateLastModified(IFolder *iface, DATE *date)
2276 struct folder *This = impl_from_IFolder(iface);
2277 FIXME("(%p)->(%p): stub\n", This, date);
2278 return E_NOTIMPL;
2281 static HRESULT WINAPI folder_get_DateLastAccessed(IFolder *iface, DATE *date)
2283 struct folder *This = impl_from_IFolder(iface);
2284 FIXME("(%p)->(%p): stub\n", This, date);
2285 return E_NOTIMPL;
2288 static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
2290 struct folder *This = impl_from_IFolder(iface);
2291 FIXME("(%p)->(%p): stub\n", This, type);
2292 return E_NOTIMPL;
2295 static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
2297 struct folder *This = impl_from_IFolder(iface);
2298 FIXME("(%p)->(%x): stub\n", This, force);
2299 return E_NOTIMPL;
2302 static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
2304 struct folder *This = impl_from_IFolder(iface);
2305 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
2306 return E_NOTIMPL;
2309 static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
2311 struct folder *This = impl_from_IFolder(iface);
2312 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
2313 return E_NOTIMPL;
2316 static HRESULT WINAPI folder_get_IsRootFolder(IFolder *iface, VARIANT_BOOL *isroot)
2318 struct folder *This = impl_from_IFolder(iface);
2319 FIXME("(%p)->(%p): stub\n", This, isroot);
2320 return E_NOTIMPL;
2323 static HRESULT WINAPI folder_get_Size(IFolder *iface, VARIANT *size)
2325 struct folder *This = impl_from_IFolder(iface);
2326 FIXME("(%p)->(%p): stub\n", This, size);
2327 return E_NOTIMPL;
2330 static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
2332 struct folder *This = impl_from_IFolder(iface);
2334 TRACE("(%p)->(%p)\n", This, folders);
2336 if(!folders)
2337 return E_POINTER;
2339 return create_foldercoll(This->path, folders);
2342 static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
2344 struct folder *This = impl_from_IFolder(iface);
2346 TRACE("(%p)->(%p)\n", This, files);
2348 if(!files)
2349 return E_POINTER;
2351 return create_filecoll(This->path, files);
2354 static HRESULT WINAPI folder_CreateTextFile(IFolder *iface, BSTR filename, VARIANT_BOOL overwrite,
2355 VARIANT_BOOL unicode, ITextStream **stream)
2357 struct folder *This = impl_from_IFolder(iface);
2358 FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
2359 return E_NOTIMPL;
2362 static const IFolderVtbl foldervtbl = {
2363 folder_QueryInterface,
2364 folder_AddRef,
2365 folder_Release,
2366 folder_GetTypeInfoCount,
2367 folder_GetTypeInfo,
2368 folder_GetIDsOfNames,
2369 folder_Invoke,
2370 folder_get_Path,
2371 folder_get_Name,
2372 folder_put_Name,
2373 folder_get_ShortPath,
2374 folder_get_ShortName,
2375 folder_get_Drive,
2376 folder_get_ParentFolder,
2377 folder_get_Attributes,
2378 folder_put_Attributes,
2379 folder_get_DateCreated,
2380 folder_get_DateLastModified,
2381 folder_get_DateLastAccessed,
2382 folder_get_Type,
2383 folder_Delete,
2384 folder_Copy,
2385 folder_Move,
2386 folder_get_IsRootFolder,
2387 folder_get_Size,
2388 folder_get_SubFolders,
2389 folder_get_Files,
2390 folder_CreateTextFile
2393 HRESULT create_folder(const WCHAR *path, IFolder **folder)
2395 struct folder *This;
2397 *folder = NULL;
2399 TRACE("%s\n", debugstr_w(path));
2401 This = heap_alloc(sizeof(struct folder));
2402 if (!This) return E_OUTOFMEMORY;
2404 This->IFolder_iface.lpVtbl = &foldervtbl;
2405 This->ref = 1;
2406 This->path = SysAllocString(path);
2407 if (!This->path)
2409 heap_free(This);
2410 return E_OUTOFMEMORY;
2413 *folder = &This->IFolder_iface;
2415 return S_OK;
2418 static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
2420 struct file *This = impl_from_IFile(iface);
2422 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2424 if (IsEqualIID(riid, &IID_IFile) ||
2425 IsEqualIID(riid, &IID_IDispatch) ||
2426 IsEqualIID(riid, &IID_IUnknown))
2428 *obj = iface;
2429 IFile_AddRef(iface);
2430 return S_OK;
2433 *obj = NULL;
2434 return E_NOINTERFACE;
2437 static ULONG WINAPI file_AddRef(IFile *iface)
2439 struct file *This = impl_from_IFile(iface);
2440 LONG ref = InterlockedIncrement(&This->ref);
2442 TRACE("(%p) ref=%d\n", This, ref);
2444 return ref;
2447 static ULONG WINAPI file_Release(IFile *iface)
2449 struct file *This = impl_from_IFile(iface);
2450 LONG ref = InterlockedDecrement(&This->ref);
2452 TRACE("(%p) ref=%d\n", This, ref);
2454 if(!ref)
2456 heap_free(This->path);
2457 heap_free(This);
2460 return ref;
2463 static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
2465 struct file *This = impl_from_IFile(iface);
2467 TRACE("(%p)->(%p)\n", This, pctinfo);
2469 *pctinfo = 1;
2470 return S_OK;
2473 static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
2474 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
2476 struct file *This = impl_from_IFile(iface);
2478 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2480 return get_typeinfo(IFile_tid, ppTInfo);
2483 static HRESULT WINAPI file_GetIDsOfNames(IFile *iface, REFIID riid,
2484 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2486 struct file *This = impl_from_IFile(iface);
2487 ITypeInfo *typeinfo;
2488 HRESULT hr;
2490 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
2491 rgszNames, cNames, lcid, rgDispId);
2493 hr = get_typeinfo(IFile_tid, &typeinfo);
2494 if(SUCCEEDED(hr)) {
2495 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2496 ITypeInfo_Release(typeinfo);
2498 return hr;
2501 static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2503 struct file *This = impl_from_IFile(iface);
2504 ITypeInfo *typeinfo;
2505 HRESULT hr;
2507 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2508 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2510 hr = get_typeinfo(IFile_tid, &typeinfo);
2511 if(SUCCEEDED(hr))
2513 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2514 pDispParams, pVarResult, pExcepInfo, puArgErr);
2515 ITypeInfo_Release(typeinfo);
2517 return hr;
2520 static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *pbstrPath)
2522 struct file *This = impl_from_IFile(iface);
2523 FIXME("(%p)->(%p)\n", This, pbstrPath);
2524 return E_NOTIMPL;
2527 static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
2529 struct file *This = impl_from_IFile(iface);
2530 WCHAR *ptr;
2532 TRACE("(%p)->(%p)\n", This, name);
2534 if(!name)
2535 return E_POINTER;
2537 *name = NULL;
2539 ptr = strrchrW(This->path, '\\');
2540 if (ptr)
2542 *name = SysAllocString(ptr+1);
2543 TRACE("%s\n", debugstr_w(*name));
2544 if (!*name) return E_OUTOFMEMORY;
2546 else
2547 return E_FAIL;
2549 return S_OK;
2552 static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
2554 struct file *This = impl_from_IFile(iface);
2555 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
2556 return E_NOTIMPL;
2559 static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
2561 struct file *This = impl_from_IFile(iface);
2562 FIXME("(%p)->(%p)\n", This, pbstrPath);
2563 return E_NOTIMPL;
2566 static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
2568 struct file *This = impl_from_IFile(iface);
2569 FIXME("(%p)->(%p)\n", This, pbstrName);
2570 return E_NOTIMPL;
2573 static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
2575 struct file *This = impl_from_IFile(iface);
2576 FIXME("(%p)->(%p)\n", This, ppdrive);
2577 return E_NOTIMPL;
2580 static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
2582 struct file *This = impl_from_IFile(iface);
2583 FIXME("(%p)->(%p)\n", This, ppfolder);
2584 return E_NOTIMPL;
2587 static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
2589 struct file *This = impl_from_IFile(iface);
2590 DWORD fa;
2592 TRACE("(%p)->(%p)\n", This, pfa);
2594 if(!pfa)
2595 return E_POINTER;
2597 fa = GetFileAttributesW(This->path);
2598 if(fa == INVALID_FILE_ATTRIBUTES)
2599 return create_error(GetLastError());
2601 *pfa = fa & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
2602 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE |
2603 FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED);
2604 return S_OK;
2607 static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
2609 struct file *This = impl_from_IFile(iface);
2610 FIXME("(%p)->(%x)\n", This, pfa);
2611 return E_NOTIMPL;
2614 static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
2616 struct file *This = impl_from_IFile(iface);
2617 FIXME("(%p)->(%p)\n", This, pdate);
2618 return E_NOTIMPL;
2621 static HRESULT WINAPI file_get_DateLastModified(IFile *iface, DATE *pdate)
2623 struct file *This = impl_from_IFile(iface);
2624 FIXME("(%p)->(%p)\n", This, pdate);
2625 return E_NOTIMPL;
2628 static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
2630 struct file *This = impl_from_IFile(iface);
2631 FIXME("(%p)->(%p)\n", This, pdate);
2632 return E_NOTIMPL;
2635 static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
2637 struct file *This = impl_from_IFile(iface);
2638 ULARGE_INTEGER size;
2639 WIN32_FIND_DATAW fd;
2640 HANDLE f;
2642 TRACE("(%p)->(%p)\n", This, pvarSize);
2644 if(!pvarSize)
2645 return E_POINTER;
2647 f = FindFirstFileW(This->path, &fd);
2648 if(f == INVALID_HANDLE_VALUE)
2649 return create_error(GetLastError());
2650 FindClose(f);
2652 size.u.LowPart = fd.nFileSizeLow;
2653 size.u.HighPart = fd.nFileSizeHigh;
2655 return variant_from_largeint(&size, pvarSize);
2658 static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
2660 struct file *This = impl_from_IFile(iface);
2661 FIXME("(%p)->(%p)\n", This, pbstrType);
2662 return E_NOTIMPL;
2665 static HRESULT WINAPI file_Delete(IFile *iface, VARIANT_BOOL Force)
2667 struct file *This = impl_from_IFile(iface);
2668 FIXME("(%p)->(%x)\n", This, Force);
2669 return E_NOTIMPL;
2672 static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
2674 struct file *This = impl_from_IFile(iface);
2675 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
2676 return E_NOTIMPL;
2679 static HRESULT WINAPI file_Move(IFile *iface, BSTR Destination)
2681 struct file *This = impl_from_IFile(iface);
2682 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
2683 return E_NOTIMPL;
2686 static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode mode, Tristate format, ITextStream **stream)
2688 struct file *This = impl_from_IFile(iface);
2690 TRACE("(%p)->(%d %d %p)\n", This, mode, format, stream);
2692 if (format == TristateUseDefault) {
2693 FIXME("default format not handled, defaulting to unicode\n");
2694 format = TristateTrue;
2697 return create_textstream(This->path, OPEN_EXISTING, mode, format == TristateTrue, stream);
2700 static const IFileVtbl file_vtbl = {
2701 file_QueryInterface,
2702 file_AddRef,
2703 file_Release,
2704 file_GetTypeInfoCount,
2705 file_GetTypeInfo,
2706 file_GetIDsOfNames,
2707 file_Invoke,
2708 file_get_Path,
2709 file_get_Name,
2710 file_put_Name,
2711 file_get_ShortPath,
2712 file_get_ShortName,
2713 file_get_Drive,
2714 file_get_ParentFolder,
2715 file_get_Attributes,
2716 file_put_Attributes,
2717 file_get_DateCreated,
2718 file_get_DateLastModified,
2719 file_get_DateLastAccessed,
2720 file_get_Size,
2721 file_get_Type,
2722 file_Delete,
2723 file_Copy,
2724 file_Move,
2725 file_OpenAsTextStream
2728 static HRESULT create_file(BSTR path, IFile **file)
2730 struct file *f;
2731 DWORD len, attrs;
2733 *file = NULL;
2735 f = heap_alloc(sizeof(struct file));
2736 if(!f)
2737 return E_OUTOFMEMORY;
2739 f->IFile_iface.lpVtbl = &file_vtbl;
2740 f->ref = 1;
2742 len = GetFullPathNameW(path, 0, NULL, NULL);
2743 if(!len) {
2744 heap_free(f);
2745 return E_FAIL;
2748 f->path = heap_alloc(len*sizeof(WCHAR));
2749 if(!f->path) {
2750 heap_free(f);
2751 return E_OUTOFMEMORY;
2754 if(!GetFullPathNameW(path, len, f->path, NULL)) {
2755 heap_free(f->path);
2756 heap_free(f);
2757 return E_FAIL;
2760 attrs = GetFileAttributesW(f->path);
2761 if(attrs==INVALID_FILE_ATTRIBUTES ||
2762 (attrs&(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))) {
2763 heap_free(f->path);
2764 heap_free(f);
2765 return create_error(GetLastError());
2768 *file = &f->IFile_iface;
2769 return S_OK;
2772 static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
2774 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
2776 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
2777 IsEqualGUID( riid, &IID_IFileSystem ) ||
2778 IsEqualGUID( riid, &IID_IDispatch ) ||
2779 IsEqualGUID( riid, &IID_IUnknown ) )
2781 *ppvObject = iface;
2783 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
2785 TRACE("Interface IDispatchEx not supported - returning NULL\n");
2786 *ppvObject = NULL;
2787 return E_NOINTERFACE;
2789 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
2791 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
2792 *ppvObject = NULL;
2793 return E_NOINTERFACE;
2795 else
2797 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
2798 return E_NOINTERFACE;
2801 IFileSystem3_AddRef(iface);
2803 return S_OK;
2806 static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
2808 TRACE("%p\n", iface);
2810 return 2;
2813 static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
2815 TRACE("%p\n", iface);
2817 return 1;
2820 static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
2822 TRACE("(%p)->(%p)\n", iface, pctinfo);
2824 *pctinfo = 1;
2825 return S_OK;
2828 static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
2829 LCID lcid, ITypeInfo **ppTInfo)
2831 TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
2832 return get_typeinfo(IFileSystem3_tid, ppTInfo);
2835 static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
2836 LPOLESTR *rgszNames, UINT cNames,
2837 LCID lcid, DISPID *rgDispId)
2839 ITypeInfo *typeinfo;
2840 HRESULT hr;
2842 TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2844 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2845 if(SUCCEEDED(hr))
2847 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2848 ITypeInfo_Release(typeinfo);
2851 return hr;
2854 static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
2855 REFIID riid, LCID lcid, WORD wFlags,
2856 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2857 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2859 ITypeInfo *typeinfo;
2860 HRESULT hr;
2862 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
2863 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2865 hr = get_typeinfo(IFileSystem3_tid, &typeinfo);
2866 if(SUCCEEDED(hr))
2868 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2869 pDispParams, pVarResult, pExcepInfo, puArgErr);
2870 ITypeInfo_Release(typeinfo);
2873 return hr;
2876 static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
2878 TRACE("%p %p\n", iface, ppdrives);
2879 return create_drivecoll(ppdrives);
2882 static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
2883 BSTR Name, BSTR *Result)
2885 BSTR ret;
2887 TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
2889 if (!Result) return E_POINTER;
2891 if (Path && Name)
2893 int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
2895 /* if both parts have backslashes strip one from Path */
2896 if (Path[path_len-1] == '\\' && Name[0] == '\\')
2898 path_len -= 1;
2900 ret = SysAllocStringLen(NULL, path_len + name_len);
2901 if (ret)
2903 strcpyW(ret, Path);
2904 ret[path_len] = 0;
2905 strcatW(ret, Name);
2908 else if (Path[path_len-1] != '\\' && Name[0] != '\\')
2910 ret = SysAllocStringLen(NULL, path_len + name_len + 1);
2911 if (ret)
2913 strcpyW(ret, Path);
2914 if (Path[path_len-1] != ':')
2915 strcatW(ret, bsW);
2916 strcatW(ret, Name);
2919 else
2921 ret = SysAllocStringLen(NULL, path_len + name_len);
2922 if (ret)
2924 strcpyW(ret, Path);
2925 strcatW(ret, Name);
2929 else if (Path || Name)
2930 ret = SysAllocString(Path ? Path : Name);
2931 else
2932 ret = SysAllocStringLen(NULL, 0);
2934 if (!ret) return E_OUTOFMEMORY;
2935 *Result = ret;
2937 return S_OK;
2940 static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR path, BSTR *drive)
2942 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), drive);
2944 if (!drive)
2945 return E_POINTER;
2947 *drive = NULL;
2949 if (path && strlenW(path) > 1 && path[1] == ':')
2950 *drive = SysAllocStringLen(path, 2);
2952 return S_OK;
2955 static inline DWORD get_parent_folder_name(const WCHAR *path, DWORD len)
2957 int i;
2959 if(!path)
2960 return 0;
2962 for(i=len-1; i>=0; i--)
2963 if(path[i]!='/' && path[i]!='\\')
2964 break;
2966 for(; i>=0; i--)
2967 if(path[i]=='/' || path[i]=='\\')
2968 break;
2970 for(; i>=0; i--)
2971 if(path[i]!='/' && path[i]!='\\')
2972 break;
2974 if(i < 0)
2975 return 0;
2977 if(path[i]==':' && i==1)
2978 i++;
2979 return i+1;
2982 static HRESULT WINAPI filesys_GetParentFolderName(IFileSystem3 *iface, BSTR Path,
2983 BSTR *pbstrResult)
2985 DWORD len;
2987 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
2989 if(!pbstrResult)
2990 return E_POINTER;
2992 len = get_parent_folder_name(Path, SysStringLen(Path));
2993 if(!len) {
2994 *pbstrResult = NULL;
2995 return S_OK;
2998 *pbstrResult = SysAllocStringLen(Path, len);
2999 if(!*pbstrResult)
3000 return E_OUTOFMEMORY;
3001 return S_OK;
3004 static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
3005 BSTR *pbstrResult)
3007 int i, end;
3009 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3011 if(!pbstrResult)
3012 return E_POINTER;
3014 if(!Path) {
3015 *pbstrResult = NULL;
3016 return S_OK;
3019 for(end=strlenW(Path)-1; end>=0; end--)
3020 if(Path[end]!='/' && Path[end]!='\\')
3021 break;
3023 for(i=end; i>=0; i--)
3024 if(Path[i]=='/' || Path[i]=='\\')
3025 break;
3026 i++;
3028 if(i>end || (i==0 && end==1 && Path[1]==':')) {
3029 *pbstrResult = NULL;
3030 return S_OK;
3033 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3034 if(!*pbstrResult)
3035 return E_OUTOFMEMORY;
3036 return S_OK;
3039 static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
3040 BSTR *pbstrResult)
3042 int i, end;
3044 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3046 if(!pbstrResult)
3047 return E_POINTER;
3049 if(!Path) {
3050 *pbstrResult = NULL;
3051 return S_OK;
3054 for(end=strlenW(Path)-1; end>=0; end--)
3055 if(Path[end]!='/' && Path[end]!='\\')
3056 break;
3058 for(i=end; i>=0; i--) {
3059 if(Path[i]=='.' && Path[end+1]!='.')
3060 end = i-1;
3061 if(Path[i]=='/' || Path[i]=='\\')
3062 break;
3064 i++;
3066 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
3067 *pbstrResult = NULL;
3068 return S_OK;
3071 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3072 if(!*pbstrResult)
3073 return E_OUTOFMEMORY;
3074 return S_OK;
3077 static HRESULT WINAPI filesys_GetExtensionName(IFileSystem3 *iface, BSTR Path,
3078 BSTR *pbstrResult)
3080 FIXME("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3082 return E_NOTIMPL;
3085 static HRESULT WINAPI filesys_GetAbsolutePathName(IFileSystem3 *iface, BSTR Path,
3086 BSTR *pbstrResult)
3088 static const WCHAR cur_path[] = {'.',0};
3090 WCHAR buf[MAX_PATH], ch;
3091 const WCHAR *path;
3092 DWORD i, beg, len, exp_len;
3093 WIN32_FIND_DATAW fdata;
3094 HANDLE fh;
3096 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3098 if(!pbstrResult)
3099 return E_POINTER;
3101 if(!Path)
3102 path = cur_path;
3103 else
3104 path = Path;
3106 len = GetFullPathNameW(path, MAX_PATH, buf, NULL);
3107 if(!len)
3108 return E_FAIL;
3110 buf[0] = toupperW(buf[0]);
3111 if(len>3 && buf[len-1] == '\\')
3112 buf[--len] = 0;
3114 for(beg=3, i=3; i<=len; i++) {
3115 if(buf[i]!='\\' && buf[i])
3116 continue;
3118 ch = buf[i];
3119 buf[i] = 0;
3120 fh = FindFirstFileW(buf, &fdata);
3121 if(fh == INVALID_HANDLE_VALUE)
3122 break;
3124 exp_len = strlenW(fdata.cFileName);
3125 if(exp_len == i-beg)
3126 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
3127 FindClose(fh);
3128 buf[i] = ch;
3129 beg = i+1;
3132 *pbstrResult = SysAllocString(buf);
3133 if(!*pbstrResult)
3134 return E_OUTOFMEMORY;
3135 return S_OK;
3138 static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
3140 static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
3142 DWORD random;
3144 TRACE("%p %p\n", iface, pbstrResult);
3146 if(!pbstrResult)
3147 return E_POINTER;
3149 *pbstrResult = SysAllocStringLen(NULL, 12);
3150 if(!*pbstrResult)
3151 return E_OUTOFMEMORY;
3153 if(!RtlGenRandom(&random, sizeof(random)))
3154 return E_FAIL;
3155 sprintfW(*pbstrResult, fmt, random & 0xfffff);
3156 return S_OK;
3159 static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
3160 VARIANT_BOOL *pfExists)
3162 FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
3164 return E_NOTIMPL;
3167 static HRESULT WINAPI filesys_FileExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3169 DWORD attrs;
3170 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3172 if (!ret) return E_POINTER;
3174 attrs = GetFileAttributesW(path);
3175 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3176 return S_OK;
3179 static HRESULT WINAPI filesys_FolderExists(IFileSystem3 *iface, BSTR path, VARIANT_BOOL *ret)
3181 DWORD attrs;
3182 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3184 if (!ret) return E_POINTER;
3186 attrs = GetFileAttributesW(path);
3187 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3189 return S_OK;
3192 static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
3193 IDrive **ppdrive)
3195 FIXME("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
3197 return E_NOTIMPL;
3200 static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
3201 IFile **ppfile)
3203 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
3205 if(!ppfile)
3206 return E_POINTER;
3207 if(!FilePath)
3208 return E_INVALIDARG;
3210 return create_file(FilePath, ppfile);
3213 static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
3214 IFolder **folder)
3216 DWORD attrs;
3218 TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
3220 if(!folder)
3221 return E_POINTER;
3223 *folder = NULL;
3224 if(!FolderPath)
3225 return E_INVALIDARG;
3227 attrs = GetFileAttributesW(FolderPath);
3228 if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
3229 return CTL_E_PATHNOTFOUND;
3231 return create_folder(FolderPath, folder);
3234 static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
3235 SpecialFolderConst SpecialFolder,
3236 IFolder **ppfolder)
3238 FIXME("%p %d %p\n", iface, SpecialFolder, ppfolder);
3240 return E_NOTIMPL;
3243 static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
3245 WCHAR path[MAX_PATH];
3246 DWORD len, name_len;
3247 WIN32_FIND_DATAW ffd;
3248 HANDLE f;
3250 f = FindFirstFileW(file, &ffd);
3251 if(f == INVALID_HANDLE_VALUE)
3252 return create_error(GetLastError());
3254 len = get_parent_folder_name(file, file_len);
3255 if(len+1 >= MAX_PATH) {
3256 FindClose(f);
3257 return E_FAIL;
3259 if(len) {
3260 memcpy(path, file, len*sizeof(WCHAR));
3261 path[len++] = '\\';
3264 do {
3265 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3266 continue;
3268 name_len = strlenW(ffd.cFileName);
3269 if(len+name_len+1 >= MAX_PATH) {
3270 FindClose(f);
3271 return E_FAIL;
3273 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3275 TRACE("deleting %s\n", debugstr_w(path));
3277 if(!DeleteFileW(path)) {
3278 if(!force || !SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL)
3279 || !DeleteFileW(path)) {
3280 FindClose(f);
3281 return create_error(GetLastError());
3284 } while(FindNextFileW(f, &ffd));
3285 FindClose(f);
3287 return S_OK;
3290 static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
3291 VARIANT_BOOL Force)
3293 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
3295 if(!FileSpec)
3296 return E_POINTER;
3298 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
3301 static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
3303 WCHAR path[MAX_PATH];
3304 DWORD len, name_len;
3305 WIN32_FIND_DATAW ffd;
3306 HANDLE f;
3307 HRESULT hr;
3309 f = FindFirstFileW(folder, &ffd);
3310 if(f == INVALID_HANDLE_VALUE)
3311 return create_error(GetLastError());
3313 len = get_parent_folder_name(folder, folder_len);
3314 if(len+1 >= MAX_PATH) {
3315 FindClose(f);
3316 return E_FAIL;
3318 if(len) {
3319 memcpy(path, folder, len*sizeof(WCHAR));
3320 path[len++] = '\\';
3323 do {
3324 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3325 continue;
3326 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3327 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3328 continue;
3330 name_len = strlenW(ffd.cFileName);
3331 if(len+name_len+3 >= MAX_PATH) {
3332 FindClose(f);
3333 return E_FAIL;
3335 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
3336 path[len+name_len] = '\\';
3337 path[len+name_len+1] = '*';
3338 path[len+name_len+2] = 0;
3340 hr = delete_file(path, len+name_len+2, force);
3341 if(FAILED(hr)) {
3342 FindClose(f);
3343 return hr;
3346 hr = delete_folder(path, len+name_len+2, force);
3347 if(FAILED(hr)) {
3348 FindClose(f);
3349 return hr;
3352 path[len+name_len] = 0;
3353 TRACE("deleting %s\n", debugstr_w(path));
3355 if(!RemoveDirectoryW(path)) {
3356 FindClose(f);
3357 return create_error(GetLastError());
3359 } while(FindNextFileW(f, &ffd));
3360 FindClose(f);
3362 return S_OK;
3365 static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
3366 VARIANT_BOOL Force)
3368 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
3370 if(!FolderSpec)
3371 return E_POINTER;
3373 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
3376 static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR Source,
3377 BSTR Destination)
3379 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3381 return E_NOTIMPL;
3384 static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
3385 BSTR Destination)
3387 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3389 return E_NOTIMPL;
3392 static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
3393 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
3395 DWORD attrs;
3396 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
3397 DWORD src_len, dst_len, name_len;
3398 WIN32_FIND_DATAW ffd;
3399 HANDLE f;
3400 HRESULT hr;
3402 if(!source[0] || !destination[0])
3403 return E_INVALIDARG;
3405 attrs = GetFileAttributesW(destination);
3406 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
3407 attrs = GetFileAttributesW(source);
3408 if(attrs == INVALID_FILE_ATTRIBUTES)
3409 return create_error(GetLastError());
3410 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
3411 return CTL_E_FILENOTFOUND;
3413 if(!CopyFileW(source, destination, !overwrite))
3414 return create_error(GetLastError());
3415 return S_OK;
3418 f = FindFirstFileW(source, &ffd);
3419 if(f == INVALID_HANDLE_VALUE)
3420 return CTL_E_FILENOTFOUND;
3422 src_len = get_parent_folder_name(source, source_len);
3423 if(src_len+1 >= MAX_PATH) {
3424 FindClose(f);
3425 return E_FAIL;
3427 if(src_len) {
3428 memcpy(src_path, source, src_len*sizeof(WCHAR));
3429 src_path[src_len++] = '\\';
3432 dst_len = destination_len;
3433 if(dst_len+1 >= MAX_PATH) {
3434 FindClose(f);
3435 return E_FAIL;
3437 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
3438 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
3439 dst_path[dst_len++] = '\\';
3441 hr = CTL_E_FILENOTFOUND;
3442 do {
3443 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3444 continue;
3446 name_len = strlenW(ffd.cFileName);
3447 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
3448 FindClose(f);
3449 return E_FAIL;
3451 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3452 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3454 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
3456 if(!CopyFileW(src_path, dst_path, !overwrite)) {
3457 FindClose(f);
3458 return create_error(GetLastError());
3459 }else {
3460 hr = S_OK;
3462 } while(FindNextFileW(f, &ffd));
3463 FindClose(f);
3465 return hr;
3468 static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
3469 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3471 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3473 if(!Source || !Destination)
3474 return E_POINTER;
3476 return copy_file(Source, SysStringLen(Source), Destination,
3477 SysStringLen(Destination), OverWriteFiles);
3480 static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
3481 DWORD destination_len, VARIANT_BOOL overwrite)
3483 DWORD tmp, src_len, dst_len, name_len;
3484 WCHAR src[MAX_PATH], dst[MAX_PATH];
3485 WIN32_FIND_DATAW ffd;
3486 HANDLE f;
3487 HRESULT hr;
3488 BOOL copied = FALSE;
3490 if(!source[0] || !destination[0])
3491 return E_INVALIDARG;
3493 dst_len = destination_len;
3494 if(dst_len+1 >= MAX_PATH)
3495 return E_FAIL;
3496 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
3498 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
3499 (tmp = GetFileAttributesW(source))!=INVALID_FILE_ATTRIBUTES &&
3500 tmp&FILE_ATTRIBUTE_DIRECTORY) {
3501 if(!CreateDirectoryW(dst, NULL)) {
3502 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3503 tmp = GetFileAttributesW(dst);
3504 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY))
3505 return CTL_E_FILEALREADYEXISTS;
3506 }else {
3507 return create_error(GetLastError());
3510 copied = TRUE;
3512 src_len = source_len;
3513 if(src_len+2 >= MAX_PATH)
3514 return E_FAIL;
3515 memcpy(src, source, src_len*sizeof(WCHAR));
3516 src[src_len++] = '\\';
3517 src[src_len] = '*';
3518 src[src_len+1] = 0;
3520 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
3521 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND)
3522 return create_error(GetLastError());
3524 f = FindFirstFileW(src, &ffd);
3525 }else {
3526 src_len = get_parent_folder_name(source, source_len);
3527 if(src_len+2 >= MAX_PATH)
3528 return E_FAIL;
3529 memcpy(src, source, src_len*sizeof(WCHAR));
3530 if(src_len)
3531 src[src_len++] = '\\';
3533 f = FindFirstFileW(source, &ffd);
3535 if(f == INVALID_HANDLE_VALUE)
3536 return CTL_E_PATHNOTFOUND;
3538 dst[dst_len++] = '\\';
3539 dst[dst_len] = 0;
3541 do {
3542 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3543 continue;
3544 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3545 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3546 continue;
3548 name_len = strlenW(ffd.cFileName);
3549 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
3550 FindClose(f);
3551 return E_FAIL;
3553 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
3554 dst[dst_len+name_len] = 0;
3555 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
3556 src[src_len+name_len] = '\\';
3557 src[src_len+name_len+1] = '*';
3558 src[src_len+name_len+2] = 0;
3560 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
3562 if(!CreateDirectoryW(dst, NULL)) {
3563 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3564 tmp = GetFileAttributesW(dst);
3565 if(tmp==INVALID_FILE_ATTRIBUTES || !(tmp&FILE_ATTRIBUTE_DIRECTORY)) {
3566 FindClose(f);
3567 return CTL_E_FILEALREADYEXISTS;
3571 FindClose(f);
3572 return create_error(GetLastError());
3574 copied = TRUE;
3576 hr = copy_file(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3577 if(FAILED(hr) && hr!=CTL_E_FILENOTFOUND) {
3578 FindClose(f);
3579 return hr;
3582 hr = copy_folder(src, src_len+name_len+2, dst, dst_len+name_len, overwrite);
3583 if(FAILED(hr) && hr!=CTL_E_PATHNOTFOUND) {
3584 FindClose(f);
3585 return hr;
3587 } while(FindNextFileW(f, &ffd));
3588 FindClose(f);
3590 return copied ? S_OK : CTL_E_PATHNOTFOUND;
3593 static HRESULT WINAPI filesys_CopyFolder(IFileSystem3 *iface, BSTR Source,
3594 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3596 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3598 if(!Source || !Destination)
3599 return E_POINTER;
3601 return copy_folder(Source, SysStringLen(Source), Destination,
3602 SysStringLen(Destination), OverWriteFiles);
3605 static HRESULT WINAPI filesys_CreateFolder(IFileSystem3 *iface, BSTR path,
3606 IFolder **folder)
3608 BOOL ret;
3610 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), folder);
3612 ret = CreateDirectoryW(path, NULL);
3613 if (!ret)
3615 *folder = NULL;
3616 if (GetLastError() == ERROR_ALREADY_EXISTS) return CTL_E_FILEALREADYEXISTS;
3617 return HRESULT_FROM_WIN32(GetLastError());
3620 return create_folder(path, folder);
3623 static HRESULT WINAPI filesys_CreateTextFile(IFileSystem3 *iface, BSTR filename,
3624 VARIANT_BOOL overwrite, VARIANT_BOOL unicode,
3625 ITextStream **stream)
3627 DWORD disposition;
3629 TRACE("%p %s %d %d %p\n", iface, debugstr_w(filename), overwrite, unicode, stream);
3631 disposition = overwrite == VARIANT_TRUE ? CREATE_ALWAYS : CREATE_NEW;
3632 return create_textstream(filename, disposition, ForWriting, !!unicode, stream);
3635 static HRESULT WINAPI filesys_OpenTextFile(IFileSystem3 *iface, BSTR filename,
3636 IOMode mode, VARIANT_BOOL create,
3637 Tristate format, ITextStream **stream)
3639 DWORD disposition;
3641 TRACE("(%p)->(%s %d %d %d %p)\n", iface, debugstr_w(filename), mode, create, format, stream);
3642 disposition = create == VARIANT_TRUE ? OPEN_ALWAYS : OPEN_EXISTING;
3644 if (format == TristateUseDefault) {
3645 FIXME("default format not handled, defaulting to unicode\n");
3646 format = TristateTrue;
3649 return create_textstream(filename, disposition, mode, format == TristateTrue, stream);
3652 static HRESULT WINAPI filesys_GetStandardStream(IFileSystem3 *iface,
3653 StandardStreamTypes StandardStreamType,
3654 VARIANT_BOOL Unicode,
3655 ITextStream **ppts)
3657 FIXME("%p %d %d %p\n", iface, StandardStreamType, Unicode, ppts);
3659 return E_NOTIMPL;
3662 static void get_versionstring(VS_FIXEDFILEINFO *info, WCHAR *ver)
3664 static const WCHAR fmtW[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
3665 DWORDLONG version;
3666 WORD a, b, c, d;
3668 version = (((DWORDLONG)info->dwFileVersionMS) << 32) + info->dwFileVersionLS;
3669 a = (WORD)( version >> 48);
3670 b = (WORD)((version >> 32) & 0xffff);
3671 c = (WORD)((version >> 16) & 0xffff);
3672 d = (WORD)( version & 0xffff);
3674 sprintfW(ver, fmtW, a, b, c, d);
3677 static HRESULT WINAPI filesys_GetFileVersion(IFileSystem3 *iface, BSTR name, BSTR *version)
3679 static const WCHAR rootW[] = {'\\',0};
3680 VS_FIXEDFILEINFO *info;
3681 WCHAR ver[30];
3682 void *ptr;
3683 DWORD len;
3684 BOOL ret;
3686 TRACE("%p %s %p\n", iface, debugstr_w(name), version);
3688 len = GetFileVersionInfoSizeW(name, NULL);
3689 if (!len)
3690 return HRESULT_FROM_WIN32(GetLastError());
3692 ptr = heap_alloc(len);
3693 if (!GetFileVersionInfoW(name, 0, len, ptr))
3695 heap_free(ptr);
3696 return HRESULT_FROM_WIN32(GetLastError());
3699 ret = VerQueryValueW(ptr, rootW, (void**)&info, &len);
3700 if (!ret)
3702 heap_free(ptr);
3703 return HRESULT_FROM_WIN32(GetLastError());
3706 get_versionstring(info, ver);
3707 heap_free(ptr);
3709 *version = SysAllocString(ver);
3710 TRACE("version=%s\n", debugstr_w(ver));
3712 return S_OK;
3715 static const struct IFileSystem3Vtbl filesys_vtbl =
3717 filesys_QueryInterface,
3718 filesys_AddRef,
3719 filesys_Release,
3720 filesys_GetTypeInfoCount,
3721 filesys_GetTypeInfo,
3722 filesys_GetIDsOfNames,
3723 filesys_Invoke,
3724 filesys_get_Drives,
3725 filesys_BuildPath,
3726 filesys_GetDriveName,
3727 filesys_GetParentFolderName,
3728 filesys_GetFileName,
3729 filesys_GetBaseName,
3730 filesys_GetExtensionName,
3731 filesys_GetAbsolutePathName,
3732 filesys_GetTempName,
3733 filesys_DriveExists,
3734 filesys_FileExists,
3735 filesys_FolderExists,
3736 filesys_GetDrive,
3737 filesys_GetFile,
3738 filesys_GetFolder,
3739 filesys_GetSpecialFolder,
3740 filesys_DeleteFile,
3741 filesys_DeleteFolder,
3742 filesys_MoveFile,
3743 filesys_MoveFolder,
3744 filesys_CopyFile,
3745 filesys_CopyFolder,
3746 filesys_CreateFolder,
3747 filesys_CreateTextFile,
3748 filesys_OpenTextFile,
3749 filesys_GetStandardStream,
3750 filesys_GetFileVersion
3753 static IFileSystem3 filesystem = { &filesys_vtbl };
3755 HRESULT WINAPI FileSystem_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
3757 TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
3759 return IFileSystem3_QueryInterface(&filesystem, riid, ppv);