Jacek Caban : mshtml: Added support for overriding builtin functions.

Alexandre Julliard julliard at winehq.org
Mon Sep 24 16:04:27 CDT 2012


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

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Mon Sep 24 14:10:05 2012 +0200

mshtml: Added support for overriding builtin functions.

---

 dlls/mshtml/dispex.c |  135 +++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 107 insertions(+), 28 deletions(-)

diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c
index eca45a6..cc22ce4 100644
--- a/dlls/mshtml/dispex.c
+++ b/dlls/mshtml/dispex.c
@@ -74,15 +74,21 @@ typedef struct {
 typedef struct {
     DispatchEx dispex;
     IUnknown IUnknown_iface;
+    LONG ref;
     DispatchEx *obj;
     func_info_t *info;
 } func_disp_t;
 
+typedef struct {
+    func_disp_t *func_obj;
+    IDispatch *val;
+} func_obj_entry_t;
+
 struct dispex_dynamic_data_t {
     DWORD buf_size;
     DWORD prop_cnt;
     dynamic_prop_t *props;
-    func_disp_t **func_disps;
+    func_obj_entry_t *func_disps;
 };
 
 #define DISPID_DYNPROP_0    0x50000000
@@ -575,19 +581,27 @@ static HRESULT WINAPI Function_QueryInterface(IUnknown *iface, REFIID riid, void
 static ULONG WINAPI Function_AddRef(IUnknown *iface)
 {
     func_disp_t *This = impl_from_IUnknown(iface);
+    LONG ref = InterlockedIncrement(&This->ref);
 
-    TRACE("(%p)\n", This);
+    TRACE("(%p) ref=%d\n", This, ref);
 
-    return IDispatchEx_AddRef(&This->obj->IDispatchEx_iface);
+    return ref;
 }
 
 static ULONG WINAPI Function_Release(IUnknown *iface)
 {
     func_disp_t *This = impl_from_IUnknown(iface);
+    LONG ref = InterlockedDecrement(&This->ref);
 
-    TRACE("(%p)\n", This);
+    TRACE("(%p) ref=%d\n", This, ref);
 
-    return IDispatchEx_Release(&This->obj->IDispatchEx_iface);
+    if(!ref) {
+        assert(!This->obj);
+        release_dispex(&This->dispex);
+        heap_free(This);
+    }
+
+    return ref;
 }
 
 static const IUnknownVtbl FunctionUnkVtbl = {
@@ -613,6 +627,8 @@ static HRESULT function_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPAR
             return E_INVALIDARG;
         /* fall through */
     case DISPATCH_METHOD:
+        if(!This->obj)
+            return E_UNEXPECTED;
         hres = typeinfo_invoke(This->obj, This->info, flags, params, res, ei);
         break;
     default:
@@ -649,6 +665,7 @@ static func_disp_t *create_func_disp(DispatchEx *obj, func_info_t *info)
 
     ret->IUnknown_iface.lpVtbl = &FunctionUnkVtbl;
     init_dispex(&ret->dispex, &ret->IUnknown_iface,  &function_dispex);
+    ret->ref = 1;
     ret->obj = obj;
     ret->info = info;
 
@@ -696,6 +713,37 @@ static HRESULT invoke_disp_value(DispatchEx *This, IDispatch *func_disp, LCID lc
     return hres;
 }
 
+static HRESULT get_func_obj_entry(DispatchEx *This, func_info_t *func, func_obj_entry_t **ret)
+{
+    dispex_dynamic_data_t *dynamic_data;
+
+    dynamic_data = get_dynamic_data(This);
+    if(!dynamic_data)
+        return E_OUTOFMEMORY;
+
+    if(!dynamic_data->func_disps) {
+        dynamic_data->func_disps = heap_alloc_zero(This->data->data->func_disp_cnt * sizeof(*dynamic_data->func_disps));
+        if(!dynamic_data->func_disps)
+            return E_OUTOFMEMORY;
+    }
+
+    if(!dynamic_data->func_disps[func->func_disp_idx].func_obj) {
+        func_disp_t *func_obj;
+
+        func_obj = create_func_disp(This, func);
+        if(!func_obj)
+            return E_OUTOFMEMORY;
+
+        dynamic_data->func_disps[func->func_disp_idx].func_obj = func_obj;
+
+        IDispatchEx_AddRef(&func_obj->dispex.IDispatchEx_iface);
+        dynamic_data->func_disps[func->func_disp_idx].val = (IDispatch*)&func_obj->dispex.IDispatchEx_iface;
+    }
+
+    *ret = dynamic_data->func_disps+func->func_disp_idx;
+    return S_OK;
+}
+
 static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res,
         EXCEPINFO *ei)
 {
@@ -707,10 +755,25 @@ static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags,
             return E_INVALIDARG;
         /* fall through */
     case DISPATCH_METHOD:
+        if(This->dynamic_data && This->dynamic_data && This->dynamic_data->func_disps
+           && This->dynamic_data->func_disps[func->func_disp_idx].func_obj) {
+            func_obj_entry_t *entry = This->dynamic_data->func_disps + func->func_disp_idx;
+
+            if((IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface != entry->val) {
+                if(!entry->val) {
+                    FIXME("Calling null\n");
+                    return E_FAIL;
+                }
+
+                hres = invoke_disp_value(This, entry->val, 0, flags, dp, res, ei, NULL);
+                break;
+            }
+        }
+
         hres = typeinfo_invoke(This, func, flags, dp, res, ei);
         break;
     case DISPATCH_PROPERTYGET: {
-        dispex_dynamic_data_t *dynamic_data;
+        func_obj_entry_t *entry;
 
         if(func->id == DISPID_VALUE) {
             BSTR ret;
@@ -724,32 +787,46 @@ static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags,
             return S_OK;
         }
 
-        dynamic_data = get_dynamic_data(This);
-        if(!dynamic_data)
-            return E_OUTOFMEMORY;
+        hres = get_func_obj_entry(This, func, &entry);
+        if(FAILED(hres))
+            return hres;
 
-        if(!dynamic_data->func_disps) {
-            dynamic_data->func_disps = heap_alloc_zero(This->data->data->func_disp_cnt * sizeof(func_disp_t*));
-            if(!dynamic_data->func_disps)
-                return E_OUTOFMEMORY;
-        }
+        V_VT(res) = VT_DISPATCH;
+        V_DISPATCH(res) = entry->val;
+        if(V_DISPATCH(res))
+            IDispatch_AddRef(V_DISPATCH(res));
+        hres = S_OK;
+        break;
+    }
+    case DISPATCH_PROPERTYPUT: {
+        func_obj_entry_t *entry;
+        VARIANT *v;
 
-        if(!dynamic_data->func_disps[func->func_disp_idx]) {
-            dynamic_data->func_disps[func->func_disp_idx] = create_func_disp(This, func);
-            if(!dynamic_data->func_disps[func->func_disp_idx])
-                return E_OUTOFMEMORY;
+        if(dp->cArgs != 1 || (dp->cNamedArgs == 1 && *dp->rgdispidNamedArgs != DISPID_PROPERTYPUT)
+           || dp->cNamedArgs > 1) {
+            FIXME("invalid args\n");
+            return E_INVALIDARG;
         }
 
-        V_VT(res) = VT_DISPATCH;
-        V_DISPATCH(res) = (IDispatch*)&dynamic_data->func_disps[func->func_disp_idx]->dispex.IDispatchEx_iface;
-        IDispatch_AddRef(V_DISPATCH(res));
+        v = dp->rgvarg;
+        /* FIXME: not exactly right */
+        if(V_VT(v) != VT_DISPATCH)
+            return E_NOTIMPL;
+
+        hres = get_func_obj_entry(This, func, &entry);
+        if(FAILED(hres))
+            return hres;
+
+        if(entry->val)
+            IDispatch_Release(entry->val);
+        entry->val = V_DISPATCH(v);
+        if(entry->val)
+            IDispatch_AddRef(entry->val);
         hres = S_OK;
         break;
     }
     default:
         FIXME("Unimplemented flags %x\n", flags);
-        /* fall through */
-    case DISPATCH_PROPERTYPUT:
         hres = E_NOTIMPL;
     }
 
@@ -1445,13 +1522,15 @@ void release_dispex(DispatchEx *This)
     heap_free(This->dynamic_data->props);
 
     if(This->dynamic_data->func_disps) {
-        unsigned i;
+        func_obj_entry_t *iter;
 
-        for(i=0; i < This->data->data->func_disp_cnt; i++) {
-            if(This->dynamic_data->func_disps[i]) {
-                release_dispex(&This->dynamic_data->func_disps[i]->dispex);
-                heap_free(This->dynamic_data->func_disps[i]);
+        for(iter = This->dynamic_data->func_disps; iter < This->dynamic_data->func_disps+This->data->data->func_disp_cnt; iter++) {
+            if(iter->func_obj) {
+                iter->func_obj->obj = NULL;
+                IDispatchEx_Release(&iter->func_obj->dispex.IDispatchEx_iface);
             }
+            if(iter->val)
+                IDispatch_Release(iter->val);
         }
 
         heap_free(This->dynamic_data->func_disps);




More information about the wine-cvs mailing list