gdi32/tests: Fix a signed/unsigned int mismatch.
[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         This->section.DebugInfo->Spare[0] = 0;
608         DeleteCriticalSection(&This->section);
609         HeapFree(GetProcessHeap(), 0, This->mime);
610         HeapFree(GetProcessHeap(), 0, This->url);
611
612         HeapFree(GetProcessHeap(), 0, This);
613
614         URLMON_UnlockModule();
615     }
616
617     return ref;
618 }
619
620 static HRESULT WINAPI Binding_Abort(IBinding *iface)
621 {
622     Binding *This = BINDING_THIS(iface);
623     FIXME("(%p)\n", This);
624     return E_NOTIMPL;
625 }
626
627 static HRESULT WINAPI Binding_Suspend(IBinding *iface)
628 {
629     Binding *This = BINDING_THIS(iface);
630     FIXME("(%p)\n", This);
631     return E_NOTIMPL;
632 }
633
634 static HRESULT WINAPI Binding_Resume(IBinding *iface)
635 {
636     Binding *This = BINDING_THIS(iface);
637     FIXME("(%p)\n", This);
638     return E_NOTIMPL;
639 }
640
641 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority)
642 {
643     Binding *This = BINDING_THIS(iface);
644     FIXME("(%p)->(%d)\n", This, nPriority);
645     return E_NOTIMPL;
646 }
647
648 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority)
649 {
650     Binding *This = BINDING_THIS(iface);
651     FIXME("(%p)->(%p)\n", This, pnPriority);
652     return E_NOTIMPL;
653 }
654
655 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol,
656         DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved)
657 {
658     Binding *This = BINDING_THIS(iface);
659     FIXME("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
660     return E_NOTIMPL;
661 }
662
663 #undef BINDING_THIS
664
665 static const IBindingVtbl BindingVtbl = {
666     Binding_QueryInterface,
667     Binding_AddRef,
668     Binding_Release,
669     Binding_Abort,
670     Binding_Suspend,
671     Binding_Resume,
672     Binding_SetPriority,
673     Binding_GetPriority,
674     Binding_GetBindResult
675 };
676
677 #define PROTSINK_THIS(iface) DEFINE_THIS(Binding, InternetProtocolSink, iface)
678
679 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
680         REFIID riid, void **ppv)
681 {
682     Binding *This = PROTSINK_THIS(iface);
683     return IBinding_QueryInterface(BINDING(This), riid, ppv);
684 }
685
686 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
687 {
688     Binding *This = PROTSINK_THIS(iface);
689     return IBinding_AddRef(BINDING(This));
690 }
691
692 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
693 {
694     Binding *This = PROTSINK_THIS(iface);
695     return IBinding_Release(BINDING(This));
696 }
697
698 typedef struct {
699     task_header_t header;
700     PROTOCOLDATA *data;
701 } switch_task_t;
702
703 static void switch_proc(Binding *binding, task_header_t *t)
704 {
705     switch_task_t *task = (switch_task_t*)t;
706
707     IInternetProtocol_Continue(binding->protocol, task->data);
708
709     HeapFree(GetProcessHeap(), 0, task);
710 }
711
712 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
713         PROTOCOLDATA *pProtocolData)
714 {
715     Binding *This = PROTSINK_THIS(iface);
716     switch_task_t *task;
717
718     TRACE("(%p)->(%p)\n", This, pProtocolData);
719
720     task = HeapAlloc(GetProcessHeap(), 0, sizeof(switch_task_t));
721     task->data = pProtocolData;
722
723     push_task(This, &task->header, switch_proc);
724
725     IBinding_AddRef(BINDING(This));
726     PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
727
728     return S_OK;
729 }
730
731 typedef struct {
732     task_header_t header;
733
734     Binding *binding;
735     ULONG progress;
736     ULONG progress_max;
737     ULONG status_code;
738     LPWSTR status_text;
739 } on_progress_task_t;
740
741 static void on_progress_proc(Binding *binding, task_header_t *t)
742 {
743     on_progress_task_t *task = (on_progress_task_t*)t;
744
745     IBindStatusCallback_OnProgress(binding->callback, task->progress,
746             task->progress_max, task->status_code, task->status_text);
747
748     HeapFree(GetProcessHeap(), 0, task->status_text);
749     HeapFree(GetProcessHeap(), 0, task);
750 }
751
752 static void on_progress(Binding *This, ULONG progress, ULONG progress_max,
753                         ULONG status_code, LPCWSTR status_text)
754 {
755     on_progress_task_t *task;
756
757     if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
758         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
759                                        status_code, status_text);
760         return;
761     }
762
763     task = HeapAlloc(GetProcessHeap(), 0, sizeof(on_progress_task_t));
764
765     task->progress = progress;
766     task->progress_max = progress_max;
767     task->status_code = status_code;
768
769     if(status_text) {
770         DWORD size = (strlenW(status_text)+1)*sizeof(WCHAR);
771
772         task->status_text = HeapAlloc(GetProcessHeap(), 0, size);
773         memcpy(task->status_text, status_text, size);
774     }else {
775         task->status_text = NULL;
776     }
777
778     push_task(This, &task->header, on_progress_proc);
779
780     if(GetCurrentThreadId() != This->apartment_thread) {
781         IBinding_AddRef(BINDING(This));
782         PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
783     }
784 }
785
786 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
787         ULONG ulStatusCode, LPCWSTR szStatusText)
788 {
789     Binding *This = PROTSINK_THIS(iface);
790
791     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
792
793     switch(ulStatusCode) {
794     case BINDSTATUS_FINDINGRESOURCE:
795         on_progress(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, szStatusText);
796         break;
797     case BINDSTATUS_CONNECTING:
798         on_progress(This, 0, 0, BINDSTATUS_CONNECTING, szStatusText);
799         break;
800     case BINDSTATUS_BEGINDOWNLOADDATA:
801         fill_stream_buffer(This->stream);
802         break;
803     case BINDSTATUS_MIMETYPEAVAILABLE: {
804         int len = strlenW(szStatusText)+1;
805         This->mime = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
806         memcpy(This->mime, szStatusText, len*sizeof(WCHAR));
807         break;
808     }
809     case BINDSTATUS_SENDINGREQUEST:
810         on_progress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, szStatusText);
811         break;
812     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
813         This->report_mime = FALSE;
814         on_progress(This, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE, szStatusText);
815         break;
816     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
817         break;
818     case BINDSTATUS_DIRECTBIND:
819         This->report_mime = FALSE;
820         break;
821     default:
822         FIXME("Unhandled status code %d\n", ulStatusCode);
823         return E_NOTIMPL;
824     };
825
826     return S_OK;
827 }
828
829 static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progress_max)
830 {
831     FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM};
832
833     TRACE("(%p)->(%d %u %u)\n", This, bscf, progress, progress_max);
834
835     if(This->download_state == END_DOWNLOAD)
836         return;
837
838     if(GetCurrentThreadId() != This->apartment_thread)
839         FIXME("called from worked hread\n");
840
841     if(This->report_mime) {
842         LPWSTR mime;
843
844         This->report_mime = FALSE;
845
846         fill_stream_buffer(This->stream);
847
848         FindMimeFromData(NULL, This->url, This->stream->buf,
849                          min(This->stream->buf_size, 255), This->mime, 0, &mime, 0);
850
851         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
852                 BINDSTATUS_MIMETYPEAVAILABLE, mime);
853     }
854
855     if(This->download_state == BEFORE_DOWNLOAD) {
856         fill_stream_buffer(This->stream);
857
858         This->download_state = DOWNLOADING;
859         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
860                 BINDSTATUS_BEGINDOWNLOADDATA, This->url);
861     }
862
863     if(This->stream->hres == S_FALSE || (bscf & BSCF_LASTDATANOTIFICATION)) {
864         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
865                 BINDSTATUS_ENDDOWNLOADDATA, This->url);
866     }
867
868     if(!This->request_locked) {
869         HRESULT hres = IInternetProtocol_LockRequest(This->protocol, 0);
870         This->request_locked = SUCCEEDED(hres);
871     }
872
873     fill_stream_buffer(This->stream);
874
875     IBindStatusCallback_OnDataAvailable(This->callback, bscf, This->stream->buf_size,
876             &formatetc, &This->stgmed);
877
878     if(This->stream->hres == S_FALSE) {
879         This->download_state = END_DOWNLOAD;
880         IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL);
881     }
882 }
883
884 typedef struct {
885     task_header_t header;
886     DWORD bscf;
887     ULONG progress;
888     ULONG progress_max;
889 } report_data_task_t;
890
891 static void report_data_proc(Binding *binding, task_header_t *t)
892 {
893     report_data_task_t *task = (report_data_task_t*)t;
894
895     report_data(binding, task->bscf, task->progress, task->progress_max);
896
897     HeapFree(GetProcessHeap(), 0, task);
898 }
899
900 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
901         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
902 {
903     Binding *This = PROTSINK_THIS(iface);
904
905     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
906
907     if(GetCurrentThreadId() != This->apartment_thread)
908         FIXME("called from worked hread\n");
909
910     if(This->continue_call) {
911         report_data_task_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(report_data_task_t));
912         task->bscf = grfBSCF;
913         task->progress = ulProgress;
914         task->progress_max = ulProgressMax;
915
916         push_task(This, &task->header, report_data_proc);
917     }else {
918         report_data(This, grfBSCF, ulProgress, ulProgressMax);
919     }
920
921     return S_OK;
922 }
923
924 static void report_result_proc(Binding *binding, task_header_t *t)
925 {
926     IInternetProtocol_Terminate(binding->protocol, 0);
927
928     if(binding->request_locked) {
929         IInternetProtocol_UnlockRequest(binding->protocol);
930         binding->request_locked = FALSE;
931     }
932
933     HeapFree(GetProcessHeap(), 0, t);
934 }
935
936 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
937         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
938 {
939     Binding *This = PROTSINK_THIS(iface);
940
941     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
942
943     if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
944         IInternetProtocol_Terminate(This->protocol, 0);
945     }else {
946         task_header_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(task_header_t));
947         push_task(This, task, report_result_proc);
948     }
949
950     return S_OK;
951 }
952
953 #undef PROTSINK_THIS
954
955 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
956     InternetProtocolSink_QueryInterface,
957     InternetProtocolSink_AddRef,
958     InternetProtocolSink_Release,
959     InternetProtocolSink_Switch,
960     InternetProtocolSink_ReportProgress,
961     InternetProtocolSink_ReportData,
962     InternetProtocolSink_ReportResult
963 };
964
965 #define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
966
967 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
968         REFIID riid, void **ppv)
969 {
970     Binding *This = BINDINF_THIS(iface);
971     return IBinding_QueryInterface(BINDING(This), riid, ppv);
972 }
973
974 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
975 {
976     Binding *This = BINDINF_THIS(iface);
977     return IBinding_AddRef(BINDING(This));
978 }
979
980 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
981 {
982     Binding *This = BINDINF_THIS(iface);
983     return IBinding_Release(BINDING(This));
984 }
985
986 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
987         DWORD *grfBINDF, BINDINFO *pbindinfo)
988 {
989     Binding *This = BINDINF_THIS(iface);
990
991     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
992
993     *grfBINDF = This->bindf;
994
995     memcpy(pbindinfo, &This->bindinfo, sizeof(BINDINFO));
996
997     if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
998         FIXME("copy strings\n");
999
1000     if(pbindinfo->pUnk)
1001         IUnknown_AddRef(pbindinfo->pUnk);
1002
1003     return S_OK;
1004 }
1005
1006 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
1007         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1008 {
1009     Binding *This = BINDINF_THIS(iface);
1010
1011     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1012
1013     switch(ulStringType) {
1014     case BINDSTRING_ACCEPT_MIMES: {
1015         static const WCHAR wszMimes[] = {'*','/','*',0};
1016
1017         if(!ppwzStr || !pcElFetched)
1018             return E_INVALIDARG;
1019
1020         ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes));
1021         memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes));
1022         *pcElFetched = 1;
1023         return S_OK;
1024     }
1025     case BINDSTRING_USER_AGENT: {
1026         IInternetBindInfo *bindinfo = NULL;
1027         HRESULT hres;
1028
1029         hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo,
1030                                                   (void**)&bindinfo);
1031         if(FAILED(hres))
1032             return hres;
1033
1034         hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr,
1035                                                cEl, pcElFetched);
1036         IInternetBindInfo_Release(bindinfo);
1037
1038         return hres;
1039     }
1040     }
1041
1042     FIXME("not supported string type %d\n", ulStringType);
1043     return E_NOTIMPL;
1044 }
1045
1046 #undef BINDF_THIS
1047
1048 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1049     InternetBindInfo_QueryInterface,
1050     InternetBindInfo_AddRef,
1051     InternetBindInfo_Release,
1052     InternetBindInfo_GetBindInfo,
1053     InternetBindInfo_GetBindString
1054 };
1055
1056 #define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
1057
1058 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
1059         REFIID riid, void **ppv)
1060 {
1061     Binding *This = SERVPROV_THIS(iface);
1062     return IBinding_QueryInterface(BINDING(This), riid, ppv);
1063 }
1064
1065 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
1066 {
1067     Binding *This = SERVPROV_THIS(iface);
1068     return IBinding_AddRef(BINDING(This));
1069 }
1070
1071 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
1072 {
1073     Binding *This = SERVPROV_THIS(iface);
1074     return IBinding_Release(BINDING(This));
1075 }
1076
1077 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
1078         REFGUID guidService, REFIID riid, void **ppv)
1079 {
1080     Binding *This = SERVPROV_THIS(iface);
1081     HRESULT hres;
1082
1083     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1084
1085     if(This->service_provider) {
1086         hres = IServiceProvider_QueryService(This->service_provider, guidService,
1087                                              riid, ppv);
1088         if(SUCCEEDED(hres))
1089             return hres;
1090     }
1091
1092     if(IsEqualGUID(&IID_IHttpNegotiate, guidService)
1093        || IsEqualGUID(&IID_IHttpNegotiate2, guidService))
1094         return IHttpNegotiate2_QueryInterface(&HttpNegotiate, riid, ppv);
1095
1096     WARN("unknown service %s\n", debugstr_guid(guidService));
1097     return E_NOTIMPL;
1098 }
1099
1100 #undef SERVPROV_THIS
1101
1102 static const IServiceProviderVtbl ServiceProviderVtbl = {
1103     ServiceProvider_QueryInterface,
1104     ServiceProvider_AddRef,
1105     ServiceProvider_Release,
1106     ServiceProvider_QueryService
1107 };
1108
1109 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
1110 {
1111     HRESULT hres;
1112
1113     static WCHAR wszBSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
1114
1115     hres = IBindCtx_GetObjectParam(pbc, wszBSCBHolder, (IUnknown**)callback);
1116     if(FAILED(hres))
1117         return MK_E_SYNTAX;
1118
1119     return S_OK;
1120 }
1121
1122 static HRESULT get_protocol(Binding *This, LPCWSTR url)
1123 {
1124     IClassFactory *cf = NULL;
1125     HRESULT hres;
1126
1127     hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetProtocol,
1128             (void**)&This->protocol);
1129     if(SUCCEEDED(hres))
1130         return S_OK;
1131
1132     if(This->service_provider) {
1133         hres = IServiceProvider_QueryService(This->service_provider, &IID_IInternetProtocol,
1134                 &IID_IInternetProtocol, (void**)&This->protocol);
1135         if(SUCCEEDED(hres))
1136             return S_OK;
1137     }
1138
1139     hres = get_protocol_handler(url, NULL, &cf);
1140     if(FAILED(hres))
1141         return hres;
1142
1143     hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&This->protocol);
1144     IClassFactory_Release(cf);
1145
1146     return hres;
1147 }
1148
1149 static BOOL is_urlmon_protocol(LPCWSTR url)
1150 {
1151     static const WCHAR wszCdl[] = {'c','d','l'};
1152     static const WCHAR wszFile[] = {'f','i','l','e'};
1153     static const WCHAR wszFtp[]  = {'f','t','p'};
1154     static const WCHAR wszGopher[] = {'g','o','p','h','e','r'};
1155     static const WCHAR wszHttp[] = {'h','t','t','p'};
1156     static const WCHAR wszHttps[] = {'h','t','t','p','s'};
1157     static const WCHAR wszMk[]   = {'m','k'};
1158
1159     static const struct {
1160         LPCWSTR scheme;
1161         int len;
1162     } protocol_list[] = {
1163         {wszCdl,    sizeof(wszCdl)   /sizeof(WCHAR)},
1164         {wszFile,   sizeof(wszFile)  /sizeof(WCHAR)},
1165         {wszFtp,    sizeof(wszFtp)   /sizeof(WCHAR)},
1166         {wszGopher, sizeof(wszGopher)/sizeof(WCHAR)},
1167         {wszHttp,   sizeof(wszHttp)  /sizeof(WCHAR)},
1168         {wszHttps,  sizeof(wszHttps) /sizeof(WCHAR)},
1169         {wszMk,     sizeof(wszMk)    /sizeof(WCHAR)}
1170     };
1171
1172     int i, len = strlenW(url);
1173
1174     for(i=0; i < sizeof(protocol_list)/sizeof(protocol_list[0]); i++) {
1175         if(len >= protocol_list[i].len
1176            && !memcmp(url, protocol_list[i].scheme, protocol_list[i].len*sizeof(WCHAR)))
1177             return TRUE;
1178     }
1179
1180     return FALSE;
1181 }
1182
1183 static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding)
1184 {
1185     Binding *ret;
1186     int len;
1187     HRESULT hres;
1188
1189     if(!IsEqualGUID(&IID_IStream, riid)) {
1190         FIXME("Unsupported riid %s\n", debugstr_guid(riid));
1191         return E_NOTIMPL;
1192     }
1193
1194     URLMON_LockModule();
1195
1196     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(Binding));
1197
1198     ret->lpBindingVtbl              = &BindingVtbl;
1199     ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1200     ret->lpInternetBindInfoVtbl     = &InternetBindInfoVtbl;
1201     ret->lpServiceProviderVtbl      = &ServiceProviderVtbl;
1202
1203     ret->ref = 1;
1204
1205     ret->callback = NULL;
1206     ret->protocol = NULL;
1207     ret->service_provider = NULL;
1208     ret->stream = NULL;
1209     ret->mime = NULL;
1210     ret->url = NULL;
1211     ret->apartment_thread = GetCurrentThreadId();
1212     ret->notif_hwnd = get_notif_hwnd();
1213     ret->report_mime = TRUE;
1214     ret->continue_call = 0;
1215     ret->request_locked = FALSE;
1216     ret->download_state = BEFORE_DOWNLOAD;
1217     ret->task_queue_head = ret->task_queue_tail = NULL;
1218
1219     memset(&ret->bindinfo, 0, sizeof(BINDINFO));
1220     ret->bindinfo.cbSize = sizeof(BINDINFO);
1221     ret->bindf = 0;
1222
1223     InitializeCriticalSection(&ret->section);
1224     ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Binding.section");
1225
1226     hres = get_callback(pbc, &ret->callback);
1227     if(FAILED(hres)) {
1228         WARN("Could not get IBindStatusCallback\n");
1229         IBinding_Release(BINDING(ret));
1230         return hres;
1231     }
1232
1233     IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider,
1234                                        (void**)&ret->service_provider);
1235
1236     hres = get_protocol(ret, url);
1237     if(FAILED(hres)) {
1238         WARN("Could not get protocol handler\n");
1239         IBinding_Release(BINDING(ret));
1240         return hres;
1241     }
1242
1243     hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
1244     if(FAILED(hres)) {
1245         WARN("GetBindInfo failed: %08x\n", hres);
1246         IBinding_Release(BINDING(ret));
1247         return hres;
1248     }
1249
1250     dump_BINDINFO(&ret->bindinfo);
1251
1252     ret->bindf |= BINDF_FROMURLMON;
1253
1254     if(!is_urlmon_protocol(url))
1255         ret->bindf |= BINDF_NEEDFILE;
1256
1257     len = strlenW(url)+1;
1258     ret->url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
1259     memcpy(ret->url, url, len*sizeof(WCHAR));
1260
1261     ret->stream = create_stream(ret->protocol);
1262     ret->stgmed.tymed = TYMED_ISTREAM;
1263     ret->stgmed.u.pstm = STREAM(ret->stream);
1264     ret->stgmed.pUnkForRelease = (IUnknown*)BINDING(ret); /* NOTE: Windows uses other IUnknown */
1265
1266     *binding = ret;
1267     return S_OK;
1268 }
1269
1270 HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
1271 {
1272     Binding *binding = NULL;
1273     HRESULT hres;
1274
1275     *ppv = NULL;
1276
1277     hres = Binding_Create(url, pbc, riid, &binding);
1278     if(FAILED(hres))
1279         return hres;
1280
1281     hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, BINDING(binding));
1282     if(FAILED(hres)) {
1283         WARN("OnStartBinding failed: %08x\n", hres);
1284         IBindStatusCallback_OnStopBinding(binding->callback, 0x800c0008, NULL);
1285         IBinding_Release(BINDING(binding));
1286         return hres;
1287     }
1288
1289     hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding),
1290              BINDINF(binding), 0, 0);
1291
1292     if(FAILED(hres)) {
1293         WARN("Start failed: %08x\n", hres);
1294
1295         IInternetProtocol_Terminate(binding->protocol, 0);
1296         IBindStatusCallback_OnStopBinding(binding->callback, S_OK, NULL);
1297         IBinding_Release(BINDING(binding));
1298
1299         return hres;
1300     }
1301
1302     if(binding->stream->init_buf) {
1303         if(binding->request_locked)
1304             IInternetProtocol_UnlockRequest(binding->protocol);
1305
1306         IStream_AddRef(STREAM(binding->stream));
1307         *ppv = binding->stream;
1308
1309         hres = S_OK;
1310     }else {
1311         hres = MK_S_ASYNCHRONOUS;
1312     }
1313
1314     IBinding_Release(BINDING(binding));
1315
1316     return hres;
1317 }