Jacek Caban : urlmon: Added support for PI_APARTMENTTHREADED to BindProtocol::Switch.

Alexandre Julliard julliard at winehq.org
Tue May 12 09:08:46 CDT 2009


Module: wine
Branch: master
Commit: e487196dc2ec499ac11a0e99d9919db799a03f0f
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=e487196dc2ec499ac11a0e99d9919db799a03f0f

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Mon May 11 21:59:31 2009 +0200

urlmon: Added support for PI_APARTMENTTHREADED to BindProtocol::Switch.

---

 dlls/urlmon/binding.c     |    7 ++-
 dlls/urlmon/bindprot.c    |  117 ++++++++++++++++++++++++++++++++++++++++++++-
 dlls/urlmon/urlmon_main.h |    6 ++
 3 files changed, 126 insertions(+), 4 deletions(-)

diff --git a/dlls/urlmon/binding.c b/dlls/urlmon/binding.c
index f8ad73a..4b8651c 100644
--- a/dlls/urlmon/binding.c
+++ b/dlls/urlmon/binding.c
@@ -192,6 +192,9 @@ static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
         IBinding_Release(BINDING(binding));
         return 0;
     }
+    case WM_MK_CONTINUE2:
+        handle_bindprot_task((void*)lParam);
+        return 0;
     case WM_MK_RELEASE: {
         tls_data_t *data = get_tls_data();
 
@@ -205,7 +208,7 @@ static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
     return DefWindowProcW(hwnd, msg, wParam, lParam);
 }
 
-static HWND get_notif_hwnd(void)
+HWND get_notif_hwnd(void)
 {
     static ATOM wnd_class = 0;
     tls_data_t *tls_data;
@@ -250,7 +253,7 @@ static HWND get_notif_hwnd(void)
     return tls_data->notif_hwnd;
 }
 
-static void release_notif_hwnd(HWND hwnd)
+void release_notif_hwnd(HWND hwnd)
 {
     tls_data_t *data = get_tls_data();
 
diff --git a/dlls/urlmon/bindprot.c b/dlls/urlmon/bindprot.c
index 1f24594..eaee9b6 100644
--- a/dlls/urlmon/bindprot.c
+++ b/dlls/urlmon/bindprot.c
@@ -21,7 +21,18 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
 
-typedef struct {
+typedef struct BindProtocol BindProtocol;
+
+struct _task_header_t;
+
+typedef void (*task_proc_t)(BindProtocol*,struct _task_header_t*);
+
+typedef struct _task_header_t {
+    task_proc_t proc;
+    struct _task_header_t *next;
+} task_header_t;
+
+struct BindProtocol {
     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
     const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
     const IInternetPriorityVtbl *lpInternetPriorityVtbl;
@@ -40,7 +51,15 @@ typedef struct {
 
     BOOL reported_result;
     BOOL from_urlmon;
-} BindProtocol;
+    DWORD pi;
+
+    DWORD apartment_thread;
+    HWND notif_hwnd;
+    DWORD continue_call;
+
+    CRITICAL_SECTION section;
+    task_header_t *task_queue_head, *task_queue_tail;
+};
 
 #define PROTOCOL(x)  ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
 #define BINDINFO(x)  ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
@@ -48,6 +67,64 @@ typedef struct {
 #define SERVPROV(x)  ((IServiceProvider*)  &(x)->lpServiceProviderVtbl)
 #define PROTSINK(x)  ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
 
+void handle_bindprot_task(void *v)
+{
+    BindProtocol *This = v;
+    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;
+
+        This->continue_call++;
+        task->proc(This, task);
+        This->continue_call--;
+    }
+
+    IInternetProtocol_Release(PROTOCOL(This));
+}
+
+static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
+{
+    BOOL do_post = FALSE;
+
+    task->proc = proc;
+    task->next = NULL;
+
+    EnterCriticalSection(&This->section);
+
+    if(This->task_queue_tail) {
+        This->task_queue_tail->next = task;
+        This->task_queue_tail = task;
+    }else {
+        This->task_queue_tail = This->task_queue_head = task;
+        do_post = TRUE;
+    }
+
+    LeaveCriticalSection(&This->section);
+
+    if(do_post) {
+        IInternetProtocol_AddRef(PROTOCOL(This));
+        PostMessageW(This->notif_hwnd, WM_MK_CONTINUE2, 0, (LPARAM)This);
+    }
+}
+
+static BOOL inline do_direct_notif(BindProtocol *This)
+{
+    return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
+}
+
 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocol, iface)
 
 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
@@ -113,6 +190,10 @@ static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
             IInternetBindInfo_Release(This->bind_info);
 
         set_binding_sink(PROTOCOL(This), NULL);
+
+        if(This->notif_hwnd)
+            release_notif_hwnd(This->notif_hwnd);
+        DeleteCriticalSection(&This->section);
         heap_free(This);
 
         URLMON_UnlockModule();
@@ -140,6 +221,8 @@ static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl
     if(!szUrl || !pOIProtSink || !pOIBindInfo)
         return E_INVALIDARG;
 
+    This->pi = grfPI;
+
     hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
                                                 (void**)&service_provider);
     if(SUCCEEDED(hres)) {
@@ -468,6 +551,20 @@ static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
     return IInternetProtocol_Release(PROTOCOL(This));
 }
 
+typedef struct {
+    task_header_t header;
+    PROTOCOLDATA data;
+} switch_task_t;
+
+static void switch_proc(BindProtocol *bind, task_header_t *t)
+{
+    switch_task_t *task = (switch_task_t*)t;
+
+    IInternetProtocol_Continue(bind->protocol, &task->data);
+
+    heap_free(task);
+}
+
 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
         PROTOCOLDATA *pProtocolData)
 {
@@ -478,6 +575,19 @@ static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface
     TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
           pProtocolData->pData, pProtocolData->cbData);
 
+    if(!do_direct_notif(This)) {
+        switch_task_t *task;
+
+        task = heap_alloc(sizeof(switch_task_t));
+        if(!task)
+            return E_OUTOFMEMORY;
+
+        task->data = *pProtocolData;
+
+        push_task(This, &task->header, switch_proc);
+        return S_OK;
+    }
+
     if(!This->protocol_sink) {
         IInternetProtocol_Continue(This->protocol, pProtocolData);
         return S_OK;
@@ -615,6 +725,9 @@ HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol
 
     ret->ref = 1;
     ret->from_urlmon = from_urlmon;
+    ret->apartment_thread = GetCurrentThreadId();
+    ret->notif_hwnd = get_notif_hwnd();
+    InitializeCriticalSection(&ret->section);
 
     URLMON_LockModule();
 
diff --git a/dlls/urlmon/urlmon_main.h b/dlls/urlmon/urlmon_main.h
index aa2f276..13eb4f3 100644
--- a/dlls/urlmon/urlmon_main.h
+++ b/dlls/urlmon/urlmon_main.h
@@ -116,6 +116,12 @@ typedef struct {
 
 tls_data_t *get_tls_data(void);
 
+HWND get_notif_hwnd(void);
+void release_notif_hwnd(HWND);
+
+#define WM_MK_CONTINUE2   (WM_USER+103)
+void handle_bindprot_task(void*);
+
 static inline void *heap_alloc(size_t len)
 {
     return HeapAlloc(GetProcessHeap(), 0, len);




More information about the wine-cvs mailing list