ddraw/tests: Add another invalid arguments test for surface QI.
[wine.git] / dlls / urlmon / bindprot.c
blob47c972b1e3e840f526bea9cfc7444b64e4919c1d
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 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};
90 static ATOM notif_wnd_class;
92 static BOOL WINAPI register_notif_wnd_class(INIT_ONCE *once, void *param, void **context)
94 static WNDCLASSEXW wndclass = {
95 sizeof(wndclass), 0, notif_wnd_proc, 0, 0,
96 NULL, NULL, NULL, NULL, NULL,
97 wszURLMonikerNotificationWindow, NULL
100 wndclass.hInstance = hProxyDll;
101 notif_wnd_class = RegisterClassExW(&wndclass);
102 return TRUE;
105 void unregister_notif_wnd_class(void)
107 if(notif_wnd_class)
108 UnregisterClassW(MAKEINTRESOURCEW(notif_wnd_class), hProxyDll);
111 HWND get_notif_hwnd(void)
113 tls_data_t *tls_data;
115 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
117 tls_data = get_tls_data();
118 if(!tls_data)
119 return NULL;
121 if(tls_data->notif_hwnd_cnt) {
122 tls_data->notif_hwnd_cnt++;
123 return tls_data->notif_hwnd;
126 InitOnceExecuteOnce(&init_once, register_notif_wnd_class, NULL, NULL);
127 if(!notif_wnd_class)
128 return NULL;
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++;
136 TRACE("hwnd = %p\n", tls_data->notif_hwnd);
138 return tls_data->notif_hwnd;
141 void release_notif_hwnd(HWND hwnd)
143 tls_data_t *data = get_tls_data();
145 if(!data)
146 return;
148 if(data->notif_hwnd != hwnd) {
149 PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
150 return;
153 if(!--data->notif_hwnd_cnt) {
154 DestroyWindow(data->notif_hwnd);
155 data->notif_hwnd = NULL;
159 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
161 BOOL do_post = FALSE;
163 task->proc = proc;
164 task->next = NULL;
166 EnterCriticalSection(&This->section);
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;
176 LeaveCriticalSection(&This->section);
178 if(do_post) {
179 IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
180 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
184 static inline BOOL is_apartment_thread(BindProtocol *This)
186 return This->apartment_thread == GetCurrentThreadId();
189 static inline BOOL do_direct_notif(BindProtocol *This)
191 return !(This->pi & PI_APARTMENTTHREADED) || (is_apartment_thread(This) && !This->continue_call);
194 static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter)
196 PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 };
197 HRESULT hres;
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;
205 IInternetProtocol_AddRef(mime_filter);
206 This->protocol_handler = mime_filter;
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;
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);
223 return S_OK;
226 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
228 IInternetProtocol *mime_filter;
229 HRESULT hres;
231 heap_free(This->mime);
232 This->mime = heap_strdupW(mime);
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));
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);
244 if(This->reported_mime || verified || !(This->pi & PI_MIMEVERIFICATION)) {
245 This->reported_mime = TRUE;
246 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
250 static inline BindProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
252 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolEx_iface);
255 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
257 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
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(IsEqualGUID(&IID_IWinInetInfo, riid)) {
287 TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
289 if(This->protocol) {
290 IWinInetInfo *inet_info;
291 HRESULT hres;
293 hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetInfo, (void**)&inet_info);
294 if(SUCCEEDED(hres)) {
295 *ppv = &This->IWinInetHttpInfo_iface;
296 IWinInetInfo_Release(inet_info);
299 }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
300 TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv);
302 if(This->protocol) {
303 IWinInetHttpInfo *http_info;
304 HRESULT hres;
306 hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetHttpInfo, (void**)&http_info);
307 if(SUCCEEDED(hres)) {
308 *ppv = &This->IWinInetHttpInfo_iface;
309 IWinInetHttpInfo_Release(http_info);
312 }else {
313 WARN("not supported interface %s\n", debugstr_guid(riid));
316 if(!*ppv)
317 return E_NOINTERFACE;
319 IUnknown_AddRef((IUnknown*)*ppv);
320 return S_OK;
323 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocolEx *iface)
325 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
326 LONG ref = InterlockedIncrement(&This->ref);
327 TRACE("(%p) ref=%d\n", This, ref);
328 return ref;
331 static void release_protocol_handler(BindProtocol *This)
333 if(This->wininet_info) {
334 IWinInetInfo_Release(This->wininet_info);
335 This->wininet_info = NULL;
337 if(This->wininet_http_info) {
338 IWinInetHttpInfo_Release(This->wininet_http_info);
339 This->wininet_http_info = NULL;
341 if(This->protocol) {
342 IInternetProtocol_Release(This->protocol);
343 This->protocol = NULL;
345 if(This->protocol_handler && This->protocol_handler != &This->default_protocol_handler.IInternetProtocol_iface) {
346 IInternetProtocol_Release(This->protocol_handler);
347 This->protocol_handler = &This->default_protocol_handler.IInternetProtocol_iface;
349 if(This->protocol_sink_handler &&
350 This->protocol_sink_handler != &This->default_protocol_handler.IInternetProtocolSink_iface) {
351 IInternetProtocolSink_Release(This->protocol_sink_handler);
352 This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
356 static ULONG WINAPI BindProtocol_Release(IInternetProtocolEx *iface)
358 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
359 LONG ref = InterlockedDecrement(&This->ref);
361 TRACE("(%p) ref=%d\n", This, ref);
363 if(!ref) {
364 release_protocol_handler(This);
365 if(This->redirect_callback)
366 IBindCallbackRedirect_Release(This->redirect_callback);
367 if(This->bind_info)
368 IInternetBindInfo_Release(This->bind_info);
369 if(This->uri)
370 IUri_Release(This->uri);
371 SysFreeString(This->display_uri);
373 set_binding_sink(This, NULL, NULL);
375 if(This->notif_hwnd)
376 release_notif_hwnd(This->notif_hwnd);
377 This->section.DebugInfo->Spare[0] = 0;
378 DeleteCriticalSection(&This->section);
380 heap_free(This->mime);
381 heap_free(This);
383 URLMON_UnlockModule();
386 return ref;
389 static HRESULT WINAPI BindProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
390 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
391 DWORD grfPI, HANDLE_PTR dwReserved)
393 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
394 IUri *uri;
395 HRESULT hres;
397 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
398 pOIBindInfo, grfPI, dwReserved);
400 hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
401 if(FAILED(hres))
402 return hres;
404 hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
405 pOIBindInfo, grfPI, (HANDLE*)dwReserved);
407 IUri_Release(uri);
408 return hres;
411 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
413 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
415 TRACE("(%p)->(%p)\n", This, pProtocolData);
417 return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
420 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
421 DWORD dwOptions)
423 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
425 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
427 return IInternetProtocol_Abort(This->protocol_handler, hrReason, dwOptions);
430 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
432 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
434 TRACE("(%p)->(%08x)\n", This, dwOptions);
436 return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
439 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocolEx *iface)
441 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
442 FIXME("(%p)\n", This);
443 return E_NOTIMPL;
446 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocolEx *iface)
448 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
449 FIXME("(%p)\n", This);
450 return E_NOTIMPL;
453 static HRESULT WINAPI BindProtocol_Read(IInternetProtocolEx *iface, void *pv,
454 ULONG cb, ULONG *pcbRead)
456 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
458 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
460 if(pcbRead)
461 *pcbRead = 0;
462 return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
465 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
466 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
468 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
469 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
470 return E_NOTIMPL;
473 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
475 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
477 TRACE("(%p)->(%08x)\n", This, dwOptions);
479 return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
482 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocolEx *iface)
484 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
486 TRACE("(%p)\n", This);
488 return IInternetProtocol_UnlockRequest(This->protocol_handler);
491 static HRESULT WINAPI BindProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
492 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
493 DWORD grfPI, HANDLE *dwReserved)
495 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
496 IInternetProtocol *protocol = NULL;
497 IInternetProtocolEx *protocolex;
498 IInternetPriority *priority;
499 IServiceProvider *service_provider;
500 BOOL urlmon_protocol = FALSE;
501 CLSID clsid = IID_NULL;
502 LPOLESTR clsid_str;
503 HRESULT hres;
505 TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
507 if(!pUri || !pOIProtSink || !pOIBindInfo)
508 return E_INVALIDARG;
510 This->pi = grfPI;
512 if(This->uri) {
513 SysFreeString(This->display_uri);
514 IUri_Release(This->uri);
516 IUri_AddRef(pUri);
517 This->uri = pUri;
519 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
520 (void**)&service_provider);
521 if(SUCCEEDED(hres)) {
522 /* FIXME: What's protocol CLSID here? */
523 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
524 &IID_IInternetProtocol, (void**)&protocol);
525 IServiceProvider_Release(service_provider);
528 if(!protocol) {
529 IClassFactory *cf;
530 IUnknown *unk;
532 hres = get_protocol_handler(pUri, &clsid, &urlmon_protocol, &cf);
533 if(FAILED(hres))
534 return hres;
536 if(This->from_urlmon) {
537 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
538 IClassFactory_Release(cf);
539 if(FAILED(hres))
540 return hres;
541 }else {
542 hres = IClassFactory_CreateInstance(cf, (IUnknown*)&This->IInternetBindInfo_iface,
543 &IID_IUnknown, (void**)&unk);
544 IClassFactory_Release(cf);
545 if(FAILED(hres))
546 return hres;
548 hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
549 IUnknown_Release(unk);
550 if(FAILED(hres))
551 return hres;
555 StringFromCLSID(&clsid, &clsid_str);
556 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
557 CoTaskMemFree(clsid_str);
559 This->protocol = protocol;
561 if(urlmon_protocol) {
562 IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
563 IInternetProtocol_QueryInterface(protocol, &IID_IWinInetHttpInfo, (void**)&This->wininet_http_info);
566 set_binding_sink(This, pOIProtSink, pOIBindInfo);
568 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
569 if(SUCCEEDED(hres)) {
570 IInternetPriority_SetPriority(priority, This->priority);
571 IInternetPriority_Release(priority);
574 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolEx, (void**)&protocolex);
575 if(SUCCEEDED(hres)) {
576 hres = IInternetProtocolEx_StartEx(protocolex, pUri, &This->IInternetProtocolSink_iface,
577 &This->IInternetBindInfo_iface, 0, NULL);
578 IInternetProtocolEx_Release(protocolex);
579 }else {
580 hres = IUri_GetDisplayUri(pUri, &This->display_uri);
581 if(FAILED(hres))
582 return hres;
584 hres = IInternetProtocol_Start(protocol, This->display_uri, &This->IInternetProtocolSink_iface,
585 &This->IInternetBindInfo_iface, 0, 0);
588 if(SUCCEEDED(hres))
589 process_tasks(This);
590 return hres;
593 void set_binding_sink(BindProtocol *This, IInternetProtocolSink *sink, IInternetBindInfo *bind_info)
595 IInternetProtocolSink *prev_sink;
596 IServiceProvider *service_provider = NULL;
598 if(sink)
599 IInternetProtocolSink_AddRef(sink);
600 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
601 if(prev_sink)
602 IInternetProtocolSink_Release(prev_sink);
604 if(sink)
605 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
606 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
607 if(service_provider)
608 IServiceProvider_Release(service_provider);
610 if(bind_info)
611 IInternetBindInfo_AddRef(bind_info);
612 bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info);
613 if(bind_info)
614 IInternetBindInfo_Release(bind_info);
617 static const IInternetProtocolExVtbl BindProtocolVtbl = {
618 BindProtocol_QueryInterface,
619 BindProtocol_AddRef,
620 BindProtocol_Release,
621 BindProtocol_Start,
622 BindProtocol_Continue,
623 BindProtocol_Abort,
624 BindProtocol_Terminate,
625 BindProtocol_Suspend,
626 BindProtocol_Resume,
627 BindProtocol_Read,
628 BindProtocol_Seek,
629 BindProtocol_LockRequest,
630 BindProtocol_UnlockRequest,
631 BindProtocol_StartEx
634 static inline BindProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
636 return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocol_iface);
639 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
641 BindProtocol *This = impl_from_IInternetProtocol(iface);
643 *ppv = NULL;
644 if(IsEqualGUID(&IID_IUnknown, riid)) {
645 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
646 *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
647 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
648 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
649 *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
650 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
651 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
652 *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
653 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
654 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
655 *ppv = &This->default_protocol_handler.IInternetProtocolSink_iface;
658 if(*ppv) {
659 IInternetProtocol_AddRef(iface);
660 return S_OK;
663 WARN("not supported interface %s\n", debugstr_guid(riid));
664 return E_NOINTERFACE;
667 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
669 BindProtocol *This = impl_from_IInternetProtocol(iface);
670 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
673 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
675 BindProtocol *This = impl_from_IInternetProtocol(iface);
676 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
679 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
680 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
681 DWORD grfPI, HANDLE_PTR dwReserved)
683 ERR("Should not be called\n");
684 return E_NOTIMPL;
687 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
689 BindProtocol *This = impl_from_IInternetProtocol(iface);
690 HRESULT hres;
692 TRACE("(%p)->(%p)\n", This, pProtocolData);
694 hres = IInternetProtocol_Continue(This->protocol, pProtocolData);
696 heap_free(pProtocolData);
697 return hres;
700 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
701 DWORD dwOptions)
703 BindProtocol *This = impl_from_IInternetProtocol(iface);
705 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
707 if(This->protocol && !This->reported_result)
708 return IInternetProtocol_Abort(This->protocol, hrReason, dwOptions);
710 return S_OK;
713 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
715 BindProtocol *This = impl_from_IInternetProtocol(iface);
717 TRACE("(%p)->(%08x)\n", This, dwOptions);
719 if(!This->reported_result)
720 return E_FAIL;
722 /* This may get released in Terminate call. */
723 IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
725 IInternetProtocol_Terminate(This->protocol, 0);
727 set_binding_sink(This, NULL, NULL);
729 if(This->bind_info) {
730 IInternetBindInfo_Release(This->bind_info);
731 This->bind_info = NULL;
734 if(This->redirect_callback) {
735 IBindCallbackRedirect_Release(This->redirect_callback);
736 This->redirect_callback = NULL;
739 IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
740 return S_OK;
743 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
745 BindProtocol *This = impl_from_IInternetProtocol(iface);
746 FIXME("(%p)\n", This);
747 return E_NOTIMPL;
750 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
752 BindProtocol *This = impl_from_IInternetProtocol(iface);
753 FIXME("(%p)\n", This);
754 return E_NOTIMPL;
757 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
758 ULONG cb, ULONG *pcbRead)
760 BindProtocol *This = impl_from_IInternetProtocol(iface);
761 ULONG read = 0;
762 HRESULT hres = S_OK;
764 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
766 if(This->buf_size) {
767 read = min(cb, This->buf_size);
768 memcpy(pv, This->buf, read);
770 if(read == This->buf_size) {
771 heap_free(This->buf);
772 This->buf = NULL;
773 }else {
774 memmove(This->buf, This->buf+cb, This->buf_size-cb);
777 This->buf_size -= read;
780 if(read < cb) {
781 ULONG cread = 0;
783 if(is_apartment_thread(This))
784 This->continue_call++;
785 hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
786 if(is_apartment_thread(This))
787 This->continue_call--;
788 read += cread;
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_IWinInetHttpInfo(IWinInetHttpInfo *iface)
1396 return CONTAINING_RECORD(iface, BindProtocol, IWinInetHttpInfo_iface);
1399 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
1401 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1402 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1405 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface)
1407 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1408 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1411 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface)
1413 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1414 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1417 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
1418 void *pBuffer, DWORD *pcbBuffer)
1420 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1421 FIXME("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
1422 return E_NOTIMPL;
1425 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
1426 void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
1428 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1429 FIXME("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
1430 return E_NOTIMPL;
1433 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
1434 WinInetHttpInfo_QueryInterface,
1435 WinInetHttpInfo_AddRef,
1436 WinInetHttpInfo_Release,
1437 WinInetHttpInfo_QueryOption,
1438 WinInetHttpInfo_QueryInfo
1441 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface)
1443 return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface);
1446 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1447 REFIID riid, void **ppv)
1449 BindProtocol *This = impl_from_IServiceProvider(iface);
1450 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1453 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1455 BindProtocol *This = impl_from_IServiceProvider(iface);
1456 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1459 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1461 BindProtocol *This = impl_from_IServiceProvider(iface);
1462 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1465 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1466 REFGUID guidService, REFIID riid, void **ppv)
1468 BindProtocol *This = impl_from_IServiceProvider(iface);
1470 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1472 if(!This->service_provider)
1473 return E_NOINTERFACE;
1475 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1478 static const IServiceProviderVtbl ServiceProviderVtbl = {
1479 BPServiceProvider_QueryInterface,
1480 BPServiceProvider_AddRef,
1481 BPServiceProvider_Release,
1482 BPServiceProvider_QueryService
1485 HRESULT create_binding_protocol(BOOL from_urlmon, BindProtocol **protocol)
1487 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1489 ret->IInternetProtocolEx_iface.lpVtbl = &BindProtocolVtbl;
1490 ret->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
1491 ret->IInternetPriority_iface.lpVtbl = &InternetPriorityVtbl;
1492 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
1493 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
1494 ret->IWinInetHttpInfo_iface.lpVtbl = &WinInetHttpInfoVtbl;
1496 ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
1497 ret->default_protocol_handler.IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkHandlerVtbl;
1499 ret->ref = 1;
1500 ret->from_urlmon = from_urlmon;
1501 ret->apartment_thread = GetCurrentThreadId();
1502 ret->notif_hwnd = get_notif_hwnd();
1503 ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
1504 ret->protocol_sink_handler = &ret->default_protocol_handler.IInternetProtocolSink_iface;
1505 InitializeCriticalSection(&ret->section);
1506 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BindProtocol.section");
1508 URLMON_LockModule();
1510 *protocol = ret;
1511 return S_OK;