ReactOS 0.4.16-dev-340-g0540c21
filesystem.c
Go to the documentation of this file.
1/*
2 * Copyright 2012 Alistair Leslie-Hughes
3 *
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.
8 *
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.
13 *
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
17 */
18
19#define COBJMACROS
20
21#include <stdarg.h>
22#include <limits.h>
23#ifdef __REACTOS__
24#include <wchar.h>
25#endif
26
27#include "windef.h"
28#include "winbase.h"
29#include "ole2.h"
30#include "olectl.h"
31#include "dispex.h"
32#include "ntsecapi.h"
33#include "scrrun.h"
34#include "scrrun_private.h"
35
36#include "wine/debug.h"
37#include "wine/heap.h"
38
39#ifdef __REACTOS__
40#include <winver.h>
41#endif
42
44
45static const WCHAR bsW[] = {'\\',0};
46static const WCHAR utf16bom = 0xfeff;
47
48struct filesystem {
50 IFileSystem3 IFileSystem3_iface;
51};
52
55 IFolderCollection IFolderCollection_iface;
58};
59
62 IFileCollection IFileCollection_iface;
65};
66
69 IDriveCollection IDriveCollection_iface;
73};
74
75struct enumdata {
76 union
77 {
78 struct
79 {
83 struct
84 {
88 struct
89 {
93 } u;
94};
95
99
101};
102
103struct drive {
108};
109
110struct folder {
115};
116
117struct file {
121
123};
124
127 ITextStream ITextStream_iface;
129
130 IOMode mode;
135};
136
137enum iotype {
139 IOWrite
141
142static inline struct filesystem *impl_from_IFileSystem3(IFileSystem3 *iface)
143{
144 return CONTAINING_RECORD(iface, struct filesystem, IFileSystem3_iface);
145}
146
147static inline struct drive *impl_from_IDrive(IDrive *iface)
148{
149 return CONTAINING_RECORD(iface, struct drive, IDrive_iface);
150}
151
152static inline struct folder *impl_from_IFolder(IFolder *iface)
153{
154 return CONTAINING_RECORD(iface, struct folder, IFolder_iface);
155}
156
157static inline struct file *impl_from_IFile(IFile *iface)
158{
159 return CONTAINING_RECORD(iface, struct file, IFile_iface);
160}
161
162static inline struct textstream *impl_from_ITextStream(ITextStream *iface)
163{
164 return CONTAINING_RECORD(iface, struct textstream, ITextStream_iface);
165}
166
167static inline struct foldercollection *impl_from_IFolderCollection(IFolderCollection *iface)
168{
170}
171
172static inline struct filecollection *impl_from_IFileCollection(IFileCollection *iface)
173{
175}
176
177static inline struct drivecollection *impl_from_IDriveCollection(IDriveCollection *iface)
178{
180}
181
183{
184 return CONTAINING_RECORD(iface, struct enumvariant, IEnumVARIANT_iface);
185}
186
188{
189 switch(err) {
195 default:
196 FIXME("Unsupported error code: %d\n", err);
197 return E_FAIL;
198 }
199}
200
201static HRESULT create_folder(const WCHAR*, IFolder**);
202static HRESULT create_file(BSTR, IFile**);
206
208{
209 static const WCHAR dotdotW[] = {'.','.',0};
210 static const WCHAR dotW[] = {'.',0};
211
212 return (data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
213 wcscmp(data->cFileName, dotdotW) &&
214 wcscmp(data->cFileName, dotW);
215}
216
218{
219 return !(data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
220}
221
223{
224 int len = SysStringLen(path);
225 WCHAR buffW[MAX_PATH];
226
227 lstrcpyW(buffW, path);
228 if (path[len-1] != '\\')
229 lstrcatW(buffW, bsW);
230 lstrcatW(buffW, data->cFileName);
231
232 return SysAllocString(buffW);
233}
234
236{
237 if (type == IORead)
238 return This->mode == ForWriting || This->mode == ForAppending;
239 else
240 return This->mode == ForReading;
241}
242
243static HRESULT WINAPI textstream_QueryInterface(ITextStream *iface, REFIID riid, void **obj)
244{
245 struct textstream *This = impl_from_ITextStream(iface);
246
247 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
248
249 if (IsEqualIID(riid, &IID_ITextStream) ||
252 {
253 *obj = &This->ITextStream_iface;
254 }
256 {
257 *obj = &This->classinfo.IProvideClassInfo_iface;
258 }
259 else
260 return E_NOINTERFACE;
261
262 IUnknown_AddRef((IUnknown*)*obj);
263 return S_OK;
264}
265
266static ULONG WINAPI textstream_AddRef(ITextStream *iface)
267{
268 struct textstream *This = impl_from_ITextStream(iface);
270 TRACE("(%p)->(%d)\n", This, ref);
271 return ref;
272}
273
274static ULONG WINAPI textstream_Release(ITextStream *iface)
275{
276 struct textstream *This = impl_from_ITextStream(iface);
278 TRACE("(%p)->(%d)\n", This, ref);
279
280 if (!ref)
281 {
282 CloseHandle(This->file);
284 }
285
286 return ref;
287}
288
289static HRESULT WINAPI textstream_GetTypeInfoCount(ITextStream *iface, UINT *pctinfo)
290{
291 struct textstream *This = impl_from_ITextStream(iface);
292 TRACE("(%p)->(%p)\n", This, pctinfo);
293 *pctinfo = 1;
294 return S_OK;
295}
296
297static HRESULT WINAPI textstream_GetTypeInfo(ITextStream *iface, UINT iTInfo,
298 LCID lcid, ITypeInfo **ppTInfo)
299{
300 struct textstream *This = impl_from_ITextStream(iface);
301 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
302 return get_typeinfo(ITextStream_tid, ppTInfo);
303}
304
306 LPOLESTR *rgszNames, UINT cNames,
307 LCID lcid, DISPID *rgDispId)
308{
309 struct textstream *This = impl_from_ITextStream(iface);
311 HRESULT hr;
312
313 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
314
316 if(SUCCEEDED(hr))
317 {
318 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
319 ITypeInfo_Release(typeinfo);
320 }
321
322 return hr;
323}
324
325static HRESULT WINAPI textstream_Invoke(ITextStream *iface, DISPID dispIdMember,
326 REFIID riid, LCID lcid, WORD wFlags,
327 DISPPARAMS *pDispParams, VARIANT *pVarResult,
328 EXCEPINFO *pExcepInfo, UINT *puArgErr)
329{
330 struct textstream *This = impl_from_ITextStream(iface);
332 HRESULT hr;
333
334 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
335 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
336
338 if(SUCCEEDED(hr))
339 {
340 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
341 pDispParams, pVarResult, pExcepInfo, puArgErr);
342 ITypeInfo_Release(typeinfo);
343 }
344
345 return hr;
346}
347
348static HRESULT WINAPI textstream_get_Line(ITextStream *iface, LONG *line)
349{
350 struct textstream *This = impl_from_ITextStream(iface);
351 FIXME("(%p)->(%p): stub\n", This, line);
352 return E_NOTIMPL;
353}
354
355static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
356{
357 struct textstream *This = impl_from_ITextStream(iface);
358 FIXME("(%p)->(%p): stub\n", This, column);
359 return E_NOTIMPL;
360}
361
363{
364 struct textstream *This = impl_from_ITextStream(iface);
365 LARGE_INTEGER pos, dist;
366
367 TRACE("(%p)->(%p)\n", This, eos);
368
369 if (!eos)
370 return E_POINTER;
371
373 *eos = VARIANT_TRUE;
374 return CTL_E_BADFILEMODE;
375 }
376
377 dist.QuadPart = 0;
378 if (!SetFilePointerEx(This->file, dist, &pos, FILE_CURRENT))
379 return E_FAIL;
380
381 *eos = This->size.QuadPart == pos.QuadPart ? VARIANT_TRUE : VARIANT_FALSE;
382 return S_OK;
383}
384
386{
387 struct textstream *This = impl_from_ITextStream(iface);
388 FIXME("(%p)->(%p): stub\n", This, eol);
389 return E_NOTIMPL;
390}
391
392/*
393 Reads 'toread' bytes from a file, converts if needed
394 BOM is skipped if 'bof' is set.
395 */
397{
398 HRESULT hr = S_OK;
399 DWORD read;
400 char *buff;
401 BOOL ret;
402
403 if (toread == 0) {
405 return *text ? S_FALSE : E_OUTOFMEMORY;
406 }
407
408 if (toread < sizeof(WCHAR))
409 return CTL_E_ENDOFFILE;
410
411 buff = heap_alloc(toread);
412 if (!buff)
413 return E_OUTOFMEMORY;
414
415 ret = ReadFile(stream->file, buff, toread, &read, NULL);
416 if (!ret || toread != read) {
417 WARN("failed to read from file %d, %d, error %d\n", read, toread, GetLastError());
419 return E_FAIL;
420 }
421
422 if (stream->unicode) {
423 int i = 0;
424
425 /* skip BOM */
426 if (bof && *(WCHAR*)buff == utf16bom) {
427 read -= sizeof(WCHAR);
428 i += sizeof(WCHAR);
429 }
430
431 *text = SysAllocStringLen(read ? (WCHAR*)&buff[i] : NULL, read/sizeof(WCHAR));
432 if (!*text) hr = E_OUTOFMEMORY;
433 }
434 else {
437 if (*text)
439 else
441 }
443
444 return hr;
445}
446
447static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
448{
449 struct textstream *This = impl_from_ITextStream(iface);
450 LARGE_INTEGER start, end, dist;
451 DWORD toread;
452 HRESULT hr;
453
454 TRACE("(%p)->(%d %p)\n", This, len, text);
455
456 if (!text)
457 return E_POINTER;
458
459 *text = NULL;
460 if (len <= 0)
461 return len == 0 ? S_OK : E_INVALIDARG;
462
464 return CTL_E_BADFILEMODE;
465
466 if (!This->first_read) {
467 VARIANT_BOOL eos;
468
469 /* check for EOF */
470 hr = ITextStream_get_AtEndOfStream(iface, &eos);
471 if (FAILED(hr))
472 return hr;
473
474 if (eos == VARIANT_TRUE)
475 return CTL_E_ENDOFFILE;
476 }
477
478 /* read everything from current position */
479 dist.QuadPart = 0;
480 SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
481 SetFilePointerEx(This->file, dist, &end, FILE_END);
482 toread = end.QuadPart - start.QuadPart;
483 /* rewind back */
484 dist.QuadPart = start.QuadPart;
485 SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
486
487 This->first_read = FALSE;
488 if (This->unicode) len *= sizeof(WCHAR);
489
490 hr = textstream_read(This, min(toread, len), start.QuadPart == 0, text);
491 if (FAILED(hr))
492 return hr;
493 else
494 return toread <= len ? S_FALSE : S_OK;
495}
496
497static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
498{
499 struct textstream *This = impl_from_ITextStream(iface);
500 VARIANT_BOOL eos;
501 HRESULT hr;
502
503 FIXME("(%p)->(%p): stub\n", This, text);
504
505 if (!text)
506 return E_POINTER;
507
508 *text = NULL;
510 return CTL_E_BADFILEMODE;
511
512 /* check for EOF */
513 hr = ITextStream_get_AtEndOfStream(iface, &eos);
514 if (FAILED(hr))
515 return hr;
516
517 if (eos == VARIANT_TRUE)
518 return CTL_E_ENDOFFILE;
519
520 return E_NOTIMPL;
521}
522
523static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
524{
525 struct textstream *This = impl_from_ITextStream(iface);
526 LARGE_INTEGER start, end, dist;
527 DWORD toread;
528 HRESULT hr;
529
530 TRACE("(%p)->(%p)\n", This, text);
531
532 if (!text)
533 return E_POINTER;
534
535 *text = NULL;
537 return CTL_E_BADFILEMODE;
538
539 if (!This->first_read) {
540 VARIANT_BOOL eos;
541
542 /* check for EOF */
543 hr = ITextStream_get_AtEndOfStream(iface, &eos);
544 if (FAILED(hr))
545 return hr;
546
547 if (eos == VARIANT_TRUE)
548 return CTL_E_ENDOFFILE;
549 }
550
551 /* read everything from current position */
552 dist.QuadPart = 0;
553 SetFilePointerEx(This->file, dist, &start, FILE_CURRENT);
554 SetFilePointerEx(This->file, dist, &end, FILE_END);
555 toread = end.QuadPart - start.QuadPart;
556 /* rewind back */
557 dist.QuadPart = start.QuadPart;
558 SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN);
559
560 This->first_read = FALSE;
561
562 hr = textstream_read(This, toread, start.QuadPart == 0, text);
563 return FAILED(hr) ? hr : S_FALSE;
564}
565
567{
568 DWORD written = 0;
569 BOOL ret;
570
571 if (stream->unicode) {
572 ret = WriteFile(stream->file, text, SysStringByteLen(text), &written, NULL);
573 return (ret && written == SysStringByteLen(text)) ? S_OK : create_error(GetLastError());
574 } else {
576 char *buffA;
577 HRESULT hr;
578
579 buffA = heap_alloc(len);
580 if (!buffA)
581 return E_OUTOFMEMORY;
582
584 ret = WriteFile(stream->file, buffA, len, &written, NULL);
585 hr = (ret && written == len) ? S_OK : create_error(GetLastError());
586 heap_free(buffA);
587 return hr;
588 }
589}
590
591static HRESULT WINAPI textstream_Write(ITextStream *iface, BSTR text)
592{
593 struct textstream *This = impl_from_ITextStream(iface);
594
595 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
596
598 return CTL_E_BADFILEMODE;
599
601}
602
604{
605 static const WCHAR crlfW[] = {'\r','\n'};
606 static const char crlfA[] = {'\r','\n'};
607 DWORD written = 0, len;
608 const void *ptr;
609 BOOL ret;
610
611 if (stream->unicode) {
612 ptr = crlfW;
613 len = sizeof(crlfW);
614 }
615 else {
616 ptr = crlfA;
617 len = sizeof(crlfA);
618 }
619
620 ret = WriteFile(stream->file, ptr, len, &written, NULL);
621 return (ret && written == len) ? S_OK : create_error(GetLastError());
622}
623
624static HRESULT WINAPI textstream_WriteLine(ITextStream *iface, BSTR text)
625{
626 struct textstream *This = impl_from_ITextStream(iface);
627 HRESULT hr;
628
629 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
630
632 return CTL_E_BADFILEMODE;
633
635 if (SUCCEEDED(hr))
637 return hr;
638}
639
641{
642 struct textstream *This = impl_from_ITextStream(iface);
643 FIXME("(%p)->(%d): stub\n", This, lines);
644 return E_NOTIMPL;
645}
646
647static HRESULT WINAPI textstream_Skip(ITextStream *iface, LONG count)
648{
649 struct textstream *This = impl_from_ITextStream(iface);
650 FIXME("(%p)->(%d): stub\n", This, count);
651 return E_NOTIMPL;
652}
653
654static HRESULT WINAPI textstream_SkipLine(ITextStream *iface)
655{
656 struct textstream *This = impl_from_ITextStream(iface);
657 FIXME("(%p): stub\n", This);
658 return E_NOTIMPL;
659}
660
661static HRESULT WINAPI textstream_Close(ITextStream *iface)
662{
663 struct textstream *This = impl_from_ITextStream(iface);
664 HRESULT hr = S_OK;
665
666 TRACE("(%p)\n", This);
667
668 if(!CloseHandle(This->file))
669 hr = S_FALSE;
670
671 This->file = NULL;
672
673 return hr;
674}
675
676static const ITextStreamVtbl textstreamvtbl = {
697};
698
699static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMode mode, Tristate format, ITextStream **ret)
700{
701 struct textstream *stream;
702 DWORD access = 0;
703
704 /* map access mode */
705 switch (mode)
706 {
707 case ForReading:
709 break;
710 case ForWriting:
712 break;
713 case ForAppending:
715 break;
716 default:
717 return E_INVALIDARG;
718 }
719
720 stream = heap_alloc(sizeof(struct textstream));
721 if (!stream) return E_OUTOFMEMORY;
722
723 stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
724 stream->ref = 1;
725 stream->mode = mode;
726 stream->first_read = TRUE;
727
728 stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
729 if (stream->file == INVALID_HANDLE_VALUE)
730 {
733 return hr;
734 }
735
736 if (mode == ForReading)
738 else
739 stream->size.QuadPart = 0;
740
741 if (mode == ForWriting)
742 {
743 stream->unicode = format == TristateTrue;
744 /* Write Unicode BOM */
745 if (stream->unicode && (disposition == CREATE_ALWAYS || disposition == CREATE_NEW)) {
746 DWORD written = 0;
747 BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL);
748 if (!ret || written != sizeof(utf16bom)) {
749 ITextStream_Release(&stream->ITextStream_iface);
750 return create_error(GetLastError());
751 }
752 }
753 }
754 else
755 {
756 if (format == TristateUseDefault)
757 {
758 BYTE buf[64];
759 DWORD read;
760 BOOL ret;
761
762 ret = ReadFile(stream->file, buf, sizeof(buf), &read, NULL);
763 if (!ret) {
764 ITextStream_Release(&stream->ITextStream_iface);
765 return create_error(GetLastError());
766 }
767
768 stream->unicode = IsTextUnicode(buf, read, NULL);
769 if (mode == ForReading) SetFilePointer(stream->file, 0, 0, FILE_BEGIN);
770 }
771 else stream->unicode = format != TristateFalse;
772
773 if (mode == ForAppending) SetFilePointer(stream->file, 0, 0, FILE_END);
774 }
775
776 init_classinfo(&CLSID_TextStream, (IUnknown *)&stream->ITextStream_iface, &stream->classinfo);
777 *ret = &stream->ITextStream_iface;
778 return S_OK;
779}
780
781static HRESULT WINAPI drive_QueryInterface(IDrive *iface, REFIID riid, void **obj)
782{
783 struct drive *This = impl_from_IDrive(iface);
784
785 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
786
787 *obj = NULL;
788
789 if (IsEqualIID( riid, &IID_IDrive ) ||
792 {
793 *obj = &This->IDrive_iface;
794 }
796 {
797 *obj = &This->classinfo.IProvideClassInfo_iface;
798 }
799 else
800 return E_NOINTERFACE;
801
802 IUnknown_AddRef((IUnknown*)*obj);
803 return S_OK;
804}
805
806static ULONG WINAPI drive_AddRef(IDrive *iface)
807{
808 struct drive *This = impl_from_IDrive(iface);
810 TRACE("(%p)->(%d)\n", This, ref);
811 return ref;
812}
813
814static ULONG WINAPI drive_Release(IDrive *iface)
815{
816 struct drive *This = impl_from_IDrive(iface);
818 TRACE("(%p)->(%d)\n", This, ref);
819
820 if (!ref)
821 {
822 SysFreeString(This->root);
824 }
825
826 return ref;
827}
828
829static HRESULT WINAPI drive_GetTypeInfoCount(IDrive *iface, UINT *pctinfo)
830{
831 struct drive *This = impl_from_IDrive(iface);
832 TRACE("(%p)->(%p)\n", This, pctinfo);
833 *pctinfo = 1;
834 return S_OK;
835}
836
837static HRESULT WINAPI drive_GetTypeInfo(IDrive *iface, UINT iTInfo,
838 LCID lcid, ITypeInfo **ppTInfo)
839{
840 struct drive *This = impl_from_IDrive(iface);
841 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
842 return get_typeinfo(IDrive_tid, ppTInfo);
843}
844
846 LPOLESTR *rgszNames, UINT cNames,
847 LCID lcid, DISPID *rgDispId)
848{
849 struct drive *This = impl_from_IDrive(iface);
851 HRESULT hr;
852
853 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
854
856 if(SUCCEEDED(hr))
857 {
858 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
859 ITypeInfo_Release(typeinfo);
860 }
861
862 return hr;
863}
864
865static HRESULT WINAPI drive_Invoke(IDrive *iface, DISPID dispIdMember,
866 REFIID riid, LCID lcid, WORD wFlags,
867 DISPPARAMS *pDispParams, VARIANT *pVarResult,
868 EXCEPINFO *pExcepInfo, UINT *puArgErr)
869{
870 struct drive *This = impl_from_IDrive(iface);
872 HRESULT hr;
873
874 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
875 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
876
878 if(SUCCEEDED(hr))
879 {
880 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
881 pDispParams, pVarResult, pExcepInfo, puArgErr);
882 ITypeInfo_Release(typeinfo);
883 }
884
885 return hr;
886}
887
888static HRESULT WINAPI drive_get_Path(IDrive *iface, BSTR *path)
889{
890 struct drive *This = impl_from_IDrive(iface);
891 FIXME("(%p)->(%p): stub\n", This, path);
892 return E_NOTIMPL;
893}
894
895static HRESULT WINAPI drive_get_DriveLetter(IDrive *iface, BSTR *letter)
896{
897 struct drive *This = impl_from_IDrive(iface);
898
899 TRACE("(%p)->(%p)\n", This, letter);
900
901 if (!letter)
902 return E_POINTER;
903
904 *letter = SysAllocStringLen(This->root, 1);
905 if (!*letter)
906 return E_OUTOFMEMORY;
907
908 return S_OK;
909}
910
911static HRESULT WINAPI drive_get_ShareName(IDrive *iface, BSTR *share_name)
912{
913 struct drive *This = impl_from_IDrive(iface);
914 FIXME("(%p)->(%p): stub\n", This, share_name);
915 return E_NOTIMPL;
916}
917
918static HRESULT WINAPI drive_get_DriveType(IDrive *iface, DriveTypeConst *type)
919{
920 struct drive *This = impl_from_IDrive(iface);
921
922 TRACE("(%p)->(%p)\n", This, type);
923
924 switch (GetDriveTypeW(This->root))
925 {
926 case DRIVE_REMOVABLE:
927 *type = Removable;
928 break;
929 case DRIVE_FIXED:
930 *type = Fixed;
931 break;
932 case DRIVE_REMOTE:
933 *type = Remote;
934 break;
935 case DRIVE_CDROM:
936 *type = CDRom;
937 break;
938 case DRIVE_RAMDISK:
939 *type = RamDisk;
940 break;
941 default:
942 *type = UnknownType;
943 break;
944 }
945
946 return S_OK;
947}
948
949static HRESULT WINAPI drive_get_RootFolder(IDrive *iface, IFolder **folder)
950{
951 struct drive *This = impl_from_IDrive(iface);
952 FIXME("(%p)->(%p): stub\n", This, folder);
953 return E_NOTIMPL;
954}
955
957{
958 HRESULT hr = S_OK;
959
960 if (src->u.HighPart || src->u.LowPart > INT_MAX)
961 {
962 V_VT(v) = VT_R8;
963 hr = VarR8FromUI8(src->QuadPart, &V_R8(v));
964 }
965 else
966 {
967 V_VT(v) = VT_I4;
968 V_I4(v) = src->u.LowPart;
969 }
970
971 return hr;
972}
973
975{
976 struct drive *This = impl_from_IDrive(iface);
978
979 TRACE("(%p)->(%p)\n", This, v);
980
981 if (!v)
982 return E_POINTER;
983
984 if (!GetDiskFreeSpaceExW(This->root, &avail, NULL, NULL))
985 return E_FAIL;
986
987 return variant_from_largeint(&avail, v);
988}
989
991{
992 struct drive *This = impl_from_IDrive(iface);
993 ULARGE_INTEGER freespace;
994
995 TRACE("(%p)->(%p)\n", This, v);
996
997 if (!v)
998 return E_POINTER;
999
1000 if (!GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL))
1001 return E_FAIL;
1002
1003 return variant_from_largeint(&freespace, v);
1004}
1005
1007{
1008 struct drive *This = impl_from_IDrive(iface);
1010
1011 TRACE("(%p)->(%p)\n", This, v);
1012
1013 if (!v)
1014 return E_POINTER;
1015
1016 if (!GetDiskFreeSpaceExW(This->root, NULL, &total, NULL))
1017 return E_FAIL;
1018
1019 return variant_from_largeint(&total, v);
1020}
1021
1023{
1024 struct drive *This = impl_from_IDrive(iface);
1025 WCHAR nameW[MAX_PATH+1];
1026 BOOL ret;
1027
1028 TRACE("(%p)->(%p)\n", This, name);
1029
1030 if (!name)
1031 return E_POINTER;
1032
1033 *name = NULL;
1035 if (ret)
1037 return ret ? S_OK : E_FAIL;
1038}
1039
1041{
1042 struct drive *This = impl_from_IDrive(iface);
1043 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
1044 return E_NOTIMPL;
1045}
1046
1048{
1049 struct drive *This = impl_from_IDrive(iface);
1050 WCHAR nameW[MAX_PATH+1];
1051 BOOL ret;
1052
1053 TRACE("(%p)->(%p)\n", This, fs);
1054
1055 if (!fs)
1056 return E_POINTER;
1057
1058 *fs = NULL;
1060 if (ret)
1062 return ret ? S_OK : E_FAIL;
1063}
1064
1066{
1067 struct drive *This = impl_from_IDrive(iface);
1068 BOOL ret;
1069
1070 TRACE("(%p)->(%p)\n", This, serial);
1071
1072 if (!serial)
1073 return E_POINTER;
1074
1075 ret = GetVolumeInformationW(This->root, NULL, 0, (DWORD*)serial, NULL, NULL, NULL, 0);
1076 return ret ? S_OK : E_FAIL;
1077}
1078
1079static HRESULT WINAPI drive_get_IsReady(IDrive *iface, VARIANT_BOOL *ready)
1080{
1081 struct drive *This = impl_from_IDrive(iface);
1082 ULARGE_INTEGER freespace;
1083 BOOL ret;
1084
1085 TRACE("(%p)->(%p)\n", This, ready);
1086
1087 if (!ready)
1088 return E_POINTER;
1089
1090 ret = GetDiskFreeSpaceExW(This->root, &freespace, NULL, NULL);
1091 *ready = ret ? VARIANT_TRUE : VARIANT_FALSE;
1092 return S_OK;
1093}
1094
1095static const IDriveVtbl drivevtbl = {
1116};
1117
1118static HRESULT create_drive(WCHAR letter, IDrive **drive)
1119{
1120 struct drive *This;
1121
1122 *drive = NULL;
1123
1124 This = heap_alloc(sizeof(*This));
1125 if (!This) return E_OUTOFMEMORY;
1126
1127 This->IDrive_iface.lpVtbl = &drivevtbl;
1128 This->ref = 1;
1129 This->root = SysAllocStringLen(NULL, 3);
1130 if (!This->root)
1131 {
1132 heap_free(This);
1133 return E_OUTOFMEMORY;
1134 }
1135 This->root[0] = letter;
1136 This->root[1] = ':';
1137 This->root[2] = '\\';
1138 This->root[3] = 0;
1139
1140 init_classinfo(&CLSID_Drive, (IUnknown *)&This->IDrive_iface, &This->classinfo);
1141 *drive = &This->IDrive_iface;
1142 return S_OK;
1143}
1144
1146{
1147 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1148
1149 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1150
1151 *obj = NULL;
1152
1153 if (IsEqualIID( riid, &IID_IEnumVARIANT ) ||
1155 {
1156 *obj = iface;
1157 IEnumVARIANT_AddRef(iface);
1158 }
1159 else
1160 return E_NOINTERFACE;
1161
1162 return S_OK;
1163}
1164
1166{
1167 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1169 TRACE("(%p)->(%d)\n", This, ref);
1170 return ref;
1171}
1172
1174{
1175 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1177
1178 TRACE("(%p)->(%d)\n", This, ref);
1179
1180 if (!ref)
1181 {
1182 IFolderCollection_Release(&This->data.u.foldercoll.coll->IFolderCollection_iface);
1183 FindClose(This->data.u.foldercoll.find);
1184 heap_free(This);
1185 }
1186
1187 return ref;
1188}
1189
1191{
1192 static const WCHAR allW[] = {'*',0};
1193 WCHAR pathW[MAX_PATH];
1194 int len;
1195 HANDLE handle;
1196
1197 lstrcpyW(pathW, path);
1198 len = lstrlenW(pathW);
1199 if (len && pathW[len-1] != '\\')
1200 lstrcatW(pathW, bsW);
1201 lstrcatW(pathW, allW);
1202 handle = FindFirstFileW(pathW, data);
1203 if (handle == INVALID_HANDLE_VALUE) return 0;
1204
1205 /* find first dir/file */
1206 while (1)
1207 {
1209 break;
1210
1211 if (!FindNextFileW(handle, data))
1212 {
1214 return 0;
1215 }
1216 }
1217 return handle;
1218}
1219
1221{
1222 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1223 HANDLE handle = This->data.u.foldercoll.find;
1225 ULONG count = 0;
1226
1227 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1228
1229 if (fetched)
1230 *fetched = 0;
1231
1232 if (!celt) return S_OK;
1233
1234 if (!handle)
1235 {
1236 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1237 if (!handle) return S_FALSE;
1238
1239 This->data.u.foldercoll.find = handle;
1240 }
1241 else
1242 {
1243 if (!FindNextFileW(handle, &data))
1244 return S_FALSE;
1245 }
1246
1247 do
1248 {
1249 if (is_dir_data(&data))
1250 {
1251 IFolder *folder;
1252 HRESULT hr;
1253 BSTR str;
1254
1255 str = get_full_path(This->data.u.foldercoll.coll->path, &data);
1258 if (FAILED(hr)) return hr;
1259
1262 count++;
1263
1264 if (count >= celt) break;
1265 }
1266 } while (FindNextFileW(handle, &data));
1267
1268 if (fetched)
1269 *fetched = count;
1270
1271 return (count < celt) ? S_FALSE : S_OK;
1272}
1273
1275{
1276 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1277 HANDLE handle = This->data.u.foldercoll.find;
1279
1280 TRACE("(%p)->(%d)\n", This, celt);
1281
1282 if (!celt) return S_OK;
1283
1284 if (!handle)
1285 {
1286 handle = start_enumeration(This->data.u.foldercoll.coll->path, &data, FALSE);
1287 if (!handle) return S_FALSE;
1288
1289 This->data.u.foldercoll.find = handle;
1290 }
1291 else
1292 {
1293 if (!FindNextFileW(handle, &data))
1294 return S_FALSE;
1295 }
1296
1297 do
1298 {
1299 if (is_dir_data(&data))
1300 --celt;
1301
1302 if (!celt) break;
1303 } while (FindNextFileW(handle, &data));
1304
1305 return celt ? S_FALSE : S_OK;
1306}
1307
1309{
1310 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1311
1312 TRACE("(%p)\n", This);
1313
1314 FindClose(This->data.u.foldercoll.find);
1315 This->data.u.foldercoll.find = NULL;
1316
1317 return S_OK;
1318}
1319
1321{
1322 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1323 TRACE("(%p)->(%p)\n", This, pclone);
1324 return create_foldercoll_enum(This->data.u.foldercoll.coll, (IUnknown**)pclone);
1325}
1326
1327static const IEnumVARIANTVtbl foldercollenumvariantvtbl = {
1335};
1336
1338{
1339 struct enumvariant *This;
1340
1341 *newenum = NULL;
1342
1343 This = heap_alloc(sizeof(*This));
1344 if (!This) return E_OUTOFMEMORY;
1345
1346 This->IEnumVARIANT_iface.lpVtbl = &foldercollenumvariantvtbl;
1347 This->ref = 1;
1348 This->data.u.foldercoll.find = NULL;
1349 This->data.u.foldercoll.coll = collection;
1350 IFolderCollection_AddRef(&collection->IFolderCollection_iface);
1351
1352 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1353
1354 return S_OK;
1355}
1356
1358{
1359 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1361
1362 TRACE("(%p)->(%d)\n", This, ref);
1363
1364 if (!ref)
1365 {
1366 IFileCollection_Release(&This->data.u.filecoll.coll->IFileCollection_iface);
1367 FindClose(This->data.u.filecoll.find);
1368 heap_free(This);
1369 }
1370
1371 return ref;
1372}
1373
1375{
1376 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1377 HANDLE handle = This->data.u.filecoll.find;
1379 ULONG count = 0;
1380
1381 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1382
1383 if (fetched)
1384 *fetched = 0;
1385
1386 if (!celt) return S_OK;
1387
1388 if (!handle)
1389 {
1390 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1391 if (!handle) return S_FALSE;
1392 This->data.u.filecoll.find = handle;
1393 }
1394 else if (!FindNextFileW(handle, &data))
1395 return S_FALSE;
1396
1397 do
1398 {
1399 if (is_file_data(&data))
1400 {
1401 IFile *file;
1402 HRESULT hr;
1403 BSTR str;
1404
1405 str = get_full_path(This->data.u.filecoll.coll->path, &data);
1406 hr = create_file(str, &file);
1408 if (FAILED(hr)) return hr;
1409
1412 if (++count >= celt) break;
1413 }
1414 } while (FindNextFileW(handle, &data));
1415
1416 if (fetched)
1417 *fetched = count;
1418
1419 return (count < celt) ? S_FALSE : S_OK;
1420}
1421
1423{
1424 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1425 HANDLE handle = This->data.u.filecoll.find;
1427
1428 TRACE("(%p)->(%d)\n", This, celt);
1429
1430 if (!celt) return S_OK;
1431
1432 if (!handle)
1433 {
1434 handle = start_enumeration(This->data.u.filecoll.coll->path, &data, TRUE);
1435 if (!handle) return S_FALSE;
1436 This->data.u.filecoll.find = handle;
1437 }
1438 else if (!FindNextFileW(handle, &data))
1439 return S_FALSE;
1440
1441 do
1442 {
1443 if (is_file_data(&data))
1444 --celt;
1445 } while (celt && FindNextFileW(handle, &data));
1446
1447 return celt ? S_FALSE : S_OK;
1448}
1449
1451{
1452 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1453
1454 TRACE("(%p)\n", This);
1455
1456 FindClose(This->data.u.filecoll.find);
1457 This->data.u.filecoll.find = NULL;
1458
1459 return S_OK;
1460}
1461
1463{
1464 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1465 TRACE("(%p)->(%p)\n", This, pclone);
1466 return create_filecoll_enum(This->data.u.filecoll.coll, (IUnknown**)pclone);
1467}
1468
1469static const IEnumVARIANTVtbl filecollenumvariantvtbl = {
1477};
1478
1480{
1481 struct enumvariant *This;
1482
1483 *newenum = NULL;
1484
1485 This = heap_alloc(sizeof(*This));
1486 if (!This) return E_OUTOFMEMORY;
1487
1488 This->IEnumVARIANT_iface.lpVtbl = &filecollenumvariantvtbl;
1489 This->ref = 1;
1490 This->data.u.filecoll.find = NULL;
1491 This->data.u.filecoll.coll = collection;
1492 IFileCollection_AddRef(&collection->IFileCollection_iface);
1493
1494 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1495
1496 return S_OK;
1497}
1498
1500{
1501 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1503
1504 TRACE("(%p)->(%d)\n", This, ref);
1505
1506 if (!ref)
1507 {
1508 IDriveCollection_Release(&This->data.u.drivecoll.coll->IDriveCollection_iface);
1509 heap_free(This);
1510 }
1511
1512 return ref;
1513}
1514
1516{
1517 int i = penum->data.u.drivecoll.cur == -1 ? 0 : penum->data.u.drivecoll.cur + 1;
1518
1519 for (; i < 32; i++)
1520 if (penum->data.u.drivecoll.coll->drives & (1 << i))
1521 {
1522 penum->data.u.drivecoll.cur = i;
1523 return S_OK;
1524 }
1525
1526 return S_FALSE;
1527}
1528
1530{
1531 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1532 ULONG count = 0;
1533
1534 TRACE("(%p)->(%d %p %p)\n", This, celt, var, fetched);
1535
1536 if (fetched)
1537 *fetched = 0;
1538
1539 if (!celt) return S_OK;
1540
1541 while (find_next_drive(This) == S_OK)
1542 {
1543 IDrive *drive;
1544 HRESULT hr;
1545
1546 hr = create_drive('A' + This->data.u.drivecoll.cur, &drive);
1547 if (FAILED(hr)) return hr;
1548
1551
1552 if (++count >= celt) break;
1553 }
1554
1555 if (fetched)
1556 *fetched = count;
1557
1558 return (count < celt) ? S_FALSE : S_OK;
1559}
1560
1562{
1563 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1564
1565 TRACE("(%p)->(%d)\n", This, celt);
1566
1567 if (!celt) return S_OK;
1568
1569 while (celt && find_next_drive(This) == S_OK)
1570 celt--;
1571
1572 return celt ? S_FALSE : S_OK;
1573}
1574
1576{
1577 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1578
1579 TRACE("(%p)\n", This);
1580
1581 This->data.u.drivecoll.cur = -1;
1582 return S_OK;
1583}
1584
1586{
1587 struct enumvariant *This = impl_from_IEnumVARIANT(iface);
1588 TRACE("(%p)->(%p)\n", This, pclone);
1589 return create_drivecoll_enum(This->data.u.drivecoll.coll, (IUnknown**)pclone);
1590}
1591
1592static const IEnumVARIANTVtbl drivecollenumvariantvtbl = {
1600};
1601
1603{
1604 struct enumvariant *This;
1605
1606 *newenum = NULL;
1607
1608 This = heap_alloc(sizeof(*This));
1609 if (!This) return E_OUTOFMEMORY;
1610
1611 This->IEnumVARIANT_iface.lpVtbl = &drivecollenumvariantvtbl;
1612 This->ref = 1;
1613 This->data.u.drivecoll.coll = collection;
1614 This->data.u.drivecoll.cur = -1;
1615 IDriveCollection_AddRef(&collection->IDriveCollection_iface);
1616
1617 *newenum = (IUnknown*)&This->IEnumVARIANT_iface;
1618
1619 return S_OK;
1620}
1621
1622static HRESULT WINAPI foldercoll_QueryInterface(IFolderCollection *iface, REFIID riid, void **obj)
1623{
1625
1626 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1627
1628 *obj = NULL;
1629
1630 if (IsEqualIID( riid, &IID_IFolderCollection ) ||
1633 {
1634 *obj = &This->IFolderCollection_iface;
1635 }
1637 {
1638 *obj = &This->classinfo.IProvideClassInfo_iface;
1639 }
1640 else
1641 return E_NOINTERFACE;
1642
1643 IUnknown_AddRef((IUnknown*)*obj);
1644 return S_OK;
1645}
1646
1647static ULONG WINAPI foldercoll_AddRef(IFolderCollection *iface)
1648{
1651 TRACE("(%p)->(%d)\n", This, ref);
1652 return ref;
1653}
1654
1655static ULONG WINAPI foldercoll_Release(IFolderCollection *iface)
1656{
1659 TRACE("(%p)->(%d)\n", This, ref);
1660
1661 if (!ref)
1662 {
1663 SysFreeString(This->path);
1664 heap_free(This);
1665 }
1666
1667 return ref;
1668}
1669
1670static HRESULT WINAPI foldercoll_GetTypeInfoCount(IFolderCollection *iface, UINT *pctinfo)
1671{
1673 TRACE("(%p)->(%p)\n", This, pctinfo);
1674 *pctinfo = 1;
1675 return S_OK;
1676}
1677
1678static HRESULT WINAPI foldercoll_GetTypeInfo(IFolderCollection *iface, UINT iTInfo,
1679 LCID lcid, ITypeInfo **ppTInfo)
1680{
1682 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1683 return get_typeinfo(IFolderCollection_tid, ppTInfo);
1684}
1685
1686static HRESULT WINAPI foldercoll_GetIDsOfNames(IFolderCollection *iface, REFIID riid,
1687 LPOLESTR *rgszNames, UINT cNames,
1688 LCID lcid, DISPID *rgDispId)
1689{
1692 HRESULT hr;
1693
1694 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1695
1697 if(SUCCEEDED(hr))
1698 {
1699 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1700 ITypeInfo_Release(typeinfo);
1701 }
1702
1703 return hr;
1704}
1705
1706static HRESULT WINAPI foldercoll_Invoke(IFolderCollection *iface, DISPID dispIdMember,
1707 REFIID riid, LCID lcid, WORD wFlags,
1708 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1709 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1710{
1713 HRESULT hr;
1714
1715 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1716 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1717
1719 if(SUCCEEDED(hr))
1720 {
1721 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1722 pDispParams, pVarResult, pExcepInfo, puArgErr);
1723 ITypeInfo_Release(typeinfo);
1724 }
1725
1726 return hr;
1727}
1728
1729static HRESULT WINAPI foldercoll_Add(IFolderCollection *iface, BSTR name, IFolder **folder)
1730{
1732 FIXME("(%p)->(%s %p): stub\n", This, debugstr_w(name), folder);
1733 return E_NOTIMPL;
1734}
1735
1736static HRESULT WINAPI foldercoll_get_Item(IFolderCollection *iface, VARIANT key, IFolder **folder)
1737{
1739 FIXME("(%p)->(%p): stub\n", This, folder);
1740 return E_NOTIMPL;
1741}
1742
1743static HRESULT WINAPI foldercoll_get__NewEnum(IFolderCollection *iface, IUnknown **newenum)
1744{
1746
1747 TRACE("(%p)->(%p)\n", This, newenum);
1748
1749 if(!newenum)
1750 return E_POINTER;
1751
1752 return create_foldercoll_enum(This, newenum);
1753}
1754
1755static HRESULT WINAPI foldercoll_get_Count(IFolderCollection *iface, LONG *count)
1756{
1758 static const WCHAR allW[] = {'\\','*',0};
1760 WCHAR pathW[MAX_PATH];
1761 HANDLE handle;
1762
1763 TRACE("(%p)->(%p)\n", This, count);
1764
1765 if(!count)
1766 return E_POINTER;
1767
1768 *count = 0;
1769
1770 lstrcpyW(pathW, This->path);
1771 lstrcatW(pathW, allW);
1772 handle = FindFirstFileW(pathW, &data);
1775
1776 do
1777 {
1778 if (is_dir_data(&data))
1779 *count += 1;
1780 } while (FindNextFileW(handle, &data));
1782
1783 return S_OK;
1784}
1785
1786static const IFolderCollectionVtbl foldercollvtbl = {
1798};
1799
1800static HRESULT create_foldercoll(BSTR path, IFolderCollection **folders)
1801{
1802 struct foldercollection *This;
1803
1804 *folders = NULL;
1805
1806 This = heap_alloc(sizeof(struct foldercollection));
1807 if (!This) return E_OUTOFMEMORY;
1808
1809 This->IFolderCollection_iface.lpVtbl = &foldercollvtbl;
1810 This->ref = 1;
1811 This->path = SysAllocString(path);
1812 if (!This->path)
1813 {
1814 heap_free(This);
1815 return E_OUTOFMEMORY;
1816 }
1817
1818 init_classinfo(&CLSID_Folders, (IUnknown *)&This->IFolderCollection_iface, &This->classinfo);
1819 *folders = &This->IFolderCollection_iface;
1820
1821 return S_OK;
1822}
1823
1824static HRESULT WINAPI filecoll_QueryInterface(IFileCollection *iface, REFIID riid, void **obj)
1825{
1827
1828 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1829
1830 *obj = NULL;
1831
1832 if (IsEqualIID( riid, &IID_IFileCollection ) ||
1835 {
1836 *obj = &This->IFileCollection_iface;
1837 }
1839 {
1840 *obj = &This->classinfo.IProvideClassInfo_iface;
1841 }
1842 else
1843 return E_NOINTERFACE;
1844
1845 IUnknown_AddRef((IUnknown*)*obj);
1846 return S_OK;
1847}
1848
1849static ULONG WINAPI filecoll_AddRef(IFileCollection *iface)
1850{
1853 TRACE("(%p)->(%d)\n", This, ref);
1854 return ref;
1855}
1856
1857static ULONG WINAPI filecoll_Release(IFileCollection *iface)
1858{
1861 TRACE("(%p)->(%d)\n", This, ref);
1862
1863 if (!ref)
1864 {
1865 SysFreeString(This->path);
1866 heap_free(This);
1867 }
1868
1869 return ref;
1870}
1871
1872static HRESULT WINAPI filecoll_GetTypeInfoCount(IFileCollection *iface, UINT *pctinfo)
1873{
1875 TRACE("(%p)->(%p)\n", This, pctinfo);
1876 *pctinfo = 1;
1877 return S_OK;
1878}
1879
1880static HRESULT WINAPI filecoll_GetTypeInfo(IFileCollection *iface, UINT iTInfo,
1881 LCID lcid, ITypeInfo **ppTInfo)
1882{
1884 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1885 return get_typeinfo(IFileCollection_tid, ppTInfo);
1886}
1887
1888static HRESULT WINAPI filecoll_GetIDsOfNames(IFileCollection *iface, REFIID riid,
1889 LPOLESTR *rgszNames, UINT cNames,
1890 LCID lcid, DISPID *rgDispId)
1891{
1894 HRESULT hr;
1895
1896 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1897
1899 if(SUCCEEDED(hr))
1900 {
1901 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
1902 ITypeInfo_Release(typeinfo);
1903 }
1904
1905 return hr;
1906}
1907
1908static HRESULT WINAPI filecoll_Invoke(IFileCollection *iface, DISPID dispIdMember,
1909 REFIID riid, LCID lcid, WORD wFlags,
1910 DISPPARAMS *pDispParams, VARIANT *pVarResult,
1911 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1912{
1915 HRESULT hr;
1916
1917 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1918 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1919
1921 if(SUCCEEDED(hr))
1922 {
1923 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
1924 pDispParams, pVarResult, pExcepInfo, puArgErr);
1925 ITypeInfo_Release(typeinfo);
1926 }
1927
1928 return hr;
1929}
1930
1931static HRESULT WINAPI filecoll_get_Item(IFileCollection *iface, VARIANT Key, IFile **file)
1932{
1934 FIXME("(%p)->(%p)\n", This, file);
1935 return E_NOTIMPL;
1936}
1937
1938static HRESULT WINAPI filecoll_get__NewEnum(IFileCollection *iface, IUnknown **ppenum)
1939{
1941
1942 TRACE("(%p)->(%p)\n", This, ppenum);
1943
1944 if(!ppenum)
1945 return E_POINTER;
1946
1947 return create_filecoll_enum(This, ppenum);
1948}
1949
1950static HRESULT WINAPI filecoll_get_Count(IFileCollection *iface, LONG *count)
1951{
1953 static const WCHAR allW[] = {'\\','*',0};
1955 WCHAR pathW[MAX_PATH];
1956 HANDLE handle;
1957
1958 TRACE("(%p)->(%p)\n", This, count);
1959
1960 if(!count)
1961 return E_POINTER;
1962
1963 *count = 0;
1964
1965 lstrcpyW(pathW, This->path);
1966 lstrcatW(pathW, allW);
1967 handle = FindFirstFileW(pathW, &data);
1970
1971 do
1972 {
1973 if (is_file_data(&data))
1974 *count += 1;
1975 } while (FindNextFileW(handle, &data));
1977
1978 return S_OK;
1979}
1980
1981static const IFileCollectionVtbl filecollectionvtbl = {
1992};
1993
1994static HRESULT create_filecoll(BSTR path, IFileCollection **files)
1995{
1996 struct filecollection *This;
1997
1998 *files = NULL;
1999
2000 This = heap_alloc(sizeof(*This));
2001 if (!This) return E_OUTOFMEMORY;
2002
2003 This->IFileCollection_iface.lpVtbl = &filecollectionvtbl;
2004 This->ref = 1;
2005 This->path = SysAllocString(path);
2006 if (!This->path)
2007 {
2008 heap_free(This);
2009 return E_OUTOFMEMORY;
2010 }
2011
2012 init_classinfo(&CLSID_Files, (IUnknown *)&This->IFileCollection_iface, &This->classinfo);
2013 *files = &This->IFileCollection_iface;
2014 return S_OK;
2015}
2016
2017static HRESULT WINAPI drivecoll_QueryInterface(IDriveCollection *iface, REFIID riid, void **obj)
2018{
2020
2021 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2022
2023 *obj = NULL;
2024
2025 if (IsEqualIID( riid, &IID_IDriveCollection ) ||
2028 {
2029 *obj = &This->IDriveCollection_iface;
2030 }
2032 {
2033 *obj = &This->classinfo.IProvideClassInfo_iface;
2034 }
2035 else
2036 return E_NOINTERFACE;
2037
2038 IUnknown_AddRef((IUnknown*)*obj);
2039 return S_OK;
2040}
2041
2042static ULONG WINAPI drivecoll_AddRef(IDriveCollection *iface)
2043{
2046 TRACE("(%p)->(%d)\n", This, ref);
2047 return ref;
2048}
2049
2050static ULONG WINAPI drivecoll_Release(IDriveCollection *iface)
2051{
2054 TRACE("(%p)->(%d)\n", This, ref);
2055
2056 if (!ref)
2057 heap_free(This);
2058
2059 return ref;
2060}
2061
2062static HRESULT WINAPI drivecoll_GetTypeInfoCount(IDriveCollection *iface, UINT *pctinfo)
2063{
2065 TRACE("(%p)->(%p)\n", This, pctinfo);
2066 *pctinfo = 1;
2067 return S_OK;
2068}
2069
2070static HRESULT WINAPI drivecoll_GetTypeInfo(IDriveCollection *iface, UINT iTInfo,
2071 LCID lcid, ITypeInfo **ppTInfo)
2072{
2074 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2075 return get_typeinfo(IDriveCollection_tid, ppTInfo);
2076}
2077
2078static HRESULT WINAPI drivecoll_GetIDsOfNames(IDriveCollection *iface, REFIID riid,
2079 LPOLESTR *rgszNames, UINT cNames,
2080 LCID lcid, DISPID *rgDispId)
2081{
2084 HRESULT hr;
2085
2086 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2087
2089 if(SUCCEEDED(hr))
2090 {
2091 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2092 ITypeInfo_Release(typeinfo);
2093 }
2094
2095 return hr;
2096}
2097
2098static HRESULT WINAPI drivecoll_Invoke(IDriveCollection *iface, DISPID dispIdMember,
2099 REFIID riid, LCID lcid, WORD wFlags,
2100 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2101 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2102{
2105 HRESULT hr;
2106
2107 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2108 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2109
2111 if(SUCCEEDED(hr))
2112 {
2113 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2114 pDispParams, pVarResult, pExcepInfo, puArgErr);
2115 ITypeInfo_Release(typeinfo);
2116 }
2117
2118 return hr;
2119}
2120
2121static HRESULT WINAPI drivecoll_get_Item(IDriveCollection *iface, VARIANT key, IDrive **drive)
2122{
2124 FIXME("(%p)->(%p): stub\n", This, drive);
2125 return E_NOTIMPL;
2126}
2127
2128static HRESULT WINAPI drivecoll_get__NewEnum(IDriveCollection *iface, IUnknown **ppenum)
2129{
2131
2132 TRACE("(%p)->(%p)\n", This, ppenum);
2133
2134 if(!ppenum)
2135 return E_POINTER;
2136
2137 return create_drivecoll_enum(This, ppenum);
2138}
2139
2140static HRESULT WINAPI drivecoll_get_Count(IDriveCollection *iface, LONG *count)
2141{
2143
2144 TRACE("(%p)->(%p)\n", This, count);
2145
2146 if (!count) return E_POINTER;
2147
2148 *count = This->count;
2149 return S_OK;
2150}
2151
2152static const IDriveCollectionVtbl drivecollectionvtbl = {
2163};
2164
2165static HRESULT create_drivecoll(IDriveCollection **drives)
2166{
2167 struct drivecollection *This;
2168 DWORD mask;
2169
2170 *drives = NULL;
2171
2172 This = heap_alloc(sizeof(*This));
2173 if (!This) return E_OUTOFMEMORY;
2174
2175 This->IDriveCollection_iface.lpVtbl = &drivecollectionvtbl;
2176 This->ref = 1;
2177 This->drives = mask = GetLogicalDrives();
2178 /* count set bits */
2179 for (This->count = 0; mask; This->count++)
2180 mask &= mask - 1;
2181
2182 init_classinfo(&CLSID_Drives, (IUnknown *)&This->IDriveCollection_iface, &This->classinfo);
2183 *drives = &This->IDriveCollection_iface;
2184 return S_OK;
2185}
2186
2187static HRESULT WINAPI folder_QueryInterface(IFolder *iface, REFIID riid, void **obj)
2188{
2189 struct folder *This = impl_from_IFolder(iface);
2190
2191 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2192
2193 *obj = NULL;
2194
2195 if (IsEqualIID( riid, &IID_IFolder ) ||
2198 {
2199 *obj = &This->IFolder_iface;
2200 }
2202 {
2203 *obj = &This->classinfo.IProvideClassInfo_iface;
2204 }
2205 else
2206 return E_NOINTERFACE;
2207
2208 IUnknown_AddRef((IUnknown*)*obj);
2209 return S_OK;
2210}
2211
2212static ULONG WINAPI folder_AddRef(IFolder *iface)
2213{
2214 struct folder *This = impl_from_IFolder(iface);
2216 TRACE("(%p)->(%d)\n", This, ref);
2217 return ref;
2218}
2219
2220static ULONG WINAPI folder_Release(IFolder *iface)
2221{
2222 struct folder *This = impl_from_IFolder(iface);
2224 TRACE("(%p)->(%d)\n", This, ref);
2225
2226 if (!ref)
2227 {
2228 SysFreeString(This->path);
2229 heap_free(This);
2230 }
2231
2232 return ref;
2233}
2234
2235static HRESULT WINAPI folder_GetTypeInfoCount(IFolder *iface, UINT *pctinfo)
2236{
2237 struct folder *This = impl_from_IFolder(iface);
2238 TRACE("(%p)->(%p)\n", This, pctinfo);
2239 *pctinfo = 1;
2240 return S_OK;
2241}
2242
2243static HRESULT WINAPI folder_GetTypeInfo(IFolder *iface, UINT iTInfo,
2244 LCID lcid, ITypeInfo **ppTInfo)
2245{
2246 struct folder *This = impl_from_IFolder(iface);
2247 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2248 return get_typeinfo(IFolder_tid, ppTInfo);
2249}
2250
2252 LPOLESTR *rgszNames, UINT cNames,
2253 LCID lcid, DISPID *rgDispId)
2254{
2255 struct folder *This = impl_from_IFolder(iface);
2257 HRESULT hr;
2258
2259 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2260
2262 if(SUCCEEDED(hr))
2263 {
2264 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2265 ITypeInfo_Release(typeinfo);
2266 }
2267
2268 return hr;
2269}
2270
2271static HRESULT WINAPI folder_Invoke(IFolder *iface, DISPID dispIdMember,
2272 REFIID riid, LCID lcid, WORD wFlags,
2273 DISPPARAMS *pDispParams, VARIANT *pVarResult,
2274 EXCEPINFO *pExcepInfo, UINT *puArgErr)
2275{
2276 struct folder *This = impl_from_IFolder(iface);
2278 HRESULT hr;
2279
2280 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2281 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2282
2284 if(SUCCEEDED(hr))
2285 {
2286 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2287 pDispParams, pVarResult, pExcepInfo, puArgErr);
2288 ITypeInfo_Release(typeinfo);
2289 }
2290
2291 return hr;
2292}
2293
2294static HRESULT WINAPI folder_get_Path(IFolder *iface, BSTR *path)
2295{
2296 struct folder *This = impl_from_IFolder(iface);
2297
2298 TRACE("(%p)->(%p)\n", This, path);
2299
2300 if(!path)
2301 return E_POINTER;
2302
2303 *path = SysAllocString(This->path);
2304 return *path ? S_OK : E_OUTOFMEMORY;
2305}
2306
2307static HRESULT WINAPI folder_get_Name(IFolder *iface, BSTR *name)
2308{
2309 struct folder *This = impl_from_IFolder(iface);
2310 WCHAR *ptr;
2311
2312 TRACE("(%p)->(%p)\n", This, name);
2313
2314 if(!name)
2315 return E_POINTER;
2316
2317 *name = NULL;
2318
2319 ptr = wcsrchr(This->path, '\\');
2320 if (ptr)
2321 {
2322 *name = SysAllocString(ptr+1);
2323 TRACE("%s\n", debugstr_w(*name));
2324 if (!*name) return E_OUTOFMEMORY;
2325 }
2326 else
2327 return E_FAIL;
2328
2329 return S_OK;
2330}
2331
2332static HRESULT WINAPI folder_put_Name(IFolder *iface, BSTR name)
2333{
2334 struct folder *This = impl_from_IFolder(iface);
2335 FIXME("(%p)->(%s): stub\n", This, debugstr_w(name));
2336 return E_NOTIMPL;
2337}
2338
2340{
2341 struct folder *This = impl_from_IFolder(iface);
2342 FIXME("(%p)->(%p): stub\n", This, path);
2343 return E_NOTIMPL;
2344}
2345
2347{
2348 struct folder *This = impl_from_IFolder(iface);
2349 FIXME("(%p)->(%p): stub\n", This, name);
2350 return E_NOTIMPL;
2351}
2352
2353static HRESULT WINAPI folder_get_Drive(IFolder *iface, IDrive **drive)
2354{
2355 struct folder *This = impl_from_IFolder(iface);
2356 FIXME("(%p)->(%p): stub\n", This, drive);
2357 return E_NOTIMPL;
2358}
2359
2360static HRESULT WINAPI folder_get_ParentFolder(IFolder *iface, IFolder **parent)
2361{
2362 struct folder *This = impl_from_IFolder(iface);
2363 FIXME("(%p)->(%p): stub\n", This, parent);
2364 return E_NOTIMPL;
2365}
2366
2367static HRESULT WINAPI folder_get_Attributes(IFolder *iface, FileAttribute *attr)
2368{
2369 struct folder *This = impl_from_IFolder(iface);
2370 FIXME("(%p)->(%p): stub\n", This, attr);
2371 return E_NOTIMPL;
2372}
2373
2374static HRESULT WINAPI folder_put_Attributes(IFolder *iface, FileAttribute attr)
2375{
2376 struct folder *This = impl_from_IFolder(iface);
2377 FIXME("(%p)->(0x%x): stub\n", This, attr);
2378 return E_NOTIMPL;
2379}
2380
2382{
2383 struct folder *This = impl_from_IFolder(iface);
2384 FIXME("(%p)->(%p): stub\n", This, date);
2385 return E_NOTIMPL;
2386}
2387
2389{
2390 struct folder *This = impl_from_IFolder(iface);
2391 FIXME("(%p)->(%p): stub\n", This, date);
2392 return E_NOTIMPL;
2393}
2394
2396{
2397 struct folder *This = impl_from_IFolder(iface);
2398 FIXME("(%p)->(%p): stub\n", This, date);
2399 return E_NOTIMPL;
2400}
2401
2402static HRESULT WINAPI folder_get_Type(IFolder *iface, BSTR *type)
2403{
2404 struct folder *This = impl_from_IFolder(iface);
2405 FIXME("(%p)->(%p): stub\n", This, type);
2406 return E_NOTIMPL;
2407}
2408
2409static HRESULT WINAPI folder_Delete(IFolder *iface, VARIANT_BOOL force)
2410{
2411 struct folder *This = impl_from_IFolder(iface);
2412 FIXME("(%p)->(%x): stub\n", This, force);
2413 return E_NOTIMPL;
2414}
2415
2416static HRESULT WINAPI folder_Copy(IFolder *iface, BSTR dest, VARIANT_BOOL overwrite)
2417{
2418 struct folder *This = impl_from_IFolder(iface);
2419 FIXME("(%p)->(%s %x): stub\n", This, debugstr_w(dest), overwrite);
2420 return E_NOTIMPL;
2421}
2422
2423static HRESULT WINAPI folder_Move(IFolder *iface, BSTR dest)
2424{
2425 struct folder *This = impl_from_IFolder(iface);
2426 FIXME("(%p)->(%s): stub\n", This, debugstr_w(dest));
2427 return E_NOTIMPL;
2428}
2429
2431{
2432 struct folder *This = impl_from_IFolder(iface);
2433 FIXME("(%p)->(%p): stub\n", This, isroot);
2434 return E_NOTIMPL;
2435}
2436
2438{
2439 struct folder *This = impl_from_IFolder(iface);
2440 FIXME("(%p)->(%p): stub\n", This, size);
2441 return E_NOTIMPL;
2442}
2443
2444static HRESULT WINAPI folder_get_SubFolders(IFolder *iface, IFolderCollection **folders)
2445{
2446 struct folder *This = impl_from_IFolder(iface);
2447
2448 TRACE("(%p)->(%p)\n", This, folders);
2449
2450 if(!folders)
2451 return E_POINTER;
2452
2453 return create_foldercoll(This->path, folders);
2454}
2455
2456static HRESULT WINAPI folder_get_Files(IFolder *iface, IFileCollection **files)
2457{
2458 struct folder *This = impl_from_IFolder(iface);
2459
2460 TRACE("(%p)->(%p)\n", This, files);
2461
2462 if(!files)
2463 return E_POINTER;
2464
2465 return create_filecoll(This->path, files);
2466}
2467
2469 VARIANT_BOOL unicode, ITextStream **stream)
2470{
2471 struct folder *This = impl_from_IFolder(iface);
2472 FIXME("(%p)->(%s %x %x %p): stub\n", This, debugstr_w(filename), overwrite, unicode, stream);
2473 return E_NOTIMPL;
2474}
2475
2476static const IFolderVtbl foldervtbl = {
2505};
2506
2508{
2509 struct folder *This;
2510
2511 *folder = NULL;
2512
2513 TRACE("%s\n", debugstr_w(path));
2514
2515 This = heap_alloc(sizeof(struct folder));
2516 if (!This) return E_OUTOFMEMORY;
2517
2518 This->IFolder_iface.lpVtbl = &foldervtbl;
2519 This->ref = 1;
2520 This->path = SysAllocString(path);
2521 if (!This->path)
2522 {
2523 heap_free(This);
2524 return E_OUTOFMEMORY;
2525 }
2526
2527 init_classinfo(&CLSID_Folder, (IUnknown *)&This->IFolder_iface, &This->classinfo);
2528 *folder = &This->IFolder_iface;
2529
2530 return S_OK;
2531}
2532
2533static HRESULT WINAPI file_QueryInterface(IFile *iface, REFIID riid, void **obj)
2534{
2535 struct file *This = impl_from_IFile(iface);
2536
2537 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2538
2539 *obj = NULL;
2540
2541 if (IsEqualIID(riid, &IID_IFile) ||
2544 {
2545 *obj = &This->IFile_iface;
2546 }
2548 {
2549 *obj = &This->classinfo.IProvideClassInfo_iface;
2550 }
2551 else
2552 return E_NOINTERFACE;
2553
2554 IUnknown_AddRef((IUnknown*)*obj);
2555 return S_OK;
2556}
2557
2558static ULONG WINAPI file_AddRef(IFile *iface)
2559{
2560 struct file *This = impl_from_IFile(iface);
2562
2563 TRACE("(%p) ref=%d\n", This, ref);
2564
2565 return ref;
2566}
2567
2568static ULONG WINAPI file_Release(IFile *iface)
2569{
2570 struct file *This = impl_from_IFile(iface);
2572
2573 TRACE("(%p) ref=%d\n", This, ref);
2574
2575 if(!ref)
2576 {
2577 heap_free(This->path);
2578 heap_free(This);
2579 }
2580
2581 return ref;
2582}
2583
2584static HRESULT WINAPI file_GetTypeInfoCount(IFile *iface, UINT *pctinfo)
2585{
2586 struct file *This = impl_from_IFile(iface);
2587
2588 TRACE("(%p)->(%p)\n", This, pctinfo);
2589
2590 *pctinfo = 1;
2591 return S_OK;
2592}
2593
2594static HRESULT WINAPI file_GetTypeInfo(IFile *iface,
2595 UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
2596{
2597 struct file *This = impl_from_IFile(iface);
2598
2599 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
2600
2601 return get_typeinfo(IFile_tid, ppTInfo);
2602}
2603
2605 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
2606{
2607 struct file *This = impl_from_IFile(iface);
2609 HRESULT hr;
2610
2611 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid),
2612 rgszNames, cNames, lcid, rgDispId);
2613
2615 if(SUCCEEDED(hr)) {
2616 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2617 ITypeInfo_Release(typeinfo);
2618 }
2619 return hr;
2620}
2621
2622static HRESULT WINAPI file_Invoke(IFile *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2623{
2624 struct file *This = impl_from_IFile(iface);
2626 HRESULT hr;
2627
2628 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
2629 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2630
2632 if(SUCCEEDED(hr))
2633 {
2634 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
2635 pDispParams, pVarResult, pExcepInfo, puArgErr);
2636 ITypeInfo_Release(typeinfo);
2637 }
2638 return hr;
2639}
2640
2641static HRESULT WINAPI file_get_Path(IFile *iface, BSTR *path)
2642{
2643 struct file *This = impl_from_IFile(iface);
2644
2645 TRACE("(%p)->(%p)\n", This, path);
2646
2647 if (!path)
2648 return E_POINTER;
2649
2650 *path = SysAllocString(This->path);
2651 if (!*path)
2652 return E_OUTOFMEMORY;
2653
2654 return S_OK;
2655}
2656
2657static HRESULT WINAPI file_get_Name(IFile *iface, BSTR *name)
2658{
2659 struct file *This = impl_from_IFile(iface);
2660 WCHAR *ptr;
2661
2662 TRACE("(%p)->(%p)\n", This, name);
2663
2664 if(!name)
2665 return E_POINTER;
2666
2667 *name = NULL;
2668
2669 ptr = wcsrchr(This->path, '\\');
2670 if (ptr)
2671 {
2672 *name = SysAllocString(ptr+1);
2673 TRACE("%s\n", debugstr_w(*name));
2674 if (!*name) return E_OUTOFMEMORY;
2675 }
2676 else
2677 return E_FAIL;
2678
2679 return S_OK;
2680}
2681
2682static HRESULT WINAPI file_put_Name(IFile *iface, BSTR pbstrName)
2683{
2684 struct file *This = impl_from_IFile(iface);
2685 FIXME("(%p)->(%s)\n", This, debugstr_w(pbstrName));
2686 return E_NOTIMPL;
2687}
2688
2689static HRESULT WINAPI file_get_ShortPath(IFile *iface, BSTR *pbstrPath)
2690{
2691 struct file *This = impl_from_IFile(iface);
2692 FIXME("(%p)->(%p)\n", This, pbstrPath);
2693 return E_NOTIMPL;
2694}
2695
2696static HRESULT WINAPI file_get_ShortName(IFile *iface, BSTR *pbstrName)
2697{
2698 struct file *This = impl_from_IFile(iface);
2699 FIXME("(%p)->(%p)\n", This, pbstrName);
2700 return E_NOTIMPL;
2701}
2702
2703static HRESULT WINAPI file_get_Drive(IFile *iface, IDrive **ppdrive)
2704{
2705 struct file *This = impl_from_IFile(iface);
2706 FIXME("(%p)->(%p)\n", This, ppdrive);
2707 return E_NOTIMPL;
2708}
2709
2710static HRESULT WINAPI file_get_ParentFolder(IFile *iface, IFolder **ppfolder)
2711{
2712 struct file *This = impl_from_IFile(iface);
2713 FIXME("(%p)->(%p)\n", This, ppfolder);
2714 return E_NOTIMPL;
2715}
2716
2717static HRESULT WINAPI file_get_Attributes(IFile *iface, FileAttribute *pfa)
2718{
2719 struct file *This = impl_from_IFile(iface);
2720 DWORD fa;
2721
2722 TRACE("(%p)->(%p)\n", This, pfa);
2723
2724 if(!pfa)
2725 return E_POINTER;
2726
2727 fa = GetFileAttributesW(This->path);
2729 return create_error(GetLastError());
2730
2734 return S_OK;
2735}
2736
2737static HRESULT WINAPI file_put_Attributes(IFile *iface, FileAttribute pfa)
2738{
2739 struct file *This = impl_from_IFile(iface);
2740
2741 TRACE("(%p)->(%x)\n", This, pfa);
2742
2743 return SetFileAttributesW(This->path, pfa) ? S_OK : create_error(GetLastError());
2744}
2745
2747{
2748 FILETIME ftlocal;
2749 SYSTEMTIME st;
2750
2751 if (!date)
2752 return E_POINTER;
2753
2754 FileTimeToLocalFileTime(ft, &ftlocal);
2755 FileTimeToSystemTime(&ftlocal, &st);
2757
2758 return S_OK;
2759}
2760
2761static HRESULT WINAPI file_get_DateCreated(IFile *iface, DATE *pdate)
2762{
2763 struct file *This = impl_from_IFile(iface);
2764 FIXME("(%p)->(%p)\n", This, pdate);
2765 return E_NOTIMPL;
2766}
2767
2769{
2770 struct file *This = impl_from_IFile(iface);
2772
2773 TRACE("(%p)->(%p)\n", This, date);
2774
2777
2778 return E_FAIL;
2779}
2780
2781static HRESULT WINAPI file_get_DateLastAccessed(IFile *iface, DATE *pdate)
2782{
2783 struct file *This = impl_from_IFile(iface);
2784 FIXME("(%p)->(%p)\n", This, pdate);
2785 return E_NOTIMPL;
2786}
2787
2788static HRESULT WINAPI file_get_Size(IFile *iface, VARIANT *pvarSize)
2789{
2790 struct file *This = impl_from_IFile(iface);
2793 HANDLE f;
2794
2795 TRACE("(%p)->(%p)\n", This, pvarSize);
2796
2797 if(!pvarSize)
2798 return E_POINTER;
2799
2800 f = FindFirstFileW(This->path, &fd);
2801 if(f == INVALID_HANDLE_VALUE)
2802 return create_error(GetLastError());
2803 FindClose(f);
2804
2805 size.u.LowPart = fd.nFileSizeLow;
2806 size.u.HighPart = fd.nFileSizeHigh;
2807
2808 return variant_from_largeint(&size, pvarSize);
2809}
2810
2811static HRESULT WINAPI file_get_Type(IFile *iface, BSTR *pbstrType)
2812{
2813 struct file *This = impl_from_IFile(iface);
2814 FIXME("(%p)->(%p)\n", This, pbstrType);
2815 return E_NOTIMPL;
2816}
2817
2819{
2820 struct file *This = impl_from_IFile(iface);
2821 FIXME("(%p)->(%x)\n", This, Force);
2822 return E_NOTIMPL;
2823}
2824
2825static HRESULT WINAPI file_Copy(IFile *iface, BSTR Destination, VARIANT_BOOL OverWriteFiles)
2826{
2827 struct file *This = impl_from_IFile(iface);
2828 FIXME("(%p)->(%s %x)\n", This, debugstr_w(Destination), OverWriteFiles);
2829 return E_NOTIMPL;
2830}
2831
2833{
2834 struct file *This = impl_from_IFile(iface);
2835 FIXME("(%p)->(%s)\n", This, debugstr_w(Destination));
2836 return E_NOTIMPL;
2837}
2838
2839static HRESULT WINAPI file_OpenAsTextStream(IFile *iface, IOMode mode, Tristate format, ITextStream **stream)
2840{
2841 struct file *This = impl_from_IFile(iface);
2842
2843 TRACE("(%p)->(%d %d %p)\n", This, mode, format, stream);
2844
2846}
2847
2848static const IFileVtbl file_vtbl = {
2871 file_Copy,
2872 file_Move,
2874};
2875
2877{
2878 struct file *f;
2879 DWORD len, attrs;
2880
2881 *file = NULL;
2882
2883 f = heap_alloc(sizeof(struct file));
2884 if(!f)
2885 return E_OUTOFMEMORY;
2886
2887 f->IFile_iface.lpVtbl = &file_vtbl;
2888 f->ref = 1;
2889
2891 if(!len) {
2892 heap_free(f);
2893 return E_FAIL;
2894 }
2895
2896 f->path = heap_alloc(len*sizeof(WCHAR));
2897 if(!f->path) {
2898 heap_free(f);
2899 return E_OUTOFMEMORY;
2900 }
2901
2902 if(!GetFullPathNameW(path, len, f->path, NULL)) {
2903 heap_free(f->path);
2904 heap_free(f);
2905 return E_FAIL;
2906 }
2907
2908 attrs = GetFileAttributesW(f->path);
2909 if(attrs==INVALID_FILE_ATTRIBUTES ||
2911 heap_free(f->path);
2912 heap_free(f);
2913 return create_error(GetLastError());
2914 }
2915
2916 init_classinfo(&CLSID_File, (IUnknown *)&f->IFile_iface, &f->classinfo);
2917 *file = &f->IFile_iface;
2918 return S_OK;
2919}
2920
2921static HRESULT WINAPI filesys_QueryInterface(IFileSystem3 *iface, REFIID riid, void **ppvObject)
2922{
2923 struct filesystem *This = impl_from_IFileSystem3(iface);
2924
2925 TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
2926
2927 if ( IsEqualGUID( riid, &IID_IFileSystem3 ) ||
2928 IsEqualGUID( riid, &IID_IFileSystem ) ||
2931 {
2932 *ppvObject = &This->IFileSystem3_iface;
2933 }
2935 {
2936 *ppvObject = &This->classinfo.IProvideClassInfo_iface;
2937 }
2938 else if ( IsEqualGUID( riid, &IID_IDispatchEx ))
2939 {
2940 TRACE("Interface IDispatchEx not supported - returning NULL\n");
2941 *ppvObject = NULL;
2942 return E_NOINTERFACE;
2943 }
2944 else if ( IsEqualGUID( riid, &IID_IObjectWithSite ))
2945 {
2946 TRACE("Interface IObjectWithSite not supported - returning NULL\n");
2947 *ppvObject = NULL;
2948 return E_NOINTERFACE;
2949 }
2950 else
2951 {
2952 FIXME("Unsupported interface %s\n", debugstr_guid(riid));
2953 return E_NOINTERFACE;
2954 }
2955
2956 IUnknown_AddRef((IUnknown*)*ppvObject);
2957
2958 return S_OK;
2959}
2960
2961static ULONG WINAPI filesys_AddRef(IFileSystem3 *iface)
2962{
2963 TRACE("%p\n", iface);
2964
2965 return 2;
2966}
2967
2968static ULONG WINAPI filesys_Release(IFileSystem3 *iface)
2969{
2970 TRACE("%p\n", iface);
2971
2972 return 1;
2973}
2974
2975static HRESULT WINAPI filesys_GetTypeInfoCount(IFileSystem3 *iface, UINT *pctinfo)
2976{
2977 TRACE("(%p)->(%p)\n", iface, pctinfo);
2978
2979 *pctinfo = 1;
2980 return S_OK;
2981}
2982
2983static HRESULT WINAPI filesys_GetTypeInfo(IFileSystem3 *iface, UINT iTInfo,
2984 LCID lcid, ITypeInfo **ppTInfo)
2985{
2986 TRACE("(%p)->(%u %u %p)\n", iface, iTInfo, lcid, ppTInfo);
2987 return get_typeinfo(IFileSystem3_tid, ppTInfo);
2988}
2989
2990static HRESULT WINAPI filesys_GetIDsOfNames(IFileSystem3 *iface, REFIID riid,
2991 LPOLESTR *rgszNames, UINT cNames,
2992 LCID lcid, DISPID *rgDispId)
2993{
2995 HRESULT hr;
2996
2997 TRACE("(%p)->(%s %p %u %u %p)\n", iface, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
2998
3000 if(SUCCEEDED(hr))
3001 {
3002 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
3003 ITypeInfo_Release(typeinfo);
3004 }
3005
3006 return hr;
3007}
3008
3009static HRESULT WINAPI filesys_Invoke(IFileSystem3 *iface, DISPID dispIdMember,
3010 REFIID riid, LCID lcid, WORD wFlags,
3011 DISPPARAMS *pDispParams, VARIANT *pVarResult,
3012 EXCEPINFO *pExcepInfo, UINT *puArgErr)
3013{
3015 HRESULT hr;
3016
3017 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", iface, dispIdMember, debugstr_guid(riid),
3018 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
3019
3021 if(SUCCEEDED(hr))
3022 {
3023 hr = ITypeInfo_Invoke(typeinfo, iface, dispIdMember, wFlags,
3024 pDispParams, pVarResult, pExcepInfo, puArgErr);
3025 ITypeInfo_Release(typeinfo);
3026 }
3027
3028 return hr;
3029}
3030
3031static HRESULT WINAPI filesys_get_Drives(IFileSystem3 *iface, IDriveCollection **ppdrives)
3032{
3033 TRACE("%p %p\n", iface, ppdrives);
3034 return create_drivecoll(ppdrives);
3035}
3036
3037static HRESULT WINAPI filesys_BuildPath(IFileSystem3 *iface, BSTR Path,
3038 BSTR Name, BSTR *Result)
3039{
3040 BSTR ret;
3041
3042 TRACE("%p %s %s %p\n", iface, debugstr_w(Path), debugstr_w(Name), Result);
3043
3044 if (!Result) return E_POINTER;
3045
3046 if (Path && Name)
3047 {
3048 int path_len = SysStringLen(Path), name_len = SysStringLen(Name);
3049
3050 /* if both parts have backslashes strip one from Path */
3051 if (Path[path_len-1] == '\\' && Name[0] == '\\')
3052 {
3053 path_len -= 1;
3054
3055 ret = SysAllocStringLen(NULL, path_len + name_len);
3056 if (ret)
3057 {
3058 lstrcpyW(ret, Path);
3059 ret[path_len] = 0;
3060 lstrcatW(ret, Name);
3061 }
3062 }
3063 else if (Path[path_len-1] != '\\' && Name[0] != '\\')
3064 {
3065 ret = SysAllocStringLen(NULL, path_len + name_len + 1);
3066 if (ret)
3067 {
3068 lstrcpyW(ret, Path);
3069 if (Path[path_len-1] != ':')
3070 lstrcatW(ret, bsW);
3071 lstrcatW(ret, Name);
3072 }
3073 }
3074 else
3075 {
3076 ret = SysAllocStringLen(NULL, path_len + name_len);
3077 if (ret)
3078 {
3079 lstrcpyW(ret, Path);
3080 lstrcatW(ret, Name);
3081 }
3082 }
3083 }
3084 else if (Path || Name)
3086 else
3088
3089 if (!ret) return E_OUTOFMEMORY;
3090 *Result = ret;
3091
3092 return S_OK;
3093}
3094
3095static HRESULT WINAPI filesys_GetDriveName(IFileSystem3 *iface, BSTR path, BSTR *drive)
3096{
3097 TRACE("(%p)->(%s %p)\n", iface, debugstr_w(path), drive);
3098
3099 if (!drive)
3100 return E_POINTER;
3101
3102 *drive = NULL;
3103
3104 if (path && lstrlenW(path) > 1 && path[1] == ':')
3106
3107 return S_OK;
3108}
3109
3111{
3112 int i;
3113
3114 if(!path)
3115 return 0;
3116
3117 for(i=len-1; i>=0; i--)
3118 if(path[i]!='/' && path[i]!='\\')
3119 break;
3120
3121 for(; i>=0; i--)
3122 if(path[i]=='/' || path[i]=='\\')
3123 break;
3124
3125 for(; i>=0; i--)
3126 if(path[i]!='/' && path[i]!='\\')
3127 break;
3128
3129 if(i < 0)
3130 return 0;
3131
3132 if(path[i]==':' && i==1)
3133 i++;
3134 return i+1;
3135}
3136
3138 BSTR *pbstrResult)
3139{
3140 DWORD len;
3141
3142 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3143
3144 if(!pbstrResult)
3145 return E_POINTER;
3146
3148 if(!len) {
3149 *pbstrResult = NULL;
3150 return S_OK;
3151 }
3152
3153 *pbstrResult = SysAllocStringLen(Path, len);
3154 if(!*pbstrResult)
3155 return E_OUTOFMEMORY;
3156 return S_OK;
3157}
3158
3159static HRESULT WINAPI filesys_GetFileName(IFileSystem3 *iface, BSTR Path,
3160 BSTR *pbstrResult)
3161{
3162 int i, end;
3163
3164 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3165
3166 if(!pbstrResult)
3167 return E_POINTER;
3168
3169 if(!Path) {
3170 *pbstrResult = NULL;
3171 return S_OK;
3172 }
3173
3174 for(end=lstrlenW(Path)-1; end>=0; end--)
3175 if(Path[end]!='/' && Path[end]!='\\')
3176 break;
3177
3178 for(i=end; i>=0; i--)
3179 if(Path[i]=='/' || Path[i]=='\\')
3180 break;
3181 i++;
3182
3183 if(i>end || (i==0 && end==1 && Path[1]==':')) {
3184 *pbstrResult = NULL;
3185 return S_OK;
3186 }
3187
3188 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3189 if(!*pbstrResult)
3190 return E_OUTOFMEMORY;
3191 return S_OK;
3192}
3193
3194static HRESULT WINAPI filesys_GetBaseName(IFileSystem3 *iface, BSTR Path,
3195 BSTR *pbstrResult)
3196{
3197 int i, end;
3198
3199 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3200
3201 if(!pbstrResult)
3202 return E_POINTER;
3203
3204 if(!Path) {
3205 *pbstrResult = NULL;
3206 return S_OK;
3207 }
3208
3209 for(end=lstrlenW(Path)-1; end>=0; end--)
3210 if(Path[end]!='/' && Path[end]!='\\')
3211 break;
3212
3213 for(i=end; i>=0; i--) {
3214 if(Path[i]=='.' && Path[end+1]!='.')
3215 end = i-1;
3216 if(Path[i]=='/' || Path[i]=='\\')
3217 break;
3218 }
3219 i++;
3220
3221 if((i>end && Path[end+1]!='.') || (i==0 && end==1 && Path[1]==':')) {
3222 *pbstrResult = NULL;
3223 return S_OK;
3224 }
3225
3226 *pbstrResult = SysAllocStringLen(Path+i, end-i+1);
3227 if(!*pbstrResult)
3228 return E_OUTOFMEMORY;
3229 return S_OK;
3230}
3231
3233 BSTR *ext)
3234{
3235 INT len;
3236
3237 TRACE("%p %s %p\n", iface, debugstr_w(path), ext);
3238
3239 *ext = NULL;
3241 while (len) {
3242 if (path[len-1] == '.') {
3243 *ext = SysAllocString(&path[len]);
3244 if (!*ext)
3245 return E_OUTOFMEMORY;
3246 break;
3247 }
3248 len--;
3249 }
3250
3251 return S_OK;
3252}
3253
3255 BSTR *pbstrResult)
3256{
3257 static const WCHAR cur_path[] = {'.',0};
3258
3259 WCHAR buf[MAX_PATH], ch;
3260 const WCHAR *path;
3261 DWORD i, beg, len, exp_len;
3262 WIN32_FIND_DATAW fdata;
3263 HANDLE fh;
3264
3265 TRACE("%p %s %p\n", iface, debugstr_w(Path), pbstrResult);
3266
3267 if(!pbstrResult)
3268 return E_POINTER;
3269
3270 if(!Path)
3271 path = cur_path;
3272 else
3273 path = Path;
3274
3276 if(!len)
3277 return E_FAIL;
3278
3279 buf[0] = towupper(buf[0]);
3280 if(len>3 && buf[len-1] == '\\')
3281 buf[--len] = 0;
3282
3283 for(beg=3, i=3; i<=len; i++) {
3284 if(buf[i]!='\\' && buf[i])
3285 continue;
3286
3287 ch = buf[i];
3288 buf[i] = 0;
3289 fh = FindFirstFileW(buf, &fdata);
3290 if(fh == INVALID_HANDLE_VALUE)
3291 break;
3292
3293 exp_len = lstrlenW(fdata.cFileName);
3294 if(exp_len == i-beg)
3295 memcpy(buf+beg, fdata.cFileName, exp_len*sizeof(WCHAR));
3296 FindClose(fh);
3297 buf[i] = ch;
3298 beg = i+1;
3299 }
3300
3301 *pbstrResult = SysAllocString(buf);
3302 if(!*pbstrResult)
3303 return E_OUTOFMEMORY;
3304 return S_OK;
3305}
3306
3307static HRESULT WINAPI filesys_GetTempName(IFileSystem3 *iface, BSTR *pbstrResult)
3308{
3309 static const WCHAR fmt[] = {'r','a','d','%','0','5','X','.','t','x','t',0};
3310
3311 DWORD random;
3312
3313 TRACE("%p %p\n", iface, pbstrResult);
3314
3315 if(!pbstrResult)
3316 return E_POINTER;
3317
3318 *pbstrResult = SysAllocStringLen(NULL, 12);
3319 if(!*pbstrResult)
3320 return E_OUTOFMEMORY;
3321
3322 if(!RtlGenRandom(&random, sizeof(random)))
3323 return E_FAIL;
3324 swprintf(*pbstrResult, fmt, random & 0xfffff);
3325 return S_OK;
3326}
3327
3328static HRESULT WINAPI filesys_DriveExists(IFileSystem3 *iface, BSTR DriveSpec,
3329 VARIANT_BOOL *pfExists)
3330{
3331 UINT len;
3332 WCHAR driveletter;
3333 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), pfExists);
3334
3335 if (!pfExists) return E_POINTER;
3336
3337 *pfExists = VARIANT_FALSE;
3338 len = SysStringLen(DriveSpec);
3339
3340 if (len >= 1) {
3341 driveletter = towupper(DriveSpec[0]);
3342 if (driveletter >= 'A' && driveletter <= 'Z'
3343 && (len < 2 || DriveSpec[1] == ':')
3344 && (len < 3 || DriveSpec[2] == '\\')) {
3345 const WCHAR root[] = {driveletter, ':', '\\', 0};
3346 UINT drivetype = GetDriveTypeW(root);
3347 *pfExists = drivetype != DRIVE_NO_ROOT_DIR && drivetype != DRIVE_UNKNOWN ? VARIANT_TRUE : VARIANT_FALSE;
3348 }
3349 }
3350
3351 return S_OK;
3352}
3353
3355{
3356 DWORD attrs;
3357 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3358
3359 if (!ret) return E_POINTER;
3360
3361 attrs = GetFileAttributesW(path);
3362 *ret = attrs != INVALID_FILE_ATTRIBUTES && !(attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3363 return S_OK;
3364}
3365
3367{
3368 DWORD attrs;
3369 TRACE("%p %s %p\n", iface, debugstr_w(path), ret);
3370
3371 if (!ret) return E_POINTER;
3372
3373 attrs = GetFileAttributesW(path);
3374 *ret = attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) ? VARIANT_TRUE : VARIANT_FALSE;
3375
3376 return S_OK;
3377}
3378
3379static HRESULT WINAPI filesys_GetDrive(IFileSystem3 *iface, BSTR DriveSpec,
3380 IDrive **ppdrive)
3381{
3382 UINT len;
3383 HRESULT hr;
3384 WCHAR driveletter;
3385 VARIANT_BOOL drive_exists;
3386
3387 TRACE("%p %s %p\n", iface, debugstr_w(DriveSpec), ppdrive);
3388
3389 if (!ppdrive)
3390 return E_POINTER;
3391
3392 *ppdrive = NULL;
3393
3394 /* DriveSpec may be one of: 'x', 'x:', 'x:\', '\\computer\share' */
3395 len = SysStringLen(DriveSpec);
3396 if (!len)
3397 return E_INVALIDARG;
3398 else if (len <= 3) {
3399 driveletter = towupper(DriveSpec[0]);
3400 if (driveletter < 'A' || driveletter > 'Z'
3401 || (len >= 2 && DriveSpec[1] != ':')
3402 || (len == 3 && DriveSpec[2] != '\\'))
3403 return E_INVALIDARG;
3404 hr = IFileSystem3_DriveExists(iface, DriveSpec, &drive_exists);
3405 if (FAILED(hr))
3406 return hr;
3407 if (drive_exists == VARIANT_FALSE)
3409 return create_drive(driveletter, ppdrive);
3410 } else {
3411 if (DriveSpec[0] != '\\' || DriveSpec[1] != '\\')
3412 return E_INVALIDARG;
3413 FIXME("%s not implemented yet\n", debugstr_w(DriveSpec));
3414 return E_NOTIMPL;
3415 }
3416}
3417
3418static HRESULT WINAPI filesys_GetFile(IFileSystem3 *iface, BSTR FilePath,
3419 IFile **ppfile)
3420{
3421 TRACE("%p %s %p\n", iface, debugstr_w(FilePath), ppfile);
3422
3423 if(!ppfile)
3424 return E_POINTER;
3425 if(!FilePath)
3426 return E_INVALIDARG;
3427
3428 return create_file(FilePath, ppfile);
3429}
3430
3431static HRESULT WINAPI filesys_GetFolder(IFileSystem3 *iface, BSTR FolderPath,
3432 IFolder **folder)
3433{
3434 DWORD attrs;
3435
3436 TRACE("%p %s %p\n", iface, debugstr_w(FolderPath), folder);
3437
3438 if(!folder)
3439 return E_POINTER;
3440
3441 *folder = NULL;
3442 if(!FolderPath)
3443 return E_INVALIDARG;
3444
3445 attrs = GetFileAttributesW(FolderPath);
3446 if((attrs == INVALID_FILE_ATTRIBUTES) || !(attrs & FILE_ATTRIBUTE_DIRECTORY))
3447 return CTL_E_PATHNOTFOUND;
3448
3449 return create_folder(FolderPath, folder);
3450}
3451
3452static HRESULT WINAPI filesys_GetSpecialFolder(IFileSystem3 *iface,
3453 SpecialFolderConst SpecialFolder,
3454 IFolder **folder)
3455{
3456 WCHAR pathW[MAX_PATH];
3457 DWORD ret;
3458
3459 TRACE("%p %d %p\n", iface, SpecialFolder, folder);
3460
3461 if (!folder)
3462 return E_POINTER;
3463
3464 *folder = NULL;
3465
3466 switch (SpecialFolder)
3467 {
3468 case WindowsFolder:
3469 ret = GetWindowsDirectoryW(pathW, ARRAY_SIZE(pathW));
3470 break;
3471 case SystemFolder:
3472 ret = GetSystemDirectoryW(pathW, ARRAY_SIZE(pathW));
3473 break;
3474 case TemporaryFolder:
3475 ret = GetTempPathW(ARRAY_SIZE(pathW), pathW);
3476 /* we don't want trailing backslash */
3477 if (ret && pathW[ret-1] == '\\')
3478 pathW[ret-1] = 0;
3479 break;
3480 default:
3481 FIXME("unknown special folder type, %d\n", SpecialFolder);
3482 return E_INVALIDARG;
3483 }
3484
3485 if (!ret)
3487
3488 return create_folder(pathW, folder);
3489}
3490
3491static inline HRESULT delete_file(const WCHAR *file, DWORD file_len, VARIANT_BOOL force)
3492{
3494 DWORD len, name_len;
3495 WIN32_FIND_DATAW ffd;
3496 HANDLE f;
3497
3498 f = FindFirstFileW(file, &ffd);
3499 if(f == INVALID_HANDLE_VALUE)
3500 return create_error(GetLastError());
3501
3502 len = get_parent_folder_name(file, file_len);
3503 if(len+1 >= MAX_PATH) {
3504 FindClose(f);
3505 return E_FAIL;
3506 }
3507 if(len) {
3508 memcpy(path, file, len*sizeof(WCHAR));
3509 path[len++] = '\\';
3510 }
3511
3512 do {
3513 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3514 continue;
3515
3516 name_len = lstrlenW(ffd.cFileName);
3517 if(len+name_len+1 >= MAX_PATH) {
3518 FindClose(f);
3519 return E_FAIL;
3520 }
3521 memcpy(path+len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3522
3523 TRACE("deleting %s\n", debugstr_w(path));
3524
3525 if(!DeleteFileW(path)) {
3527 || !DeleteFileW(path)) {
3528 FindClose(f);
3529 return create_error(GetLastError());
3530 }
3531 }
3532 } while(FindNextFileW(f, &ffd));
3533 FindClose(f);
3534
3535 return S_OK;
3536}
3537
3538static HRESULT WINAPI filesys_DeleteFile(IFileSystem3 *iface, BSTR FileSpec,
3540{
3541 TRACE("%p %s %d\n", iface, debugstr_w(FileSpec), Force);
3542
3543 if(!FileSpec)
3544 return E_POINTER;
3545
3546 return delete_file(FileSpec, SysStringLen(FileSpec), Force);
3547}
3548
3549static HRESULT delete_folder(const WCHAR *folder, DWORD folder_len, VARIANT_BOOL force)
3550{
3552 DWORD len, name_len;
3553 WIN32_FIND_DATAW ffd;
3554 HANDLE f;
3555 HRESULT hr;
3556
3557 f = FindFirstFileW(folder, &ffd);
3558 if(f == INVALID_HANDLE_VALUE)
3559 return create_error(GetLastError());
3560
3561 len = get_parent_folder_name(folder, folder_len);
3562 if(len+1 >= MAX_PATH) {
3563 FindClose(f);
3564 return E_FAIL;
3565 }
3566 if(len) {
3567 memcpy(path, folder, len*sizeof(WCHAR));
3568 path[len++] = '\\';
3569 }
3570
3571 do {
3572 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3573 continue;
3574 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3575 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3576 continue;
3577
3578 name_len = lstrlenW(ffd.cFileName);
3579 if(len+name_len+3 >= MAX_PATH) {
3580 FindClose(f);
3581 return E_FAIL;
3582 }
3583 memcpy(path+len, ffd.cFileName, name_len*sizeof(WCHAR));
3584 path[len+name_len] = '\\';
3585 path[len+name_len+1] = '*';
3586 path[len+name_len+2] = 0;
3587
3588 hr = delete_file(path, len+name_len+2, force);
3589 if(FAILED(hr)) {
3590 FindClose(f);
3591 return hr;
3592 }
3593
3594 hr = delete_folder(path, len+name_len+2, force);
3595 if(FAILED(hr)) {
3596 FindClose(f);
3597 return hr;
3598 }
3599
3600 path[len+name_len] = 0;
3601 TRACE("deleting %s\n", debugstr_w(path));
3602
3603 if(!RemoveDirectoryW(path)) {
3604 FindClose(f);
3605 return create_error(GetLastError());
3606 }
3607 } while(FindNextFileW(f, &ffd));
3608 FindClose(f);
3609
3610 return S_OK;
3611}
3612
3613static HRESULT WINAPI filesys_DeleteFolder(IFileSystem3 *iface, BSTR FolderSpec,
3615{
3616 TRACE("%p %s %d\n", iface, debugstr_w(FolderSpec), Force);
3617
3618 if(!FolderSpec)
3619 return E_POINTER;
3620
3621 return delete_folder(FolderSpec, SysStringLen(FolderSpec), Force);
3622}
3623
3624static HRESULT WINAPI filesys_MoveFile(IFileSystem3 *iface, BSTR Source,
3626{
3627 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3628
3629 return E_NOTIMPL;
3630}
3631
3632static HRESULT WINAPI filesys_MoveFolder(IFileSystem3 *iface,BSTR Source,
3634{
3635 FIXME("%p %s %s\n", iface, debugstr_w(Source), debugstr_w(Destination));
3636
3637 return E_NOTIMPL;
3638}
3639
3640static inline HRESULT copy_file(const WCHAR *source, DWORD source_len,
3641 const WCHAR *destination, DWORD destination_len, VARIANT_BOOL overwrite)
3642{
3643 DWORD attrs;
3644 WCHAR src_path[MAX_PATH], dst_path[MAX_PATH];
3645 DWORD src_len, dst_len, name_len;
3646 WIN32_FIND_DATAW ffd;
3647 HANDLE f;
3648 HRESULT hr;
3649
3650 if(!source[0] || !destination[0])
3651 return E_INVALIDARG;
3652
3653 attrs = GetFileAttributesW(destination);
3654 if(attrs==INVALID_FILE_ATTRIBUTES || !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
3655 attrs = GetFileAttributesW(source);
3656 if(attrs == INVALID_FILE_ATTRIBUTES)
3657 return create_error(GetLastError());
3658 else if(attrs & FILE_ATTRIBUTE_DIRECTORY)
3659 return CTL_E_FILENOTFOUND;
3660
3661 if(!CopyFileW(source, destination, !overwrite))
3662 return create_error(GetLastError());
3663 return S_OK;
3664 }
3665
3666 f = FindFirstFileW(source, &ffd);
3667 if(f == INVALID_HANDLE_VALUE)
3668 return CTL_E_FILENOTFOUND;
3669
3670 src_len = get_parent_folder_name(source, source_len);
3671 if(src_len+1 >= MAX_PATH) {
3672 FindClose(f);
3673 return E_FAIL;
3674 }
3675 if(src_len) {
3676 memcpy(src_path, source, src_len*sizeof(WCHAR));
3677 src_path[src_len++] = '\\';
3678 }
3679
3680 dst_len = destination_len;
3681 if(dst_len+1 >= MAX_PATH) {
3682 FindClose(f);
3683 return E_FAIL;
3684 }
3685 memcpy(dst_path, destination, dst_len*sizeof(WCHAR));
3686 if(dst_path[dst_len-1]!= '\\' && dst_path[dst_len-1]!='/')
3687 dst_path[dst_len++] = '\\';
3688
3690 do {
3691 if(ffd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
3692 continue;
3693
3694 name_len = lstrlenW(ffd.cFileName);
3695 if(src_len+name_len+1>=MAX_PATH || dst_len+name_len+1>=MAX_PATH) {
3696 FindClose(f);
3697 return E_FAIL;
3698 }
3699 memcpy(src_path+src_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3700 memcpy(dst_path+dst_len, ffd.cFileName, (name_len+1)*sizeof(WCHAR));
3701
3702 TRACE("copying %s to %s\n", debugstr_w(src_path), debugstr_w(dst_path));
3703
3704 if(!CopyFileW(src_path, dst_path, !overwrite)) {
3705 FindClose(f);
3706 return create_error(GetLastError());
3707 }else {
3708 hr = S_OK;
3709 }
3710 } while(FindNextFileW(f, &ffd));
3711 FindClose(f);
3712
3713 return hr;
3714}
3715
3716static HRESULT WINAPI filesys_CopyFile(IFileSystem3 *iface, BSTR Source,
3717 BSTR Destination, VARIANT_BOOL OverWriteFiles)
3718{
3719 TRACE("%p %s %s %d\n", iface, debugstr_w(Source), debugstr_w(Destination), OverWriteFiles);
3720
3721 if(!Source || !Destination)
3722 return E_POINTER;
3723
3725 SysStringLen(Destination), OverWriteFiles);
3726}
3727
3728static HRESULT copy_folder(const WCHAR *source, DWORD source_len, const WCHAR *destination,
3729 DWORD destination_len, VARIANT_BOOL overwrite)
3730{
3731 DWORD tmp, src_len, dst_len, name_len;
3733 WIN32_FIND_DATAW ffd;
3734 HANDLE f;
3735 HRESULT hr;
3736 BOOL copied = FALSE;
3737
3738 if(!source[0] || !destination[0])
3739 return E_INVALIDARG;
3740
3741 dst_len = destination_len;
3742 if(dst_len+1 >= MAX_PATH)
3743 return E_FAIL;
3744 memcpy(dst, destination, (dst_len+1)*sizeof(WCHAR));
3745
3746 if(dst[dst_len-1]!='\\' && dst[dst_len-1]!='/' &&
3749 if(!CreateDirectoryW(dst, NULL)) {
3750 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3751 tmp = GetFileAttributesW(dst);
3754 }else {
3755 return create_error(GetLastError());
3756 }
3757 }
3758 copied = TRUE;
3759
3760 src_len = source_len;
3761 if(src_len+2 >= MAX_PATH)
3762 return E_FAIL;
3763 memcpy(src, source, src_len*sizeof(WCHAR));
3764 src[src_len++] = '\\';
3765 src[src_len] = '*';
3766 src[src_len+1] = 0;
3767
3768 hr = copy_file(src, src_len+1, dst, dst_len, overwrite);
3770 return create_error(GetLastError());
3771
3772 f = FindFirstFileW(src, &ffd);
3773 }else {
3774 src_len = get_parent_folder_name(source, source_len);
3775 if(src_len+2 >= MAX_PATH)
3776 return E_FAIL;
3777 memcpy(src, source, src_len*sizeof(WCHAR));
3778 if(src_len)
3779 src[src_len++] = '\\';
3780
3781 f = FindFirstFileW(source, &ffd);
3782 }
3783 if(f == INVALID_HANDLE_VALUE)
3784 return CTL_E_PATHNOTFOUND;
3785
3786 dst[dst_len++] = '\\';
3787 dst[dst_len] = 0;
3788
3789 do {
3790 if(!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
3791 continue;
3792 if(ffd.cFileName[0]=='.' && (ffd.cFileName[1]==0 ||
3793 (ffd.cFileName[1]=='.' && ffd.cFileName[2]==0)))
3794 continue;
3795
3796 name_len = lstrlenW(ffd.cFileName);
3797 if(dst_len+name_len>=MAX_PATH || src_len+name_len+2>=MAX_PATH) {
3798 FindClose(f);
3799 return E_FAIL;
3800 }
3801 memcpy(dst+dst_len, ffd.cFileName, name_len*sizeof(WCHAR));
3802 dst[dst_len+name_len] = 0;
3803 memcpy(src+src_len, ffd.cFileName, name_len*sizeof(WCHAR));
3804 src[src_len+name_len] = '\\';
3805 src[src_len+name_len+1] = '*';
3806 src[src_len+name_len+2] = 0;
3807
3808 TRACE("copying %s to %s\n", debugstr_w(src), debugstr_w(dst));
3809
3810 if(!CreateDirectoryW(dst, NULL)) {
3811 if(overwrite && GetLastError()==ERROR_ALREADY_EXISTS) {
3812 tmp = GetFileAttributesW(dst);
3814