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