quartz: Use proper alloc/free functions for COM objects.
[wine] / dlls / urlmon / binding.c
1 /*
2  * Copyright 2005-2007 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20
21 #define COBJMACROS
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
24
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"
31
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
36
37 typedef struct Binding Binding;
38
39 struct _task_header_t;
40
41 typedef void (*task_proc_t)(Binding*, struct _task_header_t*);
42
43 typedef struct _task_header_t {
44     task_proc_t proc;
45     struct _task_header_t *next;
46 } task_header_t;
47
48 typedef struct {
49     const IStreamVtbl *lpStreamVtbl;
50
51     LONG ref;
52
53     IInternetProtocol *protocol;
54
55     BYTE buf[1024*8];
56     DWORD buf_size;
57     BOOL init_buf;
58     HRESULT hres;
59 } ProtocolStream;
60
61 typedef enum {
62     BEFORE_DOWNLOAD,
63     DOWNLOADING,
64     END_DOWNLOAD
65 } download_state_t;
66
67 struct Binding {
68     const IBindingVtbl               *lpBindingVtbl;
69     const IInternetProtocolSinkVtbl  *lpInternetProtocolSinkVtbl;
70     const IInternetBindInfoVtbl      *lpInternetBindInfoVtbl;
71     const IServiceProviderVtbl       *lpServiceProviderVtbl;
72
73     LONG ref;
74
75     IBindStatusCallback *callback;
76     IInternetProtocol *protocol;
77     IServiceProvider *service_provider;
78     ProtocolStream *stream;
79
80     BINDINFO bindinfo;
81     DWORD bindf;
82     LPWSTR mime;
83     LPWSTR url;
84     BOOL report_mime;
85     DWORD continue_call;
86     BOOL request_locked;
87     download_state_t download_state;
88
89     DWORD apartment_thread;
90     HWND notif_hwnd;
91
92     STGMEDIUM stgmed;
93
94     task_header_t *task_queue_head, *task_queue_tail;
95     CRITICAL_SECTION section;
96 };
97
98 #define BINDING(x)   ((IBinding*)               &(x)->lpBindingVtbl)
99 #define PROTSINK(x)  ((IInternetProtocolSink*)  &(x)->lpInternetProtocolSinkVtbl)
100 #define BINDINF(x)   ((IInternetBindInfo*)      &(x)->lpInternetBindInfoVtbl)
101 #define SERVPROV(x)  ((IServiceProvider*)       &(x)->lpServiceProviderVtbl)
102
103 #define STREAM(x) ((IStream*) &(x)->lpStreamVtbl)
104
105 #define WM_MK_CONTINUE   (WM_USER+101)
106
107 static void push_task(Binding *binding, task_header_t *task, task_proc_t proc)
108 {
109     task->proc = proc;
110     task->next = NULL;
111
112     EnterCriticalSection(&binding->section);
113
114     if(binding->task_queue_tail)
115         binding->task_queue_tail->next = task;
116     else
117         binding->task_queue_tail = binding->task_queue_head = task;
118
119     LeaveCriticalSection(&binding->section);
120 }
121
122 static task_header_t *pop_task(Binding *binding)
123 {
124     task_header_t *ret;
125
126     EnterCriticalSection(&binding->section);
127
128     ret = binding->task_queue_head;
129     if(ret) {
130         binding->task_queue_head = ret->next;
131         if(!binding->task_queue_head)
132             binding->task_queue_tail = NULL;
133     }
134
135     LeaveCriticalSection(&binding->section);
136
137     return ret;
138 }
139
140 static void fill_stream_buffer(ProtocolStream *This)
141 {
142     DWORD read = 0;
143
144     if(sizeof(This->buf) == This->buf_size)
145         return;
146
147     This->hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size,
148             sizeof(This->buf)-This->buf_size, &read);
149     if(SUCCEEDED(This->hres)) {
150         This->buf_size += read;
151         This->init_buf = TRUE;
152     }
153 }
154
155 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
156 {
157     if(msg == WM_MK_CONTINUE) {
158         Binding *binding = (Binding*)lParam;
159         task_header_t *task;
160
161         while((task = pop_task(binding))) {
162             binding->continue_call++;
163             task->proc(binding, task);
164             binding->continue_call--;
165         }
166
167         IBinding_Release(BINDING(binding));
168         return 0;
169     }
170
171     return DefWindowProcW(hwnd, msg, wParam, lParam);
172 }
173
174 static HWND get_notif_hwnd(void)
175 {
176     static ATOM wnd_class = 0;
177     HWND hwnd;
178
179     static const WCHAR wszURLMonikerNotificationWindow[] =
180         {'U','R','L',' ','M','o','n','i','k','e','r',' ',
181          'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
182
183     if(!wnd_class) {
184         static WNDCLASSEXW wndclass = {
185             sizeof(wndclass), 0,
186             notif_wnd_proc, 0, 0,
187             NULL, NULL, NULL, NULL, NULL,
188             wszURLMonikerNotificationWindow,
189             NULL        
190         };
191
192         wndclass.hInstance = URLMON_hInstance;
193
194         wnd_class = RegisterClassExW(&wndclass);
195         if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
196             wnd_class = 1;
197     }
198
199     hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
200                            wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
201                            NULL, URLMON_hInstance, NULL);
202
203     TRACE("hwnd = %p\n", hwnd);
204
205     return hwnd;
206 }
207
208 static void dump_BINDINFO(BINDINFO *bi)
209 {
210     static const char * const BINDINFOF_str[] = {
211         "#0",
212         "BINDINFOF_URLENCODESTGMEDDATA",
213         "BINDINFOF_URLENCODEDEXTRAINFO"
214     };
215
216     static const char * const BINDVERB_str[] = {
217         "BINDVERB_GET",
218         "BINDVERB_POST",
219         "BINDVERB_PUT",
220         "BINDVERB_CUSTOM"
221     };
222
223     TRACE("\n"
224             "BINDINFO = {\n"
225             "    %d, %s,\n"
226             "    {%d, %p, %p},\n"
227             "    %s,\n"
228             "    %s,\n"
229             "    %s,\n"
230             "    %d, %08x, %d, %d\n"
231             "    {%d %p %x},\n"
232             "    %s\n"
233             "    %p, %d\n"
234             "}\n",
235
236             bi->cbSize, debugstr_w(bi->szExtraInfo),
237             bi->stgmedData.tymed, bi->stgmedData.u.hGlobal, bi->stgmedData.pUnkForRelease,
238             bi->grfBindInfoF > BINDINFOF_URLENCODEDEXTRAINFO
239                 ? "unknown" : BINDINFOF_str[bi->grfBindInfoF],
240             bi->dwBindVerb > BINDVERB_CUSTOM
241                 ? "unknown" : BINDVERB_str[bi->dwBindVerb],
242             debugstr_w(bi->szCustomVerb),
243             bi->cbstgmedData, bi->dwOptions, bi->dwOptionsFlags, bi->dwCodePage,
244             bi->securityAttributes.nLength,
245             bi->securityAttributes.lpSecurityDescriptor,
246             bi->securityAttributes.bInheritHandle,
247             debugstr_guid(&bi->iid),
248             bi->pUnk, bi->dwReserved
249             );
250 }
251
252 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface,
253                                                    REFIID riid, void **ppv)
254 {
255     *ppv = NULL;
256
257     if(IsEqualGUID(&IID_IUnknown, riid)) {
258         TRACE("(IID_IUnknown %p)\n", ppv);
259         *ppv = iface;
260     }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
261         TRACE("(IID_IHttpNegotiate %p)\n", ppv);
262         *ppv = iface;
263     }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
264         TRACE("(IID_IHttpNegotiate2 %p)\n", ppv);
265         *ppv = iface;
266     }
267
268     if(*ppv) {
269         IHttpNegotiate2_AddRef(iface);
270         return S_OK;
271     }
272
273     WARN("Unsupported interface %s\n", debugstr_guid(riid));
274     return E_NOINTERFACE;
275 }
276
277 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
278 {
279     URLMON_LockModule();
280     return 2;
281 }
282
283 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
284 {
285     URLMON_UnlockModule();
286     return 1;
287 }
288
289 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
290         LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
291 {
292     TRACE("(%s %s %d %p)\n", debugstr_w(szURL), debugstr_w(szHeaders), dwReserved,
293           pszAdditionalHeaders);
294
295     *pszAdditionalHeaders = NULL;
296     return S_OK;
297 }
298
299 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
300         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders,
301         LPWSTR *pszAdditionalRequestHeaders)
302 {
303     TRACE("(%d %s %s %p)\n", dwResponseCode, debugstr_w(szResponseHeaders),
304           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
305
306     if(pszAdditionalRequestHeaders)
307         *pszAdditionalRequestHeaders = NULL;
308     return S_OK;
309 }
310
311 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
312         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
313 {
314     TRACE("(%p %p %ld)\n", pbSecurityId, pcbSecurityId, dwReserved);
315
316     /* That's all we have to do here */
317     return E_FAIL;
318 }
319
320 static const IHttpNegotiate2Vtbl HttpNegotiate2Vtbl = {
321     HttpNegotiate_QueryInterface,
322     HttpNegotiate_AddRef,
323     HttpNegotiate_Release,
324     HttpNegotiate_BeginningTransaction,
325     HttpNegotiate_OnResponse,
326     HttpNegotiate_GetRootSecurityId
327 };
328
329 static IHttpNegotiate2 HttpNegotiate = { &HttpNegotiate2Vtbl };
330
331 #define STREAM_THIS(iface) DEFINE_THIS(ProtocolStream, Stream, iface)
332
333 static HRESULT WINAPI ProtocolStream_QueryInterface(IStream *iface,
334                                                           REFIID riid, void **ppv)
335 {
336     ProtocolStream *This = STREAM_THIS(iface);
337
338     *ppv = NULL;
339
340     if(IsEqualGUID(&IID_IUnknown, riid)) {
341         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
342         *ppv = STREAM(This);
343     }else if(IsEqualGUID(&IID_ISequentialStream, riid)) {
344         TRACE("(%p)->(IID_ISequentialStream %p)\n", This, ppv);
345         *ppv = STREAM(This);
346     }else if(IsEqualGUID(&IID_IStream, riid)) {
347         TRACE("(%p)->(IID_IStream %p)\n", This, ppv);
348         *ppv = STREAM(This);
349     }
350
351     if(*ppv) {
352         IStream_AddRef(STREAM(This));
353         return S_OK;
354     }
355
356     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
357     return E_NOINTERFACE;
358 }
359
360 static ULONG WINAPI ProtocolStream_AddRef(IStream *iface)
361 {
362     ProtocolStream *This = STREAM_THIS(iface);
363     LONG ref = InterlockedIncrement(&This->ref);
364
365     TRACE("(%p) ref=%d\n", This, ref);
366
367     return ref;
368 }
369
370 static ULONG WINAPI ProtocolStream_Release(IStream *iface)
371 {
372     ProtocolStream *This = STREAM_THIS(iface);
373     LONG ref = InterlockedDecrement(&This->ref);
374
375     TRACE("(%p) ref=%d\n", This, ref);
376
377     if(!ref) {
378         IInternetProtocol_Release(This->protocol);
379         HeapFree(GetProcessHeap(), 0, This);
380
381         URLMON_UnlockModule();
382     }
383
384     return ref;
385 }
386
387 static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv,
388                                          ULONG cb, ULONG *pcbRead)
389 {
390     ProtocolStream *This = STREAM_THIS(iface);
391     DWORD read = 0, pread = 0;
392
393     TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbRead);
394
395     if(This->buf_size) {
396         read = cb;
397
398         if(read > This->buf_size)
399             read = This->buf_size;
400
401         memcpy(pv, This->buf, read);
402
403         if(read < This->buf_size)
404             memmove(This->buf, This->buf+read, This->buf_size-read);
405         This->buf_size -= read;
406     }
407
408     if(read == cb) {
409         *pcbRead = read;
410         return S_OK;
411     }
412
413     This->hres = IInternetProtocol_Read(This->protocol, (PBYTE)pv+read, cb-read, &pread);
414     *pcbRead = read + pread;
415
416     if(This->hres == E_PENDING)
417         return E_PENDING;
418     else if(FAILED(This->hres))
419         FIXME("Read failed: %08x\n", This->hres);
420
421     return read || pread ? S_OK : S_FALSE;
422 }
423
424 static HRESULT WINAPI ProtocolStream_Write(IStream *iface, const void *pv,
425                                           ULONG cb, ULONG *pcbWritten)
426 {
427     ProtocolStream *This = STREAM_THIS(iface);
428
429     TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbWritten);
430
431     return STG_E_ACCESSDENIED;
432 }
433
434 static HRESULT WINAPI ProtocolStream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
435                                          DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
436 {
437     ProtocolStream *This = STREAM_THIS(iface);
438     FIXME("(%p)->(%d %08x %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
439     return E_NOTIMPL;
440 }
441
442 static HRESULT WINAPI ProtocolStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
443 {
444     ProtocolStream *This = STREAM_THIS(iface);
445     FIXME("(%p)->(%d)\n", This, libNewSize.u.LowPart);
446     return E_NOTIMPL;
447 }
448
449 static HRESULT WINAPI ProtocolStream_CopyTo(IStream *iface, IStream *pstm,
450         ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
451 {
452     ProtocolStream *This = STREAM_THIS(iface);
453     FIXME("(%p)->(%p %d %p %p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten);
454     return E_NOTIMPL;
455 }
456
457 static HRESULT WINAPI ProtocolStream_Commit(IStream *iface, DWORD grfCommitFlags)
458 {
459     ProtocolStream *This = STREAM_THIS(iface);
460
461     TRACE("(%p)->(%08x)\n", This, grfCommitFlags);
462
463     return E_NOTIMPL;
464 }
465
466 static HRESULT WINAPI ProtocolStream_Revert(IStream *iface)
467 {
468     ProtocolStream *This = STREAM_THIS(iface);
469
470     TRACE("(%p)\n", This);
471
472     return E_NOTIMPL;
473 }
474
475 static HRESULT WINAPI ProtocolStream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
476                                                ULARGE_INTEGER cb, DWORD dwLockType)
477 {
478     ProtocolStream *This = STREAM_THIS(iface);
479     FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
480     return E_NOTIMPL;
481 }
482
483 static HRESULT WINAPI ProtocolStream_UnlockRegion(IStream *iface,
484         ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
485 {
486     ProtocolStream *This = STREAM_THIS(iface);
487     FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
488     return E_NOTIMPL;
489 }
490
491 static HRESULT WINAPI ProtocolStream_Stat(IStream *iface, STATSTG *pstatstg,
492                                          DWORD dwStatFlag)
493 {
494     ProtocolStream *This = STREAM_THIS(iface);
495     FIXME("(%p)->(%p %08x)\n", This, pstatstg, dwStatFlag);
496     return E_NOTIMPL;
497 }
498
499 static HRESULT WINAPI ProtocolStream_Clone(IStream *iface, IStream **ppstm)
500 {
501     ProtocolStream *This = STREAM_THIS(iface);
502     FIXME("(%p)->(%p)\n", This, ppstm);
503     return E_NOTIMPL;
504 }
505
506 #undef STREAM_THIS
507
508 static const IStreamVtbl ProtocolStreamVtbl = {
509     ProtocolStream_QueryInterface,
510     ProtocolStream_AddRef,
511     ProtocolStream_Release,
512     ProtocolStream_Read,
513     ProtocolStream_Write,
514     ProtocolStream_Seek,
515     ProtocolStream_SetSize,
516     ProtocolStream_CopyTo,
517     ProtocolStream_Commit,
518     ProtocolStream_Revert,
519     ProtocolStream_LockRegion,
520     ProtocolStream_UnlockRegion,
521     ProtocolStream_Stat,
522     ProtocolStream_Clone
523 };
524
525 #define BINDING_THIS(iface) DEFINE_THIS(Binding, Binding, iface)
526
527 static ProtocolStream *create_stream(IInternetProtocol *protocol)
528 {
529     ProtocolStream *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ProtocolStream));
530
531     ret->lpStreamVtbl = &ProtocolStreamVtbl;
532     ret->ref = 1;
533     ret->buf_size = 0;
534     ret->init_buf = FALSE;
535     ret->hres = S_OK;
536
537     IInternetProtocol_AddRef(protocol);
538     ret->protocol = protocol;
539
540     URLMON_LockModule();
541
542     return ret;
543 }
544
545 static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv)
546 {
547     Binding *This = BINDING_THIS(iface);
548
549     *ppv = NULL;
550
551     if(IsEqualGUID(&IID_IUnknown, riid)) {
552         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
553         *ppv = BINDING(This);
554     }else if(IsEqualGUID(&IID_IBinding, riid)) {
555         TRACE("(%p)->(IID_IBinding %p)\n", This, ppv);
556         *ppv = BINDING(This);
557     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
558         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
559         *ppv = PROTSINK(This);
560     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
561         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
562         *ppv = BINDINF(This);
563     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
564         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
565         *ppv = SERVPROV(This);
566     }
567
568     if(*ppv) {
569         IBinding_AddRef(BINDING(This));
570         return S_OK;
571     }
572
573     WARN("Unsupported interface %s\n", debugstr_guid(riid));
574     return E_NOINTERFACE;
575 }
576
577 static ULONG WINAPI Binding_AddRef(IBinding *iface)
578 {
579     Binding *This = BINDING_THIS(iface);
580     LONG ref = InterlockedIncrement(&This->ref);
581
582     TRACE("(%p) ref=%d\n", This, ref);
583
584     return ref;
585 }
586
587 static ULONG WINAPI Binding_Release(IBinding *iface)
588 {
589     Binding *This = BINDING_THIS(iface);
590     LONG ref = InterlockedDecrement(&This->ref);
591
592     TRACE("(%p) ref=%d\n", This, ref);
593
594     if(!ref) {
595         if (This->notif_hwnd)
596             DestroyWindow( This->notif_hwnd );
597         if(This->callback)
598             IBindStatusCallback_Release(This->callback);
599         if(This->protocol)
600             IInternetProtocol_Release(This->protocol);
601         if(This->service_provider)
602             IServiceProvider_Release(This->service_provider);
603         if(This->stream)
604             IStream_Release(STREAM(This->stream));
605
606         ReleaseBindInfo(&This->bindinfo);
607         DeleteCriticalSection(&This->section);
608         HeapFree(GetProcessHeap(), 0, This->mime);
609         HeapFree(GetProcessHeap(), 0, This->url);
610
611         HeapFree(GetProcessHeap(), 0, This);
612
613         URLMON_UnlockModule();
614     }
615
616     return ref;
617 }
618
619 static HRESULT WINAPI Binding_Abort(IBinding *iface)
620 {
621     Binding *This = BINDING_THIS(iface);
622     FIXME("(%p)\n", This);
623     return E_NOTIMPL;
624 }
625
626 static HRESULT WINAPI Binding_Suspend(IBinding *iface)
627 {
628     Binding *This = BINDING_THIS(iface);
629     FIXME("(%p)\n", This);
630     return E_NOTIMPL;
631 }
632
633 static HRESULT WINAPI Binding_Resume(IBinding *iface)
634 {
635     Binding *This = BINDING_THIS(iface);
636     FIXME("(%p)\n", This);
637     return E_NOTIMPL;
638 }
639
640 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority)
641 {
642     Binding *This = BINDING_THIS(iface);
643     FIXME("(%p)->(%d)\n", This, nPriority);
644     return E_NOTIMPL;
645 }
646
647 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority)
648 {
649     Binding *This = BINDING_THIS(iface);
650     FIXME("(%p)->(%p)\n", This, pnPriority);
651     return E_NOTIMPL;
652 }
653
654 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol,
655         DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved)
656 {
657     Binding *This = BINDING_THIS(iface);
658     FIXME("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
659     return E_NOTIMPL;
660 }
661
662 #undef BINDING_THIS
663
664 static const IBindingVtbl BindingVtbl = {
665     Binding_QueryInterface,
666     Binding_AddRef,
667     Binding_Release,
668     Binding_Abort,
669     Binding_Suspend,
670     Binding_Resume,
671     Binding_SetPriority,
672     Binding_GetPriority,
673     Binding_GetBindResult
674 };
675
676 #define PROTSINK_THIS(iface) DEFINE_THIS(Binding, InternetProtocolSink, iface)
677
678 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
679         REFIID riid, void **ppv)
680 {
681     Binding *This = PROTSINK_THIS(iface);
682     return IBinding_QueryInterface(BINDING(This), riid, ppv);
683 }
684
685 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
686 {
687     Binding *This = PROTSINK_THIS(iface);
688     return IBinding_AddRef(BINDING(This));
689 }
690
691 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
692 {
693     Binding *This = PROTSINK_THIS(iface);
694     return IBinding_Release(BINDING(This));
695 }
696
697 typedef struct {
698     task_header_t header;
699     PROTOCOLDATA *data;
700 } switch_task_t;
701
702 static void switch_proc(Binding *binding, task_header_t *t)
703 {
704     switch_task_t *task = (switch_task_t*)t;
705
706     IInternetProtocol_Continue(binding->protocol, task->data);
707
708     HeapFree(GetProcessHeap(), 0, task);
709 }
710
711 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
712         PROTOCOLDATA *pProtocolData)
713 {
714     Binding *This = PROTSINK_THIS(iface);
715     switch_task_t *task;
716
717     TRACE("(%p)->(%p)\n", This, pProtocolData);
718
719     task = HeapAlloc(GetProcessHeap(), 0, sizeof(switch_task_t));
720     task->data = pProtocolData;
721
722     push_task(This, &task->header, switch_proc);
723
724     IBinding_AddRef(BINDING(This));
725     PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
726
727     return S_OK;
728 }
729
730 typedef struct {
731     task_header_t header;
732
733     Binding *binding;
734     ULONG progress;
735     ULONG progress_max;
736     ULONG status_code;
737     LPWSTR status_text;
738 } on_progress_task_t;
739
740 static void on_progress_proc(Binding *binding, task_header_t *t)
741 {
742     on_progress_task_t *task = (on_progress_task_t*)t;
743
744     IBindStatusCallback_OnProgress(binding->callback, task->progress,
745             task->progress_max, task->status_code, task->status_text);
746
747     HeapFree(GetProcessHeap(), 0, task->status_text);
748     HeapFree(GetProcessHeap(), 0, task);
749 }
750
751 static void on_progress(Binding *This, ULONG progress, ULONG progress_max,
752                         ULONG status_code, LPCWSTR status_text)
753 {
754     on_progress_task_t *task;
755
756     if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
757         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
758                                        status_code, status_text);
759         return;
760     }
761
762     task = HeapAlloc(GetProcessHeap(), 0, sizeof(on_progress_task_t));
763
764     task->progress = progress;
765     task->progress_max = progress_max;
766     task->status_code = status_code;
767
768     if(status_text) {
769         DWORD size = (strlenW(status_text)+1)*sizeof(WCHAR);
770
771         task->status_text = HeapAlloc(GetProcessHeap(), 0, size);
772         memcpy(task->status_text, status_text, size);
773     }else {
774         task->status_text = NULL;
775     }
776
777     push_task(This, &task->header, on_progress_proc);
778
779     if(GetCurrentThreadId() != This->apartment_thread) {
780         IBinding_AddRef(BINDING(This));
781         PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
782     }
783 }
784
785 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
786         ULONG ulStatusCode, LPCWSTR szStatusText)
787 {
788     Binding *This = PROTSINK_THIS(iface);
789
790     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
791
792     switch(ulStatusCode) {
793     case BINDSTATUS_FINDINGRESOURCE:
794         on_progress(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, szStatusText);
795         break;
796     case BINDSTATUS_CONNECTING:
797         on_progress(This, 0, 0, BINDSTATUS_CONNECTING, szStatusText);
798         break;
799     case BINDSTATUS_BEGINDOWNLOADDATA:
800         fill_stream_buffer(This->stream);
801         break;
802     case BINDSTATUS_MIMETYPEAVAILABLE: {
803         int len = strlenW(szStatusText)+1;
804         This->mime = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
805         memcpy(This->mime, szStatusText, len*sizeof(WCHAR));
806         break;
807     }
808     case BINDSTATUS_SENDINGREQUEST:
809         on_progress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, szStatusText);
810         break;
811     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
812         This->report_mime = FALSE;
813         on_progress(This, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE, szStatusText);
814         break;
815     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
816         break;
817     case BINDSTATUS_DIRECTBIND:
818         This->report_mime = FALSE;
819         break;
820     default:
821         FIXME("Unhandled status code %d\n", ulStatusCode);
822         return E_NOTIMPL;
823     };
824
825     return S_OK;
826 }
827
828 static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progress_max)
829 {
830     FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM};
831
832     TRACE("(%p)->(%d %u %u)\n", This, bscf, progress, progress_max);
833
834     if(This->download_state == END_DOWNLOAD)
835         return;
836
837     if(GetCurrentThreadId() != This->apartment_thread)
838         FIXME("called from worked hread\n");
839
840     if(This->report_mime) {
841         LPWSTR mime;
842
843         This->report_mime = FALSE;
844
845         fill_stream_buffer(This->stream);
846
847         FindMimeFromData(NULL, This->url, This->stream->buf,
848                          min(This->stream->buf_size, 255), This->mime, 0, &mime, 0);
849
850         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
851                 BINDSTATUS_MIMETYPEAVAILABLE, mime);
852     }
853
854     if(This->download_state == BEFORE_DOWNLOAD) {
855         fill_stream_buffer(This->stream);
856
857         This->download_state = DOWNLOADING;
858         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
859                 BINDSTATUS_BEGINDOWNLOADDATA, This->url);
860     }
861
862     if(This->stream->hres == S_FALSE || (bscf & BSCF_LASTDATANOTIFICATION)) {
863         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
864                 BINDSTATUS_ENDDOWNLOADDATA, This->url);
865     }
866
867     if(!This->request_locked) {
868         HRESULT hres = IInternetProtocol_LockRequest(This->protocol, 0);
869         This->request_locked = SUCCEEDED(hres);
870     }
871
872     fill_stream_buffer(This->stream);
873
874     IBindStatusCallback_OnDataAvailable(This->callback, bscf, This->stream->buf_size,
875             &formatetc, &This->stgmed);
876
877     if(This->stream->hres == S_FALSE) {
878         This->download_state = END_DOWNLOAD;
879         IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL);
880     }
881 }
882
883 typedef struct {
884     task_header_t header;
885     DWORD bscf;
886     ULONG progress;
887     ULONG progress_max;
888 } report_data_task_t;
889
890 static void report_data_proc(Binding *binding, task_header_t *t)
891 {
892     report_data_task_t *task = (report_data_task_t*)t;
893
894     report_data(binding, task->bscf, task->progress, task->progress_max);
895
896     HeapFree(GetProcessHeap(), 0, task);
897 }
898
899 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
900         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
901 {
902     Binding *This = PROTSINK_THIS(iface);
903
904     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
905
906     if(GetCurrentThreadId() != This->apartment_thread)
907         FIXME("called from worked hread\n");
908
909     if(This->continue_call) {
910         report_data_task_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(report_data_task_t));
911         task->bscf = grfBSCF;
912         task->progress = ulProgress;
913         task->progress_max = ulProgressMax;
914
915         push_task(This, &task->header, report_data_proc);
916     }else {
917         report_data(This, grfBSCF, ulProgress, ulProgressMax);
918     }
919
920     return S_OK;
921 }
922
923 static void report_result_proc(Binding *binding, task_header_t *t)
924 {
925     IInternetProtocol_Terminate(binding->protocol, 0);
926
927     if(binding->request_locked) {
928         IInternetProtocol_UnlockRequest(binding->protocol);
929         binding->request_locked = FALSE;
930     }
931
932     HeapFree(GetProcessHeap(), 0, t);
933 }
934
935 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
936         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
937 {
938     Binding *This = PROTSINK_THIS(iface);
939
940     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
941
942     if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
943         IInternetProtocol_Terminate(This->protocol, 0);
944     }else {
945         task_header_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(task_header_t));
946         push_task(This, task, report_result_proc);
947     }
948
949     return S_OK;
950 }
951
952 #undef PROTSINK_THIS
953
954 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
955     InternetProtocolSink_QueryInterface,
956     InternetProtocolSink_AddRef,
957     InternetProtocolSink_Release,
958     InternetProtocolSink_Switch,
959     InternetProtocolSink_ReportProgress,
960     InternetProtocolSink_ReportData,
961     InternetProtocolSink_ReportResult
962 };
963
964 #define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
965
966 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
967         REFIID riid, void **ppv)
968 {
969     Binding *This = BINDINF_THIS(iface);
970     return IBinding_QueryInterface(BINDING(This), riid, ppv);
971 }
972
973 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
974 {
975     Binding *This = BINDINF_THIS(iface);
976     return IBinding_AddRef(BINDING(This));
977 }
978
979 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
980 {
981     Binding *This = BINDINF_THIS(iface);
982     return IBinding_Release(BINDING(This));
983 }
984
985 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
986         DWORD *grfBINDF, BINDINFO *pbindinfo)
987 {
988     Binding *This = BINDINF_THIS(iface);
989
990     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
991
992     *grfBINDF = This->bindf;
993
994     memcpy(pbindinfo, &This->bindinfo, sizeof(BINDINFO));
995
996     if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
997         FIXME("copy strings\n");
998
999     if(pbindinfo->pUnk)
1000         IUnknown_AddRef(pbindinfo->pUnk);
1001
1002     return S_OK;
1003 }
1004
1005 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
1006         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1007 {
1008     Binding *This = BINDINF_THIS(iface);
1009
1010     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1011
1012     switch(ulStringType) {
1013     case BINDSTRING_ACCEPT_MIMES: {
1014         static const WCHAR wszMimes[] = {'*','/','*',0};
1015
1016         if(!ppwzStr || !pcElFetched)
1017             return E_INVALIDARG;
1018
1019         ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes));
1020         memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes));
1021         *pcElFetched = 1;
1022         return S_OK;
1023     }
1024     case BINDSTRING_USER_AGENT: {
1025         IInternetBindInfo *bindinfo = NULL;
1026         HRESULT hres;
1027
1028         hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo,
1029                                                   (void**)&bindinfo);
1030         if(FAILED(hres))
1031             return hres;
1032
1033         hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr,
1034                                                cEl, pcElFetched);
1035         IInternetBindInfo_Release(bindinfo);
1036
1037         return hres;
1038     }
1039     }
1040
1041     FIXME("not supported string type %d\n", ulStringType);
1042     return E_NOTIMPL;
1043 }
1044
1045 #undef BINDF_THIS
1046
1047 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1048     InternetBindInfo_QueryInterface,
1049     InternetBindInfo_AddRef,
1050     InternetBindInfo_Release,
1051     InternetBindInfo_GetBindInfo,
1052     InternetBindInfo_GetBindString
1053 };
1054
1055 #define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
1056
1057 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
1058         REFIID riid, void **ppv)
1059 {
1060     Binding *This = SERVPROV_THIS(iface);
1061     return IBinding_QueryInterface(BINDING(This), riid, ppv);
1062 }
1063
1064 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
1065 {
1066     Binding *This = SERVPROV_THIS(iface);
1067     return IBinding_AddRef(BINDING(This));
1068 }
1069
1070 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
1071 {
1072     Binding *This = SERVPROV_THIS(iface);
1073     return IBinding_Release(BINDING(This));
1074 }
1075
1076 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
1077         REFGUID guidService, REFIID riid, void **ppv)
1078 {
1079     Binding *This = SERVPROV_THIS(iface);
1080     HRESULT hres;
1081
1082     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1083
1084     if(This->service_provider) {
1085         hres = IServiceProvider_QueryService(This->service_provider, guidService,
1086                                              riid, ppv);
1087         if(SUCCEEDED(hres))
1088             return hres;
1089     }
1090
1091     if(IsEqualGUID(&IID_IHttpNegotiate, guidService)
1092        || IsEqualGUID(&IID_IHttpNegotiate2, guidService))
1093         return IHttpNegotiate2_QueryInterface(&HttpNegotiate, riid, ppv);
1094
1095     WARN("unknown service %s\n", debugstr_guid(guidService));
1096     return E_NOTIMPL;
1097 }
1098
1099 #undef SERVPROV_THIS
1100
1101 static const IServiceProviderVtbl ServiceProviderVtbl = {
1102     ServiceProvider_QueryInterface,
1103     ServiceProvider_AddRef,
1104     ServiceProvider_Release,
1105     ServiceProvider_QueryService
1106 };
1107
1108 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
1109 {
1110     HRESULT hres;
1111
1112     static WCHAR wszBSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
1113
1114     hres = IBindCtx_GetObjectParam(pbc, wszBSCBHolder, (IUnknown**)callback);
1115     if(FAILED(hres))
1116         return MK_E_SYNTAX;
1117
1118     return S_OK;
1119 }
1120
1121 static HRESULT get_protocol(Binding *This, LPCWSTR url)
1122 {
1123     IClassFactory *cf = NULL;
1124     HRESULT hres;
1125
1126     hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetProtocol,
1127             (void**)&This->protocol);
1128     if(SUCCEEDED(hres))
1129         return S_OK;
1130
1131     if(This->service_provider) {
1132         hres = IServiceProvider_QueryService(This->service_provider, &IID_IInternetProtocol,
1133                 &IID_IInternetProtocol, (void**)&This->protocol);
1134         if(SUCCEEDED(hres))
1135             return S_OK;
1136     }
1137
1138     hres = get_protocol_handler(url, NULL, &cf);
1139     if(FAILED(hres))
1140         return hres;
1141
1142     hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&This->protocol);
1143     IClassFactory_Release(cf);
1144
1145     return hres;
1146 }
1147
1148 static BOOL is_urlmon_protocol(LPCWSTR url)
1149 {
1150     static const WCHAR wszCdl[] = {'c','d','l'};
1151     static const WCHAR wszFile[] = {'f','i','l','e'};
1152     static const WCHAR wszFtp[]  = {'f','t','p'};
1153     static const WCHAR wszGopher[] = {'g','o','p','h','e','r'};
1154     static const WCHAR wszHttp[] = {'h','t','t','p'};
1155     static const WCHAR wszHttps[] = {'h','t','t','p','s'};
1156     static const WCHAR wszMk[]   = {'m','k'};
1157
1158     static const struct {
1159         LPCWSTR scheme;
1160         int len;
1161     } protocol_list[] = {
1162         {wszCdl,    sizeof(wszCdl)   /sizeof(WCHAR)},
1163         {wszFile,   sizeof(wszFile)  /sizeof(WCHAR)},
1164         {wszFtp,    sizeof(wszFtp)   /sizeof(WCHAR)},
1165         {wszGopher, sizeof(wszGopher)/sizeof(WCHAR)},
1166         {wszHttp,   sizeof(wszHttp)  /sizeof(WCHAR)},
1167         {wszHttps,  sizeof(wszHttps) /sizeof(WCHAR)},
1168         {wszMk,     sizeof(wszMk)    /sizeof(WCHAR)}
1169     };
1170
1171     int i, len = strlenW(url);
1172
1173     for(i=0; i < sizeof(protocol_list)/sizeof(protocol_list[0]); i++) {
1174         if(len >= protocol_list[i].len
1175            && !memcmp(url, protocol_list[i].scheme, protocol_list[i].len*sizeof(WCHAR)))
1176             return TRUE;
1177     }
1178
1179     return FALSE;
1180 }
1181
1182 static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding)
1183 {
1184     Binding *ret;
1185     int len;
1186     HRESULT hres;
1187
1188     if(!IsEqualGUID(&IID_IStream, riid)) {
1189         FIXME("Unsupported riid %s\n", debugstr_guid(riid));
1190         return E_NOTIMPL;
1191     }
1192
1193     URLMON_LockModule();
1194
1195     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(Binding));
1196
1197     ret->lpBindingVtbl              = &BindingVtbl;
1198     ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1199     ret->lpInternetBindInfoVtbl     = &InternetBindInfoVtbl;
1200     ret->lpServiceProviderVtbl      = &ServiceProviderVtbl;
1201
1202     ret->ref = 1;
1203
1204     ret->callback = NULL;
1205     ret->protocol = NULL;
1206     ret->service_provider = NULL;
1207     ret->stream = NULL;
1208     ret->mime = NULL;
1209     ret->url = NULL;
1210     ret->apartment_thread = GetCurrentThreadId();
1211     ret->notif_hwnd = get_notif_hwnd();
1212     ret->report_mime = TRUE;
1213     ret->continue_call = 0;
1214     ret->request_locked = FALSE;
1215     ret->download_state = BEFORE_DOWNLOAD;
1216     ret->task_queue_head = ret->task_queue_tail = NULL;
1217
1218     memset(&ret->bindinfo, 0, sizeof(BINDINFO));
1219     ret->bindinfo.cbSize = sizeof(BINDINFO);
1220     ret->bindf = 0;
1221
1222     InitializeCriticalSection(&ret->section);
1223
1224     hres = get_callback(pbc, &ret->callback);
1225     if(FAILED(hres)) {
1226         WARN("Could not get IBindStatusCallback\n");
1227         IBinding_Release(BINDING(ret));
1228         return hres;
1229     }
1230
1231     IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider,
1232                                        (void**)&ret->service_provider);
1233
1234     hres = get_protocol(ret, url);
1235     if(FAILED(hres)) {
1236         WARN("Could not get protocol handler\n");
1237         IBinding_Release(BINDING(ret));
1238         return hres;
1239     }
1240
1241     hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
1242     if(FAILED(hres)) {
1243         WARN("GetBindInfo failed: %08x\n", hres);
1244         IBinding_Release(BINDING(ret));
1245         return hres;
1246     }
1247
1248     dump_BINDINFO(&ret->bindinfo);
1249
1250     ret->bindf |= BINDF_FROMURLMON;
1251
1252     if(!is_urlmon_protocol(url))
1253         ret->bindf |= BINDF_NEEDFILE;
1254
1255     len = strlenW(url)+1;
1256     ret->url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
1257     memcpy(ret->url, url, len*sizeof(WCHAR));
1258
1259     ret->stream = create_stream(ret->protocol);
1260     ret->stgmed.tymed = TYMED_ISTREAM;
1261     ret->stgmed.u.pstm = STREAM(ret->stream);
1262     ret->stgmed.pUnkForRelease = (IUnknown*)BINDING(ret); /* NOTE: Windows uses other IUnknown */
1263
1264     *binding = ret;
1265     return S_OK;
1266 }
1267
1268 HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
1269 {
1270     Binding *binding = NULL;
1271     HRESULT hres;
1272
1273     *ppv = NULL;
1274
1275     hres = Binding_Create(url, pbc, riid, &binding);
1276     if(FAILED(hres))
1277         return hres;
1278
1279     hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, BINDING(binding));
1280     if(FAILED(hres)) {
1281         WARN("OnStartBinding failed: %08x\n", hres);
1282         IBindStatusCallback_OnStopBinding(binding->callback, 0x800c0008, NULL);
1283         IBinding_Release(BINDING(binding));
1284         return hres;
1285     }
1286
1287     hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding),
1288              BINDINF(binding), 0, 0);
1289
1290     if(FAILED(hres)) {
1291         WARN("Start failed: %08x\n", hres);
1292
1293         IInternetProtocol_Terminate(binding->protocol, 0);
1294         IBindStatusCallback_OnStopBinding(binding->callback, S_OK, NULL);
1295         IBinding_Release(BINDING(binding));
1296
1297         return hres;
1298     }
1299
1300     if(binding->stream->init_buf) {
1301         if(binding->request_locked)
1302             IInternetProtocol_UnlockRequest(binding->protocol);
1303
1304         IStream_AddRef(STREAM(binding->stream));
1305         *ppv = binding->stream;
1306
1307         hres = S_OK;
1308     }else {
1309         hres = MK_S_ASYNCHRONOUS;
1310     }
1311
1312     IBinding_Release(BINDING(binding));
1313
1314     return hres;
1315 }