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