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