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