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