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