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
);