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 IWinInetInfo *wininet_info; 796 HRESULT hres; 797 798 TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv); 799 800 /* NOTE: This violidates COM rules, but tests prove that we should do it */ 801 hres = IInternetProtocolEx_QueryInterface(&This->protocol->IInternetProtocolEx_iface, 802 &IID_IWinInetInfo, (void**)&wininet_info); 803 if(SUCCEEDED(hres)) { 804 IWinInetInfo_Release(wininet_info); 805 *ppv = &This->IWinInetHttpInfo_iface; 806 } 807 }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) { 808 IWinInetHttpInfo *http_info; 809 HRESULT hres; 810 811 TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv); 812 813 /* NOTE: This violidates COM rules, but tests prove that we should do it */ 814 hres = IInternetProtocolEx_QueryInterface(&This->protocol->IInternetProtocolEx_iface, 815 &IID_IWinInetHttpInfo, (void**)&http_info); 816 if(SUCCEEDED(hres)) { 817 IWinInetHttpInfo_Release(http_info); 818 *ppv = &This->IWinInetHttpInfo_iface; 819 } 820 } 821 822 if(*ppv) { 823 IBinding_AddRef(&This->IBinding_iface); 824 return S_OK; 825 } 826 827 WARN("Unsupported interface %s\n", debugstr_guid(riid)); 828 return E_NOINTERFACE; 829 } 830 831 static ULONG WINAPI Binding_AddRef(IBinding *iface) 832 { 833 Binding *This = impl_from_IBinding(iface); 834 LONG ref = InterlockedIncrement(&This->ref); 835 836 TRACE("(%p) ref=%d\n", This, ref); 837 838 return ref; 839 } 840 841 static ULONG WINAPI Binding_Release(IBinding *iface) 842 { 843 Binding *This = impl_from_IBinding(iface); 844 LONG ref = InterlockedDecrement(&This->ref); 845 846 TRACE("(%p) ref=%d\n", This, ref); 847 848 if(!ref) { 849 if(This->notif_hwnd) 850 release_notif_hwnd(This->notif_hwnd); 851 if(This->mon) 852 IMoniker_Release(This->mon); 853 if(This->callback) 854 IBindStatusCallback_Release(This->callback); 855 if(This->protocol) 856 IInternetProtocolEx_Release(&This->protocol->IInternetProtocolEx_iface); 857 if(This->service_provider) 858 IServiceProvider_Release(This->service_provider); 859 if(This->stgmed_buf) 860 IUnknown_Release(&This->stgmed_buf->IUnknown_iface); 861 if(This->stgmed_obj) 862 This->stgmed_obj->vtbl->release(This->stgmed_obj); 863 if(This->obj) 864 IUnknown_Release(This->obj); 865 if(This->bctx) 866 IBindCtx_Release(This->bctx); 867 868 ReleaseBindInfo(&This->bindinfo); 869 This->section.DebugInfo->Spare[0] = 0; 870 DeleteCriticalSection(&This->section); 871 SysFreeString(This->url); 872 heap_free(This->mime); 873 heap_free(This->redirect_url); 874 heap_free(This); 875 876 URLMON_UnlockModule(); 877 } 878 879 return ref; 880 } 881 882 static HRESULT WINAPI Binding_Abort(IBinding *iface) 883 { 884 Binding *This = impl_from_IBinding(iface); 885 HRESULT hres; 886 887 TRACE("(%p)\n", This); 888 889 if(This->state & BINDING_ABORTED) 890 return E_FAIL; 891 892 hres = IInternetProtocolEx_Abort(&This->protocol->IInternetProtocolEx_iface, E_ABORT, 893 ERROR_SUCCESS); 894 if(FAILED(hres)) 895 return hres; 896 897 This->state |= BINDING_ABORTED; 898 return S_OK; 899 } 900 901 static HRESULT WINAPI Binding_Suspend(IBinding *iface) 902 { 903 Binding *This = impl_from_IBinding(iface); 904 FIXME("(%p)\n", This); 905 return E_NOTIMPL; 906 } 907 908 static HRESULT WINAPI Binding_Resume(IBinding *iface) 909 { 910 Binding *This = impl_from_IBinding(iface); 911 FIXME("(%p)\n", This); 912 return E_NOTIMPL; 913 } 914 915 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority) 916 { 917 Binding *This = impl_from_IBinding(iface); 918 FIXME("(%p)->(%d)\n", This, nPriority); 919 return E_NOTIMPL; 920 } 921 922 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority) 923 { 924 Binding *This = impl_from_IBinding(iface); 925 FIXME("(%p)->(%p)\n", This, pnPriority); 926 return E_NOTIMPL; 927 } 928 929 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol, 930 DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved) 931 { 932 Binding *This = impl_from_IBinding(iface); 933 934 TRACE("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved); 935 936 if(!pdwResult || !pszResult || pdwReserved) 937 return E_INVALIDARG; 938 939 if(!(This->state & BINDING_STOPPED)) { 940 *pclsidProtocol = CLSID_NULL; 941 *pdwResult = 0; 942 *pszResult = NULL; 943 return S_OK; 944 } 945 946 *pclsidProtocol = This->hres==S_OK ? CLSID_NULL : This->clsid; 947 *pdwResult = This->hres; 948 *pszResult = NULL; 949 return S_OK; 950 } 951 952 static const IBindingVtbl BindingVtbl = { 953 Binding_QueryInterface, 954 Binding_AddRef, 955 Binding_Release, 956 Binding_Abort, 957 Binding_Suspend, 958 Binding_Resume, 959 Binding_SetPriority, 960 Binding_GetPriority, 961 Binding_GetBindResult 962 }; 963 964 static Binding *get_bctx_binding(IBindCtx *bctx) 965 { 966 IBinding *binding; 967 IUnknown *unk; 968 HRESULT hres; 969 970 hres = IBindCtx_GetObjectParam(bctx, cbinding_contextW, &unk); 971 if(FAILED(hres)) 972 return NULL; 973 974 hres = IUnknown_QueryInterface(unk, &IID_IBinding, (void**)&binding); 975 IUnknown_Release(unk); 976 if(FAILED(hres)) 977 return NULL; 978 979 if (binding->lpVtbl != &BindingVtbl) 980 return NULL; 981 return impl_from_IBinding(binding); 982 } 983 984 static inline Binding *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface) 985 { 986 return CONTAINING_RECORD(iface, Binding, IInternetProtocolSink_iface); 987 } 988 989 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface, 990 REFIID riid, void **ppv) 991 { 992 Binding *This = impl_from_IInternetProtocolSink(iface); 993 return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv); 994 } 995 996 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface) 997 { 998 Binding *This = impl_from_IInternetProtocolSink(iface); 999 return IBinding_AddRef(&This->IBinding_iface); 1000 } 1001 1002 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface) 1003 { 1004 Binding *This = impl_from_IInternetProtocolSink(iface); 1005 return IBinding_Release(&This->IBinding_iface); 1006 } 1007 1008 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface, 1009 PROTOCOLDATA *pProtocolData) 1010 { 1011 Binding *This = impl_from_IInternetProtocolSink(iface); 1012 1013 WARN("(%p)->(%p)\n", This, pProtocolData); 1014 1015 return E_FAIL; 1016 } 1017 1018 static void on_progress(Binding *This, ULONG progress, ULONG progress_max, 1019 ULONG status_code, LPCWSTR status_text) 1020 { 1021 IBindStatusCallback_OnProgress(This->callback, progress, progress_max, 1022 status_code, status_text); 1023 } 1024 1025 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface, 1026 ULONG ulStatusCode, LPCWSTR szStatusText) 1027 { 1028 Binding *This = impl_from_IInternetProtocolSink(iface); 1029 1030 TRACE("(%p)->(%s %s)\n", This, debugstr_bindstatus(ulStatusCode), debugstr_w(szStatusText)); 1031 1032 switch(ulStatusCode) { 1033 case BINDSTATUS_FINDINGRESOURCE: 1034 on_progress(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, szStatusText); 1035 break; 1036 case BINDSTATUS_CONNECTING: 1037 on_progress(This, 0, 0, BINDSTATUS_CONNECTING, szStatusText); 1038 break; 1039 case BINDSTATUS_REDIRECTING: 1040 heap_free(This->redirect_url); 1041 This->redirect_url = heap_strdupW(szStatusText); 1042 on_progress(This, 0, 0, BINDSTATUS_REDIRECTING, szStatusText); 1043 break; 1044 case BINDSTATUS_BEGINDOWNLOADDATA: 1045 break; 1046 case BINDSTATUS_SENDINGREQUEST: 1047 on_progress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, szStatusText); 1048 break; 1049 case BINDSTATUS_PROTOCOLCLASSID: 1050 CLSIDFromString(szStatusText, &This->clsid); 1051 break; 1052 case BINDSTATUS_MIMETYPEAVAILABLE: 1053 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE: 1054 mime_available(This, szStatusText); 1055 break; 1056 case BINDSTATUS_CACHEFILENAMEAVAILABLE: 1057 cache_file_available(This, szStatusText); 1058 break; 1059 case BINDSTATUS_DECODING: 1060 IBindStatusCallback_OnProgress(This->callback, 0, 0, BINDSTATUS_DECODING, szStatusText); 1061 break; 1062 case BINDSTATUS_LOADINGMIMEHANDLER: 1063 on_progress(This, 0, 0, BINDSTATUS_LOADINGMIMEHANDLER, szStatusText); 1064 break; 1065 case BINDSTATUS_DIRECTBIND: /* FIXME: Handle BINDSTATUS_DIRECTBIND in BindProtocol */ 1066 This->report_mime = FALSE; 1067 break; 1068 case BINDSTATUS_ACCEPTRANGES: 1069 break; 1070 default: 1071 FIXME("Unhandled status code %d\n", ulStatusCode); 1072 return E_NOTIMPL; 1073 }; 1074 1075 return S_OK; 1076 } 1077 1078 static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progress_max) 1079 { 1080 FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM}; 1081 BOOL sent_begindownloaddata = FALSE; 1082 1083 TRACE("(%p)->(%d %u %u)\n", This, bscf, progress, progress_max); 1084 1085 if(This->download_state == END_DOWNLOAD || (This->state & BINDING_ABORTED)) { 1086 read_protocol_data(This->stgmed_buf); 1087 return; 1088 } 1089 1090 if(This->state & BINDING_STOPPED) 1091 return; 1092 1093 if(This->stgmed_buf->file != INVALID_HANDLE_VALUE) 1094 read_protocol_data(This->stgmed_buf); 1095 1096 if(This->download_state == BEFORE_DOWNLOAD) { 1097 This->download_state = DOWNLOADING; 1098 sent_begindownloaddata = TRUE; 1099 IBindStatusCallback_OnProgress(This->callback, progress, progress_max, 1100 BINDSTATUS_BEGINDOWNLOADDATA, This->url); 1101 1102 if(This->stgmed_buf->cache_file) 1103 IBindStatusCallback_OnProgress(This->callback, progress, progress_max, 1104 BINDSTATUS_CACHEFILENAMEAVAILABLE, This->stgmed_buf->cache_file); 1105 } 1106 1107 if(This->stgmed_buf->hres == S_FALSE || (bscf & BSCF_LASTDATANOTIFICATION)) { 1108 This->download_state = END_DOWNLOAD; 1109 IBindStatusCallback_OnProgress(This->callback, progress, progress_max, 1110 BINDSTATUS_ENDDOWNLOADDATA, This->url); 1111 }else if(!sent_begindownloaddata) { 1112 IBindStatusCallback_OnProgress(This->callback, progress, progress_max, 1113 BINDSTATUS_DOWNLOADINGDATA, This->url); 1114 } 1115 1116 if(This->state & (BINDING_STOPPED|BINDING_ABORTED)) 1117 return; 1118 1119 if(This->to_object) { 1120 if(!(This->state & BINDING_OBJAVAIL)) { 1121 IBinding_AddRef(&This->IBinding_iface); 1122 create_object(This); 1123 IBinding_Release(&This->IBinding_iface); 1124 } 1125 }else { 1126 STGMEDIUM stgmed; 1127 HRESULT hres; 1128 1129 if(!(This->state & BINDING_LOCKED)) { 1130 HRESULT hres = IInternetProtocolEx_LockRequest( 1131 &This->protocol->IInternetProtocolEx_iface, 0); 1132 if(SUCCEEDED(hres)) 1133 This->state |= BINDING_LOCKED; 1134 } 1135 1136 hres = This->stgmed_obj->vtbl->fill_stgmed(This->stgmed_obj, &stgmed); 1137 if(FAILED(hres)) { 1138 stop_binding(This, hres, NULL); 1139 return; 1140 } 1141 1142 formatetc.tymed = stgmed.tymed; 1143 formatetc.cfFormat = This->clipboard_format; 1144 1145 hres = IBindStatusCallback_OnDataAvailable(This->callback, bscf, progress, 1146 &formatetc, &stgmed); 1147 if(hres != S_OK) { 1148 if(This->download_state != END_DOWNLOAD) { 1149 This->download_state = END_DOWNLOAD; 1150 IBindStatusCallback_OnProgress(This->callback, progress, progress_max, 1151 BINDSTATUS_ENDDOWNLOADDATA, This->url); 1152 } 1153 1154 WARN("OnDataAvailable returned %x\n", hres); 1155 stop_binding(This, hres, NULL); 1156 return; 1157 } 1158 1159 if(This->download_state == END_DOWNLOAD) 1160 stop_binding(This, S_OK, NULL); 1161 } 1162 } 1163 1164 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface, 1165 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax) 1166 { 1167 Binding *This = impl_from_IInternetProtocolSink(iface); 1168 1169 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax); 1170 1171 report_data(This, grfBSCF, ulProgress, ulProgressMax); 1172 return S_OK; 1173 } 1174 1175 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface, 1176 HRESULT hrResult, DWORD dwError, LPCWSTR szResult) 1177 { 1178 Binding *This = impl_from_IInternetProtocolSink(iface); 1179 1180 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult)); 1181 1182 stop_binding(This, hrResult, szResult); 1183 1184 IInternetProtocolEx_Terminate(&This->protocol->IInternetProtocolEx_iface, 0); 1185 return S_OK; 1186 } 1187 1188 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = { 1189 InternetProtocolSink_QueryInterface, 1190 InternetProtocolSink_AddRef, 1191 InternetProtocolSink_Release, 1192 InternetProtocolSink_Switch, 1193 InternetProtocolSink_ReportProgress, 1194 InternetProtocolSink_ReportData, 1195 InternetProtocolSink_ReportResult 1196 }; 1197 1198 static inline Binding *impl_from_IInternetBindInfo(IInternetBindInfo *iface) 1199 { 1200 return CONTAINING_RECORD(iface, Binding, IInternetBindInfo_iface); 1201 } 1202 1203 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface, 1204 REFIID riid, void **ppv) 1205 { 1206 Binding *This = impl_from_IInternetBindInfo(iface); 1207 return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv); 1208 } 1209 1210 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface) 1211 { 1212 Binding *This = impl_from_IInternetBindInfo(iface); 1213 return IBinding_AddRef(&This->IBinding_iface); 1214 } 1215 1216 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface) 1217 { 1218 Binding *This = impl_from_IInternetBindInfo(iface); 1219 return IBinding_Release(&This->IBinding_iface); 1220 } 1221 1222 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface, 1223 DWORD *grfBINDF, BINDINFO *pbindinfo) 1224 { 1225 Binding *This = impl_from_IInternetBindInfo(iface); 1226 1227 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo); 1228 1229 *grfBINDF = This->bindf; 1230 return CopyBindInfo(&This->bindinfo, pbindinfo); 1231 } 1232 1233 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface, 1234 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched) 1235 { 1236 Binding *This = impl_from_IInternetBindInfo(iface); 1237 1238 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched); 1239 1240 switch(ulStringType) { 1241 case BINDSTRING_ACCEPT_MIMES: { 1242 static const WCHAR wszMimes[] = {'*','/','*',0}; 1243 1244 if(!ppwzStr || !pcElFetched) 1245 return E_INVALIDARG; 1246 1247 ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes)); 1248 memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes)); 1249 *pcElFetched = 1; 1250 return S_OK; 1251 } 1252 case BINDSTRING_USER_AGENT: { 1253 IInternetBindInfo *bindinfo = NULL; 1254 HRESULT hres; 1255 1256 hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo, 1257 (void**)&bindinfo); 1258 if(FAILED(hres)) 1259 return hres; 1260 1261 hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr, 1262 cEl, pcElFetched); 1263 IInternetBindInfo_Release(bindinfo); 1264 1265 return hres; 1266 } 1267 case BINDSTRING_URL: { 1268 DWORD size = (SysStringLen(This->url)+1) * sizeof(WCHAR); 1269 1270 if(!ppwzStr || !pcElFetched) 1271 return E_INVALIDARG; 1272 1273 *ppwzStr = CoTaskMemAlloc(size); 1274 memcpy(*ppwzStr, This->url, size); 1275 *pcElFetched = 1; 1276 return S_OK; 1277 } 1278 } 1279 1280 FIXME("not supported string type %d\n", ulStringType); 1281 return E_NOTIMPL; 1282 } 1283 1284 static const IInternetBindInfoVtbl InternetBindInfoVtbl = { 1285 InternetBindInfo_QueryInterface, 1286 InternetBindInfo_AddRef, 1287 InternetBindInfo_Release, 1288 InternetBindInfo_GetBindInfo, 1289 InternetBindInfo_GetBindString 1290 }; 1291 1292 static inline Binding *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface) 1293 { 1294 return CONTAINING_RECORD(iface, Binding, IWinInetHttpInfo_iface); 1295 } 1296 1297 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv) 1298 { 1299 Binding *This = impl_from_IWinInetHttpInfo(iface); 1300 return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv); 1301 } 1302 1303 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface) 1304 { 1305 Binding *This = impl_from_IWinInetHttpInfo(iface); 1306 return IBinding_AddRef(&This->IBinding_iface); 1307 } 1308 1309 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface) 1310 { 1311 Binding *This = impl_from_IWinInetHttpInfo(iface); 1312 return IBinding_Release(&This->IBinding_iface); 1313 } 1314 1315 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption, 1316 void *pBuffer, DWORD *pcbBuffer) 1317 { 1318 Binding *This = impl_from_IWinInetHttpInfo(iface); 1319 IWinInetInfo *wininet_info; 1320 HRESULT hres; 1321 1322 TRACE("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer); 1323 1324 hres = IInternetProtocolEx_QueryInterface(&This->protocol->IInternetProtocolEx_iface, 1325 &IID_IWinInetInfo, (void**)&wininet_info); 1326 if(FAILED(hres)) 1327 return E_FAIL; 1328 1329 hres = IWinInetInfo_QueryOption(wininet_info, dwOption, pBuffer, pcbBuffer); 1330 IWinInetInfo_Release(wininet_info); 1331 return hres; 1332 } 1333 1334 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption, 1335 void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved) 1336 { 1337 Binding *This = impl_from_IWinInetHttpInfo(iface); 1338 IWinInetHttpInfo *http_info; 1339 HRESULT hres; 1340 1341 TRACE("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved); 1342 1343 hres = IInternetProtocolEx_QueryInterface(&This->protocol->IInternetProtocolEx_iface, 1344 &IID_IWinInetHttpInfo, (void**)&http_info); 1345 if(FAILED(hres)) 1346 return E_FAIL; 1347 1348 hres = IWinInetHttpInfo_QueryInfo(http_info, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved); 1349 IWinInetHttpInfo_Release(http_info); 1350 return hres; 1351 } 1352 1353 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = { 1354 WinInetHttpInfo_QueryInterface, 1355 WinInetHttpInfo_AddRef, 1356 WinInetHttpInfo_Release, 1357 WinInetHttpInfo_QueryOption, 1358 WinInetHttpInfo_QueryInfo 1359 }; 1360 1361 static inline Binding *impl_from_IServiceProvider(IServiceProvider *iface) 1362 { 1363 return CONTAINING_RECORD(iface, Binding, IServiceProvider_iface); 1364 } 1365 1366 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, 1367 REFIID riid, void **ppv) 1368 { 1369 Binding *This = impl_from_IServiceProvider(iface); 1370 return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv); 1371 } 1372 1373 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface) 1374 { 1375 Binding *This = impl_from_IServiceProvider(iface); 1376 return IBinding_AddRef(&This->IBinding_iface); 1377 } 1378 1379 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface) 1380 { 1381 Binding *This = impl_from_IServiceProvider(iface); 1382 return IBinding_Release(&This->IBinding_iface); 1383 } 1384 1385 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, 1386 REFGUID guidService, REFIID riid, void **ppv) 1387 { 1388 Binding *This = impl_from_IServiceProvider(iface); 1389 HRESULT hres; 1390 1391 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); 1392 1393 if(This->service_provider) { 1394 hres = IServiceProvider_QueryService(This->service_provider, guidService, 1395 riid, ppv); 1396 if(SUCCEEDED(hres)) 1397 return hres; 1398 } 1399 1400 WARN("unknown service %s\n", debugstr_guid(guidService)); 1401 return E_NOINTERFACE; 1402 } 1403 1404 static const IServiceProviderVtbl ServiceProviderVtbl = { 1405 ServiceProvider_QueryInterface, 1406 ServiceProvider_AddRef, 1407 ServiceProvider_Release, 1408 ServiceProvider_QueryService 1409 }; 1410 1411 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback) 1412 { 1413 IUnknown *unk; 1414 HRESULT hres; 1415 1416 hres = IBindCtx_GetObjectParam(pbc, bscb_holderW, &unk); 1417 if(FAILED(hres)) 1418 return create_default_callback(callback); 1419 1420 hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)callback); 1421 IUnknown_Release(unk); 1422 return hres; 1423 } 1424 1425 static BOOL is_urlmon_protocol(IUri *uri) 1426 { 1427 DWORD scheme; 1428 HRESULT hres; 1429 1430 hres = IUri_GetScheme(uri, &scheme); 1431 if(FAILED(hres)) 1432 return FALSE; 1433 1434 switch(scheme) { 1435 case URL_SCHEME_FILE: 1436 case URL_SCHEME_FTP: 1437 case URL_SCHEME_GOPHER: 1438 case URL_SCHEME_HTTP: 1439 case URL_SCHEME_HTTPS: 1440 case URL_SCHEME_MK: 1441 return TRUE; 1442 } 1443 1444 return FALSE; 1445 } 1446 1447 static HRESULT Binding_Create(IMoniker *mon, Binding *binding_ctx, IUri *uri, IBindCtx *pbc, 1448 BOOL to_obj, REFIID riid, Binding **binding) 1449 { 1450 Binding *ret; 1451 HRESULT hres; 1452 1453 URLMON_LockModule(); 1454 1455 ret = heap_alloc_zero(sizeof(Binding)); 1456 1457 ret->IBinding_iface.lpVtbl = &BindingVtbl; 1458 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl; 1459 ret->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl; 1460 ret->IWinInetHttpInfo_iface.lpVtbl = &WinInetHttpInfoVtbl; 1461 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; 1462 1463 ret->ref = 1; 1464 1465 ret->to_object = to_obj; 1466 ret->iid = *riid; 1467 ret->notif_hwnd = get_notif_hwnd(); 1468 ret->report_mime = !binding_ctx; 1469 ret->download_state = BEFORE_DOWNLOAD; 1470 1471 if(to_obj) { 1472 IBindCtx_AddRef(pbc); 1473 ret->bctx = pbc; 1474 } 1475 1476 if(mon) { 1477 IMoniker_AddRef(mon); 1478 ret->mon = mon; 1479 } 1480 1481 ret->bindinfo.cbSize = sizeof(BINDINFO); 1482 1483 InitializeCriticalSection(&ret->section); 1484 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Binding.section"); 1485 1486 hres = get_callback(pbc, &ret->callback); 1487 if(FAILED(hres)) { 1488 WARN("Could not get IBindStatusCallback\n"); 1489 IBinding_Release(&ret->IBinding_iface); 1490 return hres; 1491 } 1492 1493 IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider, 1494 (void**)&ret->service_provider); 1495 1496 if(binding_ctx) { 1497 ret->protocol = binding_ctx->protocol; 1498 IInternetProtocolEx_AddRef(&ret->protocol->IInternetProtocolEx_iface); 1499 }else { 1500 hres = create_binding_protocol(&ret->protocol); 1501 if(FAILED(hres)) { 1502 WARN("Could not get protocol handler\n"); 1503 IBinding_Release(&ret->IBinding_iface); 1504 return hres; 1505 } 1506 } 1507 1508 hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo); 1509 if(FAILED(hres)) { 1510 WARN("GetBindInfo failed: %08x\n", hres); 1511 IBinding_Release(&ret->IBinding_iface); 1512 return hres; 1513 } 1514 1515 TRACE("bindf %08x\n", ret->bindf); 1516 dump_BINDINFO(&ret->bindinfo); 1517 1518 ret->bindf |= BINDF_FROMURLMON; 1519 if(to_obj) 1520 ret->bindinfo.dwOptions |= 0x100000; 1521 1522 if(!(ret->bindf & BINDF_ASYNCHRONOUS) || !(ret->bindf & BINDF_PULLDATA)) { 1523 ret->bindf |= BINDF_NEEDFILE; 1524 ret->use_cache_file = TRUE; 1525 }else if(!is_urlmon_protocol(uri)) { 1526 ret->bindf |= BINDF_NEEDFILE; 1527 } 1528 1529 hres = IUri_GetDisplayUri(uri, &ret->url); 1530 if(FAILED(hres)) { 1531 IBinding_Release(&ret->IBinding_iface); 1532 return hres; 1533 } 1534 1535 if(binding_ctx) { 1536 ret->stgmed_buf = binding_ctx->stgmed_buf; 1537 IUnknown_AddRef(&ret->stgmed_buf->IUnknown_iface); 1538 ret->clipboard_format = binding_ctx->clipboard_format; 1539 }else { 1540 ret->stgmed_buf = create_stgmed_buf(&ret->protocol->IInternetProtocolEx_iface); 1541 } 1542 1543 if(to_obj) { 1544 ret->stgmed_obj = NULL; 1545 }else if(IsEqualGUID(&IID_IStream, riid)) { 1546 ret->stgmed_obj = create_stgmed_stream(ret->stgmed_buf); 1547 }else if(IsEqualGUID(&IID_IUnknown, riid)) { 1548 ret->bindf |= BINDF_NEEDFILE; 1549 ret->stgmed_obj = create_stgmed_file(ret->stgmed_buf); 1550 }else { 1551 FIXME("Unsupported riid %s\n", debugstr_guid(riid)); 1552 IBinding_Release(&ret->IBinding_iface); 1553 return E_NOTIMPL; 1554 } 1555 1556 *binding = ret; 1557 return S_OK; 1558 } 1559 1560 static HRESULT start_binding(IMoniker *mon, Binding *binding_ctx, IUri *uri, IBindCtx *pbc, 1561 BOOL to_obj, REFIID riid, Binding **ret) 1562 { 1563 Binding *binding = NULL; 1564 HRESULT hres; 1565 MSG msg; 1566 1567 hres = Binding_Create(mon, binding_ctx, uri, pbc, to_obj, riid, &binding); 1568 if(FAILED(hres)) 1569 return hres; 1570 1571 hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, &binding->IBinding_iface); 1572 if(FAILED(hres)) { 1573 WARN("OnStartBinding failed: %08x\n", hres); 1574 if(hres != E_ABORT && hres != E_NOTIMPL) 1575 hres = INET_E_DOWNLOAD_FAILURE; 1576 1577 stop_binding(binding, hres, NULL); 1578 IBinding_Release(&binding->IBinding_iface); 1579 return hres; 1580 } 1581 1582 if(binding_ctx) { 1583 set_binding_sink(binding->protocol, &binding->IInternetProtocolSink_iface, 1584 &binding->IInternetBindInfo_iface); 1585 if(binding_ctx->redirect_url) 1586 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_REDIRECTING, binding_ctx->redirect_url); 1587 report_data(binding, BSCF_FIRSTDATANOTIFICATION | (binding_ctx->download_state == END_DOWNLOAD ? BSCF_LASTDATANOTIFICATION : 0), 1588 0, 0); 1589 }else { 1590 hres = IInternetProtocolEx_StartEx(&binding->protocol->IInternetProtocolEx_iface, uri, 1591 &binding->IInternetProtocolSink_iface, &binding->IInternetBindInfo_iface, 1592 PI_APARTMENTTHREADED|PI_MIMEVERIFICATION, 0); 1593 1594 TRACE("start ret %08x\n", hres); 1595 1596 if(FAILED(hres) && hres != E_PENDING) { 1597 stop_binding(binding, hres, NULL); 1598 IBinding_Release(&binding->IBinding_iface); 1599 1600 return hres; 1601 } 1602 } 1603 1604 while(!(binding->bindf & BINDF_ASYNCHRONOUS) && 1605 !(binding->state & BINDING_STOPPED)) { 1606 MsgWaitForMultipleObjects(0, NULL, FALSE, 5000, QS_POSTMESSAGE); 1607 while (PeekMessageW(&msg, binding->notif_hwnd, WM_USER, WM_USER+117, PM_REMOVE|PM_NOYIELD)) { 1608 TranslateMessage(&msg); 1609 DispatchMessageW(&msg); 1610 } 1611 } 1612 1613 *ret = binding; 1614 return S_OK; 1615 } 1616 1617 HRESULT bind_to_storage(IUri *uri, IBindCtx *pbc, REFIID riid, void **ppv) 1618 { 1619 Binding *binding = NULL, *binding_ctx; 1620 HRESULT hres; 1621 1622 binding_ctx = get_bctx_binding(pbc); 1623 1624 hres = start_binding(NULL, binding_ctx, uri, pbc, FALSE, riid, &binding); 1625 if(binding_ctx) 1626 IBinding_Release(&binding_ctx->IBinding_iface); 1627 if(FAILED(hres)) 1628 return hres; 1629 1630 if(binding->hres == S_OK && binding->download_state != BEFORE_DOWNLOAD /* FIXME */) { 1631 if((binding->state & BINDING_STOPPED) && (binding->state & BINDING_LOCKED)) 1632 IInternetProtocolEx_UnlockRequest(&binding->protocol->IInternetProtocolEx_iface); 1633 1634 hres = binding->stgmed_obj->vtbl->get_result(binding->stgmed_obj, binding->bindf, ppv); 1635 }else if(binding->bindf & BINDF_ASYNCHRONOUS) { 1636 hres = MK_S_ASYNCHRONOUS; 1637 }else { 1638 hres = FAILED(binding->hres) ? binding->hres : S_OK; 1639 } 1640 1641 IBinding_Release(&binding->IBinding_iface); 1642 1643 return hres; 1644 } 1645 1646 HRESULT bind_to_object(IMoniker *mon, IUri *uri, IBindCtx *pbc, REFIID riid, void **ppv) 1647 { 1648 Binding *binding; 1649 HRESULT hres; 1650 1651 *ppv = NULL; 1652 1653 hres = start_binding(mon, NULL, uri, pbc, TRUE, riid, &binding); 1654 if(FAILED(hres)) 1655 return hres; 1656 1657 if(binding->hres != S_OK) { 1658 hres = SUCCEEDED(binding->hres) ? S_OK : binding->hres; 1659 }else if(binding->bindf & BINDF_ASYNCHRONOUS) { 1660 hres = MK_S_ASYNCHRONOUS; 1661 }else { 1662 *ppv = binding->obj; 1663 IUnknown_AddRef(binding->obj); 1664 hres = S_OK; 1665 } 1666 1667 IBinding_Release(&binding->IBinding_iface); 1668 1669 return hres; 1670 } 1671