Sync with trunk r63174.
[reactos.git] / dll / win32 / urlmon / bindprot.c
index 29b8532..77a20bc 100644 (file)
  */
 
 #include "urlmon_main.h"
-#include "wine/debug.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
+typedef void (*task_proc_t)(BindProtocol*,task_header_t*);
 
-typedef struct BindProtocol BindProtocol;
-
-struct _task_header_t;
-
-typedef void (*task_proc_t)(BindProtocol*,struct _task_header_t*);
-
-typedef struct _task_header_t {
+struct _task_header_t {
     task_proc_t proc;
-    struct _task_header_t *next;
-} task_header_t;
-
-struct BindProtocol {
-    const IInternetProtocolVtbl      *lpIInternetProtocolVtbl;
-    const IInternetBindInfoVtbl      *lpInternetBindInfoVtbl;
-    const IInternetPriorityVtbl      *lpInternetPriorityVtbl;
-    const IServiceProviderVtbl       *lpServiceProviderVtbl;
-    const IInternetProtocolSinkVtbl  *lpIInternetProtocolSinkVtbl;
-    const IWinInetHttpInfoVtbl       *lpIWinInetHttpInfoVtbl;
-
-    const IInternetProtocolVtbl *lpIInternetProtocolHandlerVtbl;
-
-    LONG ref;
-
-    IInternetProtocol *protocol;
-    IInternetProtocol *protocol_handler;
-    IInternetBindInfo *bind_info;
-    IInternetProtocolSink *protocol_sink;
-    IServiceProvider *service_provider;
-    IWinInetInfo *wininet_info;
-
-    LONG priority;
+    task_header_t *next;
+};
 
-    BOOL reported_result;
-    BOOL reported_mime;
-    BOOL from_urlmon;
-    DWORD pi;
+#define BUFFER_SIZE     2048
+#define MIME_TEST_SIZE  255
 
-    DWORD apartment_thread;
-    HWND notif_hwnd;
-    DWORD continue_call;
+#define WM_MK_CONTINUE   (WM_USER+101)
+#define WM_MK_RELEASE    (WM_USER+102)
 
-    CRITICAL_SECTION section;
-    task_header_t *task_queue_head, *task_queue_tail;
+static void process_tasks(BindProtocol *This)
+{
+    task_header_t *task;
 
-    BYTE *buf;
-    DWORD buf_size;
-    LPWSTR mime;
-    LPWSTR url;
-    ProtocolProxy *filter_proxy;
-};
+    while(1) {
+        EnterCriticalSection(&This->section);
 
-#define BINDINFO(x)  ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
-#define PRIORITY(x)  ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
-#define HTTPINFO(x)  ((IWinInetHttpInfo*)  &(x)->lpIWinInetHttpInfoVtbl)
-#define SERVPROV(x)  ((IServiceProvider*)  &(x)->lpServiceProviderVtbl)
+        task = This->task_queue_head;
+        if(task) {
+            This->task_queue_head = task->next;
+            if(!This->task_queue_head)
+                This->task_queue_tail = NULL;
+        }
 
-#define PROTOCOLHANDLER(x)  ((IInternetProtocol*)  &(x)->lpIInternetProtocolHandlerVtbl)
+        LeaveCriticalSection(&This->section);
 
-#define BUFFER_SIZE     2048
-#define MIME_TEST_SIZE  255
+        if(!task)
+            break;
 
-#define WM_MK_CONTINUE   (WM_USER+101)
-#define WM_MK_RELEASE    (WM_USER+102)
+        This->continue_call++;
+        task->proc(This, task);
+        This->continue_call--;
+    }
+}
 
 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     switch(msg) {
     case WM_MK_CONTINUE: {
         BindProtocol *This = (BindProtocol*)lParam;
-        task_header_t *task;
-
-        while(1) {
-            EnterCriticalSection(&This->section);
-
-            task = This->task_queue_head;
-            if(task) {
-                This->task_queue_head = task->next;
-                if(!This->task_queue_head)
-                    This->task_queue_tail = NULL;
-            }
-
-            LeaveCriticalSection(&This->section);
 
-            if(!task)
-                break;
+        process_tasks(This);
 
-            This->continue_call++;
-            task->proc(This, task);
-            This->continue_call--;
-        }
-
-        IInternetProtocol_Release(PROTOCOL(This));
+        IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
         return 0;
     }
     case WM_MK_RELEASE: {
@@ -211,52 +163,50 @@ static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
     LeaveCriticalSection(&This->section);
 
     if(do_post) {
-        IInternetProtocol_AddRef(PROTOCOL(This));
+        IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
         PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
     }
 }
 
+static inline BOOL is_apartment_thread(BindProtocol *This)
+{
+    return This->apartment_thread == GetCurrentThreadId();
+}
+
 static inline BOOL do_direct_notif(BindProtocol *This)
 {
-    return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
+    return !(This->pi & PI_APARTMENTTHREADED) || (is_apartment_thread(This) && !This->continue_call);
 }
 
-static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter, LPCWSTR mime)
+static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter)
 {
     PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 };
-    IInternetProtocolSink *protocol_sink, *old_sink;
-    ProtocolProxy *filter_proxy;
     HRESULT hres;
 
-    hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&protocol_sink);
-    if(FAILED(hres))
-        return hres;
-
-    hres = create_protocol_proxy(PROTOCOLHANDLER(This), This->protocol_sink, &filter_proxy);
+    hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&This->protocol_sink_handler);
     if(FAILED(hres)) {
-        IInternetProtocolSink_Release(protocol_sink);
+        This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
         return hres;
     }
 
-    old_sink = This->protocol_sink;
-    This->protocol_sink = protocol_sink;
-    This->filter_proxy = filter_proxy;
-
     IInternetProtocol_AddRef(mime_filter);
     This->protocol_handler = mime_filter;
 
-    filter_data.pProtocol = PROTOCOL(filter_proxy);
-    hres = IInternetProtocol_Start(mime_filter, mime, PROTSINK(filter_proxy), BINDINFO(This),
-            PI_FILTER_MODE|PI_FORCE_ASYNC, (HANDLE_PTR)&filter_data);
+    filter_data.pProtocol = &This->default_protocol_handler.IInternetProtocol_iface;
+    hres = IInternetProtocol_Start(mime_filter, This->mime, &This->default_protocol_handler.IInternetProtocolSink_iface,
+            &This->IInternetBindInfo_iface, PI_FILTER_MODE|PI_FORCE_ASYNC,
+            (HANDLE_PTR)&filter_data);
     if(FAILED(hres)) {
-        IInternetProtocolSink_Release(old_sink);
+        IInternetProtocolSink_Release(This->protocol_sink_handler);
+        IInternetProtocol_Release(This->protocol_handler);
+        This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
+        This->protocol_handler = &This->default_protocol_handler.IInternetProtocol_iface;
         return hres;
     }
 
-    IInternetProtocolSink_ReportProgress(old_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL);
-    IInternetProtocolSink_Release(old_sink);
+    /* NOTE: IE9 calls it on the new protocol_sink. It doesn't make sense so it seems to be a bug there. */
+    IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL);
 
-    This->pi &= ~PI_MIMEVERIFICATION; /* FIXME: more tests */
     return S_OK;
 }
 
@@ -266,58 +216,60 @@ static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
     HRESULT hres;
 
     heap_free(This->mime);
-    This->mime = NULL;
+    This->mime = heap_strdupW(mime);
 
-    mime_filter = get_mime_filter(mime);
-    if(mime_filter) {
+    if(This->protocol_handler==&This->default_protocol_handler.IInternetProtocol_iface
+            && (mime_filter = get_mime_filter(mime))) {
         TRACE("Got mime filter for %s\n", debugstr_w(mime));
 
-        hres = handle_mime_filter(This, mime_filter, mime);
+        hres = handle_mime_filter(This, mime_filter);
         IInternetProtocol_Release(mime_filter);
         if(FAILED(hres))
             FIXME("MIME filter failed: %08x\n", hres);
-    }else {
-        This->mime = heap_strdupW(mime);
-
-        if(verified || !(This->pi & PI_MIMEVERIFICATION)) {
-            This->reported_mime = TRUE;
+    }
 
-            if(This->protocol_sink)
-                IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
-        }
+    if(This->reported_mime || verified || !(This->pi & PI_MIMEVERIFICATION)) {
+        This->reported_mime = TRUE;
+        IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
     }
 }
 
-#define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocol, iface)
+static inline BindProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
+{
+    return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolEx_iface);
+}
 
-static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
+static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
 
     *ppv = NULL;
     if(IsEqualGUID(&IID_IUnknown, riid)) {
         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
-        *ppv = PROTOCOL(This);
+        *ppv = &This->IInternetProtocolEx_iface;
     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
-        *ppv = PROTOCOL(This);
+        *ppv = &This->IInternetProtocolEx_iface;
     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
-        *ppv = PROTOCOL(This);
+        *ppv = &This->IInternetProtocolEx_iface;
+    }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
+        TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
+        *ppv = &This->IInternetProtocolEx_iface;
     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
-        *ppv = BINDINFO(This);
+        *ppv = &This->IInternetBindInfo_iface;
     }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
         TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
-        *ppv = PRIORITY(This);
+        *ppv = &This->IInternetPriority_iface;
     }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
         FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
-        *ppv = SERVPROV(This);
+        *ppv = &This->IServiceProvider_iface;
     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
-        *ppv = PROTSINK(This);
+        *ppv = &This->IInternetProtocolSink_iface;
     }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
         TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
 
@@ -327,7 +279,7 @@ static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFI
 
             hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetInfo, (void**)&inet_info);
             if(SUCCEEDED(hres)) {
-                *ppv = HTTPINFO(This);
+                *ppv = &This->IWinInetHttpInfo_iface;
                 IWinInetInfo_Release(inet_info);
             }
         }
@@ -340,7 +292,7 @@ static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFI
 
             hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetHttpInfo, (void**)&http_info);
             if(SUCCEEDED(hres)) {
-                *ppv = HTTPINFO(This);
+                *ppv = &This->IWinInetHttpInfo_iface;
                 IWinInetHttpInfo_Release(http_info);
             }
         }
@@ -355,17 +307,17 @@ static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFI
     return S_OK;
 }
 
-static ULONG WINAPI BindProtocol_AddRef(IInternetProtocol *iface)
+static ULONG WINAPI BindProtocol_AddRef(IInternetProtocolEx *iface)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
     LONG ref = InterlockedIncrement(&This->ref);
     TRACE("(%p) ref=%d\n", This, ref);
     return ref;
 }
 
-static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
+static ULONG WINAPI BindProtocol_Release(IInternetProtocolEx *iface)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
     LONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) ref=%d\n", This, ref);
@@ -373,23 +325,29 @@ static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
     if(!ref) {
         if(This->wininet_info)
             IWinInetInfo_Release(This->wininet_info);
+        if(This->wininet_http_info)
+            IWinInetHttpInfo_Release(This->wininet_http_info);
         if(This->protocol)
             IInternetProtocol_Release(This->protocol);
         if(This->bind_info)
             IInternetBindInfo_Release(This->bind_info);
-        if(This->protocol_handler && This->protocol_handler != PROTOCOLHANDLER(This))
+        if(This->protocol_handler && This->protocol_handler != &This->default_protocol_handler.IInternetProtocol_iface)
             IInternetProtocol_Release(This->protocol_handler);
-        if(This->filter_proxy)
-            IInternetProtocol_Release(PROTOCOL(This->filter_proxy));
+        if(This->protocol_sink_handler &&
+                This->protocol_sink_handler != &This->default_protocol_handler.IInternetProtocolSink_iface)
+            IInternetProtocolSink_Release(This->protocol_sink_handler);
+        if(This->uri)
+            IUri_Release(This->uri);
+        SysFreeString(This->display_uri);
 
-        set_binding_sink(PROTOCOL(This), NULL);
+        set_binding_sink(This, NULL, NULL);
 
         if(This->notif_hwnd)
             release_notif_hwnd(This->notif_hwnd);
+        This->section.DebugInfo->Spare[0] = 0;
         DeleteCriticalSection(&This->section);
 
         heap_free(This->mime);
-        heap_free(This->url);
         heap_free(This);
 
         URLMON_UnlockModule();
@@ -398,62 +356,74 @@ static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
     return ref;
 }
 
-static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
+static HRESULT WINAPI BindProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
         DWORD grfPI, HANDLE_PTR dwReserved)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
+    IUri *uri;
+    HRESULT hres;
 
     TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
             pOIBindInfo, grfPI, dwReserved);
 
-    return IInternetProtocol_Start(This->protocol_handler, szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
+    hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
+    if(FAILED(hres))
+        return hres;
+
+    hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
+            pOIBindInfo, grfPI, (HANDLE*)dwReserved);
+
+    IUri_Release(uri);
+    return hres;
 }
 
-static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
+static HRESULT WINAPI BindProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
 
     TRACE("(%p)->(%p)\n", This, pProtocolData);
 
     return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
 }
 
-static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
+static HRESULT WINAPI BindProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
         DWORD dwOptions)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
-    FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
-    return E_NOTIMPL;
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
+
+    TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
+
+    return IInternetProtocol_Abort(This->protocol_handler, hrReason, dwOptions);
 }
 
-static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
+static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
 
     TRACE("(%p)->(%08x)\n", This, dwOptions);
 
     return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
 }
 
-static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface)
+static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocolEx *iface)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
     FIXME("(%p)\n", This);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface)
+static HRESULT WINAPI BindProtocol_Resume(IInternetProtocolEx *iface)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
     FIXME("(%p)\n", This);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
+static HRESULT WINAPI BindProtocol_Read(IInternetProtocolEx *iface, void *pv,
         ULONG cb, ULONG *pcbRead)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
 
     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
 
@@ -462,102 +432,39 @@ static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
     return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
 }
 
-static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
+static HRESULT WINAPI BindProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
+static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
 
     TRACE("(%p)->(%08x)\n", This, dwOptions);
 
     return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
 }
 
-static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
+static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocolEx *iface)
 {
-    BindProtocol *This = PROTOCOL_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
 
     TRACE("(%p)\n", This);
 
     return IInternetProtocol_UnlockRequest(This->protocol_handler);
 }
 
-void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink)
-{
-    BindProtocol *This = PROTOCOL_THIS(bind_protocol);
-    IInternetProtocolSink *prev_sink;
-    IServiceProvider *service_provider = NULL;
-
-    if(sink)
-        IInternetProtocolSink_AddRef(sink);
-    prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
-    if(prev_sink)
-        IInternetProtocolSink_Release(prev_sink);
-
-    if(sink)
-        IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
-    service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
-    if(service_provider)
-        IServiceProvider_Release(service_provider);
-}
-
-IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol)
-{
-    BindProtocol *This = PROTOCOL_THIS(bind_protocol);
-
-    return This->wininet_info;
-}
-
-#undef PROTOCOL_THIS
-
-static const IInternetProtocolVtbl BindProtocolVtbl = {
-    BindProtocol_QueryInterface,
-    BindProtocol_AddRef,
-    BindProtocol_Release,
-    BindProtocol_Start,
-    BindProtocol_Continue,
-    BindProtocol_Abort,
-    BindProtocol_Terminate,
-    BindProtocol_Suspend,
-    BindProtocol_Resume,
-    BindProtocol_Read,
-    BindProtocol_Seek,
-    BindProtocol_LockRequest,
-    BindProtocol_UnlockRequest
-};
-
-#define PROTOCOLHANDLER_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolHandler, iface)
-
-static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
-{
-    ERR("should not be called\n");
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
-{
-    BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
-    return IInternetProtocol_AddRef(PROTOCOL(This));
-}
-
-static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
-{
-    BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
-    return IInternetProtocol_Release(PROTOCOL(This));
-}
-
-static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
+static HRESULT WINAPI BindProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
-        DWORD grfPI, HANDLE_PTR dwReserved)
+        DWORD grfPI, HANDLE *dwReserved)
 {
-    BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolEx(iface);
     IInternetProtocol *protocol = NULL;
+    IInternetProtocolEx *protocolex;
     IInternetPriority *priority;
     IServiceProvider *service_provider;
     BOOL urlmon_protocol = FALSE;
@@ -565,21 +472,22 @@ static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR sz
     LPOLESTR clsid_str;
     HRESULT hres;
 
-    TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
-            pOIBindInfo, grfPI, dwReserved);
+    TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
 
-    if(!szUrl || !pOIProtSink || !pOIBindInfo)
+    if(!pUri || !pOIProtSink || !pOIBindInfo)
         return E_INVALIDARG;
 
     This->pi = grfPI;
-    This->url = heap_strdupW(szUrl);
+
+    IUri_AddRef(pUri);
+    This->uri = pUri;
 
     hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
                                                 (void**)&service_provider);
     if(SUCCEEDED(hres)) {
         /* FIXME: What's protocol CLSID here? */
         IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
-                                      &IID_IInternetProtocol, (void**)&protocol);
+                &IID_IInternetProtocol, (void**)&protocol);
         IServiceProvider_Release(service_provider);
     }
 
@@ -587,7 +495,7 @@ static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR sz
         IClassFactory *cf;
         IUnknown *unk;
 
-        hres = get_protocol_handler(szUrl, &clsid, &urlmon_protocol, &cf);
+        hres = get_protocol_handler(pUri, &clsid, &urlmon_protocol, &cf);
         if(FAILED(hres))
             return hres;
 
@@ -597,7 +505,7 @@ static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR sz
             if(FAILED(hres))
                 return hres;
         }else {
-            hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
+            hres = IClassFactory_CreateInstance(cf, (IUnknown*)&This->IInternetBindInfo_iface,
                     &IID_IUnknown, (void**)&unk);
             IClassFactory_Release(cf);
             if(FAILED(hres))
@@ -616,13 +524,12 @@ static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR sz
 
     This->protocol = protocol;
 
-    if(urlmon_protocol)
+    if(urlmon_protocol) {
         IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
+        IInternetProtocol_QueryInterface(protocol, &IID_IWinInetHttpInfo, (void**)&This->wininet_http_info);
+    }
 
-    IInternetBindInfo_AddRef(pOIBindInfo);
-    This->bind_info = pOIBindInfo;
-
-    set_binding_sink(PROTOCOL(This), pOIProtSink);
+    set_binding_sink(This, pOIProtSink, pOIBindInfo);
 
     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
     if(SUCCEEDED(hres)) {
@@ -630,12 +537,122 @@ static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR sz
         IInternetPriority_Release(priority);
     }
 
-    return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0);
+    hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolEx, (void**)&protocolex);
+    if(SUCCEEDED(hres)) {
+        hres = IInternetProtocolEx_StartEx(protocolex, pUri, &This->IInternetProtocolSink_iface,
+                &This->IInternetBindInfo_iface, 0, NULL);
+        IInternetProtocolEx_Release(protocolex);
+    }else {
+        hres = IUri_GetDisplayUri(pUri, &This->display_uri);
+        if(FAILED(hres))
+            return hres;
+
+        hres = IInternetProtocol_Start(protocol, This->display_uri, &This->IInternetProtocolSink_iface,
+                &This->IInternetBindInfo_iface, 0, 0);
+    }
+
+    if(SUCCEEDED(hres))
+        process_tasks(This);
+    return hres;
+}
+
+void set_binding_sink(BindProtocol *This, IInternetProtocolSink *sink, IInternetBindInfo *bind_info)
+{
+    IInternetProtocolSink *prev_sink;
+    IServiceProvider *service_provider = NULL;
+
+    if(sink)
+        IInternetProtocolSink_AddRef(sink);
+    prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
+    if(prev_sink)
+        IInternetProtocolSink_Release(prev_sink);
+
+    if(sink)
+        IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
+    service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
+    if(service_provider)
+        IServiceProvider_Release(service_provider);
+
+    if(bind_info)
+        IInternetBindInfo_AddRef(bind_info);
+    bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info);
+    if(bind_info)
+        IInternetBindInfo_Release(bind_info);
+}
+
+static const IInternetProtocolExVtbl BindProtocolVtbl = {
+    BindProtocol_QueryInterface,
+    BindProtocol_AddRef,
+    BindProtocol_Release,
+    BindProtocol_Start,
+    BindProtocol_Continue,
+    BindProtocol_Abort,
+    BindProtocol_Terminate,
+    BindProtocol_Suspend,
+    BindProtocol_Resume,
+    BindProtocol_Read,
+    BindProtocol_Seek,
+    BindProtocol_LockRequest,
+    BindProtocol_UnlockRequest,
+    BindProtocol_StartEx
+};
+
+static inline BindProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
+{
+    return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocol_iface);
+}
+
+static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
+{
+    BindProtocol *This = impl_from_IInternetProtocol(iface);
+
+    *ppv = NULL;
+    if(IsEqualGUID(&IID_IUnknown, riid)) {
+        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
+        *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
+    }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
+        TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
+        *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
+    }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
+        TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
+        *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
+    }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
+        TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
+        *ppv = &This->default_protocol_handler.IInternetProtocolSink_iface;
+    }
+
+    if(*ppv) {
+        IInternetProtocol_AddRef(iface);
+        return S_OK;
+    }
+
+    WARN("not supported interface %s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
+{
+    BindProtocol *This = impl_from_IInternetProtocol(iface);
+    return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
+}
+
+static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
+{
+    BindProtocol *This = impl_from_IInternetProtocol(iface);
+    return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
+}
+
+static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
+        IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
+        DWORD grfPI, HANDLE_PTR dwReserved)
+{
+    ERR("Should not be called\n");
+    return E_NOTIMPL;
 }
 
 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
 {
-    BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocol(iface);
     HRESULT hres;
 
     TRACE("(%p)->(%p)\n", This, pProtocolData);
@@ -649,14 +666,19 @@ static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCO
 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
         DWORD dwOptions)
 {
-    BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
-    FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
-    return E_NOTIMPL;
+    BindProtocol *This = impl_from_IInternetProtocol(iface);
+
+    TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
+
+    if(This->protocol && !This->reported_result)
+        return IInternetProtocol_Abort(This->protocol, hrReason, dwOptions);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
 {
-    BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocol(iface);
 
     TRACE("(%p)->(%08x)\n", This, dwOptions);
 
@@ -665,12 +687,7 @@ static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD
 
     IInternetProtocol_Terminate(This->protocol, 0);
 
-    if(This->filter_proxy) {
-        IInternetProtocol_Release(PROTOCOL(This->filter_proxy));
-        This->filter_proxy = NULL;
-    }
-
-    set_binding_sink(PROTOCOL(This), NULL);
+    set_binding_sink(This, NULL, NULL);
 
     if(This->bind_info) {
         IInternetBindInfo_Release(This->bind_info);
@@ -682,14 +699,14 @@ static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD
 
 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
 {
-    BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocol(iface);
     FIXME("(%p)\n", This);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
 {
-    BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocol(iface);
     FIXME("(%p)\n", This);
     return E_NOTIMPL;
 }
@@ -697,7 +714,7 @@ static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
         ULONG cb, ULONG *pcbRead)
 {
-    BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocol(iface);
     ULONG read = 0;
     HRESULT hres = S_OK;
 
@@ -720,7 +737,11 @@ static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
     if(read < cb) {
         ULONG cread = 0;
 
+        if(is_apartment_thread(This))
+            This->continue_call++;
         hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
+        if(is_apartment_thread(This))
+            This->continue_call--;
         read += cread;
     }
 
@@ -731,14 +752,14 @@ static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
 {
-    BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocol(iface);
     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
     return E_NOTIMPL;
 }
 
 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
 {
-    BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocol(iface);
 
     TRACE("(%p)->(%08x)\n", This, dwOptions);
 
@@ -747,15 +768,13 @@ static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWOR
 
 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
 {
-    BindProtocol *This = PROTOCOLHANDLER_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocol(iface);
 
     TRACE("(%p)\n", This);
 
     return IInternetProtocol_UnlockRequest(This->protocol);
 }
 
-#undef PROTOCOL_THIS
-
 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
     ProtocolHandler_QueryInterface,
     ProtocolHandler_AddRef,
@@ -772,31 +791,220 @@ static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
     ProtocolHandler_UnlockRequest
 };
 
-#define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
+static inline BindProtocol *impl_from_IInternetProtocolSinkHandler(IInternetProtocolSink *iface)
+{
+    return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocolSink_iface);
+}
+
+static HRESULT WINAPI ProtocolSinkHandler_QueryInterface(IInternetProtocolSink *iface,
+        REFIID riid, void **ppvObject)
+{
+    BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
+    return IInternetProtocol_QueryInterface(&This->default_protocol_handler.IInternetProtocol_iface,
+            riid, ppvObject);
+}
+
+static ULONG WINAPI ProtocolSinkHandler_AddRef(IInternetProtocolSink *iface)
+{
+    BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
+    return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
+}
+
+static ULONG WINAPI ProtocolSinkHandler_Release(IInternetProtocolSink *iface)
+{
+    BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
+    return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
+}
+
+static HRESULT WINAPI ProtocolSinkHandler_Switch(IInternetProtocolSink *iface,
+        PROTOCOLDATA *pProtocolData)
+{
+    BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
+
+    TRACE("(%p)->(%p)\n", This, pProtocolData);
+
+    if(!This->protocol_sink) {
+        IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
+        return S_OK;
+    }
+
+    return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
+}
+
+static HRESULT WINAPI ProtocolSinkHandler_ReportProgress(IInternetProtocolSink *iface,
+        ULONG status_code, LPCWSTR status_text)
+{
+    BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
+
+    TRACE("(%p)->(%s %s)\n", This, debugstr_bindstatus(status_code), debugstr_w(status_text));
+
+    if(!This->protocol_sink)
+        return S_OK;
+
+    switch(status_code) {
+    case BINDSTATUS_FINDINGRESOURCE:
+    case BINDSTATUS_CONNECTING:
+    case BINDSTATUS_REDIRECTING:
+    case BINDSTATUS_SENDINGREQUEST:
+    case BINDSTATUS_CACHEFILENAMEAVAILABLE:
+    case BINDSTATUS_DIRECTBIND:
+    case BINDSTATUS_ACCEPTRANGES:
+    case BINDSTATUS_DECODING:
+        IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
+        break;
+
+    case BINDSTATUS_BEGINDOWNLOADDATA:
+        IInternetProtocolSink_ReportData(This->protocol_sink, This->bscf, This->progress, This->progress_max);
+        break;
+
+    case BINDSTATUS_MIMETYPEAVAILABLE:
+        mime_available(This, status_text, FALSE);
+        break;
+
+    case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
+        mime_available(This, status_text, TRUE);
+        break;
+
+    default:
+        FIXME("unsupported ulStatusCode %u\n", status_code);
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI ProtocolSinkHandler_ReportData(IInternetProtocolSink *iface,
+        DWORD bscf, ULONG progress, ULONG progress_max)
+{
+    BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
+
+    TRACE("(%p)->(%x %u %u)\n", This, bscf, progress, progress_max);
+
+    This->bscf = bscf;
+    This->progress = progress;
+    This->progress_max = progress_max;
+
+    if(!This->protocol_sink)
+        return S_OK;
+
+    if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
+        BYTE buf[BUFFER_SIZE];
+        DWORD read = 0;
+        LPWSTR mime;
+        HRESULT hres;
+
+        do {
+            read = 0;
+            if(is_apartment_thread(This))
+                This->continue_call++;
+            hres = IInternetProtocol_Read(This->protocol, buf,
+                    sizeof(buf)-This->buf_size, &read);
+            if(is_apartment_thread(This))
+                This->continue_call--;
+            if(FAILED(hres) && hres != E_PENDING)
+                return hres;
+
+            if(!This->buf) {
+                This->buf = heap_alloc(BUFFER_SIZE);
+                if(!This->buf)
+                    return E_OUTOFMEMORY;
+            }else if(read + This->buf_size > BUFFER_SIZE) {
+                BYTE *tmp;
+
+                tmp = heap_realloc(This->buf, read+This->buf_size);
+                if(!tmp)
+                    return E_OUTOFMEMORY;
+                This->buf = tmp;
+            }
+
+            memcpy(This->buf+This->buf_size, buf, read);
+            This->buf_size += read;
+        }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
+
+        if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
+            return S_OK;
+
+        bscf = BSCF_FIRSTDATANOTIFICATION;
+        if(hres == S_FALSE)
+            bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
+
+        if(!This->reported_mime) {
+            BSTR raw_uri;
+
+            hres = IUri_GetRawUri(This->uri, &raw_uri);
+            if(FAILED(hres))
+                return hres;
+
+            hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE),
+                    This->mime, 0, &mime, 0);
+            SysFreeString(raw_uri);
+            if(FAILED(hres))
+                return hres;
+
+            heap_free(This->mime);
+            This->mime = heap_strdupW(mime);
+            CoTaskMemFree(mime);
+            This->reported_mime = TRUE;
+            if(This->protocol_sink)
+                IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
+        }
+    }
+
+    if(!This->protocol_sink)
+        return S_OK;
+
+    return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
+}
+
+static HRESULT WINAPI ProtocolSinkHandler_ReportResult(IInternetProtocolSink *iface,
+        HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
+{
+    BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
+
+    TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
+
+    if(This->protocol_sink)
+        return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
+    return S_OK;
+}
+
+static const IInternetProtocolSinkVtbl InternetProtocolSinkHandlerVtbl = {
+    ProtocolSinkHandler_QueryInterface,
+    ProtocolSinkHandler_AddRef,
+    ProtocolSinkHandler_Release,
+    ProtocolSinkHandler_Switch,
+    ProtocolSinkHandler_ReportProgress,
+    ProtocolSinkHandler_ReportData,
+    ProtocolSinkHandler_ReportResult
+};
+
+static inline BindProtocol *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
+{
+    return CONTAINING_RECORD(iface, BindProtocol, IInternetBindInfo_iface);
+}
 
 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
         REFIID riid, void **ppv)
 {
-    BindProtocol *This = BINDINFO_THIS(iface);
-    return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
+    BindProtocol *This = impl_from_IInternetBindInfo(iface);
+    return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
 }
 
 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
 {
-    BindProtocol *This = BINDINFO_THIS(iface);
-    return IBinding_AddRef(PROTOCOL(This));
+    BindProtocol *This = impl_from_IInternetBindInfo(iface);
+    return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
 }
 
 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
 {
-    BindProtocol *This = BINDINFO_THIS(iface);
-    return IBinding_Release(PROTOCOL(This));
+    BindProtocol *This = impl_from_IInternetBindInfo(iface);
+    return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
 }
 
 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
         DWORD *grfBINDF, BINDINFO *pbindinfo)
 {
-    BindProtocol *This = BINDINFO_THIS(iface);
+    BindProtocol *This = impl_from_IInternetBindInfo(iface);
     HRESULT hres;
 
     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
@@ -814,15 +1022,13 @@ static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
 {
-    BindProtocol *This = BINDINFO_THIS(iface);
+    BindProtocol *This = impl_from_IInternetBindInfo(iface);
 
     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
 
     return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
 }
 
-#undef BINDFO_THIS
-
 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
     BindInfo_QueryInterface,
     BindInfo_AddRef,
@@ -831,30 +1037,33 @@ static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
     BindInfo_GetBindString
 };
 
-#define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
+static inline BindProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
+{
+    return CONTAINING_RECORD(iface, BindProtocol, IInternetPriority_iface);
+}
 
 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
         REFIID riid, void **ppv)
 {
-    BindProtocol *This = PRIORITY_THIS(iface);
-    return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
+    BindProtocol *This = impl_from_IInternetPriority(iface);
+    return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
 }
 
 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
 {
-    BindProtocol *This = PRIORITY_THIS(iface);
-    return IInternetProtocol_AddRef(PROTOCOL(This));
+    BindProtocol *This = impl_from_IInternetPriority(iface);
+    return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
 }
 
 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
 {
-    BindProtocol *This = PRIORITY_THIS(iface);
-    return IInternetProtocol_Release(PROTOCOL(This));
+    BindProtocol *This = impl_from_IInternetPriority(iface);
+    return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
 }
 
 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
 {
-    BindProtocol *This = PRIORITY_THIS(iface);
+    BindProtocol *This = impl_from_IInternetPriority(iface);
 
     TRACE("(%p)->(%d)\n", This, nPriority);
 
@@ -864,7 +1073,7 @@ static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LON
 
 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
 {
-    BindProtocol *This = PRIORITY_THIS(iface);
+    BindProtocol *This = impl_from_IInternetPriority(iface);
 
     TRACE("(%p)->(%p)\n", This, pnPriority);
 
@@ -872,8 +1081,6 @@ static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LON
     return S_OK;
 }
 
-#undef PRIORITY_THIS
-
 static const IInternetPriorityVtbl InternetPriorityVtbl = {
     InternetPriority_QueryInterface,
     InternetPriority_AddRef,
@@ -883,25 +1090,28 @@ static const IInternetPriorityVtbl InternetPriorityVtbl = {
 
 };
 
-#define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolSink, iface)
+static inline BindProtocol *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
+{
+    return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolSink_iface);
+}
 
 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
         REFIID riid, void **ppv)
 {
-    BindProtocol *This = PROTSINK_THIS(iface);
-    return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
+    BindProtocol *This = impl_from_IInternetProtocolSink(iface);
+    return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
 }
 
 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
 {
-    BindProtocol *This = PROTSINK_THIS(iface);
-    return IInternetProtocol_AddRef(PROTOCOL(This));
+    BindProtocol *This = impl_from_IInternetProtocolSink(iface);
+    return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
 }
 
 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
 {
-    BindProtocol *This = PROTSINK_THIS(iface);
-    return IInternetProtocol_Release(PROTOCOL(This));
+    BindProtocol *This = impl_from_IInternetProtocolSink(iface);
+    return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
 }
 
 typedef struct {
@@ -921,7 +1131,7 @@ static void switch_proc(BindProtocol *bind, task_header_t *t)
 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
         PROTOCOLDATA *pProtocolData)
 {
-    BindProtocol *This = PROTSINK_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolSink(iface);
     PROTOCOLDATA *data;
 
     TRACE("(%p)->(%p)\n", This, pProtocolData);
@@ -934,12 +1144,16 @@ static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface
         return E_OUTOFMEMORY;
     memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
 
-    if(!do_direct_notif(This)) {
+    if((This->pi&PI_APARTMENTTHREADED && pProtocolData->grfFlags&PI_FORCE_ASYNC)
+            || !do_direct_notif(This)) {
         switch_task_t *task;
 
         task = heap_alloc(sizeof(switch_task_t));
         if(!task)
+        {
+            heap_free(data);
             return E_OUTOFMEMORY;
+        }
 
         task->data = data;
 
@@ -947,40 +1161,7 @@ static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface
         return S_OK;
     }
 
-    if(!This->protocol_sink) {
-        IInternetProtocol_Continue(This->protocol_handler, data);
-        return S_OK;
-    }
-
-    return IInternetProtocolSink_Switch(This->protocol_sink, data);
-}
-
-static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
-{
-    switch(status_code) {
-    case BINDSTATUS_FINDINGRESOURCE:
-    case BINDSTATUS_CONNECTING:
-    case BINDSTATUS_REDIRECTING:
-    case BINDSTATUS_BEGINDOWNLOADDATA:
-    case BINDSTATUS_SENDINGREQUEST:
-    case BINDSTATUS_CACHEFILENAMEAVAILABLE:
-    case BINDSTATUS_DIRECTBIND:
-    case BINDSTATUS_ACCEPTRANGES:
-        if(This->protocol_sink)
-            IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
-        break;
-
-    case BINDSTATUS_MIMETYPEAVAILABLE:
-        mime_available(This, status_text, FALSE);
-        break;
-
-    case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
-        mime_available(This, status_text, TRUE);
-        break;
-
-    default:
-        FIXME("unsupported ulStatusCode %u\n", status_code);
-    }
+    return IInternetProtocolSink_Switch(This->protocol_sink_handler, data);
 }
 
 typedef struct {
@@ -994,7 +1175,7 @@ static void on_progress_proc(BindProtocol *This, task_header_t *t)
 {
     on_progress_task_t *task = (on_progress_task_t*)t;
 
-    report_progress(This, task->status_code, task->status_text);
+    IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, task->status_code, task->status_text);
 
     heap_free(task->status_text);
     heap_free(task);
@@ -1003,12 +1184,12 @@ static void on_progress_proc(BindProtocol *This, task_header_t *t)
 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
         ULONG ulStatusCode, LPCWSTR szStatusText)
 {
-    BindProtocol *This = PROTSINK_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolSink(iface);
 
     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
 
     if(do_direct_notif(This)) {
-        report_progress(This, ulStatusCode, szStatusText);
+        IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, ulStatusCode, szStatusText);
     }else {
         on_progress_task_t *task;
 
@@ -1023,65 +1204,6 @@ static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSin
     return S_OK;
 }
 
-static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max)
-{
-    if(!This->protocol_sink)
-        return S_OK;
-
-    if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
-        BYTE buf[BUFFER_SIZE];
-        DWORD read = 0;
-        LPWSTR mime;
-        HRESULT hres;
-
-        do {
-            read = 0;
-            hres = IInternetProtocol_Read(This->protocol, buf,
-                    sizeof(buf)-This->buf_size, &read);
-            if(FAILED(hres) && hres != E_PENDING)
-                return hres;
-
-            if(!This->buf) {
-                This->buf = heap_alloc(BUFFER_SIZE);
-                if(!This->buf)
-                    return E_OUTOFMEMORY;
-            }else if(read + This->buf_size > BUFFER_SIZE) {
-                BYTE *tmp;
-
-                tmp = heap_realloc(This->buf, read+This->buf_size);
-                if(!tmp)
-                    return E_OUTOFMEMORY;
-                This->buf = tmp;
-            }
-
-            memcpy(This->buf+This->buf_size, buf, read);
-            This->buf_size += read;
-        }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
-
-        if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
-            return S_OK;
-
-        bscf = BSCF_FIRSTDATANOTIFICATION;
-        if(hres == S_FALSE)
-            bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
-
-        if(!This->reported_mime) {
-            hres = FindMimeFromData(NULL, This->url, This->buf, min(This->buf_size, MIME_TEST_SIZE),
-                    This->mime, 0, &mime, 0);
-            if(FAILED(hres))
-                return hres;
-
-            mime_available(This, mime, TRUE);
-            CoTaskMemFree(mime);
-        }
-    }
-
-    if(!This->protocol_sink)
-        return S_OK;
-
-    return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
-}
-
 typedef struct {
     task_header_t header;
     DWORD bscf;
@@ -1093,16 +1215,18 @@ static void report_data_proc(BindProtocol *This, task_header_t *t)
 {
     report_data_task_t *task = (report_data_task_t*)t;
 
-    report_data(This, task->bscf, task->progress, task->progress_max);
+    IInternetProtocolSink_ReportData(This->protocol_sink_handler,
+            task->bscf, task->progress, task->progress_max);
+
     heap_free(task);
 }
 
 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
 {
-    BindProtocol *This = PROTSINK_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolSink(iface);
 
-    TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
+    TRACE("(%p)->(%x %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
 
     if(!This->protocol_sink)
         return S_OK;
@@ -1122,7 +1246,8 @@ static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *i
         return S_OK;
     }
 
-    return report_data(This, grfBSCF, ulProgress, ulProgressMax);
+    return IInternetProtocolSink_ReportData(This->protocol_sink_handler,
+            grfBSCF, ulProgress, ulProgressMax);
 }
 
 typedef struct {
@@ -1137,8 +1262,7 @@ static void report_result_proc(BindProtocol *This, task_header_t *t)
 {
     report_result_task_t *task = (report_result_task_t*)t;
 
-    if(This->protocol_sink)
-        IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str);
+    IInternetProtocolSink_ReportResult(This->protocol_sink_handler, task->hres, task->err, task->str);
 
     heap_free(task->str);
     heap_free(task);
@@ -1147,13 +1271,12 @@ static void report_result_proc(BindProtocol *This, task_header_t *t)
 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
 {
-    BindProtocol *This = PROTSINK_THIS(iface);
+    BindProtocol *This = impl_from_IInternetProtocolSink(iface);
 
     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
 
     if(!This->protocol_sink)
         return E_FAIL;
-
     This->reported_result = TRUE;
 
     if(!do_direct_notif(This)) {
@@ -1171,11 +1294,9 @@ static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink
         return S_OK;
     }
 
-    return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
+    return IInternetProtocolSink_ReportResult(This->protocol_sink_handler, hrResult, dwError, szResult);
 }
 
-#undef PROTSINK_THIS
-
 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
     BPInternetProtocolSink_QueryInterface,
     BPInternetProtocolSink_AddRef,
@@ -1186,30 +1307,33 @@ static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
     BPInternetProtocolSink_ReportResult
 };
 
-#define INETINFO_THIS(iface) DEFINE_THIS(BindProtocol, IWinInetHttpInfo, iface)
+static inline BindProtocol *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface)
+{
+    return CONTAINING_RECORD(iface, BindProtocol, IWinInetHttpInfo_iface);
+}
 
 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
 {
-    BindProtocol *This = INETINFO_THIS(iface);
-    return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
+    BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
+    return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
 }
 
 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface)
 {
-    BindProtocol *This = INETINFO_THIS(iface);
-    return IInternetProtocol_AddRef(PROTOCOL(This));
+    BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
+    return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
 }
 
 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface)
 {
-    BindProtocol *This = INETINFO_THIS(iface);
-    return IInternetProtocol_Release(PROTOCOL(This));
+    BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
+    return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
 }
 
 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
         void *pBuffer, DWORD *pcbBuffer)
 {
-    BindProtocol *This = INETINFO_THIS(iface);
+    BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
     FIXME("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
     return E_NOTIMPL;
 }
@@ -1217,13 +1341,11 @@ static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD
 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
         void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
 {
-    BindProtocol *This = INETINFO_THIS(iface);
+    BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
     FIXME("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
     return E_NOTIMPL;
 }
 
-#undef INETINFO_THIS
-
 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
     WinInetHttpInfo_QueryInterface,
     WinInetHttpInfo_AddRef,
@@ -1232,31 +1354,34 @@ static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
     WinInetHttpInfo_QueryInfo
 };
 
-#define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
+static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface)
+{
+    return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface);
+}
 
 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
         REFIID riid, void **ppv)
 {
-    BindProtocol *This = SERVPROV_THIS(iface);
-    return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
+    BindProtocol *This = impl_from_IServiceProvider(iface);
+    return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
 }
 
 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
 {
-    BindProtocol *This = SERVPROV_THIS(iface);
-    return IInternetProtocol_AddRef(PROTOCOL(This));
+    BindProtocol *This = impl_from_IServiceProvider(iface);
+    return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
 }
 
 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
 {
-    BindProtocol *This = SERVPROV_THIS(iface);
-    return IInternetProtocol_Release(PROTOCOL(This));
+    BindProtocol *This = impl_from_IServiceProvider(iface);
+    return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
 }
 
 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
         REFGUID guidService, REFIID riid, void **ppv)
 {
-    BindProtocol *This = SERVPROV_THIS(iface);
+    BindProtocol *This = impl_from_IServiceProvider(iface);
 
     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
 
@@ -1266,8 +1391,6 @@ static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
     return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
 }
 
-#undef SERVPROV_THIS
-
 static const IServiceProviderVtbl ServiceProviderVtbl = {
     BPServiceProvider_QueryInterface,
     BPServiceProvider_AddRef,
@@ -1275,27 +1398,31 @@ static const IServiceProviderVtbl ServiceProviderVtbl = {
     BPServiceProvider_QueryService
 };
 
-HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol)
+HRESULT create_binding_protocol(BOOL from_urlmon, BindProtocol **protocol)
 {
     BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
 
-    ret->lpIInternetProtocolVtbl        = &BindProtocolVtbl;
-    ret->lpInternetBindInfoVtbl         = &InternetBindInfoVtbl;
-    ret->lpInternetPriorityVtbl         = &InternetPriorityVtbl;
-    ret->lpServiceProviderVtbl          = &ServiceProviderVtbl;
-    ret->lpIInternetProtocolSinkVtbl    = &InternetProtocolSinkVtbl;
-    ret->lpIInternetProtocolHandlerVtbl = &InternetProtocolHandlerVtbl;
-    ret->lpIWinInetHttpInfoVtbl         = &WinInetHttpInfoVtbl;
+    ret->IInternetProtocolEx_iface.lpVtbl   = &BindProtocolVtbl;
+    ret->IInternetBindInfo_iface.lpVtbl     = &InternetBindInfoVtbl;
+    ret->IInternetPriority_iface.lpVtbl     = &InternetPriorityVtbl;
+    ret->IServiceProvider_iface.lpVtbl      = &ServiceProviderVtbl;
+    ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
+    ret->IWinInetHttpInfo_iface.lpVtbl      = &WinInetHttpInfoVtbl;
+
+    ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
+    ret->default_protocol_handler.IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkHandlerVtbl;
 
     ret->ref = 1;
     ret->from_urlmon = from_urlmon;
     ret->apartment_thread = GetCurrentThreadId();
     ret->notif_hwnd = get_notif_hwnd();
-    ret->protocol_handler = PROTOCOLHANDLER(ret);
+    ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
+    ret->protocol_sink_handler = &ret->default_protocol_handler.IInternetProtocolSink_iface;
     InitializeCriticalSection(&ret->section);
+    ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BindProtocol.section");
 
     URLMON_LockModule();
 
-    *protocol = PROTOCOL(ret);
+    *protocol = ret;
     return S_OK;
 }