kernel32: Update version to Win 10.
[wine.git] / dlls / urlmon / bindprot.c
blob2e58884b199f68d040f53b64919bee25bc9f7472
1 /*
2 * Copyright 2007-2009 Jacek Caban for CodeWeavers
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.
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.
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
19 #include "urlmon_main.h"
20 #include "wine/debug.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
24 typedef void (*task_proc_t)(BindProtocol*,task_header_t*);
26 struct _task_header_t {
27 task_proc_t proc;
28 task_header_t *next;
31 #define BUFFER_SIZE 2048
32 #define MIME_TEST_SIZE 255
34 #define WM_MK_CONTINUE (WM_USER+101)
35 #define WM_MK_RELEASE (WM_USER+102)
37 static void process_tasks(BindProtocol *This)
39 task_header_t *task;
41 while(1) {
42 EnterCriticalSection(&This->section);
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;
51 LeaveCriticalSection(&This->section);
53 if(!task)
54 break;
56 This->continue_call++;
57 task->proc(This, task);
58 This->continue_call--;
62 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
64 switch(msg) {
65 case WM_MK_CONTINUE: {
66 BindProtocol *This = (BindProtocol*)lParam;
68 process_tasks(This);
70 IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
71 return 0;
73 case WM_MK_RELEASE: {
74 tls_data_t *data = get_tls_data();
76 if(!--data->notif_hwnd_cnt) {
77 DestroyWindow(hwnd);
78 data->notif_hwnd = NULL;
83 return DefWindowProcW(hwnd, msg, wParam, lParam);
86 static ATOM notif_wnd_class;
88 static BOOL WINAPI register_notif_wnd_class(INIT_ONCE *once, void *param, void **context)
90 static WNDCLASSEXW wndclass = {
91 sizeof(wndclass), 0, notif_wnd_proc, 0, 0,
92 NULL, NULL, NULL, NULL, NULL,
93 L"URL Moniker Notification Window", NULL
96 wndclass.hInstance = hProxyDll;
97 notif_wnd_class = RegisterClassExW(&wndclass);
98 return TRUE;
101 void unregister_notif_wnd_class(void)
103 if(notif_wnd_class)
104 UnregisterClassW(MAKEINTRESOURCEW(notif_wnd_class), hProxyDll);
107 HWND get_notif_hwnd(void)
109 tls_data_t *tls_data;
111 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
113 tls_data = get_tls_data();
114 if(!tls_data)
115 return NULL;
117 if(tls_data->notif_hwnd_cnt) {
118 tls_data->notif_hwnd_cnt++;
119 return tls_data->notif_hwnd;
122 InitOnceExecuteOnce(&init_once, register_notif_wnd_class, NULL, NULL);
123 if(!notif_wnd_class)
124 return NULL;
126 tls_data->notif_hwnd = CreateWindowExW(0, MAKEINTRESOURCEW(notif_wnd_class),
127 L"URL Moniker Notification Window", 0, 0, 0, 0, 0, HWND_MESSAGE,
128 NULL, hProxyDll, NULL);
129 if(tls_data->notif_hwnd)
130 tls_data->notif_hwnd_cnt++;
132 TRACE("hwnd = %p\n", tls_data->notif_hwnd);
134 return tls_data->notif_hwnd;
137 void release_notif_hwnd(HWND hwnd)
139 tls_data_t *data = get_tls_data();
141 if(!data)
142 return;
144 if(data->notif_hwnd != hwnd) {
145 PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
146 return;
149 if(!--data->notif_hwnd_cnt) {
150 DestroyWindow(data->notif_hwnd);
151 data->notif_hwnd = NULL;
155 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
157 BOOL do_post = FALSE;
159 task->proc = proc;
160 task->next = NULL;
162 EnterCriticalSection(&This->section);
164 if(This->task_queue_tail) {
165 This->task_queue_tail->next = task;
166 This->task_queue_tail = task;
167 }else {
168 This->task_queue_tail = This->task_queue_head = task;
169 do_post = !This->continue_call;
172 LeaveCriticalSection(&This->section);
174 if(do_post) {
175 IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
176 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
180 static inline BOOL is_apartment_thread(BindProtocol *This)
182 return This->apartment_thread == GetCurrentThreadId();
185 static inline BOOL do_direct_notif(BindProtocol *This)
187 return !(This->pi & PI_APARTMENTTHREADED) || (is_apartment_thread(This) && !This->continue_call);
190 static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter)
192 PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 };
193 HRESULT hres;
195 hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&This->protocol_sink_handler);
196 if(FAILED(hres)) {
197 This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
198 return hres;
201 IInternetProtocol_AddRef(mime_filter);
202 This->protocol_handler = mime_filter;
204 filter_data.pProtocol = &This->default_protocol_handler.IInternetProtocol_iface;
205 hres = IInternetProtocol_Start(mime_filter, This->mime, &This->default_protocol_handler.IInternetProtocolSink_iface,
206 &This->IInternetBindInfo_iface, PI_FILTER_MODE|PI_FORCE_ASYNC,
207 (HANDLE_PTR)&filter_data);
208 if(FAILED(hres)) {
209 IInternetProtocolSink_Release(This->protocol_sink_handler);
210 IInternetProtocol_Release(This->protocol_handler);
211 This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
212 This->protocol_handler = &This->default_protocol_handler.IInternetProtocol_iface;
213 return hres;
216 /* NOTE: IE9 calls it on the new protocol_sink. It doesn't make sense so it seems to be a bug there. */
217 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL);
219 return S_OK;
222 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
224 IInternetProtocol *mime_filter;
225 HRESULT hres;
227 heap_free(This->mime);
228 This->mime = heap_strdupW(mime);
230 if(This->protocol_handler==&This->default_protocol_handler.IInternetProtocol_iface
231 && (mime_filter = get_mime_filter(mime))) {
232 TRACE("Got mime filter for %s\n", debugstr_w(mime));
234 hres = handle_mime_filter(This, mime_filter);
235 IInternetProtocol_Release(mime_filter);
236 if(FAILED(hres))
237 FIXME("MIME filter failed: %08x\n", hres);
240 if(This->reported_mime || verified || !(This->pi & PI_MIMEVERIFICATION)) {
241 This->reported_mime = TRUE;
242 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
246 static inline BindProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
248 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolEx_iface);
251 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
253 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
255 *ppv = NULL;
256 if(IsEqualGUID(&IID_IUnknown, riid)) {
257 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
258 *ppv = &This->IInternetProtocolEx_iface;
259 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
260 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
261 *ppv = &This->IInternetProtocolEx_iface;
262 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
263 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
264 *ppv = &This->IInternetProtocolEx_iface;
265 }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
266 TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
267 *ppv = &This->IInternetProtocolEx_iface;
268 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
269 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
270 *ppv = &This->IInternetBindInfo_iface;
271 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
272 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
273 *ppv = &This->IInternetPriority_iface;
274 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
275 FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
276 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
277 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
278 *ppv = &This->IServiceProvider_iface;
279 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
280 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
281 *ppv = &This->IInternetProtocolSink_iface;
282 }else if(This->protocol_unk) {
283 HRESULT hres;
284 hres = IUnknown_QueryInterface(This->protocol_unk, riid, ppv);
285 TRACE("(%p) aggregated handler returned %08x for %s\n", This, hres, debugstr_guid(riid));
286 return hres;
287 }else {
288 WARN("not supported interface %s\n", debugstr_guid(riid));
291 if(!*ppv)
292 return E_NOINTERFACE;
294 IUnknown_AddRef((IUnknown*)*ppv);
295 return S_OK;
298 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocolEx *iface)
300 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
301 LONG ref = InterlockedIncrement(&This->ref);
302 TRACE("(%p) ref=%d\n", This, ref);
303 return ref;
306 static void release_protocol_handler(BindProtocol *This)
308 if(This->protocol) {
309 IInternetProtocol_Release(This->protocol);
310 This->protocol = NULL;
312 if(This->protocol_handler && This->protocol_handler != &This->default_protocol_handler.IInternetProtocol_iface) {
313 IInternetProtocol_Release(This->protocol_handler);
314 This->protocol_handler = &This->default_protocol_handler.IInternetProtocol_iface;
316 if(This->protocol_sink_handler &&
317 This->protocol_sink_handler != &This->default_protocol_handler.IInternetProtocolSink_iface) {
318 IInternetProtocolSink_Release(This->protocol_sink_handler);
319 This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
321 if(This->protocol_unk) {
322 IUnknown_Release(This->protocol_unk);
323 This->protocol_unk = NULL;
327 static ULONG WINAPI BindProtocol_Release(IInternetProtocolEx *iface)
329 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
330 LONG ref = InterlockedDecrement(&This->ref);
332 TRACE("(%p) ref=%d\n", This, ref);
334 if(!ref) {
335 release_protocol_handler(This);
336 if(This->redirect_callback)
337 IBindCallbackRedirect_Release(This->redirect_callback);
338 if(This->bind_info)
339 IInternetBindInfo_Release(This->bind_info);
340 if(This->uri)
341 IUri_Release(This->uri);
342 SysFreeString(This->display_uri);
344 set_binding_sink(This, NULL, NULL);
346 if(This->notif_hwnd)
347 release_notif_hwnd(This->notif_hwnd);
348 This->section.DebugInfo->Spare[0] = 0;
349 DeleteCriticalSection(&This->section);
351 heap_free(This->mime);
352 heap_free(This);
354 URLMON_UnlockModule();
357 return ref;
360 static HRESULT WINAPI BindProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
361 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
362 DWORD grfPI, HANDLE_PTR dwReserved)
364 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
365 IUri *uri;
366 HRESULT hres;
368 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
369 pOIBindInfo, grfPI, dwReserved);
371 hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
372 if(FAILED(hres))
373 return hres;
375 hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
376 pOIBindInfo, grfPI, (HANDLE*)dwReserved);
378 IUri_Release(uri);
379 return hres;
382 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
384 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
386 TRACE("(%p)->(%p)\n", This, pProtocolData);
388 return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
391 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
392 DWORD dwOptions)
394 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
396 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
398 return IInternetProtocol_Abort(This->protocol_handler, hrReason, dwOptions);
401 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
403 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
405 TRACE("(%p)->(%08x)\n", This, dwOptions);
407 return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
410 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocolEx *iface)
412 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
413 FIXME("(%p)\n", This);
414 return E_NOTIMPL;
417 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocolEx *iface)
419 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
420 FIXME("(%p)\n", This);
421 return E_NOTIMPL;
424 static HRESULT WINAPI BindProtocol_Read(IInternetProtocolEx *iface, void *pv,
425 ULONG cb, ULONG *pcbRead)
427 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
429 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
431 if(pcbRead)
432 *pcbRead = 0;
433 return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
436 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
437 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
439 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
440 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
441 return E_NOTIMPL;
444 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
446 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
448 TRACE("(%p)->(%08x)\n", This, dwOptions);
450 return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
453 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocolEx *iface)
455 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
457 TRACE("(%p)\n", This);
459 return IInternetProtocol_UnlockRequest(This->protocol_handler);
462 static HRESULT WINAPI BindProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
463 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
464 DWORD grfPI, HANDLE *dwReserved)
466 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
467 IInternetProtocol *protocol = NULL;
468 IInternetProtocolEx *protocolex;
469 IInternetPriority *priority;
470 IServiceProvider *service_provider;
471 CLSID clsid = IID_NULL;
472 IUnknown *protocol_unk = NULL;
473 LPOLESTR clsid_str;
474 HRESULT hres;
476 TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
478 if(!pUri || !pOIProtSink || !pOIBindInfo)
479 return E_INVALIDARG;
481 This->pi = grfPI;
483 if(This->uri) {
484 SysFreeString(This->display_uri);
485 IUri_Release(This->uri);
487 IUri_AddRef(pUri);
488 This->uri = pUri;
490 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
491 (void**)&service_provider);
492 if(SUCCEEDED(hres)) {
493 /* FIXME: What's protocol CLSID here? */
494 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
495 &IID_IInternetProtocol, (void**)&protocol);
496 IServiceProvider_Release(service_provider);
499 if(!protocol) {
500 IClassFactory *cf;
502 hres = get_protocol_handler(pUri, &clsid, &cf);
503 if(FAILED(hres))
504 return hres;
506 hres = IClassFactory_CreateInstance(cf, (IUnknown*)&This->IInternetBindInfo_iface,
507 &IID_IUnknown, (void**)&protocol_unk);
508 if(SUCCEEDED(hres)) {
509 hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetProtocol, (void**)&protocol);
510 if(SUCCEEDED(hres))
511 This->protocol_unk = protocol_unk;
512 else
513 IUnknown_Release(protocol_unk);
515 else if(hres == CLASS_E_NOAGGREGATION)
516 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
518 IClassFactory_Release(cf);
519 if(FAILED(hres))
520 return hres;
523 StringFromCLSID(&clsid, &clsid_str);
524 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
525 CoTaskMemFree(clsid_str);
527 This->protocol_unk = protocol_unk;
528 This->protocol = protocol;
530 if(!protocol_unk)
531 protocol_unk = (IUnknown*)protocol;
533 set_binding_sink(This, pOIProtSink, pOIBindInfo);
535 hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetPriority, (void**)&priority);
536 if(SUCCEEDED(hres)) {
537 IInternetPriority_SetPriority(priority, This->priority);
538 IInternetPriority_Release(priority);
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;
551 hres = IInternetProtocol_Start(protocol, This->display_uri, &This->IInternetProtocolSink_iface,
552 &This->IInternetBindInfo_iface, 0, 0);
555 if(SUCCEEDED(hres))
556 process_tasks(This);
557 return hres;
560 void set_binding_sink(BindProtocol *This, IInternetProtocolSink *sink, IInternetBindInfo *bind_info)
562 IInternetProtocolSink *prev_sink;
563 IServiceProvider *service_provider = NULL;
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);
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);
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);
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
601 static inline BindProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
603 return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocol_iface);
606 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
608 BindProtocol *This = impl_from_IInternetProtocol(iface);
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;
625 if(*ppv) {
626 IInternetProtocol_AddRef(iface);
627 return S_OK;
630 WARN("not supported interface %s\n", debugstr_guid(riid));
631 return E_NOINTERFACE;
634 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
636 BindProtocol *This = impl_from_IInternetProtocol(iface);
637 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
640 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
642 BindProtocol *This = impl_from_IInternetProtocol(iface);
643 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
646 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
647 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
648 DWORD grfPI, HANDLE_PTR dwReserved)
650 ERR("Should not be called\n");
651 return E_NOTIMPL;
654 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
656 BindProtocol *This = impl_from_IInternetProtocol(iface);
657 IInternetProtocol *protocol = NULL;
658 HRESULT hres;
660 TRACE("(%p)->(%p)\n", This, pProtocolData);
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;
671 hres = IInternetProtocol_Continue(protocol ? protocol : This->protocol, pProtocolData);
673 heap_free(pProtocolData);
674 if(protocol)
675 IInternetProtocol_Release(protocol);
676 return hres;
679 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
680 DWORD dwOptions)
682 BindProtocol *This = impl_from_IInternetProtocol(iface);
684 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
686 if(This->protocol && !This->reported_result)
687 return IInternetProtocol_Abort(This->protocol, hrReason, dwOptions);
689 return S_OK;
692 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
694 BindProtocol *This = impl_from_IInternetProtocol(iface);
696 TRACE("(%p)->(%08x)\n", This, dwOptions);
698 if(!This->reported_result)
699 return E_FAIL;
701 /* This may get released in Terminate call. */
702 IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
704 if(This->protocol) {
705 IInternetProtocol_Terminate(This->protocol, 0);
707 if (This->protocol_unk) {
708 IInternetProtocol_Release(This->protocol);
709 This->protocol = NULL;
713 set_binding_sink(This, NULL, NULL);
715 if(This->bind_info) {
716 IInternetBindInfo_Release(This->bind_info);
717 This->bind_info = NULL;
720 if(This->redirect_callback) {
721 IBindCallbackRedirect_Release(This->redirect_callback);
722 This->redirect_callback = NULL;
725 IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
726 return S_OK;
729 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
731 BindProtocol *This = impl_from_IInternetProtocol(iface);
732 FIXME("(%p)\n", This);
733 return E_NOTIMPL;
736 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
738 BindProtocol *This = impl_from_IInternetProtocol(iface);
739 FIXME("(%p)\n", This);
740 return E_NOTIMPL;
743 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
744 ULONG cb, ULONG *pcbRead)
746 BindProtocol *This = impl_from_IInternetProtocol(iface);
747 ULONG read = 0;
748 HRESULT hres = S_OK;
750 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
752 if(This->buf_size) {
753 read = min(cb, This->buf_size);
754 memcpy(pv, This->buf, read);
756 if(read == This->buf_size) {
757 heap_free(This->buf);
758 This->buf = NULL;
759 }else {
760 memmove(This->buf, This->buf+cb, This->buf_size-cb);
763 This->buf_size -= read;
766 if(read < cb) {
767 IInternetProtocol *protocol;
768 ULONG cread = 0;
770 /* FIXME: We shouldn't need it, but out binding code currently depends on it. */
771 if(!This->protocol && This->protocol_unk) {
772 hres = IUnknown_QueryInterface(This->protocol_unk, &IID_IInternetProtocol,
773 (void**)&protocol);
774 if(FAILED(hres))
775 return E_ABORT;
776 }else {
777 protocol = This->protocol;
780 if(is_apartment_thread(This))
781 This->continue_call++;
782 hres = IInternetProtocol_Read(protocol, (BYTE*)pv+read, cb-read, &cread);
783 if(is_apartment_thread(This))
784 This->continue_call--;
785 read += cread;
787 if(!This->protocol)
788 IInternetProtocol_Release(protocol);
791 *pcbRead = read;
792 return hres;
795 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
796 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
798 BindProtocol *This = impl_from_IInternetProtocol(iface);
799 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
800 return E_NOTIMPL;
803 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
805 BindProtocol *This = impl_from_IInternetProtocol(iface);
807 TRACE("(%p)->(%08x)\n", This, dwOptions);
809 return IInternetProtocol_LockRequest(This->protocol, dwOptions);
812 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
814 BindProtocol *This = impl_from_IInternetProtocol(iface);
816 TRACE("(%p)\n", This);
818 return IInternetProtocol_UnlockRequest(This->protocol);
821 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
822 ProtocolHandler_QueryInterface,
823 ProtocolHandler_AddRef,
824 ProtocolHandler_Release,
825 ProtocolHandler_Start,
826 ProtocolHandler_Continue,
827 ProtocolHandler_Abort,
828 ProtocolHandler_Terminate,
829 ProtocolHandler_Suspend,
830 ProtocolHandler_Resume,
831 ProtocolHandler_Read,
832 ProtocolHandler_Seek,
833 ProtocolHandler_LockRequest,
834 ProtocolHandler_UnlockRequest
837 static inline BindProtocol *impl_from_IInternetProtocolSinkHandler(IInternetProtocolSink *iface)
839 return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocolSink_iface);
842 static HRESULT WINAPI ProtocolSinkHandler_QueryInterface(IInternetProtocolSink *iface,
843 REFIID riid, void **ppvObject)
845 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
846 return IInternetProtocol_QueryInterface(&This->default_protocol_handler.IInternetProtocol_iface,
847 riid, ppvObject);
850 static ULONG WINAPI ProtocolSinkHandler_AddRef(IInternetProtocolSink *iface)
852 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
853 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
856 static ULONG WINAPI ProtocolSinkHandler_Release(IInternetProtocolSink *iface)
858 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
859 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
862 static HRESULT WINAPI ProtocolSinkHandler_Switch(IInternetProtocolSink *iface,
863 PROTOCOLDATA *pProtocolData)
865 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
867 TRACE("(%p)->(%p)\n", This, pProtocolData);
869 if(!This->protocol_sink) {
870 IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
871 return S_OK;
874 return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
877 static HRESULT WINAPI ProtocolSinkHandler_ReportProgress(IInternetProtocolSink *iface,
878 ULONG status_code, LPCWSTR status_text)
880 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
882 TRACE("(%p)->(%s %s)\n", This, debugstr_bindstatus(status_code), debugstr_w(status_text));
884 if(!This->protocol_sink)
885 return S_OK;
887 switch(status_code) {
888 case BINDSTATUS_FINDINGRESOURCE:
889 case BINDSTATUS_CONNECTING:
890 case BINDSTATUS_REDIRECTING:
891 case BINDSTATUS_SENDINGREQUEST:
892 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
893 case BINDSTATUS_DIRECTBIND:
894 case BINDSTATUS_ACCEPTRANGES:
895 case BINDSTATUS_DECODING:
896 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
897 break;
899 case BINDSTATUS_BEGINDOWNLOADDATA:
900 IInternetProtocolSink_ReportData(This->protocol_sink, This->bscf, This->progress, This->progress_max);
901 break;
903 case BINDSTATUS_MIMETYPEAVAILABLE:
904 mime_available(This, status_text, FALSE);
905 break;
907 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
908 mime_available(This, status_text, TRUE);
909 break;
911 default:
912 FIXME("unsupported ulStatusCode %u\n", status_code);
915 return S_OK;
918 static HRESULT WINAPI ProtocolSinkHandler_ReportData(IInternetProtocolSink *iface,
919 DWORD bscf, ULONG progress, ULONG progress_max)
921 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
923 TRACE("(%p)->(%x %u %u)\n", This, bscf, progress, progress_max);
925 This->bscf = bscf;
926 This->progress = progress;
927 This->progress_max = progress_max;
929 if(!This->protocol_sink)
930 return S_OK;
932 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
933 BYTE buf[BUFFER_SIZE];
934 DWORD read = 0;
935 LPWSTR mime;
936 HRESULT hres;
938 do {
939 read = 0;
940 if(is_apartment_thread(This))
941 This->continue_call++;
942 hres = IInternetProtocol_Read(This->protocol, buf,
943 sizeof(buf)-This->buf_size, &read);
944 if(is_apartment_thread(This))
945 This->continue_call--;
946 if(FAILED(hres) && hres != E_PENDING)
947 return hres;
949 if(!This->buf) {
950 This->buf = heap_alloc(BUFFER_SIZE);
951 if(!This->buf)
952 return E_OUTOFMEMORY;
953 }else if(read + This->buf_size > BUFFER_SIZE) {
954 BYTE *tmp;
956 tmp = heap_realloc(This->buf, read+This->buf_size);
957 if(!tmp)
958 return E_OUTOFMEMORY;
959 This->buf = tmp;
962 memcpy(This->buf+This->buf_size, buf, read);
963 This->buf_size += read;
964 }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
966 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
967 return S_OK;
969 bscf = BSCF_FIRSTDATANOTIFICATION;
970 if(hres == S_FALSE)
971 bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
973 if(!This->reported_mime) {
974 BSTR raw_uri;
976 hres = IUri_GetRawUri(This->uri, &raw_uri);
977 if(FAILED(hres))
978 return hres;
980 hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE),
981 This->mime, 0, &mime, 0);
982 SysFreeString(raw_uri);
983 if(FAILED(hres))
984 return hres;
986 heap_free(This->mime);
987 This->mime = heap_strdupW(mime);
988 CoTaskMemFree(mime);
989 This->reported_mime = TRUE;
990 if(This->protocol_sink)
991 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
995 if(!This->protocol_sink)
996 return S_OK;
998 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
1001 static HRESULT handle_redirect(BindProtocol *This, const WCHAR *url)
1003 HRESULT hres;
1005 if(This->redirect_callback) {
1006 VARIANT_BOOL cancel = VARIANT_FALSE;
1007 IBindCallbackRedirect_Redirect(This->redirect_callback, url, &cancel);
1008 if(cancel)
1009 return INET_E_REDIRECT_FAILED;
1012 if(This->protocol_sink) {
1013 hres = IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_REDIRECTING, url);
1014 if(FAILED(hres))
1015 return hres;
1018 IInternetProtocol_Terminate(This->protocol, 0); /* should this be done in StartEx? */
1019 release_protocol_handler(This);
1021 return IInternetProtocolEx_Start(&This->IInternetProtocolEx_iface, url, This->protocol_sink, This->bind_info, This->pi, 0);
1024 static HRESULT WINAPI ProtocolSinkHandler_ReportResult(IInternetProtocolSink *iface,
1025 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1027 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
1029 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1031 if(hrResult == INET_E_REDIRECT_FAILED) {
1032 hrResult = handle_redirect(This, szResult);
1033 if(hrResult == S_OK)
1034 return S_OK;
1035 szResult = NULL;
1038 if(This->protocol_sink)
1039 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1040 return S_OK;
1043 static const IInternetProtocolSinkVtbl InternetProtocolSinkHandlerVtbl = {
1044 ProtocolSinkHandler_QueryInterface,
1045 ProtocolSinkHandler_AddRef,
1046 ProtocolSinkHandler_Release,
1047 ProtocolSinkHandler_Switch,
1048 ProtocolSinkHandler_ReportProgress,
1049 ProtocolSinkHandler_ReportData,
1050 ProtocolSinkHandler_ReportResult
1053 static inline BindProtocol *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
1055 return CONTAINING_RECORD(iface, BindProtocol, IInternetBindInfo_iface);
1058 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
1059 REFIID riid, void **ppv)
1061 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1062 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1065 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
1067 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1068 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1071 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
1073 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1074 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1077 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
1078 DWORD *grfBINDF, BINDINFO *pbindinfo)
1080 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1081 HRESULT hres;
1083 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1085 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
1086 if(FAILED(hres)) {
1087 WARN("GetBindInfo failed: %08x\n", hres);
1088 return hres;
1091 if((pbindinfo->dwOptions & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS) && !This->redirect_callback) {
1092 IServiceProvider *service_provider;
1094 hres = IInternetProtocolSink_QueryInterface(This->protocol_sink, &IID_IServiceProvider, (void**)&service_provider);
1095 if(SUCCEEDED(hres)) {
1096 hres = IServiceProvider_QueryService(service_provider, &IID_IBindCallbackRedirect, &IID_IBindCallbackRedirect,
1097 (void**)&This->redirect_callback);
1098 IServiceProvider_Release(service_provider);
1102 *grfBINDF |= BINDF_FROMURLMON;
1103 return hres;
1106 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
1107 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1109 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1111 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1113 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
1116 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1117 BindInfo_QueryInterface,
1118 BindInfo_AddRef,
1119 BindInfo_Release,
1120 BindInfo_GetBindInfo,
1121 BindInfo_GetBindString
1124 static inline BindProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
1126 return CONTAINING_RECORD(iface, BindProtocol, IInternetPriority_iface);
1129 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
1130 REFIID riid, void **ppv)
1132 BindProtocol *This = impl_from_IInternetPriority(iface);
1133 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1136 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
1138 BindProtocol *This = impl_from_IInternetPriority(iface);
1139 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1142 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
1144 BindProtocol *This = impl_from_IInternetPriority(iface);
1145 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1148 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
1150 BindProtocol *This = impl_from_IInternetPriority(iface);
1152 TRACE("(%p)->(%d)\n", This, nPriority);
1154 This->priority = nPriority;
1155 return S_OK;
1158 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
1160 BindProtocol *This = impl_from_IInternetPriority(iface);
1162 TRACE("(%p)->(%p)\n", This, pnPriority);
1164 *pnPriority = This->priority;
1165 return S_OK;
1168 static const IInternetPriorityVtbl InternetPriorityVtbl = {
1169 InternetPriority_QueryInterface,
1170 InternetPriority_AddRef,
1171 InternetPriority_Release,
1172 InternetPriority_SetPriority,
1173 InternetPriority_GetPriority
1177 static inline BindProtocol *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
1179 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolSink_iface);
1182 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
1183 REFIID riid, void **ppv)
1185 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1186 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1189 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
1191 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1192 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1195 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
1197 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1198 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1201 typedef struct {
1202 task_header_t header;
1203 PROTOCOLDATA *data;
1204 } switch_task_t;
1206 static void switch_proc(BindProtocol *bind, task_header_t *t)
1208 switch_task_t *task = (switch_task_t*)t;
1210 IInternetProtocol_Continue(bind->protocol_handler, task->data);
1212 heap_free(task);
1215 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
1216 PROTOCOLDATA *pProtocolData)
1218 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1219 PROTOCOLDATA *data;
1221 TRACE("(%p)->(%p)\n", This, pProtocolData);
1223 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
1224 pProtocolData->pData, pProtocolData->cbData);
1226 data = heap_alloc(sizeof(PROTOCOLDATA));
1227 if(!data)
1228 return E_OUTOFMEMORY;
1229 memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
1231 if((This->pi&PI_APARTMENTTHREADED && pProtocolData->grfFlags&PI_FORCE_ASYNC)
1232 || !do_direct_notif(This)) {
1233 switch_task_t *task;
1235 task = heap_alloc(sizeof(switch_task_t));
1236 if(!task)
1238 heap_free(data);
1239 return E_OUTOFMEMORY;
1242 task->data = data;
1244 push_task(This, &task->header, switch_proc);
1245 return S_OK;
1248 return IInternetProtocolSink_Switch(This->protocol_sink_handler, data);
1251 typedef struct {
1252 task_header_t header;
1254 ULONG status_code;
1255 LPWSTR status_text;
1256 } on_progress_task_t;
1258 static void on_progress_proc(BindProtocol *This, task_header_t *t)
1260 on_progress_task_t *task = (on_progress_task_t*)t;
1262 IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, task->status_code, task->status_text);
1264 heap_free(task->status_text);
1265 heap_free(task);
1268 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
1269 ULONG ulStatusCode, LPCWSTR szStatusText)
1271 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1273 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
1275 if(do_direct_notif(This)) {
1276 IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, ulStatusCode, szStatusText);
1277 }else {
1278 on_progress_task_t *task;
1280 task = heap_alloc(sizeof(on_progress_task_t));
1282 task->status_code = ulStatusCode;
1283 task->status_text = heap_strdupW(szStatusText);
1285 push_task(This, &task->header, on_progress_proc);
1288 return S_OK;
1291 typedef struct {
1292 task_header_t header;
1293 DWORD bscf;
1294 ULONG progress;
1295 ULONG progress_max;
1296 } report_data_task_t;
1298 static void report_data_proc(BindProtocol *This, task_header_t *t)
1300 report_data_task_t *task = (report_data_task_t*)t;
1302 IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1303 task->bscf, task->progress, task->progress_max);
1305 heap_free(task);
1308 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1309 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1311 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1313 TRACE("(%p)->(%x %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1315 if(!This->protocol_sink)
1316 return S_OK;
1318 if(!do_direct_notif(This)) {
1319 report_data_task_t *task;
1321 task = heap_alloc(sizeof(report_data_task_t));
1322 if(!task)
1323 return E_OUTOFMEMORY;
1325 task->bscf = grfBSCF;
1326 task->progress = ulProgress;
1327 task->progress_max = ulProgressMax;
1329 push_task(This, &task->header, report_data_proc);
1330 return S_OK;
1333 return IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1334 grfBSCF, ulProgress, ulProgressMax);
1337 typedef struct {
1338 task_header_t header;
1340 HRESULT hres;
1341 DWORD err;
1342 LPWSTR str;
1343 } report_result_task_t;
1345 static void report_result_proc(BindProtocol *This, task_header_t *t)
1347 report_result_task_t *task = (report_result_task_t*)t;
1349 IInternetProtocolSink_ReportResult(This->protocol_sink_handler, task->hres, task->err, task->str);
1351 heap_free(task->str);
1352 heap_free(task);
1355 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1356 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1358 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1360 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1362 if(!This->protocol_sink)
1363 return E_FAIL;
1364 This->reported_result = TRUE;
1366 if(!do_direct_notif(This)) {
1367 report_result_task_t *task;
1369 task = heap_alloc(sizeof(report_result_task_t));
1370 if(!task)
1371 return E_OUTOFMEMORY;
1373 task->hres = hrResult;
1374 task->err = dwError;
1375 task->str = heap_strdupW(szResult);
1377 push_task(This, &task->header, report_result_proc);
1378 return S_OK;
1381 return IInternetProtocolSink_ReportResult(This->protocol_sink_handler, hrResult, dwError, szResult);
1384 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1385 BPInternetProtocolSink_QueryInterface,
1386 BPInternetProtocolSink_AddRef,
1387 BPInternetProtocolSink_Release,
1388 BPInternetProtocolSink_Switch,
1389 BPInternetProtocolSink_ReportProgress,
1390 BPInternetProtocolSink_ReportData,
1391 BPInternetProtocolSink_ReportResult
1394 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface)
1396 return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface);
1399 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1400 REFIID riid, void **ppv)
1402 BindProtocol *This = impl_from_IServiceProvider(iface);
1403 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1406 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1408 BindProtocol *This = impl_from_IServiceProvider(iface);
1409 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1412 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1414 BindProtocol *This = impl_from_IServiceProvider(iface);
1415 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1418 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1419 REFGUID guidService, REFIID riid, void **ppv)
1421 BindProtocol *This = impl_from_IServiceProvider(iface);
1423 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1425 if(!This->service_provider)
1426 return E_NOINTERFACE;
1428 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1431 static const IServiceProviderVtbl ServiceProviderVtbl = {
1432 BPServiceProvider_QueryInterface,
1433 BPServiceProvider_AddRef,
1434 BPServiceProvider_Release,
1435 BPServiceProvider_QueryService
1438 HRESULT create_binding_protocol(BindProtocol **protocol)
1440 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1442 ret->IInternetProtocolEx_iface.lpVtbl = &BindProtocolVtbl;
1443 ret->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
1444 ret->IInternetPriority_iface.lpVtbl = &InternetPriorityVtbl;
1445 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
1446 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
1448 ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
1449 ret->default_protocol_handler.IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkHandlerVtbl;
1451 ret->ref = 1;
1452 ret->apartment_thread = GetCurrentThreadId();
1453 ret->notif_hwnd = get_notif_hwnd();
1454 ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
1455 ret->protocol_sink_handler = &ret->default_protocol_handler.IInternetProtocolSink_iface;
1456 InitializeCriticalSection(&ret->section);
1457 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BindProtocol.section");
1459 URLMON_LockModule();
1461 *protocol = ret;
1462 return S_OK;