urlmon: Fixed buffer size argument in Read call.
[wine/hacks.git] / dlls / urlmon / bindprot.c
blobec58436d0ef4d2bd5664425eeac60056e71e526a
1 /*
2 * Copyright 2007 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "urlmon_main.h"
20 #include "wine/debug.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
24 typedef struct BindProtocol BindProtocol;
26 struct _task_header_t;
28 typedef void (*task_proc_t)(BindProtocol*,struct _task_header_t*);
30 typedef struct _task_header_t {
31 task_proc_t proc;
32 struct _task_header_t *next;
33 } task_header_t;
35 struct BindProtocol {
36 const IInternetProtocolVtbl *lpInternetProtocolVtbl;
37 const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
38 const IInternetPriorityVtbl *lpInternetPriorityVtbl;
39 const IServiceProviderVtbl *lpServiceProviderVtbl;
40 const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl;
42 const IInternetProtocolVtbl *lpIInternetProtocolHandlerVtbl;
44 LONG ref;
46 IInternetProtocol *protocol;
47 IInternetProtocol *protocol_handler;
48 IInternetBindInfo *bind_info;
49 IInternetProtocolSink *protocol_sink;
50 IServiceProvider *service_provider;
51 IWinInetInfo *wininet_info;
53 LONG priority;
55 BOOL reported_result;
56 BOOL reported_mime;
57 BOOL from_urlmon;
58 DWORD pi;
60 DWORD apartment_thread;
61 HWND notif_hwnd;
62 DWORD continue_call;
64 CRITICAL_SECTION section;
65 task_header_t *task_queue_head, *task_queue_tail;
67 BYTE *buf;
68 DWORD buf_size;
69 LPWSTR mime;
70 LPWSTR url;
73 #define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
74 #define BINDINFO(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
75 #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
76 #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl)
77 #define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
79 #define PROTOCOLHANDLER(x) ((IInternetProtocol*) &(x)->lpIInternetProtocolHandlerVtbl)
81 #define BUFFER_SIZE 2048
82 #define MIME_TEST_SIZE 255
84 #define WM_MK_CONTINUE (WM_USER+101)
85 #define WM_MK_RELEASE (WM_USER+102)
87 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
89 switch(msg) {
90 case WM_MK_CONTINUE: {
91 BindProtocol *This = (BindProtocol*)lParam;
92 task_header_t *task;
94 while(1) {
95 EnterCriticalSection(&This->section);
97 task = This->task_queue_head;
98 if(task) {
99 This->task_queue_head = task->next;
100 if(!This->task_queue_head)
101 This->task_queue_tail = NULL;
104 LeaveCriticalSection(&This->section);
106 if(!task)
107 break;
109 This->continue_call++;
110 task->proc(This, task);
111 This->continue_call--;
114 IInternetProtocol_Release(PROTOCOL(This));
115 return 0;
117 case WM_MK_RELEASE: {
118 tls_data_t *data = get_tls_data();
120 if(!--data->notif_hwnd_cnt) {
121 DestroyWindow(hwnd);
122 data->notif_hwnd = NULL;
127 return DefWindowProcW(hwnd, msg, wParam, lParam);
130 HWND get_notif_hwnd(void)
132 static ATOM wnd_class = 0;
133 tls_data_t *tls_data;
135 static const WCHAR wszURLMonikerNotificationWindow[] =
136 {'U','R','L',' ','M','o','n','i','k','e','r',' ',
137 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
139 tls_data = get_tls_data();
140 if(!tls_data)
141 return NULL;
143 if(tls_data->notif_hwnd_cnt) {
144 tls_data->notif_hwnd_cnt++;
145 return tls_data->notif_hwnd;
148 if(!wnd_class) {
149 static WNDCLASSEXW wndclass = {
150 sizeof(wndclass), 0,
151 notif_wnd_proc, 0, 0,
152 NULL, NULL, NULL, NULL, NULL,
153 wszURLMonikerNotificationWindow,
154 NULL
157 wndclass.hInstance = URLMON_hInstance;
159 wnd_class = RegisterClassExW(&wndclass);
160 if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
161 wnd_class = 1;
164 tls_data->notif_hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
165 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
166 NULL, URLMON_hInstance, NULL);
167 if(tls_data->notif_hwnd)
168 tls_data->notif_hwnd_cnt++;
170 TRACE("hwnd = %p\n", tls_data->notif_hwnd);
172 return tls_data->notif_hwnd;
175 void release_notif_hwnd(HWND hwnd)
177 tls_data_t *data = get_tls_data();
179 if(!data)
180 return;
182 if(data->notif_hwnd != hwnd) {
183 PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
184 return;
187 if(!--data->notif_hwnd_cnt) {
188 DestroyWindow(data->notif_hwnd);
189 data->notif_hwnd = NULL;
193 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
195 BOOL do_post = FALSE;
197 task->proc = proc;
198 task->next = NULL;
200 EnterCriticalSection(&This->section);
202 if(This->task_queue_tail) {
203 This->task_queue_tail->next = task;
204 This->task_queue_tail = task;
205 }else {
206 This->task_queue_tail = This->task_queue_head = task;
207 do_post = TRUE;
210 LeaveCriticalSection(&This->section);
212 if(do_post) {
213 IInternetProtocol_AddRef(PROTOCOL(This));
214 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
218 static BOOL inline do_direct_notif(BindProtocol *This)
220 return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
223 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocol, iface)
225 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
227 BindProtocol *This = PROTOCOL_THIS(iface);
229 *ppv = NULL;
230 if(IsEqualGUID(&IID_IUnknown, riid)) {
231 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
232 *ppv = PROTOCOL(This);
233 }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
234 TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
235 *ppv = PROTOCOL(This);
236 }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
237 TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
238 *ppv = PROTOCOL(This);
239 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
240 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
241 *ppv = BINDINFO(This);
242 }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
243 TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
244 *ppv = PRIORITY(This);
245 }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
246 FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
247 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
248 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
249 *ppv = SERVPROV(This);
250 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
251 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
252 *ppv = PROTSINK(This);
255 if(*ppv) {
256 IInternetProtocol_AddRef(iface);
257 return S_OK;
260 WARN("not supported interface %s\n", debugstr_guid(riid));
261 return E_NOINTERFACE;
264 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocol *iface)
266 BindProtocol *This = PROTOCOL_THIS(iface);
267 LONG ref = InterlockedIncrement(&This->ref);
268 TRACE("(%p) ref=%d\n", This, ref);
269 return ref;
272 static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
274 BindProtocol *This = PROTOCOL_THIS(iface);
275 LONG ref = InterlockedDecrement(&This->ref);
277 TRACE("(%p) ref=%d\n", This, ref);
279 if(!ref) {
280 if(This->wininet_info)
281 IWinInetInfo_Release(This->wininet_info);
282 if(This->protocol)
283 IInternetProtocol_Release(This->protocol);
284 if(This->bind_info)
285 IInternetBindInfo_Release(This->bind_info);
286 if(This->protocol_handler && This->protocol_handler != PROTOCOLHANDLER(This))
287 IInternetProtocol_Release(This->protocol_handler);
289 set_binding_sink(PROTOCOL(This), NULL);
291 if(This->notif_hwnd)
292 release_notif_hwnd(This->notif_hwnd);
293 DeleteCriticalSection(&This->section);
295 heap_free(This->mime);
296 heap_free(This->url);
297 heap_free(This);
299 URLMON_UnlockModule();
302 return ref;
305 static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
306 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
307 DWORD grfPI, HANDLE_PTR dwReserved)
309 BindProtocol *This = PROTOCOL_THIS(iface);
311 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
312 pOIBindInfo, grfPI, dwReserved);
314 return IInternetProtocol_Start(This->protocol_handler, szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
317 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
319 BindProtocol *This = PROTOCOL_THIS(iface);
321 TRACE("(%p)->(%p)\n", This, pProtocolData);
323 return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
326 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
327 DWORD dwOptions)
329 BindProtocol *This = PROTOCOL_THIS(iface);
330 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
331 return E_NOTIMPL;
334 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
336 BindProtocol *This = PROTOCOL_THIS(iface);
338 TRACE("(%p)->(%08x)\n", This, dwOptions);
340 return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
343 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface)
345 BindProtocol *This = PROTOCOL_THIS(iface);
346 FIXME("(%p)\n", This);
347 return E_NOTIMPL;
350 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface)
352 BindProtocol *This = PROTOCOL_THIS(iface);
353 FIXME("(%p)\n", This);
354 return E_NOTIMPL;
357 static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
358 ULONG cb, ULONG *pcbRead)
360 BindProtocol *This = PROTOCOL_THIS(iface);
362 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
364 if(pcbRead)
365 *pcbRead = 0;
366 return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
369 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
370 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
372 BindProtocol *This = PROTOCOL_THIS(iface);
373 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
374 return E_NOTIMPL;
377 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
379 BindProtocol *This = PROTOCOL_THIS(iface);
381 TRACE("(%p)->(%08x)\n", This, dwOptions);
383 return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
386 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
388 BindProtocol *This = PROTOCOL_THIS(iface);
390 TRACE("(%p)\n", This);
392 return IInternetProtocol_UnlockRequest(This->protocol_handler);
395 void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink)
397 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
398 IInternetProtocolSink *prev_sink;
399 IServiceProvider *service_provider = NULL;
401 if(sink)
402 IInternetProtocolSink_AddRef(sink);
403 prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
404 if(prev_sink)
405 IInternetProtocolSink_Release(prev_sink);
407 if(sink)
408 IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
409 service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
410 if(service_provider)
411 IServiceProvider_Release(service_provider);
414 IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol)
416 BindProtocol *This = PROTOCOL_THIS(bind_protocol);
418 return This->wininet_info;
421 #undef PROTOCOL_THIS
423 static const IInternetProtocolVtbl BindProtocolVtbl = {
424 BindProtocol_QueryInterface,
425 BindProtocol_AddRef,
426 BindProtocol_Release,
427 BindProtocol_Start,
428 BindProtocol_Continue,
429 BindProtocol_Abort,
430 BindProtocol_Terminate,
431 BindProtocol_Suspend,
432 BindProtocol_Resume,
433 BindProtocol_Read,
434 BindProtocol_Seek,
435 BindProtocol_LockRequest,
436 BindProtocol_UnlockRequest
439 #define PROTOCOLHANDLER_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolHandler, iface)
441 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
443 ERR("should not be called\n");
444 return E_NOINTERFACE;
447 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
449 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
450 return IInternetProtocol_AddRef(PROTOCOL(This));
453 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
455 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
456 return IInternetProtocol_Release(PROTOCOL(This));
459 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
460 IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
461 DWORD grfPI, HANDLE_PTR dwReserved)
463 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
464 IInternetProtocol *protocol = NULL;
465 IInternetPriority *priority;
466 IServiceProvider *service_provider;
467 BOOL urlmon_protocol = FALSE;
468 CLSID clsid = IID_NULL;
469 LPOLESTR clsid_str;
470 HRESULT hres;
472 TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
473 pOIBindInfo, grfPI, dwReserved);
475 if(!szUrl || !pOIProtSink || !pOIBindInfo)
476 return E_INVALIDARG;
478 This->pi = grfPI;
479 This->url = heap_strdupW(szUrl);
481 hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
482 (void**)&service_provider);
483 if(SUCCEEDED(hres)) {
484 /* FIXME: What's protocol CLSID here? */
485 IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
486 &IID_IInternetProtocol, (void**)&protocol);
487 IServiceProvider_Release(service_provider);
490 if(!protocol) {
491 IClassFactory *cf;
492 IUnknown *unk;
494 hres = get_protocol_handler(szUrl, &clsid, &urlmon_protocol, &cf);
495 if(FAILED(hres))
496 return hres;
498 if(This->from_urlmon) {
499 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
500 IClassFactory_Release(cf);
501 if(FAILED(hres))
502 return hres;
503 }else {
504 hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
505 &IID_IUnknown, (void**)&unk);
506 IClassFactory_Release(cf);
507 if(FAILED(hres))
508 return hres;
510 hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
511 IUnknown_Release(unk);
512 if(FAILED(hres))
513 return hres;
517 StringFromCLSID(&clsid, &clsid_str);
518 IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
519 CoTaskMemFree(clsid_str);
521 This->protocol = protocol;
523 if(urlmon_protocol)
524 IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
526 IInternetBindInfo_AddRef(pOIBindInfo);
527 This->bind_info = pOIBindInfo;
529 set_binding_sink(PROTOCOL(This), pOIProtSink);
531 hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
532 if(SUCCEEDED(hres)) {
533 IInternetPriority_SetPriority(priority, This->priority);
534 IInternetPriority_Release(priority);
537 return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0);
540 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
542 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
544 TRACE("(%p)->(%p)\n", This, pProtocolData);
546 return IInternetProtocol_Continue(This->protocol, pProtocolData);
549 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
550 DWORD dwOptions)
552 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
553 FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
554 return E_NOTIMPL;
557 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
559 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
561 TRACE("(%p)->(%08x)\n", This, dwOptions);
563 if(!This->reported_result)
564 return E_FAIL;
566 IInternetProtocol_Terminate(This->protocol, 0);
568 set_binding_sink(PROTOCOL(This), NULL);
570 if(This->bind_info) {
571 IInternetBindInfo_Release(This->bind_info);
572 This->bind_info = NULL;
575 return S_OK;
578 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
580 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
581 FIXME("(%p)\n", This);
582 return E_NOTIMPL;
585 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
587 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
588 FIXME("(%p)\n", This);
589 return E_NOTIMPL;
592 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
593 ULONG cb, ULONG *pcbRead)
595 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
596 ULONG read = 0;
597 HRESULT hres = S_OK;
599 TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
601 if(This->buf) {
602 read = min(cb, This->buf_size);
603 memcpy(pv, This->buf, read);
605 if(read == This->buf_size) {
606 heap_free(This->buf);
607 This->buf = NULL;
608 }else {
609 memmove(This->buf, This->buf+cb, This->buf_size-cb);
612 This->buf_size -= read;
615 if(read < cb) {
616 ULONG cread = 0;
618 hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
619 read += cread;
622 *pcbRead = read;
623 return hres;
626 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
627 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
629 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
630 FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
631 return E_NOTIMPL;
634 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
636 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
638 TRACE("(%p)->(%08x)\n", This, dwOptions);
640 return IInternetProtocol_LockRequest(This->protocol, dwOptions);
643 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
645 BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
647 TRACE("(%p)\n", This);
649 return IInternetProtocol_UnlockRequest(This->protocol);
652 #undef PROTOCOL_THIS
654 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
655 ProtocolHandler_QueryInterface,
656 ProtocolHandler_AddRef,
657 ProtocolHandler_Release,
658 ProtocolHandler_Start,
659 ProtocolHandler_Continue,
660 ProtocolHandler_Abort,
661 ProtocolHandler_Terminate,
662 ProtocolHandler_Suspend,
663 ProtocolHandler_Resume,
664 ProtocolHandler_Read,
665 ProtocolHandler_Seek,
666 ProtocolHandler_LockRequest,
667 ProtocolHandler_UnlockRequest
670 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
672 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
673 REFIID riid, void **ppv)
675 BindProtocol *This = BINDINFO_THIS(iface);
676 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
679 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
681 BindProtocol *This = BINDINFO_THIS(iface);
682 return IBinding_AddRef(PROTOCOL(This));
685 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
687 BindProtocol *This = BINDINFO_THIS(iface);
688 return IBinding_Release(PROTOCOL(This));
691 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
692 DWORD *grfBINDF, BINDINFO *pbindinfo)
694 BindProtocol *This = BINDINFO_THIS(iface);
695 HRESULT hres;
697 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
699 hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
700 if(FAILED(hres)) {
701 WARN("GetBindInfo failed: %08x\n", hres);
702 return hres;
705 *grfBINDF |= BINDF_FROMURLMON;
706 return hres;
709 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
710 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
712 BindProtocol *This = BINDINFO_THIS(iface);
714 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
716 return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
719 #undef BINDFO_THIS
721 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
722 BindInfo_QueryInterface,
723 BindInfo_AddRef,
724 BindInfo_Release,
725 BindInfo_GetBindInfo,
726 BindInfo_GetBindString
729 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
731 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
732 REFIID riid, void **ppv)
734 BindProtocol *This = PRIORITY_THIS(iface);
735 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
738 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
740 BindProtocol *This = PRIORITY_THIS(iface);
741 return IInternetProtocol_AddRef(PROTOCOL(This));
744 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
746 BindProtocol *This = PRIORITY_THIS(iface);
747 return IInternetProtocol_Release(PROTOCOL(This));
750 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
752 BindProtocol *This = PRIORITY_THIS(iface);
754 TRACE("(%p)->(%d)\n", This, nPriority);
756 This->priority = nPriority;
757 return S_OK;
760 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
762 BindProtocol *This = PRIORITY_THIS(iface);
764 TRACE("(%p)->(%p)\n", This, pnPriority);
766 *pnPriority = This->priority;
767 return S_OK;
770 #undef PRIORITY_THIS
772 static const IInternetPriorityVtbl InternetPriorityVtbl = {
773 InternetPriority_QueryInterface,
774 InternetPriority_AddRef,
775 InternetPriority_Release,
776 InternetPriority_SetPriority,
777 InternetPriority_GetPriority
781 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocolSink, iface)
783 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
784 REFIID riid, void **ppv)
786 BindProtocol *This = PROTSINK_THIS(iface);
787 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
790 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
792 BindProtocol *This = PROTSINK_THIS(iface);
793 return IInternetProtocol_AddRef(PROTOCOL(This));
796 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
798 BindProtocol *This = PROTSINK_THIS(iface);
799 return IInternetProtocol_Release(PROTOCOL(This));
802 typedef struct {
803 task_header_t header;
804 PROTOCOLDATA data;
805 } switch_task_t;
807 static void switch_proc(BindProtocol *bind, task_header_t *t)
809 switch_task_t *task = (switch_task_t*)t;
811 IInternetProtocol_Continue(bind->protocol, &task->data);
813 heap_free(task);
816 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
817 PROTOCOLDATA *pProtocolData)
819 BindProtocol *This = PROTSINK_THIS(iface);
821 TRACE("(%p)->(%p)\n", This, pProtocolData);
823 TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
824 pProtocolData->pData, pProtocolData->cbData);
826 if(!do_direct_notif(This)) {
827 switch_task_t *task;
829 task = heap_alloc(sizeof(switch_task_t));
830 if(!task)
831 return E_OUTOFMEMORY;
833 task->data = *pProtocolData;
835 push_task(This, &task->header, switch_proc);
836 return S_OK;
839 if(!This->protocol_sink) {
840 IInternetProtocol_Continue(This->protocol, pProtocolData);
841 return S_OK;
844 return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
847 static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
849 switch(status_code) {
850 case BINDSTATUS_FINDINGRESOURCE:
851 case BINDSTATUS_CONNECTING:
852 case BINDSTATUS_BEGINDOWNLOADDATA:
853 case BINDSTATUS_SENDINGREQUEST:
854 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
855 case BINDSTATUS_DIRECTBIND:
856 case BINDSTATUS_ACCEPTRANGES:
857 if(This->protocol_sink)
858 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
859 break;
861 case BINDSTATUS_MIMETYPEAVAILABLE:
862 if(!This->reported_mime) {
863 heap_free(This->mime);
864 This->mime = heap_strdupW(status_text);
867 if(This->protocol_sink && !(This->pi & PI_MIMEVERIFICATION))
868 IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
869 break;
871 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
872 if(!This->reported_mime) {
873 heap_free(This->mime);
874 This->mime = heap_strdupW(status_text);
877 if(This->protocol_sink) {
878 This->reported_mime = TRUE;
879 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, status_text);
881 break;
883 default:
884 FIXME("unsupported ulStatusCode %u\n", status_code);
888 typedef struct {
889 task_header_t header;
891 ULONG status_code;
892 LPWSTR status_text;
893 } on_progress_task_t;
895 static void on_progress_proc(BindProtocol *This, task_header_t *t)
897 on_progress_task_t *task = (on_progress_task_t*)t;
899 report_progress(This, task->status_code, task->status_text);
901 heap_free(task->status_text);
902 heap_free(task);
905 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
906 ULONG ulStatusCode, LPCWSTR szStatusText)
908 BindProtocol *This = PROTSINK_THIS(iface);
910 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
912 if(do_direct_notif(This)) {
913 report_progress(This, ulStatusCode, szStatusText);
914 }else {
915 on_progress_task_t *task;
917 task = heap_alloc(sizeof(on_progress_task_t));
919 task->status_code = ulStatusCode;
920 task->status_text = heap_strdupW(szStatusText);
922 push_task(This, &task->header, on_progress_proc);
925 return S_OK;
928 static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max)
930 if(!This->protocol_sink)
931 return S_OK;
933 if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
934 DWORD read = 0;
935 LPWSTR mime;
936 HRESULT hres;
938 if(!This->buf) {
939 This->buf = heap_alloc(BUFFER_SIZE);
940 if(!This->buf)
941 return E_OUTOFMEMORY;
944 do {
945 read = 0;
946 hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size, BUFFER_SIZE-This->buf_size, &read);
947 if(hres != S_OK)
948 break;
949 This->buf_size += read;
950 }while(This->buf_size < MIME_TEST_SIZE);
951 if(FAILED(hres) && hres != E_PENDING)
952 return hres;
954 This->buf_size += read;
955 if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
956 return S_OK;
959 hres = FindMimeFromData(NULL, This->url, This->buf, min(This->buf_size, MIME_TEST_SIZE), This->mime, 0, &mime, 0);
960 if(FAILED(hres))
961 return hres;
963 heap_free(This->mime);
964 This->mime = heap_strdupW(mime);
965 CoTaskMemFree(mime);
967 This->reported_mime = TRUE;
968 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
971 return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
974 typedef struct {
975 task_header_t header;
976 DWORD bscf;
977 ULONG progress;
978 ULONG progress_max;
979 } report_data_task_t;
981 static void report_data_proc(BindProtocol *This, task_header_t *t)
983 report_data_task_t *task = (report_data_task_t*)t;
985 report_data(This, task->bscf, task->progress, task->progress_max);
986 heap_free(task);
989 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
990 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
992 BindProtocol *This = PROTSINK_THIS(iface);
994 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
996 if(!This->protocol_sink)
997 return S_OK;
999 if(!do_direct_notif(This)) {
1000 report_data_task_t *task;
1002 task = heap_alloc(sizeof(report_data_task_t));
1003 if(!task)
1004 return E_OUTOFMEMORY;
1006 task->bscf = grfBSCF;
1007 task->progress = ulProgress;
1008 task->progress_max = ulProgressMax;
1010 push_task(This, &task->header, report_data_proc);
1011 return S_OK;
1014 return report_data(This, grfBSCF, ulProgress, ulProgressMax);
1017 typedef struct {
1018 task_header_t header;
1020 HRESULT hres;
1021 DWORD err;
1022 LPWSTR str;
1023 } report_result_task_t;
1025 static void report_result_proc(BindProtocol *This, task_header_t *t)
1027 report_result_task_t *task = (report_result_task_t*)t;
1029 if(This->protocol_sink)
1030 IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str);
1032 heap_free(task->str);
1033 heap_free(task);
1036 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1037 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1039 BindProtocol *This = PROTSINK_THIS(iface);
1041 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1043 if(!This->protocol_sink)
1044 return E_FAIL;
1046 This->reported_result = TRUE;
1048 if(!do_direct_notif(This)) {
1049 report_result_task_t *task;
1051 task = heap_alloc(sizeof(report_result_task_t));
1052 if(!task)
1053 return E_OUTOFMEMORY;
1055 task->hres = hrResult;
1056 task->err = dwError;
1057 task->str = heap_strdupW(szResult);
1059 push_task(This, &task->header, report_result_proc);
1060 return S_OK;
1063 return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1066 #undef PROTSINK_THIS
1068 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1069 BPInternetProtocolSink_QueryInterface,
1070 BPInternetProtocolSink_AddRef,
1071 BPInternetProtocolSink_Release,
1072 BPInternetProtocolSink_Switch,
1073 BPInternetProtocolSink_ReportProgress,
1074 BPInternetProtocolSink_ReportData,
1075 BPInternetProtocolSink_ReportResult
1078 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
1080 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1081 REFIID riid, void **ppv)
1083 BindProtocol *This = SERVPROV_THIS(iface);
1084 return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
1087 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1089 BindProtocol *This = SERVPROV_THIS(iface);
1090 return IInternetProtocol_AddRef(PROTOCOL(This));
1093 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1095 BindProtocol *This = SERVPROV_THIS(iface);
1096 return IInternetProtocol_Release(PROTOCOL(This));
1099 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1100 REFGUID guidService, REFIID riid, void **ppv)
1102 BindProtocol *This = SERVPROV_THIS(iface);
1104 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1106 if(!This->service_provider)
1107 return E_NOINTERFACE;
1109 return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1112 #undef SERVPROV_THIS
1114 static const IServiceProviderVtbl ServiceProviderVtbl = {
1115 BPServiceProvider_QueryInterface,
1116 BPServiceProvider_AddRef,
1117 BPServiceProvider_Release,
1118 BPServiceProvider_QueryService
1121 HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol)
1123 BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1125 ret->lpInternetProtocolVtbl = &BindProtocolVtbl;
1126 ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
1127 ret->lpInternetPriorityVtbl = &InternetPriorityVtbl;
1128 ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
1129 ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1130 ret->lpIInternetProtocolHandlerVtbl = &InternetProtocolHandlerVtbl;
1132 ret->ref = 1;
1133 ret->from_urlmon = from_urlmon;
1134 ret->apartment_thread = GetCurrentThreadId();
1135 ret->notif_hwnd = get_notif_hwnd();
1136 ret->protocol_handler = PROTOCOLHANDLER(ret);
1137 InitializeCriticalSection(&ret->section);
1139 URLMON_LockModule();
1141 *protocol = PROTOCOL(ret);
1142 return S_OK;