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