2 * Copyright 2007-2009 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "urlmon_main.h"
20 #include "wine/debug.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
24 typedef void (*task_proc_t)(BindProtocol*,task_header_t*);
26 struct _task_header_t {
31 #define BUFFER_SIZE 2048
32 #define MIME_TEST_SIZE 255
34 #define WM_MK_CONTINUE (WM_USER+101)
35 #define WM_MK_RELEASE (WM_USER+102)
37 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
40 case WM_MK_CONTINUE: {
41 BindProtocol *This = (BindProtocol*)lParam;
45 EnterCriticalSection(&This->section);
47 task = This->task_queue_head;
49 This->task_queue_head = task->next;
50 if(!This->task_queue_head)
51 This->task_queue_tail = NULL;
54 LeaveCriticalSection(&This->section);
59 This->continue_call++;
60 task->proc(This, task);
61 This->continue_call--;
64 IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
68 tls_data_t *data = get_tls_data();
70 if(!--data->notif_hwnd_cnt) {
72 data->notif_hwnd = NULL;
77 return DefWindowProcW(hwnd, msg, wParam, lParam);
80 HWND get_notif_hwnd(void)
82 static ATOM wnd_class = 0;
85 static const WCHAR wszURLMonikerNotificationWindow[] =
86 {'U','R','L',' ','M','o','n','i','k','e','r',' ',
87 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
89 tls_data = get_tls_data();
93 if(tls_data->notif_hwnd_cnt) {
94 tls_data->notif_hwnd_cnt++;
95 return tls_data->notif_hwnd;
99 static WNDCLASSEXW wndclass = {
101 notif_wnd_proc, 0, 0,
102 NULL, NULL, NULL, NULL, NULL,
103 wszURLMonikerNotificationWindow,
107 wndclass.hInstance = hProxyDll;
109 wnd_class = RegisterClassExW(&wndclass);
110 if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
114 tls_data->notif_hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
115 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
116 NULL, hProxyDll, NULL);
117 if(tls_data->notif_hwnd)
118 tls_data->notif_hwnd_cnt++;
120 TRACE("hwnd = %p\n", tls_data->notif_hwnd);
122 return tls_data->notif_hwnd;
125 void release_notif_hwnd(HWND hwnd)
127 tls_data_t *data = get_tls_data();
132 if(data->notif_hwnd != hwnd) {
133 PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
137 if(!--data->notif_hwnd_cnt) {
138 DestroyWindow(data->notif_hwnd);
139 data->notif_hwnd = NULL;
143 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
145 BOOL do_post = FALSE;
150 EnterCriticalSection(&This->section);
152 if(This->task_queue_tail) {
153 This->task_queue_tail->next = task;
154 This->task_queue_tail = task;
156 This->task_queue_tail = This->task_queue_head = task;
157 do_post = !This->continue_call;
160 LeaveCriticalSection(&This->section);
163 IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
164 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
168 static inline BOOL do_direct_notif(BindProtocol *This)
170 return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
173 static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter, LPCWSTR mime)
175 PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 };
176 IInternetProtocolSink *protocol_sink, *old_sink;
177 ProtocolProxy *filter_proxy;
180 hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&protocol_sink);
184 hres = create_protocol_proxy(&This->default_protocol_handler.IInternetProtocol_iface, This->protocol_sink, &filter_proxy);
186 IInternetProtocolSink_Release(protocol_sink);
190 old_sink = This->protocol_sink;
191 This->protocol_sink = protocol_sink;
192 This->filter_proxy = filter_proxy;
194 IInternetProtocol_AddRef(mime_filter);
195 This->protocol_handler = mime_filter;
197 filter_data.pProtocol = &filter_proxy->IInternetProtocol_iface;
198 hres = IInternetProtocol_Start(mime_filter, mime, &filter_proxy->IInternetProtocolSink_iface,
199 &This->IInternetBindInfo_iface, PI_FILTER_MODE|PI_FORCE_ASYNC,
200 (HANDLE_PTR)&filter_data);
202 IInternetProtocolSink_Release(old_sink);
206 /* NOTE: IE9 calls it on the new protocol_sink. It doesn't make sense to is seems to be a bug there. */
207 IInternetProtocolSink_ReportProgress(old_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL);
208 IInternetProtocolSink_Release(old_sink);
210 This->pi &= ~PI_MIMEVERIFICATION; /* FIXME: more tests */
214 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
216 IInternetProtocol *mime_filter;
219 heap_free(This->mime);
222 mime_filter = get_mime_filter(mime);
224 TRACE("Got mime filter for %s\n", debugstr_w(mime));
226 hres = handle_mime_filter(This, mime_filter, mime);
227 IInternetProtocol_Release(mime_filter);
229 FIXME("MIME filter failed: %08x\n", hres);
231 This->mime = heap_strdupW(mime);
233 if(verified || !(This->pi & PI_MIMEVERIFICATION)) {
234 This->reported_mime = TRUE;
236 if(This->protocol_sink)
237 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
242 static inline BindProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
244 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolEx_iface);
247 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
249 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
252 if(IsEqualGUID(&IID_IUnknown, riid)) {
253 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
254 *ppv = &This->IInternetProtocolEx_iface;
255 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
256 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
257 *ppv = &This->IInternetProtocolEx_iface;
258 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
259 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
260 *ppv = &This->IInternetProtocolEx_iface;
261 }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
262 TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
263 *ppv = &This->IInternetProtocolEx_iface;
264 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
265 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
266 *ppv = &This->IInternetBindInfo_iface;
267 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
268 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
269 *ppv = &This->IInternetPriority_iface;
270 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
271 FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
272 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
273 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
274 *ppv = &This->IServiceProvider_iface;
275 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
276 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
277 *ppv = &This->IInternetProtocolSink_iface;
278 }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
279 TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
282 IWinInetInfo *inet_info;
285 hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetInfo, (void**)&inet_info);
286 if(SUCCEEDED(hres)) {
287 *ppv = &This->IWinInetHttpInfo_iface;
288 IWinInetInfo_Release(inet_info);
291 }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
292 TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv);
295 IWinInetHttpInfo *http_info;
298 hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetHttpInfo, (void**)&http_info);
299 if(SUCCEEDED(hres)) {
300 *ppv = &This->IWinInetHttpInfo_iface;
301 IWinInetHttpInfo_Release(http_info);
305 WARN("not supported interface %s\n", debugstr_guid(riid));
309 return E_NOINTERFACE;
311 IUnknown_AddRef((IUnknown*)*ppv);
315 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocolEx *iface)
317 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
318 LONG ref = InterlockedIncrement(&This->ref);
319 TRACE("(%p) ref=%d\n", This, ref);
323 static ULONG WINAPI BindProtocol_Release(IInternetProtocolEx *iface)
325 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
326 LONG ref = InterlockedDecrement(&This->ref);
328 TRACE("(%p) ref=%d\n", This, ref);
331 if(This->wininet_info)
332 IWinInetInfo_Release(This->wininet_info);
333 if(This->wininet_http_info)
334 IWinInetHttpInfo_Release(This->wininet_http_info);
336 IInternetProtocol_Release(This->protocol);
338 IInternetBindInfo_Release(This->bind_info);
339 if(This->protocol_handler && This->protocol_handler != &This->default_protocol_handler.IInternetProtocol_iface)
340 IInternetProtocol_Release(This->protocol_handler);
341 if(This->filter_proxy)
342 IInternetProtocol_Release(&This->filter_proxy->IInternetProtocol_iface);
344 IUri_Release(This->uri);
345 SysFreeString(This->display_uri);
347 set_binding_sink(This, NULL, NULL);
350 release_notif_hwnd(This->notif_hwnd);
351 This->section.DebugInfo->Spare[0] = 0;
352 DeleteCriticalSection(&This->section);
354 heap_free(This->mime);
357 URLMON_UnlockModule();
363 static HRESULT WINAPI BindProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
364 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
365 DWORD grfPI, HANDLE_PTR dwReserved)
367 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
371 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
372 pOIBindInfo, grfPI, dwReserved);
374 hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
378 hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
379 pOIBindInfo, grfPI, (HANDLE*)dwReserved);
385 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
387 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
389 TRACE("(%p)->(%p)\n", This, pProtocolData);
391 return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
394 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
397 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
399 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
401 return IInternetProtocol_Abort(This->protocol_handler, hrReason, dwOptions);
404 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
406 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
408 TRACE("(%p)->(%08x)\n", This, dwOptions);
410 return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
413 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocolEx *iface)
415 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
416 FIXME("(%p)\n", This);
420 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocolEx *iface)
422 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
423 FIXME("(%p)\n", This);
427 static HRESULT WINAPI BindProtocol_Read(IInternetProtocolEx *iface, void *pv,
428 ULONG cb, ULONG *pcbRead)
430 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
432 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
436 return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
439 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
440 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
442 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
443 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
447 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
449 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
451 TRACE("(%p)->(%08x)\n", This, dwOptions);
453 return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
456 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocolEx *iface)
458 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
460 TRACE("(%p)\n", This);
462 return IInternetProtocol_UnlockRequest(This->protocol_handler);
465 static HRESULT WINAPI BindProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
466 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
467 DWORD grfPI, HANDLE *dwReserved)
469 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
470 IInternetProtocol *protocol = NULL;
471 IInternetProtocolEx *protocolex;
472 IInternetPriority *priority;
473 IServiceProvider *service_provider;
474 BOOL urlmon_protocol = FALSE;
475 CLSID clsid = IID_NULL;
479 TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
481 if(!pUri || !pOIProtSink || !pOIBindInfo)
489 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
490 (void**)&service_provider);
491 if(SUCCEEDED(hres)) {
492 /* FIXME: What's protocol CLSID here? */
493 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
494 &IID_IInternetProtocol, (void**)&protocol);
495 IServiceProvider_Release(service_provider);
502 hres = get_protocol_handler(pUri, &clsid, &urlmon_protocol, &cf);
506 if(This->from_urlmon) {
507 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
508 IClassFactory_Release(cf);
512 hres = IClassFactory_CreateInstance(cf, (IUnknown*)&This->IInternetBindInfo_iface,
513 &IID_IUnknown, (void**)&unk);
514 IClassFactory_Release(cf);
518 hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
519 IUnknown_Release(unk);
525 StringFromCLSID(&clsid, &clsid_str);
526 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
527 CoTaskMemFree(clsid_str);
529 This->protocol = protocol;
531 if(urlmon_protocol) {
532 IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
533 IInternetProtocol_QueryInterface(protocol, &IID_IWinInetHttpInfo, (void**)&This->wininet_http_info);
536 set_binding_sink(This, pOIProtSink, pOIBindInfo);
538 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
539 if(SUCCEEDED(hres)) {
540 IInternetPriority_SetPriority(priority, This->priority);
541 IInternetPriority_Release(priority);
544 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolEx, (void**)&protocolex);
545 if(SUCCEEDED(hres)) {
546 hres = IInternetProtocolEx_StartEx(protocolex, pUri, &This->IInternetProtocolSink_iface,
547 &This->IInternetBindInfo_iface, 0, NULL);
548 IInternetProtocolEx_Release(protocolex);
550 hres = IUri_GetDisplayUri(pUri, &This->display_uri);
554 hres = IInternetProtocol_Start(protocol, This->display_uri, &This->IInternetProtocolSink_iface,
555 &This->IInternetBindInfo_iface, 0, 0);
561 void set_binding_sink(BindProtocol *This, IInternetProtocolSink *sink, IInternetBindInfo *bind_info)
563 IInternetProtocolSink *prev_sink;
564 IServiceProvider *service_provider = NULL;
567 IInternetProtocolSink_AddRef(sink);
568 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
570 IInternetProtocolSink_Release(prev_sink);
573 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
574 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
576 IServiceProvider_Release(service_provider);
579 IInternetBindInfo_AddRef(bind_info);
580 bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info);
582 IInternetBindInfo_Release(bind_info);
585 static const IInternetProtocolExVtbl BindProtocolVtbl = {
586 BindProtocol_QueryInterface,
588 BindProtocol_Release,
590 BindProtocol_Continue,
592 BindProtocol_Terminate,
593 BindProtocol_Suspend,
597 BindProtocol_LockRequest,
598 BindProtocol_UnlockRequest,
602 static inline BindProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
604 return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocol_iface);
607 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
609 ERR("should not be called\n");
610 return E_NOINTERFACE;
613 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
615 BindProtocol *This = impl_from_IInternetProtocol(iface);
616 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
619 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
621 BindProtocol *This = impl_from_IInternetProtocol(iface);
622 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
625 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
626 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
627 DWORD grfPI, HANDLE_PTR dwReserved)
629 ERR("Should not be called\n");
633 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
635 BindProtocol *This = impl_from_IInternetProtocol(iface);
638 TRACE("(%p)->(%p)\n", This, pProtocolData);
640 hres = IInternetProtocol_Continue(This->protocol, pProtocolData);
642 heap_free(pProtocolData);
646 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
649 BindProtocol *This = impl_from_IInternetProtocol(iface);
651 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
653 if(This->protocol && !This->reported_result)
654 return IInternetProtocol_Abort(This->protocol, hrReason, dwOptions);
659 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
661 BindProtocol *This = impl_from_IInternetProtocol(iface);
663 TRACE("(%p)->(%08x)\n", This, dwOptions);
665 if(!This->reported_result)
668 IInternetProtocol_Terminate(This->protocol, 0);
670 if(This->filter_proxy) {
671 IInternetProtocol_Release(&This->filter_proxy->IInternetProtocol_iface);
672 This->filter_proxy = NULL;
675 set_binding_sink(This, NULL, NULL);
677 if(This->bind_info) {
678 IInternetBindInfo_Release(This->bind_info);
679 This->bind_info = NULL;
685 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
687 BindProtocol *This = impl_from_IInternetProtocol(iface);
688 FIXME("(%p)\n", This);
692 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
694 BindProtocol *This = impl_from_IInternetProtocol(iface);
695 FIXME("(%p)\n", This);
699 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
700 ULONG cb, ULONG *pcbRead)
702 BindProtocol *This = impl_from_IInternetProtocol(iface);
706 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
709 read = min(cb, This->buf_size);
710 memcpy(pv, This->buf, read);
712 if(read == This->buf_size) {
713 heap_free(This->buf);
716 memmove(This->buf, This->buf+cb, This->buf_size-cb);
719 This->buf_size -= read;
725 hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
733 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
734 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
736 BindProtocol *This = impl_from_IInternetProtocol(iface);
737 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
741 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
743 BindProtocol *This = impl_from_IInternetProtocol(iface);
745 TRACE("(%p)->(%08x)\n", This, dwOptions);
747 return IInternetProtocol_LockRequest(This->protocol, dwOptions);
750 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
752 BindProtocol *This = impl_from_IInternetProtocol(iface);
754 TRACE("(%p)\n", This);
756 return IInternetProtocol_UnlockRequest(This->protocol);
759 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
760 ProtocolHandler_QueryInterface,
761 ProtocolHandler_AddRef,
762 ProtocolHandler_Release,
763 ProtocolHandler_Start,
764 ProtocolHandler_Continue,
765 ProtocolHandler_Abort,
766 ProtocolHandler_Terminate,
767 ProtocolHandler_Suspend,
768 ProtocolHandler_Resume,
769 ProtocolHandler_Read,
770 ProtocolHandler_Seek,
771 ProtocolHandler_LockRequest,
772 ProtocolHandler_UnlockRequest
775 static inline BindProtocol *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
777 return CONTAINING_RECORD(iface, BindProtocol, IInternetBindInfo_iface);
780 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
781 REFIID riid, void **ppv)
783 BindProtocol *This = impl_from_IInternetBindInfo(iface);
784 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
787 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
789 BindProtocol *This = impl_from_IInternetBindInfo(iface);
790 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
793 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
795 BindProtocol *This = impl_from_IInternetBindInfo(iface);
796 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
799 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
800 DWORD *grfBINDF, BINDINFO *pbindinfo)
802 BindProtocol *This = impl_from_IInternetBindInfo(iface);
805 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
807 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
809 WARN("GetBindInfo failed: %08x\n", hres);
813 *grfBINDF |= BINDF_FROMURLMON;
817 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
818 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
820 BindProtocol *This = impl_from_IInternetBindInfo(iface);
822 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
824 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
827 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
828 BindInfo_QueryInterface,
831 BindInfo_GetBindInfo,
832 BindInfo_GetBindString
835 static inline BindProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
837 return CONTAINING_RECORD(iface, BindProtocol, IInternetPriority_iface);
840 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
841 REFIID riid, void **ppv)
843 BindProtocol *This = impl_from_IInternetPriority(iface);
844 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
847 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
849 BindProtocol *This = impl_from_IInternetPriority(iface);
850 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
853 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
855 BindProtocol *This = impl_from_IInternetPriority(iface);
856 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
859 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
861 BindProtocol *This = impl_from_IInternetPriority(iface);
863 TRACE("(%p)->(%d)\n", This, nPriority);
865 This->priority = nPriority;
869 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
871 BindProtocol *This = impl_from_IInternetPriority(iface);
873 TRACE("(%p)->(%p)\n", This, pnPriority);
875 *pnPriority = This->priority;
879 static const IInternetPriorityVtbl InternetPriorityVtbl = {
880 InternetPriority_QueryInterface,
881 InternetPriority_AddRef,
882 InternetPriority_Release,
883 InternetPriority_SetPriority,
884 InternetPriority_GetPriority
888 static inline BindProtocol *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
890 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolSink_iface);
893 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
894 REFIID riid, void **ppv)
896 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
897 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
900 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
902 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
903 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
906 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
908 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
909 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
913 task_header_t header;
917 static void switch_proc(BindProtocol *bind, task_header_t *t)
919 switch_task_t *task = (switch_task_t*)t;
921 IInternetProtocol_Continue(bind->protocol_handler, task->data);
926 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
927 PROTOCOLDATA *pProtocolData)
929 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
932 TRACE("(%p)->(%p)\n", This, pProtocolData);
934 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
935 pProtocolData->pData, pProtocolData->cbData);
937 data = heap_alloc(sizeof(PROTOCOLDATA));
939 return E_OUTOFMEMORY;
940 memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
942 if((This->pi&PI_APARTMENTTHREADED && pProtocolData->grfFlags&PI_FORCE_ASYNC)
943 || !do_direct_notif(This)) {
946 task = heap_alloc(sizeof(switch_task_t));
948 return E_OUTOFMEMORY;
952 push_task(This, &task->header, switch_proc);
956 if(!This->protocol_sink) {
957 IInternetProtocol_Continue(This->protocol_handler, data);
961 return IInternetProtocolSink_Switch(This->protocol_sink, data);
964 static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
966 switch(status_code) {
967 case BINDSTATUS_FINDINGRESOURCE:
968 case BINDSTATUS_CONNECTING:
969 case BINDSTATUS_REDIRECTING:
970 case BINDSTATUS_SENDINGREQUEST:
971 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
972 case BINDSTATUS_DIRECTBIND:
973 case BINDSTATUS_ACCEPTRANGES:
974 if(This->protocol_sink)
975 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
978 case BINDSTATUS_BEGINDOWNLOADDATA:
979 if(This->protocol_sink)
980 IInternetProtocolSink_ReportData(This->protocol_sink, This->bscf, This->progress, This->progress_max);
983 case BINDSTATUS_MIMETYPEAVAILABLE:
984 mime_available(This, status_text, FALSE);
987 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
988 mime_available(This, status_text, TRUE);
992 FIXME("unsupported ulStatusCode %u\n", status_code);
997 task_header_t header;
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);
1013 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
1014 ULONG ulStatusCode, LPCWSTR szStatusText)
1016 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1018 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
1020 if(do_direct_notif(This)) {
1021 report_progress(This, ulStatusCode, szStatusText);
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);
1036 static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max)
1039 This->progress = progress;
1040 This->progress_max = progress_max;
1042 if(!This->protocol_sink)
1045 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
1046 BYTE buf[BUFFER_SIZE];
1053 hres = IInternetProtocol_Read(This->protocol, buf,
1054 sizeof(buf)-This->buf_size, &read);
1055 if(FAILED(hres) && hres != E_PENDING)
1059 This->buf = heap_alloc(BUFFER_SIZE);
1061 return E_OUTOFMEMORY;
1062 }else if(read + This->buf_size > BUFFER_SIZE) {
1065 tmp = heap_realloc(This->buf, read+This->buf_size);
1067 return E_OUTOFMEMORY;
1071 memcpy(This->buf+This->buf_size, buf, read);
1072 This->buf_size += read;
1073 }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
1075 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
1078 bscf = BSCF_FIRSTDATANOTIFICATION;
1080 bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
1082 if(!This->reported_mime) {
1085 hres = IUri_GetRawUri(This->uri, &raw_uri);
1089 hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE),
1090 This->mime, 0, &mime, 0);
1091 SysFreeString(raw_uri);
1095 mime_available(This, mime, TRUE);
1096 CoTaskMemFree(mime);
1100 if(!This->protocol_sink)
1103 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
1107 task_header_t header;
1111 } report_data_task_t;
1113 static void report_data_proc(BindProtocol *This, task_header_t *t)
1115 report_data_task_t *task = (report_data_task_t*)t;
1117 report_data(This, task->bscf, task->progress, task->progress_max);
1121 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1122 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1124 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1126 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1128 if(!This->protocol_sink)
1131 if(!do_direct_notif(This)) {
1132 report_data_task_t *task;
1134 task = heap_alloc(sizeof(report_data_task_t));
1136 return E_OUTOFMEMORY;
1138 task->bscf = grfBSCF;
1139 task->progress = ulProgress;
1140 task->progress_max = ulProgressMax;
1142 push_task(This, &task->header, report_data_proc);
1146 return report_data(This, grfBSCF, ulProgress, ulProgressMax);
1150 task_header_t header;
1155 } report_result_task_t;
1157 static void report_result_proc(BindProtocol *This, task_header_t *t)
1159 report_result_task_t *task = (report_result_task_t*)t;
1161 if(This->protocol_sink)
1162 IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str);
1164 heap_free(task->str);
1168 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1169 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1171 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1173 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1175 if(!This->protocol_sink)
1178 This->reported_result = TRUE;
1180 if(!do_direct_notif(This)) {
1181 report_result_task_t *task;
1183 task = heap_alloc(sizeof(report_result_task_t));
1185 return E_OUTOFMEMORY;
1187 task->hres = hrResult;
1188 task->err = dwError;
1189 task->str = heap_strdupW(szResult);
1191 push_task(This, &task->header, report_result_proc);
1195 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1198 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1199 BPInternetProtocolSink_QueryInterface,
1200 BPInternetProtocolSink_AddRef,
1201 BPInternetProtocolSink_Release,
1202 BPInternetProtocolSink_Switch,
1203 BPInternetProtocolSink_ReportProgress,
1204 BPInternetProtocolSink_ReportData,
1205 BPInternetProtocolSink_ReportResult
1208 static inline BindProtocol *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface)
1210 return CONTAINING_RECORD(iface, BindProtocol, IWinInetHttpInfo_iface);
1213 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
1215 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1216 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1219 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface)
1221 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1222 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1225 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface)
1227 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1228 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1231 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
1232 void *pBuffer, DWORD *pcbBuffer)
1234 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1235 FIXME("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
1239 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
1240 void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
1242 BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1243 FIXME("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
1247 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
1248 WinInetHttpInfo_QueryInterface,
1249 WinInetHttpInfo_AddRef,
1250 WinInetHttpInfo_Release,
1251 WinInetHttpInfo_QueryOption,
1252 WinInetHttpInfo_QueryInfo
1255 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface)
1257 return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface);
1260 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1261 REFIID riid, void **ppv)
1263 BindProtocol *This = impl_from_IServiceProvider(iface);
1264 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1267 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1269 BindProtocol *This = impl_from_IServiceProvider(iface);
1270 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1273 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1275 BindProtocol *This = impl_from_IServiceProvider(iface);
1276 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1279 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1280 REFGUID guidService, REFIID riid, void **ppv)
1282 BindProtocol *This = impl_from_IServiceProvider(iface);
1284 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1286 if(!This->service_provider)
1287 return E_NOINTERFACE;
1289 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1292 static const IServiceProviderVtbl ServiceProviderVtbl = {
1293 BPServiceProvider_QueryInterface,
1294 BPServiceProvider_AddRef,
1295 BPServiceProvider_Release,
1296 BPServiceProvider_QueryService
1299 HRESULT create_binding_protocol(BOOL from_urlmon, BindProtocol **protocol)
1301 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1303 ret->IInternetProtocolEx_iface.lpVtbl = &BindProtocolVtbl;
1304 ret->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
1305 ret->IInternetPriority_iface.lpVtbl = &InternetPriorityVtbl;
1306 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
1307 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
1308 ret->IWinInetHttpInfo_iface.lpVtbl = &WinInetHttpInfoVtbl;
1310 ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
1313 ret->from_urlmon = from_urlmon;
1314 ret->apartment_thread = GetCurrentThreadId();
1315 ret->notif_hwnd = get_notif_hwnd();
1316 ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
1317 InitializeCriticalSection(&ret->section);
1318 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BindProtocol.section");
1320 URLMON_LockModule();