2 * Copyright 2007 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 {
32 struct _task_header_t *next;
36 const IInternetProtocolVtbl *lpInternetProtocolVtbl;
37 const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
38 const IInternetPriorityVtbl *lpInternetPriorityVtbl;
39 const IServiceProviderVtbl *lpServiceProviderVtbl;
40 const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl;
42 const IInternetProtocolVtbl *lpIInternetProtocolHandlerVtbl;
46 IInternetProtocol *protocol;
47 IInternetProtocol *protocol_handler;
48 IInternetBindInfo *bind_info;
49 IInternetProtocolSink *protocol_sink;
50 IServiceProvider *service_provider;
51 IWinInetInfo *wininet_info;
60 DWORD apartment_thread;
64 CRITICAL_SECTION section;
65 task_header_t *task_queue_head, *task_queue_tail;
73 #define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
74 #define BINDINFO(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
75 #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
76 #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl)
77 #define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
79 #define PROTOCOLHANDLER(x) ((IInternetProtocol*) &(x)->lpIInternetProtocolHandlerVtbl)
81 #define BUFFER_SIZE 2048
82 #define MIME_TEST_SIZE 255
84 #define WM_MK_CONTINUE (WM_USER+101)
85 #define WM_MK_RELEASE (WM_USER+102)
87 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
90 case WM_MK_CONTINUE: {
91 BindProtocol *This = (BindProtocol*)lParam;
95 EnterCriticalSection(&This->section);
97 task = This->task_queue_head;
99 This->task_queue_head = task->next;
100 if(!This->task_queue_head)
101 This->task_queue_tail = NULL;
104 LeaveCriticalSection(&This->section);
109 This->continue_call++;
110 task->proc(This, task);
111 This->continue_call--;
114 IInternetProtocol_Release(PROTOCOL(This));
117 case WM_MK_RELEASE: {
118 tls_data_t *data = get_tls_data();
120 if(!--data->notif_hwnd_cnt) {
122 data->notif_hwnd = NULL;
127 return DefWindowProcW(hwnd, msg, wParam, lParam);
130 HWND get_notif_hwnd(void)
132 static ATOM wnd_class = 0;
133 tls_data_t *tls_data;
135 static const WCHAR wszURLMonikerNotificationWindow[] =
136 {'U','R','L',' ','M','o','n','i','k','e','r',' ',
137 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
139 tls_data = get_tls_data();
143 if(tls_data->notif_hwnd_cnt) {
144 tls_data->notif_hwnd_cnt++;
145 return tls_data->notif_hwnd;
149 static WNDCLASSEXW wndclass = {
151 notif_wnd_proc, 0, 0,
152 NULL, NULL, NULL, NULL, NULL,
153 wszURLMonikerNotificationWindow,
157 wndclass.hInstance = URLMON_hInstance;
159 wnd_class = RegisterClassExW(&wndclass);
160 if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
164 tls_data->notif_hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
165 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
166 NULL, URLMON_hInstance, NULL);
167 if(tls_data->notif_hwnd)
168 tls_data->notif_hwnd_cnt++;
170 TRACE("hwnd = %p\n", tls_data->notif_hwnd);
172 return tls_data->notif_hwnd;
175 void release_notif_hwnd(HWND hwnd)
177 tls_data_t *data = get_tls_data();
182 if(data->notif_hwnd != hwnd) {
183 PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
187 if(!--data->notif_hwnd_cnt) {
188 DestroyWindow(data->notif_hwnd);
189 data->notif_hwnd = NULL;
193 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
195 BOOL do_post = FALSE;
200 EnterCriticalSection(&This->section);
202 if(This->task_queue_tail) {
203 This->task_queue_tail->next = task;
204 This->task_queue_tail = task;
206 This->task_queue_tail = This->task_queue_head = task;
210 LeaveCriticalSection(&This->section);
213 IInternetProtocol_AddRef(PROTOCOL(This));
214 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
218 static BOOL inline do_direct_notif(BindProtocol *This)
220 return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
223 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
225 heap_free(This->mime);
227 This->mime = heap_strdupW(mime);
229 if(verified || !(This->pi & PI_MIMEVERIFICATION)) {
230 This->reported_mime = TRUE;
232 if(This->protocol_sink)
233 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
237 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocol, iface)
239 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
241 BindProtocol *This = PROTOCOL_THIS(iface);
244 if(IsEqualGUID(&IID_IUnknown, riid)) {
245 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
246 *ppv = PROTOCOL(This);
247 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
248 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
249 *ppv = PROTOCOL(This);
250 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
251 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
252 *ppv = PROTOCOL(This);
253 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
254 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
255 *ppv = BINDINFO(This);
256 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
257 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
258 *ppv = PRIORITY(This);
259 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
260 FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
261 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
262 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
263 *ppv = SERVPROV(This);
264 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
265 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
266 *ppv = PROTSINK(This);
270 IInternetProtocol_AddRef(iface);
274 WARN("not supported interface %s\n", debugstr_guid(riid));
275 return E_NOINTERFACE;
278 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocol *iface)
280 BindProtocol *This = PROTOCOL_THIS(iface);
281 LONG ref = InterlockedIncrement(&This->ref);
282 TRACE("(%p) ref=%d\n", This, ref);
286 static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
288 BindProtocol *This = PROTOCOL_THIS(iface);
289 LONG ref = InterlockedDecrement(&This->ref);
291 TRACE("(%p) ref=%d\n", This, ref);
294 if(This->wininet_info)
295 IWinInetInfo_Release(This->wininet_info);
297 IInternetProtocol_Release(This->protocol);
299 IInternetBindInfo_Release(This->bind_info);
300 if(This->protocol_handler && This->protocol_handler != PROTOCOLHANDLER(This))
301 IInternetProtocol_Release(This->protocol_handler);
303 set_binding_sink(PROTOCOL(This), NULL);
306 release_notif_hwnd(This->notif_hwnd);
307 DeleteCriticalSection(&This->section);
309 heap_free(This->mime);
310 heap_free(This->url);
313 URLMON_UnlockModule();
319 static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
320 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
321 DWORD grfPI, HANDLE_PTR dwReserved)
323 BindProtocol *This = PROTOCOL_THIS(iface);
325 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
326 pOIBindInfo, grfPI, dwReserved);
328 return IInternetProtocol_Start(This->protocol_handler, szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
331 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
333 BindProtocol *This = PROTOCOL_THIS(iface);
335 TRACE("(%p)->(%p)\n", This, pProtocolData);
337 return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
340 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
343 BindProtocol *This = PROTOCOL_THIS(iface);
344 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
348 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
350 BindProtocol *This = PROTOCOL_THIS(iface);
352 TRACE("(%p)->(%08x)\n", This, dwOptions);
354 return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
357 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface)
359 BindProtocol *This = PROTOCOL_THIS(iface);
360 FIXME("(%p)\n", This);
364 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface)
366 BindProtocol *This = PROTOCOL_THIS(iface);
367 FIXME("(%p)\n", This);
371 static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
372 ULONG cb, ULONG *pcbRead)
374 BindProtocol *This = PROTOCOL_THIS(iface);
376 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
380 return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
383 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
384 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
386 BindProtocol *This = PROTOCOL_THIS(iface);
387 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
391 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
393 BindProtocol *This = PROTOCOL_THIS(iface);
395 TRACE("(%p)->(%08x)\n", This, dwOptions);
397 return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
400 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
402 BindProtocol *This = PROTOCOL_THIS(iface);
404 TRACE("(%p)\n", This);
406 return IInternetProtocol_UnlockRequest(This->protocol_handler);
409 void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink)
411 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
412 IInternetProtocolSink *prev_sink;
413 IServiceProvider *service_provider = NULL;
416 IInternetProtocolSink_AddRef(sink);
417 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
419 IInternetProtocolSink_Release(prev_sink);
422 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
423 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
425 IServiceProvider_Release(service_provider);
428 IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol)
430 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
432 return This->wininet_info;
437 static const IInternetProtocolVtbl BindProtocolVtbl = {
438 BindProtocol_QueryInterface,
440 BindProtocol_Release,
442 BindProtocol_Continue,
444 BindProtocol_Terminate,
445 BindProtocol_Suspend,
449 BindProtocol_LockRequest,
450 BindProtocol_UnlockRequest
453 #define PROTOCOLHANDLER_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolHandler, iface)
455 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
457 ERR("should not be called\n");
458 return E_NOINTERFACE;
461 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
463 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
464 return IInternetProtocol_AddRef(PROTOCOL(This));
467 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
469 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
470 return IInternetProtocol_Release(PROTOCOL(This));
473 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
474 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
475 DWORD grfPI, HANDLE_PTR dwReserved)
477 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
478 IInternetProtocol *protocol = NULL;
479 IInternetPriority *priority;
480 IServiceProvider *service_provider;
481 BOOL urlmon_protocol = FALSE;
482 CLSID clsid = IID_NULL;
486 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
487 pOIBindInfo, grfPI, dwReserved);
489 if(!szUrl || !pOIProtSink || !pOIBindInfo)
493 This->url = heap_strdupW(szUrl);
495 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
496 (void**)&service_provider);
497 if(SUCCEEDED(hres)) {
498 /* FIXME: What's protocol CLSID here? */
499 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
500 &IID_IInternetProtocol, (void**)&protocol);
501 IServiceProvider_Release(service_provider);
508 hres = get_protocol_handler(szUrl, &clsid, &urlmon_protocol, &cf);
512 if(This->from_urlmon) {
513 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
514 IClassFactory_Release(cf);
518 hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
519 &IID_IUnknown, (void**)&unk);
520 IClassFactory_Release(cf);
524 hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
525 IUnknown_Release(unk);
531 StringFromCLSID(&clsid, &clsid_str);
532 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
533 CoTaskMemFree(clsid_str);
535 This->protocol = protocol;
538 IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
540 IInternetBindInfo_AddRef(pOIBindInfo);
541 This->bind_info = pOIBindInfo;
543 set_binding_sink(PROTOCOL(This), pOIProtSink);
545 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
546 if(SUCCEEDED(hres)) {
547 IInternetPriority_SetPriority(priority, This->priority);
548 IInternetPriority_Release(priority);
551 return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0);
554 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
556 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
558 TRACE("(%p)->(%p)\n", This, pProtocolData);
560 return IInternetProtocol_Continue(This->protocol, pProtocolData);
563 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
566 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
567 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
571 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
573 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
575 TRACE("(%p)->(%08x)\n", This, dwOptions);
577 if(!This->reported_result)
580 IInternetProtocol_Terminate(This->protocol, 0);
582 set_binding_sink(PROTOCOL(This), NULL);
584 if(This->bind_info) {
585 IInternetBindInfo_Release(This->bind_info);
586 This->bind_info = NULL;
592 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
594 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
595 FIXME("(%p)\n", This);
599 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
601 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
602 FIXME("(%p)\n", This);
606 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
607 ULONG cb, ULONG *pcbRead)
609 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
613 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
616 read = min(cb, This->buf_size);
617 memcpy(pv, This->buf, read);
619 if(read == This->buf_size) {
620 heap_free(This->buf);
623 memmove(This->buf, This->buf+cb, This->buf_size-cb);
626 This->buf_size -= read;
632 hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
640 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
641 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
643 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
644 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
648 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
650 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
652 TRACE("(%p)->(%08x)\n", This, dwOptions);
654 return IInternetProtocol_LockRequest(This->protocol, dwOptions);
657 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
659 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
661 TRACE("(%p)\n", This);
663 return IInternetProtocol_UnlockRequest(This->protocol);
668 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
669 ProtocolHandler_QueryInterface,
670 ProtocolHandler_AddRef,
671 ProtocolHandler_Release,
672 ProtocolHandler_Start,
673 ProtocolHandler_Continue,
674 ProtocolHandler_Abort,
675 ProtocolHandler_Terminate,
676 ProtocolHandler_Suspend,
677 ProtocolHandler_Resume,
678 ProtocolHandler_Read,
679 ProtocolHandler_Seek,
680 ProtocolHandler_LockRequest,
681 ProtocolHandler_UnlockRequest
684 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
686 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
687 REFIID riid, void **ppv)
689 BindProtocol *This = BINDINFO_THIS(iface);
690 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
693 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
695 BindProtocol *This = BINDINFO_THIS(iface);
696 return IBinding_AddRef(PROTOCOL(This));
699 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
701 BindProtocol *This = BINDINFO_THIS(iface);
702 return IBinding_Release(PROTOCOL(This));
705 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
706 DWORD *grfBINDF, BINDINFO *pbindinfo)
708 BindProtocol *This = BINDINFO_THIS(iface);
711 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
713 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
715 WARN("GetBindInfo failed: %08x\n", hres);
719 *grfBINDF |= BINDF_FROMURLMON;
723 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
724 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
726 BindProtocol *This = BINDINFO_THIS(iface);
728 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
730 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
735 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
736 BindInfo_QueryInterface,
739 BindInfo_GetBindInfo,
740 BindInfo_GetBindString
743 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
745 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
746 REFIID riid, void **ppv)
748 BindProtocol *This = PRIORITY_THIS(iface);
749 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
752 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
754 BindProtocol *This = PRIORITY_THIS(iface);
755 return IInternetProtocol_AddRef(PROTOCOL(This));
758 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
760 BindProtocol *This = PRIORITY_THIS(iface);
761 return IInternetProtocol_Release(PROTOCOL(This));
764 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
766 BindProtocol *This = PRIORITY_THIS(iface);
768 TRACE("(%p)->(%d)\n", This, nPriority);
770 This->priority = nPriority;
774 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
776 BindProtocol *This = PRIORITY_THIS(iface);
778 TRACE("(%p)->(%p)\n", This, pnPriority);
780 *pnPriority = This->priority;
786 static const IInternetPriorityVtbl InternetPriorityVtbl = {
787 InternetPriority_QueryInterface,
788 InternetPriority_AddRef,
789 InternetPriority_Release,
790 InternetPriority_SetPriority,
791 InternetPriority_GetPriority
795 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocolSink, iface)
797 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
798 REFIID riid, void **ppv)
800 BindProtocol *This = PROTSINK_THIS(iface);
801 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
804 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
806 BindProtocol *This = PROTSINK_THIS(iface);
807 return IInternetProtocol_AddRef(PROTOCOL(This));
810 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
812 BindProtocol *This = PROTSINK_THIS(iface);
813 return IInternetProtocol_Release(PROTOCOL(This));
817 task_header_t header;
821 static void switch_proc(BindProtocol *bind, task_header_t *t)
823 switch_task_t *task = (switch_task_t*)t;
825 IInternetProtocol_Continue(bind->protocol_handler, &task->data);
830 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
831 PROTOCOLDATA *pProtocolData)
833 BindProtocol *This = PROTSINK_THIS(iface);
835 TRACE("(%p)->(%p)\n", This, pProtocolData);
837 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
838 pProtocolData->pData, pProtocolData->cbData);
840 if(!do_direct_notif(This)) {
843 task = heap_alloc(sizeof(switch_task_t));
845 return E_OUTOFMEMORY;
847 task->data = *pProtocolData;
849 push_task(This, &task->header, switch_proc);
853 if(!This->protocol_sink) {
854 IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
858 return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
861 static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
863 switch(status_code) {
864 case BINDSTATUS_FINDINGRESOURCE:
865 case BINDSTATUS_CONNECTING:
866 case BINDSTATUS_BEGINDOWNLOADDATA:
867 case BINDSTATUS_SENDINGREQUEST:
868 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
869 case BINDSTATUS_DIRECTBIND:
870 case BINDSTATUS_ACCEPTRANGES:
871 if(This->protocol_sink)
872 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
875 case BINDSTATUS_MIMETYPEAVAILABLE:
876 mime_available(This, status_text, FALSE);
879 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
880 mime_available(This, status_text, TRUE);
884 FIXME("unsupported ulStatusCode %u\n", status_code);
889 task_header_t header;
893 } on_progress_task_t;
895 static void on_progress_proc(BindProtocol *This, task_header_t *t)
897 on_progress_task_t *task = (on_progress_task_t*)t;
899 report_progress(This, task->status_code, task->status_text);
901 heap_free(task->status_text);
905 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
906 ULONG ulStatusCode, LPCWSTR szStatusText)
908 BindProtocol *This = PROTSINK_THIS(iface);
910 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
912 if(do_direct_notif(This)) {
913 report_progress(This, ulStatusCode, szStatusText);
915 on_progress_task_t *task;
917 task = heap_alloc(sizeof(on_progress_task_t));
919 task->status_code = ulStatusCode;
920 task->status_text = heap_strdupW(szStatusText);
922 push_task(This, &task->header, on_progress_proc);
928 static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max)
930 if(!This->protocol_sink)
933 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
939 This->buf = heap_alloc(BUFFER_SIZE);
941 return E_OUTOFMEMORY;
946 hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size, BUFFER_SIZE-This->buf_size, &read);
949 This->buf_size += read;
950 }while(This->buf_size < MIME_TEST_SIZE);
951 if(FAILED(hres) && hres != E_PENDING)
954 This->buf_size += read;
955 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
959 hres = FindMimeFromData(NULL, This->url, This->buf, min(This->buf_size, MIME_TEST_SIZE), This->mime, 0, &mime, 0);
963 mime_available(This, mime, TRUE);
967 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
971 task_header_t header;
975 } report_data_task_t;
977 static void report_data_proc(BindProtocol *This, task_header_t *t)
979 report_data_task_t *task = (report_data_task_t*)t;
981 report_data(This, task->bscf, task->progress, task->progress_max);
985 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
986 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
988 BindProtocol *This = PROTSINK_THIS(iface);
990 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
992 if(!This->protocol_sink)
995 if(!do_direct_notif(This)) {
996 report_data_task_t *task;
998 task = heap_alloc(sizeof(report_data_task_t));
1000 return E_OUTOFMEMORY;
1002 task->bscf = grfBSCF;
1003 task->progress = ulProgress;
1004 task->progress_max = ulProgressMax;
1006 push_task(This, &task->header, report_data_proc);
1010 return report_data(This, grfBSCF, ulProgress, ulProgressMax);
1014 task_header_t header;
1019 } report_result_task_t;
1021 static void report_result_proc(BindProtocol *This, task_header_t *t)
1023 report_result_task_t *task = (report_result_task_t*)t;
1025 if(This->protocol_sink)
1026 IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str);
1028 heap_free(task->str);
1032 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1033 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1035 BindProtocol *This = PROTSINK_THIS(iface);
1037 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1039 if(!This->protocol_sink)
1042 This->reported_result = TRUE;
1044 if(!do_direct_notif(This)) {
1045 report_result_task_t *task;
1047 task = heap_alloc(sizeof(report_result_task_t));
1049 return E_OUTOFMEMORY;
1051 task->hres = hrResult;
1052 task->err = dwError;
1053 task->str = heap_strdupW(szResult);
1055 push_task(This, &task->header, report_result_proc);
1059 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1062 #undef PROTSINK_THIS
1064 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1065 BPInternetProtocolSink_QueryInterface,
1066 BPInternetProtocolSink_AddRef,
1067 BPInternetProtocolSink_Release,
1068 BPInternetProtocolSink_Switch,
1069 BPInternetProtocolSink_ReportProgress,
1070 BPInternetProtocolSink_ReportData,
1071 BPInternetProtocolSink_ReportResult
1074 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
1076 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1077 REFIID riid, void **ppv)
1079 BindProtocol *This = SERVPROV_THIS(iface);
1080 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
1083 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1085 BindProtocol *This = SERVPROV_THIS(iface);
1086 return IInternetProtocol_AddRef(PROTOCOL(This));
1089 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1091 BindProtocol *This = SERVPROV_THIS(iface);
1092 return IInternetProtocol_Release(PROTOCOL(This));
1095 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1096 REFGUID guidService, REFIID riid, void **ppv)
1098 BindProtocol *This = SERVPROV_THIS(iface);
1100 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1102 if(!This->service_provider)
1103 return E_NOINTERFACE;
1105 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1108 #undef SERVPROV_THIS
1110 static const IServiceProviderVtbl ServiceProviderVtbl = {
1111 BPServiceProvider_QueryInterface,
1112 BPServiceProvider_AddRef,
1113 BPServiceProvider_Release,
1114 BPServiceProvider_QueryService
1117 HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol)
1119 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1121 ret->lpInternetProtocolVtbl = &BindProtocolVtbl;
1122 ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
1123 ret->lpInternetPriorityVtbl = &InternetPriorityVtbl;
1124 ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
1125 ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1126 ret->lpIInternetProtocolHandlerVtbl = &InternetProtocolHandlerVtbl;
1129 ret->from_urlmon = from_urlmon;
1130 ret->apartment_thread = GetCurrentThreadId();
1131 ret->notif_hwnd = get_notif_hwnd();
1132 ret->protocol_handler = PROTOCOLHANDLER(ret);
1133 InitializeCriticalSection(&ret->section);
1135 URLMON_LockModule();
1137 *protocol = PROTOCOL(ret);