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