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 {
32 struct _task_header_t *next;
36 const IInternetProtocolExVtbl *lpIInternetProtocolExVtbl;
37 const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
38 const IInternetPriorityVtbl *lpInternetPriorityVtbl;
39 const IServiceProviderVtbl *lpServiceProviderVtbl;
40 const IInternetProtocolSinkVtbl *lpIInternetProtocolSinkVtbl;
41 const IWinInetHttpInfoVtbl *lpIWinInetHttpInfoVtbl;
45 IInternetProtocol *protocol;
46 IInternetBindInfo *bind_info;
47 IInternetProtocolSink *protocol_sink;
48 IServiceProvider *service_provider;
49 IWinInetInfo *wininet_info;
52 IInternetProtocol IInternetProtocol_iface;
53 } default_protocol_handler;
54 IInternetProtocol *protocol_handler;
63 DWORD apartment_thread;
67 CRITICAL_SECTION section;
68 task_header_t *task_queue_head, *task_queue_tail;
74 ProtocolProxy *filter_proxy;
77 #define BINDINFO(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
78 #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
79 #define HTTPINFO(x) ((IWinInetHttpInfo*) &(x)->lpIWinInetHttpInfoVtbl)
80 #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl)
81 #define PROTOCOLEX(x) ((IInternetProtocolEx*) &(x)->lpIInternetProtocolExVtbl)
83 #define PROTOCOLHANDLER(x) ((IInternetProtocol*) &(x)->lpIInternetProtocolHandlerVtbl)
85 #define BUFFER_SIZE 2048
86 #define MIME_TEST_SIZE 255
88 #define WM_MK_CONTINUE (WM_USER+101)
89 #define WM_MK_RELEASE (WM_USER+102)
91 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
94 case WM_MK_CONTINUE: {
95 BindProtocol *This = (BindProtocol*)lParam;
99 EnterCriticalSection(&This->section);
101 task = This->task_queue_head;
103 This->task_queue_head = task->next;
104 if(!This->task_queue_head)
105 This->task_queue_tail = NULL;
108 LeaveCriticalSection(&This->section);
113 This->continue_call++;
114 task->proc(This, task);
115 This->continue_call--;
118 IInternetProtocolEx_Release(PROTOCOLEX(This));
121 case WM_MK_RELEASE: {
122 tls_data_t *data = get_tls_data();
124 if(!--data->notif_hwnd_cnt) {
126 data->notif_hwnd = NULL;
131 return DefWindowProcW(hwnd, msg, wParam, lParam);
134 HWND get_notif_hwnd(void)
136 static ATOM wnd_class = 0;
137 tls_data_t *tls_data;
139 static const WCHAR wszURLMonikerNotificationWindow[] =
140 {'U','R','L',' ','M','o','n','i','k','e','r',' ',
141 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
143 tls_data = get_tls_data();
147 if(tls_data->notif_hwnd_cnt) {
148 tls_data->notif_hwnd_cnt++;
149 return tls_data->notif_hwnd;
153 static WNDCLASSEXW wndclass = {
155 notif_wnd_proc, 0, 0,
156 NULL, NULL, NULL, NULL, NULL,
157 wszURLMonikerNotificationWindow,
161 wndclass.hInstance = hProxyDll;
163 wnd_class = RegisterClassExW(&wndclass);
164 if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
168 tls_data->notif_hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
169 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
170 NULL, hProxyDll, NULL);
171 if(tls_data->notif_hwnd)
172 tls_data->notif_hwnd_cnt++;
174 TRACE("hwnd = %p\n", tls_data->notif_hwnd);
176 return tls_data->notif_hwnd;
179 void release_notif_hwnd(HWND hwnd)
181 tls_data_t *data = get_tls_data();
186 if(data->notif_hwnd != hwnd) {
187 PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
191 if(!--data->notif_hwnd_cnt) {
192 DestroyWindow(data->notif_hwnd);
193 data->notif_hwnd = NULL;
197 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
199 BOOL do_post = FALSE;
204 EnterCriticalSection(&This->section);
206 if(This->task_queue_tail) {
207 This->task_queue_tail->next = task;
208 This->task_queue_tail = task;
210 This->task_queue_tail = This->task_queue_head = task;
211 do_post = !This->continue_call;
214 LeaveCriticalSection(&This->section);
217 IInternetProtocolEx_AddRef(PROTOCOLEX(This));
218 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
222 static inline BOOL do_direct_notif(BindProtocol *This)
224 return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
227 static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter, LPCWSTR mime)
229 PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 };
230 IInternetProtocolSink *protocol_sink, *old_sink;
231 ProtocolProxy *filter_proxy;
234 hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&protocol_sink);
238 hres = create_protocol_proxy(&This->default_protocol_handler.IInternetProtocol_iface, This->protocol_sink, &filter_proxy);
240 IInternetProtocolSink_Release(protocol_sink);
244 old_sink = This->protocol_sink;
245 This->protocol_sink = protocol_sink;
246 This->filter_proxy = filter_proxy;
248 IInternetProtocol_AddRef(mime_filter);
249 This->protocol_handler = mime_filter;
251 filter_data.pProtocol = PROTOCOL(filter_proxy);
252 hres = IInternetProtocol_Start(mime_filter, mime, PROTSINK(filter_proxy), BINDINFO(This),
253 PI_FILTER_MODE|PI_FORCE_ASYNC, (HANDLE_PTR)&filter_data);
255 IInternetProtocolSink_Release(old_sink);
259 IInternetProtocolSink_ReportProgress(old_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL);
260 IInternetProtocolSink_Release(old_sink);
262 This->pi &= ~PI_MIMEVERIFICATION; /* FIXME: more tests */
266 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
268 IInternetProtocol *mime_filter;
271 heap_free(This->mime);
274 mime_filter = get_mime_filter(mime);
276 TRACE("Got mime filter for %s\n", debugstr_w(mime));
278 hres = handle_mime_filter(This, mime_filter, mime);
279 IInternetProtocol_Release(mime_filter);
281 FIXME("MIME filter failed: %08x\n", hres);
283 This->mime = heap_strdupW(mime);
285 if(verified || !(This->pi & PI_MIMEVERIFICATION)) {
286 This->reported_mime = TRUE;
288 if(This->protocol_sink)
289 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
294 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolEx, iface)
296 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
298 BindProtocol *This = PROTOCOL_THIS(iface);
301 if(IsEqualGUID(&IID_IUnknown, riid)) {
302 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
303 *ppv = PROTOCOLEX(This);
304 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
305 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
306 *ppv = PROTOCOLEX(This);
307 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
308 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
309 *ppv = PROTOCOLEX(This);
310 }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
311 TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
312 *ppv = PROTOCOLEX(This);
313 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
314 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
315 *ppv = BINDINFO(This);
316 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
317 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
318 *ppv = PRIORITY(This);
319 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
320 FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
321 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
322 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
323 *ppv = SERVPROV(This);
324 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
325 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
326 *ppv = PROTSINK(This);
327 }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
328 TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
331 IWinInetInfo *inet_info;
334 hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetInfo, (void**)&inet_info);
335 if(SUCCEEDED(hres)) {
336 *ppv = HTTPINFO(This);
337 IWinInetInfo_Release(inet_info);
340 }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
341 TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv);
344 IWinInetHttpInfo *http_info;
347 hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetHttpInfo, (void**)&http_info);
348 if(SUCCEEDED(hres)) {
349 *ppv = HTTPINFO(This);
350 IWinInetHttpInfo_Release(http_info);
354 WARN("not supported interface %s\n", debugstr_guid(riid));
358 return E_NOINTERFACE;
360 IUnknown_AddRef((IUnknown*)*ppv);
364 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocolEx *iface)
366 BindProtocol *This = PROTOCOL_THIS(iface);
367 LONG ref = InterlockedIncrement(&This->ref);
368 TRACE("(%p) ref=%d\n", This, ref);
372 static ULONG WINAPI BindProtocol_Release(IInternetProtocolEx *iface)
374 BindProtocol *This = PROTOCOL_THIS(iface);
375 LONG ref = InterlockedDecrement(&This->ref);
377 TRACE("(%p) ref=%d\n", This, ref);
380 if(This->wininet_info)
381 IWinInetInfo_Release(This->wininet_info);
383 IInternetProtocol_Release(This->protocol);
385 IInternetBindInfo_Release(This->bind_info);
386 if(This->protocol_handler && This->protocol_handler != &This->default_protocol_handler.IInternetProtocol_iface)
387 IInternetProtocol_Release(This->protocol_handler);
388 if(This->filter_proxy)
389 IInternetProtocol_Release(PROTOCOL(This->filter_proxy));
391 IUri_Release(This->uri);
393 set_binding_sink(PROTOCOLEX(This), NULL, NULL);
396 release_notif_hwnd(This->notif_hwnd);
397 DeleteCriticalSection(&This->section);
399 heap_free(This->mime);
402 URLMON_UnlockModule();
408 static HRESULT WINAPI BindProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
409 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
410 DWORD grfPI, HANDLE_PTR dwReserved)
412 BindProtocol *This = PROTOCOL_THIS(iface);
416 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
417 pOIBindInfo, grfPI, dwReserved);
419 hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
423 hres = IInternetProtocolEx_StartEx(PROTOCOLEX(This), uri, pOIProtSink, pOIBindInfo,
424 grfPI, (HANDLE*)dwReserved);
430 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
432 BindProtocol *This = PROTOCOL_THIS(iface);
434 TRACE("(%p)->(%p)\n", This, pProtocolData);
436 return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
439 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
442 BindProtocol *This = PROTOCOL_THIS(iface);
444 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
446 return IInternetProtocol_Abort(This->protocol_handler, hrReason, dwOptions);
449 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
451 BindProtocol *This = PROTOCOL_THIS(iface);
453 TRACE("(%p)->(%08x)\n", This, dwOptions);
455 return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
458 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocolEx *iface)
460 BindProtocol *This = PROTOCOL_THIS(iface);
461 FIXME("(%p)\n", This);
465 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocolEx *iface)
467 BindProtocol *This = PROTOCOL_THIS(iface);
468 FIXME("(%p)\n", This);
472 static HRESULT WINAPI BindProtocol_Read(IInternetProtocolEx *iface, void *pv,
473 ULONG cb, ULONG *pcbRead)
475 BindProtocol *This = PROTOCOL_THIS(iface);
477 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
481 return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
484 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
485 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
487 BindProtocol *This = PROTOCOL_THIS(iface);
488 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
492 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
494 BindProtocol *This = PROTOCOL_THIS(iface);
496 TRACE("(%p)->(%08x)\n", This, dwOptions);
498 return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
501 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocolEx *iface)
503 BindProtocol *This = PROTOCOL_THIS(iface);
505 TRACE("(%p)\n", This);
507 return IInternetProtocol_UnlockRequest(This->protocol_handler);
510 static HRESULT WINAPI BindProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
511 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
512 DWORD grfPI, HANDLE *dwReserved)
514 BindProtocol *This = PROTOCOL_THIS(iface);
515 IInternetProtocol *protocol = NULL;
516 IInternetProtocolEx *protocolex;
517 IInternetPriority *priority;
518 IServiceProvider *service_provider;
519 BOOL urlmon_protocol = FALSE;
520 CLSID clsid = IID_NULL;
524 TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
526 if(!pUri || !pOIProtSink || !pOIBindInfo)
534 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
535 (void**)&service_provider);
536 if(SUCCEEDED(hres)) {
537 /* FIXME: What's protocol CLSID here? */
538 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
539 &IID_IInternetProtocol, (void**)&protocol);
540 IServiceProvider_Release(service_provider);
547 hres = get_protocol_handler(pUri, &clsid, &urlmon_protocol, &cf);
551 if(This->from_urlmon) {
552 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
553 IClassFactory_Release(cf);
557 hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
558 &IID_IUnknown, (void**)&unk);
559 IClassFactory_Release(cf);
563 hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
564 IUnknown_Release(unk);
570 StringFromCLSID(&clsid, &clsid_str);
571 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
572 CoTaskMemFree(clsid_str);
574 This->protocol = protocol;
577 IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
579 set_binding_sink(PROTOCOLEX(This), pOIProtSink, pOIBindInfo);
581 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
582 if(SUCCEEDED(hres)) {
583 IInternetPriority_SetPriority(priority, This->priority);
584 IInternetPriority_Release(priority);
587 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolEx, (void**)&protocolex);
588 if(SUCCEEDED(hres)) {
589 hres = IInternetProtocolEx_StartEx(protocolex, pUri, PROTSINK(This), BINDINFO(This), 0, NULL);
590 IInternetProtocolEx_Release(protocolex);
594 hres = IUri_GetDisplayUri(pUri, &display_uri);
598 hres = IInternetProtocol_Start(protocol, display_uri, PROTSINK(This), BINDINFO(This), 0, 0);
599 SysFreeString(display_uri);
605 void set_binding_sink(IInternetProtocolEx *bind_protocol, IInternetProtocolSink *sink, IInternetBindInfo *bind_info)
607 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
608 IInternetProtocolSink *prev_sink;
609 IServiceProvider *service_provider = NULL;
612 IInternetProtocolSink_AddRef(sink);
613 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
615 IInternetProtocolSink_Release(prev_sink);
618 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
619 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
621 IServiceProvider_Release(service_provider);
624 IInternetBindInfo_AddRef(bind_info);
625 bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info);
627 IInternetBindInfo_Release(bind_info);
630 IWinInetInfo *get_wininet_info(IInternetProtocolEx *bind_protocol)
632 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
634 return This->wininet_info;
639 static const IInternetProtocolExVtbl BindProtocolVtbl = {
640 BindProtocol_QueryInterface,
642 BindProtocol_Release,
644 BindProtocol_Continue,
646 BindProtocol_Terminate,
647 BindProtocol_Suspend,
651 BindProtocol_LockRequest,
652 BindProtocol_UnlockRequest,
656 static inline BindProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
658 return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocol_iface);
661 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
663 ERR("should not be called\n");
664 return E_NOINTERFACE;
667 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
669 BindProtocol *This = impl_from_IInternetProtocol(iface);
670 return IInternetProtocolEx_AddRef(PROTOCOLEX(This));
673 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
675 BindProtocol *This = impl_from_IInternetProtocol(iface);
676 return IInternetProtocolEx_Release(PROTOCOLEX(This));
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");
687 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
689 BindProtocol *This = impl_from_IInternetProtocol(iface);
692 TRACE("(%p)->(%p)\n", This, pProtocolData);
694 hres = IInternetProtocol_Continue(This->protocol, pProtocolData);
696 heap_free(pProtocolData);
700 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
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);
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)
722 IInternetProtocol_Terminate(This->protocol, 0);
724 if(This->filter_proxy) {
725 IInternetProtocol_Release(PROTOCOL(This->filter_proxy));
726 This->filter_proxy = NULL;
729 set_binding_sink(PROTOCOLEX(This), NULL, NULL);
731 if(This->bind_info) {
732 IInternetBindInfo_Release(This->bind_info);
733 This->bind_info = NULL;
739 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
741 BindProtocol *This = impl_from_IInternetProtocol(iface);
742 FIXME("(%p)\n", This);
746 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
748 BindProtocol *This = impl_from_IInternetProtocol(iface);
749 FIXME("(%p)\n", This);
753 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
754 ULONG cb, ULONG *pcbRead)
756 BindProtocol *This = impl_from_IInternetProtocol(iface);
760 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
763 read = min(cb, This->buf_size);
764 memcpy(pv, This->buf, read);
766 if(read == This->buf_size) {
767 heap_free(This->buf);
770 memmove(This->buf, This->buf+cb, This->buf_size-cb);
773 This->buf_size -= read;
779 hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
787 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
788 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
790 BindProtocol *This = impl_from_IInternetProtocol(iface);
791 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
795 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
797 BindProtocol *This = impl_from_IInternetProtocol(iface);
799 TRACE("(%p)->(%08x)\n", This, dwOptions);
801 return IInternetProtocol_LockRequest(This->protocol, dwOptions);
804 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
806 BindProtocol *This = impl_from_IInternetProtocol(iface);
808 TRACE("(%p)\n", This);
810 return IInternetProtocol_UnlockRequest(This->protocol);
813 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
814 ProtocolHandler_QueryInterface,
815 ProtocolHandler_AddRef,
816 ProtocolHandler_Release,
817 ProtocolHandler_Start,
818 ProtocolHandler_Continue,
819 ProtocolHandler_Abort,
820 ProtocolHandler_Terminate,
821 ProtocolHandler_Suspend,
822 ProtocolHandler_Resume,
823 ProtocolHandler_Read,
824 ProtocolHandler_Seek,
825 ProtocolHandler_LockRequest,
826 ProtocolHandler_UnlockRequest
829 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
831 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
832 REFIID riid, void **ppv)
834 BindProtocol *This = BINDINFO_THIS(iface);
835 return IInternetProtocolEx_QueryInterface(PROTOCOLEX(This), riid, ppv);
838 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
840 BindProtocol *This = BINDINFO_THIS(iface);
841 return IInternetProtocolEx_AddRef(PROTOCOLEX(This));
844 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
846 BindProtocol *This = BINDINFO_THIS(iface);
847 return IInternetProtocolEx_Release(PROTOCOLEX(This));
850 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
851 DWORD *grfBINDF, BINDINFO *pbindinfo)
853 BindProtocol *This = BINDINFO_THIS(iface);
856 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
858 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
860 WARN("GetBindInfo failed: %08x\n", hres);
864 *grfBINDF |= BINDF_FROMURLMON;
868 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
869 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
871 BindProtocol *This = BINDINFO_THIS(iface);
873 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
875 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
880 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
881 BindInfo_QueryInterface,
884 BindInfo_GetBindInfo,
885 BindInfo_GetBindString
888 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
890 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
891 REFIID riid, void **ppv)
893 BindProtocol *This = PRIORITY_THIS(iface);
894 return IInternetProtocolEx_QueryInterface(PROTOCOLEX(This), riid, ppv);
897 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
899 BindProtocol *This = PRIORITY_THIS(iface);
900 return IInternetProtocolEx_AddRef(PROTOCOLEX(This));
903 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
905 BindProtocol *This = PRIORITY_THIS(iface);
906 return IInternetProtocolEx_Release(PROTOCOLEX(This));
909 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
911 BindProtocol *This = PRIORITY_THIS(iface);
913 TRACE("(%p)->(%d)\n", This, nPriority);
915 This->priority = nPriority;
919 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
921 BindProtocol *This = PRIORITY_THIS(iface);
923 TRACE("(%p)->(%p)\n", This, pnPriority);
925 *pnPriority = This->priority;
931 static const IInternetPriorityVtbl InternetPriorityVtbl = {
932 InternetPriority_QueryInterface,
933 InternetPriority_AddRef,
934 InternetPriority_Release,
935 InternetPriority_SetPriority,
936 InternetPriority_GetPriority
940 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolSink, iface)
942 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
943 REFIID riid, void **ppv)
945 BindProtocol *This = PROTSINK_THIS(iface);
946 return IInternetProtocolEx_QueryInterface(PROTOCOLEX(This), riid, ppv);
949 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
951 BindProtocol *This = PROTSINK_THIS(iface);
952 return IInternetProtocolEx_AddRef(PROTOCOLEX(This));
955 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
957 BindProtocol *This = PROTSINK_THIS(iface);
958 return IInternetProtocolEx_Release(PROTOCOLEX(This));
962 task_header_t header;
966 static void switch_proc(BindProtocol *bind, task_header_t *t)
968 switch_task_t *task = (switch_task_t*)t;
970 IInternetProtocol_Continue(bind->protocol_handler, task->data);
975 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
976 PROTOCOLDATA *pProtocolData)
978 BindProtocol *This = PROTSINK_THIS(iface);
981 TRACE("(%p)->(%p)\n", This, pProtocolData);
983 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
984 pProtocolData->pData, pProtocolData->cbData);
986 data = heap_alloc(sizeof(PROTOCOLDATA));
988 return E_OUTOFMEMORY;
989 memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
991 if(!do_direct_notif(This)) {
994 task = heap_alloc(sizeof(switch_task_t));
996 return E_OUTOFMEMORY;
1000 push_task(This, &task->header, switch_proc);
1004 if(!This->protocol_sink) {
1005 IInternetProtocol_Continue(This->protocol_handler, data);
1009 return IInternetProtocolSink_Switch(This->protocol_sink, data);
1012 static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
1014 switch(status_code) {
1015 case BINDSTATUS_FINDINGRESOURCE:
1016 case BINDSTATUS_CONNECTING:
1017 case BINDSTATUS_REDIRECTING:
1018 case BINDSTATUS_BEGINDOWNLOADDATA:
1019 case BINDSTATUS_SENDINGREQUEST:
1020 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
1021 case BINDSTATUS_DIRECTBIND:
1022 case BINDSTATUS_ACCEPTRANGES:
1023 if(This->protocol_sink)
1024 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
1027 case BINDSTATUS_MIMETYPEAVAILABLE:
1028 mime_available(This, status_text, FALSE);
1031 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
1032 mime_available(This, status_text, TRUE);
1036 FIXME("unsupported ulStatusCode %u\n", status_code);
1041 task_header_t header;
1045 } on_progress_task_t;
1047 static void on_progress_proc(BindProtocol *This, task_header_t *t)
1049 on_progress_task_t *task = (on_progress_task_t*)t;
1051 report_progress(This, task->status_code, task->status_text);
1053 heap_free(task->status_text);
1057 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
1058 ULONG ulStatusCode, LPCWSTR szStatusText)
1060 BindProtocol *This = PROTSINK_THIS(iface);
1062 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
1064 if(do_direct_notif(This)) {
1065 report_progress(This, ulStatusCode, szStatusText);
1067 on_progress_task_t *task;
1069 task = heap_alloc(sizeof(on_progress_task_t));
1071 task->status_code = ulStatusCode;
1072 task->status_text = heap_strdupW(szStatusText);
1074 push_task(This, &task->header, on_progress_proc);
1080 static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max)
1082 if(!This->protocol_sink)
1085 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
1086 BYTE buf[BUFFER_SIZE];
1093 hres = IInternetProtocol_Read(This->protocol, buf,
1094 sizeof(buf)-This->buf_size, &read);
1095 if(FAILED(hres) && hres != E_PENDING)
1099 This->buf = heap_alloc(BUFFER_SIZE);
1101 return E_OUTOFMEMORY;
1102 }else if(read + This->buf_size > BUFFER_SIZE) {
1105 tmp = heap_realloc(This->buf, read+This->buf_size);
1107 return E_OUTOFMEMORY;
1111 memcpy(This->buf+This->buf_size, buf, read);
1112 This->buf_size += read;
1113 }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
1115 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
1118 bscf = BSCF_FIRSTDATANOTIFICATION;
1120 bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
1122 if(!This->reported_mime) {
1125 hres = IUri_GetRawUri(This->uri, &raw_uri);
1129 hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE),
1130 This->mime, 0, &mime, 0);
1131 SysFreeString(raw_uri);
1135 mime_available(This, mime, TRUE);
1136 CoTaskMemFree(mime);
1140 if(!This->protocol_sink)
1143 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
1147 task_header_t header;
1151 } report_data_task_t;
1153 static void report_data_proc(BindProtocol *This, task_header_t *t)
1155 report_data_task_t *task = (report_data_task_t*)t;
1157 report_data(This, task->bscf, task->progress, task->progress_max);
1161 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1162 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1164 BindProtocol *This = PROTSINK_THIS(iface);
1166 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1168 if(!This->protocol_sink)
1171 if(!do_direct_notif(This)) {
1172 report_data_task_t *task;
1174 task = heap_alloc(sizeof(report_data_task_t));
1176 return E_OUTOFMEMORY;
1178 task->bscf = grfBSCF;
1179 task->progress = ulProgress;
1180 task->progress_max = ulProgressMax;
1182 push_task(This, &task->header, report_data_proc);
1186 return report_data(This, grfBSCF, ulProgress, ulProgressMax);
1190 task_header_t header;
1195 } report_result_task_t;
1197 static void report_result_proc(BindProtocol *This, task_header_t *t)
1199 report_result_task_t *task = (report_result_task_t*)t;
1201 if(This->protocol_sink)
1202 IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str);
1204 heap_free(task->str);
1208 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1209 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1211 BindProtocol *This = PROTSINK_THIS(iface);
1213 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1215 if(!This->protocol_sink)
1218 This->reported_result = TRUE;
1220 if(!do_direct_notif(This)) {
1221 report_result_task_t *task;
1223 task = heap_alloc(sizeof(report_result_task_t));
1225 return E_OUTOFMEMORY;
1227 task->hres = hrResult;
1228 task->err = dwError;
1229 task->str = heap_strdupW(szResult);
1231 push_task(This, &task->header, report_result_proc);
1235 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1238 #undef PROTSINK_THIS
1240 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1241 BPInternetProtocolSink_QueryInterface,
1242 BPInternetProtocolSink_AddRef,
1243 BPInternetProtocolSink_Release,
1244 BPInternetProtocolSink_Switch,
1245 BPInternetProtocolSink_ReportProgress,
1246 BPInternetProtocolSink_ReportData,
1247 BPInternetProtocolSink_ReportResult
1250 #define INETINFO_THIS(iface) DEFINE_THIS(BindProtocol, IWinInetHttpInfo, iface)
1252 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
1254 BindProtocol *This = INETINFO_THIS(iface);
1255 return IInternetProtocolEx_QueryInterface(PROTOCOLEX(This), riid, ppv);
1258 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface)
1260 BindProtocol *This = INETINFO_THIS(iface);
1261 return IInternetProtocolEx_AddRef(PROTOCOLEX(This));
1264 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface)
1266 BindProtocol *This = INETINFO_THIS(iface);
1267 return IInternetProtocolEx_Release(PROTOCOLEX(This));
1270 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
1271 void *pBuffer, DWORD *pcbBuffer)
1273 BindProtocol *This = INETINFO_THIS(iface);
1274 FIXME("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
1278 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
1279 void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
1281 BindProtocol *This = INETINFO_THIS(iface);
1282 FIXME("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
1286 #undef INETINFO_THIS
1288 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
1289 WinInetHttpInfo_QueryInterface,
1290 WinInetHttpInfo_AddRef,
1291 WinInetHttpInfo_Release,
1292 WinInetHttpInfo_QueryOption,
1293 WinInetHttpInfo_QueryInfo
1296 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
1298 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1299 REFIID riid, void **ppv)
1301 BindProtocol *This = SERVPROV_THIS(iface);
1302 return IInternetProtocolEx_QueryInterface(PROTOCOLEX(This), riid, ppv);
1305 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1307 BindProtocol *This = SERVPROV_THIS(iface);
1308 return IInternetProtocolEx_AddRef(PROTOCOLEX(This));
1311 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1313 BindProtocol *This = SERVPROV_THIS(iface);
1314 return IInternetProtocolEx_Release(PROTOCOLEX(This));
1317 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1318 REFGUID guidService, REFIID riid, void **ppv)
1320 BindProtocol *This = SERVPROV_THIS(iface);
1322 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1324 if(!This->service_provider)
1325 return E_NOINTERFACE;
1327 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1330 #undef SERVPROV_THIS
1332 static const IServiceProviderVtbl ServiceProviderVtbl = {
1333 BPServiceProvider_QueryInterface,
1334 BPServiceProvider_AddRef,
1335 BPServiceProvider_Release,
1336 BPServiceProvider_QueryService
1339 HRESULT create_binding_protocol(BOOL from_urlmon, IInternetProtocolEx **protocol)
1341 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1343 ret->lpIInternetProtocolExVtbl = &BindProtocolVtbl;
1344 ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
1345 ret->lpInternetPriorityVtbl = &InternetPriorityVtbl;
1346 ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
1347 ret->lpIInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1348 ret->lpIWinInetHttpInfoVtbl = &WinInetHttpInfoVtbl;
1350 ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
1353 ret->from_urlmon = from_urlmon;
1354 ret->apartment_thread = GetCurrentThreadId();
1355 ret->notif_hwnd = get_notif_hwnd();
1356 ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
1357 InitializeCriticalSection(&ret->section);
1359 URLMON_LockModule();
1361 *protocol = PROTOCOLEX(ret);