1 /* 2 * Copyright 2007-2009 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 #include "wine/debug.h" 21 22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon); 23 24 typedef void (*task_proc_t)(BindProtocol*,task_header_t*); 25 26 struct _task_header_t { 27 task_proc_t proc; 28 task_header_t *next; 29 }; 30 31 #define BUFFER_SIZE 2048 32 #define MIME_TEST_SIZE 255 33 34 #define WM_MK_CONTINUE (WM_USER+101) 35 #define WM_MK_RELEASE (WM_USER+102) 36 37 static void process_tasks(BindProtocol *This) 38 { 39 task_header_t *task; 40 41 while(1) { 42 EnterCriticalSection(&This->section); 43 44 task = This->task_queue_head; 45 if(task) { 46 This->task_queue_head = task->next; 47 if(!This->task_queue_head) 48 This->task_queue_tail = NULL; 49 } 50 51 LeaveCriticalSection(&This->section); 52 53 if(!task) 54 break; 55 56 This->continue_call++; 57 task->proc(This, task); 58 This->continue_call--; 59 } 60 } 61 62 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 63 { 64 switch(msg) { 65 case WM_MK_CONTINUE: { 66 BindProtocol *This = (BindProtocol*)lParam; 67 68 process_tasks(This); 69 70 IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 71 return 0; 72 } 73 case WM_MK_RELEASE: { 74 tls_data_t *data = get_tls_data(); 75 76 if(!--data->notif_hwnd_cnt) { 77 DestroyWindow(hwnd); 78 data->notif_hwnd = NULL; 79 } 80 } 81 } 82 83 return DefWindowProcW(hwnd, msg, wParam, lParam); 84 } 85 86 static const WCHAR wszURLMonikerNotificationWindow[] = 87 {'U','R','L',' ','M','o','n','i','k','e','r',' ', 88 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0}; 89 90 static ATOM notif_wnd_class; 91 92 static BOOL WINAPI register_notif_wnd_class(INIT_ONCE *once, void *param, void **context) 93 { 94 static WNDCLASSEXW wndclass = { 95 sizeof(wndclass), 0, notif_wnd_proc, 0, 0, 96 NULL, NULL, NULL, NULL, NULL, 97 wszURLMonikerNotificationWindow, NULL 98 }; 99 100 wndclass.hInstance = hProxyDll; 101 notif_wnd_class = RegisterClassExW(&wndclass); 102 return TRUE; 103 } 104 105 void unregister_notif_wnd_class(void) 106 { 107 if(notif_wnd_class) 108 UnregisterClassW(MAKEINTRESOURCEW(notif_wnd_class), hProxyDll); 109 } 110 111 HWND get_notif_hwnd(void) 112 { 113 tls_data_t *tls_data; 114 115 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; 116 117 tls_data = get_tls_data(); 118 if(!tls_data) 119 return NULL; 120 121 if(tls_data->notif_hwnd_cnt) { 122 tls_data->notif_hwnd_cnt++; 123 return tls_data->notif_hwnd; 124 } 125 126 InitOnceExecuteOnce(&init_once, register_notif_wnd_class, NULL, NULL); 127 if(!notif_wnd_class) 128 return NULL; 129 130 tls_data->notif_hwnd = CreateWindowExW(0, MAKEINTRESOURCEW(notif_wnd_class), 131 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE, 132 NULL, hProxyDll, NULL); 133 if(tls_data->notif_hwnd) 134 tls_data->notif_hwnd_cnt++; 135 136 TRACE("hwnd = %p\n", tls_data->notif_hwnd); 137 138 return tls_data->notif_hwnd; 139 } 140 141 void release_notif_hwnd(HWND hwnd) 142 { 143 tls_data_t *data = get_tls_data(); 144 145 if(!data) 146 return; 147 148 if(data->notif_hwnd != hwnd) { 149 PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0); 150 return; 151 } 152 153 if(!--data->notif_hwnd_cnt) { 154 DestroyWindow(data->notif_hwnd); 155 data->notif_hwnd = NULL; 156 } 157 } 158 159 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc) 160 { 161 BOOL do_post = FALSE; 162 163 task->proc = proc; 164 task->next = NULL; 165 166 EnterCriticalSection(&This->section); 167 168 if(This->task_queue_tail) { 169 This->task_queue_tail->next = task; 170 This->task_queue_tail = task; 171 }else { 172 This->task_queue_tail = This->task_queue_head = task; 173 do_post = !This->continue_call; 174 } 175 176 LeaveCriticalSection(&This->section); 177 178 if(do_post) { 179 IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 180 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This); 181 } 182 } 183 184 static inline BOOL is_apartment_thread(BindProtocol *This) 185 { 186 return This->apartment_thread == GetCurrentThreadId(); 187 } 188 189 static inline BOOL do_direct_notif(BindProtocol *This) 190 { 191 return !(This->pi & PI_APARTMENTTHREADED) || (is_apartment_thread(This) && !This->continue_call); 192 } 193 194 static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter) 195 { 196 PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 }; 197 HRESULT hres; 198 199 hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&This->protocol_sink_handler); 200 if(FAILED(hres)) { 201 This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface; 202 return hres; 203 } 204 205 IInternetProtocol_AddRef(mime_filter); 206 This->protocol_handler = mime_filter; 207 208 filter_data.pProtocol = &This->default_protocol_handler.IInternetProtocol_iface; 209 hres = IInternetProtocol_Start(mime_filter, This->mime, &This->default_protocol_handler.IInternetProtocolSink_iface, 210 &This->IInternetBindInfo_iface, PI_FILTER_MODE|PI_FORCE_ASYNC, 211 (HANDLE_PTR)&filter_data); 212 if(FAILED(hres)) { 213 IInternetProtocolSink_Release(This->protocol_sink_handler); 214 IInternetProtocol_Release(This->protocol_handler); 215 This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface; 216 This->protocol_handler = &This->default_protocol_handler.IInternetProtocol_iface; 217 return hres; 218 } 219 220 /* NOTE: IE9 calls it on the new protocol_sink. It doesn't make sense so it seems to be a bug there. */ 221 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL); 222 223 return S_OK; 224 } 225 226 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified) 227 { 228 IInternetProtocol *mime_filter; 229 HRESULT hres; 230 231 heap_free(This->mime); 232 This->mime = heap_strdupW(mime); 233 234 if(This->protocol_handler==&This->default_protocol_handler.IInternetProtocol_iface 235 && (mime_filter = get_mime_filter(mime))) { 236 TRACE("Got mime filter for %s\n", debugstr_w(mime)); 237 238 hres = handle_mime_filter(This, mime_filter); 239 IInternetProtocol_Release(mime_filter); 240 if(FAILED(hres)) 241 FIXME("MIME filter failed: %08x\n", hres); 242 } 243 244 if(This->reported_mime || verified || !(This->pi & PI_MIMEVERIFICATION)) { 245 This->reported_mime = TRUE; 246 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime); 247 } 248 } 249 250 static inline BindProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface) 251 { 252 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolEx_iface); 253 } 254 255 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv) 256 { 257 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 258 259 *ppv = NULL; 260 if(IsEqualGUID(&IID_IUnknown, riid)) { 261 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 262 *ppv = &This->IInternetProtocolEx_iface; 263 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) { 264 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv); 265 *ppv = &This->IInternetProtocolEx_iface; 266 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) { 267 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv); 268 *ppv = &This->IInternetProtocolEx_iface; 269 }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) { 270 TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv); 271 *ppv = &This->IInternetProtocolEx_iface; 272 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) { 273 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv); 274 *ppv = &This->IInternetBindInfo_iface; 275 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) { 276 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv); 277 *ppv = &This->IInternetPriority_iface; 278 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) { 279 FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv); 280 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) { 281 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv); 282 *ppv = &This->IServiceProvider_iface; 283 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) { 284 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv); 285 *ppv = &This->IInternetProtocolSink_iface; 286 }else if(This->protocol_unk) { 287 HRESULT hres; 288 hres = IUnknown_QueryInterface(This->protocol_unk, riid, ppv); 289 TRACE("(%p) aggregated handler returned %08x for %s\n", This, hres, debugstr_guid(riid)); 290 return hres; 291 }else { 292 WARN("not supported interface %s\n", debugstr_guid(riid)); 293 } 294 295 if(!*ppv) 296 return E_NOINTERFACE; 297 298 IUnknown_AddRef((IUnknown*)*ppv); 299 return S_OK; 300 } 301 302 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocolEx *iface) 303 { 304 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 305 LONG ref = InterlockedIncrement(&This->ref); 306 TRACE("(%p) ref=%d\n", This, ref); 307 return ref; 308 } 309 310 static void release_protocol_handler(BindProtocol *This) 311 { 312 if(This->protocol) { 313 IInternetProtocol_Release(This->protocol); 314 This->protocol = NULL; 315 } 316 if(This->protocol_handler && This->protocol_handler != &This->default_protocol_handler.IInternetProtocol_iface) { 317 IInternetProtocol_Release(This->protocol_handler); 318 This->protocol_handler = &This->default_protocol_handler.IInternetProtocol_iface; 319 } 320 if(This->protocol_sink_handler && 321 This->protocol_sink_handler != &This->default_protocol_handler.IInternetProtocolSink_iface) { 322 IInternetProtocolSink_Release(This->protocol_sink_handler); 323 This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface; 324 } 325 if(This->protocol_unk) { 326 IUnknown_Release(This->protocol_unk); 327 This->protocol_unk = NULL; 328 } 329 } 330 331 static ULONG WINAPI BindProtocol_Release(IInternetProtocolEx *iface) 332 { 333 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 334 LONG ref = InterlockedDecrement(&This->ref); 335 336 TRACE("(%p) ref=%d\n", This, ref); 337 338 if(!ref) { 339 release_protocol_handler(This); 340 if(This->redirect_callback) 341 IBindCallbackRedirect_Release(This->redirect_callback); 342 if(This->bind_info) 343 IInternetBindInfo_Release(This->bind_info); 344 if(This->uri) 345 IUri_Release(This->uri); 346 SysFreeString(This->display_uri); 347 348 set_binding_sink(This, NULL, NULL); 349 350 if(This->notif_hwnd) 351 release_notif_hwnd(This->notif_hwnd); 352 This->section.DebugInfo->Spare[0] = 0; 353 DeleteCriticalSection(&This->section); 354 355 heap_free(This->mime); 356 heap_free(This); 357 358 URLMON_UnlockModule(); 359 } 360 361 return ref; 362 } 363 364 static HRESULT WINAPI BindProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl, 365 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, 366 DWORD grfPI, HANDLE_PTR dwReserved) 367 { 368 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 369 IUri *uri; 370 HRESULT hres; 371 372 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink, 373 pOIBindInfo, grfPI, dwReserved); 374 375 hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri); 376 if(FAILED(hres)) 377 return hres; 378 379 hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink, 380 pOIBindInfo, grfPI, (HANDLE*)dwReserved); 381 382 IUri_Release(uri); 383 return hres; 384 } 385 386 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData) 387 { 388 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 389 390 TRACE("(%p)->(%p)\n", This, pProtocolData); 391 392 return IInternetProtocol_Continue(This->protocol_handler, pProtocolData); 393 } 394 395 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason, 396 DWORD dwOptions) 397 { 398 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 399 400 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); 401 402 return IInternetProtocol_Abort(This->protocol_handler, hrReason, dwOptions); 403 } 404 405 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions) 406 { 407 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 408 409 TRACE("(%p)->(%08x)\n", This, dwOptions); 410 411 return IInternetProtocol_Terminate(This->protocol_handler, dwOptions); 412 } 413 414 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocolEx *iface) 415 { 416 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 417 FIXME("(%p)\n", This); 418 return E_NOTIMPL; 419 } 420 421 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocolEx *iface) 422 { 423 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 424 FIXME("(%p)\n", This); 425 return E_NOTIMPL; 426 } 427 428 static HRESULT WINAPI BindProtocol_Read(IInternetProtocolEx *iface, void *pv, 429 ULONG cb, ULONG *pcbRead) 430 { 431 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 432 433 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); 434 435 if(pcbRead) 436 *pcbRead = 0; 437 return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead); 438 } 439 440 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove, 441 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 442 { 443 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 444 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); 445 return E_NOTIMPL; 446 } 447 448 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions) 449 { 450 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 451 452 TRACE("(%p)->(%08x)\n", This, dwOptions); 453 454 return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions); 455 } 456 457 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocolEx *iface) 458 { 459 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 460 461 TRACE("(%p)\n", This); 462 463 return IInternetProtocol_UnlockRequest(This->protocol_handler); 464 } 465 466 static HRESULT WINAPI BindProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri, 467 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, 468 DWORD grfPI, HANDLE *dwReserved) 469 { 470 BindProtocol *This = impl_from_IInternetProtocolEx(iface); 471 IInternetProtocol *protocol = NULL; 472 IInternetProtocolEx *protocolex; 473 IInternetPriority *priority; 474 IServiceProvider *service_provider; 475 CLSID clsid = IID_NULL; 476 IUnknown *protocol_unk = NULL; 477 LPOLESTR clsid_str; 478 HRESULT hres; 479 480 TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink, pOIBindInfo, grfPI, dwReserved); 481 482 if(!pUri || !pOIProtSink || !pOIBindInfo) 483 return E_INVALIDARG; 484 485 This->pi = grfPI; 486 487 if(This->uri) { 488 SysFreeString(This->display_uri); 489 IUri_Release(This->uri); 490 } 491 IUri_AddRef(pUri); 492 This->uri = pUri; 493 494 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider, 495 (void**)&service_provider); 496 if(SUCCEEDED(hres)) { 497 /* FIXME: What's protocol CLSID here? */ 498 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol, 499 &IID_IInternetProtocol, (void**)&protocol); 500 IServiceProvider_Release(service_provider); 501 } 502 503 if(!protocol) { 504 IClassFactory *cf; 505 506 hres = get_protocol_handler(pUri, &clsid, &cf); 507 if(FAILED(hres)) 508 return hres; 509 510 hres = IClassFactory_CreateInstance(cf, (IUnknown*)&This->IInternetBindInfo_iface, 511 &IID_IUnknown, (void**)&protocol_unk); 512 if(SUCCEEDED(hres)) { 513 hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetProtocol, (void**)&protocol); 514 if(SUCCEEDED(hres)) 515 This->protocol_unk = protocol_unk; 516 else 517 IUnknown_Release(protocol_unk); 518 } 519 else if(hres == CLASS_E_NOAGGREGATION) 520 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol); 521 522 IClassFactory_Release(cf); 523 if(FAILED(hres)) 524 return hres; 525 } 526 527 StringFromCLSID(&clsid, &clsid_str); 528 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str); 529 CoTaskMemFree(clsid_str); 530 531 This->protocol_unk = protocol_unk; 532 This->protocol = protocol; 533 534 if(!protocol_unk) 535 protocol_unk = (IUnknown*)protocol; 536 537 set_binding_sink(This, pOIProtSink, pOIBindInfo); 538 539 hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetPriority, (void**)&priority); 540 if(SUCCEEDED(hres)) { 541 IInternetPriority_SetPriority(priority, This->priority); 542 IInternetPriority_Release(priority); 543 } 544 545 hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetProtocolEx, (void**)&protocolex); 546 if(SUCCEEDED(hres)) { 547 hres = IInternetProtocolEx_StartEx(protocolex, pUri, &This->IInternetProtocolSink_iface, 548 &This->IInternetBindInfo_iface, 0, NULL); 549 IInternetProtocolEx_Release(protocolex); 550 }else { 551 hres = IUri_GetDisplayUri(pUri, &This->display_uri); 552 if(FAILED(hres)) 553 return hres; 554 555 hres = IInternetProtocol_Start(protocol, This->display_uri, &This->IInternetProtocolSink_iface, 556 &This->IInternetBindInfo_iface, 0, 0); 557 } 558 559 if(SUCCEEDED(hres)) 560 process_tasks(This); 561 return hres; 562 } 563 564 void set_binding_sink(BindProtocol *This, IInternetProtocolSink *sink, IInternetBindInfo *bind_info) 565 { 566 IInternetProtocolSink *prev_sink; 567 IServiceProvider *service_provider = NULL; 568 569 if(sink) 570 IInternetProtocolSink_AddRef(sink); 571 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink); 572 if(prev_sink) 573 IInternetProtocolSink_Release(prev_sink); 574 575 if(sink) 576 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider); 577 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider); 578 if(service_provider) 579 IServiceProvider_Release(service_provider); 580 581 if(bind_info) 582 IInternetBindInfo_AddRef(bind_info); 583 bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info); 584 if(bind_info) 585 IInternetBindInfo_Release(bind_info); 586 } 587 588 static const IInternetProtocolExVtbl BindProtocolVtbl = { 589 BindProtocol_QueryInterface, 590 BindProtocol_AddRef, 591 BindProtocol_Release, 592 BindProtocol_Start, 593 BindProtocol_Continue, 594 BindProtocol_Abort, 595 BindProtocol_Terminate, 596 BindProtocol_Suspend, 597 BindProtocol_Resume, 598 BindProtocol_Read, 599 BindProtocol_Seek, 600 BindProtocol_LockRequest, 601 BindProtocol_UnlockRequest, 602 BindProtocol_StartEx 603 }; 604 605 static inline BindProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface) 606 { 607 return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocol_iface); 608 } 609 610 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) 611 { 612 BindProtocol *This = impl_from_IInternetProtocol(iface); 613 614 *ppv = NULL; 615 if(IsEqualGUID(&IID_IUnknown, riid)) { 616 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 617 *ppv = &This->default_protocol_handler.IInternetProtocol_iface; 618 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) { 619 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv); 620 *ppv = &This->default_protocol_handler.IInternetProtocol_iface; 621 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) { 622 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv); 623 *ppv = &This->default_protocol_handler.IInternetProtocol_iface; 624 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) { 625 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv); 626 *ppv = &This->default_protocol_handler.IInternetProtocolSink_iface; 627 } 628 629 if(*ppv) { 630 IInternetProtocol_AddRef(iface); 631 return S_OK; 632 } 633 634 WARN("not supported interface %s\n", debugstr_guid(riid)); 635 return E_NOINTERFACE; 636 } 637 638 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface) 639 { 640 BindProtocol *This = impl_from_IInternetProtocol(iface); 641 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 642 } 643 644 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface) 645 { 646 BindProtocol *This = impl_from_IInternetProtocol(iface); 647 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 648 } 649 650 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl, 651 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, 652 DWORD grfPI, HANDLE_PTR dwReserved) 653 { 654 ERR("Should not be called\n"); 655 return E_NOTIMPL; 656 } 657 658 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData) 659 { 660 BindProtocol *This = impl_from_IInternetProtocol(iface); 661 IInternetProtocol *protocol = NULL; 662 HRESULT hres; 663 664 TRACE("(%p)->(%p)\n", This, pProtocolData); 665 666 /* FIXME: This should not be needed. */ 667 if(!This->protocol) { 668 if(!This->protocol_unk) 669 return E_FAIL; 670 hres = IUnknown_QueryInterface(This->protocol_unk, &IID_IInternetProtocol, (void**)&protocol); 671 if(FAILED(hres)) 672 return E_FAIL; 673 } 674 675 hres = IInternetProtocol_Continue(protocol ? protocol : This->protocol, pProtocolData); 676 677 heap_free(pProtocolData); 678 if(protocol) 679 IInternetProtocol_Release(protocol); 680 return hres; 681 } 682 683 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason, 684 DWORD dwOptions) 685 { 686 BindProtocol *This = impl_from_IInternetProtocol(iface); 687 688 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); 689 690 if(This->protocol && !This->reported_result) 691 return IInternetProtocol_Abort(This->protocol, hrReason, dwOptions); 692 693 return S_OK; 694 } 695 696 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions) 697 { 698 BindProtocol *This = impl_from_IInternetProtocol(iface); 699 700 TRACE("(%p)->(%08x)\n", This, dwOptions); 701 702 if(!This->reported_result) 703 return E_FAIL; 704 705 /* This may get released in Terminate call. */ 706 IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 707 708 if(This->protocol) { 709 IInternetProtocol_Terminate(This->protocol, 0); 710 711 if (This->protocol_unk) { 712 IInternetProtocol_Release(This->protocol); 713 This->protocol = NULL; 714 } 715 } 716 717 set_binding_sink(This, NULL, NULL); 718 719 if(This->bind_info) { 720 IInternetBindInfo_Release(This->bind_info); 721 This->bind_info = NULL; 722 } 723 724 if(This->redirect_callback) { 725 IBindCallbackRedirect_Release(This->redirect_callback); 726 This->redirect_callback = NULL; 727 } 728 729 IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 730 return S_OK; 731 } 732 733 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface) 734 { 735 BindProtocol *This = impl_from_IInternetProtocol(iface); 736 FIXME("(%p)\n", This); 737 return E_NOTIMPL; 738 } 739 740 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface) 741 { 742 BindProtocol *This = impl_from_IInternetProtocol(iface); 743 FIXME("(%p)\n", This); 744 return E_NOTIMPL; 745 } 746 747 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv, 748 ULONG cb, ULONG *pcbRead) 749 { 750 BindProtocol *This = impl_from_IInternetProtocol(iface); 751 ULONG read = 0; 752 HRESULT hres = S_OK; 753 754 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); 755 756 if(This->buf_size) { 757 read = min(cb, This->buf_size); 758 memcpy(pv, This->buf, read); 759 760 if(read == This->buf_size) { 761 heap_free(This->buf); 762 This->buf = NULL; 763 }else { 764 memmove(This->buf, This->buf+cb, This->buf_size-cb); 765 } 766 767 This->buf_size -= read; 768 } 769 770 if(read < cb) { 771 IInternetProtocol *protocol; 772 ULONG cread = 0; 773 774 /* FIXME: We shouldn't need it, but out binding code currently depends on it. */ 775 if(!This->protocol && This->protocol_unk) { 776 hres = IUnknown_QueryInterface(This->protocol_unk, &IID_IInternetProtocol, 777 (void**)&protocol); 778 if(FAILED(hres)) 779 return E_ABORT; 780 }else { 781 protocol = This->protocol; 782 } 783 784 if(is_apartment_thread(This)) 785 This->continue_call++; 786 hres = IInternetProtocol_Read(protocol, (BYTE*)pv+read, cb-read, &cread); 787 if(is_apartment_thread(This)) 788 This->continue_call--; 789 read += cread; 790 791 if(!This->protocol) 792 IInternetProtocol_Release(protocol); 793 } 794 795 *pcbRead = read; 796 return hres; 797 } 798 799 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, 800 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 801 { 802 BindProtocol *This = impl_from_IInternetProtocol(iface); 803 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); 804 return E_NOTIMPL; 805 } 806 807 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions) 808 { 809 BindProtocol *This = impl_from_IInternetProtocol(iface); 810 811 TRACE("(%p)->(%08x)\n", This, dwOptions); 812 813 return IInternetProtocol_LockRequest(This->protocol, dwOptions); 814 } 815 816 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface) 817 { 818 BindProtocol *This = impl_from_IInternetProtocol(iface); 819 820 TRACE("(%p)\n", This); 821 822 return IInternetProtocol_UnlockRequest(This->protocol); 823 } 824 825 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = { 826 ProtocolHandler_QueryInterface, 827 ProtocolHandler_AddRef, 828 ProtocolHandler_Release, 829 ProtocolHandler_Start, 830 ProtocolHandler_Continue, 831 ProtocolHandler_Abort, 832 ProtocolHandler_Terminate, 833 ProtocolHandler_Suspend, 834 ProtocolHandler_Resume, 835 ProtocolHandler_Read, 836 ProtocolHandler_Seek, 837 ProtocolHandler_LockRequest, 838 ProtocolHandler_UnlockRequest 839 }; 840 841 static inline BindProtocol *impl_from_IInternetProtocolSinkHandler(IInternetProtocolSink *iface) 842 { 843 return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocolSink_iface); 844 } 845 846 static HRESULT WINAPI ProtocolSinkHandler_QueryInterface(IInternetProtocolSink *iface, 847 REFIID riid, void **ppvObject) 848 { 849 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 850 return IInternetProtocol_QueryInterface(&This->default_protocol_handler.IInternetProtocol_iface, 851 riid, ppvObject); 852 } 853 854 static ULONG WINAPI ProtocolSinkHandler_AddRef(IInternetProtocolSink *iface) 855 { 856 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 857 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 858 } 859 860 static ULONG WINAPI ProtocolSinkHandler_Release(IInternetProtocolSink *iface) 861 { 862 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 863 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 864 } 865 866 static HRESULT WINAPI ProtocolSinkHandler_Switch(IInternetProtocolSink *iface, 867 PROTOCOLDATA *pProtocolData) 868 { 869 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 870 871 TRACE("(%p)->(%p)\n", This, pProtocolData); 872 873 if(!This->protocol_sink) { 874 IInternetProtocol_Continue(This->protocol_handler, pProtocolData); 875 return S_OK; 876 } 877 878 return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData); 879 } 880 881 static HRESULT WINAPI ProtocolSinkHandler_ReportProgress(IInternetProtocolSink *iface, 882 ULONG status_code, LPCWSTR status_text) 883 { 884 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 885 886 TRACE("(%p)->(%s %s)\n", This, debugstr_bindstatus(status_code), debugstr_w(status_text)); 887 888 if(!This->protocol_sink) 889 return S_OK; 890 891 switch(status_code) { 892 case BINDSTATUS_FINDINGRESOURCE: 893 case BINDSTATUS_CONNECTING: 894 case BINDSTATUS_REDIRECTING: 895 case BINDSTATUS_SENDINGREQUEST: 896 case BINDSTATUS_CACHEFILENAMEAVAILABLE: 897 case BINDSTATUS_DIRECTBIND: 898 case BINDSTATUS_ACCEPTRANGES: 899 case BINDSTATUS_DECODING: 900 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text); 901 break; 902 903 case BINDSTATUS_BEGINDOWNLOADDATA: 904 IInternetProtocolSink_ReportData(This->protocol_sink, This->bscf, This->progress, This->progress_max); 905 break; 906 907 case BINDSTATUS_MIMETYPEAVAILABLE: 908 mime_available(This, status_text, FALSE); 909 break; 910 911 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE: 912 mime_available(This, status_text, TRUE); 913 break; 914 915 default: 916 FIXME("unsupported ulStatusCode %u\n", status_code); 917 } 918 919 return S_OK; 920 } 921 922 static HRESULT WINAPI ProtocolSinkHandler_ReportData(IInternetProtocolSink *iface, 923 DWORD bscf, ULONG progress, ULONG progress_max) 924 { 925 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 926 927 TRACE("(%p)->(%x %u %u)\n", This, bscf, progress, progress_max); 928 929 This->bscf = bscf; 930 This->progress = progress; 931 This->progress_max = progress_max; 932 933 if(!This->protocol_sink) 934 return S_OK; 935 936 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) { 937 BYTE buf[BUFFER_SIZE]; 938 DWORD read = 0; 939 LPWSTR mime; 940 HRESULT hres; 941 942 do { 943 read = 0; 944 if(is_apartment_thread(This)) 945 This->continue_call++; 946 hres = IInternetProtocol_Read(This->protocol, buf, 947 sizeof(buf)-This->buf_size, &read); 948 if(is_apartment_thread(This)) 949 This->continue_call--; 950 if(FAILED(hres) && hres != E_PENDING) 951 return hres; 952 953 if(!This->buf) { 954 This->buf = heap_alloc(BUFFER_SIZE); 955 if(!This->buf) 956 return E_OUTOFMEMORY; 957 }else if(read + This->buf_size > BUFFER_SIZE) { 958 BYTE *tmp; 959 960 tmp = heap_realloc(This->buf, read+This->buf_size); 961 if(!tmp) 962 return E_OUTOFMEMORY; 963 This->buf = tmp; 964 } 965 966 memcpy(This->buf+This->buf_size, buf, read); 967 This->buf_size += read; 968 }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK); 969 970 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE) 971 return S_OK; 972 973 bscf = BSCF_FIRSTDATANOTIFICATION; 974 if(hres == S_FALSE) 975 bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE; 976 977 if(!This->reported_mime) { 978 BSTR raw_uri; 979 980 hres = IUri_GetRawUri(This->uri, &raw_uri); 981 if(FAILED(hres)) 982 return hres; 983 984 hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE), 985 This->mime, 0, &mime, 0); 986 SysFreeString(raw_uri); 987 if(FAILED(hres)) 988 return hres; 989 990 heap_free(This->mime); 991 This->mime = heap_strdupW(mime); 992 CoTaskMemFree(mime); 993 This->reported_mime = TRUE; 994 if(This->protocol_sink) 995 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, This->mime); 996 } 997 } 998 999 if(!This->protocol_sink) 1000 return S_OK; 1001 1002 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max); 1003 } 1004 1005 static HRESULT handle_redirect(BindProtocol *This, const WCHAR *url) 1006 { 1007 HRESULT hres; 1008 1009 if(This->redirect_callback) { 1010 VARIANT_BOOL cancel = VARIANT_FALSE; 1011 IBindCallbackRedirect_Redirect(This->redirect_callback, url, &cancel); 1012 if(cancel) 1013 return INET_E_REDIRECT_FAILED; 1014 } 1015 1016 if(This->protocol_sink) { 1017 hres = IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_REDIRECTING, url); 1018 if(FAILED(hres)) 1019 return hres; 1020 } 1021 1022 IInternetProtocol_Terminate(This->protocol, 0); /* should this be done in StartEx? */ 1023 release_protocol_handler(This); 1024 1025 return IInternetProtocolEx_Start(&This->IInternetProtocolEx_iface, url, This->protocol_sink, This->bind_info, This->pi, 0); 1026 } 1027 1028 static HRESULT WINAPI ProtocolSinkHandler_ReportResult(IInternetProtocolSink *iface, 1029 HRESULT hrResult, DWORD dwError, LPCWSTR szResult) 1030 { 1031 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 1032 1033 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult)); 1034 1035 if(hrResult == INET_E_REDIRECT_FAILED) { 1036 hrResult = handle_redirect(This, szResult); 1037 if(hrResult == S_OK) 1038 return S_OK; 1039 szResult = NULL; 1040 } 1041 1042 if(This->protocol_sink) 1043 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult); 1044 return S_OK; 1045 } 1046 1047 static const IInternetProtocolSinkVtbl InternetProtocolSinkHandlerVtbl = { 1048 ProtocolSinkHandler_QueryInterface, 1049 ProtocolSinkHandler_AddRef, 1050 ProtocolSinkHandler_Release, 1051 ProtocolSinkHandler_Switch, 1052 ProtocolSinkHandler_ReportProgress, 1053 ProtocolSinkHandler_ReportData, 1054 ProtocolSinkHandler_ReportResult 1055 }; 1056 1057 static inline BindProtocol *impl_from_IInternetBindInfo(IInternetBindInfo *iface) 1058 { 1059 return CONTAINING_RECORD(iface, BindProtocol, IInternetBindInfo_iface); 1060 } 1061 1062 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface, 1063 REFIID riid, void **ppv) 1064 { 1065 BindProtocol *This = impl_from_IInternetBindInfo(iface); 1066 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv); 1067 } 1068 1069 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface) 1070 { 1071 BindProtocol *This = impl_from_IInternetBindInfo(iface); 1072 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 1073 } 1074 1075 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface) 1076 { 1077 BindProtocol *This = impl_from_IInternetBindInfo(iface); 1078 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 1079 } 1080 1081 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, 1082 DWORD *grfBINDF, BINDINFO *pbindinfo) 1083 { 1084 BindProtocol *This = impl_from_IInternetBindInfo(iface); 1085 HRESULT hres; 1086 1087 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo); 1088 1089 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo); 1090 if(FAILED(hres)) { 1091 WARN("GetBindInfo failed: %08x\n", hres); 1092 return hres; 1093 } 1094 1095 if((pbindinfo->dwOptions & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS) && !This->redirect_callback) { 1096 IServiceProvider *service_provider; 1097 1098 hres = IInternetProtocolSink_QueryInterface(This->protocol_sink, &IID_IServiceProvider, (void**)&service_provider); 1099 if(SUCCEEDED(hres)) { 1100 hres = IServiceProvider_QueryService(service_provider, &IID_IBindCallbackRedirect, &IID_IBindCallbackRedirect, 1101 (void**)&This->redirect_callback); 1102 IServiceProvider_Release(service_provider); 1103 } 1104 } 1105 1106 *grfBINDF |= BINDF_FROMURLMON; 1107 return hres; 1108 } 1109 1110 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, 1111 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched) 1112 { 1113 BindProtocol *This = impl_from_IInternetBindInfo(iface); 1114 1115 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched); 1116 1117 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched); 1118 } 1119 1120 static const IInternetBindInfoVtbl InternetBindInfoVtbl = { 1121 BindInfo_QueryInterface, 1122 BindInfo_AddRef, 1123 BindInfo_Release, 1124 BindInfo_GetBindInfo, 1125 BindInfo_GetBindString 1126 }; 1127 1128 static inline BindProtocol *impl_from_IInternetPriority(IInternetPriority *iface) 1129 { 1130 return CONTAINING_RECORD(iface, BindProtocol, IInternetPriority_iface); 1131 } 1132 1133 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface, 1134 REFIID riid, void **ppv) 1135 { 1136 BindProtocol *This = impl_from_IInternetPriority(iface); 1137 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv); 1138 } 1139 1140 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface) 1141 { 1142 BindProtocol *This = impl_from_IInternetPriority(iface); 1143 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 1144 } 1145 1146 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface) 1147 { 1148 BindProtocol *This = impl_from_IInternetPriority(iface); 1149 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 1150 } 1151 1152 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority) 1153 { 1154 BindProtocol *This = impl_from_IInternetPriority(iface); 1155 1156 TRACE("(%p)->(%d)\n", This, nPriority); 1157 1158 This->priority = nPriority; 1159 return S_OK; 1160 } 1161 1162 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority) 1163 { 1164 BindProtocol *This = impl_from_IInternetPriority(iface); 1165 1166 TRACE("(%p)->(%p)\n", This, pnPriority); 1167 1168 *pnPriority = This->priority; 1169 return S_OK; 1170 } 1171 1172 static const IInternetPriorityVtbl InternetPriorityVtbl = { 1173 InternetPriority_QueryInterface, 1174 InternetPriority_AddRef, 1175 InternetPriority_Release, 1176 InternetPriority_SetPriority, 1177 InternetPriority_GetPriority 1178 1179 }; 1180 1181 static inline BindProtocol *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface) 1182 { 1183 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolSink_iface); 1184 } 1185 1186 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface, 1187 REFIID riid, void **ppv) 1188 { 1189 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1190 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv); 1191 } 1192 1193 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface) 1194 { 1195 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1196 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 1197 } 1198 1199 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface) 1200 { 1201 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1202 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 1203 } 1204 1205 typedef struct { 1206 task_header_t header; 1207 PROTOCOLDATA *data; 1208 } switch_task_t; 1209 1210 static void switch_proc(BindProtocol *bind, task_header_t *t) 1211 { 1212 switch_task_t *task = (switch_task_t*)t; 1213 1214 IInternetProtocol_Continue(bind->protocol_handler, task->data); 1215 1216 heap_free(task); 1217 } 1218 1219 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface, 1220 PROTOCOLDATA *pProtocolData) 1221 { 1222 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1223 PROTOCOLDATA *data; 1224 1225 TRACE("(%p)->(%p)\n", This, pProtocolData); 1226 1227 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState, 1228 pProtocolData->pData, pProtocolData->cbData); 1229 1230 data = heap_alloc(sizeof(PROTOCOLDATA)); 1231 if(!data) 1232 return E_OUTOFMEMORY; 1233 memcpy(data, pProtocolData, sizeof(PROTOCOLDATA)); 1234 1235 if((This->pi&PI_APARTMENTTHREADED && pProtocolData->grfFlags&PI_FORCE_ASYNC) 1236 || !do_direct_notif(This)) { 1237 switch_task_t *task; 1238 1239 task = heap_alloc(sizeof(switch_task_t)); 1240 if(!task) 1241 { 1242 heap_free(data); 1243 return E_OUTOFMEMORY; 1244 } 1245 1246 task->data = data; 1247 1248 push_task(This, &task->header, switch_proc); 1249 return S_OK; 1250 } 1251 1252 return IInternetProtocolSink_Switch(This->protocol_sink_handler, data); 1253 } 1254 1255 typedef struct { 1256 task_header_t header; 1257 1258 ULONG status_code; 1259 LPWSTR status_text; 1260 } on_progress_task_t; 1261 1262 static void on_progress_proc(BindProtocol *This, task_header_t *t) 1263 { 1264 on_progress_task_t *task = (on_progress_task_t*)t; 1265 1266 IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, task->status_code, task->status_text); 1267 1268 heap_free(task->status_text); 1269 heap_free(task); 1270 } 1271 1272 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface, 1273 ULONG ulStatusCode, LPCWSTR szStatusText) 1274 { 1275 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1276 1277 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText)); 1278 1279 if(do_direct_notif(This)) { 1280 IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, ulStatusCode, szStatusText); 1281 }else { 1282 on_progress_task_t *task; 1283 1284 task = heap_alloc(sizeof(on_progress_task_t)); 1285 1286 task->status_code = ulStatusCode; 1287 task->status_text = heap_strdupW(szStatusText); 1288 1289 push_task(This, &task->header, on_progress_proc); 1290 } 1291 1292 return S_OK; 1293 } 1294 1295 typedef struct { 1296 task_header_t header; 1297 DWORD bscf; 1298 ULONG progress; 1299 ULONG progress_max; 1300 } report_data_task_t; 1301 1302 static void report_data_proc(BindProtocol *This, task_header_t *t) 1303 { 1304 report_data_task_t *task = (report_data_task_t*)t; 1305 1306 IInternetProtocolSink_ReportData(This->protocol_sink_handler, 1307 task->bscf, task->progress, task->progress_max); 1308 1309 heap_free(task); 1310 } 1311 1312 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface, 1313 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax) 1314 { 1315 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1316 1317 TRACE("(%p)->(%x %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax); 1318 1319 if(!This->protocol_sink) 1320 return S_OK; 1321 1322 if(!do_direct_notif(This)) { 1323 report_data_task_t *task; 1324 1325 task = heap_alloc(sizeof(report_data_task_t)); 1326 if(!task) 1327 return E_OUTOFMEMORY; 1328 1329 task->bscf = grfBSCF; 1330 task->progress = ulProgress; 1331 task->progress_max = ulProgressMax; 1332 1333 push_task(This, &task->header, report_data_proc); 1334 return S_OK; 1335 } 1336 1337 return IInternetProtocolSink_ReportData(This->protocol_sink_handler, 1338 grfBSCF, ulProgress, ulProgressMax); 1339 } 1340 1341 typedef struct { 1342 task_header_t header; 1343 1344 HRESULT hres; 1345 DWORD err; 1346 LPWSTR str; 1347 } report_result_task_t; 1348 1349 static void report_result_proc(BindProtocol *This, task_header_t *t) 1350 { 1351 report_result_task_t *task = (report_result_task_t*)t; 1352 1353 IInternetProtocolSink_ReportResult(This->protocol_sink_handler, task->hres, task->err, task->str); 1354 1355 heap_free(task->str); 1356 heap_free(task); 1357 } 1358 1359 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface, 1360 HRESULT hrResult, DWORD dwError, LPCWSTR szResult) 1361 { 1362 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1363 1364 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult)); 1365 1366 if(!This->protocol_sink) 1367 return E_FAIL; 1368 This->reported_result = TRUE; 1369 1370 if(!do_direct_notif(This)) { 1371 report_result_task_t *task; 1372 1373 task = heap_alloc(sizeof(report_result_task_t)); 1374 if(!task) 1375 return E_OUTOFMEMORY; 1376 1377 task->hres = hrResult; 1378 task->err = dwError; 1379 task->str = heap_strdupW(szResult); 1380 1381 push_task(This, &task->header, report_result_proc); 1382 return S_OK; 1383 } 1384 1385 return IInternetProtocolSink_ReportResult(This->protocol_sink_handler, hrResult, dwError, szResult); 1386 } 1387 1388 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = { 1389 BPInternetProtocolSink_QueryInterface, 1390 BPInternetProtocolSink_AddRef, 1391 BPInternetProtocolSink_Release, 1392 BPInternetProtocolSink_Switch, 1393 BPInternetProtocolSink_ReportProgress, 1394 BPInternetProtocolSink_ReportData, 1395 BPInternetProtocolSink_ReportResult 1396 }; 1397 1398 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface) 1399 { 1400 return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface); 1401 } 1402 1403 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface, 1404 REFIID riid, void **ppv) 1405 { 1406 BindProtocol *This = impl_from_IServiceProvider(iface); 1407 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv); 1408 } 1409 1410 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface) 1411 { 1412 BindProtocol *This = impl_from_IServiceProvider(iface); 1413 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 1414 } 1415 1416 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface) 1417 { 1418 BindProtocol *This = impl_from_IServiceProvider(iface); 1419 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 1420 } 1421 1422 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface, 1423 REFGUID guidService, REFIID riid, void **ppv) 1424 { 1425 BindProtocol *This = impl_from_IServiceProvider(iface); 1426 1427 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); 1428 1429 if(!This->service_provider) 1430 return E_NOINTERFACE; 1431 1432 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv); 1433 } 1434 1435 static const IServiceProviderVtbl ServiceProviderVtbl = { 1436 BPServiceProvider_QueryInterface, 1437 BPServiceProvider_AddRef, 1438 BPServiceProvider_Release, 1439 BPServiceProvider_QueryService 1440 }; 1441 1442 HRESULT create_binding_protocol(BindProtocol **protocol) 1443 { 1444 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol)); 1445 1446 ret->IInternetProtocolEx_iface.lpVtbl = &BindProtocolVtbl; 1447 ret->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl; 1448 ret->IInternetPriority_iface.lpVtbl = &InternetPriorityVtbl; 1449 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; 1450 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl; 1451 1452 ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl; 1453 ret->default_protocol_handler.IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkHandlerVtbl; 1454 1455 ret->ref = 1; 1456 ret->apartment_thread = GetCurrentThreadId(); 1457 ret->notif_hwnd = get_notif_hwnd(); 1458 ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface; 1459 ret->protocol_sink_handler = &ret->default_protocol_handler.IInternetProtocolSink_iface; 1460 InitializeCriticalSection(&ret->section); 1461 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BindProtocol.section"); 1462 1463 URLMON_LockModule(); 1464 1465 *protocol = ret; 1466 return S_OK; 1467 } 1468