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