urlmon: Added Abort support to BindProtocol.
[wine/multimedia.git] / dlls / urlmon / bindprot.c
blob3e1fb582d9f6765b1082df83c19bbc22d2cf6593
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 struct BindProtocol BindProtocol;
26 struct _task_header_t;
28 typedef void (*task_proc_t)(BindProtocol*,struct _task_header_t*);
30 typedef struct _task_header_t {
31 task_proc_t proc;
32 struct _task_header_t *next;
33 } task_header_t;
35 struct BindProtocol {
36 const IInternetProtocolVtbl *lpIInternetProtocolVtbl;
37 const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
38 const IInternetPriorityVtbl *lpInternetPriorityVtbl;
39 const IServiceProviderVtbl *lpServiceProviderVtbl;
40 const IInternetProtocolSinkVtbl *lpIInternetProtocolSinkVtbl;
41 const IWinInetHttpInfoVtbl *lpIWinInetHttpInfoVtbl;
43 const IInternetProtocolVtbl *lpIInternetProtocolHandlerVtbl;
45 LONG ref;
47 IInternetProtocol *protocol;
48 IInternetProtocol *protocol_handler;
49 IInternetBindInfo *bind_info;
50 IInternetProtocolSink *protocol_sink;
51 IServiceProvider *service_provider;
52 IWinInetInfo *wininet_info;
54 LONG priority;
56 BOOL reported_result;
57 BOOL reported_mime;
58 BOOL from_urlmon;
59 DWORD pi;
61 DWORD apartment_thread;
62 HWND notif_hwnd;
63 DWORD continue_call;
65 CRITICAL_SECTION section;
66 task_header_t *task_queue_head, *task_queue_tail;
68 BYTE *buf;
69 DWORD buf_size;
70 LPWSTR mime;
71 LPWSTR url;
72 ProtocolProxy *filter_proxy;
75 #define BINDINFO(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
76 #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
77 #define HTTPINFO(x) ((IWinInetHttpInfo*) &(x)->lpIWinInetHttpInfoVtbl)
78 #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl)
80 #define PROTOCOLHANDLER(x) ((IInternetProtocol*) &(x)->lpIInternetProtocolHandlerVtbl)
82 #define BUFFER_SIZE 2048
83 #define MIME_TEST_SIZE 255
85 #define WM_MK_CONTINUE (WM_USER+101)
86 #define WM_MK_RELEASE (WM_USER+102)
88 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
90 switch(msg) {
91 case WM_MK_CONTINUE: {
92 BindProtocol *This = (BindProtocol*)lParam;
93 task_header_t *task;
95 while(1) {
96 EnterCriticalSection(&This->section);
98 task = This->task_queue_head;
99 if(task) {
100 This->task_queue_head = task->next;
101 if(!This->task_queue_head)
102 This->task_queue_tail = NULL;
105 LeaveCriticalSection(&This->section);
107 if(!task)
108 break;
110 This->continue_call++;
111 task->proc(This, task);
112 This->continue_call--;
115 IInternetProtocol_Release(PROTOCOL(This));
116 return 0;
118 case WM_MK_RELEASE: {
119 tls_data_t *data = get_tls_data();
121 if(!--data->notif_hwnd_cnt) {
122 DestroyWindow(hwnd);
123 data->notif_hwnd = NULL;
128 return DefWindowProcW(hwnd, msg, wParam, lParam);
131 HWND get_notif_hwnd(void)
133 static ATOM wnd_class = 0;
134 tls_data_t *tls_data;
136 static const WCHAR wszURLMonikerNotificationWindow[] =
137 {'U','R','L',' ','M','o','n','i','k','e','r',' ',
138 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
140 tls_data = get_tls_data();
141 if(!tls_data)
142 return NULL;
144 if(tls_data->notif_hwnd_cnt) {
145 tls_data->notif_hwnd_cnt++;
146 return tls_data->notif_hwnd;
149 if(!wnd_class) {
150 static WNDCLASSEXW wndclass = {
151 sizeof(wndclass), 0,
152 notif_wnd_proc, 0, 0,
153 NULL, NULL, NULL, NULL, NULL,
154 wszURLMonikerNotificationWindow,
155 NULL
158 wndclass.hInstance = hProxyDll;
160 wnd_class = RegisterClassExW(&wndclass);
161 if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
162 wnd_class = 1;
165 tls_data->notif_hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
166 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
167 NULL, hProxyDll, NULL);
168 if(tls_data->notif_hwnd)
169 tls_data->notif_hwnd_cnt++;
171 TRACE("hwnd = %p\n", tls_data->notif_hwnd);
173 return tls_data->notif_hwnd;
176 void release_notif_hwnd(HWND hwnd)
178 tls_data_t *data = get_tls_data();
180 if(!data)
181 return;
183 if(data->notif_hwnd != hwnd) {
184 PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
185 return;
188 if(!--data->notif_hwnd_cnt) {
189 DestroyWindow(data->notif_hwnd);
190 data->notif_hwnd = NULL;
194 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
196 BOOL do_post = FALSE;
198 task->proc = proc;
199 task->next = NULL;
201 EnterCriticalSection(&This->section);
203 if(This->task_queue_tail) {
204 This->task_queue_tail->next = task;
205 This->task_queue_tail = task;
206 }else {
207 This->task_queue_tail = This->task_queue_head = task;
208 do_post = !This->continue_call;
211 LeaveCriticalSection(&This->section);
213 if(do_post) {
214 IInternetProtocol_AddRef(PROTOCOL(This));
215 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
219 static inline BOOL do_direct_notif(BindProtocol *This)
221 return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
224 static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter, LPCWSTR mime)
226 PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 };
227 IInternetProtocolSink *protocol_sink, *old_sink;
228 ProtocolProxy *filter_proxy;
229 HRESULT hres;
231 hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&protocol_sink);
232 if(FAILED(hres))
233 return hres;
235 hres = create_protocol_proxy(PROTOCOLHANDLER(This), This->protocol_sink, &filter_proxy);
236 if(FAILED(hres)) {
237 IInternetProtocolSink_Release(protocol_sink);
238 return hres;
241 old_sink = This->protocol_sink;
242 This->protocol_sink = protocol_sink;
243 This->filter_proxy = filter_proxy;
245 IInternetProtocol_AddRef(mime_filter);
246 This->protocol_handler = mime_filter;
248 filter_data.pProtocol = PROTOCOL(filter_proxy);
249 hres = IInternetProtocol_Start(mime_filter, mime, PROTSINK(filter_proxy), BINDINFO(This),
250 PI_FILTER_MODE|PI_FORCE_ASYNC, (HANDLE_PTR)&filter_data);
251 if(FAILED(hres)) {
252 IInternetProtocolSink_Release(old_sink);
253 return hres;
256 IInternetProtocolSink_ReportProgress(old_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL);
257 IInternetProtocolSink_Release(old_sink);
259 This->pi &= ~PI_MIMEVERIFICATION; /* FIXME: more tests */
260 return S_OK;
263 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
265 IInternetProtocol *mime_filter;
266 HRESULT hres;
268 heap_free(This->mime);
269 This->mime = NULL;
271 mime_filter = get_mime_filter(mime);
272 if(mime_filter) {
273 TRACE("Got mime filter for %s\n", debugstr_w(mime));
275 hres = handle_mime_filter(This, mime_filter, mime);
276 IInternetProtocol_Release(mime_filter);
277 if(FAILED(hres))
278 FIXME("MIME filter failed: %08x\n", hres);
279 }else {
280 This->mime = heap_strdupW(mime);
282 if(verified || !(This->pi & PI_MIMEVERIFICATION)) {
283 This->reported_mime = TRUE;
285 if(This->protocol_sink)
286 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
291 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocol, iface)
293 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
295 BindProtocol *This = PROTOCOL_THIS(iface);
297 *ppv = NULL;
298 if(IsEqualGUID(&IID_IUnknown, riid)) {
299 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
300 *ppv = PROTOCOL(This);
301 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
302 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
303 *ppv = PROTOCOL(This);
304 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
305 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
306 *ppv = PROTOCOL(This);
307 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
308 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
309 *ppv = BINDINFO(This);
310 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
311 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
312 *ppv = PRIORITY(This);
313 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
314 FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
315 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
316 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
317 *ppv = SERVPROV(This);
318 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
319 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
320 *ppv = PROTSINK(This);
321 }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
322 TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
324 if(This->protocol) {
325 IWinInetInfo *inet_info;
326 HRESULT hres;
328 hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetInfo, (void**)&inet_info);
329 if(SUCCEEDED(hres)) {
330 *ppv = HTTPINFO(This);
331 IWinInetInfo_Release(inet_info);
334 }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
335 TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv);
337 if(This->protocol) {
338 IWinInetHttpInfo *http_info;
339 HRESULT hres;
341 hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetHttpInfo, (void**)&http_info);
342 if(SUCCEEDED(hres)) {
343 *ppv = HTTPINFO(This);
344 IWinInetHttpInfo_Release(http_info);
347 }else {
348 WARN("not supported interface %s\n", debugstr_guid(riid));
351 if(!*ppv)
352 return E_NOINTERFACE;
354 IUnknown_AddRef((IUnknown*)*ppv);
355 return S_OK;
358 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocol *iface)
360 BindProtocol *This = PROTOCOL_THIS(iface);
361 LONG ref = InterlockedIncrement(&This->ref);
362 TRACE("(%p) ref=%d\n", This, ref);
363 return ref;
366 static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
368 BindProtocol *This = PROTOCOL_THIS(iface);
369 LONG ref = InterlockedDecrement(&This->ref);
371 TRACE("(%p) ref=%d\n", This, ref);
373 if(!ref) {
374 if(This->wininet_info)
375 IWinInetInfo_Release(This->wininet_info);
376 if(This->protocol)
377 IInternetProtocol_Release(This->protocol);
378 if(This->bind_info)
379 IInternetBindInfo_Release(This->bind_info);
380 if(This->protocol_handler && This->protocol_handler != PROTOCOLHANDLER(This))
381 IInternetProtocol_Release(This->protocol_handler);
382 if(This->filter_proxy)
383 IInternetProtocol_Release(PROTOCOL(This->filter_proxy));
385 set_binding_sink(PROTOCOL(This), NULL, NULL);
387 if(This->notif_hwnd)
388 release_notif_hwnd(This->notif_hwnd);
389 DeleteCriticalSection(&This->section);
391 heap_free(This->mime);
392 heap_free(This->url);
393 heap_free(This);
395 URLMON_UnlockModule();
398 return ref;
401 static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
402 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
403 DWORD grfPI, HANDLE_PTR dwReserved)
405 BindProtocol *This = PROTOCOL_THIS(iface);
407 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
408 pOIBindInfo, grfPI, dwReserved);
410 return IInternetProtocol_Start(This->protocol_handler, szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
413 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
415 BindProtocol *This = PROTOCOL_THIS(iface);
417 TRACE("(%p)->(%p)\n", This, pProtocolData);
419 return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
422 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
423 DWORD dwOptions)
425 BindProtocol *This = PROTOCOL_THIS(iface);
427 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
429 return IInternetProtocol_Abort(This->protocol_handler, hrReason, dwOptions);
432 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
434 BindProtocol *This = PROTOCOL_THIS(iface);
436 TRACE("(%p)->(%08x)\n", This, dwOptions);
438 return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
441 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface)
443 BindProtocol *This = PROTOCOL_THIS(iface);
444 FIXME("(%p)\n", This);
445 return E_NOTIMPL;
448 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface)
450 BindProtocol *This = PROTOCOL_THIS(iface);
451 FIXME("(%p)\n", This);
452 return E_NOTIMPL;
455 static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
456 ULONG cb, ULONG *pcbRead)
458 BindProtocol *This = PROTOCOL_THIS(iface);
460 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
462 if(pcbRead)
463 *pcbRead = 0;
464 return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
467 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
468 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
470 BindProtocol *This = PROTOCOL_THIS(iface);
471 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
472 return E_NOTIMPL;
475 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
477 BindProtocol *This = PROTOCOL_THIS(iface);
479 TRACE("(%p)->(%08x)\n", This, dwOptions);
481 return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
484 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
486 BindProtocol *This = PROTOCOL_THIS(iface);
488 TRACE("(%p)\n", This);
490 return IInternetProtocol_UnlockRequest(This->protocol_handler);
493 void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink, IInternetBindInfo *bind_info)
495 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
496 IInternetProtocolSink *prev_sink;
497 IServiceProvider *service_provider = NULL;
499 if(sink)
500 IInternetProtocolSink_AddRef(sink);
501 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
502 if(prev_sink)
503 IInternetProtocolSink_Release(prev_sink);
505 if(sink)
506 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
507 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
508 if(service_provider)
509 IServiceProvider_Release(service_provider);
511 if(bind_info)
512 IInternetBindInfo_AddRef(bind_info);
513 bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info);
514 if(bind_info)
515 IInternetBindInfo_Release(bind_info);
518 IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol)
520 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
522 return This->wininet_info;
525 #undef PROTOCOL_THIS
527 static const IInternetProtocolVtbl BindProtocolVtbl = {
528 BindProtocol_QueryInterface,
529 BindProtocol_AddRef,
530 BindProtocol_Release,
531 BindProtocol_Start,
532 BindProtocol_Continue,
533 BindProtocol_Abort,
534 BindProtocol_Terminate,
535 BindProtocol_Suspend,
536 BindProtocol_Resume,
537 BindProtocol_Read,
538 BindProtocol_Seek,
539 BindProtocol_LockRequest,
540 BindProtocol_UnlockRequest
543 #define PROTOCOLHANDLER_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolHandler, iface)
545 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
547 ERR("should not be called\n");
548 return E_NOINTERFACE;
551 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
553 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
554 return IInternetProtocol_AddRef(PROTOCOL(This));
557 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
559 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
560 return IInternetProtocol_Release(PROTOCOL(This));
563 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
564 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
565 DWORD grfPI, HANDLE_PTR dwReserved)
567 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
568 IInternetProtocol *protocol = NULL;
569 IInternetPriority *priority;
570 IServiceProvider *service_provider;
571 BOOL urlmon_protocol = FALSE;
572 CLSID clsid = IID_NULL;
573 LPOLESTR clsid_str;
574 HRESULT hres;
576 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
577 pOIBindInfo, grfPI, dwReserved);
579 if(!szUrl || !pOIProtSink || !pOIBindInfo)
580 return E_INVALIDARG;
582 This->pi = grfPI;
583 This->url = heap_strdupW(szUrl);
585 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
586 (void**)&service_provider);
587 if(SUCCEEDED(hres)) {
588 /* FIXME: What's protocol CLSID here? */
589 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
590 &IID_IInternetProtocol, (void**)&protocol);
591 IServiceProvider_Release(service_provider);
594 if(!protocol) {
595 IClassFactory *cf;
596 IUnknown *unk;
598 hres = get_protocol_handler(szUrl, &clsid, &urlmon_protocol, &cf);
599 if(FAILED(hres))
600 return hres;
602 if(This->from_urlmon) {
603 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
604 IClassFactory_Release(cf);
605 if(FAILED(hres))
606 return hres;
607 }else {
608 hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
609 &IID_IUnknown, (void**)&unk);
610 IClassFactory_Release(cf);
611 if(FAILED(hres))
612 return hres;
614 hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
615 IUnknown_Release(unk);
616 if(FAILED(hres))
617 return hres;
621 StringFromCLSID(&clsid, &clsid_str);
622 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
623 CoTaskMemFree(clsid_str);
625 This->protocol = protocol;
627 if(urlmon_protocol)
628 IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
630 set_binding_sink(PROTOCOL(This), pOIProtSink, pOIBindInfo);
632 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
633 if(SUCCEEDED(hres)) {
634 IInternetPriority_SetPriority(priority, This->priority);
635 IInternetPriority_Release(priority);
638 return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0);
641 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
643 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
644 HRESULT hres;
646 TRACE("(%p)->(%p)\n", This, pProtocolData);
648 hres = IInternetProtocol_Continue(This->protocol, pProtocolData);
650 heap_free(pProtocolData);
651 return hres;
654 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
655 DWORD dwOptions)
657 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
659 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
661 if(This->protocol && !This->reported_result)
662 return IInternetProtocol_Abort(This->protocol, hrReason, dwOptions);
664 return S_OK;
667 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
669 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
671 TRACE("(%p)->(%08x)\n", This, dwOptions);
673 if(!This->reported_result)
674 return E_FAIL;
676 IInternetProtocol_Terminate(This->protocol, 0);
678 if(This->filter_proxy) {
679 IInternetProtocol_Release(PROTOCOL(This->filter_proxy));
680 This->filter_proxy = NULL;
683 set_binding_sink(PROTOCOL(This), NULL, NULL);
685 if(This->bind_info) {
686 IInternetBindInfo_Release(This->bind_info);
687 This->bind_info = NULL;
690 return S_OK;
693 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
695 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
696 FIXME("(%p)\n", This);
697 return E_NOTIMPL;
700 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
702 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
703 FIXME("(%p)\n", This);
704 return E_NOTIMPL;
707 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
708 ULONG cb, ULONG *pcbRead)
710 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
711 ULONG read = 0;
712 HRESULT hres = S_OK;
714 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
716 if(This->buf_size) {
717 read = min(cb, This->buf_size);
718 memcpy(pv, This->buf, read);
720 if(read == This->buf_size) {
721 heap_free(This->buf);
722 This->buf = NULL;
723 }else {
724 memmove(This->buf, This->buf+cb, This->buf_size-cb);
727 This->buf_size -= read;
730 if(read < cb) {
731 ULONG cread = 0;
733 hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
734 read += cread;
737 *pcbRead = read;
738 return hres;
741 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
742 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
744 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
745 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
746 return E_NOTIMPL;
749 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
751 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
753 TRACE("(%p)->(%08x)\n", This, dwOptions);
755 return IInternetProtocol_LockRequest(This->protocol, dwOptions);
758 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
760 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
762 TRACE("(%p)\n", This);
764 return IInternetProtocol_UnlockRequest(This->protocol);
767 #undef PROTOCOL_THIS
769 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
770 ProtocolHandler_QueryInterface,
771 ProtocolHandler_AddRef,
772 ProtocolHandler_Release,
773 ProtocolHandler_Start,
774 ProtocolHandler_Continue,
775 ProtocolHandler_Abort,
776 ProtocolHandler_Terminate,
777 ProtocolHandler_Suspend,
778 ProtocolHandler_Resume,
779 ProtocolHandler_Read,
780 ProtocolHandler_Seek,
781 ProtocolHandler_LockRequest,
782 ProtocolHandler_UnlockRequest
785 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
787 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
788 REFIID riid, void **ppv)
790 BindProtocol *This = BINDINFO_THIS(iface);
791 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
794 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
796 BindProtocol *This = BINDINFO_THIS(iface);
797 return IBinding_AddRef(PROTOCOL(This));
800 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
802 BindProtocol *This = BINDINFO_THIS(iface);
803 return IBinding_Release(PROTOCOL(This));
806 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
807 DWORD *grfBINDF, BINDINFO *pbindinfo)
809 BindProtocol *This = BINDINFO_THIS(iface);
810 HRESULT hres;
812 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
814 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
815 if(FAILED(hres)) {
816 WARN("GetBindInfo failed: %08x\n", hres);
817 return hres;
820 *grfBINDF |= BINDF_FROMURLMON;
821 return hres;
824 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
825 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
827 BindProtocol *This = BINDINFO_THIS(iface);
829 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
831 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
834 #undef BINDFO_THIS
836 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
837 BindInfo_QueryInterface,
838 BindInfo_AddRef,
839 BindInfo_Release,
840 BindInfo_GetBindInfo,
841 BindInfo_GetBindString
844 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
846 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
847 REFIID riid, void **ppv)
849 BindProtocol *This = PRIORITY_THIS(iface);
850 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
853 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
855 BindProtocol *This = PRIORITY_THIS(iface);
856 return IInternetProtocol_AddRef(PROTOCOL(This));
859 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
861 BindProtocol *This = PRIORITY_THIS(iface);
862 return IInternetProtocol_Release(PROTOCOL(This));
865 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
867 BindProtocol *This = PRIORITY_THIS(iface);
869 TRACE("(%p)->(%d)\n", This, nPriority);
871 This->priority = nPriority;
872 return S_OK;
875 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
877 BindProtocol *This = PRIORITY_THIS(iface);
879 TRACE("(%p)->(%p)\n", This, pnPriority);
881 *pnPriority = This->priority;
882 return S_OK;
885 #undef PRIORITY_THIS
887 static const IInternetPriorityVtbl InternetPriorityVtbl = {
888 InternetPriority_QueryInterface,
889 InternetPriority_AddRef,
890 InternetPriority_Release,
891 InternetPriority_SetPriority,
892 InternetPriority_GetPriority
896 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolSink, iface)
898 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
899 REFIID riid, void **ppv)
901 BindProtocol *This = PROTSINK_THIS(iface);
902 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
905 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
907 BindProtocol *This = PROTSINK_THIS(iface);
908 return IInternetProtocol_AddRef(PROTOCOL(This));
911 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
913 BindProtocol *This = PROTSINK_THIS(iface);
914 return IInternetProtocol_Release(PROTOCOL(This));
917 typedef struct {
918 task_header_t header;
919 PROTOCOLDATA *data;
920 } switch_task_t;
922 static void switch_proc(BindProtocol *bind, task_header_t *t)
924 switch_task_t *task = (switch_task_t*)t;
926 IInternetProtocol_Continue(bind->protocol_handler, task->data);
928 heap_free(task);
931 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
932 PROTOCOLDATA *pProtocolData)
934 BindProtocol *This = PROTSINK_THIS(iface);
935 PROTOCOLDATA *data;
937 TRACE("(%p)->(%p)\n", This, pProtocolData);
939 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
940 pProtocolData->pData, pProtocolData->cbData);
942 data = heap_alloc(sizeof(PROTOCOLDATA));
943 if(!data)
944 return E_OUTOFMEMORY;
945 memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
947 if(!do_direct_notif(This)) {
948 switch_task_t *task;
950 task = heap_alloc(sizeof(switch_task_t));
951 if(!task)
952 return E_OUTOFMEMORY;
954 task->data = data;
956 push_task(This, &task->header, switch_proc);
957 return S_OK;
960 if(!This->protocol_sink) {
961 IInternetProtocol_Continue(This->protocol_handler, data);
962 return S_OK;
965 return IInternetProtocolSink_Switch(This->protocol_sink, data);
968 static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
970 switch(status_code) {
971 case BINDSTATUS_FINDINGRESOURCE:
972 case BINDSTATUS_CONNECTING:
973 case BINDSTATUS_REDIRECTING:
974 case BINDSTATUS_BEGINDOWNLOADDATA:
975 case BINDSTATUS_SENDINGREQUEST:
976 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
977 case BINDSTATUS_DIRECTBIND:
978 case BINDSTATUS_ACCEPTRANGES:
979 if(This->protocol_sink)
980 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
981 break;
983 case BINDSTATUS_MIMETYPEAVAILABLE:
984 mime_available(This, status_text, FALSE);
985 break;
987 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
988 mime_available(This, status_text, TRUE);
989 break;
991 default:
992 FIXME("unsupported ulStatusCode %u\n", status_code);
996 typedef struct {
997 task_header_t header;
999 ULONG status_code;
1000 LPWSTR status_text;
1001 } on_progress_task_t;
1003 static void on_progress_proc(BindProtocol *This, task_header_t *t)
1005 on_progress_task_t *task = (on_progress_task_t*)t;
1007 report_progress(This, task->status_code, task->status_text);
1009 heap_free(task->status_text);
1010 heap_free(task);
1013 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
1014 ULONG ulStatusCode, LPCWSTR szStatusText)
1016 BindProtocol *This = PROTSINK_THIS(iface);
1018 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
1020 if(do_direct_notif(This)) {
1021 report_progress(This, ulStatusCode, szStatusText);
1022 }else {
1023 on_progress_task_t *task;
1025 task = heap_alloc(sizeof(on_progress_task_t));
1027 task->status_code = ulStatusCode;
1028 task->status_text = heap_strdupW(szStatusText);
1030 push_task(This, &task->header, on_progress_proc);
1033 return S_OK;
1036 static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max)
1038 if(!This->protocol_sink)
1039 return S_OK;
1041 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
1042 BYTE buf[BUFFER_SIZE];
1043 DWORD read = 0;
1044 LPWSTR mime;
1045 HRESULT hres;
1047 do {
1048 read = 0;
1049 hres = IInternetProtocol_Read(This->protocol, buf,
1050 sizeof(buf)-This->buf_size, &read);
1051 if(FAILED(hres) && hres != E_PENDING)
1052 return hres;
1054 if(!This->buf) {
1055 This->buf = heap_alloc(BUFFER_SIZE);
1056 if(!This->buf)
1057 return E_OUTOFMEMORY;
1058 }else if(read + This->buf_size > BUFFER_SIZE) {
1059 BYTE *tmp;
1061 tmp = heap_realloc(This->buf, read+This->buf_size);
1062 if(!tmp)
1063 return E_OUTOFMEMORY;
1064 This->buf = tmp;
1067 memcpy(This->buf+This->buf_size, buf, read);
1068 This->buf_size += read;
1069 }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
1071 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
1072 return S_OK;
1074 bscf = BSCF_FIRSTDATANOTIFICATION;
1075 if(hres == S_FALSE)
1076 bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
1078 if(!This->reported_mime) {
1079 hres = FindMimeFromData(NULL, This->url, This->buf, min(This->buf_size, MIME_TEST_SIZE),
1080 This->mime, 0, &mime, 0);
1081 if(FAILED(hres))
1082 return hres;
1084 mime_available(This, mime, TRUE);
1085 CoTaskMemFree(mime);
1089 if(!This->protocol_sink)
1090 return S_OK;
1092 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
1095 typedef struct {
1096 task_header_t header;
1097 DWORD bscf;
1098 ULONG progress;
1099 ULONG progress_max;
1100 } report_data_task_t;
1102 static void report_data_proc(BindProtocol *This, task_header_t *t)
1104 report_data_task_t *task = (report_data_task_t*)t;
1106 report_data(This, task->bscf, task->progress, task->progress_max);
1107 heap_free(task);
1110 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1111 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1113 BindProtocol *This = PROTSINK_THIS(iface);
1115 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1117 if(!This->protocol_sink)
1118 return S_OK;
1120 if(!do_direct_notif(This)) {
1121 report_data_task_t *task;
1123 task = heap_alloc(sizeof(report_data_task_t));
1124 if(!task)
1125 return E_OUTOFMEMORY;
1127 task->bscf = grfBSCF;
1128 task->progress = ulProgress;
1129 task->progress_max = ulProgressMax;
1131 push_task(This, &task->header, report_data_proc);
1132 return S_OK;
1135 return report_data(This, grfBSCF, ulProgress, ulProgressMax);
1138 typedef struct {
1139 task_header_t header;
1141 HRESULT hres;
1142 DWORD err;
1143 LPWSTR str;
1144 } report_result_task_t;
1146 static void report_result_proc(BindProtocol *This, task_header_t *t)
1148 report_result_task_t *task = (report_result_task_t*)t;
1150 if(This->protocol_sink)
1151 IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str);
1153 heap_free(task->str);
1154 heap_free(task);
1157 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1158 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1160 BindProtocol *This = PROTSINK_THIS(iface);
1162 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1164 if(!This->protocol_sink)
1165 return E_FAIL;
1167 This->reported_result = TRUE;
1169 if(!do_direct_notif(This)) {
1170 report_result_task_t *task;
1172 task = heap_alloc(sizeof(report_result_task_t));
1173 if(!task)
1174 return E_OUTOFMEMORY;
1176 task->hres = hrResult;
1177 task->err = dwError;
1178 task->str = heap_strdupW(szResult);
1180 push_task(This, &task->header, report_result_proc);
1181 return S_OK;
1184 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1187 #undef PROTSINK_THIS
1189 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1190 BPInternetProtocolSink_QueryInterface,
1191 BPInternetProtocolSink_AddRef,
1192 BPInternetProtocolSink_Release,
1193 BPInternetProtocolSink_Switch,
1194 BPInternetProtocolSink_ReportProgress,
1195 BPInternetProtocolSink_ReportData,
1196 BPInternetProtocolSink_ReportResult
1199 #define INETINFO_THIS(iface) DEFINE_THIS(BindProtocol, IWinInetHttpInfo, iface)
1201 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
1203 BindProtocol *This = INETINFO_THIS(iface);
1204 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
1207 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface)
1209 BindProtocol *This = INETINFO_THIS(iface);
1210 return IInternetProtocol_AddRef(PROTOCOL(This));
1213 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface)
1215 BindProtocol *This = INETINFO_THIS(iface);
1216 return IInternetProtocol_Release(PROTOCOL(This));
1219 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
1220 void *pBuffer, DWORD *pcbBuffer)
1222 BindProtocol *This = INETINFO_THIS(iface);
1223 FIXME("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
1224 return E_NOTIMPL;
1227 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
1228 void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
1230 BindProtocol *This = INETINFO_THIS(iface);
1231 FIXME("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
1232 return E_NOTIMPL;
1235 #undef INETINFO_THIS
1237 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
1238 WinInetHttpInfo_QueryInterface,
1239 WinInetHttpInfo_AddRef,
1240 WinInetHttpInfo_Release,
1241 WinInetHttpInfo_QueryOption,
1242 WinInetHttpInfo_QueryInfo
1245 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
1247 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1248 REFIID riid, void **ppv)
1250 BindProtocol *This = SERVPROV_THIS(iface);
1251 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
1254 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1256 BindProtocol *This = SERVPROV_THIS(iface);
1257 return IInternetProtocol_AddRef(PROTOCOL(This));
1260 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1262 BindProtocol *This = SERVPROV_THIS(iface);
1263 return IInternetProtocol_Release(PROTOCOL(This));
1266 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1267 REFGUID guidService, REFIID riid, void **ppv)
1269 BindProtocol *This = SERVPROV_THIS(iface);
1271 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1273 if(!This->service_provider)
1274 return E_NOINTERFACE;
1276 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1279 #undef SERVPROV_THIS
1281 static const IServiceProviderVtbl ServiceProviderVtbl = {
1282 BPServiceProvider_QueryInterface,
1283 BPServiceProvider_AddRef,
1284 BPServiceProvider_Release,
1285 BPServiceProvider_QueryService
1288 HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol)
1290 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1292 ret->lpIInternetProtocolVtbl = &BindProtocolVtbl;
1293 ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
1294 ret->lpInternetPriorityVtbl = &InternetPriorityVtbl;
1295 ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
1296 ret->lpIInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1297 ret->lpIInternetProtocolHandlerVtbl = &InternetProtocolHandlerVtbl;
1298 ret->lpIWinInetHttpInfoVtbl = &WinInetHttpInfoVtbl;
1300 ret->ref = 1;
1301 ret->from_urlmon = from_urlmon;
1302 ret->apartment_thread = GetCurrentThreadId();
1303 ret->notif_hwnd = get_notif_hwnd();
1304 ret->protocol_handler = PROTOCOLHANDLER(ret);
1305 InitializeCriticalSection(&ret->section);
1307 URLMON_LockModule();
1309 *protocol = PROTOCOL(ret);
1310 return S_OK;