urlmon: Report BINDSTATUS_DOWNLOADINGDATA on BSCF_INTERMEDIATEDATANOTIFICATION.
[wine/wine-kai.git] / dlls / urlmon / binding.c
blobb4541d3e32c5c70e3b3dcb7c533bb06ab1d4bb59
1 /*
2 * Copyright 2005-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 <stdarg.h>
21 #define COBJMACROS
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
29 #include "urlmon.h"
30 #include "urlmon_main.h"
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
37 typedef struct Binding Binding;
39 struct _task_header_t;
41 typedef void (*task_proc_t)(Binding*, struct _task_header_t*);
43 typedef struct _task_header_t {
44 task_proc_t proc;
45 struct _task_header_t *next;
46 } task_header_t;
48 typedef struct {
49 const IHttpNegotiate2Vtbl *lpHttpNegotiate2Vtbl;
51 LONG ref;
53 IHttpNegotiate *http_negotiate;
54 IHttpNegotiate2 *http_negotiate2;
55 } HttpNegotiate2Wrapper;
57 typedef struct {
58 const IStreamVtbl *lpStreamVtbl;
60 LONG ref;
62 IInternetProtocol *protocol;
64 BYTE buf[1024*8];
65 DWORD buf_size;
66 BOOL init_buf;
67 HRESULT hres;
68 } ProtocolStream;
70 struct Binding {
71 const IBindingVtbl *lpBindingVtbl;
72 const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl;
73 const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
74 const IServiceProviderVtbl *lpServiceProviderVtbl;
76 LONG ref;
78 IBindStatusCallback *callback;
79 IInternetProtocol *protocol;
80 IServiceProvider *service_provider;
81 ProtocolStream *stream;
82 HttpNegotiate2Wrapper *httpneg2_wrapper;
84 BINDINFO bindinfo;
85 DWORD bindf;
86 LPWSTR mime;
87 LPWSTR url;
88 BOOL report_mime;
89 DWORD continue_call;
90 BOOL request_locked;
92 DWORD apartment_thread;
93 HWND notif_hwnd;
95 STGMEDIUM stgmed;
97 task_header_t *task_queue_head, *task_queue_tail;
98 CRITICAL_SECTION section;
101 #define BINDING(x) ((IBinding*) &(x)->lpBindingVtbl)
102 #define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
103 #define BINDINF(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
104 #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl)
106 #define STREAM(x) ((IStream*) &(x)->lpStreamVtbl)
107 #define HTTPNEG2(x) ((IHttpNegotiate2*) &(x)->lpHttpNegotiate2Vtbl)
109 #define WM_MK_CONTINUE (WM_USER+101)
111 static void push_task(Binding *binding, task_header_t *task, task_proc_t proc)
113 task->proc = proc;
114 task->next = NULL;
116 EnterCriticalSection(&binding->section);
118 if(binding->task_queue_tail) {
119 binding->task_queue_tail->next = task;
120 binding->task_queue_tail = task;
121 }else {
122 binding->task_queue_tail = binding->task_queue_head = task;
125 LeaveCriticalSection(&binding->section);
128 static task_header_t *pop_task(Binding *binding)
130 task_header_t *ret;
132 EnterCriticalSection(&binding->section);
134 ret = binding->task_queue_head;
135 if(ret) {
136 binding->task_queue_head = ret->next;
137 if(!binding->task_queue_head)
138 binding->task_queue_tail = NULL;
141 LeaveCriticalSection(&binding->section);
143 return ret;
146 static void fill_stream_buffer(ProtocolStream *This)
148 DWORD read = 0;
150 if(sizeof(This->buf) == This->buf_size)
151 return;
153 This->hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size,
154 sizeof(This->buf)-This->buf_size, &read);
155 This->buf_size += read;
156 if(read > 0)
157 This->init_buf = TRUE;
160 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
162 if(msg == WM_MK_CONTINUE) {
163 Binding *binding = (Binding*)lParam;
164 task_header_t *task;
166 while((task = pop_task(binding))) {
167 binding->continue_call++;
168 task->proc(binding, task);
169 binding->continue_call--;
172 IBinding_Release(BINDING(binding));
173 return 0;
176 return DefWindowProcW(hwnd, msg, wParam, lParam);
179 static HWND get_notif_hwnd(void)
181 static ATOM wnd_class = 0;
182 HWND hwnd;
184 static const WCHAR wszURLMonikerNotificationWindow[] =
185 {'U','R','L',' ','M','o','n','i','k','e','r',' ',
186 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
188 if(!wnd_class) {
189 static WNDCLASSEXW wndclass = {
190 sizeof(wndclass), 0,
191 notif_wnd_proc, 0, 0,
192 NULL, NULL, NULL, NULL, NULL,
193 wszURLMonikerNotificationWindow,
194 NULL
197 wndclass.hInstance = URLMON_hInstance;
199 wnd_class = RegisterClassExW(&wndclass);
200 if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
201 wnd_class = 1;
204 hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
205 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
206 NULL, URLMON_hInstance, NULL);
208 TRACE("hwnd = %p\n", hwnd);
210 return hwnd;
213 static void dump_BINDINFO(BINDINFO *bi)
215 static const char * const BINDINFOF_str[] = {
216 "#0",
217 "BINDINFOF_URLENCODESTGMEDDATA",
218 "BINDINFOF_URLENCODEDEXTRAINFO"
221 static const char * const BINDVERB_str[] = {
222 "BINDVERB_GET",
223 "BINDVERB_POST",
224 "BINDVERB_PUT",
225 "BINDVERB_CUSTOM"
228 TRACE("\n"
229 "BINDINFO = {\n"
230 " %d, %s,\n"
231 " {%d, %p, %p},\n"
232 " %s,\n"
233 " %s,\n"
234 " %s,\n"
235 " %d, %08x, %d, %d\n"
236 " {%d %p %x},\n"
237 " %s\n"
238 " %p, %d\n"
239 "}\n",
241 bi->cbSize, debugstr_w(bi->szExtraInfo),
242 bi->stgmedData.tymed, bi->stgmedData.u.hGlobal, bi->stgmedData.pUnkForRelease,
243 bi->grfBindInfoF > BINDINFOF_URLENCODEDEXTRAINFO
244 ? "unknown" : BINDINFOF_str[bi->grfBindInfoF],
245 bi->dwBindVerb > BINDVERB_CUSTOM
246 ? "unknown" : BINDVERB_str[bi->dwBindVerb],
247 debugstr_w(bi->szCustomVerb),
248 bi->cbstgmedData, bi->dwOptions, bi->dwOptionsFlags, bi->dwCodePage,
249 bi->securityAttributes.nLength,
250 bi->securityAttributes.lpSecurityDescriptor,
251 bi->securityAttributes.bInheritHandle,
252 debugstr_guid(&bi->iid),
253 bi->pUnk, bi->dwReserved
257 #define HTTPNEG2_THIS(iface) DEFINE_THIS(HttpNegotiate2Wrapper, HttpNegotiate2, iface)
259 static HRESULT WINAPI HttpNegotiate2Wrapper_QueryInterface(IHttpNegotiate2 *iface,
260 REFIID riid, void **ppv)
262 HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
264 *ppv = NULL;
266 if(IsEqualGUID(&IID_IUnknown, riid)) {
267 TRACE("(IID_IUnknown %p)\n", ppv);
268 *ppv = HTTPNEG2(This);
269 }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
270 TRACE("(IID_IHttpNegotiate %p)\n", ppv);
271 *ppv = HTTPNEG2(This);
272 }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
273 TRACE("(IID_IHttpNegotiate2 %p)\n", ppv);
274 *ppv = HTTPNEG2(This);
277 if(*ppv) {
278 IHttpNegotiate2_AddRef(HTTPNEG2(This));
279 return S_OK;
282 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
283 return E_NOINTERFACE;
286 static ULONG WINAPI HttpNegotiate2Wrapper_AddRef(IHttpNegotiate2 *iface)
288 HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
289 LONG ref = InterlockedIncrement(&This->ref);
291 TRACE("(%p) ref=%d\n", This, ref);
293 return ref;
296 static ULONG WINAPI HttpNegotiate2Wrapper_Release(IHttpNegotiate2 *iface)
298 HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
299 LONG ref = InterlockedDecrement(&This->ref);
301 TRACE("(%p) ref=%d\n", This, ref);
303 if(!ref) {
304 if (This->http_negotiate)
305 IHttpNegotiate_Release(This->http_negotiate);
306 if (This->http_negotiate2)
307 IHttpNegotiate2_Release(This->http_negotiate2);
308 HeapFree(GetProcessHeap(), 0, This);
310 URLMON_UnlockModule();
313 return ref;
316 static HRESULT WINAPI HttpNegotiate2Wrapper_BeginningTransaction(IHttpNegotiate2 *iface,
317 LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
319 HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
321 TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders), dwReserved,
322 pszAdditionalHeaders);
324 if(This->http_negotiate)
325 return IHttpNegotiate_BeginningTransaction(This->http_negotiate, szURL, szHeaders,
326 dwReserved, pszAdditionalHeaders);
328 *pszAdditionalHeaders = NULL;
329 return S_OK;
332 static HRESULT WINAPI HttpNegotiate2Wrapper_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
333 LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders,
334 LPWSTR *pszAdditionalRequestHeaders)
336 HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
337 LPWSTR szAdditionalRequestHeaders = NULL;
338 HRESULT hres = S_OK;
340 TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
341 debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
343 /* IHttpNegotiate2_OnResponse expects pszAdditionalHeaders to be non-NULL when it is
344 * implemented as part of IBindStatusCallback, but it is NULL when called directly from
345 * IProtocol */
346 if(!pszAdditionalRequestHeaders)
347 pszAdditionalRequestHeaders = &szAdditionalRequestHeaders;
349 if(This->http_negotiate)
351 hres = IHttpNegotiate_OnResponse(This->http_negotiate, dwResponseCode, szResponseHeaders,
352 szRequestHeaders, pszAdditionalRequestHeaders);
353 if(pszAdditionalRequestHeaders == &szAdditionalRequestHeaders &&
354 szAdditionalRequestHeaders)
355 CoTaskMemFree(szAdditionalRequestHeaders);
357 else
359 *pszAdditionalRequestHeaders = NULL;
362 return hres;
365 static HRESULT WINAPI HttpNegotiate2Wrapper_GetRootSecurityId(IHttpNegotiate2 *iface,
366 BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
368 HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
370 TRACE("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved);
372 if (This->http_negotiate2)
373 return IHttpNegotiate2_GetRootSecurityId(This->http_negotiate2, pbSecurityId,
374 pcbSecurityId, dwReserved);
376 /* That's all we have to do here */
377 return E_FAIL;
380 #undef HTTPNEG2_THIS
382 static const IHttpNegotiate2Vtbl HttpNegotiate2WrapperVtbl = {
383 HttpNegotiate2Wrapper_QueryInterface,
384 HttpNegotiate2Wrapper_AddRef,
385 HttpNegotiate2Wrapper_Release,
386 HttpNegotiate2Wrapper_BeginningTransaction,
387 HttpNegotiate2Wrapper_OnResponse,
388 HttpNegotiate2Wrapper_GetRootSecurityId
391 static HttpNegotiate2Wrapper *create_httpneg2_wrapper(void)
393 HttpNegotiate2Wrapper *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(HttpNegotiate2Wrapper));
395 ret->lpHttpNegotiate2Vtbl = &HttpNegotiate2WrapperVtbl;
396 ret->ref = 1;
397 ret->http_negotiate = NULL;
398 ret->http_negotiate2 = NULL;
400 URLMON_LockModule();
402 return ret;
405 #define STREAM_THIS(iface) DEFINE_THIS(ProtocolStream, Stream, iface)
407 static HRESULT WINAPI ProtocolStream_QueryInterface(IStream *iface,
408 REFIID riid, void **ppv)
410 ProtocolStream *This = STREAM_THIS(iface);
412 *ppv = NULL;
414 if(IsEqualGUID(&IID_IUnknown, riid)) {
415 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
416 *ppv = STREAM(This);
417 }else if(IsEqualGUID(&IID_ISequentialStream, riid)) {
418 TRACE("(%p)->(IID_ISequentialStream %p)\n", This, ppv);
419 *ppv = STREAM(This);
420 }else if(IsEqualGUID(&IID_IStream, riid)) {
421 TRACE("(%p)->(IID_IStream %p)\n", This, ppv);
422 *ppv = STREAM(This);
425 if(*ppv) {
426 IStream_AddRef(STREAM(This));
427 return S_OK;
430 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
431 return E_NOINTERFACE;
434 static ULONG WINAPI ProtocolStream_AddRef(IStream *iface)
436 ProtocolStream *This = STREAM_THIS(iface);
437 LONG ref = InterlockedIncrement(&This->ref);
439 TRACE("(%p) ref=%d\n", This, ref);
441 return ref;
444 static ULONG WINAPI ProtocolStream_Release(IStream *iface)
446 ProtocolStream *This = STREAM_THIS(iface);
447 LONG ref = InterlockedDecrement(&This->ref);
449 TRACE("(%p) ref=%d\n", This, ref);
451 if(!ref) {
452 IInternetProtocol_Release(This->protocol);
453 HeapFree(GetProcessHeap(), 0, This);
455 URLMON_UnlockModule();
458 return ref;
461 static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv,
462 ULONG cb, ULONG *pcbRead)
464 ProtocolStream *This = STREAM_THIS(iface);
465 DWORD read = 0, pread = 0;
467 TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbRead);
469 if(This->buf_size) {
470 read = cb;
472 if(read > This->buf_size)
473 read = This->buf_size;
475 memcpy(pv, This->buf, read);
477 if(read < This->buf_size)
478 memmove(This->buf, This->buf+read, This->buf_size-read);
479 This->buf_size -= read;
482 if(read == cb) {
483 *pcbRead = read;
484 return S_OK;
487 This->hres = IInternetProtocol_Read(This->protocol, (PBYTE)pv+read, cb-read, &pread);
488 *pcbRead = read + pread;
490 if(This->hres == E_PENDING)
491 return E_PENDING;
492 else if(FAILED(This->hres))
493 FIXME("Read failed: %08x\n", This->hres);
495 return read || pread ? S_OK : S_FALSE;
498 static HRESULT WINAPI ProtocolStream_Write(IStream *iface, const void *pv,
499 ULONG cb, ULONG *pcbWritten)
501 ProtocolStream *This = STREAM_THIS(iface);
503 TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbWritten);
505 return STG_E_ACCESSDENIED;
508 static HRESULT WINAPI ProtocolStream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
509 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
511 ProtocolStream *This = STREAM_THIS(iface);
512 FIXME("(%p)->(%d %08x %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
513 return E_NOTIMPL;
516 static HRESULT WINAPI ProtocolStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
518 ProtocolStream *This = STREAM_THIS(iface);
519 FIXME("(%p)->(%d)\n", This, libNewSize.u.LowPart);
520 return E_NOTIMPL;
523 static HRESULT WINAPI ProtocolStream_CopyTo(IStream *iface, IStream *pstm,
524 ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
526 ProtocolStream *This = STREAM_THIS(iface);
527 FIXME("(%p)->(%p %d %p %p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten);
528 return E_NOTIMPL;
531 static HRESULT WINAPI ProtocolStream_Commit(IStream *iface, DWORD grfCommitFlags)
533 ProtocolStream *This = STREAM_THIS(iface);
535 TRACE("(%p)->(%08x)\n", This, grfCommitFlags);
537 return E_NOTIMPL;
540 static HRESULT WINAPI ProtocolStream_Revert(IStream *iface)
542 ProtocolStream *This = STREAM_THIS(iface);
544 TRACE("(%p)\n", This);
546 return E_NOTIMPL;
549 static HRESULT WINAPI ProtocolStream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
550 ULARGE_INTEGER cb, DWORD dwLockType)
552 ProtocolStream *This = STREAM_THIS(iface);
553 FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
554 return E_NOTIMPL;
557 static HRESULT WINAPI ProtocolStream_UnlockRegion(IStream *iface,
558 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
560 ProtocolStream *This = STREAM_THIS(iface);
561 FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
562 return E_NOTIMPL;
565 static HRESULT WINAPI ProtocolStream_Stat(IStream *iface, STATSTG *pstatstg,
566 DWORD dwStatFlag)
568 ProtocolStream *This = STREAM_THIS(iface);
569 FIXME("(%p)->(%p %08x)\n", This, pstatstg, dwStatFlag);
570 return E_NOTIMPL;
573 static HRESULT WINAPI ProtocolStream_Clone(IStream *iface, IStream **ppstm)
575 ProtocolStream *This = STREAM_THIS(iface);
576 FIXME("(%p)->(%p)\n", This, ppstm);
577 return E_NOTIMPL;
580 #undef STREAM_THIS
582 static const IStreamVtbl ProtocolStreamVtbl = {
583 ProtocolStream_QueryInterface,
584 ProtocolStream_AddRef,
585 ProtocolStream_Release,
586 ProtocolStream_Read,
587 ProtocolStream_Write,
588 ProtocolStream_Seek,
589 ProtocolStream_SetSize,
590 ProtocolStream_CopyTo,
591 ProtocolStream_Commit,
592 ProtocolStream_Revert,
593 ProtocolStream_LockRegion,
594 ProtocolStream_UnlockRegion,
595 ProtocolStream_Stat,
596 ProtocolStream_Clone
599 #define BINDING_THIS(iface) DEFINE_THIS(Binding, Binding, iface)
601 static ProtocolStream *create_stream(IInternetProtocol *protocol)
603 ProtocolStream *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ProtocolStream));
605 ret->lpStreamVtbl = &ProtocolStreamVtbl;
606 ret->ref = 1;
607 ret->buf_size = 0;
608 ret->init_buf = FALSE;
609 ret->hres = S_OK;
611 IInternetProtocol_AddRef(protocol);
612 ret->protocol = protocol;
614 URLMON_LockModule();
616 return ret;
619 static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv)
621 Binding *This = BINDING_THIS(iface);
623 *ppv = NULL;
625 if(IsEqualGUID(&IID_IUnknown, riid)) {
626 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
627 *ppv = BINDING(This);
628 }else if(IsEqualGUID(&IID_IBinding, riid)) {
629 TRACE("(%p)->(IID_IBinding %p)\n", This, ppv);
630 *ppv = BINDING(This);
631 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
632 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
633 *ppv = PROTSINK(This);
634 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
635 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
636 *ppv = BINDINF(This);
637 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
638 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
639 *ppv = SERVPROV(This);
642 if(*ppv) {
643 IBinding_AddRef(BINDING(This));
644 return S_OK;
647 WARN("Unsupported interface %s\n", debugstr_guid(riid));
648 return E_NOINTERFACE;
651 static ULONG WINAPI Binding_AddRef(IBinding *iface)
653 Binding *This = BINDING_THIS(iface);
654 LONG ref = InterlockedIncrement(&This->ref);
656 TRACE("(%p) ref=%d\n", This, ref);
658 return ref;
661 static ULONG WINAPI Binding_Release(IBinding *iface)
663 Binding *This = BINDING_THIS(iface);
664 LONG ref = InterlockedDecrement(&This->ref);
666 TRACE("(%p) ref=%d\n", This, ref);
668 if(!ref) {
669 if (This->notif_hwnd)
670 DestroyWindow( This->notif_hwnd );
671 if(This->callback)
672 IBindStatusCallback_Release(This->callback);
673 if(This->protocol)
674 IInternetProtocol_Release(This->protocol);
675 if(This->service_provider)
676 IServiceProvider_Release(This->service_provider);
677 if(This->stream)
678 IStream_Release(STREAM(This->stream));
679 if(This->httpneg2_wrapper)
680 IHttpNegotiate2_Release(HTTPNEG2(This->httpneg2_wrapper));
682 ReleaseBindInfo(&This->bindinfo);
683 This->section.DebugInfo->Spare[0] = 0;
684 DeleteCriticalSection(&This->section);
685 HeapFree(GetProcessHeap(), 0, This->mime);
686 HeapFree(GetProcessHeap(), 0, This->url);
688 HeapFree(GetProcessHeap(), 0, This);
690 URLMON_UnlockModule();
693 return ref;
696 static HRESULT WINAPI Binding_Abort(IBinding *iface)
698 Binding *This = BINDING_THIS(iface);
699 FIXME("(%p)\n", This);
700 return E_NOTIMPL;
703 static HRESULT WINAPI Binding_Suspend(IBinding *iface)
705 Binding *This = BINDING_THIS(iface);
706 FIXME("(%p)\n", This);
707 return E_NOTIMPL;
710 static HRESULT WINAPI Binding_Resume(IBinding *iface)
712 Binding *This = BINDING_THIS(iface);
713 FIXME("(%p)\n", This);
714 return E_NOTIMPL;
717 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority)
719 Binding *This = BINDING_THIS(iface);
720 FIXME("(%p)->(%d)\n", This, nPriority);
721 return E_NOTIMPL;
724 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority)
726 Binding *This = BINDING_THIS(iface);
727 FIXME("(%p)->(%p)\n", This, pnPriority);
728 return E_NOTIMPL;
731 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol,
732 DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved)
734 Binding *This = BINDING_THIS(iface);
735 FIXME("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
736 return E_NOTIMPL;
739 #undef BINDING_THIS
741 static const IBindingVtbl BindingVtbl = {
742 Binding_QueryInterface,
743 Binding_AddRef,
744 Binding_Release,
745 Binding_Abort,
746 Binding_Suspend,
747 Binding_Resume,
748 Binding_SetPriority,
749 Binding_GetPriority,
750 Binding_GetBindResult
753 #define PROTSINK_THIS(iface) DEFINE_THIS(Binding, InternetProtocolSink, iface)
755 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
756 REFIID riid, void **ppv)
758 Binding *This = PROTSINK_THIS(iface);
759 return IBinding_QueryInterface(BINDING(This), riid, ppv);
762 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
764 Binding *This = PROTSINK_THIS(iface);
765 return IBinding_AddRef(BINDING(This));
768 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
770 Binding *This = PROTSINK_THIS(iface);
771 return IBinding_Release(BINDING(This));
774 typedef struct {
775 task_header_t header;
776 PROTOCOLDATA *data;
777 } switch_task_t;
779 static void switch_proc(Binding *binding, task_header_t *t)
781 switch_task_t *task = (switch_task_t*)t;
783 IInternetProtocol_Continue(binding->protocol, task->data);
785 HeapFree(GetProcessHeap(), 0, task);
788 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
789 PROTOCOLDATA *pProtocolData)
791 Binding *This = PROTSINK_THIS(iface);
792 switch_task_t *task;
794 TRACE("(%p)->(%p)\n", This, pProtocolData);
796 task = HeapAlloc(GetProcessHeap(), 0, sizeof(switch_task_t));
797 task->data = pProtocolData;
799 push_task(This, &task->header, switch_proc);
801 IBinding_AddRef(BINDING(This));
802 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
804 return S_OK;
807 typedef struct {
808 task_header_t header;
810 Binding *binding;
811 ULONG progress;
812 ULONG progress_max;
813 ULONG status_code;
814 LPWSTR status_text;
815 } on_progress_task_t;
817 static void on_progress_proc(Binding *binding, task_header_t *t)
819 on_progress_task_t *task = (on_progress_task_t*)t;
821 IBindStatusCallback_OnProgress(binding->callback, task->progress,
822 task->progress_max, task->status_code, task->status_text);
824 HeapFree(GetProcessHeap(), 0, task->status_text);
825 HeapFree(GetProcessHeap(), 0, task);
828 static void on_progress(Binding *This, ULONG progress, ULONG progress_max,
829 ULONG status_code, LPCWSTR status_text)
831 on_progress_task_t *task;
833 if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
834 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
835 status_code, status_text);
836 return;
839 task = HeapAlloc(GetProcessHeap(), 0, sizeof(on_progress_task_t));
841 task->progress = progress;
842 task->progress_max = progress_max;
843 task->status_code = status_code;
845 if(status_text) {
846 DWORD size = (strlenW(status_text)+1)*sizeof(WCHAR);
848 task->status_text = HeapAlloc(GetProcessHeap(), 0, size);
849 memcpy(task->status_text, status_text, size);
850 }else {
851 task->status_text = NULL;
854 push_task(This, &task->header, on_progress_proc);
856 if(GetCurrentThreadId() != This->apartment_thread) {
857 IBinding_AddRef(BINDING(This));
858 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
862 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
863 ULONG ulStatusCode, LPCWSTR szStatusText)
865 Binding *This = PROTSINK_THIS(iface);
867 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
869 switch(ulStatusCode) {
870 case BINDSTATUS_FINDINGRESOURCE:
871 on_progress(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, szStatusText);
872 break;
873 case BINDSTATUS_CONNECTING:
874 on_progress(This, 0, 0, BINDSTATUS_CONNECTING, szStatusText);
875 break;
876 case BINDSTATUS_BEGINDOWNLOADDATA:
877 fill_stream_buffer(This->stream);
878 break;
879 case BINDSTATUS_MIMETYPEAVAILABLE: {
880 int len = strlenW(szStatusText)+1;
881 This->mime = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
882 memcpy(This->mime, szStatusText, len*sizeof(WCHAR));
883 break;
885 case BINDSTATUS_SENDINGREQUEST:
886 on_progress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, szStatusText);
887 break;
888 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
889 This->report_mime = FALSE;
890 on_progress(This, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE, szStatusText);
891 break;
892 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
893 break;
894 case BINDSTATUS_DIRECTBIND:
895 This->report_mime = FALSE;
896 break;
897 default:
898 FIXME("Unhandled status code %d\n", ulStatusCode);
899 return E_NOTIMPL;
902 return S_OK;
905 static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progress_max)
907 FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM};
908 BOOL end_download = FALSE;
910 TRACE("(%p)->(%d %u %u)\n", This, bscf, progress, progress_max);
912 if(GetCurrentThreadId() != This->apartment_thread)
913 FIXME("called from worked hread\n");
915 if(This->report_mime) {
916 LPWSTR mime;
918 This->report_mime = FALSE;
920 fill_stream_buffer(This->stream);
922 FindMimeFromData(NULL, This->url, This->stream->buf,
923 min(This->stream->buf_size, 255), This->mime, 0, &mime, 0);
925 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
926 BINDSTATUS_MIMETYPEAVAILABLE, mime);
929 if(bscf & BSCF_FIRSTDATANOTIFICATION) {
930 fill_stream_buffer(This->stream);
932 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
933 BINDSTATUS_BEGINDOWNLOADDATA, This->url);
936 if((bscf & BSCF_LASTDATANOTIFICATION) ||
937 (bscf & BSCF_DATAFULLYAVAILABLE) ||
938 progress == progress_max) {
939 end_download = TRUE;
940 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
941 BINDSTATUS_ENDDOWNLOADDATA, This->url);
942 } else if(bscf & BSCF_INTERMEDIATEDATANOTIFICATION) {
943 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
944 BINDSTATUS_DOWNLOADINGDATA, This->url);
947 if(!This->request_locked) {
948 HRESULT hres = IInternetProtocol_LockRequest(This->protocol, 0);
949 This->request_locked = SUCCEEDED(hres);
952 fill_stream_buffer(This->stream);
954 IBindStatusCallback_OnDataAvailable(This->callback, bscf, This->stream->buf_size,
955 &formatetc, &This->stgmed);
957 if(end_download) {
958 IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL);
962 typedef struct {
963 task_header_t header;
964 DWORD bscf;
965 ULONG progress;
966 ULONG progress_max;
967 } report_data_task_t;
969 static void report_data_proc(Binding *binding, task_header_t *t)
971 report_data_task_t *task = (report_data_task_t*)t;
973 report_data(binding, task->bscf, task->progress, task->progress_max);
975 HeapFree(GetProcessHeap(), 0, task);
978 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
979 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
981 Binding *This = PROTSINK_THIS(iface);
983 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
985 if(GetCurrentThreadId() != This->apartment_thread)
986 FIXME("called from worked hread\n");
988 if(This->continue_call) {
989 report_data_task_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(report_data_task_t));
990 task->bscf = grfBSCF;
991 task->progress = ulProgress;
992 task->progress_max = ulProgressMax;
994 push_task(This, &task->header, report_data_proc);
995 }else {
996 report_data(This, grfBSCF, ulProgress, ulProgressMax);
999 return S_OK;
1002 static void report_result_proc(Binding *binding, task_header_t *t)
1004 IInternetProtocol_Terminate(binding->protocol, 0);
1006 if(binding->request_locked) {
1007 IInternetProtocol_UnlockRequest(binding->protocol);
1008 binding->request_locked = FALSE;
1011 HeapFree(GetProcessHeap(), 0, t);
1014 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1015 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1017 Binding *This = PROTSINK_THIS(iface);
1019 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1021 if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
1022 IInternetProtocol_Terminate(This->protocol, 0);
1023 }else {
1024 task_header_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(task_header_t));
1025 push_task(This, task, report_result_proc);
1028 return S_OK;
1031 #undef PROTSINK_THIS
1033 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1034 InternetProtocolSink_QueryInterface,
1035 InternetProtocolSink_AddRef,
1036 InternetProtocolSink_Release,
1037 InternetProtocolSink_Switch,
1038 InternetProtocolSink_ReportProgress,
1039 InternetProtocolSink_ReportData,
1040 InternetProtocolSink_ReportResult
1043 #define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
1045 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
1046 REFIID riid, void **ppv)
1048 Binding *This = BINDINF_THIS(iface);
1049 return IBinding_QueryInterface(BINDING(This), riid, ppv);
1052 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
1054 Binding *This = BINDINF_THIS(iface);
1055 return IBinding_AddRef(BINDING(This));
1058 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
1060 Binding *This = BINDINF_THIS(iface);
1061 return IBinding_Release(BINDING(This));
1064 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
1065 DWORD *grfBINDF, BINDINFO *pbindinfo)
1067 Binding *This = BINDINF_THIS(iface);
1069 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1071 *grfBINDF = This->bindf;
1073 memcpy(pbindinfo, &This->bindinfo, sizeof(BINDINFO));
1075 if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
1076 FIXME("copy strings\n");
1078 if(pbindinfo->stgmedData.pUnkForRelease)
1079 IUnknown_AddRef(pbindinfo->stgmedData.pUnkForRelease);
1081 if(pbindinfo->pUnk)
1082 IUnknown_AddRef(pbindinfo->pUnk);
1084 return S_OK;
1087 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
1088 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1090 Binding *This = BINDINF_THIS(iface);
1092 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1094 switch(ulStringType) {
1095 case BINDSTRING_ACCEPT_MIMES: {
1096 static const WCHAR wszMimes[] = {'*','/','*',0};
1098 if(!ppwzStr || !pcElFetched)
1099 return E_INVALIDARG;
1101 ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes));
1102 memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes));
1103 *pcElFetched = 1;
1104 return S_OK;
1106 case BINDSTRING_USER_AGENT: {
1107 IInternetBindInfo *bindinfo = NULL;
1108 HRESULT hres;
1110 hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo,
1111 (void**)&bindinfo);
1112 if(FAILED(hres))
1113 return hres;
1115 hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr,
1116 cEl, pcElFetched);
1117 IInternetBindInfo_Release(bindinfo);
1119 return hres;
1123 FIXME("not supported string type %d\n", ulStringType);
1124 return E_NOTIMPL;
1127 #undef BINDF_THIS
1129 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1130 InternetBindInfo_QueryInterface,
1131 InternetBindInfo_AddRef,
1132 InternetBindInfo_Release,
1133 InternetBindInfo_GetBindInfo,
1134 InternetBindInfo_GetBindString
1137 #define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
1139 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
1140 REFIID riid, void **ppv)
1142 Binding *This = SERVPROV_THIS(iface);
1143 return IBinding_QueryInterface(BINDING(This), riid, ppv);
1146 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
1148 Binding *This = SERVPROV_THIS(iface);
1149 return IBinding_AddRef(BINDING(This));
1152 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
1154 Binding *This = SERVPROV_THIS(iface);
1155 return IBinding_Release(BINDING(This));
1158 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
1159 REFGUID guidService, REFIID riid, void **ppv)
1161 Binding *This = SERVPROV_THIS(iface);
1162 HRESULT hres;
1164 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1166 if(This->service_provider) {
1167 hres = IServiceProvider_QueryService(This->service_provider, guidService,
1168 riid, ppv);
1169 if(SUCCEEDED(hres))
1170 return hres;
1173 if(IsEqualGUID(&IID_IHttpNegotiate, guidService)
1174 || IsEqualGUID(&IID_IHttpNegotiate2, guidService)) {
1175 if(!This->httpneg2_wrapper) {
1176 WARN("HttpNegotiate2Wrapper expected to be non-NULL\n");
1177 } else {
1178 if(IsEqualGUID(&IID_IHttpNegotiate, guidService))
1179 IBindStatusCallback_QueryInterface(This->callback, riid,
1180 (void **)&This->httpneg2_wrapper->http_negotiate);
1181 else
1182 IBindStatusCallback_QueryInterface(This->callback, riid,
1183 (void **)&This->httpneg2_wrapper->http_negotiate2);
1185 return IHttpNegotiate2_QueryInterface(HTTPNEG2(This->httpneg2_wrapper), riid, ppv);
1189 WARN("unknown service %s\n", debugstr_guid(guidService));
1190 return E_NOTIMPL;
1193 #undef SERVPROV_THIS
1195 static const IServiceProviderVtbl ServiceProviderVtbl = {
1196 ServiceProvider_QueryInterface,
1197 ServiceProvider_AddRef,
1198 ServiceProvider_Release,
1199 ServiceProvider_QueryService
1202 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
1204 HRESULT hres;
1206 static WCHAR wszBSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
1208 hres = IBindCtx_GetObjectParam(pbc, wszBSCBHolder, (IUnknown**)callback);
1209 if(FAILED(hres))
1210 return MK_E_SYNTAX;
1212 return S_OK;
1215 static HRESULT get_protocol(Binding *This, LPCWSTR url)
1217 IClassFactory *cf = NULL;
1218 HRESULT hres;
1220 hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetProtocol,
1221 (void**)&This->protocol);
1222 if(SUCCEEDED(hres))
1223 return S_OK;
1225 if(This->service_provider) {
1226 hres = IServiceProvider_QueryService(This->service_provider, &IID_IInternetProtocol,
1227 &IID_IInternetProtocol, (void**)&This->protocol);
1228 if(SUCCEEDED(hres))
1229 return S_OK;
1232 hres = get_protocol_handler(url, NULL, &cf);
1233 if(FAILED(hres))
1234 return hres;
1236 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&This->protocol);
1237 IClassFactory_Release(cf);
1239 return hres;
1242 static BOOL is_urlmon_protocol(LPCWSTR url)
1244 static const WCHAR wszCdl[] = {'c','d','l'};
1245 static const WCHAR wszFile[] = {'f','i','l','e'};
1246 static const WCHAR wszFtp[] = {'f','t','p'};
1247 static const WCHAR wszGopher[] = {'g','o','p','h','e','r'};
1248 static const WCHAR wszHttp[] = {'h','t','t','p'};
1249 static const WCHAR wszHttps[] = {'h','t','t','p','s'};
1250 static const WCHAR wszMk[] = {'m','k'};
1252 static const struct {
1253 LPCWSTR scheme;
1254 int len;
1255 } protocol_list[] = {
1256 {wszCdl, sizeof(wszCdl) /sizeof(WCHAR)},
1257 {wszFile, sizeof(wszFile) /sizeof(WCHAR)},
1258 {wszFtp, sizeof(wszFtp) /sizeof(WCHAR)},
1259 {wszGopher, sizeof(wszGopher)/sizeof(WCHAR)},
1260 {wszHttp, sizeof(wszHttp) /sizeof(WCHAR)},
1261 {wszHttps, sizeof(wszHttps) /sizeof(WCHAR)},
1262 {wszMk, sizeof(wszMk) /sizeof(WCHAR)}
1265 int i, len = strlenW(url);
1267 for(i=0; i < sizeof(protocol_list)/sizeof(protocol_list[0]); i++) {
1268 if(len >= protocol_list[i].len
1269 && !memcmp(url, protocol_list[i].scheme, protocol_list[i].len*sizeof(WCHAR)))
1270 return TRUE;
1273 return FALSE;
1276 static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding)
1278 Binding *ret;
1279 int len;
1280 HRESULT hres;
1282 if(!IsEqualGUID(&IID_IStream, riid)) {
1283 FIXME("Unsupported riid %s\n", debugstr_guid(riid));
1284 return E_NOTIMPL;
1287 URLMON_LockModule();
1289 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(Binding));
1291 ret->lpBindingVtbl = &BindingVtbl;
1292 ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1293 ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
1294 ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
1296 ret->ref = 1;
1298 ret->callback = NULL;
1299 ret->protocol = NULL;
1300 ret->service_provider = NULL;
1301 ret->stream = NULL;
1302 ret->httpneg2_wrapper = NULL;
1303 ret->mime = NULL;
1304 ret->url = NULL;
1305 ret->apartment_thread = GetCurrentThreadId();
1306 ret->notif_hwnd = get_notif_hwnd();
1307 ret->report_mime = TRUE;
1308 ret->continue_call = 0;
1309 ret->request_locked = FALSE;
1310 ret->task_queue_head = ret->task_queue_tail = NULL;
1312 memset(&ret->bindinfo, 0, sizeof(BINDINFO));
1313 ret->bindinfo.cbSize = sizeof(BINDINFO);
1314 ret->bindf = 0;
1316 InitializeCriticalSection(&ret->section);
1317 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Binding.section");
1319 hres = get_callback(pbc, &ret->callback);
1320 if(FAILED(hres)) {
1321 WARN("Could not get IBindStatusCallback\n");
1322 IBinding_Release(BINDING(ret));
1323 return hres;
1326 IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider,
1327 (void**)&ret->service_provider);
1329 hres = get_protocol(ret, url);
1330 if(FAILED(hres)) {
1331 WARN("Could not get protocol handler\n");
1332 IBinding_Release(BINDING(ret));
1333 return hres;
1336 hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
1337 if(FAILED(hres)) {
1338 WARN("GetBindInfo failed: %08x\n", hres);
1339 IBinding_Release(BINDING(ret));
1340 return hres;
1343 dump_BINDINFO(&ret->bindinfo);
1345 ret->bindf |= BINDF_FROMURLMON;
1347 if(!is_urlmon_protocol(url))
1348 ret->bindf |= BINDF_NEEDFILE;
1350 len = strlenW(url)+1;
1351 ret->url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
1352 memcpy(ret->url, url, len*sizeof(WCHAR));
1354 ret->stream = create_stream(ret->protocol);
1355 ret->stgmed.tymed = TYMED_ISTREAM;
1356 ret->stgmed.u.pstm = STREAM(ret->stream);
1357 ret->stgmed.pUnkForRelease = (IUnknown*)BINDING(ret); /* NOTE: Windows uses other IUnknown */
1359 ret->httpneg2_wrapper = create_httpneg2_wrapper();
1361 *binding = ret;
1362 return S_OK;
1365 HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
1367 Binding *binding = NULL;
1368 HRESULT hres;
1370 *ppv = NULL;
1372 hres = Binding_Create(url, pbc, riid, &binding);
1373 if(FAILED(hres))
1374 return hres;
1376 hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, BINDING(binding));
1377 if(FAILED(hres)) {
1378 WARN("OnStartBinding failed: %08x\n", hres);
1379 IBindStatusCallback_OnStopBinding(binding->callback, 0x800c0008, NULL);
1380 IBinding_Release(BINDING(binding));
1381 return hres;
1384 hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding),
1385 BINDINF(binding), 0, 0);
1387 if(FAILED(hres)) {
1388 WARN("Start failed: %08x\n", hres);
1390 IInternetProtocol_Terminate(binding->protocol, 0);
1391 IBindStatusCallback_OnStopBinding(binding->callback, S_OK, NULL);
1392 IBinding_Release(BINDING(binding));
1394 return hres;
1397 if(binding->stream->init_buf) {
1398 if(binding->request_locked)
1399 IInternetProtocol_UnlockRequest(binding->protocol);
1401 IStream_AddRef(STREAM(binding->stream));
1402 *ppv = binding->stream;
1404 hres = S_OK;
1405 }else {
1406 hres = MK_S_ASYNCHRONOUS;
1409 IBinding_Release(BINDING(binding));
1411 return hres;