urlmon: Wrap IHttpNegotiate2 interface exposed by IBindStatusCallback as done by...
[wine.git] / dlls / urlmon / binding.c
blobaaadbd87638962c8df581f24899aca0f46fc60b2
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 typedef enum {
71 BEFORE_DOWNLOAD,
72 DOWNLOADING,
73 END_DOWNLOAD
74 } download_state_t;
76 struct Binding {
77 const IBindingVtbl *lpBindingVtbl;
78 const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl;
79 const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
80 const IServiceProviderVtbl *lpServiceProviderVtbl;
82 LONG ref;
84 IBindStatusCallback *callback;
85 IInternetProtocol *protocol;
86 IServiceProvider *service_provider;
87 ProtocolStream *stream;
88 HttpNegotiate2Wrapper *httpneg2_wrapper;
90 BINDINFO bindinfo;
91 DWORD bindf;
92 LPWSTR mime;
93 LPWSTR url;
94 BOOL report_mime;
95 DWORD continue_call;
96 BOOL request_locked;
97 download_state_t download_state;
99 DWORD apartment_thread;
100 HWND notif_hwnd;
102 STGMEDIUM stgmed;
104 task_header_t *task_queue_head, *task_queue_tail;
105 CRITICAL_SECTION section;
108 #define BINDING(x) ((IBinding*) &(x)->lpBindingVtbl)
109 #define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
110 #define BINDINF(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
111 #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl)
113 #define STREAM(x) ((IStream*) &(x)->lpStreamVtbl)
114 #define HTTPNEG2(x) ((IHttpNegotiate2*) &(x)->lpHttpNegotiate2Vtbl)
116 #define WM_MK_CONTINUE (WM_USER+101)
118 static void push_task(Binding *binding, task_header_t *task, task_proc_t proc)
120 task->proc = proc;
121 task->next = NULL;
123 EnterCriticalSection(&binding->section);
125 if(binding->task_queue_tail)
126 binding->task_queue_tail->next = task;
127 else
128 binding->task_queue_tail = binding->task_queue_head = task;
130 LeaveCriticalSection(&binding->section);
133 static task_header_t *pop_task(Binding *binding)
135 task_header_t *ret;
137 EnterCriticalSection(&binding->section);
139 ret = binding->task_queue_head;
140 if(ret) {
141 binding->task_queue_head = ret->next;
142 if(!binding->task_queue_head)
143 binding->task_queue_tail = NULL;
146 LeaveCriticalSection(&binding->section);
148 return ret;
151 static void fill_stream_buffer(ProtocolStream *This)
153 DWORD read = 0;
155 if(sizeof(This->buf) == This->buf_size)
156 return;
158 This->hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size,
159 sizeof(This->buf)-This->buf_size, &read);
160 This->buf_size += read;
161 if(read > 0)
162 This->init_buf = TRUE;
165 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
167 if(msg == WM_MK_CONTINUE) {
168 Binding *binding = (Binding*)lParam;
169 task_header_t *task;
171 while((task = pop_task(binding))) {
172 binding->continue_call++;
173 task->proc(binding, task);
174 binding->continue_call--;
177 IBinding_Release(BINDING(binding));
178 return 0;
181 return DefWindowProcW(hwnd, msg, wParam, lParam);
184 static HWND get_notif_hwnd(void)
186 static ATOM wnd_class = 0;
187 HWND hwnd;
189 static const WCHAR wszURLMonikerNotificationWindow[] =
190 {'U','R','L',' ','M','o','n','i','k','e','r',' ',
191 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
193 if(!wnd_class) {
194 static WNDCLASSEXW wndclass = {
195 sizeof(wndclass), 0,
196 notif_wnd_proc, 0, 0,
197 NULL, NULL, NULL, NULL, NULL,
198 wszURLMonikerNotificationWindow,
199 NULL
202 wndclass.hInstance = URLMON_hInstance;
204 wnd_class = RegisterClassExW(&wndclass);
205 if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
206 wnd_class = 1;
209 hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
210 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
211 NULL, URLMON_hInstance, NULL);
213 TRACE("hwnd = %p\n", hwnd);
215 return hwnd;
218 static void dump_BINDINFO(BINDINFO *bi)
220 static const char * const BINDINFOF_str[] = {
221 "#0",
222 "BINDINFOF_URLENCODESTGMEDDATA",
223 "BINDINFOF_URLENCODEDEXTRAINFO"
226 static const char * const BINDVERB_str[] = {
227 "BINDVERB_GET",
228 "BINDVERB_POST",
229 "BINDVERB_PUT",
230 "BINDVERB_CUSTOM"
233 TRACE("\n"
234 "BINDINFO = {\n"
235 " %d, %s,\n"
236 " {%d, %p, %p},\n"
237 " %s,\n"
238 " %s,\n"
239 " %s,\n"
240 " %d, %08x, %d, %d\n"
241 " {%d %p %x},\n"
242 " %s\n"
243 " %p, %d\n"
244 "}\n",
246 bi->cbSize, debugstr_w(bi->szExtraInfo),
247 bi->stgmedData.tymed, bi->stgmedData.u.hGlobal, bi->stgmedData.pUnkForRelease,
248 bi->grfBindInfoF > BINDINFOF_URLENCODEDEXTRAINFO
249 ? "unknown" : BINDINFOF_str[bi->grfBindInfoF],
250 bi->dwBindVerb > BINDVERB_CUSTOM
251 ? "unknown" : BINDVERB_str[bi->dwBindVerb],
252 debugstr_w(bi->szCustomVerb),
253 bi->cbstgmedData, bi->dwOptions, bi->dwOptionsFlags, bi->dwCodePage,
254 bi->securityAttributes.nLength,
255 bi->securityAttributes.lpSecurityDescriptor,
256 bi->securityAttributes.bInheritHandle,
257 debugstr_guid(&bi->iid),
258 bi->pUnk, bi->dwReserved
262 #define HTTPNEG2_THIS(iface) DEFINE_THIS(HttpNegotiate2Wrapper, HttpNegotiate2, iface)
264 static HRESULT WINAPI HttpNegotiate2Wrapper_QueryInterface(IHttpNegotiate2 *iface,
265 REFIID riid, void **ppv)
267 HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
269 *ppv = NULL;
271 if(IsEqualGUID(&IID_IUnknown, riid)) {
272 TRACE("(IID_IUnknown %p)\n", ppv);
273 *ppv = HTTPNEG2(This);
274 }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
275 TRACE("(IID_IHttpNegotiate %p)\n", ppv);
276 *ppv = HTTPNEG2(This);
277 }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
278 TRACE("(IID_IHttpNegotiate2 %p)\n", ppv);
279 *ppv = HTTPNEG2(This);
282 if(*ppv) {
283 IHttpNegotiate2_AddRef(HTTPNEG2(This));
284 return S_OK;
287 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
288 return E_NOINTERFACE;
291 static ULONG WINAPI HttpNegotiate2Wrapper_AddRef(IHttpNegotiate2 *iface)
293 HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
294 LONG ref = InterlockedIncrement(&This->ref);
296 TRACE("(%p) ref=%d\n", This, ref);
298 return ref;
301 static ULONG WINAPI HttpNegotiate2Wrapper_Release(IHttpNegotiate2 *iface)
303 HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
304 LONG ref = InterlockedDecrement(&This->ref);
306 TRACE("(%p) ref=%d\n", This, ref);
308 if(!ref) {
309 if (This->http_negotiate)
310 IHttpNegotiate_Release(This->http_negotiate);
311 if (This->http_negotiate2)
312 IHttpNegotiate2_Release(This->http_negotiate2);
313 HeapFree(GetProcessHeap(), 0, This);
315 URLMON_UnlockModule();
318 return ref;
321 static HRESULT WINAPI HttpNegotiate2Wrapper_BeginningTransaction(IHttpNegotiate2 *iface,
322 LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
324 HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
326 TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders), dwReserved,
327 pszAdditionalHeaders);
329 if(This->http_negotiate)
330 return IHttpNegotiate_BeginningTransaction(This->http_negotiate, szURL, szHeaders,
331 dwReserved, pszAdditionalHeaders);
333 *pszAdditionalHeaders = NULL;
334 return S_OK;
337 static HRESULT WINAPI HttpNegotiate2Wrapper_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
338 LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders,
339 LPWSTR *pszAdditionalRequestHeaders)
341 HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
342 LPWSTR szAdditionalRequestHeaders = NULL;
343 HRESULT hres = S_OK;
345 TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
346 debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
348 /* IHttpNegotiate2_OnResponse expects pszAdditionalHeaders to be non-NULL when it is
349 * implemented as part of IBindStatusCallback, but it is NULL when called directly from
350 * IProtocol */
351 if(!pszAdditionalRequestHeaders)
352 pszAdditionalRequestHeaders = &szAdditionalRequestHeaders;
354 if(This->http_negotiate)
356 hres = IHttpNegotiate_OnResponse(This->http_negotiate, dwResponseCode, szResponseHeaders,
357 szRequestHeaders, pszAdditionalRequestHeaders);
358 if(pszAdditionalRequestHeaders == &szAdditionalRequestHeaders &&
359 szAdditionalRequestHeaders)
360 CoTaskMemFree(szAdditionalRequestHeaders);
362 else
364 *pszAdditionalRequestHeaders = NULL;
367 return hres;
370 static HRESULT WINAPI HttpNegotiate2Wrapper_GetRootSecurityId(IHttpNegotiate2 *iface,
371 BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
373 HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
375 TRACE("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved);
377 if (This->http_negotiate2)
378 return IHttpNegotiate2_GetRootSecurityId(This->http_negotiate2, pbSecurityId,
379 pcbSecurityId, dwReserved);
381 /* That's all we have to do here */
382 return E_FAIL;
385 #undef HTTPNEG2_THIS
387 static const IHttpNegotiate2Vtbl HttpNegotiate2WrapperVtbl = {
388 HttpNegotiate2Wrapper_QueryInterface,
389 HttpNegotiate2Wrapper_AddRef,
390 HttpNegotiate2Wrapper_Release,
391 HttpNegotiate2Wrapper_BeginningTransaction,
392 HttpNegotiate2Wrapper_OnResponse,
393 HttpNegotiate2Wrapper_GetRootSecurityId
396 static HttpNegotiate2Wrapper *create_httpneg2_wrapper(void)
398 HttpNegotiate2Wrapper *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(HttpNegotiate2Wrapper));
400 ret->lpHttpNegotiate2Vtbl = &HttpNegotiate2WrapperVtbl;
401 ret->ref = 1;
402 ret->http_negotiate = NULL;
403 ret->http_negotiate2 = NULL;
405 URLMON_LockModule();
407 return ret;
410 #define STREAM_THIS(iface) DEFINE_THIS(ProtocolStream, Stream, iface)
412 static HRESULT WINAPI ProtocolStream_QueryInterface(IStream *iface,
413 REFIID riid, void **ppv)
415 ProtocolStream *This = STREAM_THIS(iface);
417 *ppv = NULL;
419 if(IsEqualGUID(&IID_IUnknown, riid)) {
420 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
421 *ppv = STREAM(This);
422 }else if(IsEqualGUID(&IID_ISequentialStream, riid)) {
423 TRACE("(%p)->(IID_ISequentialStream %p)\n", This, ppv);
424 *ppv = STREAM(This);
425 }else if(IsEqualGUID(&IID_IStream, riid)) {
426 TRACE("(%p)->(IID_IStream %p)\n", This, ppv);
427 *ppv = STREAM(This);
430 if(*ppv) {
431 IStream_AddRef(STREAM(This));
432 return S_OK;
435 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
436 return E_NOINTERFACE;
439 static ULONG WINAPI ProtocolStream_AddRef(IStream *iface)
441 ProtocolStream *This = STREAM_THIS(iface);
442 LONG ref = InterlockedIncrement(&This->ref);
444 TRACE("(%p) ref=%d\n", This, ref);
446 return ref;
449 static ULONG WINAPI ProtocolStream_Release(IStream *iface)
451 ProtocolStream *This = STREAM_THIS(iface);
452 LONG ref = InterlockedDecrement(&This->ref);
454 TRACE("(%p) ref=%d\n", This, ref);
456 if(!ref) {
457 IInternetProtocol_Release(This->protocol);
458 HeapFree(GetProcessHeap(), 0, This);
460 URLMON_UnlockModule();
463 return ref;
466 static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv,
467 ULONG cb, ULONG *pcbRead)
469 ProtocolStream *This = STREAM_THIS(iface);
470 DWORD read = 0, pread = 0;
472 TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbRead);
474 if(This->buf_size) {
475 read = cb;
477 if(read > This->buf_size)
478 read = This->buf_size;
480 memcpy(pv, This->buf, read);
482 if(read < This->buf_size)
483 memmove(This->buf, This->buf+read, This->buf_size-read);
484 This->buf_size -= read;
487 if(read == cb) {
488 *pcbRead = read;
489 return S_OK;
492 This->hres = IInternetProtocol_Read(This->protocol, (PBYTE)pv+read, cb-read, &pread);
493 *pcbRead = read + pread;
495 if(This->hres == E_PENDING)
496 return E_PENDING;
497 else if(FAILED(This->hres))
498 FIXME("Read failed: %08x\n", This->hres);
500 return read || pread ? S_OK : S_FALSE;
503 static HRESULT WINAPI ProtocolStream_Write(IStream *iface, const void *pv,
504 ULONG cb, ULONG *pcbWritten)
506 ProtocolStream *This = STREAM_THIS(iface);
508 TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbWritten);
510 return STG_E_ACCESSDENIED;
513 static HRESULT WINAPI ProtocolStream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
514 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
516 ProtocolStream *This = STREAM_THIS(iface);
517 FIXME("(%p)->(%d %08x %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
518 return E_NOTIMPL;
521 static HRESULT WINAPI ProtocolStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
523 ProtocolStream *This = STREAM_THIS(iface);
524 FIXME("(%p)->(%d)\n", This, libNewSize.u.LowPart);
525 return E_NOTIMPL;
528 static HRESULT WINAPI ProtocolStream_CopyTo(IStream *iface, IStream *pstm,
529 ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
531 ProtocolStream *This = STREAM_THIS(iface);
532 FIXME("(%p)->(%p %d %p %p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten);
533 return E_NOTIMPL;
536 static HRESULT WINAPI ProtocolStream_Commit(IStream *iface, DWORD grfCommitFlags)
538 ProtocolStream *This = STREAM_THIS(iface);
540 TRACE("(%p)->(%08x)\n", This, grfCommitFlags);
542 return E_NOTIMPL;
545 static HRESULT WINAPI ProtocolStream_Revert(IStream *iface)
547 ProtocolStream *This = STREAM_THIS(iface);
549 TRACE("(%p)\n", This);
551 return E_NOTIMPL;
554 static HRESULT WINAPI ProtocolStream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
555 ULARGE_INTEGER cb, DWORD dwLockType)
557 ProtocolStream *This = STREAM_THIS(iface);
558 FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
559 return E_NOTIMPL;
562 static HRESULT WINAPI ProtocolStream_UnlockRegion(IStream *iface,
563 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
565 ProtocolStream *This = STREAM_THIS(iface);
566 FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
567 return E_NOTIMPL;
570 static HRESULT WINAPI ProtocolStream_Stat(IStream *iface, STATSTG *pstatstg,
571 DWORD dwStatFlag)
573 ProtocolStream *This = STREAM_THIS(iface);
574 FIXME("(%p)->(%p %08x)\n", This, pstatstg, dwStatFlag);
575 return E_NOTIMPL;
578 static HRESULT WINAPI ProtocolStream_Clone(IStream *iface, IStream **ppstm)
580 ProtocolStream *This = STREAM_THIS(iface);
581 FIXME("(%p)->(%p)\n", This, ppstm);
582 return E_NOTIMPL;
585 #undef STREAM_THIS
587 static const IStreamVtbl ProtocolStreamVtbl = {
588 ProtocolStream_QueryInterface,
589 ProtocolStream_AddRef,
590 ProtocolStream_Release,
591 ProtocolStream_Read,
592 ProtocolStream_Write,
593 ProtocolStream_Seek,
594 ProtocolStream_SetSize,
595 ProtocolStream_CopyTo,
596 ProtocolStream_Commit,
597 ProtocolStream_Revert,
598 ProtocolStream_LockRegion,
599 ProtocolStream_UnlockRegion,
600 ProtocolStream_Stat,
601 ProtocolStream_Clone
604 #define BINDING_THIS(iface) DEFINE_THIS(Binding, Binding, iface)
606 static ProtocolStream *create_stream(IInternetProtocol *protocol)
608 ProtocolStream *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ProtocolStream));
610 ret->lpStreamVtbl = &ProtocolStreamVtbl;
611 ret->ref = 1;
612 ret->buf_size = 0;
613 ret->init_buf = FALSE;
614 ret->hres = S_OK;
616 IInternetProtocol_AddRef(protocol);
617 ret->protocol = protocol;
619 URLMON_LockModule();
621 return ret;
624 static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv)
626 Binding *This = BINDING_THIS(iface);
628 *ppv = NULL;
630 if(IsEqualGUID(&IID_IUnknown, riid)) {
631 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
632 *ppv = BINDING(This);
633 }else if(IsEqualGUID(&IID_IBinding, riid)) {
634 TRACE("(%p)->(IID_IBinding %p)\n", This, ppv);
635 *ppv = BINDING(This);
636 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
637 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
638 *ppv = PROTSINK(This);
639 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
640 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
641 *ppv = BINDINF(This);
642 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
643 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
644 *ppv = SERVPROV(This);
647 if(*ppv) {
648 IBinding_AddRef(BINDING(This));
649 return S_OK;
652 WARN("Unsupported interface %s\n", debugstr_guid(riid));
653 return E_NOINTERFACE;
656 static ULONG WINAPI Binding_AddRef(IBinding *iface)
658 Binding *This = BINDING_THIS(iface);
659 LONG ref = InterlockedIncrement(&This->ref);
661 TRACE("(%p) ref=%d\n", This, ref);
663 return ref;
666 static ULONG WINAPI Binding_Release(IBinding *iface)
668 Binding *This = BINDING_THIS(iface);
669 LONG ref = InterlockedDecrement(&This->ref);
671 TRACE("(%p) ref=%d\n", This, ref);
673 if(!ref) {
674 if (This->notif_hwnd)
675 DestroyWindow( This->notif_hwnd );
676 if(This->callback)
677 IBindStatusCallback_Release(This->callback);
678 if(This->protocol)
679 IInternetProtocol_Release(This->protocol);
680 if(This->service_provider)
681 IServiceProvider_Release(This->service_provider);
682 if(This->stream)
683 IStream_Release(STREAM(This->stream));
684 if(This->httpneg2_wrapper)
685 IHttpNegotiate2_Release(HTTPNEG2(This->httpneg2_wrapper));
687 ReleaseBindInfo(&This->bindinfo);
688 This->section.DebugInfo->Spare[0] = 0;
689 DeleteCriticalSection(&This->section);
690 HeapFree(GetProcessHeap(), 0, This->mime);
691 HeapFree(GetProcessHeap(), 0, This->url);
693 HeapFree(GetProcessHeap(), 0, This);
695 URLMON_UnlockModule();
698 return ref;
701 static HRESULT WINAPI Binding_Abort(IBinding *iface)
703 Binding *This = BINDING_THIS(iface);
704 FIXME("(%p)\n", This);
705 return E_NOTIMPL;
708 static HRESULT WINAPI Binding_Suspend(IBinding *iface)
710 Binding *This = BINDING_THIS(iface);
711 FIXME("(%p)\n", This);
712 return E_NOTIMPL;
715 static HRESULT WINAPI Binding_Resume(IBinding *iface)
717 Binding *This = BINDING_THIS(iface);
718 FIXME("(%p)\n", This);
719 return E_NOTIMPL;
722 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority)
724 Binding *This = BINDING_THIS(iface);
725 FIXME("(%p)->(%d)\n", This, nPriority);
726 return E_NOTIMPL;
729 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority)
731 Binding *This = BINDING_THIS(iface);
732 FIXME("(%p)->(%p)\n", This, pnPriority);
733 return E_NOTIMPL;
736 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol,
737 DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved)
739 Binding *This = BINDING_THIS(iface);
740 FIXME("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
741 return E_NOTIMPL;
744 #undef BINDING_THIS
746 static const IBindingVtbl BindingVtbl = {
747 Binding_QueryInterface,
748 Binding_AddRef,
749 Binding_Release,
750 Binding_Abort,
751 Binding_Suspend,
752 Binding_Resume,
753 Binding_SetPriority,
754 Binding_GetPriority,
755 Binding_GetBindResult
758 #define PROTSINK_THIS(iface) DEFINE_THIS(Binding, InternetProtocolSink, iface)
760 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
761 REFIID riid, void **ppv)
763 Binding *This = PROTSINK_THIS(iface);
764 return IBinding_QueryInterface(BINDING(This), riid, ppv);
767 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
769 Binding *This = PROTSINK_THIS(iface);
770 return IBinding_AddRef(BINDING(This));
773 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
775 Binding *This = PROTSINK_THIS(iface);
776 return IBinding_Release(BINDING(This));
779 typedef struct {
780 task_header_t header;
781 PROTOCOLDATA *data;
782 } switch_task_t;
784 static void switch_proc(Binding *binding, task_header_t *t)
786 switch_task_t *task = (switch_task_t*)t;
788 IInternetProtocol_Continue(binding->protocol, task->data);
790 HeapFree(GetProcessHeap(), 0, task);
793 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
794 PROTOCOLDATA *pProtocolData)
796 Binding *This = PROTSINK_THIS(iface);
797 switch_task_t *task;
799 TRACE("(%p)->(%p)\n", This, pProtocolData);
801 task = HeapAlloc(GetProcessHeap(), 0, sizeof(switch_task_t));
802 task->data = pProtocolData;
804 push_task(This, &task->header, switch_proc);
806 IBinding_AddRef(BINDING(This));
807 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
809 return S_OK;
812 typedef struct {
813 task_header_t header;
815 Binding *binding;
816 ULONG progress;
817 ULONG progress_max;
818 ULONG status_code;
819 LPWSTR status_text;
820 } on_progress_task_t;
822 static void on_progress_proc(Binding *binding, task_header_t *t)
824 on_progress_task_t *task = (on_progress_task_t*)t;
826 IBindStatusCallback_OnProgress(binding->callback, task->progress,
827 task->progress_max, task->status_code, task->status_text);
829 HeapFree(GetProcessHeap(), 0, task->status_text);
830 HeapFree(GetProcessHeap(), 0, task);
833 static void on_progress(Binding *This, ULONG progress, ULONG progress_max,
834 ULONG status_code, LPCWSTR status_text)
836 on_progress_task_t *task;
838 if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
839 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
840 status_code, status_text);
841 return;
844 task = HeapAlloc(GetProcessHeap(), 0, sizeof(on_progress_task_t));
846 task->progress = progress;
847 task->progress_max = progress_max;
848 task->status_code = status_code;
850 if(status_text) {
851 DWORD size = (strlenW(status_text)+1)*sizeof(WCHAR);
853 task->status_text = HeapAlloc(GetProcessHeap(), 0, size);
854 memcpy(task->status_text, status_text, size);
855 }else {
856 task->status_text = NULL;
859 push_task(This, &task->header, on_progress_proc);
861 if(GetCurrentThreadId() != This->apartment_thread) {
862 IBinding_AddRef(BINDING(This));
863 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
867 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
868 ULONG ulStatusCode, LPCWSTR szStatusText)
870 Binding *This = PROTSINK_THIS(iface);
872 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
874 switch(ulStatusCode) {
875 case BINDSTATUS_FINDINGRESOURCE:
876 on_progress(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, szStatusText);
877 break;
878 case BINDSTATUS_CONNECTING:
879 on_progress(This, 0, 0, BINDSTATUS_CONNECTING, szStatusText);
880 break;
881 case BINDSTATUS_BEGINDOWNLOADDATA:
882 fill_stream_buffer(This->stream);
883 break;
884 case BINDSTATUS_MIMETYPEAVAILABLE: {
885 int len = strlenW(szStatusText)+1;
886 This->mime = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
887 memcpy(This->mime, szStatusText, len*sizeof(WCHAR));
888 break;
890 case BINDSTATUS_SENDINGREQUEST:
891 on_progress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, szStatusText);
892 break;
893 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
894 This->report_mime = FALSE;
895 on_progress(This, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE, szStatusText);
896 break;
897 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
898 break;
899 case BINDSTATUS_DIRECTBIND:
900 This->report_mime = FALSE;
901 break;
902 default:
903 FIXME("Unhandled status code %d\n", ulStatusCode);
904 return E_NOTIMPL;
907 return S_OK;
910 static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progress_max)
912 FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM};
914 TRACE("(%p)->(%d %u %u)\n", This, bscf, progress, progress_max);
916 if(This->download_state == END_DOWNLOAD)
917 return;
919 if(GetCurrentThreadId() != This->apartment_thread)
920 FIXME("called from worked hread\n");
922 if(This->report_mime) {
923 LPWSTR mime;
925 This->report_mime = FALSE;
927 fill_stream_buffer(This->stream);
929 FindMimeFromData(NULL, This->url, This->stream->buf,
930 min(This->stream->buf_size, 255), This->mime, 0, &mime, 0);
932 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
933 BINDSTATUS_MIMETYPEAVAILABLE, mime);
936 if(This->download_state == BEFORE_DOWNLOAD) {
937 fill_stream_buffer(This->stream);
939 This->download_state = DOWNLOADING;
940 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
941 BINDSTATUS_BEGINDOWNLOADDATA, This->url);
944 if(This->stream->hres == S_FALSE || (bscf & BSCF_LASTDATANOTIFICATION)) {
945 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
946 BINDSTATUS_ENDDOWNLOADDATA, This->url);
949 if(!This->request_locked) {
950 HRESULT hres = IInternetProtocol_LockRequest(This->protocol, 0);
951 This->request_locked = SUCCEEDED(hres);
954 fill_stream_buffer(This->stream);
956 IBindStatusCallback_OnDataAvailable(This->callback, bscf, This->stream->buf_size,
957 &formatetc, &This->stgmed);
959 if(This->stream->hres == S_FALSE) {
960 This->download_state = END_DOWNLOAD;
961 IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL);
965 typedef struct {
966 task_header_t header;
967 DWORD bscf;
968 ULONG progress;
969 ULONG progress_max;
970 } report_data_task_t;
972 static void report_data_proc(Binding *binding, task_header_t *t)
974 report_data_task_t *task = (report_data_task_t*)t;
976 report_data(binding, task->bscf, task->progress, task->progress_max);
978 HeapFree(GetProcessHeap(), 0, task);
981 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
982 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
984 Binding *This = PROTSINK_THIS(iface);
986 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
988 if(GetCurrentThreadId() != This->apartment_thread)
989 FIXME("called from worked hread\n");
991 if(This->continue_call) {
992 report_data_task_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(report_data_task_t));
993 task->bscf = grfBSCF;
994 task->progress = ulProgress;
995 task->progress_max = ulProgressMax;
997 push_task(This, &task->header, report_data_proc);
998 }else {
999 report_data(This, grfBSCF, ulProgress, ulProgressMax);
1002 return S_OK;
1005 static void report_result_proc(Binding *binding, task_header_t *t)
1007 IInternetProtocol_Terminate(binding->protocol, 0);
1009 if(binding->request_locked) {
1010 IInternetProtocol_UnlockRequest(binding->protocol);
1011 binding->request_locked = FALSE;
1014 HeapFree(GetProcessHeap(), 0, t);
1017 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1018 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1020 Binding *This = PROTSINK_THIS(iface);
1022 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1024 if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
1025 IInternetProtocol_Terminate(This->protocol, 0);
1026 }else {
1027 task_header_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(task_header_t));
1028 push_task(This, task, report_result_proc);
1031 return S_OK;
1034 #undef PROTSINK_THIS
1036 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1037 InternetProtocolSink_QueryInterface,
1038 InternetProtocolSink_AddRef,
1039 InternetProtocolSink_Release,
1040 InternetProtocolSink_Switch,
1041 InternetProtocolSink_ReportProgress,
1042 InternetProtocolSink_ReportData,
1043 InternetProtocolSink_ReportResult
1046 #define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
1048 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
1049 REFIID riid, void **ppv)
1051 Binding *This = BINDINF_THIS(iface);
1052 return IBinding_QueryInterface(BINDING(This), riid, ppv);
1055 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
1057 Binding *This = BINDINF_THIS(iface);
1058 return IBinding_AddRef(BINDING(This));
1061 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
1063 Binding *This = BINDINF_THIS(iface);
1064 return IBinding_Release(BINDING(This));
1067 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
1068 DWORD *grfBINDF, BINDINFO *pbindinfo)
1070 Binding *This = BINDINF_THIS(iface);
1072 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1074 *grfBINDF = This->bindf;
1076 memcpy(pbindinfo, &This->bindinfo, sizeof(BINDINFO));
1078 if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
1079 FIXME("copy strings\n");
1081 if(pbindinfo->stgmedData.pUnkForRelease)
1082 IUnknown_AddRef(pbindinfo->stgmedData.pUnkForRelease);
1084 if(pbindinfo->pUnk)
1085 IUnknown_AddRef(pbindinfo->pUnk);
1087 return S_OK;
1090 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
1091 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1093 Binding *This = BINDINF_THIS(iface);
1095 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1097 switch(ulStringType) {
1098 case BINDSTRING_ACCEPT_MIMES: {
1099 static const WCHAR wszMimes[] = {'*','/','*',0};
1101 if(!ppwzStr || !pcElFetched)
1102 return E_INVALIDARG;
1104 ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes));
1105 memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes));
1106 *pcElFetched = 1;
1107 return S_OK;
1109 case BINDSTRING_USER_AGENT: {
1110 IInternetBindInfo *bindinfo = NULL;
1111 HRESULT hres;
1113 hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo,
1114 (void**)&bindinfo);
1115 if(FAILED(hres))
1116 return hres;
1118 hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr,
1119 cEl, pcElFetched);
1120 IInternetBindInfo_Release(bindinfo);
1122 return hres;
1126 FIXME("not supported string type %d\n", ulStringType);
1127 return E_NOTIMPL;
1130 #undef BINDF_THIS
1132 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1133 InternetBindInfo_QueryInterface,
1134 InternetBindInfo_AddRef,
1135 InternetBindInfo_Release,
1136 InternetBindInfo_GetBindInfo,
1137 InternetBindInfo_GetBindString
1140 #define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
1142 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
1143 REFIID riid, void **ppv)
1145 Binding *This = SERVPROV_THIS(iface);
1146 return IBinding_QueryInterface(BINDING(This), riid, ppv);
1149 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
1151 Binding *This = SERVPROV_THIS(iface);
1152 return IBinding_AddRef(BINDING(This));
1155 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
1157 Binding *This = SERVPROV_THIS(iface);
1158 return IBinding_Release(BINDING(This));
1161 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
1162 REFGUID guidService, REFIID riid, void **ppv)
1164 Binding *This = SERVPROV_THIS(iface);
1165 HRESULT hres;
1167 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1169 if(This->service_provider) {
1170 hres = IServiceProvider_QueryService(This->service_provider, guidService,
1171 riid, ppv);
1172 if(SUCCEEDED(hres))
1173 return hres;
1176 if(IsEqualGUID(&IID_IHttpNegotiate, guidService)
1177 || IsEqualGUID(&IID_IHttpNegotiate2, guidService)) {
1178 if(!This->httpneg2_wrapper) {
1179 WARN("HttpNegotiate2Wrapper expected to be non-NULL\n");
1180 } else {
1181 if(IsEqualGUID(&IID_IHttpNegotiate, guidService))
1182 IBindStatusCallback_QueryInterface(This->callback, riid,
1183 (void **)&This->httpneg2_wrapper->http_negotiate);
1184 else
1185 IBindStatusCallback_QueryInterface(This->callback, riid,
1186 (void **)&This->httpneg2_wrapper->http_negotiate2);
1188 return IHttpNegotiate2_QueryInterface(HTTPNEG2(This->httpneg2_wrapper), riid, ppv);
1192 WARN("unknown service %s\n", debugstr_guid(guidService));
1193 return E_NOTIMPL;
1196 #undef SERVPROV_THIS
1198 static const IServiceProviderVtbl ServiceProviderVtbl = {
1199 ServiceProvider_QueryInterface,
1200 ServiceProvider_AddRef,
1201 ServiceProvider_Release,
1202 ServiceProvider_QueryService
1205 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
1207 HRESULT hres;
1209 static WCHAR wszBSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
1211 hres = IBindCtx_GetObjectParam(pbc, wszBSCBHolder, (IUnknown**)callback);
1212 if(FAILED(hres))
1213 return MK_E_SYNTAX;
1215 return S_OK;
1218 static HRESULT get_protocol(Binding *This, LPCWSTR url)
1220 IClassFactory *cf = NULL;
1221 HRESULT hres;
1223 hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetProtocol,
1224 (void**)&This->protocol);
1225 if(SUCCEEDED(hres))
1226 return S_OK;
1228 if(This->service_provider) {
1229 hres = IServiceProvider_QueryService(This->service_provider, &IID_IInternetProtocol,
1230 &IID_IInternetProtocol, (void**)&This->protocol);
1231 if(SUCCEEDED(hres))
1232 return S_OK;
1235 hres = get_protocol_handler(url, NULL, &cf);
1236 if(FAILED(hres))
1237 return hres;
1239 hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&This->protocol);
1240 IClassFactory_Release(cf);
1242 return hres;
1245 static BOOL is_urlmon_protocol(LPCWSTR url)
1247 static const WCHAR wszCdl[] = {'c','d','l'};
1248 static const WCHAR wszFile[] = {'f','i','l','e'};
1249 static const WCHAR wszFtp[] = {'f','t','p'};
1250 static const WCHAR wszGopher[] = {'g','o','p','h','e','r'};
1251 static const WCHAR wszHttp[] = {'h','t','t','p'};
1252 static const WCHAR wszHttps[] = {'h','t','t','p','s'};
1253 static const WCHAR wszMk[] = {'m','k'};
1255 static const struct {
1256 LPCWSTR scheme;
1257 int len;
1258 } protocol_list[] = {
1259 {wszCdl, sizeof(wszCdl) /sizeof(WCHAR)},
1260 {wszFile, sizeof(wszFile) /sizeof(WCHAR)},
1261 {wszFtp, sizeof(wszFtp) /sizeof(WCHAR)},
1262 {wszGopher, sizeof(wszGopher)/sizeof(WCHAR)},
1263 {wszHttp, sizeof(wszHttp) /sizeof(WCHAR)},
1264 {wszHttps, sizeof(wszHttps) /sizeof(WCHAR)},
1265 {wszMk, sizeof(wszMk) /sizeof(WCHAR)}
1268 int i, len = strlenW(url);
1270 for(i=0; i < sizeof(protocol_list)/sizeof(protocol_list[0]); i++) {
1271 if(len >= protocol_list[i].len
1272 && !memcmp(url, protocol_list[i].scheme, protocol_list[i].len*sizeof(WCHAR)))
1273 return TRUE;
1276 return FALSE;
1279 static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding)
1281 Binding *ret;
1282 int len;
1283 HRESULT hres;
1285 if(!IsEqualGUID(&IID_IStream, riid)) {
1286 FIXME("Unsupported riid %s\n", debugstr_guid(riid));
1287 return E_NOTIMPL;
1290 URLMON_LockModule();
1292 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(Binding));
1294 ret->lpBindingVtbl = &BindingVtbl;
1295 ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1296 ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
1297 ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
1299 ret->ref = 1;
1301 ret->callback = NULL;
1302 ret->protocol = NULL;
1303 ret->service_provider = NULL;
1304 ret->stream = NULL;
1305 ret->httpneg2_wrapper = NULL;
1306 ret->mime = NULL;
1307 ret->url = NULL;
1308 ret->apartment_thread = GetCurrentThreadId();
1309 ret->notif_hwnd = get_notif_hwnd();
1310 ret->report_mime = TRUE;
1311 ret->continue_call = 0;
1312 ret->request_locked = FALSE;
1313 ret->download_state = BEFORE_DOWNLOAD;
1314 ret->task_queue_head = ret->task_queue_tail = NULL;
1316 memset(&ret->bindinfo, 0, sizeof(BINDINFO));
1317 ret->bindinfo.cbSize = sizeof(BINDINFO);
1318 ret->bindf = 0;
1320 InitializeCriticalSection(&ret->section);
1321 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Binding.section");
1323 hres = get_callback(pbc, &ret->callback);
1324 if(FAILED(hres)) {
1325 WARN("Could not get IBindStatusCallback\n");
1326 IBinding_Release(BINDING(ret));
1327 return hres;
1330 IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider,
1331 (void**)&ret->service_provider);
1333 hres = get_protocol(ret, url);
1334 if(FAILED(hres)) {
1335 WARN("Could not get protocol handler\n");
1336 IBinding_Release(BINDING(ret));
1337 return hres;
1340 hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
1341 if(FAILED(hres)) {
1342 WARN("GetBindInfo failed: %08x\n", hres);
1343 IBinding_Release(BINDING(ret));
1344 return hres;
1347 dump_BINDINFO(&ret->bindinfo);
1349 ret->bindf |= BINDF_FROMURLMON;
1351 if(!is_urlmon_protocol(url))
1352 ret->bindf |= BINDF_NEEDFILE;
1354 len = strlenW(url)+1;
1355 ret->url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
1356 memcpy(ret->url, url, len*sizeof(WCHAR));
1358 ret->stream = create_stream(ret->protocol);
1359 ret->stgmed.tymed = TYMED_ISTREAM;
1360 ret->stgmed.u.pstm = STREAM(ret->stream);
1361 ret->stgmed.pUnkForRelease = (IUnknown*)BINDING(ret); /* NOTE: Windows uses other IUnknown */
1363 ret->httpneg2_wrapper = create_httpneg2_wrapper();
1365 *binding = ret;
1366 return S_OK;
1369 HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
1371 Binding *binding = NULL;
1372 HRESULT hres;
1374 *ppv = NULL;
1376 hres = Binding_Create(url, pbc, riid, &binding);
1377 if(FAILED(hres))
1378 return hres;
1380 hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, BINDING(binding));
1381 if(FAILED(hres)) {
1382 WARN("OnStartBinding failed: %08x\n", hres);
1383 IBindStatusCallback_OnStopBinding(binding->callback, 0x800c0008, NULL);
1384 IBinding_Release(BINDING(binding));
1385 return hres;
1388 hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding),
1389 BINDINF(binding), 0, 0);
1391 if(FAILED(hres)) {
1392 WARN("Start failed: %08x\n", hres);
1394 IInternetProtocol_Terminate(binding->protocol, 0);
1395 IBindStatusCallback_OnStopBinding(binding->callback, S_OK, NULL);
1396 IBinding_Release(BINDING(binding));
1398 return hres;
1401 if(binding->stream->init_buf) {
1402 if(binding->request_locked)
1403 IInternetProtocol_UnlockRequest(binding->protocol);
1405 IStream_AddRef(STREAM(binding->stream));
1406 *ppv = binding->stream;
1408 hres = S_OK;
1409 }else {
1410 hres = MK_S_ASYNCHRONOUS;
1413 IBinding_Release(BINDING(binding));
1415 return hres;