42d3d2192520ce8b5bf151864bcc81285af996d0
[reactos.git] / dll / win32 / urlmon / bindprot.c
1 /*
2 * Copyright 2007-2009 Jacek Caban for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #include "urlmon_main.h"
20 #include "wine/debug.h"
21
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
23
24 typedef void (*task_proc_t)(BindProtocol*,task_header_t*);
25
26 struct _task_header_t {
27 task_proc_t proc;
28 task_header_t *next;
29 };
30
31 #define BUFFER_SIZE 2048
32 #define MIME_TEST_SIZE 255
33
34 #define WM_MK_CONTINUE (WM_USER+101)
35 #define WM_MK_RELEASE (WM_USER+102)
36
37 static void process_tasks(BindProtocol *This)
38 {
39 task_header_t *task;
40
41 while(1) {
42 EnterCriticalSection(&This->section);
43
44 task = This->task_queue_head;
45 if(task) {
46 This->task_queue_head = task->next;
47 if(!This->task_queue_head)
48 This->task_queue_tail = NULL;
49 }
50
51 LeaveCriticalSection(&This->section);
52
53 if(!task)
54 break;
55
56 This->continue_call++;
57 task->proc(This, task);
58 This->continue_call--;
59 }
60 }
61
62 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
63 {
64 switch(msg) {
65 case WM_MK_CONTINUE: {
66 BindProtocol *This = (BindProtocol*)lParam;
67
68 process_tasks(This);
69
70 IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
71 return 0;
72 }
73 case WM_MK_RELEASE: {
74 tls_data_t *data = get_tls_data();
75
76 if(!--data->notif_hwnd_cnt) {
77 DestroyWindow(hwnd);
78 data->notif_hwnd = NULL;
79 }
80 }
81 }
82
83 return DefWindowProcW(hwnd, msg, wParam, lParam);
84 }
85
86 static const WCHAR wszURLMonikerNotificationWindow[] =
87 {'U','R','L',' ','M','o','n','i','k','e','r',' ',
88 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
89
90 static ATOM notif_wnd_class;
91
92 static BOOL WINAPI register_notif_wnd_class(INIT_ONCE *once, void *param, void **context)
93 {
94 static WNDCLASSEXW wndclass = {
95 sizeof(wndclass), 0, notif_wnd_proc, 0, 0,
96 NULL, NULL, NULL, NULL, NULL,
97 wszURLMonikerNotificationWindow, NULL
98 };
99
100 wndclass.hInstance = hProxyDll;
101 notif_wnd_class = RegisterClassExW(&wndclass);
102 return TRUE;
103 }
104
105 void unregister_notif_wnd_class(void)
106 {
107 if(notif_wnd_class)
108 UnregisterClassW(MAKEINTRESOURCEW(notif_wnd_class), hProxyDll);
109 }
110
111 HWND get_notif_hwnd(void)
112 {
113 tls_data_t *tls_data;
114
115 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
116
117 tls_data = get_tls_data();
118 if(!tls_data)
119 return NULL;
120
121 if(tls_data->notif_hwnd_cnt) {
122 tls_data->notif_hwnd_cnt++;
123 return tls_data->notif_hwnd;
124 }
125
126 InitOnceExecuteOnce(&init_once, register_notif_wnd_class, NULL, NULL);
127 if(!notif_wnd_class)
128 return NULL;
129
130 tls_data->notif_hwnd = CreateWindowExW(0, MAKEINTRESOURCEW(notif_wnd_class),
131 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
132 NULL, hProxyDll, NULL);
133 if(tls_data->notif_hwnd)
134 tls_data->notif_hwnd_cnt++;
135
136 TRACE("hwnd = %p\n", tls_data->notif_hwnd);
137
138 return tls_data->notif_hwnd;
139 }
140
141 void release_notif_hwnd(HWND hwnd)
142 {
143 tls_data_t *data = get_tls_data();
144
145 if(!data)
146 return;
147
148 if(data->notif_hwnd != hwnd) {
149 PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
150 return;
151 }
152
153 if(!--data->notif_hwnd_cnt) {
154 DestroyWindow(data->notif_hwnd);
155 data->notif_hwnd = NULL;
156 }
157 }
158
159 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
160 {
161 BOOL do_post = FALSE;
162
163 task->proc = proc;
164 task->next = NULL;
165
166 EnterCriticalSection(&This->section);
167
168 if(This->task_queue_tail) {
169 This->task_queue_tail->next = task;
170 This->task_queue_tail = task;
171 }else {
172 This->task_queue_tail = This->task_queue_head = task;
173 do_post = !This->continue_call;
174 }
175
176 LeaveCriticalSection(&This->section);
177
178 if(do_post) {
179 IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
180 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
181 }
182 }
183
184 static inline BOOL is_apartment_thread(BindProtocol *This)
185 {
186 return This->apartment_thread == GetCurrentThreadId();
187 }
188
189 static inline BOOL do_direct_notif(BindProtocol *This)
190 {
191 return !(This->pi & PI_APARTMENTTHREADED) || (is_apartment_thread(This) && !This->continue_call);
192 }
193
194 static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter)
195 {
196 PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 };
197 HRESULT hres;
198
199 hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&This->protocol_sink_handler);
200 if(FAILED(hres)) {
201 This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
202 return hres;
203 }
204
205 IInternetProtocol_AddRef(mime_filter);
206 This->protocol_handler = mime_filter;
207
208 filter_data.pProtocol = &This->default_protocol_handler.IInternetProtocol_iface;
209 hres = IInternetProtocol_Start(mime_filter, This->mime, &This->default_protocol_handler.IInternetProtocolSink_iface,
210 &This->IInternetBindInfo_iface, PI_FILTER_MODE|PI_FORCE_ASYNC,
211 (HANDLE_PTR)&filter_data);
212 if(FAILED(hres)) {
213 IInternetProtocolSink_Release(This->protocol_sink_handler);
214 IInternetProtocol_Release(This->protocol_handler);
215 This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
216 This->protocol_handler = &This->default_protocol_handler.IInternetProtocol_iface;
217 return hres;
218 }
219
220 /* NOTE: IE9 calls it on the new protocol_sink. It doesn't make sense so it seems to be a bug there. */
221 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL);
222
223 return S_OK;
224 }
225
226 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
227 {
228 IInternetProtocol *mime_filter;
229 HRESULT hres;
230
231 heap_free(This->mime);
232 This->mime = heap_strdupW(mime);
233
234 if(This->protocol_handler==&This->default_protocol_handler.IInternetProtocol_iface
235 && (mime_filter = get_mime_filter(mime))) {
236 TRACE("Got mime filter for %s\n", debugstr_w(mime));
237
238 hres = handle_mime_filter(This, mime_filter);
239 IInternetProtocol_Release(mime_filter);
240 if(FAILED(hres))
241 FIXME("MIME filter failed: %08x\n", hres);
242 }
243
244 if(This->reported_mime || verified || !(This->pi & PI_MIMEVERIFICATION)) {
245 This->reported_mime = TRUE;
246 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
247 }
248 }
249
250 static inline BindProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
251 {
252 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolEx_iface);
253 }
254
255 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
256 {
257 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
258
259 *ppv = NULL;
260 if(IsEqualGUID(&IID_IUnknown, riid)) {
261 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
262 *ppv = &This->IInternetProtocolEx_iface;
263 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
264 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
265 *ppv = &This->IInternetProtocolEx_iface;
266 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
267 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
268 *ppv = &This->IInternetProtocolEx_iface;
269 }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
270 TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
271 *ppv = &This->IInternetProtocolEx_iface;
272 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
273 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
274 *ppv = &This->IInternetBindInfo_iface;
275 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
276 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
277 *ppv = &This->IInternetPriority_iface;
278 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
279 FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
280 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
281 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
282 *ppv = &This->IServiceProvider_iface;
283 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
284 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
285 *ppv = &This->IInternetProtocolSink_iface;
286 }else if(This->protocol_unk) {
287 HRESULT hres;
288 hres = IUnknown_QueryInterface(This->protocol_unk, riid, ppv);
289 TRACE("(%p) aggregated handler returned %08x for %s\n", This, hres, debugstr_guid(riid));
290 return hres;
291 }else {
292 WARN("not supported interface %s\n", debugstr_guid(riid));
293 }
294
295 if(!*ppv)
296 return E_NOINTERFACE;
297
298 IUnknown_AddRef((IUnknown*)*ppv);
299 return S_OK;
300 }
301
302 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocolEx *iface)
303 {
304 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
305 LONG ref = InterlockedIncrement(&This->ref);
306 TRACE("(%p) ref=%d\n", This, ref);
307 return ref;
308 }
309
310 static void release_protocol_handler(BindProtocol *This)
311 {
312 if(This->protocol) {
313 IInternetProtocol_Release(This->protocol);
314 This->protocol = NULL;
315 }
316 if(This->protocol_handler && This->protocol_handler != &This->default_protocol_handler.IInternetProtocol_iface) {
317 IInternetProtocol_Release(This->protocol_handler);
318 This->protocol_handler = &This->default_protocol_handler.IInternetProtocol_iface;
319 }
320 if(This->protocol_sink_handler &&
321 This->protocol_sink_handler != &This->default_protocol_handler.IInternetProtocolSink_iface) {
322 IInternetProtocolSink_Release(This->protocol_sink_handler);
323 This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
324 }
325 if(This->protocol_unk) {
326 IUnknown_Release(This->protocol_unk);
327 This->protocol_unk = NULL;
328 }
329 }
330
331 static ULONG WINAPI BindProtocol_Release(IInternetProtocolEx *iface)
332 {
333 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
334 LONG ref = InterlockedDecrement(&This->ref);
335
336 TRACE("(%p) ref=%d\n", This, ref);
337
338 if(!ref) {
339 release_protocol_handler(This);
340 if(This->redirect_callback)
341 IBindCallbackRedirect_Release(This->redirect_callback);
342 if(This->bind_info)
343 IInternetBindInfo_Release(This->bind_info);
344 if(This->uri)
345 IUri_Release(This->uri);
346 SysFreeString(This->display_uri);
347
348 set_binding_sink(This, NULL, NULL);
349
350 if(This->notif_hwnd)
351 release_notif_hwnd(This->notif_hwnd);
352 This->section.DebugInfo->Spare[0] = 0;
353 DeleteCriticalSection(&This->section);
354
355 heap_free(This->mime);
356 heap_free(This);
357
358 URLMON_UnlockModule();
359 }
360
361 return ref;
362 }
363
364 static HRESULT WINAPI BindProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
365 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
366 DWORD grfPI, HANDLE_PTR dwReserved)
367 {
368 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
369 IUri *uri;
370 HRESULT hres;
371
372 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
373 pOIBindInfo, grfPI, dwReserved);
374
375 hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
376 if(FAILED(hres))
377 return hres;
378
379 hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
380 pOIBindInfo, grfPI, (HANDLE*)dwReserved);
381
382 IUri_Release(uri);
383 return hres;
384 }
385
386 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
387 {
388 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
389
390 TRACE("(%p)->(%p)\n", This, pProtocolData);
391
392 return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
393 }
394
395 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
396 DWORD dwOptions)
397 {
398 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
399
400 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
401
402 return IInternetProtocol_Abort(This->protocol_handler, hrReason, dwOptions);
403 }
404
405 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
406 {
407 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
408
409 TRACE("(%p)->(%08x)\n", This, dwOptions);
410
411 return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
412 }
413
414 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocolEx *iface)
415 {
416 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
417 FIXME("(%p)\n", This);
418 return E_NOTIMPL;
419 }
420
421 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocolEx *iface)
422 {
423 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
424 FIXME("(%p)\n", This);
425 return E_NOTIMPL;
426 }
427
428 static HRESULT WINAPI BindProtocol_Read(IInternetProtocolEx *iface, void *pv,
429 ULONG cb, ULONG *pcbRead)
430 {
431 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
432
433 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
434
435 if(pcbRead)
436 *pcbRead = 0;
437 return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
438 }
439
440 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
441 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
442 {
443 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
444 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
445 return E_NOTIMPL;
446 }
447
448 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
449 {
450 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
451
452 TRACE("(%p)->(%08x)\n", This, dwOptions);
453
454 return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
455 }
456
457 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocolEx *iface)
458 {
459 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
460
461 TRACE("(%p)\n", This);
462
463 return IInternetProtocol_UnlockRequest(This->protocol_handler);
464 }
465
466 static HRESULT WINAPI BindProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
467 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
468 DWORD grfPI, HANDLE *dwReserved)
469 {
470 BindProtocol *This = impl_from_IInternetProtocolEx(iface);
471 IInternetProtocol *protocol = NULL;
472 IInternetProtocolEx *protocolex;
473 IInternetPriority *priority;
474 IServiceProvider *service_provider;
475 CLSID clsid = IID_NULL;
476 IUnknown *protocol_unk = NULL;
477 LPOLESTR clsid_str;
478 HRESULT hres;
479
480 TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
481
482 if(!pUri || !pOIProtSink || !pOIBindInfo)
483 return E_INVALIDARG;
484
485 This->pi = grfPI;
486
487 if(This->uri) {
488 SysFreeString(This->display_uri);
489 IUri_Release(This->uri);
490 }
491 IUri_AddRef(pUri);
492 This->uri = pUri;
493
494 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
495 (void**)&service_provider);
496 if(SUCCEEDED(hres)) {
497 /* FIXME: What's protocol CLSID here? */
498 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
499 &IID_IInternetProtocol, (void**)&protocol);
500 IServiceProvider_Release(service_provider);
501 }
502
503 if(!protocol) {
504 IClassFactory *cf;
505
506 hres = get_protocol_handler(pUri, &clsid, &cf);
507 if(FAILED(hres))
508 return hres;
509
510 hres = IClassFactory_CreateInstance(cf, (IUnknown*)&This->IInternetBindInfo_iface,
511 &IID_IUnknown, (void**)&protocol_unk);
512 IClassFactory_Release(cf);
513 if(FAILED(hres))
514 return hres;
515
516 hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetProtocol, (void**)&protocol);
517 if(FAILED(hres)) {
518 IUnknown_Release(protocol_unk);
519 return hres;
520 }
521 }
522
523 StringFromCLSID(&clsid, &clsid_str);
524 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
525 CoTaskMemFree(clsid_str);
526
527 This->protocol_unk = protocol_unk;
528 This->protocol = protocol;
529
530 if(!protocol_unk)
531 protocol_unk = (IUnknown*)protocol;
532
533 set_binding_sink(This, pOIProtSink, pOIBindInfo);
534
535 hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetPriority, (void**)&priority);
536 if(SUCCEEDED(hres)) {
537 IInternetPriority_SetPriority(priority, This->priority);
538 IInternetPriority_Release(priority);
539 }
540
541 hres = IUnknown_QueryInterface(protocol_unk, &IID_IInternetProtocolEx, (void**)&protocolex);
542 if(SUCCEEDED(hres)) {
543 hres = IInternetProtocolEx_StartEx(protocolex, pUri, &This->IInternetProtocolSink_iface,
544 &This->IInternetBindInfo_iface, 0, NULL);
545 IInternetProtocolEx_Release(protocolex);
546 }else {
547 hres = IUri_GetDisplayUri(pUri, &This->display_uri);
548 if(FAILED(hres))
549 return hres;
550
551 hres = IInternetProtocol_Start(protocol, This->display_uri, &This->IInternetProtocolSink_iface,
552 &This->IInternetBindInfo_iface, 0, 0);
553 }
554
555 if(SUCCEEDED(hres))
556 process_tasks(This);
557 return hres;
558 }
559
560 void set_binding_sink(BindProtocol *This, IInternetProtocolSink *sink, IInternetBindInfo *bind_info)
561 {
562 IInternetProtocolSink *prev_sink;
563 IServiceProvider *service_provider = NULL;
564
565 if(sink)
566 IInternetProtocolSink_AddRef(sink);
567 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
568 if(prev_sink)
569 IInternetProtocolSink_Release(prev_sink);
570
571 if(sink)
572 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
573 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
574 if(service_provider)
575 IServiceProvider_Release(service_provider);
576
577 if(bind_info)
578 IInternetBindInfo_AddRef(bind_info);
579 bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info);
580 if(bind_info)
581 IInternetBindInfo_Release(bind_info);
582 }
583
584 static const IInternetProtocolExVtbl BindProtocolVtbl = {
585 BindProtocol_QueryInterface,
586 BindProtocol_AddRef,
587 BindProtocol_Release,
588 BindProtocol_Start,
589 BindProtocol_Continue,
590 BindProtocol_Abort,
591 BindProtocol_Terminate,
592 BindProtocol_Suspend,
593 BindProtocol_Resume,
594 BindProtocol_Read,
595 BindProtocol_Seek,
596 BindProtocol_LockRequest,
597 BindProtocol_UnlockRequest,
598 BindProtocol_StartEx
599 };
600
601 static inline BindProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
602 {
603 return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocol_iface);
604 }
605
606 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
607 {
608 BindProtocol *This = impl_from_IInternetProtocol(iface);
609
610 *ppv = NULL;
611 if(IsEqualGUID(&IID_IUnknown, riid)) {
612 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
613 *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
614 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
615 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
616 *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
617 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
618 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
619 *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
620 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
621 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
622 *ppv = &This->default_protocol_handler.IInternetProtocolSink_iface;
623 }
624
625 if(*ppv) {
626 IInternetProtocol_AddRef(iface);
627 return S_OK;
628 }
629
630 WARN("not supported interface %s\n", debugstr_guid(riid));
631 return E_NOINTERFACE;
632 }
633
634 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
635 {
636 BindProtocol *This = impl_from_IInternetProtocol(iface);
637 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
638 }
639
640 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
641 {
642 BindProtocol *This = impl_from_IInternetProtocol(iface);
643 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
644 }
645
646 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
647 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
648 DWORD grfPI, HANDLE_PTR dwReserved)
649 {
650 ERR("Should not be called\n");
651 return E_NOTIMPL;
652 }
653
654 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
655 {
656 BindProtocol *This = impl_from_IInternetProtocol(iface);
657 IInternetProtocol *protocol = NULL;
658 HRESULT hres;
659
660 TRACE("(%p)->(%p)\n", This, pProtocolData);
661
662 /* FIXME: This should not be needed. */
663 if(!This->protocol) {
664 if(!This->protocol_unk)
665 return E_FAIL;
666 hres = IUnknown_QueryInterface(This->protocol_unk, &IID_IInternetProtocol, (void**)&protocol);
667 if(FAILED(hres))
668 return E_FAIL;
669 }
670
671 hres = IInternetProtocol_Continue(protocol ? protocol : This->protocol, pProtocolData);
672
673 heap_free(pProtocolData);
674 if(protocol)
675 IInternetProtocol_Release(protocol);
676 return hres;
677 }
678
679 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
680 DWORD dwOptions)
681 {
682 BindProtocol *This = impl_from_IInternetProtocol(iface);
683
684 TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
685
686 if(This->protocol && !This->reported_result)
687 return IInternetProtocol_Abort(This->protocol, hrReason, dwOptions);
688
689 return S_OK;
690 }
691
692 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
693 {
694 BindProtocol *This = impl_from_IInternetProtocol(iface);
695
696 TRACE("(%p)->(%08x)\n", This, dwOptions);
697
698 if(!This->reported_result)
699 return E_FAIL;
700
701 /* This may get released in Terminate call. */
702 IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
703
704 if(This->protocol) {
705 IInternetProtocol_Terminate(This->protocol, 0);
706 IInternetProtocol_Release(This->protocol);
707 This->protocol = NULL;
708 }
709
710 set_binding_sink(This, NULL, NULL);
711
712 if(This->bind_info) {
713 IInternetBindInfo_Release(This->bind_info);
714 This->bind_info = NULL;
715 }
716
717 if(This->redirect_callback) {
718 IBindCallbackRedirect_Release(This->redirect_callback);
719 This->redirect_callback = NULL;
720 }
721
722 IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
723 return S_OK;
724 }
725
726 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
727 {
728 BindProtocol *This = impl_from_IInternetProtocol(iface);
729 FIXME("(%p)\n", This);
730 return E_NOTIMPL;
731 }
732
733 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
734 {
735 BindProtocol *This = impl_from_IInternetProtocol(iface);
736 FIXME("(%p)\n", This);
737 return E_NOTIMPL;
738 }
739
740 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
741 ULONG cb, ULONG *pcbRead)
742 {
743 BindProtocol *This = impl_from_IInternetProtocol(iface);
744 ULONG read = 0;
745 HRESULT hres = S_OK;
746
747 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
748
749 if(This->buf_size) {
750 read = min(cb, This->buf_size);
751 memcpy(pv, This->buf, read);
752
753 if(read == This->buf_size) {
754 heap_free(This->buf);
755 This->buf = NULL;
756 }else {
757 memmove(This->buf, This->buf+cb, This->buf_size-cb);
758 }
759
760 This->buf_size -= read;
761 }
762
763 if(read < cb) {
764 IInternetProtocol *protocol;
765 ULONG cread = 0;
766
767 /* FIXME: We shouldn't need it, but out binding code currently depends on it. */
768 if(!This->protocol && This->protocol_unk) {
769 hres = IUnknown_QueryInterface(This->protocol_unk, &IID_IInternetProtocol,
770 (void**)&protocol);
771 if(FAILED(hres))
772 return E_ABORT;
773 }else {
774 protocol = This->protocol;
775 }
776
777 if(is_apartment_thread(This))
778 This->continue_call++;
779 hres = IInternetProtocol_Read(protocol, (BYTE*)pv+read, cb-read, &cread);
780 if(is_apartment_thread(This))
781 This->continue_call--;
782 read += cread;
783
784 if(!This->protocol)
785 IInternetProtocol_Release(protocol);
786 }
787
788 *pcbRead = read;
789 return hres;
790 }
791
792 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
793 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
794 {
795 BindProtocol *This = impl_from_IInternetProtocol(iface);
796 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
797 return E_NOTIMPL;
798 }
799
800 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
801 {
802 BindProtocol *This = impl_from_IInternetProtocol(iface);
803
804 TRACE("(%p)->(%08x)\n", This, dwOptions);
805
806 return IInternetProtocol_LockRequest(This->protocol, dwOptions);
807 }
808
809 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
810 {
811 BindProtocol *This = impl_from_IInternetProtocol(iface);
812
813 TRACE("(%p)\n", This);
814
815 return IInternetProtocol_UnlockRequest(This->protocol);
816 }
817
818 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
819 ProtocolHandler_QueryInterface,
820 ProtocolHandler_AddRef,
821 ProtocolHandler_Release,
822 ProtocolHandler_Start,
823 ProtocolHandler_Continue,
824 ProtocolHandler_Abort,
825 ProtocolHandler_Terminate,
826 ProtocolHandler_Suspend,
827 ProtocolHandler_Resume,
828 ProtocolHandler_Read,
829 ProtocolHandler_Seek,
830 ProtocolHandler_LockRequest,
831 ProtocolHandler_UnlockRequest
832 };
833
834 static inline BindProtocol *impl_from_IInternetProtocolSinkHandler(IInternetProtocolSink *iface)
835 {
836 return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocolSink_iface);
837 }
838
839 static HRESULT WINAPI ProtocolSinkHandler_QueryInterface(IInternetProtocolSink *iface,
840 REFIID riid, void **ppvObject)
841 {
842 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
843 return IInternetProtocol_QueryInterface(&This->default_protocol_handler.IInternetProtocol_iface,
844 riid, ppvObject);
845 }
846
847 static ULONG WINAPI ProtocolSinkHandler_AddRef(IInternetProtocolSink *iface)
848 {
849 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
850 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
851 }
852
853 static ULONG WINAPI ProtocolSinkHandler_Release(IInternetProtocolSink *iface)
854 {
855 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
856 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
857 }
858
859 static HRESULT WINAPI ProtocolSinkHandler_Switch(IInternetProtocolSink *iface,
860 PROTOCOLDATA *pProtocolData)
861 {
862 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
863
864 TRACE("(%p)->(%p)\n", This, pProtocolData);
865
866 if(!This->protocol_sink) {
867 IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
868 return S_OK;
869 }
870
871 return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
872 }
873
874 static HRESULT WINAPI ProtocolSinkHandler_ReportProgress(IInternetProtocolSink *iface,
875 ULONG status_code, LPCWSTR status_text)
876 {
877 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
878
879 TRACE("(%p)->(%s %s)\n", This, debugstr_bindstatus(status_code), debugstr_w(status_text));
880
881 if(!This->protocol_sink)
882 return S_OK;
883
884 switch(status_code) {
885 case BINDSTATUS_FINDINGRESOURCE:
886 case BINDSTATUS_CONNECTING:
887 case BINDSTATUS_REDIRECTING:
888 case BINDSTATUS_SENDINGREQUEST:
889 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
890 case BINDSTATUS_DIRECTBIND:
891 case BINDSTATUS_ACCEPTRANGES:
892 case BINDSTATUS_DECODING:
893 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
894 break;
895
896 case BINDSTATUS_BEGINDOWNLOADDATA:
897 IInternetProtocolSink_ReportData(This->protocol_sink, This->bscf, This->progress, This->progress_max);
898 break;
899
900 case BINDSTATUS_MIMETYPEAVAILABLE:
901 mime_available(This, status_text, FALSE);
902 break;
903
904 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
905 mime_available(This, status_text, TRUE);
906 break;
907
908 default:
909 FIXME("unsupported ulStatusCode %u\n", status_code);
910 }
911
912 return S_OK;
913 }
914
915 static HRESULT WINAPI ProtocolSinkHandler_ReportData(IInternetProtocolSink *iface,
916 DWORD bscf, ULONG progress, ULONG progress_max)
917 {
918 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
919
920 TRACE("(%p)->(%x %u %u)\n", This, bscf, progress, progress_max);
921
922 This->bscf = bscf;
923 This->progress = progress;
924 This->progress_max = progress_max;
925
926 if(!This->protocol_sink)
927 return S_OK;
928
929 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
930 BYTE buf[BUFFER_SIZE];
931 DWORD read = 0;
932 LPWSTR mime;
933 HRESULT hres;
934
935 do {
936 read = 0;
937 if(is_apartment_thread(This))
938 This->continue_call++;
939 hres = IInternetProtocol_Read(This->protocol, buf,
940 sizeof(buf)-This->buf_size, &read);
941 if(is_apartment_thread(This))
942 This->continue_call--;
943 if(FAILED(hres) && hres != E_PENDING)
944 return hres;
945
946 if(!This->buf) {
947 This->buf = heap_alloc(BUFFER_SIZE);
948 if(!This->buf)
949 return E_OUTOFMEMORY;
950 }else if(read + This->buf_size > BUFFER_SIZE) {
951 BYTE *tmp;
952
953 tmp = heap_realloc(This->buf, read+This->buf_size);
954 if(!tmp)
955 return E_OUTOFMEMORY;
956 This->buf = tmp;
957 }
958
959 memcpy(This->buf+This->buf_size, buf, read);
960 This->buf_size += read;
961 }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
962
963 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
964 return S_OK;
965
966 bscf = BSCF_FIRSTDATANOTIFICATION;
967 if(hres == S_FALSE)
968 bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
969
970 if(!This->reported_mime) {
971 BSTR raw_uri;
972
973 hres = IUri_GetRawUri(This->uri, &raw_uri);
974 if(FAILED(hres))
975 return hres;
976
977 hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE),
978 This->mime, 0, &mime, 0);
979 SysFreeString(raw_uri);
980 if(FAILED(hres))
981 return hres;
982
983 heap_free(This->mime);
984 This->mime = heap_strdupW(mime);
985 CoTaskMemFree(mime);
986 This->reported_mime = TRUE;
987 if(This->protocol_sink)
988 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
989 }
990 }
991
992 if(!This->protocol_sink)
993 return S_OK;
994
995 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
996 }
997
998 static HRESULT handle_redirect(BindProtocol *This, const WCHAR *url)
999 {
1000 HRESULT hres;
1001
1002 if(This->redirect_callback) {
1003 VARIANT_BOOL cancel = VARIANT_FALSE;
1004 IBindCallbackRedirect_Redirect(This->redirect_callback, url, &cancel);
1005 if(cancel)
1006 return INET_E_REDIRECT_FAILED;
1007 }
1008
1009 if(This->protocol_sink) {
1010 hres = IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_REDIRECTING, url);
1011 if(FAILED(hres))
1012 return hres;
1013 }
1014
1015 IInternetProtocol_Terminate(This->protocol, 0); /* should this be done in StartEx? */
1016 release_protocol_handler(This);
1017
1018 return IInternetProtocolEx_Start(&This->IInternetProtocolEx_iface, url, This->protocol_sink, This->bind_info, This->pi, 0);
1019 }
1020
1021 static HRESULT WINAPI ProtocolSinkHandler_ReportResult(IInternetProtocolSink *iface,
1022 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1023 {
1024 BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
1025
1026 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1027
1028 if(hrResult == INET_E_REDIRECT_FAILED) {
1029 hrResult = handle_redirect(This, szResult);
1030 if(hrResult == S_OK)
1031 return S_OK;
1032 szResult = NULL;
1033 }
1034
1035 if(This->protocol_sink)
1036 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1037 return S_OK;
1038 }
1039
1040 static const IInternetProtocolSinkVtbl InternetProtocolSinkHandlerVtbl = {
1041 ProtocolSinkHandler_QueryInterface,
1042 ProtocolSinkHandler_AddRef,
1043 ProtocolSinkHandler_Release,
1044 ProtocolSinkHandler_Switch,
1045 ProtocolSinkHandler_ReportProgress,
1046 ProtocolSinkHandler_ReportData,
1047 ProtocolSinkHandler_ReportResult
1048 };
1049
1050 static inline BindProtocol *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
1051 {
1052 return CONTAINING_RECORD(iface, BindProtocol, IInternetBindInfo_iface);
1053 }
1054
1055 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
1056 REFIID riid, void **ppv)
1057 {
1058 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1059 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1060 }
1061
1062 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
1063 {
1064 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1065 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1066 }
1067
1068 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
1069 {
1070 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1071 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1072 }
1073
1074 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
1075 DWORD *grfBINDF, BINDINFO *pbindinfo)
1076 {
1077 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1078 HRESULT hres;
1079
1080 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1081
1082 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
1083 if(FAILED(hres)) {
1084 WARN("GetBindInfo failed: %08x\n", hres);
1085 return hres;
1086 }
1087
1088 if((pbindinfo->dwOptions & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS) && !This->redirect_callback) {
1089 IServiceProvider *service_provider;
1090
1091 hres = IInternetProtocolSink_QueryInterface(This->protocol_sink, &IID_IServiceProvider, (void**)&service_provider);
1092 if(SUCCEEDED(hres)) {
1093 hres = IServiceProvider_QueryService(service_provider, &IID_IBindCallbackRedirect, &IID_IBindCallbackRedirect,
1094 (void**)&This->redirect_callback);
1095 IServiceProvider_Release(service_provider);
1096 }
1097 }
1098
1099 *grfBINDF |= BINDF_FROMURLMON;
1100 return hres;
1101 }
1102
1103 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
1104 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1105 {
1106 BindProtocol *This = impl_from_IInternetBindInfo(iface);
1107
1108 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1109
1110 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
1111 }
1112
1113 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1114 BindInfo_QueryInterface,
1115 BindInfo_AddRef,
1116 BindInfo_Release,
1117 BindInfo_GetBindInfo,
1118 BindInfo_GetBindString
1119 };
1120
1121 static inline BindProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
1122 {
1123 return CONTAINING_RECORD(iface, BindProtocol, IInternetPriority_iface);
1124 }
1125
1126 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
1127 REFIID riid, void **ppv)
1128 {
1129 BindProtocol *This = impl_from_IInternetPriority(iface);
1130 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1131 }
1132
1133 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
1134 {
1135 BindProtocol *This = impl_from_IInternetPriority(iface);
1136 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1137 }
1138
1139 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
1140 {
1141 BindProtocol *This = impl_from_IInternetPriority(iface);
1142 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1143 }
1144
1145 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
1146 {
1147 BindProtocol *This = impl_from_IInternetPriority(iface);
1148
1149 TRACE("(%p)->(%d)\n", This, nPriority);
1150
1151 This->priority = nPriority;
1152 return S_OK;
1153 }
1154
1155 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
1156 {
1157 BindProtocol *This = impl_from_IInternetPriority(iface);
1158
1159 TRACE("(%p)->(%p)\n", This, pnPriority);
1160
1161 *pnPriority = This->priority;
1162 return S_OK;
1163 }
1164
1165 static const IInternetPriorityVtbl InternetPriorityVtbl = {
1166 InternetPriority_QueryInterface,
1167 InternetPriority_AddRef,
1168 InternetPriority_Release,
1169 InternetPriority_SetPriority,
1170 InternetPriority_GetPriority
1171
1172 };
1173
1174 static inline BindProtocol *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
1175 {
1176 return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolSink_iface);
1177 }
1178
1179 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
1180 REFIID riid, void **ppv)
1181 {
1182 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1183 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1184 }
1185
1186 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
1187 {
1188 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1189 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1190 }
1191
1192 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
1193 {
1194 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1195 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1196 }
1197
1198 typedef struct {
1199 task_header_t header;
1200 PROTOCOLDATA *data;
1201 } switch_task_t;
1202
1203 static void switch_proc(BindProtocol *bind, task_header_t *t)
1204 {
1205 switch_task_t *task = (switch_task_t*)t;
1206
1207 IInternetProtocol_Continue(bind->protocol_handler, task->data);
1208
1209 heap_free(task);
1210 }
1211
1212 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
1213 PROTOCOLDATA *pProtocolData)
1214 {
1215 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1216 PROTOCOLDATA *data;
1217
1218 TRACE("(%p)->(%p)\n", This, pProtocolData);
1219
1220 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
1221 pProtocolData->pData, pProtocolData->cbData);
1222
1223 data = heap_alloc(sizeof(PROTOCOLDATA));
1224 if(!data)
1225 return E_OUTOFMEMORY;
1226 memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
1227
1228 if((This->pi&PI_APARTMENTTHREADED && pProtocolData->grfFlags&PI_FORCE_ASYNC)
1229 || !do_direct_notif(This)) {
1230 switch_task_t *task;
1231
1232 task = heap_alloc(sizeof(switch_task_t));
1233 if(!task)
1234 {
1235 heap_free(data);
1236 return E_OUTOFMEMORY;
1237 }
1238
1239 task->data = data;
1240
1241 push_task(This, &task->header, switch_proc);
1242 return S_OK;
1243 }
1244
1245 return IInternetProtocolSink_Switch(This->protocol_sink_handler, data);
1246 }
1247
1248 typedef struct {
1249 task_header_t header;
1250
1251 ULONG status_code;
1252 LPWSTR status_text;
1253 } on_progress_task_t;
1254
1255 static void on_progress_proc(BindProtocol *This, task_header_t *t)
1256 {
1257 on_progress_task_t *task = (on_progress_task_t*)t;
1258
1259 IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, task->status_code, task->status_text);
1260
1261 heap_free(task->status_text);
1262 heap_free(task);
1263 }
1264
1265 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
1266 ULONG ulStatusCode, LPCWSTR szStatusText)
1267 {
1268 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1269
1270 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
1271
1272 if(do_direct_notif(This)) {
1273 IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, ulStatusCode, szStatusText);
1274 }else {
1275 on_progress_task_t *task;
1276
1277 task = heap_alloc(sizeof(on_progress_task_t));
1278
1279 task->status_code = ulStatusCode;
1280 task->status_text = heap_strdupW(szStatusText);
1281
1282 push_task(This, &task->header, on_progress_proc);
1283 }
1284
1285 return S_OK;
1286 }
1287
1288 typedef struct {
1289 task_header_t header;
1290 DWORD bscf;
1291 ULONG progress;
1292 ULONG progress_max;
1293 } report_data_task_t;
1294
1295 static void report_data_proc(BindProtocol *This, task_header_t *t)
1296 {
1297 report_data_task_t *task = (report_data_task_t*)t;
1298
1299 IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1300 task->bscf, task->progress, task->progress_max);
1301
1302 heap_free(task);
1303 }
1304
1305 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1306 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1307 {
1308 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1309
1310 TRACE("(%p)->(%x %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1311
1312 if(!This->protocol_sink)
1313 return S_OK;
1314
1315 if(!do_direct_notif(This)) {
1316 report_data_task_t *task;
1317
1318 task = heap_alloc(sizeof(report_data_task_t));
1319 if(!task)
1320 return E_OUTOFMEMORY;
1321
1322 task->bscf = grfBSCF;
1323 task->progress = ulProgress;
1324 task->progress_max = ulProgressMax;
1325
1326 push_task(This, &task->header, report_data_proc);
1327 return S_OK;
1328 }
1329
1330 return IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1331 grfBSCF, ulProgress, ulProgressMax);
1332 }
1333
1334 typedef struct {
1335 task_header_t header;
1336
1337 HRESULT hres;
1338 DWORD err;
1339 LPWSTR str;
1340 } report_result_task_t;
1341
1342 static void report_result_proc(BindProtocol *This, task_header_t *t)
1343 {
1344 report_result_task_t *task = (report_result_task_t*)t;
1345
1346 IInternetProtocolSink_ReportResult(This->protocol_sink_handler, task->hres, task->err, task->str);
1347
1348 heap_free(task->str);
1349 heap_free(task);
1350 }
1351
1352 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1353 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1354 {
1355 BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1356
1357 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1358
1359 if(!This->protocol_sink)
1360 return E_FAIL;
1361 This->reported_result = TRUE;
1362
1363 if(!do_direct_notif(This)) {
1364 report_result_task_t *task;
1365
1366 task = heap_alloc(sizeof(report_result_task_t));
1367 if(!task)
1368 return E_OUTOFMEMORY;
1369
1370 task->hres = hrResult;
1371 task->err = dwError;
1372 task->str = heap_strdupW(szResult);
1373
1374 push_task(This, &task->header, report_result_proc);
1375 return S_OK;
1376 }
1377
1378 return IInternetProtocolSink_ReportResult(This->protocol_sink_handler, hrResult, dwError, szResult);
1379 }
1380
1381 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1382 BPInternetProtocolSink_QueryInterface,
1383 BPInternetProtocolSink_AddRef,
1384 BPInternetProtocolSink_Release,
1385 BPInternetProtocolSink_Switch,
1386 BPInternetProtocolSink_ReportProgress,
1387 BPInternetProtocolSink_ReportData,
1388 BPInternetProtocolSink_ReportResult
1389 };
1390
1391 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface)
1392 {
1393 return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface);
1394 }
1395
1396 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1397 REFIID riid, void **ppv)
1398 {
1399 BindProtocol *This = impl_from_IServiceProvider(iface);
1400 return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1401 }
1402
1403 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1404 {
1405 BindProtocol *This = impl_from_IServiceProvider(iface);
1406 return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1407 }
1408
1409 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1410 {
1411 BindProtocol *This = impl_from_IServiceProvider(iface);
1412 return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1413 }
1414
1415 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1416 REFGUID guidService, REFIID riid, void **ppv)
1417 {
1418 BindProtocol *This = impl_from_IServiceProvider(iface);
1419
1420 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1421
1422 if(!This->service_provider)
1423 return E_NOINTERFACE;
1424
1425 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1426 }
1427
1428 static const IServiceProviderVtbl ServiceProviderVtbl = {
1429 BPServiceProvider_QueryInterface,
1430 BPServiceProvider_AddRef,
1431 BPServiceProvider_Release,
1432 BPServiceProvider_QueryService
1433 };
1434
1435 HRESULT create_binding_protocol(BindProtocol **protocol)
1436 {
1437 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1438
1439 ret->IInternetProtocolEx_iface.lpVtbl = &BindProtocolVtbl;
1440 ret->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
1441 ret->IInternetPriority_iface.lpVtbl = &InternetPriorityVtbl;
1442 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
1443 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
1444
1445 ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
1446 ret->default_protocol_handler.IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkHandlerVtbl;
1447
1448 ret->ref = 1;
1449 ret->apartment_thread = GetCurrentThreadId();
1450 ret->notif_hwnd = get_notif_hwnd();
1451 ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
1452 ret->protocol_sink_handler = &ret->default_protocol_handler.IInternetProtocolSink_iface;
1453 InitializeCriticalSection(&ret->section);
1454 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BindProtocol.section");
1455
1456 URLMON_LockModule();
1457
1458 *protocol = ret;
1459 return S_OK;
1460 }