push cc8bc80451cc24f4d7cf75168b569f0ebfe19547
[wine/hacks.git] / dlls / urlmon / bindprot.c
blobaef8c23d042f9218137d5e8909b0215ad1d16b76
1 /*
2 * Copyright 2007-2009 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "urlmon_main.h"
20 #include "wine/debug.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
24 typedef struct BindProtocol BindProtocol;
26 struct _task_header_t;
28 typedef void (*task_proc_t)(BindProtocol*,struct _task_header_t*);
30 typedef struct _task_header_t {
31 task_proc_t proc;
32 struct _task_header_t *next;
33 } task_header_t;
35 struct BindProtocol {
36 const IInternetProtocolVtbl *lpIInternetProtocolVtbl;
37 const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
38 const IInternetPriorityVtbl *lpInternetPriorityVtbl;
39 const IServiceProviderVtbl *lpServiceProviderVtbl;
40 const IInternetProtocolSinkVtbl *lpIInternetProtocolSinkVtbl;
42 const IInternetProtocolVtbl *lpIInternetProtocolHandlerVtbl;
44 LONG ref;
46 IInternetProtocol *protocol;
47 IInternetProtocol *protocol_handler;
48 IInternetBindInfo *bind_info;
49 IInternetProtocolSink *protocol_sink;
50 IServiceProvider *service_provider;
51 IWinInetInfo *wininet_info;
53 LONG priority;
55 BOOL reported_result;
56 BOOL reported_mime;
57 BOOL from_urlmon;
58 DWORD pi;
60 DWORD apartment_thread;
61 HWND notif_hwnd;
62 DWORD continue_call;
64 CRITICAL_SECTION section;
65 task_header_t *task_queue_head, *task_queue_tail;
67 BYTE *buf;
68 DWORD buf_size;
69 LPWSTR mime;
70 LPWSTR url;
71 ProtocolProxy *filter_proxy;
74 #define BINDINFO(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
75 #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
76 #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl)
78 #define PROTOCOLHANDLER(x) ((IInternetProtocol*) &(x)->lpIInternetProtocolHandlerVtbl)
80 #define BUFFER_SIZE 2048
81 #define MIME_TEST_SIZE 255
83 #define WM_MK_CONTINUE (WM_USER+101)
84 #define WM_MK_RELEASE (WM_USER+102)
86 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
88 switch(msg) {
89 case WM_MK_CONTINUE: {
90 BindProtocol *This = (BindProtocol*)lParam;
91 task_header_t *task;
93 while(1) {
94 EnterCriticalSection(&This->section);
96 task = This->task_queue_head;
97 if(task) {
98 This->task_queue_head = task->next;
99 if(!This->task_queue_head)
100 This->task_queue_tail = NULL;
103 LeaveCriticalSection(&This->section);
105 if(!task)
106 break;
108 This->continue_call++;
109 task->proc(This, task);
110 This->continue_call--;
113 IInternetProtocol_Release(PROTOCOL(This));
114 return 0;
116 case WM_MK_RELEASE: {
117 tls_data_t *data = get_tls_data();
119 if(!--data->notif_hwnd_cnt) {
120 DestroyWindow(hwnd);
121 data->notif_hwnd = NULL;
126 return DefWindowProcW(hwnd, msg, wParam, lParam);
129 HWND get_notif_hwnd(void)
131 static ATOM wnd_class = 0;
132 tls_data_t *tls_data;
134 static const WCHAR wszURLMonikerNotificationWindow[] =
135 {'U','R','L',' ','M','o','n','i','k','e','r',' ',
136 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
138 tls_data = get_tls_data();
139 if(!tls_data)
140 return NULL;
142 if(tls_data->notif_hwnd_cnt) {
143 tls_data->notif_hwnd_cnt++;
144 return tls_data->notif_hwnd;
147 if(!wnd_class) {
148 static WNDCLASSEXW wndclass = {
149 sizeof(wndclass), 0,
150 notif_wnd_proc, 0, 0,
151 NULL, NULL, NULL, NULL, NULL,
152 wszURLMonikerNotificationWindow,
153 NULL
156 wndclass.hInstance = URLMON_hInstance;
158 wnd_class = RegisterClassExW(&wndclass);
159 if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
160 wnd_class = 1;
163 tls_data->notif_hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
164 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
165 NULL, URLMON_hInstance, NULL);
166 if(tls_data->notif_hwnd)
167 tls_data->notif_hwnd_cnt++;
169 TRACE("hwnd = %p\n", tls_data->notif_hwnd);
171 return tls_data->notif_hwnd;
174 void release_notif_hwnd(HWND hwnd)
176 tls_data_t *data = get_tls_data();
178 if(!data)
179 return;
181 if(data->notif_hwnd != hwnd) {
182 PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
183 return;
186 if(!--data->notif_hwnd_cnt) {
187 DestroyWindow(data->notif_hwnd);
188 data->notif_hwnd = NULL;
192 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
194 BOOL do_post = FALSE;
196 task->proc = proc;
197 task->next = NULL;
199 EnterCriticalSection(&This->section);
201 if(This->task_queue_tail) {
202 This->task_queue_tail->next = task;
203 This->task_queue_tail = task;
204 }else {
205 This->task_queue_tail = This->task_queue_head = task;
206 do_post = TRUE;
209 LeaveCriticalSection(&This->section);
211 if(do_post) {
212 IInternetProtocol_AddRef(PROTOCOL(This));
213 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
217 static inline BOOL do_direct_notif(BindProtocol *This)
219 return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
222 static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter, LPCWSTR mime)
224 PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 };
225 IInternetProtocolSink *protocol_sink, *old_sink;
226 ProtocolProxy *filter_proxy;
227 HRESULT hres;
229 hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&protocol_sink);
230 if(FAILED(hres))
231 return hres;
233 hres = create_protocol_proxy(PROTOCOLHANDLER(This), This->protocol_sink, &filter_proxy);
234 if(FAILED(hres)) {
235 IInternetProtocolSink_Release(protocol_sink);
236 return hres;
239 old_sink = This->protocol_sink;
240 This->protocol_sink = protocol_sink;
241 This->filter_proxy = filter_proxy;
243 IInternetProtocol_AddRef(mime_filter);
244 This->protocol_handler = mime_filter;
246 filter_data.pProtocol = PROTOCOL(filter_proxy);
247 hres = IInternetProtocol_Start(mime_filter, mime, PROTSINK(filter_proxy), BINDINFO(This),
248 PI_FILTER_MODE|PI_FORCE_ASYNC, (HANDLE_PTR)&filter_data);
249 if(FAILED(hres)) {
250 IInternetProtocolSink_Release(old_sink);
251 return hres;
254 IInternetProtocolSink_ReportProgress(old_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL);
255 IInternetProtocolSink_Release(old_sink);
257 This->pi &= ~PI_MIMEVERIFICATION; /* FIXME: more tests */
258 return S_OK;
261 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
263 IInternetProtocol *mime_filter;
264 HRESULT hres;
266 heap_free(This->mime);
267 This->mime = NULL;
269 mime_filter = get_mime_filter(mime);
270 if(mime_filter) {
271 TRACE("Got mime filter for %s\n", debugstr_w(mime));
273 hres = handle_mime_filter(This, mime_filter, mime);
274 IInternetProtocol_Release(mime_filter);
275 if(FAILED(hres))
276 FIXME("MIME filter failed: %08x\n", hres);
277 }else {
278 This->mime = heap_strdupW(mime);
280 if(verified || !(This->pi & PI_MIMEVERIFICATION)) {
281 This->reported_mime = TRUE;
283 if(This->protocol_sink)
284 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
289 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocol, iface)
291 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
293 BindProtocol *This = PROTOCOL_THIS(iface);
295 *ppv = NULL;
296 if(IsEqualGUID(&IID_IUnknown, riid)) {
297 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
298 *ppv = PROTOCOL(This);
299 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
300 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
301 *ppv = PROTOCOL(This);
302 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
303 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
304 *ppv = PROTOCOL(This);
305 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
306 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
307 *ppv = BINDINFO(This);
308 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
309 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
310 *ppv = PRIORITY(This);
311 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
312 FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
313 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
314 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
315 *ppv = SERVPROV(This);
316 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
317 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
318 *ppv = PROTSINK(This);
321 if(*ppv) {
322 IInternetProtocol_AddRef(iface);
323 return S_OK;
326 WARN("not supported interface %s\n", debugstr_guid(riid));
327 return E_NOINTERFACE;
330 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocol *iface)
332 BindProtocol *This = PROTOCOL_THIS(iface);
333 LONG ref = InterlockedIncrement(&This->ref);
334 TRACE("(%p) ref=%d\n", This, ref);
335 return ref;
338 static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
340 BindProtocol *This = PROTOCOL_THIS(iface);
341 LONG ref = InterlockedDecrement(&This->ref);
343 TRACE("(%p) ref=%d\n", This, ref);
345 if(!ref) {
346 if(This->wininet_info)
347 IWinInetInfo_Release(This->wininet_info);
348 if(This->protocol)
349 IInternetProtocol_Release(This->protocol);
350 if(This->bind_info)
351 IInternetBindInfo_Release(This->bind_info);
352 if(This->protocol_handler && This->protocol_handler != PROTOCOLHANDLER(This))
353 IInternetProtocol_Release(This->protocol_handler);
354 if(This->filter_proxy)
355 IInternetProtocol_Release(PROTOCOL(This->filter_proxy));
357 set_binding_sink(PROTOCOL(This), NULL);
359 if(This->notif_hwnd)
360 release_notif_hwnd(This->notif_hwnd);
361 DeleteCriticalSection(&This->section);
363 heap_free(This->mime);
364 heap_free(This->url);
365 heap_free(This);
367 URLMON_UnlockModule();
370 return ref;
373 static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
374 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
375 DWORD grfPI, HANDLE_PTR dwReserved)
377 BindProtocol *This = PROTOCOL_THIS(iface);
379 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
380 pOIBindInfo, grfPI, dwReserved);
382 return IInternetProtocol_Start(This->protocol_handler, szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
385 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
387 BindProtocol *This = PROTOCOL_THIS(iface);
389 TRACE("(%p)->(%p)\n", This, pProtocolData);
391 return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
394 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
395 DWORD dwOptions)
397 BindProtocol *This = PROTOCOL_THIS(iface);
398 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
399 return E_NOTIMPL;
402 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
404 BindProtocol *This = PROTOCOL_THIS(iface);
406 TRACE("(%p)->(%08x)\n", This, dwOptions);
408 return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
411 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface)
413 BindProtocol *This = PROTOCOL_THIS(iface);
414 FIXME("(%p)\n", This);
415 return E_NOTIMPL;
418 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface)
420 BindProtocol *This = PROTOCOL_THIS(iface);
421 FIXME("(%p)\n", This);
422 return E_NOTIMPL;
425 static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
426 ULONG cb, ULONG *pcbRead)
428 BindProtocol *This = PROTOCOL_THIS(iface);
430 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
432 if(pcbRead)
433 *pcbRead = 0;
434 return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
437 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
438 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
440 BindProtocol *This = PROTOCOL_THIS(iface);
441 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
442 return E_NOTIMPL;
445 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
447 BindProtocol *This = PROTOCOL_THIS(iface);
449 TRACE("(%p)->(%08x)\n", This, dwOptions);
451 return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
454 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
456 BindProtocol *This = PROTOCOL_THIS(iface);
458 TRACE("(%p)\n", This);
460 return IInternetProtocol_UnlockRequest(This->protocol_handler);
463 void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink)
465 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
466 IInternetProtocolSink *prev_sink;
467 IServiceProvider *service_provider = NULL;
469 if(sink)
470 IInternetProtocolSink_AddRef(sink);
471 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
472 if(prev_sink)
473 IInternetProtocolSink_Release(prev_sink);
475 if(sink)
476 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
477 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
478 if(service_provider)
479 IServiceProvider_Release(service_provider);
482 IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol)
484 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
486 return This->wininet_info;
489 #undef PROTOCOL_THIS
491 static const IInternetProtocolVtbl BindProtocolVtbl = {
492 BindProtocol_QueryInterface,
493 BindProtocol_AddRef,
494 BindProtocol_Release,
495 BindProtocol_Start,
496 BindProtocol_Continue,
497 BindProtocol_Abort,
498 BindProtocol_Terminate,
499 BindProtocol_Suspend,
500 BindProtocol_Resume,
501 BindProtocol_Read,
502 BindProtocol_Seek,
503 BindProtocol_LockRequest,
504 BindProtocol_UnlockRequest
507 #define PROTOCOLHANDLER_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolHandler, iface)
509 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
511 ERR("should not be called\n");
512 return E_NOINTERFACE;
515 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
517 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
518 return IInternetProtocol_AddRef(PROTOCOL(This));
521 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
523 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
524 return IInternetProtocol_Release(PROTOCOL(This));
527 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
528 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
529 DWORD grfPI, HANDLE_PTR dwReserved)
531 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
532 IInternetProtocol *protocol = NULL;
533 IInternetPriority *priority;
534 IServiceProvider *service_provider;
535 BOOL urlmon_protocol = FALSE;
536 CLSID clsid = IID_NULL;
537 LPOLESTR clsid_str;
538 HRESULT hres;
540 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
541 pOIBindInfo, grfPI, dwReserved);
543 if(!szUrl || !pOIProtSink || !pOIBindInfo)
544 return E_INVALIDARG;
546 This->pi = grfPI;
547 This->url = heap_strdupW(szUrl);
549 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
550 (void**)&service_provider);
551 if(SUCCEEDED(hres)) {
552 /* FIXME: What's protocol CLSID here? */
553 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
554 &IID_IInternetProtocol, (void**)&protocol);
555 IServiceProvider_Release(service_provider);
558 if(!protocol) {
559 IClassFactory *cf;
560 IUnknown *unk;
562 hres = get_protocol_handler(szUrl, &clsid, &urlmon_protocol, &cf);
563 if(FAILED(hres))
564 return hres;
566 if(This->from_urlmon) {
567 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
568 IClassFactory_Release(cf);
569 if(FAILED(hres))
570 return hres;
571 }else {
572 hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
573 &IID_IUnknown, (void**)&unk);
574 IClassFactory_Release(cf);
575 if(FAILED(hres))
576 return hres;
578 hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
579 IUnknown_Release(unk);
580 if(FAILED(hres))
581 return hres;
585 StringFromCLSID(&clsid, &clsid_str);
586 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
587 CoTaskMemFree(clsid_str);
589 This->protocol = protocol;
591 if(urlmon_protocol)
592 IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
594 IInternetBindInfo_AddRef(pOIBindInfo);
595 This->bind_info = pOIBindInfo;
597 set_binding_sink(PROTOCOL(This), pOIProtSink);
599 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
600 if(SUCCEEDED(hres)) {
601 IInternetPriority_SetPriority(priority, This->priority);
602 IInternetPriority_Release(priority);
605 return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0);
608 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
610 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
611 HRESULT hres;
613 TRACE("(%p)->(%p)\n", This, pProtocolData);
615 hres = IInternetProtocol_Continue(This->protocol, pProtocolData);
617 heap_free(pProtocolData);
618 return hres;
621 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
622 DWORD dwOptions)
624 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
625 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
626 return E_NOTIMPL;
629 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
631 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
633 TRACE("(%p)->(%08x)\n", This, dwOptions);
635 if(!This->reported_result)
636 return E_FAIL;
638 IInternetProtocol_Terminate(This->protocol, 0);
640 if(This->filter_proxy) {
641 IInternetProtocol_Release(PROTOCOL(This->filter_proxy));
642 This->filter_proxy = NULL;
645 set_binding_sink(PROTOCOL(This), NULL);
647 if(This->bind_info) {
648 IInternetBindInfo_Release(This->bind_info);
649 This->bind_info = NULL;
652 return S_OK;
655 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
657 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
658 FIXME("(%p)\n", This);
659 return E_NOTIMPL;
662 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
664 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
665 FIXME("(%p)\n", This);
666 return E_NOTIMPL;
669 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
670 ULONG cb, ULONG *pcbRead)
672 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
673 ULONG read = 0;
674 HRESULT hres = S_OK;
676 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
678 if(This->buf) {
679 read = min(cb, This->buf_size);
680 memcpy(pv, This->buf, read);
682 if(read == This->buf_size) {
683 heap_free(This->buf);
684 This->buf = NULL;
685 }else {
686 memmove(This->buf, This->buf+cb, This->buf_size-cb);
689 This->buf_size -= read;
692 if(read < cb) {
693 ULONG cread = 0;
695 hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
696 read += cread;
699 *pcbRead = read;
700 return hres;
703 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
704 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
706 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
707 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
708 return E_NOTIMPL;
711 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
713 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
715 TRACE("(%p)->(%08x)\n", This, dwOptions);
717 return IInternetProtocol_LockRequest(This->protocol, dwOptions);
720 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
722 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
724 TRACE("(%p)\n", This);
726 return IInternetProtocol_UnlockRequest(This->protocol);
729 #undef PROTOCOL_THIS
731 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
732 ProtocolHandler_QueryInterface,
733 ProtocolHandler_AddRef,
734 ProtocolHandler_Release,
735 ProtocolHandler_Start,
736 ProtocolHandler_Continue,
737 ProtocolHandler_Abort,
738 ProtocolHandler_Terminate,
739 ProtocolHandler_Suspend,
740 ProtocolHandler_Resume,
741 ProtocolHandler_Read,
742 ProtocolHandler_Seek,
743 ProtocolHandler_LockRequest,
744 ProtocolHandler_UnlockRequest
747 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
749 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
750 REFIID riid, void **ppv)
752 BindProtocol *This = BINDINFO_THIS(iface);
753 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
756 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
758 BindProtocol *This = BINDINFO_THIS(iface);
759 return IBinding_AddRef(PROTOCOL(This));
762 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
764 BindProtocol *This = BINDINFO_THIS(iface);
765 return IBinding_Release(PROTOCOL(This));
768 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
769 DWORD *grfBINDF, BINDINFO *pbindinfo)
771 BindProtocol *This = BINDINFO_THIS(iface);
772 HRESULT hres;
774 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
776 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
777 if(FAILED(hres)) {
778 WARN("GetBindInfo failed: %08x\n", hres);
779 return hres;
782 *grfBINDF |= BINDF_FROMURLMON;
783 return hres;
786 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
787 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
789 BindProtocol *This = BINDINFO_THIS(iface);
791 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
793 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
796 #undef BINDFO_THIS
798 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
799 BindInfo_QueryInterface,
800 BindInfo_AddRef,
801 BindInfo_Release,
802 BindInfo_GetBindInfo,
803 BindInfo_GetBindString
806 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
808 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
809 REFIID riid, void **ppv)
811 BindProtocol *This = PRIORITY_THIS(iface);
812 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
815 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
817 BindProtocol *This = PRIORITY_THIS(iface);
818 return IInternetProtocol_AddRef(PROTOCOL(This));
821 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
823 BindProtocol *This = PRIORITY_THIS(iface);
824 return IInternetProtocol_Release(PROTOCOL(This));
827 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
829 BindProtocol *This = PRIORITY_THIS(iface);
831 TRACE("(%p)->(%d)\n", This, nPriority);
833 This->priority = nPriority;
834 return S_OK;
837 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
839 BindProtocol *This = PRIORITY_THIS(iface);
841 TRACE("(%p)->(%p)\n", This, pnPriority);
843 *pnPriority = This->priority;
844 return S_OK;
847 #undef PRIORITY_THIS
849 static const IInternetPriorityVtbl InternetPriorityVtbl = {
850 InternetPriority_QueryInterface,
851 InternetPriority_AddRef,
852 InternetPriority_Release,
853 InternetPriority_SetPriority,
854 InternetPriority_GetPriority
858 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolSink, iface)
860 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
861 REFIID riid, void **ppv)
863 BindProtocol *This = PROTSINK_THIS(iface);
864 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
867 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
869 BindProtocol *This = PROTSINK_THIS(iface);
870 return IInternetProtocol_AddRef(PROTOCOL(This));
873 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
875 BindProtocol *This = PROTSINK_THIS(iface);
876 return IInternetProtocol_Release(PROTOCOL(This));
879 typedef struct {
880 task_header_t header;
881 PROTOCOLDATA *data;
882 } switch_task_t;
884 static void switch_proc(BindProtocol *bind, task_header_t *t)
886 switch_task_t *task = (switch_task_t*)t;
888 IInternetProtocol_Continue(bind->protocol_handler, task->data);
890 heap_free(task);
893 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
894 PROTOCOLDATA *pProtocolData)
896 BindProtocol *This = PROTSINK_THIS(iface);
897 PROTOCOLDATA *data;
899 TRACE("(%p)->(%p)\n", This, pProtocolData);
901 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
902 pProtocolData->pData, pProtocolData->cbData);
904 data = heap_alloc(sizeof(PROTOCOLDATA));
905 if(!data)
906 return E_OUTOFMEMORY;
907 memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
909 if(!do_direct_notif(This)) {
910 switch_task_t *task;
912 task = heap_alloc(sizeof(switch_task_t));
913 if(!task)
914 return E_OUTOFMEMORY;
916 task->data = data;
918 push_task(This, &task->header, switch_proc);
919 return S_OK;
922 if(!This->protocol_sink) {
923 IInternetProtocol_Continue(This->protocol_handler, data);
924 return S_OK;
927 return IInternetProtocolSink_Switch(This->protocol_sink, data);
930 static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
932 switch(status_code) {
933 case BINDSTATUS_FINDINGRESOURCE:
934 case BINDSTATUS_CONNECTING:
935 case BINDSTATUS_BEGINDOWNLOADDATA:
936 case BINDSTATUS_SENDINGREQUEST:
937 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
938 case BINDSTATUS_DIRECTBIND:
939 case BINDSTATUS_ACCEPTRANGES:
940 if(This->protocol_sink)
941 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
942 break;
944 case BINDSTATUS_MIMETYPEAVAILABLE:
945 mime_available(This, status_text, FALSE);
946 break;
948 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
949 mime_available(This, status_text, TRUE);
950 break;
952 default:
953 FIXME("unsupported ulStatusCode %u\n", status_code);
957 typedef struct {
958 task_header_t header;
960 ULONG status_code;
961 LPWSTR status_text;
962 } on_progress_task_t;
964 static void on_progress_proc(BindProtocol *This, task_header_t *t)
966 on_progress_task_t *task = (on_progress_task_t*)t;
968 report_progress(This, task->status_code, task->status_text);
970 heap_free(task->status_text);
971 heap_free(task);
974 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
975 ULONG ulStatusCode, LPCWSTR szStatusText)
977 BindProtocol *This = PROTSINK_THIS(iface);
979 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
981 if(do_direct_notif(This)) {
982 report_progress(This, ulStatusCode, szStatusText);
983 }else {
984 on_progress_task_t *task;
986 task = heap_alloc(sizeof(on_progress_task_t));
988 task->status_code = ulStatusCode;
989 task->status_text = heap_strdupW(szStatusText);
991 push_task(This, &task->header, on_progress_proc);
994 return S_OK;
997 static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max)
999 if(!This->protocol_sink)
1000 return S_OK;
1002 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
1003 DWORD read = 0;
1004 LPWSTR mime;
1005 HRESULT hres;
1007 if(!This->buf) {
1008 This->buf = heap_alloc(BUFFER_SIZE);
1009 if(!This->buf)
1010 return E_OUTOFMEMORY;
1013 do {
1014 read = 0;
1015 hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size,
1016 BUFFER_SIZE-This->buf_size, &read);
1017 if(FAILED(hres) && hres != E_PENDING)
1018 return hres;
1019 This->buf_size += read;
1020 }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
1022 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
1023 return S_OK;
1025 hres = FindMimeFromData(NULL, This->url, This->buf, min(This->buf_size, MIME_TEST_SIZE),
1026 This->mime, 0, &mime, 0);
1027 if(FAILED(hres))
1028 return hres;
1030 mime_available(This, mime, TRUE);
1031 CoTaskMemFree(mime);
1034 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
1037 typedef struct {
1038 task_header_t header;
1039 DWORD bscf;
1040 ULONG progress;
1041 ULONG progress_max;
1042 } report_data_task_t;
1044 static void report_data_proc(BindProtocol *This, task_header_t *t)
1046 report_data_task_t *task = (report_data_task_t*)t;
1048 report_data(This, task->bscf, task->progress, task->progress_max);
1049 heap_free(task);
1052 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1053 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1055 BindProtocol *This = PROTSINK_THIS(iface);
1057 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1059 if(!This->protocol_sink)
1060 return S_OK;
1062 if(!do_direct_notif(This)) {
1063 report_data_task_t *task;
1065 task = heap_alloc(sizeof(report_data_task_t));
1066 if(!task)
1067 return E_OUTOFMEMORY;
1069 task->bscf = grfBSCF;
1070 task->progress = ulProgress;
1071 task->progress_max = ulProgressMax;
1073 push_task(This, &task->header, report_data_proc);
1074 return S_OK;
1077 return report_data(This, grfBSCF, ulProgress, ulProgressMax);
1080 typedef struct {
1081 task_header_t header;
1083 HRESULT hres;
1084 DWORD err;
1085 LPWSTR str;
1086 } report_result_task_t;
1088 static void report_result_proc(BindProtocol *This, task_header_t *t)
1090 report_result_task_t *task = (report_result_task_t*)t;
1092 if(This->protocol_sink)
1093 IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str);
1095 heap_free(task->str);
1096 heap_free(task);
1099 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1100 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1102 BindProtocol *This = PROTSINK_THIS(iface);
1104 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1106 if(!This->protocol_sink)
1107 return E_FAIL;
1109 This->reported_result = TRUE;
1111 if(!do_direct_notif(This)) {
1112 report_result_task_t *task;
1114 task = heap_alloc(sizeof(report_result_task_t));
1115 if(!task)
1116 return E_OUTOFMEMORY;
1118 task->hres = hrResult;
1119 task->err = dwError;
1120 task->str = heap_strdupW(szResult);
1122 push_task(This, &task->header, report_result_proc);
1123 return S_OK;
1126 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1129 #undef PROTSINK_THIS
1131 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1132 BPInternetProtocolSink_QueryInterface,
1133 BPInternetProtocolSink_AddRef,
1134 BPInternetProtocolSink_Release,
1135 BPInternetProtocolSink_Switch,
1136 BPInternetProtocolSink_ReportProgress,
1137 BPInternetProtocolSink_ReportData,
1138 BPInternetProtocolSink_ReportResult
1141 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
1143 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1144 REFIID riid, void **ppv)
1146 BindProtocol *This = SERVPROV_THIS(iface);
1147 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
1150 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1152 BindProtocol *This = SERVPROV_THIS(iface);
1153 return IInternetProtocol_AddRef(PROTOCOL(This));
1156 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1158 BindProtocol *This = SERVPROV_THIS(iface);
1159 return IInternetProtocol_Release(PROTOCOL(This));
1162 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1163 REFGUID guidService, REFIID riid, void **ppv)
1165 BindProtocol *This = SERVPROV_THIS(iface);
1167 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1169 if(!This->service_provider)
1170 return E_NOINTERFACE;
1172 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1175 #undef SERVPROV_THIS
1177 static const IServiceProviderVtbl ServiceProviderVtbl = {
1178 BPServiceProvider_QueryInterface,
1179 BPServiceProvider_AddRef,
1180 BPServiceProvider_Release,
1181 BPServiceProvider_QueryService
1184 HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol)
1186 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1188 ret->lpIInternetProtocolVtbl = &BindProtocolVtbl;
1189 ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
1190 ret->lpInternetPriorityVtbl = &InternetPriorityVtbl;
1191 ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
1192 ret->lpIInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1193 ret->lpIInternetProtocolHandlerVtbl = &InternetProtocolHandlerVtbl;
1195 ret->ref = 1;
1196 ret->from_urlmon = from_urlmon;
1197 ret->apartment_thread = GetCurrentThreadId();
1198 ret->notif_hwnd = get_notif_hwnd();
1199 ret->protocol_handler = PROTOCOLHANDLER(ret);
1200 InitializeCriticalSection(&ret->section);
1202 URLMON_LockModule();
1204 *protocol = PROTOCOL(ret);
1205 return S_OK;