dinput: Clear DIA_APPNOMAP BuildActionMap flag with specific device semantic.
[wine.git] / dlls / urlmon / bindprot.c
blobb09acdd5c3ab207625ad2e638eea475baf282d5c
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 free(This->mime);
228 This->mime = wcsdup(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: %08lx\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 %08lx 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=%ld\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=%ld\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 free(This->mime);
352 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 %08lx %Ix)\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)->(%08lx %08lx)\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)->(%08lx)\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 %lu %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)->(%ld %ld %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)->(%08lx)\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 %08lx %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 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)->(%08lx %08lx)\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)->(%08lx)\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 %lu %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 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)->(%ld %ld %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)->(%08lx)\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 %lu\n", status_code);
915 return S_OK;
918 static HRESULT report_data(BindProtocol *This)
920 DWORD bscf = This->bscf;
921 HRESULT hres;
923 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
924 BYTE buf[BUFFER_SIZE];
925 DWORD read = 0;
926 LPWSTR mime;
928 do {
929 read = 0;
930 hres = IInternetProtocol_Read(This->protocol, buf,
931 sizeof(buf)-This->buf_size, &read);
932 if(FAILED(hres) && hres != E_PENDING)
933 return hres;
935 if(!This->buf) {
936 This->buf = malloc(BUFFER_SIZE);
937 if(!This->buf)
938 return E_OUTOFMEMORY;
939 }else if(read + This->buf_size > BUFFER_SIZE) {
940 BYTE *tmp;
942 tmp = realloc(This->buf, read + This->buf_size);
943 if(!tmp)
944 return E_OUTOFMEMORY;
945 This->buf = tmp;
948 memcpy(This->buf+This->buf_size, buf, read);
949 This->buf_size += read;
950 }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
952 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
953 return S_OK;
955 bscf = BSCF_FIRSTDATANOTIFICATION;
956 if(hres == S_FALSE)
957 bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
959 if(!This->reported_mime) {
960 BSTR raw_uri;
962 hres = IUri_GetRawUri(This->uri, &raw_uri);
963 if(FAILED(hres))
964 return hres;
966 hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE),
967 This->mime, 0, &mime, 0);
968 SysFreeString(raw_uri);
969 if(FAILED(hres))
970 return hres;
972 free(This->mime);
973 This->mime = wcsdup(mime);
974 CoTaskMemFree(mime);
975 This->reported_mime = TRUE;
976 if(This->protocol_sink)
977 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
981 if(!This->protocol_sink)
982 return S_OK;
984 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, This->progress, This->progress_max);
987 static HRESULT WINAPI ProtocolSinkHandler_ReportData(IInternetProtocolSink *iface,
988 DWORD bscf, ULONG progress, ULONG progress_max)
990 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
991 HRESULT hres;
993 TRACE("(%p)->(%lx %lu %lu)\n", This, bscf, progress, progress_max);
995 This->bscf = bscf;
996 This->progress = progress;
997 This->progress_max = progress_max;
999 if(!This->protocol_sink)
1000 return S_OK;
1002 if(is_apartment_thread(This))
1003 This->continue_call++;
1005 hres = report_data(This);
1007 if(is_apartment_thread(This)) {
1008 This->continue_call--;
1009 process_tasks(This);
1011 return hres;
1014 static HRESULT handle_redirect(BindProtocol *This, const WCHAR *url)
1016 HRESULT hres;
1018 if(This->redirect_callback) {
1019 VARIANT_BOOL cancel = VARIANT_FALSE;
1020 IBindCallbackRedirect_Redirect(This->redirect_callback, url, &cancel);
1021 if(cancel)
1022 return INET_E_REDIRECT_FAILED;
1025 if(This->protocol_sink) {
1026 hres = IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_REDIRECTING, url);
1027 if(FAILED(hres))
1028 return hres;
1031 IInternetProtocol_Terminate(This->protocol, 0); /* should this be done in StartEx? */
1032 release_protocol_handler(This);
1034 return IInternetProtocolEx_Start(&This->IInternetProtocolEx_iface, url, This->protocol_sink, This->bind_info, This->pi, 0);
1037 static HRESULT WINAPI ProtocolSinkHandler_ReportResult(IInternetProtocolSink *iface,
1038 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1040 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
1042 TRACE("(%p)->(%08lx %ld %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1044 if(hrResult == INET_E_REDIRECT_FAILED) {
1045 hrResult = handle_redirect(This, szResult);
1046 if(hrResult == S_OK)
1047 return S_OK;
1048 szResult = NULL;
1051 if(This->protocol_sink)
1052 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1053 return S_OK;
1056 static const IInternetProtocolSinkVtbl InternetProtocolSinkHandlerVtbl = {
1057 ProtocolSinkHandler_QueryInterface,
1058 ProtocolSinkHandler_AddRef,
1059 ProtocolSinkHandler_Release,
1060 ProtocolSinkHandler_Switch,
1061 ProtocolSinkHandler_ReportProgress,
1062 ProtocolSinkHandler_ReportData,
1063 ProtocolSinkHandler_ReportResult
1066 static inline BindProtocol *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
1068 return CONTAINING_RECORD(iface, BindProtocol, IInternetBindInfo_iface);
1071 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
1072 REFIID riid, void **ppv)
1074 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1075 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1078 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
1080 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1081 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1084 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
1086 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1087 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1090 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
1091 DWORD *grfBINDF, BINDINFO *pbindinfo)
1093 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1094 HRESULT hres;
1096 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1098 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
1099 if(FAILED(hres)) {
1100 WARN("GetBindInfo failed: %08lx\n", hres);
1101 return hres;
1104 if((pbindinfo->dwOptions & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS) && !This->redirect_callback) {
1105 IServiceProvider *service_provider;
1107 hres = IInternetProtocolSink_QueryInterface(This->protocol_sink, &IID_IServiceProvider, (void**)&service_provider);
1108 if(SUCCEEDED(hres)) {
1109 hres = IServiceProvider_QueryService(service_provider, &IID_IBindCallbackRedirect, &IID_IBindCallbackRedirect,
1110 (void**)&This->redirect_callback);
1111 IServiceProvider_Release(service_provider);
1115 *grfBINDF |= BINDF_FROMURLMON;
1116 return hres;
1119 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
1120 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1122 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1124 TRACE("(%p)->(%ld %p %ld %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1126 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
1129 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1130 BindInfo_QueryInterface,
1131 BindInfo_AddRef,
1132 BindInfo_Release,
1133 BindInfo_GetBindInfo,
1134 BindInfo_GetBindString
1137 static inline BindProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
1139 return CONTAINING_RECORD(iface, BindProtocol, IInternetPriority_iface);
1142 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
1143 REFIID riid, void **ppv)
1145 BindProtocol *This = impl_from_IInternetPriority(iface);
1146 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1149 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
1151 BindProtocol *This = impl_from_IInternetPriority(iface);
1152 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1155 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
1157 BindProtocol *This = impl_from_IInternetPriority(iface);
1158 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1161 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
1163 BindProtocol *This = impl_from_IInternetPriority(iface);
1165 TRACE("(%p)->(%ld)\n", This, nPriority);
1167 This->priority = nPriority;
1168 return S_OK;
1171 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
1173 BindProtocol *This = impl_from_IInternetPriority(iface);
1175 TRACE("(%p)->(%p)\n", This, pnPriority);
1177 *pnPriority = This->priority;
1178 return S_OK;
1181 static const IInternetPriorityVtbl InternetPriorityVtbl = {
1182 InternetPriority_QueryInterface,
1183 InternetPriority_AddRef,
1184 InternetPriority_Release,
1185 InternetPriority_SetPriority,
1186 InternetPriority_GetPriority
1190 static inline BindProtocol *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
1192 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolSink_iface);
1195 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
1196 REFIID riid, void **ppv)
1198 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1199 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1202 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
1204 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1205 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1208 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
1210 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1211 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1214 typedef struct {
1215 task_header_t header;
1216 PROTOCOLDATA *data;
1217 } switch_task_t;
1219 static void switch_proc(BindProtocol *bind, task_header_t *t)
1221 switch_task_t *task = (switch_task_t*)t;
1223 IInternetProtocol_Continue(bind->protocol_handler, task->data);
1225 free(task);
1228 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
1229 PROTOCOLDATA *pProtocolData)
1231 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1232 PROTOCOLDATA *data;
1234 TRACE("(%p)->(%p)\n", This, pProtocolData);
1236 TRACE("flags %lx state %lx data %p cb %lu\n", pProtocolData->grfFlags, pProtocolData->dwState,
1237 pProtocolData->pData, pProtocolData->cbData);
1239 data = malloc(sizeof(PROTOCOLDATA));
1240 if(!data)
1241 return E_OUTOFMEMORY;
1242 memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
1244 if((This->pi&PI_APARTMENTTHREADED && pProtocolData->grfFlags&PI_FORCE_ASYNC)
1245 || !do_direct_notif(This)) {
1246 switch_task_t *task;
1248 task = malloc(sizeof(switch_task_t));
1249 if(!task)
1251 free(data);
1252 return E_OUTOFMEMORY;
1255 task->data = data;
1257 push_task(This, &task->header, switch_proc);
1258 return S_OK;
1261 return IInternetProtocolSink_Switch(This->protocol_sink_handler, data);
1264 typedef struct {
1265 task_header_t header;
1267 ULONG status_code;
1268 LPWSTR status_text;
1269 } on_progress_task_t;
1271 static void on_progress_proc(BindProtocol *This, task_header_t *t)
1273 on_progress_task_t *task = (on_progress_task_t*)t;
1275 IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, task->status_code, task->status_text);
1277 free(task->status_text);
1278 free(task);
1281 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
1282 ULONG ulStatusCode, LPCWSTR szStatusText)
1284 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1286 TRACE("(%p)->(%lu %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
1288 if(do_direct_notif(This)) {
1289 IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, ulStatusCode, szStatusText);
1290 }else {
1291 on_progress_task_t *task;
1293 task = malloc(sizeof(on_progress_task_t));
1295 task->status_code = ulStatusCode;
1296 task->status_text = wcsdup(szStatusText);
1298 push_task(This, &task->header, on_progress_proc);
1301 return S_OK;
1304 typedef struct {
1305 task_header_t header;
1306 DWORD bscf;
1307 ULONG progress;
1308 ULONG progress_max;
1309 } report_data_task_t;
1311 static void report_data_proc(BindProtocol *This, task_header_t *t)
1313 report_data_task_t *task = (report_data_task_t*)t;
1315 IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1316 task->bscf, task->progress, task->progress_max);
1318 free(task);
1321 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1322 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1324 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1326 TRACE("(%p)->(%lx %lu %lu)\n", This, grfBSCF, ulProgress, ulProgressMax);
1328 if(!This->protocol_sink)
1329 return S_OK;
1331 if(!do_direct_notif(This)) {
1332 report_data_task_t *task;
1334 task = malloc(sizeof(report_data_task_t));
1335 if(!task)
1336 return E_OUTOFMEMORY;
1338 task->bscf = grfBSCF;
1339 task->progress = ulProgress;
1340 task->progress_max = ulProgressMax;
1342 push_task(This, &task->header, report_data_proc);
1343 return S_OK;
1346 return IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1347 grfBSCF, ulProgress, ulProgressMax);
1350 typedef struct {
1351 task_header_t header;
1353 HRESULT hres;
1354 DWORD err;
1355 LPWSTR str;
1356 } report_result_task_t;
1358 static void report_result_proc(BindProtocol *This, task_header_t *t)
1360 report_result_task_t *task = (report_result_task_t*)t;
1362 IInternetProtocolSink_ReportResult(This->protocol_sink_handler, task->hres, task->err, task->str);
1364 free(task->str);
1365 free(task);
1368 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1369 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1371 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1373 TRACE("(%p)->(%08lx %ld %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1375 if(!This->protocol_sink)
1376 return E_FAIL;
1377 This->reported_result = TRUE;
1379 if(!do_direct_notif(This)) {
1380 report_result_task_t *task;
1382 task = malloc(sizeof(report_result_task_t));
1383 if(!task)
1384 return E_OUTOFMEMORY;
1386 task->hres = hrResult;
1387 task->err = dwError;
1388 task->str = wcsdup(szResult);
1390 push_task(This, &task->header, report_result_proc);
1391 return S_OK;
1394 return IInternetProtocolSink_ReportResult(This->protocol_sink_handler, hrResult, dwError, szResult);
1397 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1398 BPInternetProtocolSink_QueryInterface,
1399 BPInternetProtocolSink_AddRef,
1400 BPInternetProtocolSink_Release,
1401 BPInternetProtocolSink_Switch,
1402 BPInternetProtocolSink_ReportProgress,
1403 BPInternetProtocolSink_ReportData,
1404 BPInternetProtocolSink_ReportResult
1407 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface)
1409 return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface);
1412 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1413 REFIID riid, void **ppv)
1415 BindProtocol *This = impl_from_IServiceProvider(iface);
1416 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1419 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1421 BindProtocol *This = impl_from_IServiceProvider(iface);
1422 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1425 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1427 BindProtocol *This = impl_from_IServiceProvider(iface);
1428 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1431 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1432 REFGUID guidService, REFIID riid, void **ppv)
1434 BindProtocol *This = impl_from_IServiceProvider(iface);
1436 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1438 if(!This->service_provider)
1439 return E_NOINTERFACE;
1441 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1444 static const IServiceProviderVtbl ServiceProviderVtbl = {
1445 BPServiceProvider_QueryInterface,
1446 BPServiceProvider_AddRef,
1447 BPServiceProvider_Release,
1448 BPServiceProvider_QueryService
1451 HRESULT create_binding_protocol(BindProtocol **protocol)
1453 BindProtocol *ret = calloc(1, sizeof(BindProtocol));
1455 ret->IInternetProtocolEx_iface.lpVtbl = &BindProtocolVtbl;
1456 ret->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
1457 ret->IInternetPriority_iface.lpVtbl = &InternetPriorityVtbl;
1458 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
1459 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
1461 ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
1462 ret->default_protocol_handler.IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkHandlerVtbl;
1464 ret->ref = 1;
1465 ret->apartment_thread = GetCurrentThreadId();
1466 ret->notif_hwnd = get_notif_hwnd();
1467 ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
1468 ret->protocol_sink_handler = &ret->default_protocol_handler.IInternetProtocolSink_iface;
1469 InitializeCriticalSection(&ret->section);
1470 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BindProtocol.section");
1472 URLMON_LockModule();
1474 *protocol = ret;
1475 return S_OK;