urlmon: Do not fill stream buffer on every report_data, native doesn't.
[wine.git] / dlls / urlmon / binding.c
blob0ba4cdb2bbd6cd0174265ce27e7b96968d1f6395
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 IBindStatusCallback_OnDataAvailable(This->callback, bscf, progress,
953 &formatetc, &This->stgmed);
955 if(end_download) {
956 IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL);
960 typedef struct {
961 task_header_t header;
962 DWORD bscf;
963 ULONG progress;
964 ULONG progress_max;
965 } report_data_task_t;
967 static void report_data_proc(Binding *binding, task_header_t *t)
969 report_data_task_t *task = (report_data_task_t*)t;
971 report_data(binding, task->bscf, task->progress, task->progress_max);
973 HeapFree(GetProcessHeap(), 0, task);
976 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
977 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
979 Binding *This = PROTSINK_THIS(iface);
981 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
983 if(GetCurrentThreadId() != This->apartment_thread)
984 FIXME("called from worked hread\n");
986 if(This->continue_call) {
987 report_data_task_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(report_data_task_t));
988 task->bscf = grfBSCF;
989 task->progress = ulProgress;
990 task->progress_max = ulProgressMax;
992 push_task(This, &task->header, report_data_proc);
993 }else {
994 report_data(This, grfBSCF, ulProgress, ulProgressMax);
997 return S_OK;
1000 static void report_result_proc(Binding *binding, task_header_t *t)
1002 IInternetProtocol_Terminate(binding->protocol, 0);
1004 if(binding->request_locked) {
1005 IInternetProtocol_UnlockRequest(binding->protocol);
1006 binding->request_locked = FALSE;
1009 HeapFree(GetProcessHeap(), 0, t);
1012 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1013 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1015 Binding *This = PROTSINK_THIS(iface);
1017 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1019 if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
1020 IInternetProtocol_Terminate(This->protocol, 0);
1021 }else {
1022 task_header_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(task_header_t));
1023 push_task(This, task, report_result_proc);
1026 return S_OK;
1029 #undef PROTSINK_THIS
1031 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1032 InternetProtocolSink_QueryInterface,
1033 InternetProtocolSink_AddRef,
1034 InternetProtocolSink_Release,
1035 InternetProtocolSink_Switch,
1036 InternetProtocolSink_ReportProgress,
1037 InternetProtocolSink_ReportData,
1038 InternetProtocolSink_ReportResult
1041 #define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
1043 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
1044 REFIID riid, void **ppv)
1046 Binding *This = BINDINF_THIS(iface);
1047 return IBinding_QueryInterface(BINDING(This), riid, ppv);
1050 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
1052 Binding *This = BINDINF_THIS(iface);
1053 return IBinding_AddRef(BINDING(This));
1056 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
1058 Binding *This = BINDINF_THIS(iface);
1059 return IBinding_Release(BINDING(This));
1062 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
1063 DWORD *grfBINDF, BINDINFO *pbindinfo)
1065 Binding *This = BINDINF_THIS(iface);
1067 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1069 *grfBINDF = This->bindf;
1071 memcpy(pbindinfo, &This->bindinfo, sizeof(BINDINFO));
1073 if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
1074 FIXME("copy strings\n");
1076 if(pbindinfo->stgmedData.pUnkForRelease)
1077 IUnknown_AddRef(pbindinfo->stgmedData.pUnkForRelease);
1079 if(pbindinfo->pUnk)
1080 IUnknown_AddRef(pbindinfo->pUnk);
1082 return S_OK;
1085 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
1086 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1088 Binding *This = BINDINF_THIS(iface);
1090 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1092 switch(ulStringType) {
1093 case BINDSTRING_ACCEPT_MIMES: {
1094 static const WCHAR wszMimes[] = {'*','/','*',0};
1096 if(!ppwzStr || !pcElFetched)
1097 return E_INVALIDARG;
1099 ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes));
1100 memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes));
1101 *pcElFetched = 1;
1102 return S_OK;
1104 case BINDSTRING_USER_AGENT: {
1105 IInternetBindInfo *bindinfo = NULL;
1106 HRESULT hres;
1108 hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo,
1109 (void**)&bindinfo);
1110 if(FAILED(hres))
1111 return hres;
1113 hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr,
1114 cEl, pcElFetched);
1115 IInternetBindInfo_Release(bindinfo);
1117 return hres;
1121 FIXME("not supported string type %d\n", ulStringType);
1122 return E_NOTIMPL;
1125 #undef BINDF_THIS
1127 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1128 InternetBindInfo_QueryInterface,
1129 InternetBindInfo_AddRef,
1130 InternetBindInfo_Release,
1131 InternetBindInfo_GetBindInfo,
1132 InternetBindInfo_GetBindString
1135 #define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
1137 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
1138 REFIID riid, void **ppv)
1140 Binding *This = SERVPROV_THIS(iface);
1141 return IBinding_QueryInterface(BINDING(This), riid, ppv);
1144 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
1146 Binding *This = SERVPROV_THIS(iface);
1147 return IBinding_AddRef(BINDING(This));
1150 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
1152 Binding *This = SERVPROV_THIS(iface);
1153 return IBinding_Release(BINDING(This));
1156 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
1157 REFGUID guidService, REFIID riid, void **ppv)
1159 Binding *This = SERVPROV_THIS(iface);
1160 HRESULT hres;
1162 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1164 if(This->service_provider) {
1165 hres = IServiceProvider_QueryService(This->service_provider, guidService,
1166 riid, ppv);
1167 if(SUCCEEDED(hres))
1168 return hres;
1171 if(IsEqualGUID(&IID_IHttpNegotiate, guidService)
1172 || IsEqualGUID(&IID_IHttpNegotiate2, guidService)) {
1173 if(!This->httpneg2_wrapper) {
1174 WARN("HttpNegotiate2Wrapper expected to be non-NULL\n");
1175 } else {
1176 if(IsEqualGUID(&IID_IHttpNegotiate, guidService))
1177 IBindStatusCallback_QueryInterface(This->callback, riid,
1178 (void **)&This->httpneg2_wrapper->http_negotiate);
1179 else
1180 IBindStatusCallback_QueryInterface(This->callback, riid,
1181 (void **)&This->httpneg2_wrapper->http_negotiate2);
1183 return IHttpNegotiate2_QueryInterface(HTTPNEG2(This->httpneg2_wrapper), riid, ppv);
1187 WARN("unknown service %s\n", debugstr_guid(guidService));
1188 return E_NOTIMPL;
1191 #undef SERVPROV_THIS
1193 static const IServiceProviderVtbl ServiceProviderVtbl = {
1194 ServiceProvider_QueryInterface,
1195 ServiceProvider_AddRef,
1196 ServiceProvider_Release,
1197 ServiceProvider_QueryService
1200 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
1202 HRESULT hres;
1204 static WCHAR wszBSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
1206 hres = IBindCtx_GetObjectParam(pbc, wszBSCBHolder, (IUnknown**)callback);
1207 if(FAILED(hres))
1208 return MK_E_SYNTAX;
1210 return S_OK;
1213 static HRESULT get_protocol(Binding *This, LPCWSTR url)
1215 IClassFactory *cf = NULL;
1216 HRESULT hres;
1218 hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetProtocol,
1219 (void**)&This->protocol);
1220 if(SUCCEEDED(hres))
1221 return S_OK;
1223 if(This->service_provider) {
1224 hres = IServiceProvider_QueryService(This->service_provider, &IID_IInternetProtocol,
1225 &IID_IInternetProtocol, (void**)&This->protocol);
1226 if(SUCCEEDED(hres))
1227 return S_OK;
1230 hres = get_protocol_handler(url, NULL, &cf);
1231 if(FAILED(hres))
1232 return hres;
1234 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&This->protocol);
1235 IClassFactory_Release(cf);
1237 return hres;
1240 static BOOL is_urlmon_protocol(LPCWSTR url)
1242 static const WCHAR wszCdl[] = {'c','d','l'};
1243 static const WCHAR wszFile[] = {'f','i','l','e'};
1244 static const WCHAR wszFtp[] = {'f','t','p'};
1245 static const WCHAR wszGopher[] = {'g','o','p','h','e','r'};
1246 static const WCHAR wszHttp[] = {'h','t','t','p'};
1247 static const WCHAR wszHttps[] = {'h','t','t','p','s'};
1248 static const WCHAR wszMk[] = {'m','k'};
1250 static const struct {
1251 LPCWSTR scheme;
1252 int len;
1253 } protocol_list[] = {
1254 {wszCdl, sizeof(wszCdl) /sizeof(WCHAR)},
1255 {wszFile, sizeof(wszFile) /sizeof(WCHAR)},
1256 {wszFtp, sizeof(wszFtp) /sizeof(WCHAR)},
1257 {wszGopher, sizeof(wszGopher)/sizeof(WCHAR)},
1258 {wszHttp, sizeof(wszHttp) /sizeof(WCHAR)},
1259 {wszHttps, sizeof(wszHttps) /sizeof(WCHAR)},
1260 {wszMk, sizeof(wszMk) /sizeof(WCHAR)}
1263 int i, len = strlenW(url);
1265 for(i=0; i < sizeof(protocol_list)/sizeof(protocol_list[0]); i++) {
1266 if(len >= protocol_list[i].len
1267 && !memcmp(url, protocol_list[i].scheme, protocol_list[i].len*sizeof(WCHAR)))
1268 return TRUE;
1271 return FALSE;
1274 static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding)
1276 Binding *ret;
1277 int len;
1278 HRESULT hres;
1280 if(!IsEqualGUID(&IID_IStream, riid)) {
1281 FIXME("Unsupported riid %s\n", debugstr_guid(riid));
1282 return E_NOTIMPL;
1285 URLMON_LockModule();
1287 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(Binding));
1289 ret->lpBindingVtbl = &BindingVtbl;
1290 ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1291 ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
1292 ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
1294 ret->ref = 1;
1296 ret->callback = NULL;
1297 ret->protocol = NULL;
1298 ret->service_provider = NULL;
1299 ret->stream = NULL;
1300 ret->httpneg2_wrapper = NULL;
1301 ret->mime = NULL;
1302 ret->url = NULL;
1303 ret->apartment_thread = GetCurrentThreadId();
1304 ret->notif_hwnd = get_notif_hwnd();
1305 ret->report_mime = TRUE;
1306 ret->continue_call = 0;
1307 ret->request_locked = FALSE;
1308 ret->task_queue_head = ret->task_queue_tail = NULL;
1310 memset(&ret->bindinfo, 0, sizeof(BINDINFO));
1311 ret->bindinfo.cbSize = sizeof(BINDINFO);
1312 ret->bindf = 0;
1314 InitializeCriticalSection(&ret->section);
1315 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Binding.section");
1317 hres = get_callback(pbc, &ret->callback);
1318 if(FAILED(hres)) {
1319 WARN("Could not get IBindStatusCallback\n");
1320 IBinding_Release(BINDING(ret));
1321 return hres;
1324 IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider,
1325 (void**)&ret->service_provider);
1327 hres = get_protocol(ret, url);
1328 if(FAILED(hres)) {
1329 WARN("Could not get protocol handler\n");
1330 IBinding_Release(BINDING(ret));
1331 return hres;
1334 hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
1335 if(FAILED(hres)) {
1336 WARN("GetBindInfo failed: %08x\n", hres);
1337 IBinding_Release(BINDING(ret));
1338 return hres;
1341 dump_BINDINFO(&ret->bindinfo);
1343 ret->bindf |= BINDF_FROMURLMON;
1345 if(!is_urlmon_protocol(url))
1346 ret->bindf |= BINDF_NEEDFILE;
1348 len = strlenW(url)+1;
1349 ret->url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
1350 memcpy(ret->url, url, len*sizeof(WCHAR));
1352 ret->stream = create_stream(ret->protocol);
1353 ret->stgmed.tymed = TYMED_ISTREAM;
1354 ret->stgmed.u.pstm = STREAM(ret->stream);
1355 ret->stgmed.pUnkForRelease = (IUnknown*)BINDING(ret); /* NOTE: Windows uses other IUnknown */
1357 ret->httpneg2_wrapper = create_httpneg2_wrapper();
1359 *binding = ret;
1360 return S_OK;
1363 HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
1365 Binding *binding = NULL;
1366 HRESULT hres;
1368 *ppv = NULL;
1370 hres = Binding_Create(url, pbc, riid, &binding);
1371 if(FAILED(hres))
1372 return hres;
1374 hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, BINDING(binding));
1375 if(FAILED(hres)) {
1376 WARN("OnStartBinding failed: %08x\n", hres);
1377 IBindStatusCallback_OnStopBinding(binding->callback, 0x800c0008, NULL);
1378 IBinding_Release(BINDING(binding));
1379 return hres;
1382 hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding),
1383 BINDINF(binding), 0, 0);
1385 if(FAILED(hres)) {
1386 WARN("Start failed: %08x\n", hres);
1388 IInternetProtocol_Terminate(binding->protocol, 0);
1389 IBindStatusCallback_OnStopBinding(binding->callback, S_OK, NULL);
1390 IBinding_Release(BINDING(binding));
1392 return hres;
1395 if(binding->stream->init_buf) {
1396 if(binding->request_locked)
1397 IInternetProtocol_UnlockRequest(binding->protocol);
1399 IStream_AddRef(STREAM(binding->stream));
1400 *ppv = binding->stream;
1402 hres = S_OK;
1403 }else {
1404 hres = MK_S_ASYNCHRONOUS;
1407 IBinding_Release(BINDING(binding));
1409 return hres;