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