push 52cba0a224aad01bcbdb26d79e43229ba950650e
[wine/hacks.git] / dlls / urlmon / bindprot.c
blob7231ae6a4760df3359b5b2796411121a3580a622
1 /*
2 * Copyright 2007 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "urlmon_main.h"
20 #include "wine/debug.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
24 typedef struct BindProtocol BindProtocol;
26 struct _task_header_t;
28 typedef void (*task_proc_t)(BindProtocol*,struct _task_header_t*);
30 typedef struct _task_header_t {
31 task_proc_t proc;
32 struct _task_header_t *next;
33 } task_header_t;
35 struct BindProtocol {
36 const IInternetProtocolVtbl *lpInternetProtocolVtbl;
37 const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
38 const IInternetPriorityVtbl *lpInternetPriorityVtbl;
39 const IServiceProviderVtbl *lpServiceProviderVtbl;
40 const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl;
42 LONG ref;
44 IInternetProtocol *protocol;
45 IInternetBindInfo *bind_info;
46 IInternetProtocolSink *protocol_sink;
47 IServiceProvider *service_provider;
48 IWinInetInfo *wininet_info;
50 LONG priority;
52 BOOL reported_result;
53 BOOL reported_mime;
54 BOOL from_urlmon;
55 DWORD pi;
57 DWORD apartment_thread;
58 HWND notif_hwnd;
59 DWORD continue_call;
61 CRITICAL_SECTION section;
62 task_header_t *task_queue_head, *task_queue_tail;
64 BYTE *buf;
65 DWORD buf_size;
66 LPWSTR mime;
67 LPWSTR url;
70 #define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
71 #define BINDINFO(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
72 #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
73 #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl)
74 #define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
76 #define BUFFER_SIZE 2048
77 #define MIME_TEST_SIZE 255
79 #define WM_MK_CONTINUE (WM_USER+101)
80 #define WM_MK_RELEASE (WM_USER+102)
82 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
84 switch(msg) {
85 case WM_MK_CONTINUE: {
86 BindProtocol *This = (BindProtocol*)lParam;
87 task_header_t *task;
89 while(1) {
90 EnterCriticalSection(&This->section);
92 task = This->task_queue_head;
93 if(task) {
94 This->task_queue_head = task->next;
95 if(!This->task_queue_head)
96 This->task_queue_tail = NULL;
99 LeaveCriticalSection(&This->section);
101 if(!task)
102 break;
104 This->continue_call++;
105 task->proc(This, task);
106 This->continue_call--;
109 IInternetProtocol_Release(PROTOCOL(This));
110 return 0;
112 case WM_MK_RELEASE: {
113 tls_data_t *data = get_tls_data();
115 if(!--data->notif_hwnd_cnt) {
116 DestroyWindow(hwnd);
117 data->notif_hwnd = NULL;
122 return DefWindowProcW(hwnd, msg, wParam, lParam);
125 HWND get_notif_hwnd(void)
127 static ATOM wnd_class = 0;
128 tls_data_t *tls_data;
130 static const WCHAR wszURLMonikerNotificationWindow[] =
131 {'U','R','L',' ','M','o','n','i','k','e','r',' ',
132 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
134 tls_data = get_tls_data();
135 if(!tls_data)
136 return NULL;
138 if(tls_data->notif_hwnd_cnt) {
139 tls_data->notif_hwnd_cnt++;
140 return tls_data->notif_hwnd;
143 if(!wnd_class) {
144 static WNDCLASSEXW wndclass = {
145 sizeof(wndclass), 0,
146 notif_wnd_proc, 0, 0,
147 NULL, NULL, NULL, NULL, NULL,
148 wszURLMonikerNotificationWindow,
149 NULL
152 wndclass.hInstance = URLMON_hInstance;
154 wnd_class = RegisterClassExW(&wndclass);
155 if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
156 wnd_class = 1;
159 tls_data->notif_hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
160 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
161 NULL, URLMON_hInstance, NULL);
162 if(tls_data->notif_hwnd)
163 tls_data->notif_hwnd_cnt++;
165 TRACE("hwnd = %p\n", tls_data->notif_hwnd);
167 return tls_data->notif_hwnd;
170 void release_notif_hwnd(HWND hwnd)
172 tls_data_t *data = get_tls_data();
174 if(!data)
175 return;
177 if(data->notif_hwnd != hwnd) {
178 PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
179 return;
182 if(!--data->notif_hwnd_cnt) {
183 DestroyWindow(data->notif_hwnd);
184 data->notif_hwnd = NULL;
188 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
190 BOOL do_post = FALSE;
192 task->proc = proc;
193 task->next = NULL;
195 EnterCriticalSection(&This->section);
197 if(This->task_queue_tail) {
198 This->task_queue_tail->next = task;
199 This->task_queue_tail = task;
200 }else {
201 This->task_queue_tail = This->task_queue_head = task;
202 do_post = TRUE;
205 LeaveCriticalSection(&This->section);
207 if(do_post) {
208 IInternetProtocol_AddRef(PROTOCOL(This));
209 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
213 static BOOL inline do_direct_notif(BindProtocol *This)
215 return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
218 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocol, iface)
220 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
222 BindProtocol *This = PROTOCOL_THIS(iface);
224 *ppv = NULL;
225 if(IsEqualGUID(&IID_IUnknown, riid)) {
226 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
227 *ppv = PROTOCOL(This);
228 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
229 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
230 *ppv = PROTOCOL(This);
231 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
232 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
233 *ppv = PROTOCOL(This);
234 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
235 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
236 *ppv = BINDINFO(This);
237 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
238 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
239 *ppv = PRIORITY(This);
240 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
241 FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
242 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
243 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
244 *ppv = SERVPROV(This);
245 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
246 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
247 *ppv = PROTSINK(This);
250 if(*ppv) {
251 IInternetProtocol_AddRef(iface);
252 return S_OK;
255 WARN("not supported interface %s\n", debugstr_guid(riid));
256 return E_NOINTERFACE;
259 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocol *iface)
261 BindProtocol *This = PROTOCOL_THIS(iface);
262 LONG ref = InterlockedIncrement(&This->ref);
263 TRACE("(%p) ref=%d\n", This, ref);
264 return ref;
267 static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
269 BindProtocol *This = PROTOCOL_THIS(iface);
270 LONG ref = InterlockedDecrement(&This->ref);
272 TRACE("(%p) ref=%d\n", This, ref);
274 if(!ref) {
275 if(This->wininet_info)
276 IWinInetInfo_Release(This->wininet_info);
277 if(This->protocol)
278 IInternetProtocol_Release(This->protocol);
279 if(This->bind_info)
280 IInternetBindInfo_Release(This->bind_info);
282 set_binding_sink(PROTOCOL(This), NULL);
284 if(This->notif_hwnd)
285 release_notif_hwnd(This->notif_hwnd);
286 DeleteCriticalSection(&This->section);
288 heap_free(This->mime);
289 heap_free(This->url);
290 heap_free(This);
292 URLMON_UnlockModule();
295 return ref;
298 static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
299 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
300 DWORD grfPI, HANDLE_PTR dwReserved)
302 BindProtocol *This = PROTOCOL_THIS(iface);
303 IInternetProtocol *protocol = NULL;
304 IInternetPriority *priority;
305 IServiceProvider *service_provider;
306 BOOL urlmon_protocol = FALSE;
307 CLSID clsid = IID_NULL;
308 LPOLESTR clsid_str;
309 HRESULT hres;
311 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
312 pOIBindInfo, grfPI, dwReserved);
314 if(!szUrl || !pOIProtSink || !pOIBindInfo)
315 return E_INVALIDARG;
317 This->pi = grfPI;
318 This->url = heap_strdupW(szUrl);
320 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
321 (void**)&service_provider);
322 if(SUCCEEDED(hres)) {
323 /* FIXME: What's protocol CLSID here? */
324 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
325 &IID_IInternetProtocol, (void**)&protocol);
326 IServiceProvider_Release(service_provider);
329 if(!protocol) {
330 IClassFactory *cf;
331 IUnknown *unk;
333 hres = get_protocol_handler(szUrl, &clsid, &urlmon_protocol, &cf);
334 if(FAILED(hres))
335 return hres;
337 if(This->from_urlmon) {
338 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
339 IClassFactory_Release(cf);
340 if(FAILED(hres))
341 return hres;
342 }else {
343 hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
344 &IID_IUnknown, (void**)&unk);
345 IClassFactory_Release(cf);
346 if(FAILED(hres))
347 return hres;
349 hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
350 IUnknown_Release(unk);
351 if(FAILED(hres))
352 return hres;
356 StringFromCLSID(&clsid, &clsid_str);
357 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
358 CoTaskMemFree(clsid_str);
360 This->protocol = protocol;
362 if(urlmon_protocol)
363 IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
365 IInternetBindInfo_AddRef(pOIBindInfo);
366 This->bind_info = pOIBindInfo;
368 set_binding_sink(PROTOCOL(This), pOIProtSink);
370 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
371 if(SUCCEEDED(hres)) {
372 IInternetPriority_SetPriority(priority, This->priority);
373 IInternetPriority_Release(priority);
376 return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0);
379 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
381 BindProtocol *This = PROTOCOL_THIS(iface);
383 TRACE("(%p)->(%p)\n", This, pProtocolData);
385 return IInternetProtocol_Continue(This->protocol, pProtocolData);
388 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
389 DWORD dwOptions)
391 BindProtocol *This = PROTOCOL_THIS(iface);
392 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
393 return E_NOTIMPL;
396 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
398 BindProtocol *This = PROTOCOL_THIS(iface);
400 TRACE("(%p)->(%08x)\n", This, dwOptions);
402 if(!This->reported_result)
403 return E_FAIL;
405 IInternetProtocol_Terminate(This->protocol, 0);
407 set_binding_sink(PROTOCOL(This), NULL);
409 if(This->bind_info) {
410 IInternetBindInfo_Release(This->bind_info);
411 This->bind_info = NULL;
414 return S_OK;
417 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface)
419 BindProtocol *This = PROTOCOL_THIS(iface);
420 FIXME("(%p)\n", This);
421 return E_NOTIMPL;
424 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface)
426 BindProtocol *This = PROTOCOL_THIS(iface);
427 FIXME("(%p)\n", This);
428 return E_NOTIMPL;
431 static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
432 ULONG cb, ULONG *pcbRead)
434 BindProtocol *This = PROTOCOL_THIS(iface);
435 ULONG read = 0;
436 HRESULT hres = S_OK;
438 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
440 if(This->buf) {
441 read = min(cb, This->buf_size);
442 memcpy(pv, This->buf, read);
444 if(read == This->buf_size) {
445 heap_free(This->buf);
446 This->buf = NULL;
447 }else {
448 memmove(This->buf, This->buf+cb, This->buf_size-cb);
451 This->buf_size -= read;
454 if(read < cb) {
455 ULONG cread = 0;
457 hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb, &cread);
458 read += cread;
461 *pcbRead = read;
462 return hres;
465 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
466 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
468 BindProtocol *This = PROTOCOL_THIS(iface);
469 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
470 return E_NOTIMPL;
473 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
475 BindProtocol *This = PROTOCOL_THIS(iface);
477 TRACE("(%p)->(%08x)\n", This, dwOptions);
479 return IInternetProtocol_LockRequest(This->protocol, dwOptions);
482 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
484 BindProtocol *This = PROTOCOL_THIS(iface);
486 TRACE("(%p)\n", This);
488 return IInternetProtocol_UnlockRequest(This->protocol);
491 void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink)
493 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
494 IInternetProtocolSink *prev_sink;
495 IServiceProvider *service_provider = NULL;
497 if(sink)
498 IInternetProtocolSink_AddRef(sink);
499 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
500 if(prev_sink)
501 IInternetProtocolSink_Release(prev_sink);
503 if(sink)
504 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
505 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
506 if(service_provider)
507 IServiceProvider_Release(service_provider);
510 IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol)
512 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
514 return This->wininet_info;
517 #undef PROTOCOL_THIS
519 static const IInternetProtocolVtbl BindProtocolVtbl = {
520 BindProtocol_QueryInterface,
521 BindProtocol_AddRef,
522 BindProtocol_Release,
523 BindProtocol_Start,
524 BindProtocol_Continue,
525 BindProtocol_Abort,
526 BindProtocol_Terminate,
527 BindProtocol_Suspend,
528 BindProtocol_Resume,
529 BindProtocol_Read,
530 BindProtocol_Seek,
531 BindProtocol_LockRequest,
532 BindProtocol_UnlockRequest
535 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
537 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
538 REFIID riid, void **ppv)
540 BindProtocol *This = BINDINFO_THIS(iface);
541 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
544 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
546 BindProtocol *This = BINDINFO_THIS(iface);
547 return IBinding_AddRef(PROTOCOL(This));
550 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
552 BindProtocol *This = BINDINFO_THIS(iface);
553 return IBinding_Release(PROTOCOL(This));
556 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
557 DWORD *grfBINDF, BINDINFO *pbindinfo)
559 BindProtocol *This = BINDINFO_THIS(iface);
560 HRESULT hres;
562 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
564 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
565 if(FAILED(hres)) {
566 WARN("GetBindInfo failed: %08x\n", hres);
567 return hres;
570 *grfBINDF |= BINDF_FROMURLMON;
571 return hres;
574 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
575 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
577 BindProtocol *This = BINDINFO_THIS(iface);
579 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
581 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
584 #undef BINDFO_THIS
586 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
587 BindInfo_QueryInterface,
588 BindInfo_AddRef,
589 BindInfo_Release,
590 BindInfo_GetBindInfo,
591 BindInfo_GetBindString
594 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
596 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
597 REFIID riid, void **ppv)
599 BindProtocol *This = PRIORITY_THIS(iface);
600 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
603 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
605 BindProtocol *This = PRIORITY_THIS(iface);
606 return IInternetProtocol_AddRef(PROTOCOL(This));
609 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
611 BindProtocol *This = PRIORITY_THIS(iface);
612 return IInternetProtocol_Release(PROTOCOL(This));
615 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
617 BindProtocol *This = PRIORITY_THIS(iface);
619 TRACE("(%p)->(%d)\n", This, nPriority);
621 This->priority = nPriority;
622 return S_OK;
625 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
627 BindProtocol *This = PRIORITY_THIS(iface);
629 TRACE("(%p)->(%p)\n", This, pnPriority);
631 *pnPriority = This->priority;
632 return S_OK;
635 #undef PRIORITY_THIS
637 static const IInternetPriorityVtbl InternetPriorityVtbl = {
638 InternetPriority_QueryInterface,
639 InternetPriority_AddRef,
640 InternetPriority_Release,
641 InternetPriority_SetPriority,
642 InternetPriority_GetPriority
646 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocolSink, iface)
648 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
649 REFIID riid, void **ppv)
651 BindProtocol *This = PROTSINK_THIS(iface);
652 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
655 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
657 BindProtocol *This = PROTSINK_THIS(iface);
658 return IInternetProtocol_AddRef(PROTOCOL(This));
661 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
663 BindProtocol *This = PROTSINK_THIS(iface);
664 return IInternetProtocol_Release(PROTOCOL(This));
667 typedef struct {
668 task_header_t header;
669 PROTOCOLDATA data;
670 } switch_task_t;
672 static void switch_proc(BindProtocol *bind, task_header_t *t)
674 switch_task_t *task = (switch_task_t*)t;
676 IInternetProtocol_Continue(bind->protocol, &task->data);
678 heap_free(task);
681 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
682 PROTOCOLDATA *pProtocolData)
684 BindProtocol *This = PROTSINK_THIS(iface);
686 TRACE("(%p)->(%p)\n", This, pProtocolData);
688 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
689 pProtocolData->pData, pProtocolData->cbData);
691 if(!do_direct_notif(This)) {
692 switch_task_t *task;
694 task = heap_alloc(sizeof(switch_task_t));
695 if(!task)
696 return E_OUTOFMEMORY;
698 task->data = *pProtocolData;
700 push_task(This, &task->header, switch_proc);
701 return S_OK;
704 if(!This->protocol_sink) {
705 IInternetProtocol_Continue(This->protocol, pProtocolData);
706 return S_OK;
709 return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
712 static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
714 switch(status_code) {
715 case BINDSTATUS_FINDINGRESOURCE:
716 case BINDSTATUS_CONNECTING:
717 case BINDSTATUS_BEGINDOWNLOADDATA:
718 case BINDSTATUS_SENDINGREQUEST:
719 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
720 case BINDSTATUS_DIRECTBIND:
721 case BINDSTATUS_ACCEPTRANGES:
722 if(This->protocol_sink)
723 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
724 break;
726 case BINDSTATUS_MIMETYPEAVAILABLE:
727 if(!This->reported_mime) {
728 heap_free(This->mime);
729 This->mime = heap_strdupW(status_text);
732 if(This->protocol_sink && !(This->pi & PI_MIMEVERIFICATION))
733 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
734 break;
736 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
737 if(!This->reported_mime) {
738 heap_free(This->mime);
739 This->mime = heap_strdupW(status_text);
742 if(This->protocol_sink) {
743 This->reported_mime = TRUE;
744 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, status_text);
746 break;
748 default:
749 FIXME("unsupported ulStatusCode %u\n", status_code);
753 typedef struct {
754 task_header_t header;
756 ULONG status_code;
757 LPWSTR status_text;
758 } on_progress_task_t;
760 static void on_progress_proc(BindProtocol *This, task_header_t *t)
762 on_progress_task_t *task = (on_progress_task_t*)t;
764 report_progress(This, task->status_code, task->status_text);
766 heap_free(task->status_text);
767 heap_free(task);
770 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
771 ULONG ulStatusCode, LPCWSTR szStatusText)
773 BindProtocol *This = PROTSINK_THIS(iface);
775 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
777 if(do_direct_notif(This)) {
778 report_progress(This, ulStatusCode, szStatusText);
779 }else {
780 on_progress_task_t *task;
782 task = heap_alloc(sizeof(on_progress_task_t));
784 task->status_code = ulStatusCode;
785 task->status_text = heap_strdupW(szStatusText);
787 push_task(This, &task->header, on_progress_proc);
790 return S_OK;
793 static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max)
795 if(!This->protocol_sink)
796 return S_OK;
798 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
799 DWORD read = 0;
800 LPWSTR mime;
801 HRESULT hres;
803 if(!This->buf) {
804 This->buf = heap_alloc(BUFFER_SIZE);
805 if(!This->buf)
806 return E_OUTOFMEMORY;
809 do {
810 read = 0;
811 hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size, BUFFER_SIZE-This->buf_size, &read);
812 if(hres != S_OK)
813 break;
814 This->buf_size += read;
815 }while(This->buf_size < MIME_TEST_SIZE);
816 if(FAILED(hres) && hres != E_PENDING)
817 return hres;
819 This->buf_size += read;
820 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
821 return S_OK;
824 hres = FindMimeFromData(NULL, This->url, This->buf, min(This->buf_size, MIME_TEST_SIZE), This->mime, 0, &mime, 0);
825 if(FAILED(hres))
826 return hres;
828 heap_free(This->mime);
829 This->mime = heap_strdupW(mime);
830 CoTaskMemFree(mime);
832 This->reported_mime = TRUE;
833 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
836 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
839 typedef struct {
840 task_header_t header;
841 DWORD bscf;
842 ULONG progress;
843 ULONG progress_max;
844 } report_data_task_t;
846 static void report_data_proc(BindProtocol *This, task_header_t *t)
848 report_data_task_t *task = (report_data_task_t*)t;
850 report_data(This, task->bscf, task->progress, task->progress_max);
851 heap_free(task);
854 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
855 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
857 BindProtocol *This = PROTSINK_THIS(iface);
859 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
861 if(!This->protocol_sink)
862 return S_OK;
864 if(!do_direct_notif(This)) {
865 report_data_task_t *task;
867 task = heap_alloc(sizeof(report_data_task_t));
868 if(!task)
869 return E_OUTOFMEMORY;
871 task->bscf = grfBSCF;
872 task->progress = ulProgress;
873 task->progress_max = ulProgressMax;
875 push_task(This, &task->header, report_data_proc);
876 return S_OK;
879 return report_data(This, grfBSCF, ulProgress, ulProgressMax);
882 typedef struct {
883 task_header_t header;
885 HRESULT hres;
886 DWORD err;
887 LPWSTR str;
888 } report_result_task_t;
890 static void report_result_proc(BindProtocol *This, task_header_t *t)
892 report_result_task_t *task = (report_result_task_t*)t;
894 if(This->protocol_sink)
895 IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str);
897 heap_free(task->str);
898 heap_free(task);
901 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
902 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
904 BindProtocol *This = PROTSINK_THIS(iface);
906 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
908 if(!This->protocol_sink)
909 return E_FAIL;
911 This->reported_result = TRUE;
913 if(!do_direct_notif(This)) {
914 report_result_task_t *task;
916 task = heap_alloc(sizeof(report_result_task_t));
917 if(!task)
918 return E_OUTOFMEMORY;
920 task->hres = hrResult;
921 task->err = dwError;
922 task->str = heap_strdupW(szResult);
924 push_task(This, &task->header, report_result_proc);
925 return S_OK;
928 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
931 #undef PROTSINK_THIS
933 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
934 BPInternetProtocolSink_QueryInterface,
935 BPInternetProtocolSink_AddRef,
936 BPInternetProtocolSink_Release,
937 BPInternetProtocolSink_Switch,
938 BPInternetProtocolSink_ReportProgress,
939 BPInternetProtocolSink_ReportData,
940 BPInternetProtocolSink_ReportResult
943 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
945 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
946 REFIID riid, void **ppv)
948 BindProtocol *This = SERVPROV_THIS(iface);
949 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
952 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
954 BindProtocol *This = SERVPROV_THIS(iface);
955 return IInternetProtocol_AddRef(PROTOCOL(This));
958 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
960 BindProtocol *This = SERVPROV_THIS(iface);
961 return IInternetProtocol_Release(PROTOCOL(This));
964 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
965 REFGUID guidService, REFIID riid, void **ppv)
967 BindProtocol *This = SERVPROV_THIS(iface);
969 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
971 if(!This->service_provider)
972 return E_NOINTERFACE;
974 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
977 #undef SERVPROV_THIS
979 static const IServiceProviderVtbl ServiceProviderVtbl = {
980 BPServiceProvider_QueryInterface,
981 BPServiceProvider_AddRef,
982 BPServiceProvider_Release,
983 BPServiceProvider_QueryService
986 HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol)
988 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
990 ret->lpInternetProtocolVtbl = &BindProtocolVtbl;
991 ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
992 ret->lpInternetPriorityVtbl = &InternetPriorityVtbl;
993 ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
994 ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
996 ret->ref = 1;
997 ret->from_urlmon = from_urlmon;
998 ret->apartment_thread = GetCurrentThreadId();
999 ret->notif_hwnd = get_notif_hwnd();
1000 InitializeCriticalSection(&ret->section);
1002 URLMON_LockModule();
1004 *protocol = PROTOCOL(ret);
1005 return S_OK;