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 IClassFactory_Release(cf); 513 if(FAILED(hres)) 514 return hres; 515 516 hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetProtocol, (void**)&protocol); 517 if(FAILED(hres)) { 518 IUnknown_Release(protocol_unk); 519 return hres; 520 } 521 } 522 523 StringFromCLSID(&clsid, &clsid_str); 524 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str); 525 CoTaskMemFree(clsid_str); 526 527 This->protocol_unk = protocol_unk; 528 This->protocol = protocol; 529 530 if(!protocol_unk) 531 protocol_unk = (IUnknown*)protocol; 532 533 set_binding_sink(This, pOIProtSink, pOIBindInfo); 534 535 hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetPriority, (void**)&priority); 536 if(SUCCEEDED(hres)) { 537 IInternetPriority_SetPriority(priority, This->priority); 538 IInternetPriority_Release(priority); 539 } 540 541 hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetProtocolEx, (void**)&protocolex); 542 if(SUCCEEDED(hres)) { 543 hres = IInternetProtocolEx_StartEx(protocolex, pUri, &This->IInternetProtocolSink_iface, 544 &This->IInternetBindInfo_iface, 0, NULL); 545 IInternetProtocolEx_Release(protocolex); 546 }else { 547 hres = IUri_GetDisplayUri(pUri, &This->display_uri); 548 if(FAILED(hres)) 549 return hres; 550 551 hres = IInternetProtocol_Start(protocol, This->display_uri, &This->IInternetProtocolSink_iface, 552 &This->IInternetBindInfo_iface, 0, 0); 553 } 554 555 if(SUCCEEDED(hres)) 556 process_tasks(This); 557 return hres; 558 } 559 560 void set_binding_sink(BindProtocol *This, IInternetProtocolSink *sink, IInternetBindInfo *bind_info) 561 { 562 IInternetProtocolSink *prev_sink; 563 IServiceProvider *service_provider = NULL; 564 565 if(sink) 566 IInternetProtocolSink_AddRef(sink); 567 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink); 568 if(prev_sink) 569 IInternetProtocolSink_Release(prev_sink); 570 571 if(sink) 572 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider); 573 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider); 574 if(service_provider) 575 IServiceProvider_Release(service_provider); 576 577 if(bind_info) 578 IInternetBindInfo_AddRef(bind_info); 579 bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info); 580 if(bind_info) 581 IInternetBindInfo_Release(bind_info); 582 } 583 584 static const IInternetProtocolExVtbl BindProtocolVtbl = { 585 BindProtocol_QueryInterface, 586 BindProtocol_AddRef, 587 BindProtocol_Release, 588 BindProtocol_Start, 589 BindProtocol_Continue, 590 BindProtocol_Abort, 591 BindProtocol_Terminate, 592 BindProtocol_Suspend, 593 BindProtocol_Resume, 594 BindProtocol_Read, 595 BindProtocol_Seek, 596 BindProtocol_LockRequest, 597 BindProtocol_UnlockRequest, 598 BindProtocol_StartEx 599 }; 600 601 static inline BindProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface) 602 { 603 return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocol_iface); 604 } 605 606 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) 607 { 608 BindProtocol *This = impl_from_IInternetProtocol(iface); 609 610 *ppv = NULL; 611 if(IsEqualGUID(&IID_IUnknown, riid)) { 612 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); 613 *ppv = &This->default_protocol_handler.IInternetProtocol_iface; 614 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) { 615 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv); 616 *ppv = &This->default_protocol_handler.IInternetProtocol_iface; 617 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) { 618 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv); 619 *ppv = &This->default_protocol_handler.IInternetProtocol_iface; 620 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) { 621 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv); 622 *ppv = &This->default_protocol_handler.IInternetProtocolSink_iface; 623 } 624 625 if(*ppv) { 626 IInternetProtocol_AddRef(iface); 627 return S_OK; 628 } 629 630 WARN("not supported interface %s\n", debugstr_guid(riid)); 631 return E_NOINTERFACE; 632 } 633 634 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface) 635 { 636 BindProtocol *This = impl_from_IInternetProtocol(iface); 637 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 638 } 639 640 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface) 641 { 642 BindProtocol *This = impl_from_IInternetProtocol(iface); 643 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 644 } 645 646 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl, 647 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, 648 DWORD grfPI, HANDLE_PTR dwReserved) 649 { 650 ERR("Should not be called\n"); 651 return E_NOTIMPL; 652 } 653 654 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData) 655 { 656 BindProtocol *This = impl_from_IInternetProtocol(iface); 657 IInternetProtocol *protocol = NULL; 658 HRESULT hres; 659 660 TRACE("(%p)->(%p)\n", This, pProtocolData); 661 662 /* FIXME: This should not be needed. */ 663 if(!This->protocol) { 664 if(!This->protocol_unk) 665 return E_FAIL; 666 hres = IUnknown_QueryInterface(This->protocol_unk, &IID_IInternetProtocol, (void**)&protocol); 667 if(FAILED(hres)) 668 return E_FAIL; 669 } 670 671 hres = IInternetProtocol_Continue(protocol ? protocol : This->protocol, pProtocolData); 672 673 heap_free(pProtocolData); 674 if(protocol) 675 IInternetProtocol_Release(protocol); 676 return hres; 677 } 678 679 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason, 680 DWORD dwOptions) 681 { 682 BindProtocol *This = impl_from_IInternetProtocol(iface); 683 684 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); 685 686 if(This->protocol && !This->reported_result) 687 return IInternetProtocol_Abort(This->protocol, hrReason, dwOptions); 688 689 return S_OK; 690 } 691 692 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions) 693 { 694 BindProtocol *This = impl_from_IInternetProtocol(iface); 695 696 TRACE("(%p)->(%08x)\n", This, dwOptions); 697 698 if(!This->reported_result) 699 return E_FAIL; 700 701 /* This may get released in Terminate call. */ 702 IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 703 704 if(This->protocol) { 705 IInternetProtocol_Terminate(This->protocol, 0); 706 IInternetProtocol_Release(This->protocol); 707 This->protocol = NULL; 708 } 709 710 set_binding_sink(This, NULL, NULL); 711 712 if(This->bind_info) { 713 IInternetBindInfo_Release(This->bind_info); 714 This->bind_info = NULL; 715 } 716 717 if(This->redirect_callback) { 718 IBindCallbackRedirect_Release(This->redirect_callback); 719 This->redirect_callback = NULL; 720 } 721 722 IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 723 return S_OK; 724 } 725 726 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface) 727 { 728 BindProtocol *This = impl_from_IInternetProtocol(iface); 729 FIXME("(%p)\n", This); 730 return E_NOTIMPL; 731 } 732 733 static HRESULT WINAPI ProtocolHandler_Resume(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_Read(IInternetProtocol *iface, void *pv, 741 ULONG cb, ULONG *pcbRead) 742 { 743 BindProtocol *This = impl_from_IInternetProtocol(iface); 744 ULONG read = 0; 745 HRESULT hres = S_OK; 746 747 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); 748 749 if(This->buf_size) { 750 read = min(cb, This->buf_size); 751 memcpy(pv, This->buf, read); 752 753 if(read == This->buf_size) { 754 heap_free(This->buf); 755 This->buf = NULL; 756 }else { 757 memmove(This->buf, This->buf+cb, This->buf_size-cb); 758 } 759 760 This->buf_size -= read; 761 } 762 763 if(read < cb) { 764 IInternetProtocol *protocol; 765 ULONG cread = 0; 766 767 /* FIXME: We shouldn't need it, but out binding code currently depends on it. */ 768 if(!This->protocol && This->protocol_unk) { 769 hres = IUnknown_QueryInterface(This->protocol_unk, &IID_IInternetProtocol, 770 (void**)&protocol); 771 if(FAILED(hres)) 772 return E_ABORT; 773 }else { 774 protocol = This->protocol; 775 } 776 777 if(is_apartment_thread(This)) 778 This->continue_call++; 779 hres = IInternetProtocol_Read(protocol, (BYTE*)pv+read, cb-read, &cread); 780 if(is_apartment_thread(This)) 781 This->continue_call--; 782 read += cread; 783 784 if(!This->protocol) 785 IInternetProtocol_Release(protocol); 786 } 787 788 *pcbRead = read; 789 return hres; 790 } 791 792 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, 793 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) 794 { 795 BindProtocol *This = impl_from_IInternetProtocol(iface); 796 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); 797 return E_NOTIMPL; 798 } 799 800 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions) 801 { 802 BindProtocol *This = impl_from_IInternetProtocol(iface); 803 804 TRACE("(%p)->(%08x)\n", This, dwOptions); 805 806 return IInternetProtocol_LockRequest(This->protocol, dwOptions); 807 } 808 809 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface) 810 { 811 BindProtocol *This = impl_from_IInternetProtocol(iface); 812 813 TRACE("(%p)\n", This); 814 815 return IInternetProtocol_UnlockRequest(This->protocol); 816 } 817 818 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = { 819 ProtocolHandler_QueryInterface, 820 ProtocolHandler_AddRef, 821 ProtocolHandler_Release, 822 ProtocolHandler_Start, 823 ProtocolHandler_Continue, 824 ProtocolHandler_Abort, 825 ProtocolHandler_Terminate, 826 ProtocolHandler_Suspend, 827 ProtocolHandler_Resume, 828 ProtocolHandler_Read, 829 ProtocolHandler_Seek, 830 ProtocolHandler_LockRequest, 831 ProtocolHandler_UnlockRequest 832 }; 833 834 static inline BindProtocol *impl_from_IInternetProtocolSinkHandler(IInternetProtocolSink *iface) 835 { 836 return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocolSink_iface); 837 } 838 839 static HRESULT WINAPI ProtocolSinkHandler_QueryInterface(IInternetProtocolSink *iface, 840 REFIID riid, void **ppvObject) 841 { 842 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 843 return IInternetProtocol_QueryInterface(&This->default_protocol_handler.IInternetProtocol_iface, 844 riid, ppvObject); 845 } 846 847 static ULONG WINAPI ProtocolSinkHandler_AddRef(IInternetProtocolSink *iface) 848 { 849 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 850 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 851 } 852 853 static ULONG WINAPI ProtocolSinkHandler_Release(IInternetProtocolSink *iface) 854 { 855 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 856 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 857 } 858 859 static HRESULT WINAPI ProtocolSinkHandler_Switch(IInternetProtocolSink *iface, 860 PROTOCOLDATA *pProtocolData) 861 { 862 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 863 864 TRACE("(%p)->(%p)\n", This, pProtocolData); 865 866 if(!This->protocol_sink) { 867 IInternetProtocol_Continue(This->protocol_handler, pProtocolData); 868 return S_OK; 869 } 870 871 return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData); 872 } 873 874 static HRESULT WINAPI ProtocolSinkHandler_ReportProgress(IInternetProtocolSink *iface, 875 ULONG status_code, LPCWSTR status_text) 876 { 877 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 878 879 TRACE("(%p)->(%s %s)\n", This, debugstr_bindstatus(status_code), debugstr_w(status_text)); 880 881 if(!This->protocol_sink) 882 return S_OK; 883 884 switch(status_code) { 885 case BINDSTATUS_FINDINGRESOURCE: 886 case BINDSTATUS_CONNECTING: 887 case BINDSTATUS_REDIRECTING: 888 case BINDSTATUS_SENDINGREQUEST: 889 case BINDSTATUS_CACHEFILENAMEAVAILABLE: 890 case BINDSTATUS_DIRECTBIND: 891 case BINDSTATUS_ACCEPTRANGES: 892 case BINDSTATUS_DECODING: 893 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text); 894 break; 895 896 case BINDSTATUS_BEGINDOWNLOADDATA: 897 IInternetProtocolSink_ReportData(This->protocol_sink, This->bscf, This->progress, This->progress_max); 898 break; 899 900 case BINDSTATUS_MIMETYPEAVAILABLE: 901 mime_available(This, status_text, FALSE); 902 break; 903 904 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE: 905 mime_available(This, status_text, TRUE); 906 break; 907 908 default: 909 FIXME("unsupported ulStatusCode %u\n", status_code); 910 } 911 912 return S_OK; 913 } 914 915 static HRESULT WINAPI ProtocolSinkHandler_ReportData(IInternetProtocolSink *iface, 916 DWORD bscf, ULONG progress, ULONG progress_max) 917 { 918 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 919 920 TRACE("(%p)->(%x %u %u)\n", This, bscf, progress, progress_max); 921 922 This->bscf = bscf; 923 This->progress = progress; 924 This->progress_max = progress_max; 925 926 if(!This->protocol_sink) 927 return S_OK; 928 929 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) { 930 BYTE buf[BUFFER_SIZE]; 931 DWORD read = 0; 932 LPWSTR mime; 933 HRESULT hres; 934 935 do { 936 read = 0; 937 if(is_apartment_thread(This)) 938 This->continue_call++; 939 hres = IInternetProtocol_Read(This->protocol, buf, 940 sizeof(buf)-This->buf_size, &read); 941 if(is_apartment_thread(This)) 942 This->continue_call--; 943 if(FAILED(hres) && hres != E_PENDING) 944 return hres; 945 946 if(!This->buf) { 947 This->buf = heap_alloc(BUFFER_SIZE); 948 if(!This->buf) 949 return E_OUTOFMEMORY; 950 }else if(read + This->buf_size > BUFFER_SIZE) { 951 BYTE *tmp; 952 953 tmp = heap_realloc(This->buf, read+This->buf_size); 954 if(!tmp) 955 return E_OUTOFMEMORY; 956 This->buf = tmp; 957 } 958 959 memcpy(This->buf+This->buf_size, buf, read); 960 This->buf_size += read; 961 }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK); 962 963 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE) 964 return S_OK; 965 966 bscf = BSCF_FIRSTDATANOTIFICATION; 967 if(hres == S_FALSE) 968 bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE; 969 970 if(!This->reported_mime) { 971 BSTR raw_uri; 972 973 hres = IUri_GetRawUri(This->uri, &raw_uri); 974 if(FAILED(hres)) 975 return hres; 976 977 hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE), 978 This->mime, 0, &mime, 0); 979 SysFreeString(raw_uri); 980 if(FAILED(hres)) 981 return hres; 982 983 heap_free(This->mime); 984 This->mime = heap_strdupW(mime); 985 CoTaskMemFree(mime); 986 This->reported_mime = TRUE; 987 if(This->protocol_sink) 988 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, This->mime); 989 } 990 } 991 992 if(!This->protocol_sink) 993 return S_OK; 994 995 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max); 996 } 997 998 static HRESULT handle_redirect(BindProtocol *This, const WCHAR *url) 999 { 1000 HRESULT hres; 1001 1002 if(This->redirect_callback) { 1003 VARIANT_BOOL cancel = VARIANT_FALSE; 1004 IBindCallbackRedirect_Redirect(This->redirect_callback, url, &cancel); 1005 if(cancel) 1006 return INET_E_REDIRECT_FAILED; 1007 } 1008 1009 if(This->protocol_sink) { 1010 hres = IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_REDIRECTING, url); 1011 if(FAILED(hres)) 1012 return hres; 1013 } 1014 1015 IInternetProtocol_Terminate(This->protocol, 0); /* should this be done in StartEx? */ 1016 release_protocol_handler(This); 1017 1018 return IInternetProtocolEx_Start(&This->IInternetProtocolEx_iface, url, This->protocol_sink, This->bind_info, This->pi, 0); 1019 } 1020 1021 static HRESULT WINAPI ProtocolSinkHandler_ReportResult(IInternetProtocolSink *iface, 1022 HRESULT hrResult, DWORD dwError, LPCWSTR szResult) 1023 { 1024 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface); 1025 1026 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult)); 1027 1028 if(hrResult == INET_E_REDIRECT_FAILED) { 1029 hrResult = handle_redirect(This, szResult); 1030 if(hrResult == S_OK) 1031 return S_OK; 1032 szResult = NULL; 1033 } 1034 1035 if(This->protocol_sink) 1036 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult); 1037 return S_OK; 1038 } 1039 1040 static const IInternetProtocolSinkVtbl InternetProtocolSinkHandlerVtbl = { 1041 ProtocolSinkHandler_QueryInterface, 1042 ProtocolSinkHandler_AddRef, 1043 ProtocolSinkHandler_Release, 1044 ProtocolSinkHandler_Switch, 1045 ProtocolSinkHandler_ReportProgress, 1046 ProtocolSinkHandler_ReportData, 1047 ProtocolSinkHandler_ReportResult 1048 }; 1049 1050 static inline BindProtocol *impl_from_IInternetBindInfo(IInternetBindInfo *iface) 1051 { 1052 return CONTAINING_RECORD(iface, BindProtocol, IInternetBindInfo_iface); 1053 } 1054 1055 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface, 1056 REFIID riid, void **ppv) 1057 { 1058 BindProtocol *This = impl_from_IInternetBindInfo(iface); 1059 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv); 1060 } 1061 1062 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface) 1063 { 1064 BindProtocol *This = impl_from_IInternetBindInfo(iface); 1065 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 1066 } 1067 1068 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface) 1069 { 1070 BindProtocol *This = impl_from_IInternetBindInfo(iface); 1071 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 1072 } 1073 1074 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, 1075 DWORD *grfBINDF, BINDINFO *pbindinfo) 1076 { 1077 BindProtocol *This = impl_from_IInternetBindInfo(iface); 1078 HRESULT hres; 1079 1080 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo); 1081 1082 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo); 1083 if(FAILED(hres)) { 1084 WARN("GetBindInfo failed: %08x\n", hres); 1085 return hres; 1086 } 1087 1088 if((pbindinfo->dwOptions & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS) && !This->redirect_callback) { 1089 IServiceProvider *service_provider; 1090 1091 hres = IInternetProtocolSink_QueryInterface(This->protocol_sink, &IID_IServiceProvider, (void**)&service_provider); 1092 if(SUCCEEDED(hres)) { 1093 hres = IServiceProvider_QueryService(service_provider, &IID_IBindCallbackRedirect, &IID_IBindCallbackRedirect, 1094 (void**)&This->redirect_callback); 1095 IServiceProvider_Release(service_provider); 1096 } 1097 } 1098 1099 *grfBINDF |= BINDF_FROMURLMON; 1100 return hres; 1101 } 1102 1103 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, 1104 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched) 1105 { 1106 BindProtocol *This = impl_from_IInternetBindInfo(iface); 1107 1108 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched); 1109 1110 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched); 1111 } 1112 1113 static const IInternetBindInfoVtbl InternetBindInfoVtbl = { 1114 BindInfo_QueryInterface, 1115 BindInfo_AddRef, 1116 BindInfo_Release, 1117 BindInfo_GetBindInfo, 1118 BindInfo_GetBindString 1119 }; 1120 1121 static inline BindProtocol *impl_from_IInternetPriority(IInternetPriority *iface) 1122 { 1123 return CONTAINING_RECORD(iface, BindProtocol, IInternetPriority_iface); 1124 } 1125 1126 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface, 1127 REFIID riid, void **ppv) 1128 { 1129 BindProtocol *This = impl_from_IInternetPriority(iface); 1130 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv); 1131 } 1132 1133 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface) 1134 { 1135 BindProtocol *This = impl_from_IInternetPriority(iface); 1136 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 1137 } 1138 1139 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface) 1140 { 1141 BindProtocol *This = impl_from_IInternetPriority(iface); 1142 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 1143 } 1144 1145 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority) 1146 { 1147 BindProtocol *This = impl_from_IInternetPriority(iface); 1148 1149 TRACE("(%p)->(%d)\n", This, nPriority); 1150 1151 This->priority = nPriority; 1152 return S_OK; 1153 } 1154 1155 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority) 1156 { 1157 BindProtocol *This = impl_from_IInternetPriority(iface); 1158 1159 TRACE("(%p)->(%p)\n", This, pnPriority); 1160 1161 *pnPriority = This->priority; 1162 return S_OK; 1163 } 1164 1165 static const IInternetPriorityVtbl InternetPriorityVtbl = { 1166 InternetPriority_QueryInterface, 1167 InternetPriority_AddRef, 1168 InternetPriority_Release, 1169 InternetPriority_SetPriority, 1170 InternetPriority_GetPriority 1171 1172 }; 1173 1174 static inline BindProtocol *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface) 1175 { 1176 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolSink_iface); 1177 } 1178 1179 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface, 1180 REFIID riid, void **ppv) 1181 { 1182 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1183 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv); 1184 } 1185 1186 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface) 1187 { 1188 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1189 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 1190 } 1191 1192 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface) 1193 { 1194 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1195 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 1196 } 1197 1198 typedef struct { 1199 task_header_t header; 1200 PROTOCOLDATA *data; 1201 } switch_task_t; 1202 1203 static void switch_proc(BindProtocol *bind, task_header_t *t) 1204 { 1205 switch_task_t *task = (switch_task_t*)t; 1206 1207 IInternetProtocol_Continue(bind->protocol_handler, task->data); 1208 1209 heap_free(task); 1210 } 1211 1212 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface, 1213 PROTOCOLDATA *pProtocolData) 1214 { 1215 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1216 PROTOCOLDATA *data; 1217 1218 TRACE("(%p)->(%p)\n", This, pProtocolData); 1219 1220 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState, 1221 pProtocolData->pData, pProtocolData->cbData); 1222 1223 data = heap_alloc(sizeof(PROTOCOLDATA)); 1224 if(!data) 1225 return E_OUTOFMEMORY; 1226 memcpy(data, pProtocolData, sizeof(PROTOCOLDATA)); 1227 1228 if((This->pi&PI_APARTMENTTHREADED && pProtocolData->grfFlags&PI_FORCE_ASYNC) 1229 || !do_direct_notif(This)) { 1230 switch_task_t *task; 1231 1232 task = heap_alloc(sizeof(switch_task_t)); 1233 if(!task) 1234 { 1235 heap_free(data); 1236 return E_OUTOFMEMORY; 1237 } 1238 1239 task->data = data; 1240 1241 push_task(This, &task->header, switch_proc); 1242 return S_OK; 1243 } 1244 1245 return IInternetProtocolSink_Switch(This->protocol_sink_handler, data); 1246 } 1247 1248 typedef struct { 1249 task_header_t header; 1250 1251 ULONG status_code; 1252 LPWSTR status_text; 1253 } on_progress_task_t; 1254 1255 static void on_progress_proc(BindProtocol *This, task_header_t *t) 1256 { 1257 on_progress_task_t *task = (on_progress_task_t*)t; 1258 1259 IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, task->status_code, task->status_text); 1260 1261 heap_free(task->status_text); 1262 heap_free(task); 1263 } 1264 1265 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface, 1266 ULONG ulStatusCode, LPCWSTR szStatusText) 1267 { 1268 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1269 1270 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText)); 1271 1272 if(do_direct_notif(This)) { 1273 IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, ulStatusCode, szStatusText); 1274 }else { 1275 on_progress_task_t *task; 1276 1277 task = heap_alloc(sizeof(on_progress_task_t)); 1278 1279 task->status_code = ulStatusCode; 1280 task->status_text = heap_strdupW(szStatusText); 1281 1282 push_task(This, &task->header, on_progress_proc); 1283 } 1284 1285 return S_OK; 1286 } 1287 1288 typedef struct { 1289 task_header_t header; 1290 DWORD bscf; 1291 ULONG progress; 1292 ULONG progress_max; 1293 } report_data_task_t; 1294 1295 static void report_data_proc(BindProtocol *This, task_header_t *t) 1296 { 1297 report_data_task_t *task = (report_data_task_t*)t; 1298 1299 IInternetProtocolSink_ReportData(This->protocol_sink_handler, 1300 task->bscf, task->progress, task->progress_max); 1301 1302 heap_free(task); 1303 } 1304 1305 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface, 1306 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax) 1307 { 1308 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1309 1310 TRACE("(%p)->(%x %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax); 1311 1312 if(!This->protocol_sink) 1313 return S_OK; 1314 1315 if(!do_direct_notif(This)) { 1316 report_data_task_t *task; 1317 1318 task = heap_alloc(sizeof(report_data_task_t)); 1319 if(!task) 1320 return E_OUTOFMEMORY; 1321 1322 task->bscf = grfBSCF; 1323 task->progress = ulProgress; 1324 task->progress_max = ulProgressMax; 1325 1326 push_task(This, &task->header, report_data_proc); 1327 return S_OK; 1328 } 1329 1330 return IInternetProtocolSink_ReportData(This->protocol_sink_handler, 1331 grfBSCF, ulProgress, ulProgressMax); 1332 } 1333 1334 typedef struct { 1335 task_header_t header; 1336 1337 HRESULT hres; 1338 DWORD err; 1339 LPWSTR str; 1340 } report_result_task_t; 1341 1342 static void report_result_proc(BindProtocol *This, task_header_t *t) 1343 { 1344 report_result_task_t *task = (report_result_task_t*)t; 1345 1346 IInternetProtocolSink_ReportResult(This->protocol_sink_handler, task->hres, task->err, task->str); 1347 1348 heap_free(task->str); 1349 heap_free(task); 1350 } 1351 1352 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface, 1353 HRESULT hrResult, DWORD dwError, LPCWSTR szResult) 1354 { 1355 BindProtocol *This = impl_from_IInternetProtocolSink(iface); 1356 1357 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult)); 1358 1359 if(!This->protocol_sink) 1360 return E_FAIL; 1361 This->reported_result = TRUE; 1362 1363 if(!do_direct_notif(This)) { 1364 report_result_task_t *task; 1365 1366 task = heap_alloc(sizeof(report_result_task_t)); 1367 if(!task) 1368 return E_OUTOFMEMORY; 1369 1370 task->hres = hrResult; 1371 task->err = dwError; 1372 task->str = heap_strdupW(szResult); 1373 1374 push_task(This, &task->header, report_result_proc); 1375 return S_OK; 1376 } 1377 1378 return IInternetProtocolSink_ReportResult(This->protocol_sink_handler, hrResult, dwError, szResult); 1379 } 1380 1381 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = { 1382 BPInternetProtocolSink_QueryInterface, 1383 BPInternetProtocolSink_AddRef, 1384 BPInternetProtocolSink_Release, 1385 BPInternetProtocolSink_Switch, 1386 BPInternetProtocolSink_ReportProgress, 1387 BPInternetProtocolSink_ReportData, 1388 BPInternetProtocolSink_ReportResult 1389 }; 1390 1391 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface) 1392 { 1393 return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface); 1394 } 1395 1396 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface, 1397 REFIID riid, void **ppv) 1398 { 1399 BindProtocol *This = impl_from_IServiceProvider(iface); 1400 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv); 1401 } 1402 1403 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface) 1404 { 1405 BindProtocol *This = impl_from_IServiceProvider(iface); 1406 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface); 1407 } 1408 1409 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface) 1410 { 1411 BindProtocol *This = impl_from_IServiceProvider(iface); 1412 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface); 1413 } 1414 1415 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface, 1416 REFGUID guidService, REFIID riid, void **ppv) 1417 { 1418 BindProtocol *This = impl_from_IServiceProvider(iface); 1419 1420 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); 1421 1422 if(!This->service_provider) 1423 return E_NOINTERFACE; 1424 1425 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv); 1426 } 1427 1428 static const IServiceProviderVtbl ServiceProviderVtbl = { 1429 BPServiceProvider_QueryInterface, 1430 BPServiceProvider_AddRef, 1431 BPServiceProvider_Release, 1432 BPServiceProvider_QueryService 1433 }; 1434 1435 HRESULT create_binding_protocol(BindProtocol **protocol) 1436 { 1437 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol)); 1438 1439 ret->IInternetProtocolEx_iface.lpVtbl = &BindProtocolVtbl; 1440 ret->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl; 1441 ret->IInternetPriority_iface.lpVtbl = &InternetPriorityVtbl; 1442 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; 1443 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl; 1444 1445 ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl; 1446 ret->default_protocol_handler.IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkHandlerVtbl; 1447 1448 ret->ref = 1; 1449 ret->apartment_thread = GetCurrentThreadId(); 1450 ret->notif_hwnd = get_notif_hwnd(); 1451 ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface; 1452 ret->protocol_sink_handler = &ret->default_protocol_handler.IInternetProtocolSink_iface; 1453 InitializeCriticalSection(&ret->section); 1454 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BindProtocol.section"); 1455 1456 URLMON_LockModule(); 1457 1458 *protocol = ret; 1459 return S_OK; 1460 } 1461