urlmon: LockModule in create_binding_protocol as we ReleaseModule when the object...
[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 IHttpNegotiate2Vtbl *lpHttpNegotiate2Vtbl;
50
51     LONG ref;
52
53     IHttpNegotiate *http_negotiate;
54     IHttpNegotiate2 *http_negotiate2;
55 } HttpNegotiate2Wrapper;
56
57 typedef struct {
58     const IStreamVtbl *lpStreamVtbl;
59
60     LONG ref;
61
62     IInternetProtocol *protocol;
63
64     BYTE buf[1024*8];
65     DWORD buf_size;
66     BOOL init_buf;
67     HRESULT hres;
68 } ProtocolStream;
69
70 typedef enum {
71     BEFORE_DOWNLOAD,
72     DOWNLOADING,
73     END_DOWNLOAD
74 } download_state_t;
75
76 struct Binding {
77     const IBindingVtbl               *lpBindingVtbl;
78     const IInternetProtocolSinkVtbl  *lpInternetProtocolSinkVtbl;
79     const IInternetBindInfoVtbl      *lpInternetBindInfoVtbl;
80     const IServiceProviderVtbl       *lpServiceProviderVtbl;
81
82     LONG ref;
83
84     IBindStatusCallback *callback;
85     IInternetProtocol *protocol;
86     IServiceProvider *service_provider;
87     ProtocolStream *stream;
88     HttpNegotiate2Wrapper *httpneg2_wrapper;
89
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;
98
99     DWORD apartment_thread;
100     HWND notif_hwnd;
101
102     STGMEDIUM stgmed;
103
104     task_header_t *task_queue_head, *task_queue_tail;
105     CRITICAL_SECTION section;
106 };
107
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)
112
113 #define STREAM(x) ((IStream*) &(x)->lpStreamVtbl)
114 #define HTTPNEG2(x) ((IHttpNegotiate2*) &(x)->lpHttpNegotiate2Vtbl)
115
116 #define WM_MK_CONTINUE   (WM_USER+101)
117
118 static void push_task(Binding *binding, task_header_t *task, task_proc_t proc)
119 {
120     task->proc = proc;
121     task->next = NULL;
122
123     EnterCriticalSection(&binding->section);
124
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;
129
130     LeaveCriticalSection(&binding->section);
131 }
132
133 static task_header_t *pop_task(Binding *binding)
134 {
135     task_header_t *ret;
136
137     EnterCriticalSection(&binding->section);
138
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;
144     }
145
146     LeaveCriticalSection(&binding->section);
147
148     return ret;
149 }
150
151 static void fill_stream_buffer(ProtocolStream *This)
152 {
153     DWORD read = 0;
154
155     if(sizeof(This->buf) == This->buf_size)
156         return;
157
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;
163 }
164
165 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
166 {
167     if(msg == WM_MK_CONTINUE) {
168         Binding *binding = (Binding*)lParam;
169         task_header_t *task;
170
171         while((task = pop_task(binding))) {
172             binding->continue_call++;
173             task->proc(binding, task);
174             binding->continue_call--;
175         }
176
177         IBinding_Release(BINDING(binding));
178         return 0;
179     }
180
181     return DefWindowProcW(hwnd, msg, wParam, lParam);
182 }
183
184 static HWND get_notif_hwnd(void)
185 {
186     static ATOM wnd_class = 0;
187     HWND hwnd;
188
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};
192
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        
200         };
201
202         wndclass.hInstance = URLMON_hInstance;
203
204         wnd_class = RegisterClassExW(&wndclass);
205         if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
206             wnd_class = 1;
207     }
208
209     hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
210                            wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
211                            NULL, URLMON_hInstance, NULL);
212
213     TRACE("hwnd = %p\n", hwnd);
214
215     return hwnd;
216 }
217
218 static void dump_BINDINFO(BINDINFO *bi)
219 {
220     static const char * const BINDINFOF_str[] = {
221         "#0",
222         "BINDINFOF_URLENCODESTGMEDDATA",
223         "BINDINFOF_URLENCODEDEXTRAINFO"
224     };
225
226     static const char * const BINDVERB_str[] = {
227         "BINDVERB_GET",
228         "BINDVERB_POST",
229         "BINDVERB_PUT",
230         "BINDVERB_CUSTOM"
231     };
232
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",
245
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
259             );
260 }
261
262 #define HTTPNEG2_THIS(iface) DEFINE_THIS(HttpNegotiate2Wrapper, HttpNegotiate2, iface)
263
264 static HRESULT WINAPI HttpNegotiate2Wrapper_QueryInterface(IHttpNegotiate2 *iface,
265                                                           REFIID riid, void **ppv)
266 {
267     HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
268
269     *ppv = NULL;
270
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);
280     }
281
282     if(*ppv) {
283         IHttpNegotiate2_AddRef(HTTPNEG2(This));
284         return S_OK;
285     }
286
287     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
288     return E_NOINTERFACE;
289 }
290
291 static ULONG WINAPI HttpNegotiate2Wrapper_AddRef(IHttpNegotiate2 *iface)
292 {
293     HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
294     LONG ref = InterlockedIncrement(&This->ref);
295
296     TRACE("(%p) ref=%d\n", This, ref);
297
298     return ref;
299 }
300
301 static ULONG WINAPI HttpNegotiate2Wrapper_Release(IHttpNegotiate2 *iface)
302 {
303     HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
304     LONG ref = InterlockedDecrement(&This->ref);
305
306     TRACE("(%p) ref=%d\n", This, ref);
307
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);
314
315         URLMON_UnlockModule();
316     }
317
318     return ref;
319 }
320
321 static HRESULT WINAPI HttpNegotiate2Wrapper_BeginningTransaction(IHttpNegotiate2 *iface,
322         LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
323 {
324     HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
325
326     TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders), dwReserved,
327           pszAdditionalHeaders);
328
329     if(This->http_negotiate)
330         return IHttpNegotiate_BeginningTransaction(This->http_negotiate, szURL, szHeaders,
331                                                    dwReserved, pszAdditionalHeaders);
332
333     *pszAdditionalHeaders = NULL;
334     return S_OK;
335 }
336
337 static HRESULT WINAPI HttpNegotiate2Wrapper_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
338         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders,
339         LPWSTR *pszAdditionalRequestHeaders)
340 {
341     HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
342     LPWSTR szAdditionalRequestHeaders = NULL;
343     HRESULT hres = S_OK;
344
345     TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
346           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
347
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;
353
354     if(This->http_negotiate)
355     {
356         hres = IHttpNegotiate_OnResponse(This->http_negotiate, dwResponseCode, szResponseHeaders,
357                                          szRequestHeaders, pszAdditionalRequestHeaders);
358         if(pszAdditionalRequestHeaders == &szAdditionalRequestHeaders &&
359            szAdditionalRequestHeaders)
360             CoTaskMemFree(szAdditionalRequestHeaders);
361     }
362     else
363     {
364         *pszAdditionalRequestHeaders = NULL;
365     }
366
367     return hres;
368 }
369
370 static HRESULT WINAPI HttpNegotiate2Wrapper_GetRootSecurityId(IHttpNegotiate2 *iface,
371         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
372 {
373     HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface);
374
375     TRACE("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved);
376
377     if (This->http_negotiate2)
378         return IHttpNegotiate2_GetRootSecurityId(This->http_negotiate2, pbSecurityId,
379                                                  pcbSecurityId, dwReserved);
380
381     /* That's all we have to do here */
382     return E_FAIL;
383 }
384
385 #undef HTTPNEG2_THIS
386
387 static const IHttpNegotiate2Vtbl HttpNegotiate2WrapperVtbl = {
388     HttpNegotiate2Wrapper_QueryInterface,
389     HttpNegotiate2Wrapper_AddRef,
390     HttpNegotiate2Wrapper_Release,
391     HttpNegotiate2Wrapper_BeginningTransaction,
392     HttpNegotiate2Wrapper_OnResponse,
393     HttpNegotiate2Wrapper_GetRootSecurityId
394 };
395
396 static HttpNegotiate2Wrapper *create_httpneg2_wrapper(void)
397 {
398     HttpNegotiate2Wrapper *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(HttpNegotiate2Wrapper));
399
400     ret->lpHttpNegotiate2Vtbl = &HttpNegotiate2WrapperVtbl;
401     ret->ref = 1;
402     ret->http_negotiate = NULL;
403     ret->http_negotiate2 = NULL;
404
405     URLMON_LockModule();
406
407     return ret;
408 }
409
410 #define STREAM_THIS(iface) DEFINE_THIS(ProtocolStream, Stream, iface)
411
412 static HRESULT WINAPI ProtocolStream_QueryInterface(IStream *iface,
413                                                           REFIID riid, void **ppv)
414 {
415     ProtocolStream *This = STREAM_THIS(iface);
416
417     *ppv = NULL;
418
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);
428     }
429
430     if(*ppv) {
431         IStream_AddRef(STREAM(This));
432         return S_OK;
433     }
434
435     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
436     return E_NOINTERFACE;
437 }
438
439 static ULONG WINAPI ProtocolStream_AddRef(IStream *iface)
440 {
441     ProtocolStream *This = STREAM_THIS(iface);
442     LONG ref = InterlockedIncrement(&This->ref);
443
444     TRACE("(%p) ref=%d\n", This, ref);
445
446     return ref;
447 }
448
449 static ULONG WINAPI ProtocolStream_Release(IStream *iface)
450 {
451     ProtocolStream *This = STREAM_THIS(iface);
452     LONG ref = InterlockedDecrement(&This->ref);
453
454     TRACE("(%p) ref=%d\n", This, ref);
455
456     if(!ref) {
457         IInternetProtocol_Release(This->protocol);
458         HeapFree(GetProcessHeap(), 0, This);
459
460         URLMON_UnlockModule();
461     }
462
463     return ref;
464 }
465
466 static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv,
467                                          ULONG cb, ULONG *pcbRead)
468 {
469     ProtocolStream *This = STREAM_THIS(iface);
470     DWORD read = 0, pread = 0;
471
472     TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbRead);
473
474     if(This->buf_size) {
475         read = cb;
476
477         if(read > This->buf_size)
478             read = This->buf_size;
479
480         memcpy(pv, This->buf, read);
481
482         if(read < This->buf_size)
483             memmove(This->buf, This->buf+read, This->buf_size-read);
484         This->buf_size -= read;
485     }
486
487     if(read == cb) {
488         *pcbRead = read;
489         return S_OK;
490     }
491
492     This->hres = IInternetProtocol_Read(This->protocol, (PBYTE)pv+read, cb-read, &pread);
493     *pcbRead = read + pread;
494
495     if(This->hres == E_PENDING)
496         return E_PENDING;
497     else if(FAILED(This->hres))
498         FIXME("Read failed: %08x\n", This->hres);
499
500     return read || pread ? S_OK : S_FALSE;
501 }
502
503 static HRESULT WINAPI ProtocolStream_Write(IStream *iface, const void *pv,
504                                           ULONG cb, ULONG *pcbWritten)
505 {
506     ProtocolStream *This = STREAM_THIS(iface);
507
508     TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbWritten);
509
510     return STG_E_ACCESSDENIED;
511 }
512
513 static HRESULT WINAPI ProtocolStream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
514                                          DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
515 {
516     ProtocolStream *This = STREAM_THIS(iface);
517     FIXME("(%p)->(%d %08x %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
518     return E_NOTIMPL;
519 }
520
521 static HRESULT WINAPI ProtocolStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
522 {
523     ProtocolStream *This = STREAM_THIS(iface);
524     FIXME("(%p)->(%d)\n", This, libNewSize.u.LowPart);
525     return E_NOTIMPL;
526 }
527
528 static HRESULT WINAPI ProtocolStream_CopyTo(IStream *iface, IStream *pstm,
529         ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
530 {
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;
534 }
535
536 static HRESULT WINAPI ProtocolStream_Commit(IStream *iface, DWORD grfCommitFlags)
537 {
538     ProtocolStream *This = STREAM_THIS(iface);
539
540     TRACE("(%p)->(%08x)\n", This, grfCommitFlags);
541
542     return E_NOTIMPL;
543 }
544
545 static HRESULT WINAPI ProtocolStream_Revert(IStream *iface)
546 {
547     ProtocolStream *This = STREAM_THIS(iface);
548
549     TRACE("(%p)\n", This);
550
551     return E_NOTIMPL;
552 }
553
554 static HRESULT WINAPI ProtocolStream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
555                                                ULARGE_INTEGER cb, DWORD dwLockType)
556 {
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;
560 }
561
562 static HRESULT WINAPI ProtocolStream_UnlockRegion(IStream *iface,
563         ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
564 {
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;
568 }
569
570 static HRESULT WINAPI ProtocolStream_Stat(IStream *iface, STATSTG *pstatstg,
571                                          DWORD dwStatFlag)
572 {
573     ProtocolStream *This = STREAM_THIS(iface);
574     FIXME("(%p)->(%p %08x)\n", This, pstatstg, dwStatFlag);
575     return E_NOTIMPL;
576 }
577
578 static HRESULT WINAPI ProtocolStream_Clone(IStream *iface, IStream **ppstm)
579 {
580     ProtocolStream *This = STREAM_THIS(iface);
581     FIXME("(%p)->(%p)\n", This, ppstm);
582     return E_NOTIMPL;
583 }
584
585 #undef STREAM_THIS
586
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
602 };
603
604 #define BINDING_THIS(iface) DEFINE_THIS(Binding, Binding, iface)
605
606 static ProtocolStream *create_stream(IInternetProtocol *protocol)
607 {
608     ProtocolStream *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ProtocolStream));
609
610     ret->lpStreamVtbl = &ProtocolStreamVtbl;
611     ret->ref = 1;
612     ret->buf_size = 0;
613     ret->init_buf = FALSE;
614     ret->hres = S_OK;
615
616     IInternetProtocol_AddRef(protocol);
617     ret->protocol = protocol;
618
619     URLMON_LockModule();
620
621     return ret;
622 }
623
624 static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv)
625 {
626     Binding *This = BINDING_THIS(iface);
627
628     *ppv = NULL;
629
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);
645     }
646
647     if(*ppv) {
648         IBinding_AddRef(BINDING(This));
649         return S_OK;
650     }
651
652     WARN("Unsupported interface %s\n", debugstr_guid(riid));
653     return E_NOINTERFACE;
654 }
655
656 static ULONG WINAPI Binding_AddRef(IBinding *iface)
657 {
658     Binding *This = BINDING_THIS(iface);
659     LONG ref = InterlockedIncrement(&This->ref);
660
661     TRACE("(%p) ref=%d\n", This, ref);
662
663     return ref;
664 }
665
666 static ULONG WINAPI Binding_Release(IBinding *iface)
667 {
668     Binding *This = BINDING_THIS(iface);
669     LONG ref = InterlockedDecrement(&This->ref);
670
671     TRACE("(%p) ref=%d\n", This, ref);
672
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));
686
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);
692
693         HeapFree(GetProcessHeap(), 0, This);
694
695         URLMON_UnlockModule();
696     }
697
698     return ref;
699 }
700
701 static HRESULT WINAPI Binding_Abort(IBinding *iface)
702 {
703     Binding *This = BINDING_THIS(iface);
704     FIXME("(%p)\n", This);
705     return E_NOTIMPL;
706 }
707
708 static HRESULT WINAPI Binding_Suspend(IBinding *iface)
709 {
710     Binding *This = BINDING_THIS(iface);
711     FIXME("(%p)\n", This);
712     return E_NOTIMPL;
713 }
714
715 static HRESULT WINAPI Binding_Resume(IBinding *iface)
716 {
717     Binding *This = BINDING_THIS(iface);
718     FIXME("(%p)\n", This);
719     return E_NOTIMPL;
720 }
721
722 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority)
723 {
724     Binding *This = BINDING_THIS(iface);
725     FIXME("(%p)->(%d)\n", This, nPriority);
726     return E_NOTIMPL;
727 }
728
729 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority)
730 {
731     Binding *This = BINDING_THIS(iface);
732     FIXME("(%p)->(%p)\n", This, pnPriority);
733     return E_NOTIMPL;
734 }
735
736 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol,
737         DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved)
738 {
739     Binding *This = BINDING_THIS(iface);
740     FIXME("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
741     return E_NOTIMPL;
742 }
743
744 #undef BINDING_THIS
745
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
756 };
757
758 #define PROTSINK_THIS(iface) DEFINE_THIS(Binding, InternetProtocolSink, iface)
759
760 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
761         REFIID riid, void **ppv)
762 {
763     Binding *This = PROTSINK_THIS(iface);
764     return IBinding_QueryInterface(BINDING(This), riid, ppv);
765 }
766
767 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
768 {
769     Binding *This = PROTSINK_THIS(iface);
770     return IBinding_AddRef(BINDING(This));
771 }
772
773 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
774 {
775     Binding *This = PROTSINK_THIS(iface);
776     return IBinding_Release(BINDING(This));
777 }
778
779 typedef struct {
780     task_header_t header;
781     PROTOCOLDATA *data;
782 } switch_task_t;
783
784 static void switch_proc(Binding *binding, task_header_t *t)
785 {
786     switch_task_t *task = (switch_task_t*)t;
787
788     IInternetProtocol_Continue(binding->protocol, task->data);
789
790     HeapFree(GetProcessHeap(), 0, task);
791 }
792
793 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
794         PROTOCOLDATA *pProtocolData)
795 {
796     Binding *This = PROTSINK_THIS(iface);
797     switch_task_t *task;
798
799     TRACE("(%p)->(%p)\n", This, pProtocolData);
800
801     task = HeapAlloc(GetProcessHeap(), 0, sizeof(switch_task_t));
802     task->data = pProtocolData;
803
804     push_task(This, &task->header, switch_proc);
805
806     IBinding_AddRef(BINDING(This));
807     PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
808
809     return S_OK;
810 }
811
812 typedef struct {
813     task_header_t header;
814
815     Binding *binding;
816     ULONG progress;
817     ULONG progress_max;
818     ULONG status_code;
819     LPWSTR status_text;
820 } on_progress_task_t;
821
822 static void on_progress_proc(Binding *binding, task_header_t *t)
823 {
824     on_progress_task_t *task = (on_progress_task_t*)t;
825
826     IBindStatusCallback_OnProgress(binding->callback, task->progress,
827             task->progress_max, task->status_code, task->status_text);
828
829     HeapFree(GetProcessHeap(), 0, task->status_text);
830     HeapFree(GetProcessHeap(), 0, task);
831 }
832
833 static void on_progress(Binding *This, ULONG progress, ULONG progress_max,
834                         ULONG status_code, LPCWSTR status_text)
835 {
836     on_progress_task_t *task;
837
838     if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
839         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
840                                        status_code, status_text);
841         return;
842     }
843
844     task = HeapAlloc(GetProcessHeap(), 0, sizeof(on_progress_task_t));
845
846     task->progress = progress;
847     task->progress_max = progress_max;
848     task->status_code = status_code;
849
850     if(status_text) {
851         DWORD size = (strlenW(status_text)+1)*sizeof(WCHAR);
852
853         task->status_text = HeapAlloc(GetProcessHeap(), 0, size);
854         memcpy(task->status_text, status_text, size);
855     }else {
856         task->status_text = NULL;
857     }
858
859     push_task(This, &task->header, on_progress_proc);
860
861     if(GetCurrentThreadId() != This->apartment_thread) {
862         IBinding_AddRef(BINDING(This));
863         PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
864     }
865 }
866
867 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
868         ULONG ulStatusCode, LPCWSTR szStatusText)
869 {
870     Binding *This = PROTSINK_THIS(iface);
871
872     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
873
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;
889     }
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;
905     };
906
907     return S_OK;
908 }
909
910 static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progress_max)
911 {
912     FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM};
913
914     TRACE("(%p)->(%d %u %u)\n", This, bscf, progress, progress_max);
915
916     if(This->download_state == END_DOWNLOAD)
917         return;
918
919     if(GetCurrentThreadId() != This->apartment_thread)
920         FIXME("called from worked hread\n");
921
922     if(This->report_mime) {
923         LPWSTR mime;
924
925         This->report_mime = FALSE;
926
927         fill_stream_buffer(This->stream);
928
929         FindMimeFromData(NULL, This->url, This->stream->buf,
930                          min(This->stream->buf_size, 255), This->mime, 0, &mime, 0);
931
932         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
933                 BINDSTATUS_MIMETYPEAVAILABLE, mime);
934     }
935
936     if(This->download_state == BEFORE_DOWNLOAD) {
937         fill_stream_buffer(This->stream);
938
939         This->download_state = DOWNLOADING;
940         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
941                 BINDSTATUS_BEGINDOWNLOADDATA, This->url);
942     }
943
944     if(This->stream->hres == S_FALSE || (bscf & BSCF_LASTDATANOTIFICATION)) {
945         IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
946                 BINDSTATUS_ENDDOWNLOADDATA, This->url);
947     }
948
949     if(!This->request_locked) {
950         HRESULT hres = IInternetProtocol_LockRequest(This->protocol, 0);
951         This->request_locked = SUCCEEDED(hres);
952     }
953
954     fill_stream_buffer(This->stream);
955
956     IBindStatusCallback_OnDataAvailable(This->callback, bscf, This->stream->buf_size,
957             &formatetc, &This->stgmed);
958
959     if(This->stream->hres == S_FALSE) {
960         This->download_state = END_DOWNLOAD;
961         IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL);
962     }
963 }
964
965 typedef struct {
966     task_header_t header;
967     DWORD bscf;
968     ULONG progress;
969     ULONG progress_max;
970 } report_data_task_t;
971
972 static void report_data_proc(Binding *binding, task_header_t *t)
973 {
974     report_data_task_t *task = (report_data_task_t*)t;
975
976     report_data(binding, task->bscf, task->progress, task->progress_max);
977
978     HeapFree(GetProcessHeap(), 0, task);
979 }
980
981 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
982         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
983 {
984     Binding *This = PROTSINK_THIS(iface);
985
986     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
987
988     if(GetCurrentThreadId() != This->apartment_thread)
989         FIXME("called from worked hread\n");
990
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;
996
997         push_task(This, &task->header, report_data_proc);
998     }else {
999         report_data(This, grfBSCF, ulProgress, ulProgressMax);
1000     }
1001
1002     return S_OK;
1003 }
1004
1005 static void report_result_proc(Binding *binding, task_header_t *t)
1006 {
1007     IInternetProtocol_Terminate(binding->protocol, 0);
1008
1009     if(binding->request_locked) {
1010         IInternetProtocol_UnlockRequest(binding->protocol);
1011         binding->request_locked = FALSE;
1012     }
1013
1014     HeapFree(GetProcessHeap(), 0, t);
1015 }
1016
1017 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1018         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1019 {
1020     Binding *This = PROTSINK_THIS(iface);
1021
1022     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1023
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);
1029     }
1030
1031     return S_OK;
1032 }
1033
1034 #undef PROTSINK_THIS
1035
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
1044 };
1045
1046 #define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
1047
1048 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
1049         REFIID riid, void **ppv)
1050 {
1051     Binding *This = BINDINF_THIS(iface);
1052     return IBinding_QueryInterface(BINDING(This), riid, ppv);
1053 }
1054
1055 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
1056 {
1057     Binding *This = BINDINF_THIS(iface);
1058     return IBinding_AddRef(BINDING(This));
1059 }
1060
1061 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
1062 {
1063     Binding *This = BINDINF_THIS(iface);
1064     return IBinding_Release(BINDING(This));
1065 }
1066
1067 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
1068         DWORD *grfBINDF, BINDINFO *pbindinfo)
1069 {
1070     Binding *This = BINDINF_THIS(iface);
1071
1072     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1073
1074     *grfBINDF = This->bindf;
1075
1076     memcpy(pbindinfo, &This->bindinfo, sizeof(BINDINFO));
1077
1078     if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
1079         FIXME("copy strings\n");
1080
1081     if(pbindinfo->stgmedData.pUnkForRelease)
1082         IUnknown_AddRef(pbindinfo->stgmedData.pUnkForRelease);
1083
1084     if(pbindinfo->pUnk)
1085         IUnknown_AddRef(pbindinfo->pUnk);
1086
1087     return S_OK;
1088 }
1089
1090 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
1091         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1092 {
1093     Binding *This = BINDINF_THIS(iface);
1094
1095     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1096
1097     switch(ulStringType) {
1098     case BINDSTRING_ACCEPT_MIMES: {
1099         static const WCHAR wszMimes[] = {'*','/','*',0};
1100
1101         if(!ppwzStr || !pcElFetched)
1102             return E_INVALIDARG;
1103
1104         ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes));
1105         memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes));
1106         *pcElFetched = 1;
1107         return S_OK;
1108     }
1109     case BINDSTRING_USER_AGENT: {
1110         IInternetBindInfo *bindinfo = NULL;
1111         HRESULT hres;
1112
1113         hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo,
1114                                                   (void**)&bindinfo);
1115         if(FAILED(hres))
1116             return hres;
1117
1118         hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr,
1119                                                cEl, pcElFetched);
1120         IInternetBindInfo_Release(bindinfo);
1121
1122         return hres;
1123     }
1124     }
1125
1126     FIXME("not supported string type %d\n", ulStringType);
1127     return E_NOTIMPL;
1128 }
1129
1130 #undef BINDF_THIS
1131
1132 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1133     InternetBindInfo_QueryInterface,
1134     InternetBindInfo_AddRef,
1135     InternetBindInfo_Release,
1136     InternetBindInfo_GetBindInfo,
1137     InternetBindInfo_GetBindString
1138 };
1139
1140 #define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
1141
1142 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
1143         REFIID riid, void **ppv)
1144 {
1145     Binding *This = SERVPROV_THIS(iface);
1146     return IBinding_QueryInterface(BINDING(This), riid, ppv);
1147 }
1148
1149 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
1150 {
1151     Binding *This = SERVPROV_THIS(iface);
1152     return IBinding_AddRef(BINDING(This));
1153 }
1154
1155 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
1156 {
1157     Binding *This = SERVPROV_THIS(iface);
1158     return IBinding_Release(BINDING(This));
1159 }
1160
1161 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
1162         REFGUID guidService, REFIID riid, void **ppv)
1163 {
1164     Binding *This = SERVPROV_THIS(iface);
1165     HRESULT hres;
1166
1167     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1168
1169     if(This->service_provider) {
1170         hres = IServiceProvider_QueryService(This->service_provider, guidService,
1171                                              riid, ppv);
1172         if(SUCCEEDED(hres))
1173             return hres;
1174     }
1175
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);
1187
1188             return IHttpNegotiate2_QueryInterface(HTTPNEG2(This->httpneg2_wrapper), riid, ppv);
1189         }
1190     }
1191
1192     WARN("unknown service %s\n", debugstr_guid(guidService));
1193     return E_NOTIMPL;
1194 }
1195
1196 #undef SERVPROV_THIS
1197
1198 static const IServiceProviderVtbl ServiceProviderVtbl = {
1199     ServiceProvider_QueryInterface,
1200     ServiceProvider_AddRef,
1201     ServiceProvider_Release,
1202     ServiceProvider_QueryService
1203 };
1204
1205 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
1206 {
1207     HRESULT hres;
1208
1209     static WCHAR wszBSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
1210
1211     hres = IBindCtx_GetObjectParam(pbc, wszBSCBHolder, (IUnknown**)callback);
1212     if(FAILED(hres))
1213         return MK_E_SYNTAX;
1214
1215     return S_OK;
1216 }
1217
1218 static HRESULT get_protocol(Binding *This, LPCWSTR url)
1219 {
1220     IClassFactory *cf = NULL;
1221     HRESULT hres;
1222
1223     hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetProtocol,
1224             (void**)&This->protocol);
1225     if(SUCCEEDED(hres))
1226         return S_OK;
1227
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;
1233     }
1234
1235     hres = get_protocol_handler(url, NULL, &cf);
1236     if(FAILED(hres))
1237         return hres;
1238
1239     hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&This->protocol);
1240     IClassFactory_Release(cf);
1241
1242     return hres;
1243 }
1244
1245 static BOOL is_urlmon_protocol(LPCWSTR url)
1246 {
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'};
1254
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)}
1266     };
1267
1268     int i, len = strlenW(url);
1269
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;
1274     }
1275
1276     return FALSE;
1277 }
1278
1279 static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding)
1280 {
1281     Binding *ret;
1282     int len;
1283     HRESULT hres;
1284
1285     if(!IsEqualGUID(&IID_IStream, riid)) {
1286         FIXME("Unsupported riid %s\n", debugstr_guid(riid));
1287         return E_NOTIMPL;
1288     }
1289
1290     URLMON_LockModule();
1291
1292     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(Binding));
1293
1294     ret->lpBindingVtbl              = &BindingVtbl;
1295     ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1296     ret->lpInternetBindInfoVtbl     = &InternetBindInfoVtbl;
1297     ret->lpServiceProviderVtbl      = &ServiceProviderVtbl;
1298
1299     ret->ref = 1;
1300
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;
1315
1316     memset(&ret->bindinfo, 0, sizeof(BINDINFO));
1317     ret->bindinfo.cbSize = sizeof(BINDINFO);
1318     ret->bindf = 0;
1319
1320     InitializeCriticalSection(&ret->section);
1321     ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Binding.section");
1322
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;
1328     }
1329
1330     IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider,
1331                                        (void**)&ret->service_provider);
1332
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;
1338     }
1339
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;
1345     }
1346
1347     dump_BINDINFO(&ret->bindinfo);
1348
1349     ret->bindf |= BINDF_FROMURLMON;
1350
1351     if(!is_urlmon_protocol(url))
1352         ret->bindf |= BINDF_NEEDFILE;
1353
1354     len = strlenW(url)+1;
1355     ret->url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
1356     memcpy(ret->url, url, len*sizeof(WCHAR));
1357
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 */
1362
1363     ret->httpneg2_wrapper = create_httpneg2_wrapper();
1364
1365     *binding = ret;
1366     return S_OK;
1367 }
1368
1369 HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
1370 {
1371     Binding *binding = NULL;
1372     HRESULT hres;
1373
1374     *ppv = NULL;
1375
1376     hres = Binding_Create(url, pbc, riid, &binding);
1377     if(FAILED(hres))
1378         return hres;
1379
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;
1386     }
1387
1388     hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding),
1389              BINDINF(binding), 0, 0);
1390
1391     if(FAILED(hres)) {
1392         WARN("Start failed: %08x\n", hres);
1393
1394         IInternetProtocol_Terminate(binding->protocol, 0);
1395         IBindStatusCallback_OnStopBinding(binding->callback, S_OK, NULL);
1396         IBinding_Release(BINDING(binding));
1397
1398         return hres;
1399     }
1400
1401     if(binding->stream->init_buf) {
1402         if(binding->request_locked)
1403             IInternetProtocol_UnlockRequest(binding->protocol);
1404
1405         IStream_AddRef(STREAM(binding->stream));
1406         *ppv = binding->stream;
1407
1408         hres = S_OK;
1409     }else {
1410         hres = MK_S_ASYNCHRONOUS;
1411     }
1412
1413     IBinding_Release(BINDING(binding));
1414
1415     return hres;
1416 }