1 /* 2 * Copyright 2005-2007 Jacek Caban for CodeWeavers 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 NONAMELESSUNION 20 21 #include "urlmon_main.h" 22 #include "winreg.h" 23 #include "shlwapi.h" 24 25 #include "wine/debug.h" 26 27 WINE_DEFAULT_DEBUG_CHANNEL(urlmon); 28 29 static WCHAR cbinding_contextW[] = {'C','B','i','n','d','i','n','g',' ','C','o','n','t','e','x','t',0}; 30 static WCHAR bscb_holderW[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 }; 31 32 typedef struct { 33 IUnknown IUnknown_iface; 34 35 LONG ref; 36 37 IInternetProtocolEx *protocol; 38 39 HANDLE file; 40 HRESULT hres; 41 42 LPWSTR cache_file; 43 } stgmed_buf_t; 44 45 typedef struct _stgmed_obj_t stgmed_obj_t; 46 47 typedef struct { 48 void (*release)(stgmed_obj_t*); 49 HRESULT (*fill_stgmed)(stgmed_obj_t*,STGMEDIUM*); 50 HRESULT (*get_result)(stgmed_obj_t*,DWORD,void**); 51 } stgmed_obj_vtbl; 52 53 struct _stgmed_obj_t { 54 const stgmed_obj_vtbl *vtbl; 55 }; 56 57 typedef enum { 58 BEFORE_DOWNLOAD, 59 DOWNLOADING, 60 END_DOWNLOAD 61 } download_state_t; 62 63 #define BINDING_LOCKED 0x0001 64 #define BINDING_STOPPED 0x0002 65 #define BINDING_OBJAVAIL 0x0004 66 #define BINDING_ABORTED 0x0008 67 68 typedef struct { 69 IBinding IBinding_iface; 70 IInternetProtocolSink IInternetProtocolSink_iface; 71 IInternetBindInfo IInternetBindInfo_iface; 72 IWinInetHttpInfo IWinInetHttpInfo_iface; 73 IServiceProvider IServiceProvider_iface; 74 75 LONG ref; 76 77 IBindStatusCallback *callback; 78 IServiceProvider *service_provider; 79 80 BindProtocol *protocol; 81 82 stgmed_buf_t *stgmed_buf; 83 stgmed_obj_t *stgmed_obj; 84 85 BINDINFO bindinfo; 86 DWORD bindf; 87 BOOL to_object; 88 LPWSTR mime; 89 UINT clipboard_format; 90 LPWSTR url; 91 LPWSTR redirect_url; 92 IID iid; 93 BOOL report_mime; 94 BOOL use_cache_file; 95 DWORD state; 96 HRESULT hres; 97 CLSID clsid; 98 download_state_t download_state; 99 IUnknown *obj; 100 IMoniker *mon; 101 IBindCtx *bctx; 102 HWND notif_hwnd; 103 104 CRITICAL_SECTION section; 105 } Binding; 106 107 static void read_protocol_data(stgmed_buf_t *stgmed_buf) 108 { 109 BYTE buf[8192]; 110 DWORD read; 111 HRESULT hres; 112 113 do hres = IInternetProtocolEx_Read(stgmed_buf->protocol, buf, sizeof(buf), &read); 114 while(hres == S_OK); 115 } 116 117 static void dump_BINDINFO(BINDINFO *bi) 118 { 119 static const char * const BINDINFOF_str[] = { 120 "#0", 121 "BINDINFOF_URLENCODESTGMEDDATA", 122 "BINDINFOF_URLENCODEDEXTRAINFO" 123 }; 124 125 static const char * const BINDVERB_str[] = { 126 "BINDVERB_GET", 127 "BINDVERB_POST", 128 "BINDVERB_PUT", 129 "BINDVERB_CUSTOM" 130 }; 131 132 TRACE("\n" 133 "BINDINFO = {\n" 134 " %d, %s,\n" 135 " {%d, %p, %p},\n" 136 " %s,\n" 137 " %s,\n" 138 " %s,\n" 139 " %d, %08x, %d, %d\n" 140 " {%d %p %x},\n" 141 " %s\n" 142 " %p, %d\n" 143 "}\n", 144 145 bi->cbSize, debugstr_w(bi->szExtraInfo), 146 bi->stgmedData.tymed, bi->stgmedData.u.hGlobal, bi->stgmedData.pUnkForRelease, 147 bi->grfBindInfoF > BINDINFOF_URLENCODEDEXTRAINFO 148 ? "unknown" : BINDINFOF_str[bi->grfBindInfoF], 149 bi->dwBindVerb > BINDVERB_CUSTOM 150 ? "unknown" : BINDVERB_str[bi->dwBindVerb], 151 debugstr_w(bi->szCustomVerb), 152 bi->cbstgmedData, bi->dwOptions, bi->dwOptionsFlags, bi->dwCodePage, 153 bi->securityAttributes.nLength, 154 bi->securityAttributes.lpSecurityDescriptor, 155 bi->securityAttributes.bInheritHandle, 156 debugstr_guid(&bi->iid), 157 bi->pUnk, bi->dwReserved 158 ); 159 } 160 161 static void mime_available(Binding *This, LPCWSTR mime) 162 { 163 heap_free(This->mime); 164 This->mime = heap_strdupW(mime); 165 166 if(!This->mime || !This->report_mime) 167 return; 168 169 IBindStatusCallback_OnProgress(This->callback, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE, This->mime); 170 171 This->clipboard_format = RegisterClipboardFormatW(This->mime); 172 } 173 174 static void stop_binding(Binding *binding, HRESULT hres, LPCWSTR str) 175 { 176 if(binding->state & BINDING_LOCKED) { 177 IInternetProtocolEx_UnlockRequest(&binding->protocol->IInternetProtocolEx_iface); 178 binding->state &= ~BINDING_LOCKED; 179 } 180 181 if(!(binding->state & BINDING_STOPPED)) { 182 binding->state |= BINDING_STOPPED; 183 184 binding->hres = hres; 185 IBindStatusCallback_OnStopBinding(binding->callback, hres, str); 186 } 187 } 188 189 static LPWSTR get_mime_clsid(LPCWSTR mime, CLSID *clsid) 190 { 191 LPWSTR key_name, ret; 192 DWORD res, type, size; 193 HKEY hkey; 194 int len; 195 HRESULT hres; 196 197 static const WCHAR mime_keyW[] = 198 {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\', 199 'C','o','n','t','e','n','t',' ','T','y','p','e','\\'}; 200 static const WCHAR clsidW[] = {'C','L','S','I','D',0}; 201 202 len = strlenW(mime)+1; 203 key_name = heap_alloc(sizeof(mime_keyW) + len*sizeof(WCHAR)); 204 memcpy(key_name, mime_keyW, sizeof(mime_keyW)); 205 strcpyW(key_name + sizeof(mime_keyW)/sizeof(WCHAR), mime); 206 207 res = RegOpenKeyW(HKEY_CLASSES_ROOT, key_name, &hkey); 208 heap_free(key_name); 209 if(res != ERROR_SUCCESS) { 210 WARN("Could not open MIME key: %x\n", res); 211 return NULL; 212 } 213 214 size = 50*sizeof(WCHAR); 215 ret = heap_alloc(size); 216 res = RegQueryValueExW(hkey, clsidW, NULL, &type, (LPBYTE)ret, &size); 217 RegCloseKey(hkey); 218 if(res != ERROR_SUCCESS) { 219 WARN("Could not get CLSID: %08x\n", res); 220 heap_free(ret); 221 return NULL; 222 } 223 224 hres = CLSIDFromString(ret, clsid); 225 if(FAILED(hres)) { 226 WARN("Could not parse CLSID: %08x\n", hres); 227 heap_free(ret); 228 return NULL; 229 } 230 231 return ret; 232 } 233 234 static void load_doc_mon(Binding *binding, IPersistMoniker *persist) 235 { 236 IBindCtx *bctx; 237 HRESULT hres; 238 239 hres = CreateAsyncBindCtxEx(binding->bctx, 0, NULL, NULL, &bctx, 0); 240 if(FAILED(hres)) { 241 WARN("CreateAsyncBindCtxEx failed: %08x\n", hres); 242 return; 243 } 244 245 IBindCtx_RevokeObjectParam(bctx, bscb_holderW); 246 IBindCtx_RegisterObjectParam(bctx, cbinding_contextW, (IUnknown*)&binding->IBinding_iface); 247 248 hres = IPersistMoniker_Load(persist, binding->download_state == END_DOWNLOAD, binding->mon, bctx, 0x12); 249 IBindCtx_RevokeObjectParam(bctx, cbinding_contextW); 250 IBindCtx_Release(bctx); 251 if(FAILED(hres)) 252 FIXME("Load failed: %08x\n", hres); 253 } 254 255 static HRESULT create_mime_object(Binding *binding, const CLSID *clsid, LPCWSTR clsid_str) 256 { 257 IPersistMoniker *persist; 258 HRESULT hres; 259 260 hres = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, 261 &binding->iid, (void**)&binding->obj); 262 if(FAILED(hres)) { 263 WARN("CoCreateInstance failed: %08x\n", hres); 264 return INET_E_CANNOT_INSTANTIATE_OBJECT; 265 } 266 267 binding->state |= BINDING_OBJAVAIL; 268 269 hres = IUnknown_QueryInterface(binding->obj, &IID_IPersistMoniker, (void**)&persist); 270 if(SUCCEEDED(hres)) { 271 IMonikerProp *prop; 272 273 hres = IPersistMoniker_QueryInterface(persist, &IID_IMonikerProp, (void**)&prop); 274 if(SUCCEEDED(hres)) { 275 IMonikerProp_PutProperty(prop, MIMETYPEPROP, binding->mime); 276 IMonikerProp_PutProperty(prop, CLASSIDPROP, clsid_str); 277 IMonikerProp_Release(prop); 278 } 279 280 load_doc_mon(binding, persist); 281 282 IPersistMoniker_Release(persist); 283 }else { 284 FIXME("Could not get IPersistMoniker: %08x\n", hres); 285 /* FIXME: Try query IPersistFile */ 286 } 287 288 IBindStatusCallback_OnObjectAvailable(binding->callback, &binding->iid, binding->obj); 289 290 return S_OK; 291 } 292 293 static void create_object(Binding *binding) 294 { 295 LPWSTR clsid_str; 296 CLSID clsid; 297 HRESULT hres; 298 299 if(!binding->mime) { 300 FIXME("MIME not available\n"); 301 return; 302 } 303 304 if((clsid_str = get_mime_clsid(binding->mime, &clsid))) 305 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_CLASSIDAVAILABLE, clsid_str); 306 307 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_BEGINSYNCOPERATION, NULL); 308 309 if(clsid_str) { 310 hres = create_mime_object(binding, &clsid, clsid_str); 311 heap_free(clsid_str); 312 }else { 313 FIXME("Could not find object for MIME %s\n", debugstr_w(binding->mime)); 314 hres = REGDB_E_CLASSNOTREG; 315 } 316 317 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_ENDSYNCOPERATION, NULL); 318 binding->clsid = CLSID_NULL; 319 320 stop_binding(binding, hres, NULL); 321 if(FAILED(hres)) 322 IInternetProtocolEx_Terminate(&binding->protocol->IInternetProtocolEx_iface, 0); 323 } 324 325 static void cache_file_available(Binding *This, const WCHAR *file_name) 326 { 327 heap_free(This->stgmed_buf->cache_file); 328 This->stgmed_buf->cache_file = heap_strdupW(file_name); 329 330 if(This->use_cache_file) { 331 This->stgmed_buf->file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, 332 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 333 if(This->stgmed_buf->file == INVALID_HANDLE_VALUE) 334 WARN("CreateFile failed: %u\n", GetLastError()); 335 } 336 } 337 338 static inline stgmed_buf_t *impl_from_IUnknown(IUnknown *iface) 339 { 340 return CONTAINING_RECORD(iface, stgmed_buf_t, IUnknown_iface); 341 } 342 343 static HRESULT WINAPI StgMedUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) 344 { 345 stgmed_buf_t *This = impl_from_IUnknown(iface); 346 347 *ppv = NULL; 348 349 if(IsEqualGUID(riid, &IID_IUnknown)) { 350 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 351 352 *ppv = &This->IUnknown_iface; 353 IUnknown_AddRef(&This->IUnknown_iface); 354 return S_OK; 355 } 356 357 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 358 return E_NOINTERFACE; 359 } 360 361 static ULONG WINAPI StgMedUnk_AddRef(IUnknown *iface) 362 { 363 stgmed_buf_t *This = impl_from_IUnknown(iface); 364 LONG ref = InterlockedIncrement(&This->ref); 365 366 TRACE("(%p) ref=%d\n", This, ref); 367 368 return ref; 369 } 370 371 static ULONG WINAPI StgMedUnk_Release(IUnknown *iface) 372 { 373 stgmed_buf_t *This = impl_from_IUnknown(iface); 374 LONG ref = InterlockedDecrement(&This->ref); 375 376 TRACE("(%p) ref=%d\n", This, ref); 377 378 if(!ref) { 379 if(This->file != INVALID_HANDLE_VALUE) 380 CloseHandle(This->file); 381 IInternetProtocolEx_Release(This->protocol); 382 heap_free(This->cache_file); 383 heap_free(This); 384 385 URLMON_UnlockModule(); 386 } 387 388 return ref; 389 } 390 391 static const IUnknownVtbl StgMedUnkVtbl = { 392 StgMedUnk_QueryInterface, 393 StgMedUnk_AddRef, 394 StgMedUnk_Release 395 }; 396 397 static stgmed_buf_t *create_stgmed_buf(IInternetProtocolEx *protocol) 398 { 399 stgmed_buf_t *ret = heap_alloc(sizeof(*ret)); 400 401 ret->IUnknown_iface.lpVtbl = &StgMedUnkVtbl; 402 ret->ref = 1; 403 ret->file = INVALID_HANDLE_VALUE; 404 ret->hres = S_OK; 405 ret->cache_file = NULL; 406 407 IInternetProtocolEx_AddRef(protocol); 408 ret->protocol = protocol; 409 410 URLMON_LockModule(); 411 412 return ret; 413 } 414 415 typedef struct { 416 stgmed_obj_t stgmed_obj; 417 IStream IStream_iface; 418 419 LONG ref; 420 421 stgmed_buf_t *buf; 422 } ProtocolStream; 423 424 static inline ProtocolStream *impl_from_IStream(IStream *iface) 425 { 426 return CONTAINING_RECORD(iface, ProtocolStream, IStream_iface); 427 } 428 429 static HRESULT WINAPI ProtocolStream_QueryInterface(IStream *iface, 430 REFIID riid, void **ppv) 431 { 432 ProtocolStream *This = impl_from_IStream(iface); 433 434 *ppv = NULL; 435 436 if(IsEqualGUID(&IID_IUnknown, riid)) { 437 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 438 *ppv = &This->IStream_iface; 439 }else if(IsEqualGUID(&IID_ISequentialStream, riid)) { 440 TRACE("(%p)->(IID_ISequentialStream %p)\n", This, ppv); 441 *ppv = &This->IStream_iface; 442 }else if(IsEqualGUID(&IID_IStream, riid)) { 443 TRACE("(%p)->(IID_IStream %p)\n", This, ppv); 444 *ppv = &This->IStream_iface; 445 } 446 447 if(*ppv) { 448 IStream_AddRef(&This->IStream_iface); 449 return S_OK; 450 } 451 452 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); 453 return E_NOINTERFACE; 454 } 455 456 static ULONG WINAPI ProtocolStream_AddRef(IStream *iface) 457 { 458 ProtocolStream *This = impl_from_IStream(iface); 459 LONG ref = InterlockedIncrement(&This->ref); 460 461 TRACE("(%p) ref=%d\n", This, ref); 462 463 return ref; 464 } 465 466 static ULONG WINAPI ProtocolStream_Release(IStream *iface) 467 { 468 ProtocolStream *This = impl_from_IStream(iface); 469 LONG ref = InterlockedDecrement(&This->ref); 470 471 TRACE("(%p) ref=%d\n", This, ref); 472 473 if(!ref) { 474 IUnknown_Release(&This->buf->IUnknown_iface); 475 heap_free(This); 476 477 URLMON_UnlockModule(); 478 } 479 480 return ref; 481 } 482 483 static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv, 484 ULONG cb, ULONG *pcbRead) 485 { 486 ProtocolStream *This = impl_from_IStream(iface); 487 DWORD read = 0; 488 HRESULT hres; 489 490 TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbRead); 491 492 if(This->buf->file == INVALID_HANDLE_VALUE) { 493 hres = This->buf->hres = IInternetProtocolEx_Read(This->buf->protocol, (PBYTE)pv, cb, &read); 494 }else { 495 hres = ReadFile(This->buf->file, pv, cb, &read, NULL) ? S_OK : INET_E_DOWNLOAD_FAILURE; 496 } 497 498 if (pcbRead) 499 *pcbRead = read; 500 501 if(hres == E_PENDING) 502 return E_PENDING; 503 else if(FAILED(hres)) 504 FIXME("Read failed: %08x\n", hres); 505 506 return read ? S_OK : S_FALSE; 507 } 508 509 static HRESULT WINAPI ProtocolStream_Write(IStream *iface, const void *pv, 510 ULONG cb, ULONG *pcbWritten) 511 { 512 ProtocolStream *This = impl_from_IStream(iface); 513 514 TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbWritten); 515 516 return STG_E_ACCESSDENIED; 517 } 518 519 static HRESULT WINAPI ProtocolStream_Seek(IStream *iface, LARGE_INTEGER dlibMove, 520 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 521 { 522 ProtocolStream *This = impl_from_IStream(iface); 523 LARGE_INTEGER new_pos; 524 DWORD method; 525 526 TRACE("(%p)->(%d %08x %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); 527 528 if(This->buf->file == INVALID_HANDLE_VALUE) { 529 /* We should probably call protocol handler's Seek. */ 530 FIXME("no cache file, not supported\n"); 531 return E_FAIL; 532 } 533 534 switch(dwOrigin) { 535 case STREAM_SEEK_SET: 536 method = FILE_BEGIN; 537 break; 538 case STREAM_SEEK_CUR: 539 method = FILE_CURRENT; 540 break; 541 case STREAM_SEEK_END: 542 method = FILE_END; 543 break; 544 default: 545 WARN("Invalid origin %x\n", dwOrigin); 546 return E_FAIL; 547 } 548 549 if(!SetFilePointerEx(This->buf->file, dlibMove, &new_pos, method)) { 550 FIXME("SetFilePointerEx failed: %u\n", GetLastError()); 551 return E_FAIL; 552 } 553 554 if(plibNewPosition) 555 plibNewPosition->QuadPart = new_pos.QuadPart; 556 return S_OK; 557 } 558 559 static HRESULT WINAPI ProtocolStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize) 560 { 561 ProtocolStream *This = impl_from_IStream(iface); 562 FIXME("(%p)->(%d)\n", This, libNewSize.u.LowPart); 563 return E_NOTIMPL; 564 } 565 566 static HRESULT WINAPI ProtocolStream_CopyTo(IStream *iface, IStream *pstm, 567 ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) 568 { 569 ProtocolStream *This = impl_from_IStream(iface); 570 FIXME("(%p)->(%p %d %p %p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten); 571 return E_NOTIMPL; 572 } 573 574 static HRESULT WINAPI ProtocolStream_Commit(IStream *iface, DWORD grfCommitFlags) 575 { 576 ProtocolStream *This = impl_from_IStream(iface); 577 578 TRACE("(%p)->(%08x)\n", This, grfCommitFlags); 579 580 return E_NOTIMPL; 581 } 582 583 static HRESULT WINAPI ProtocolStream_Revert(IStream *iface) 584 { 585 ProtocolStream *This = impl_from_IStream(iface); 586 587 TRACE("(%p)\n", This); 588 589 return E_NOTIMPL; 590 } 591 592 static HRESULT WINAPI ProtocolStream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset, 593 ULARGE_INTEGER cb, DWORD dwLockType) 594 { 595 ProtocolStream *This = impl_from_IStream(iface); 596 FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType); 597 return E_NOTIMPL; 598 } 599 600 static HRESULT WINAPI ProtocolStream_UnlockRegion(IStream *iface, 601 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 602 { 603 ProtocolStream *This = impl_from_IStream(iface); 604 FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType); 605 return E_NOTIMPL; 606 } 607 608 static HRESULT WINAPI ProtocolStream_Stat(IStream *iface, STATSTG *pstatstg, 609 DWORD dwStatFlag) 610 { 611 ProtocolStream *This = impl_from_IStream(iface); 612 TRACE("(%p)->(%p %08x)\n", This, pstatstg, dwStatFlag); 613 614 if(!pstatstg) 615 return E_FAIL; 616 617 memset(pstatstg, 0, sizeof(STATSTG)); 618 619 if(!(dwStatFlag&STATFLAG_NONAME) && This->buf->cache_file) { 620 pstatstg->pwcsName = CoTaskMemAlloc((lstrlenW(This->buf->cache_file)+1)*sizeof(WCHAR)); 621 if(!pstatstg->pwcsName) 622 return STG_E_INSUFFICIENTMEMORY; 623 624 lstrcpyW(pstatstg->pwcsName, This->buf->cache_file); 625 } 626 627 pstatstg->type = STGTY_STREAM; 628 if(This->buf->file != INVALID_HANDLE_VALUE) { 629 GetFileSizeEx(This->buf->file, (PLARGE_INTEGER)&pstatstg->cbSize); 630 GetFileTime(This->buf->file, &pstatstg->ctime, &pstatstg->atime, &pstatstg->mtime); 631 if(pstatstg->cbSize.QuadPart) 632 pstatstg->grfMode = GENERIC_READ; 633 } 634 635 return S_OK; 636 } 637 638 static HRESULT WINAPI ProtocolStream_Clone(IStream *iface, IStream **ppstm) 639 { 640 ProtocolStream *This = impl_from_IStream(iface); 641 FIXME("(%p)->(%p)\n", This, ppstm); 642 return E_NOTIMPL; 643 } 644 645 static const IStreamVtbl ProtocolStreamVtbl = { 646 ProtocolStream_QueryInterface, 647 ProtocolStream_AddRef, 648 ProtocolStream_Release, 649 ProtocolStream_Read, 650 ProtocolStream_Write, 651 ProtocolStream_Seek, 652 ProtocolStream_SetSize, 653 ProtocolStream_CopyTo, 654 ProtocolStream_Commit, 655 ProtocolStream_Revert, 656 ProtocolStream_LockRegion, 657 ProtocolStream_UnlockRegion, 658 ProtocolStream_Stat, 659 ProtocolStream_Clone 660 }; 661 662 static void stgmed_stream_release(stgmed_obj_t *obj) 663 { 664 ProtocolStream *stream = (ProtocolStream*)obj; 665 IStream_Release(&stream->IStream_iface); 666 } 667 668 static HRESULT stgmed_stream_fill_stgmed(stgmed_obj_t *obj, STGMEDIUM *stgmed) 669 { 670 ProtocolStream *stream = (ProtocolStream*)obj; 671 672 stgmed->tymed = TYMED_ISTREAM; 673 stgmed->u.pstm = &stream->IStream_iface; 674 stgmed->pUnkForRelease = &stream->buf->IUnknown_iface; 675 676 return S_OK; 677 } 678 679 static HRESULT stgmed_stream_get_result(stgmed_obj_t *obj, DWORD bindf, void **result) 680 { 681 ProtocolStream *stream = (ProtocolStream*)obj; 682 683 if(!(bindf & BINDF_ASYNCHRONOUS) && stream->buf->file == INVALID_HANDLE_VALUE 684 && stream->buf->hres != S_FALSE) 685 return INET_E_DATA_NOT_AVAILABLE; 686 687 IStream_AddRef(&stream->IStream_iface); 688 *result = &stream->IStream_iface; 689 return S_OK; 690 } 691 692 static const stgmed_obj_vtbl stgmed_stream_vtbl = { 693 stgmed_stream_release, 694 stgmed_stream_fill_stgmed, 695 stgmed_stream_get_result 696 }; 697 698 typedef struct { 699 stgmed_obj_t stgmed_obj; 700 stgmed_buf_t *buf; 701 } stgmed_file_obj_t; 702 703 static stgmed_obj_t *create_stgmed_stream(stgmed_buf_t *buf) 704 { 705 ProtocolStream *ret = heap_alloc(sizeof(ProtocolStream)); 706 707 ret->stgmed_obj.vtbl = &stgmed_stream_vtbl; 708 ret->IStream_iface.lpVtbl = &ProtocolStreamVtbl; 709 ret->ref = 1; 710 711 IUnknown_AddRef(&buf->IUnknown_iface); 712 ret->buf = buf; 713 714 URLMON_LockModule(); 715 716 return &ret->stgmed_obj; 717 } 718 719 static void stgmed_file_release(stgmed_obj_t *obj) 720 { 721 stgmed_file_obj_t *file_obj = (stgmed_file_obj_t*)obj; 722 723 IUnknown_Release(&file_obj->buf->IUnknown_iface); 724 heap_free(file_obj); 725 } 726 727 static HRESULT stgmed_file_fill_stgmed(stgmed_obj_t *obj, STGMEDIUM *stgmed) 728 { 729 stgmed_file_obj_t *file_obj = (stgmed_file_obj_t*)obj; 730 731 if(!file_obj->buf->cache_file) { 732 WARN("cache_file not set\n"); 733 return INET_E_DATA_NOT_AVAILABLE; 734 } 735 736 read_protocol_data(file_obj->buf); 737 738 stgmed->tymed = TYMED_FILE; 739 stgmed->u.lpszFileName = file_obj->buf->cache_file; 740 stgmed->pUnkForRelease = &file_obj->buf->IUnknown_iface; 741 742 return S_OK; 743 } 744 745 static HRESULT stgmed_file_get_result(stgmed_obj_t *obj, DWORD bindf, void **result) 746 { 747 return bindf & BINDF_ASYNCHRONOUS ? MK_S_ASYNCHRONOUS : S_OK; 748 } 749 750 static const stgmed_obj_vtbl stgmed_file_vtbl = { 751 stgmed_file_release, 752 stgmed_file_fill_stgmed, 753 stgmed_file_get_result 754 }; 755 756 static stgmed_obj_t *create_stgmed_file(stgmed_buf_t *buf) 757 { 758 stgmed_file_obj_t *ret = heap_alloc(sizeof(*ret)); 759 760 ret->stgmed_obj.vtbl = &stgmed_file_vtbl; 761 762 IUnknown_AddRef(&buf->IUnknown_iface); 763 ret->buf = buf; 764 765 return &ret->stgmed_obj; 766 } 767 768 static inline Binding *impl_from_IBinding(IBinding *iface) 769 { 770 return CONTAINING_RECORD(iface, Binding, IBinding_iface); 771 } 772 773 static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv) 774 { 775 Binding *This = impl_from_IBinding(iface); 776 777 *ppv = NULL; 778 779 if(IsEqualGUID(&IID_IUnknown, riid)) { 780 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 781 *ppv = &This->IBinding_iface; 782 }else if(IsEqualGUID(&IID_IBinding, riid)) { 783 TRACE("(%p)->(IID_IBinding %p)\n", This, ppv); 784 *ppv = &This->IBinding_iface; 785 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) { 786 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv); 787 *ppv = &This->IInternetProtocolSink_iface; 788 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) { 789 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv); 790 *ppv = &This->IInternetBindInfo_iface; 791 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) { 792 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv); 793 *ppv = &This->IServiceProvider_iface; 794 }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) { 795 TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv); 796 797 /* NOTE: This violidates COM rules, but tests prove that we should do it */ 798 if(!This->protocol->wininet_info) 799 return E_NOINTERFACE; 800 801 *ppv = &This->IWinInetHttpInfo_iface; 802 }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) { 803 TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv); 804 805 if(!This->protocol->wininet_http_info) 806 return E_NOINTERFACE; 807 808 *ppv = &This->IWinInetHttpInfo_iface; 809 } 810 811 if(*ppv) { 812 IBinding_AddRef(&This->IBinding_iface); 813 return S_OK; 814 } 815 816 WARN("Unsupported interface %s\n", debugstr_guid(riid)); 817 return E_NOINTERFACE; 818 } 819 820 static ULONG WINAPI Binding_AddRef(IBinding *iface) 821 { 822 Binding *This = impl_from_IBinding(iface); 823 LONG ref = InterlockedIncrement(&This->ref); 824 825 TRACE("(%p) ref=%d\n", This, ref); 826 827 return ref; 828 } 829 830 static ULONG WINAPI Binding_Release(IBinding *iface) 831 { 832 Binding *This = impl_from_IBinding(iface); 833 LONG ref = InterlockedDecrement(&This->ref); 834 835 TRACE("(%p) ref=%d\n", This, ref); 836 837 if(!ref) { 838 if(This->notif_hwnd) 839 release_notif_hwnd(This->notif_hwnd); 840 if(This->mon) 841 IMoniker_Release(This->mon); 842 if(This->callback) 843 IBindStatusCallback_Release(This->callback); 844 if(This->protocol) 845 IInternetProtocolEx_Release(&This->protocol->IInternetProtocolEx_iface); 846 if(This->service_provider) 847 IServiceProvider_Release(This->service_provider); 848 if(This->stgmed_buf) 849 IUnknown_Release(&This->stgmed_buf->IUnknown_iface); 850 if(This->stgmed_obj) 851 This->stgmed_obj->vtbl->release(This->stgmed_obj); 852 if(This->obj) 853 IUnknown_Release(This->obj); 854 if(This->bctx) 855 IBindCtx_Release(This->bctx); 856 857 ReleaseBindInfo(&This->bindinfo); 858 This->section.DebugInfo->Spare[0] = 0; 859 DeleteCriticalSection(&This->section); 860 SysFreeString(This->url); 861 heap_free(This->mime); 862 heap_free(This->redirect_url); 863 heap_free(This); 864 865 URLMON_UnlockModule(); 866 } 867 868 return ref; 869 } 870 871 static HRESULT WINAPI Binding_Abort(IBinding *iface) 872 { 873 Binding *This = impl_from_IBinding(iface); 874 HRESULT hres; 875 876 TRACE("(%p)\n", This); 877 878 if(This->state & BINDING_ABORTED) 879 return E_FAIL; 880 881 hres = IInternetProtocolEx_Abort(&This->protocol->IInternetProtocolEx_iface, E_ABORT, 882 ERROR_SUCCESS); 883 if(FAILED(hres)) 884 return hres; 885 886 This->state |= BINDING_ABORTED; 887 return S_OK; 888 } 889 890 static HRESULT WINAPI Binding_Suspend(IBinding *iface) 891 { 892 Binding *This = impl_from_IBinding(iface); 893 FIXME("(%p)\n", This); 894 return E_NOTIMPL; 895 } 896 897 static HRESULT WINAPI Binding_Resume(IBinding *iface) 898 { 899 Binding *This = impl_from_IBinding(iface); 900 FIXME("(%p)\n", This); 901 return E_NOTIMPL; 902 } 903 904 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority) 905 { 906 Binding *This = impl_from_IBinding(iface); 907 FIXME("(%p)->(%d)\n", This, nPriority); 908 return E_NOTIMPL; 909 } 910 911 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority) 912 { 913 Binding *This = impl_from_IBinding(iface); 914 FIXME("(%p)->(%p)\n", This, pnPriority); 915 return E_NOTIMPL; 916 } 917 918 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol, 919 DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved) 920 { 921 Binding *This = impl_from_IBinding(iface); 922 923 TRACE("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved); 924 925 if(!pdwResult || !pszResult || pdwReserved) 926 return E_INVALIDARG; 927 928 if(!(This->state & BINDING_STOPPED)) { 929 *pclsidProtocol = CLSID_NULL; 930 *pdwResult = 0; 931 *pszResult = NULL; 932 return S_OK; 933 } 934 935 *pclsidProtocol = This->hres==S_OK ? CLSID_NULL : This->clsid; 936 *pdwResult = This->hres; 937 *pszResult = NULL; 938 return S_OK; 939 } 940 941 static const IBindingVtbl BindingVtbl = { 942 Binding_QueryInterface, 943 Binding_AddRef, 944 Binding_Release, 945 Binding_Abort, 946 Binding_Suspend, 947 Binding_Resume, 948 Binding_SetPriority, 949 Binding_GetPriority, 950 Binding_GetBindResult 951 }; 952 953 static Binding *get_bctx_binding(IBindCtx *bctx) 954 { 955 IBinding *binding; 956 IUnknown *unk; 957 HRESULT hres; 958 959 hres = IBindCtx_GetObjectParam(bctx, cbinding_contextW, &unk); 960 if(FAILED(hres)) 961 return NULL; 962 963 hres = IUnknown_QueryInterface(unk, &IID_IBinding, (void**)&binding); 964 IUnknown_Release(unk); 965 if(FAILED(hres)) 966 return NULL; 967 968 if (binding->lpVtbl != &BindingVtbl) 969 return NULL; 970 return impl_from_IBinding(binding); 971 } 972 973 static inline Binding *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface) 974 { 975 return CONTAINING_RECORD(iface, Binding, IInternetProtocolSink_iface); 976 } 977 978 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface, 979 REFIID riid, void **ppv) 980 { 981 Binding *This = impl_from_IInternetProtocolSink(iface); 982 return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv); 983 } 984 985 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface) 986 { 987 Binding *This = impl_from_IInternetProtocolSink(iface); 988 return IBinding_AddRef(&This->IBinding_iface); 989 } 990 991 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface) 992 { 993 Binding *This = impl_from_IInternetProtocolSink(iface); 994 return IBinding_Release(&This->IBinding_iface); 995 } 996 997 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface, 998 PROTOCOLDATA *pProtocolData) 999 { 1000 Binding *This = impl_from_IInternetProtocolSink(iface); 1001 1002 WARN("(%p)->(%p)\n", This, pProtocolData); 1003 1004 return E_FAIL; 1005 } 1006 1007 static void on_progress(Binding *This, ULONG progress, ULONG progress_max, 1008 ULONG status_code, LPCWSTR status_text) 1009 { 1010 IBindStatusCallback_OnProgress(This->callback, progress, progress_max, 1011 status_code, status_text); 1012 } 1013 1014 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface, 1015 ULONG ulStatusCode, LPCWSTR szStatusText) 1016 { 1017 Binding *This = impl_from_IInternetProtocolSink(iface); 1018 1019 TRACE("(%p)->(%s %s)\n", This, debugstr_bindstatus(ulStatusCode), debugstr_w(szStatusText)); 1020 1021 switch(ulStatusCode) { 1022 case BINDSTATUS_FINDINGRESOURCE: 1023 on_progress(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, szStatusText); 1024 break; 1025 case BINDSTATUS_CONNECTING: 1026 on_progress(This, 0, 0, BINDSTATUS_CONNECTING, szStatusText); 1027 break; 1028 case BINDSTATUS_REDIRECTING: 1029 heap_free(This->redirect_url); 1030 This->redirect_url = heap_strdupW(szStatusText); 1031 on_progress(This, 0, 0, BINDSTATUS_REDIRECTING, szStatusText); 1032 break; 1033 case BINDSTATUS_BEGINDOWNLOADDATA: 1034 break; 1035 case BINDSTATUS_SENDINGREQUEST: 1036 on_progress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, szStatusText); 1037 break; 1038 case BINDSTATUS_PROTOCOLCLASSID: 1039 CLSIDFromString(szStatusText, &This->clsid); 1040 break; 1041 case BINDSTATUS_MIMETYPEAVAILABLE: 1042 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE: 1043 mime_available(This, szStatusText); 1044 break; 1045 case BINDSTATUS_CACHEFILENAMEAVAILABLE: 1046 cache_file_available(This, szStatusText); 1047 break; 1048 case BINDSTATUS_DECODING: 1049 IBindStatusCallback_OnProgress(This->callback, 0, 0, BINDSTATUS_DECODING, szStatusText); 1050 break; 1051 case BINDSTATUS_LOADINGMIMEHANDLER: 1052 on_progress(This, 0, 0, BINDSTATUS_LOADINGMIMEHANDLER, szStatusText); 1053 break; 1054 case BINDSTATUS_DIRECTBIND: /* FIXME: Handle BINDSTATUS_DIRECTBIND in BindProtocol */ 1055 This->report_mime = FALSE; 1056 break; 1057 case BINDSTATUS_ACCEPTRANGES: 1058 break; 1059 default: 1060 FIXME("Unhandled status code %d\n", ulStatusCode); 1061 return E_NOTIMPL; 1062 }; 1063 1064 return S_OK; 1065 } 1066 1067 static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progress_max) 1068 { 1069 FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM}; 1070 BOOL sent_begindownloaddata = FALSE; 1071 1072 TRACE("(%p)->(%d %u %u)\n", This, bscf, progress, progress_max); 1073 1074 if(This->download_state == END_DOWNLOAD || (This->state & BINDING_ABORTED)) { 1075 read_protocol_data(This->stgmed_buf); 1076 return; 1077 } 1078 1079 if(This->state & BINDING_STOPPED) 1080 return; 1081 1082 if(This->stgmed_buf->file != INVALID_HANDLE_VALUE) 1083 read_protocol_data(This->stgmed_buf); 1084 1085 if(This->download_state == BEFORE_DOWNLOAD) { 1086 This->download_state = DOWNLOADING; 1087 sent_begindownloaddata = TRUE; 1088 IBindStatusCallback_OnProgress(This->callback, progress, progress_max, 1089 BINDSTATUS_BEGINDOWNLOADDATA, This->url); 1090 1091 if(This->stgmed_buf->cache_file) 1092 IBindStatusCallback_OnProgress(This->callback, progress, progress_max, 1093 BINDSTATUS_CACHEFILENAMEAVAILABLE, This->stgmed_buf->cache_file); 1094 } 1095 1096 if(This->stgmed_buf->hres == S_FALSE || (bscf & BSCF_LASTDATANOTIFICATION)) { 1097 This->download_state = END_DOWNLOAD; 1098 IBindStatusCallback_OnProgress(This->callback, progress, progress_max, 1099 BINDSTATUS_ENDDOWNLOADDATA, This->url); 1100 }else if(!sent_begindownloaddata) { 1101 IBindStatusCallback_OnProgress(This->callback, progress, progress_max, 1102 BINDSTATUS_DOWNLOADINGDATA, This->url); 1103 } 1104 1105 if(This->state & (BINDING_STOPPED|BINDING_ABORTED)) 1106 return; 1107 1108 if(This->to_object) { 1109 if(!(This->state & BINDING_OBJAVAIL)) { 1110 IBinding_AddRef(&This->IBinding_iface); 1111 create_object(This); 1112 IBinding_Release(&This->IBinding_iface); 1113 } 1114 }else { 1115 STGMEDIUM stgmed; 1116 HRESULT hres; 1117 1118 if(!(This->state & BINDING_LOCKED)) { 1119 HRESULT hres = IInternetProtocolEx_LockRequest( 1120 &This->protocol->IInternetProtocolEx_iface, 0); 1121 if(SUCCEEDED(hres)) 1122 This->state |= BINDING_LOCKED; 1123 } 1124 1125 hres = This->stgmed_obj->vtbl->fill_stgmed(This->stgmed_obj, &stgmed); 1126 if(FAILED(hres)) { 1127 stop_binding(This, hres, NULL); 1128 return; 1129 } 1130 1131 formatetc.tymed = stgmed.tymed; 1132 formatetc.cfFormat = This->clipboard_format; 1133 1134 hres = IBindStatusCallback_OnDataAvailable(This->callback, bscf, progress, 1135 &formatetc, &stgmed); 1136 if(hres != S_OK) { 1137 if(This->download_state != END_DOWNLOAD) { 1138 This->download_state = END_DOWNLOAD; 1139 IBindStatusCallback_OnProgress(This->callback, progress, progress_max, 1140 BINDSTATUS_ENDDOWNLOADDATA, This->url); 1141 } 1142 1143 WARN("OnDataAvailable returned %x\n", hres); 1144 stop_binding(This, hres, NULL); 1145 return; 1146 } 1147 1148 if(This->download_state == END_DOWNLOAD) 1149 stop_binding(This, S_OK, NULL); 1150 } 1151 } 1152 1153 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface, 1154 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax) 1155 { 1156 Binding *This = impl_from_IInternetProtocolSink(iface); 1157 1158 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax); 1159 1160 report_data(This, grfBSCF, ulProgress, ulProgressMax); 1161 return S_OK; 1162 } 1163 1164 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface, 1165 HRESULT hrResult, DWORD dwError, LPCWSTR szResult) 1166 { 1167 Binding *This = impl_from_IInternetProtocolSink(iface); 1168 1169 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult)); 1170 1171 stop_binding(This, hrResult, szResult); 1172 1173 IInternetProtocolEx_Terminate(&This->protocol->IInternetProtocolEx_iface, 0); 1174 return S_OK; 1175 } 1176 1177 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = { 1178 InternetProtocolSink_QueryInterface, 1179 InternetProtocolSink_AddRef, 1180 InternetProtocolSink_Release, 1181 InternetProtocolSink_Switch, 1182 InternetProtocolSink_ReportProgress, 1183 InternetProtocolSink_ReportData, 1184 InternetProtocolSink_ReportResult 1185 }; 1186 1187 static inline Binding *impl_from_IInternetBindInfo(IInternetBindInfo *iface) 1188 { 1189 return CONTAINING_RECORD(iface, Binding, IInternetBindInfo_iface); 1190 } 1191 1192 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface, 1193 REFIID riid, void **ppv) 1194 { 1195 Binding *This = impl_from_IInternetBindInfo(iface); 1196 return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv); 1197 } 1198 1199 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface) 1200 { 1201 Binding *This = impl_from_IInternetBindInfo(iface); 1202 return IBinding_AddRef(&This->IBinding_iface); 1203 } 1204 1205 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface) 1206 { 1207 Binding *This = impl_from_IInternetBindInfo(iface); 1208 return IBinding_Release(&This->IBinding_iface); 1209 } 1210 1211 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface, 1212 DWORD *grfBINDF, BINDINFO *pbindinfo) 1213 { 1214 Binding *This = impl_from_IInternetBindInfo(iface); 1215 1216 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo); 1217 1218 *grfBINDF = This->bindf; 1219 return CopyBindInfo(&This->bindinfo, pbindinfo); 1220 } 1221 1222 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface, 1223 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched) 1224 { 1225 Binding *This = impl_from_IInternetBindInfo(iface); 1226 1227 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched); 1228 1229 switch(ulStringType) { 1230 case BINDSTRING_ACCEPT_MIMES: { 1231 static const WCHAR wszMimes[] = {'*','/','*',0}; 1232 1233 if(!ppwzStr || !pcElFetched) 1234 return E_INVALIDARG; 1235 1236 ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes)); 1237 memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes)); 1238 *pcElFetched = 1; 1239 return S_OK; 1240 } 1241 case BINDSTRING_USER_AGENT: { 1242 IInternetBindInfo *bindinfo = NULL; 1243 HRESULT hres; 1244 1245 hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo, 1246 (void**)&bindinfo); 1247 if(FAILED(hres)) 1248 return hres; 1249 1250 hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr, 1251 cEl, pcElFetched); 1252 IInternetBindInfo_Release(bindinfo); 1253 1254 return hres; 1255 } 1256 case BINDSTRING_URL: { 1257 DWORD size = (SysStringLen(This->url)+1) * sizeof(WCHAR); 1258 1259 if(!ppwzStr || !pcElFetched) 1260 return E_INVALIDARG; 1261 1262 *ppwzStr = CoTaskMemAlloc(size); 1263 memcpy(*ppwzStr, This->url, size); 1264 *pcElFetched = 1; 1265 return S_OK; 1266 } 1267 } 1268 1269 FIXME("not supported string type %d\n", ulStringType); 1270 return E_NOTIMPL; 1271 } 1272 1273 static const IInternetBindInfoVtbl InternetBindInfoVtbl = { 1274 InternetBindInfo_QueryInterface, 1275 InternetBindInfo_AddRef, 1276 InternetBindInfo_Release, 1277 InternetBindInfo_GetBindInfo, 1278 InternetBindInfo_GetBindString 1279 }; 1280 1281 static inline Binding *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface) 1282 { 1283 return CONTAINING_RECORD(iface, Binding, IWinInetHttpInfo_iface); 1284 } 1285 1286 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv) 1287 { 1288 Binding *This = impl_from_IWinInetHttpInfo(iface); 1289 return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv); 1290 } 1291 1292 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface) 1293 { 1294 Binding *This = impl_from_IWinInetHttpInfo(iface); 1295 return IBinding_AddRef(&This->IBinding_iface); 1296 } 1297 1298 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface) 1299 { 1300 Binding *This = impl_from_IWinInetHttpInfo(iface); 1301 return IBinding_Release(&This->IBinding_iface); 1302 } 1303 1304 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption, 1305 void *pBuffer, DWORD *pcbBuffer) 1306 { 1307 Binding *This = impl_from_IWinInetHttpInfo(iface); 1308 TRACE("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer); 1309 1310 if(!This->protocol->wininet_info) 1311 return E_FAIL; 1312 1313 return IWinInetInfo_QueryOption(This->protocol->wininet_info, 1314 dwOption, pBuffer, pcbBuffer); 1315 } 1316 1317 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption, 1318 void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved) 1319 { 1320 Binding *This = impl_from_IWinInetHttpInfo(iface); 1321 TRACE("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved); 1322 1323 if(!This->protocol->wininet_http_info) 1324 return E_FAIL; 1325 1326 return IWinInetHttpInfo_QueryInfo(This->protocol->wininet_http_info, 1327 dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved); 1328 } 1329 1330 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = { 1331 WinInetHttpInfo_QueryInterface, 1332 WinInetHttpInfo_AddRef, 1333 WinInetHttpInfo_Release, 1334 WinInetHttpInfo_QueryOption, 1335 WinInetHttpInfo_QueryInfo 1336 }; 1337 1338 static inline Binding *impl_from_IServiceProvider(IServiceProvider *iface) 1339 { 1340 return CONTAINING_RECORD(iface, Binding, IServiceProvider_iface); 1341 } 1342 1343 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, 1344 REFIID riid, void **ppv) 1345 { 1346 Binding *This = impl_from_IServiceProvider(iface); 1347 return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv); 1348 } 1349 1350 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface) 1351 { 1352 Binding *This = impl_from_IServiceProvider(iface); 1353 return IBinding_AddRef(&This->IBinding_iface); 1354 } 1355 1356 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface) 1357 { 1358 Binding *This = impl_from_IServiceProvider(iface); 1359 return IBinding_Release(&This->IBinding_iface); 1360 } 1361 1362 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, 1363 REFGUID guidService, REFIID riid, void **ppv) 1364 { 1365 Binding *This = impl_from_IServiceProvider(iface); 1366 HRESULT hres; 1367 1368 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); 1369 1370 if(This->service_provider) { 1371 hres = IServiceProvider_QueryService(This->service_provider, guidService, 1372 riid, ppv); 1373 if(SUCCEEDED(hres)) 1374 return hres; 1375 } 1376 1377 WARN("unknown service %s\n", debugstr_guid(guidService)); 1378 return E_NOINTERFACE; 1379 } 1380 1381 static const IServiceProviderVtbl ServiceProviderVtbl = { 1382 ServiceProvider_QueryInterface, 1383 ServiceProvider_AddRef, 1384 ServiceProvider_Release, 1385 ServiceProvider_QueryService 1386 }; 1387 1388 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback) 1389 { 1390 IUnknown *unk; 1391 HRESULT hres; 1392 1393 hres = IBindCtx_GetObjectParam(pbc, bscb_holderW, &unk); 1394 if(FAILED(hres)) 1395 return create_default_callback(callback); 1396 1397 hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)callback); 1398 IUnknown_Release(unk); 1399 return hres; 1400 } 1401 1402 static BOOL is_urlmon_protocol(IUri *uri) 1403 { 1404 DWORD scheme; 1405 HRESULT hres; 1406 1407 hres = IUri_GetScheme(uri, &scheme); 1408 if(FAILED(hres)) 1409 return FALSE; 1410 1411 switch(scheme) { 1412 case URL_SCHEME_FILE: 1413 case URL_SCHEME_FTP: 1414 case URL_SCHEME_GOPHER: 1415 case URL_SCHEME_HTTP: 1416 case URL_SCHEME_HTTPS: 1417 case URL_SCHEME_MK: 1418 return TRUE; 1419 } 1420 1421 return FALSE; 1422 } 1423 1424 static HRESULT Binding_Create(IMoniker *mon, Binding *binding_ctx, IUri *uri, IBindCtx *pbc, 1425 BOOL to_obj, REFIID riid, Binding **binding) 1426 { 1427 Binding *ret; 1428 HRESULT hres; 1429 1430 URLMON_LockModule(); 1431 1432 ret = heap_alloc_zero(sizeof(Binding)); 1433 1434 ret->IBinding_iface.lpVtbl = &BindingVtbl; 1435 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl; 1436 ret->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl; 1437 ret->IWinInetHttpInfo_iface.lpVtbl = &WinInetHttpInfoVtbl; 1438 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; 1439 1440 ret->ref = 1; 1441 1442 ret->to_object = to_obj; 1443 ret->iid = *riid; 1444 ret->notif_hwnd = get_notif_hwnd(); 1445 ret->report_mime = !binding_ctx; 1446 ret->download_state = BEFORE_DOWNLOAD; 1447 1448 if(to_obj) { 1449 IBindCtx_AddRef(pbc); 1450 ret->bctx = pbc; 1451 } 1452 1453 if(mon) { 1454 IMoniker_AddRef(mon); 1455 ret->mon = mon; 1456 } 1457 1458 ret->bindinfo.cbSize = sizeof(BINDINFO); 1459 1460 InitializeCriticalSection(&ret->section); 1461 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Binding.section"); 1462 1463 hres = get_callback(pbc, &ret->callback); 1464 if(FAILED(hres)) { 1465 WARN("Could not get IBindStatusCallback\n"); 1466 IBinding_Release(&ret->IBinding_iface); 1467 return hres; 1468 } 1469 1470 IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider, 1471 (void**)&ret->service_provider); 1472 1473 if(binding_ctx) { 1474 ret->protocol = binding_ctx->protocol; 1475 IInternetProtocolEx_AddRef(&ret->protocol->IInternetProtocolEx_iface); 1476 }else { 1477 hres = create_binding_protocol(TRUE, &ret->protocol); 1478 if(FAILED(hres)) { 1479 WARN("Could not get protocol handler\n"); 1480 IBinding_Release(&ret->IBinding_iface); 1481 return hres; 1482 } 1483 } 1484 1485 hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo); 1486 if(FAILED(hres)) { 1487 WARN("GetBindInfo failed: %08x\n", hres); 1488 IBinding_Release(&ret->IBinding_iface); 1489 return hres; 1490 } 1491 1492 TRACE("bindf %08x\n", ret->bindf); 1493 dump_BINDINFO(&ret->bindinfo); 1494 1495 ret->bindf |= BINDF_FROMURLMON; 1496 if(to_obj) 1497 ret->bindinfo.dwOptions |= 0x100000; 1498 1499 if(!(ret->bindf & BINDF_ASYNCHRONOUS) || !(ret->bindf & BINDF_PULLDATA)) { 1500 ret->bindf |= BINDF_NEEDFILE; 1501 ret->use_cache_file = TRUE; 1502 }else if(!is_urlmon_protocol(uri)) { 1503 ret->bindf |= BINDF_NEEDFILE; 1504 } 1505 1506 hres = IUri_GetDisplayUri(uri, &ret->url); 1507 if(FAILED(hres)) { 1508 IBinding_Release(&ret->IBinding_iface); 1509 return hres; 1510 } 1511 1512 if(binding_ctx) { 1513 ret->stgmed_buf = binding_ctx->stgmed_buf; 1514 IUnknown_AddRef(&ret->stgmed_buf->IUnknown_iface); 1515 ret->clipboard_format = binding_ctx->clipboard_format; 1516 }else { 1517 ret->stgmed_buf = create_stgmed_buf(&ret->protocol->IInternetProtocolEx_iface); 1518 } 1519 1520 if(to_obj) { 1521 ret->stgmed_obj = NULL; 1522 }else if(IsEqualGUID(&IID_IStream, riid)) { 1523 ret->stgmed_obj = create_stgmed_stream(ret->stgmed_buf); 1524 }else if(IsEqualGUID(&IID_IUnknown, riid)) { 1525 ret->bindf |= BINDF_NEEDFILE; 1526 ret->stgmed_obj = create_stgmed_file(ret->stgmed_buf); 1527 }else { 1528 FIXME("Unsupported riid %s\n", debugstr_guid(riid)); 1529 IBinding_Release(&ret->IBinding_iface); 1530 return E_NOTIMPL; 1531 } 1532 1533 *binding = ret; 1534 return S_OK; 1535 } 1536 1537 static HRESULT start_binding(IMoniker *mon, Binding *binding_ctx, IUri *uri, IBindCtx *pbc, 1538 BOOL to_obj, REFIID riid, Binding **ret) 1539 { 1540 Binding *binding = NULL; 1541 HRESULT hres; 1542 MSG msg; 1543 1544 hres = Binding_Create(mon, binding_ctx, uri, pbc, to_obj, riid, &binding); 1545 if(FAILED(hres)) 1546 return hres; 1547 1548 hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, &binding->IBinding_iface); 1549 if(FAILED(hres)) { 1550 WARN("OnStartBinding failed: %08x\n", hres); 1551 if(hres != E_ABORT && hres != E_NOTIMPL) 1552 hres = INET_E_DOWNLOAD_FAILURE; 1553 1554 stop_binding(binding, hres, NULL); 1555 IBinding_Release(&binding->IBinding_iface); 1556 return hres; 1557 } 1558 1559 if(binding_ctx) { 1560 set_binding_sink(binding->protocol, &binding->IInternetProtocolSink_iface, 1561 &binding->IInternetBindInfo_iface); 1562 if(binding_ctx->redirect_url) 1563 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_REDIRECTING, binding_ctx->redirect_url); 1564 report_data(binding, BSCF_FIRSTDATANOTIFICATION | (binding_ctx->download_state == END_DOWNLOAD ? BSCF_LASTDATANOTIFICATION : 0), 1565 0, 0); 1566 }else { 1567 hres = IInternetProtocolEx_StartEx(&binding->protocol->IInternetProtocolEx_iface, uri, 1568 &binding->IInternetProtocolSink_iface, &binding->IInternetBindInfo_iface, 1569 PI_APARTMENTTHREADED|PI_MIMEVERIFICATION, 0); 1570 1571 TRACE("start ret %08x\n", hres); 1572 1573 if(FAILED(hres) && hres != E_PENDING) { 1574 stop_binding(binding, hres, NULL); 1575 IBinding_Release(&binding->IBinding_iface); 1576 1577 return hres; 1578 } 1579 } 1580 1581 while(!(binding->bindf & BINDF_ASYNCHRONOUS) && 1582 !(binding->state & BINDING_STOPPED)) { 1583 MsgWaitForMultipleObjects(0, NULL, FALSE, 5000, QS_POSTMESSAGE); 1584 while (PeekMessageW(&msg, binding->notif_hwnd, WM_USER, WM_USER+117, PM_REMOVE|PM_NOYIELD)) { 1585 TranslateMessage(&msg); 1586 DispatchMessageW(&msg); 1587 } 1588 } 1589 1590 *ret = binding; 1591 return S_OK; 1592 } 1593 1594 HRESULT bind_to_storage(IUri *uri, IBindCtx *pbc, REFIID riid, void **ppv) 1595 { 1596 Binding *binding = NULL, *binding_ctx; 1597 HRESULT hres; 1598 1599 binding_ctx = get_bctx_binding(pbc); 1600 1601 hres = start_binding(NULL, binding_ctx, uri, pbc, FALSE, riid, &binding); 1602 if(binding_ctx) 1603 IBinding_Release(&binding_ctx->IBinding_iface); 1604 if(FAILED(hres)) 1605 return hres; 1606 1607 if(binding->hres == S_OK && binding->download_state != BEFORE_DOWNLOAD /* FIXME */) { 1608 if((binding->state & BINDING_STOPPED) && (binding->state & BINDING_LOCKED)) 1609 IInternetProtocolEx_UnlockRequest(&binding->protocol->IInternetProtocolEx_iface); 1610 1611 hres = binding->stgmed_obj->vtbl->get_result(binding->stgmed_obj, binding->bindf, ppv); 1612 }else if(binding->bindf & BINDF_ASYNCHRONOUS) { 1613 hres = MK_S_ASYNCHRONOUS; 1614 }else { 1615 hres = FAILED(binding->hres) ? binding->hres : S_OK; 1616 } 1617 1618 IBinding_Release(&binding->IBinding_iface); 1619 1620 return hres; 1621 } 1622 1623 HRESULT bind_to_object(IMoniker *mon, IUri *uri, IBindCtx *pbc, REFIID riid, void **ppv) 1624 { 1625 Binding *binding; 1626 HRESULT hres; 1627 1628 *ppv = NULL; 1629 1630 hres = start_binding(mon, NULL, uri, pbc, TRUE, riid, &binding); 1631 if(FAILED(hres)) 1632 return hres; 1633 1634 if(binding->hres != S_OK) { 1635 hres = SUCCEEDED(binding->hres) ? S_OK : binding->hres; 1636 }else if(binding->bindf & BINDF_ASYNCHRONOUS) { 1637 hres = MK_S_ASYNCHRONOUS; 1638 }else { 1639 *ppv = binding->obj; 1640 IUnknown_AddRef(binding->obj); 1641 hres = S_OK; 1642 } 1643 1644 IBinding_Release(&binding->IBinding_iface); 1645 1646 return hres; 1647 } 1648