ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

dispex.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2008 Jacek Caban for CodeWeavers
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include "jscript.h"
00020 
00021 #include "wine/unicode.h"
00022 #include "wine/debug.h"
00023 
00024 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
00025 
00026 /*
00027  * This IID is used to get DispatchEx objecto from interface.
00028  * We might consider using private insteface instead.
00029  */
00030 static const IID IID_IDispatchJS =
00031         {0x719c3050,0xf9d3,0x11cf,{0xa4,0x93,0x00,0x40,0x05,0x23,0xa8,0xa6}};
00032 
00033 #define FDEX_VERSION_MASK 0xf0000000
00034 
00035 typedef enum {
00036     PROP_VARIANT,
00037     PROP_BUILTIN,
00038     PROP_PROTREF,
00039     PROP_DELETED
00040 } prop_type_t;
00041 
00042 struct _dispex_prop_t {
00043     WCHAR *name;
00044     prop_type_t type;
00045     DWORD flags;
00046 
00047     union {
00048         VARIANT var;
00049         const builtin_prop_t *p;
00050         DWORD ref;
00051     } u;
00052 };
00053 
00054 static inline DISPID prop_to_id(DispatchEx *This, dispex_prop_t *prop)
00055 {
00056     return prop - This->props;
00057 }
00058 
00059 static inline dispex_prop_t *get_prop(DispatchEx *This, DISPID id)
00060 {
00061     if(id < 0 || id >= This->prop_cnt || This->props[id].type == PROP_DELETED)
00062         return NULL;
00063 
00064     return This->props+id;
00065 }
00066 
00067 static DWORD get_flags(DispatchEx *This, dispex_prop_t *prop)
00068 {
00069     if(prop->type == PROP_PROTREF) {
00070         dispex_prop_t *parent = get_prop(This->prototype, prop->u.ref);
00071         if(!parent) {
00072             prop->type = PROP_DELETED;
00073             return 0;
00074         }
00075 
00076         return get_flags(This->prototype, parent);
00077     }
00078 
00079     return prop->flags;
00080 }
00081 
00082 static const builtin_prop_t *find_builtin_prop(DispatchEx *This, const WCHAR *name)
00083 {
00084     int min = 0, max, i, r;
00085 
00086     max = This->builtin_info->props_cnt-1;
00087     while(min <= max) {
00088         i = (min+max)/2;
00089 
00090         r = strcmpW(name, This->builtin_info->props[i].name);
00091         if(!r)
00092             return This->builtin_info->props + i;
00093 
00094         if(r < 0)
00095             max = i-1;
00096         else
00097             min = i+1;
00098     }
00099 
00100     return NULL;
00101 }
00102 
00103 static dispex_prop_t *alloc_prop(DispatchEx *This, const WCHAR *name, prop_type_t type, DWORD flags)
00104 {
00105     dispex_prop_t *ret;
00106 
00107     if(This->buf_size == This->prop_cnt) {
00108         dispex_prop_t *tmp = heap_realloc(This->props, (This->buf_size<<=1)*sizeof(*This->props));
00109         if(!tmp)
00110             return NULL;
00111         This->props = tmp;
00112     }
00113 
00114     ret = This->props + This->prop_cnt++;
00115     ret->type = type;
00116     ret->flags = flags;
00117     ret->name = heap_strdupW(name);
00118     if(!ret->name)
00119         return NULL;
00120 
00121     return ret;
00122 }
00123 
00124 static dispex_prop_t *alloc_protref(DispatchEx *This, const WCHAR *name, DWORD ref)
00125 {
00126     dispex_prop_t *ret;
00127 
00128     ret = alloc_prop(This, name, PROP_PROTREF, 0);
00129     if(!ret)
00130         return NULL;
00131 
00132     ret->u.ref = ref;
00133     return ret;
00134 }
00135 
00136 static HRESULT find_prop_name(DispatchEx *This, const WCHAR *name, dispex_prop_t **ret)
00137 {
00138     const builtin_prop_t *builtin;
00139     dispex_prop_t *prop;
00140 
00141     for(prop = This->props; prop < This->props+This->prop_cnt; prop++) {
00142         if(prop->name && !strcmpW(prop->name, name)) {
00143             *ret = prop;
00144             return S_OK;
00145         }
00146     }
00147 
00148     builtin = find_builtin_prop(This, name);
00149     if(builtin) {
00150         prop = alloc_prop(This, name, PROP_BUILTIN, builtin->flags);
00151         if(!prop)
00152             return E_OUTOFMEMORY;
00153 
00154         prop->u.p = builtin;
00155         *ret = prop;
00156         return S_OK;
00157     }
00158 
00159     *ret = NULL;
00160     return S_OK;
00161 }
00162 
00163 static HRESULT find_prop_name_prot(DispatchEx *This, const WCHAR *name, dispex_prop_t **ret)
00164 {
00165     dispex_prop_t *prop;
00166     HRESULT hres;
00167 
00168     hres = find_prop_name(This, name, &prop);
00169     if(FAILED(hres))
00170         return hres;
00171     if(prop) {
00172         *ret = prop;
00173         return S_OK;
00174     }
00175 
00176     if(This->prototype) {
00177         hres = find_prop_name_prot(This->prototype, name, &prop);
00178         if(FAILED(hres))
00179             return hres;
00180         if(prop) {
00181             prop = alloc_protref(This, prop->name, prop - This->prototype->props);
00182             if(!prop)
00183                 return E_OUTOFMEMORY;
00184             *ret = prop;
00185             return S_OK;
00186         }
00187     }
00188 
00189     *ret = prop;
00190     return S_OK;
00191 }
00192 
00193 static HRESULT ensure_prop_name(DispatchEx *This, const WCHAR *name, BOOL search_prot, DWORD create_flags, dispex_prop_t **ret)
00194 {
00195     dispex_prop_t *prop;
00196     HRESULT hres;
00197 
00198     if(search_prot)
00199         hres = find_prop_name_prot(This, name, &prop);
00200     else
00201         hres = find_prop_name(This, name, &prop);
00202     if(SUCCEEDED(hres) && !prop) {
00203         TRACE("creating prop %s\n", debugstr_w(name));
00204 
00205         prop = alloc_prop(This, name, PROP_VARIANT, create_flags);
00206         if(!prop)
00207             return E_OUTOFMEMORY;
00208         VariantInit(&prop->u.var);
00209     }
00210 
00211     *ret = prop;
00212     return hres;
00213 }
00214 
00215 static HRESULT set_this(DISPPARAMS *dp, DISPPARAMS *olddp, IDispatch *jsthis)
00216 {
00217     VARIANTARG *oldargs;
00218     int i;
00219 
00220     static DISPID this_id = DISPID_THIS;
00221 
00222     *dp = *olddp;
00223 
00224     for(i = 0; i < dp->cNamedArgs; i++) {
00225         if(dp->rgdispidNamedArgs[i] == DISPID_THIS)
00226             return S_OK;
00227     }
00228 
00229     oldargs = dp->rgvarg;
00230     dp->rgvarg = heap_alloc((dp->cArgs+1) * sizeof(VARIANTARG));
00231     if(!dp->rgvarg)
00232         return E_OUTOFMEMORY;
00233     memcpy(dp->rgvarg+1, oldargs, dp->cArgs*sizeof(VARIANTARG));
00234     V_VT(dp->rgvarg) = VT_DISPATCH;
00235     V_DISPATCH(dp->rgvarg) = jsthis;
00236     dp->cArgs++;
00237 
00238     if(dp->cNamedArgs) {
00239         DISPID *old = dp->rgdispidNamedArgs;
00240         dp->rgdispidNamedArgs = heap_alloc((dp->cNamedArgs+1)*sizeof(DISPID));
00241         if(!dp->rgdispidNamedArgs) {
00242             heap_free(dp->rgvarg);
00243             return E_OUTOFMEMORY;
00244         }
00245 
00246         memcpy(dp->rgdispidNamedArgs+1, old, dp->cNamedArgs*sizeof(DISPID));
00247         dp->rgdispidNamedArgs[0] = DISPID_THIS;
00248         dp->cNamedArgs++;
00249     }else {
00250         dp->rgdispidNamedArgs = &this_id;
00251         dp->cNamedArgs = 1;
00252     }
00253 
00254     return S_OK;
00255 }
00256 
00257 static HRESULT invoke_prop_func(DispatchEx *This, DispatchEx *jsthis, dispex_prop_t *prop, WORD flags,
00258         DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
00259 {
00260     HRESULT hres;
00261 
00262     switch(prop->type) {
00263     case PROP_BUILTIN: {
00264         vdisp_t vthis;
00265 
00266         if(flags == DISPATCH_CONSTRUCT && (prop->flags & DISPATCH_METHOD)) {
00267             WARN("%s is not a constructor\n", debugstr_w(prop->name));
00268             return E_INVALIDARG;
00269         }
00270 
00271         set_jsdisp(&vthis, jsthis);
00272         hres = prop->u.p->invoke(This->ctx, &vthis, flags, dp, retv, ei, caller);
00273         vdisp_release(&vthis);
00274         return hres;
00275     }
00276     case PROP_PROTREF:
00277         return invoke_prop_func(This->prototype, jsthis, This->prototype->props+prop->u.ref, flags, dp, retv, ei, caller);
00278     case PROP_VARIANT: {
00279         DISPPARAMS new_dp;
00280 
00281         if(V_VT(&prop->u.var) != VT_DISPATCH) {
00282             FIXME("invoke vt %d\n", V_VT(&prop->u.var));
00283             return E_FAIL;
00284         }
00285 
00286         TRACE("call %s %p\n", debugstr_w(prop->name), V_DISPATCH(&prop->u.var));
00287 
00288         hres = set_this(&new_dp, dp, (IDispatch*)_IDispatchEx_(jsthis));
00289         if(FAILED(hres))
00290             return hres;
00291 
00292         hres = disp_call(This->ctx, V_DISPATCH(&prop->u.var), DISPID_VALUE, flags, &new_dp, retv, ei, caller);
00293 
00294         if(new_dp.rgvarg != dp->rgvarg) {
00295             heap_free(new_dp.rgvarg);
00296             if(new_dp.cNamedArgs > 1)
00297                 heap_free(new_dp.rgdispidNamedArgs);
00298         }
00299 
00300         return hres;
00301     }
00302     default:
00303         ERR("type %d\n", prop->type);
00304     }
00305 
00306     return E_FAIL;
00307 }
00308 
00309 static HRESULT prop_get(DispatchEx *This, dispex_prop_t *prop, DISPPARAMS *dp,
00310         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
00311 {
00312     HRESULT hres;
00313 
00314     switch(prop->type) {
00315     case PROP_BUILTIN:
00316         if(prop->u.p->flags & PROPF_METHOD) {
00317             DispatchEx *obj;
00318             hres = create_builtin_function(This->ctx, prop->u.p->invoke, prop->u.p->name, NULL,
00319                     prop->u.p->flags, NULL, &obj);
00320             if(FAILED(hres))
00321                 break;
00322 
00323             prop->type = PROP_VARIANT;
00324             V_VT(&prop->u.var) = VT_DISPATCH;
00325             V_DISPATCH(&prop->u.var) = (IDispatch*)_IDispatchEx_(obj);
00326 
00327             hres = VariantCopy(retv, &prop->u.var);
00328         }else {
00329             vdisp_t vthis;
00330 
00331             set_jsdisp(&vthis, This);
00332             hres = prop->u.p->invoke(This->ctx, &vthis, DISPATCH_PROPERTYGET, dp, retv, ei, caller);
00333             vdisp_release(&vthis);
00334         }
00335         break;
00336     case PROP_PROTREF:
00337         hres = prop_get(This->prototype, This->prototype->props+prop->u.ref, dp, retv, ei, caller);
00338         break;
00339     case PROP_VARIANT:
00340         hres = VariantCopy(retv, &prop->u.var);
00341         break;
00342     default:
00343         ERR("type %d\n", prop->type);
00344         return E_FAIL;
00345     }
00346 
00347     if(FAILED(hres)) {
00348         TRACE("fail %08x\n", hres);
00349         return hres;
00350     }
00351 
00352     TRACE("%s ret %s\n", debugstr_w(prop->name), debugstr_variant(retv));
00353     return hres;
00354 }
00355 
00356 static HRESULT prop_put(DispatchEx *This, dispex_prop_t *prop, VARIANT *val,
00357         jsexcept_t *ei, IServiceProvider *caller)
00358 {
00359     HRESULT hres;
00360 
00361     if(prop->flags & PROPF_CONST)
00362         return S_OK;
00363 
00364     switch(prop->type) {
00365     case PROP_BUILTIN:
00366         if(!(prop->flags & PROPF_METHOD)) {
00367             DISPPARAMS dp = {val, NULL, 1, 0};
00368             vdisp_t vthis;
00369 
00370             set_jsdisp(&vthis, This);
00371             hres = prop->u.p->invoke(This->ctx, &vthis, DISPATCH_PROPERTYPUT, &dp, NULL, ei, caller);
00372             vdisp_release(&vthis);
00373             return hres;
00374         }
00375     case PROP_PROTREF:
00376         prop->type = PROP_VARIANT;
00377         prop->flags = PROPF_ENUM;
00378         V_VT(&prop->u.var) = VT_EMPTY;
00379         break;
00380     case PROP_VARIANT:
00381         VariantClear(&prop->u.var);
00382         break;
00383     default:
00384         ERR("type %d\n", prop->type);
00385         return E_FAIL;
00386     }
00387 
00388     hres = VariantCopy(&prop->u.var, val);
00389     if(FAILED(hres))
00390         return hres;
00391 
00392     if(This->builtin_info->on_put)
00393         This->builtin_info->on_put(This, prop->name);
00394 
00395     TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_variant(val));
00396     return S_OK;
00397 }
00398 
00399 static HRESULT fill_protrefs(DispatchEx *This)
00400 {
00401     dispex_prop_t *iter, *prop;
00402     HRESULT hres;
00403 
00404     if(!This->prototype)
00405         return S_OK;
00406 
00407     fill_protrefs(This->prototype);
00408 
00409     for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) {
00410         if(!iter->name)
00411             continue;
00412         hres = find_prop_name(This, iter->name, &prop);
00413         if(FAILED(hres))
00414             return hres;
00415         if(!prop) {
00416             prop = alloc_protref(This, iter->name, iter - This->prototype->props);
00417             if(!prop)
00418                 return E_OUTOFMEMORY;
00419         }
00420     }
00421 
00422     return S_OK;
00423 }
00424 
00425 #define DISPATCHEX_THIS(iface) DEFINE_THIS(DispatchEx, IDispatchEx, iface)
00426 
00427 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
00428 {
00429     DispatchEx *This = DISPATCHEX_THIS(iface);
00430 
00431     if(IsEqualGUID(&IID_IUnknown, riid)) {
00432         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
00433         *ppv = _IDispatchEx_(This);
00434     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
00435         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
00436         *ppv = _IDispatchEx_(This);
00437     }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
00438         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
00439         *ppv = _IDispatchEx_(This);
00440     }else if(IsEqualGUID(&IID_IDispatchJS, riid)) {
00441         TRACE("(%p)->(IID_IDispatchJS %p)\n", This, ppv);
00442         IUnknown_AddRef(_IDispatchEx_(This));
00443         *ppv = This;
00444         return S_OK;
00445     }else {
00446         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
00447         *ppv = NULL;
00448         return E_NOINTERFACE;
00449     }
00450 
00451     IUnknown_AddRef((IUnknown*)*ppv);
00452     return S_OK;
00453 }
00454 
00455 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
00456 {
00457     DispatchEx *This = DISPATCHEX_THIS(iface);
00458     LONG ref = InterlockedIncrement(&This->ref);
00459 
00460     TRACE("(%p) ref=%d\n", This, ref);
00461 
00462     return ref;
00463 }
00464 
00465 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
00466 {
00467     DispatchEx *This = DISPATCHEX_THIS(iface);
00468     LONG ref = InterlockedDecrement(&This->ref);
00469 
00470     TRACE("(%p) ref=%d\n", This, ref);
00471 
00472     if(!ref) {
00473         dispex_prop_t *prop;
00474 
00475         for(prop = This->props; prop < This->props+This->prop_cnt; prop++) {
00476             if(prop->type == PROP_VARIANT)
00477                 VariantClear(&prop->u.var);
00478             heap_free(prop->name);
00479         }
00480         heap_free(This->props);
00481         script_release(This->ctx);
00482         if(This->prototype)
00483             jsdisp_release(This->prototype);
00484 
00485         if(This->builtin_info->destructor)
00486             This->builtin_info->destructor(This);
00487         else
00488             heap_free(This);
00489     }
00490 
00491     return ref;
00492 }
00493 
00494 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
00495 {
00496     DispatchEx *This = DISPATCHEX_THIS(iface);
00497 
00498     TRACE("(%p)->(%p)\n", This, pctinfo);
00499 
00500     *pctinfo = 1;
00501     return S_OK;
00502 }
00503 
00504 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
00505                                               ITypeInfo **ppTInfo)
00506 {
00507     DispatchEx *This = DISPATCHEX_THIS(iface);
00508     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
00509     return E_NOTIMPL;
00510 }
00511 
00512 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
00513                                                 LPOLESTR *rgszNames, UINT cNames, LCID lcid,
00514                                                 DISPID *rgDispId)
00515 {
00516     DispatchEx *This = DISPATCHEX_THIS(iface);
00517     UINT i;
00518     HRESULT hres;
00519 
00520     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
00521           lcid, rgDispId);
00522 
00523     for(i=0; i < cNames; i++) {
00524         hres = IDispatchEx_GetDispID(_IDispatchEx_(This), rgszNames[i], 0, rgDispId+i);
00525         if(FAILED(hres))
00526             return hres;
00527     }
00528 
00529     return S_OK;
00530 }
00531 
00532 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
00533                                         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
00534                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
00535 {
00536     DispatchEx *This = DISPATCHEX_THIS(iface);
00537 
00538     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
00539           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
00540 
00541     return IDispatchEx_InvokeEx(_IDispatchEx_(This), dispIdMember, lcid, wFlags,
00542             pDispParams, pVarResult, pExcepInfo, NULL);
00543 }
00544 
00545 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
00546 {
00547     DispatchEx *This = DISPATCHEX_THIS(iface);
00548 
00549     TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
00550 
00551     if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) {
00552         FIXME("Unsupported grfdex %x\n", grfdex);
00553         return E_NOTIMPL;
00554     }
00555 
00556     return jsdisp_get_id(This, bstrName, grfdex, pid);
00557 }
00558 
00559 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
00560         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
00561 {
00562     DispatchEx *This = DISPATCHEX_THIS(iface);
00563     dispex_prop_t *prop;
00564     jsexcept_t jsexcept;
00565     HRESULT hres;
00566 
00567     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
00568 
00569     if(pvarRes)
00570         V_VT(pvarRes) = VT_EMPTY;
00571 
00572     prop = get_prop(This, id);
00573     if(!prop || prop->type == PROP_DELETED) {
00574         TRACE("invalid id\n");
00575         return DISP_E_MEMBERNOTFOUND;
00576     }
00577 
00578     memset(&jsexcept, 0, sizeof(jsexcept));
00579 
00580     switch(wFlags) {
00581     case DISPATCH_METHOD:
00582     case DISPATCH_CONSTRUCT:
00583         hres = invoke_prop_func(This, This, prop, wFlags, pdp, pvarRes, &jsexcept, pspCaller);
00584         break;
00585     case DISPATCH_PROPERTYGET:
00586         hres = prop_get(This, prop, pdp, pvarRes, &jsexcept, pspCaller);
00587         break;
00588     case DISPATCH_PROPERTYPUT: {
00589         DWORD i;
00590 
00591         for(i=0; i < pdp->cNamedArgs; i++) {
00592             if(pdp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT)
00593                 break;
00594         }
00595 
00596         if(i == pdp->cNamedArgs) {
00597             TRACE("no value to set\n");
00598             return DISP_E_PARAMNOTOPTIONAL;
00599         }
00600 
00601         hres = prop_put(This, prop, pdp->rgvarg+i, &jsexcept, pspCaller);
00602         break;
00603     }
00604     default:
00605         FIXME("Unimplemented flags %x\n", wFlags);
00606         return E_INVALIDARG;
00607     }
00608 
00609     if(pei)
00610         *pei = jsexcept.ei;
00611 
00612     return hres;
00613 }
00614 
00615 static HRESULT delete_prop(dispex_prop_t *prop)
00616 {
00617     heap_free(prop->name);
00618     prop->name = NULL;
00619     prop->type = PROP_DELETED;
00620 
00621     return S_OK;
00622 }
00623 
00624 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
00625 {
00626     DispatchEx *This = DISPATCHEX_THIS(iface);
00627     dispex_prop_t *prop;
00628     HRESULT hres;
00629 
00630     TRACE("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
00631 
00632     if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK))
00633         FIXME("Unsupported grfdex %x\n", grfdex);
00634 
00635     hres = find_prop_name(This, bstrName, &prop);
00636     if(FAILED(hres))
00637         return hres;
00638     if(!prop) {
00639         TRACE("not found\n");
00640         return S_OK;
00641     }
00642 
00643     return delete_prop(prop);
00644 }
00645 
00646 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
00647 {
00648     DispatchEx *This = DISPATCHEX_THIS(iface);
00649     dispex_prop_t *prop;
00650 
00651     TRACE("(%p)->(%x)\n", This, id);
00652 
00653     prop = get_prop(This, id);
00654     if(!prop) {
00655         WARN("invalid id\n");
00656         return DISP_E_MEMBERNOTFOUND;
00657     }
00658 
00659     return delete_prop(prop);
00660 }
00661 
00662 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
00663 {
00664     DispatchEx *This = DISPATCHEX_THIS(iface);
00665     FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
00666     return E_NOTIMPL;
00667 }
00668 
00669 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
00670 {
00671     DispatchEx *This = DISPATCHEX_THIS(iface);
00672     dispex_prop_t *prop;
00673 
00674     TRACE("(%p)->(%x %p)\n", This, id, pbstrName);
00675 
00676     prop = get_prop(This, id);
00677     if(!prop || !prop->name || prop->type == PROP_DELETED)
00678         return DISP_E_MEMBERNOTFOUND;
00679 
00680     *pbstrName = SysAllocString(prop->name);
00681     if(!*pbstrName)
00682         return E_OUTOFMEMORY;
00683 
00684     return S_OK;
00685 }
00686 
00687 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
00688 {
00689     DispatchEx *This = DISPATCHEX_THIS(iface);
00690     dispex_prop_t *iter;
00691     HRESULT hres;
00692 
00693     TRACE("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
00694 
00695     if(id == DISPID_STARTENUM) {
00696         hres = fill_protrefs(This);
00697         if(FAILED(hres))
00698             return hres;
00699     }
00700 
00701     iter = get_prop(This, id+1);
00702     if(!iter) {
00703         *pid = DISPID_STARTENUM;
00704         return S_FALSE;
00705     }
00706 
00707     while(iter < This->props + This->prop_cnt) {
00708         if(iter->name && (get_flags(This, iter) & PROPF_ENUM)) {
00709             *pid = prop_to_id(This, iter);
00710             return S_OK;
00711         }
00712         iter++;
00713     }
00714 
00715     *pid = DISPID_STARTENUM;
00716     return S_FALSE;
00717 }
00718 
00719 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
00720 {
00721     DispatchEx *This = DISPATCHEX_THIS(iface);
00722     FIXME("(%p)->(%p)\n", This, ppunk);
00723     return E_NOTIMPL;
00724 }
00725 
00726 #undef DISPATCHEX_THIS
00727 
00728 static IDispatchExVtbl DispatchExVtbl = {
00729     DispatchEx_QueryInterface,
00730     DispatchEx_AddRef,
00731     DispatchEx_Release,
00732     DispatchEx_GetTypeInfoCount,
00733     DispatchEx_GetTypeInfo,
00734     DispatchEx_GetIDsOfNames,
00735     DispatchEx_Invoke,
00736     DispatchEx_GetDispID,
00737     DispatchEx_InvokeEx,
00738     DispatchEx_DeleteMemberByName,
00739     DispatchEx_DeleteMemberByDispID,
00740     DispatchEx_GetMemberProperties,
00741     DispatchEx_GetMemberName,
00742     DispatchEx_GetNextDispID,
00743     DispatchEx_GetNameSpaceParent
00744 };
00745 
00746 HRESULT init_dispex(DispatchEx *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, DispatchEx *prototype)
00747 {
00748     TRACE("%p (%p)\n", dispex, prototype);
00749 
00750     dispex->lpIDispatchExVtbl = &DispatchExVtbl;
00751     dispex->ref = 1;
00752     dispex->builtin_info = builtin_info;
00753 
00754     dispex->props = heap_alloc((dispex->buf_size=4) * sizeof(dispex_prop_t));
00755     if(!dispex->props)
00756         return E_OUTOFMEMORY;
00757 
00758     dispex->prototype = prototype;
00759     if(prototype)
00760         IDispatchEx_AddRef(_IDispatchEx_(prototype));
00761 
00762     dispex->prop_cnt = 1;
00763     dispex->props[0].name = NULL;
00764     dispex->props[0].flags = 0;
00765     if(builtin_info->value_prop.invoke) {
00766         dispex->props[0].type = PROP_BUILTIN;
00767         dispex->props[0].u.p = &builtin_info->value_prop;
00768     }else {
00769         dispex->props[0].type = PROP_DELETED;
00770     }
00771 
00772     script_addref(ctx);
00773     dispex->ctx = ctx;
00774 
00775     return S_OK;
00776 }
00777 
00778 static const builtin_info_t dispex_info = {
00779     JSCLASS_NONE,
00780     {NULL, NULL, 0},
00781     0, NULL,
00782     NULL,
00783     NULL
00784 };
00785 
00786 HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, DispatchEx *prototype, DispatchEx **dispex)
00787 {
00788     DispatchEx *ret;
00789     HRESULT hres;
00790 
00791     ret = heap_alloc_zero(sizeof(DispatchEx));
00792     if(!ret)
00793         return E_OUTOFMEMORY;
00794 
00795     hres = init_dispex(ret, ctx, builtin_info ? builtin_info : &dispex_info, prototype);
00796     if(FAILED(hres))
00797         return hres;
00798 
00799     *dispex = ret;
00800     return S_OK;
00801 }
00802 
00803 HRESULT init_dispex_from_constr(DispatchEx *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, DispatchEx *constr)
00804 {
00805     DispatchEx *prot = NULL;
00806     dispex_prop_t *prop;
00807     HRESULT hres;
00808 
00809     static const WCHAR constructorW[] = {'c','o','n','s','t','r','u','c','t','o','r'};
00810     static const WCHAR prototypeW[] = {'p','r','o','t','o','t','y','p','e',0};
00811 
00812     hres = find_prop_name_prot(constr, prototypeW, &prop);
00813     if(SUCCEEDED(hres) && prop) {
00814         jsexcept_t jsexcept;
00815         VARIANT var;
00816 
00817         V_VT(&var) = VT_EMPTY;
00818         memset(&jsexcept, 0, sizeof(jsexcept));
00819         hres = prop_get(constr, prop, NULL, &var, &jsexcept, NULL/*FIXME*/);
00820         if(FAILED(hres)) {
00821             ERR("Could not get prototype\n");
00822             return hres;
00823         }
00824 
00825         if(V_VT(&var) == VT_DISPATCH)
00826             prot = iface_to_jsdisp((IUnknown*)V_DISPATCH(&var));
00827         VariantClear(&var);
00828     }
00829 
00830     hres = init_dispex(dispex, ctx, builtin_info, prot);
00831 
00832     if(prot)
00833         jsdisp_release(prot);
00834     if(FAILED(hres))
00835         return hres;
00836 
00837     hres = ensure_prop_name(dispex, constructorW, FALSE, 0, &prop);
00838     if(SUCCEEDED(hres)) {
00839         jsexcept_t jsexcept;
00840         VARIANT var;
00841 
00842         V_VT(&var) = VT_DISPATCH;
00843         V_DISPATCH(&var) = (IDispatch*)_IDispatchEx_(constr);
00844         memset(&jsexcept, 0, sizeof(jsexcept));
00845         hres = prop_put(dispex, prop, &var, &jsexcept, NULL/*FIXME*/);
00846     }
00847     if(FAILED(hres))
00848         jsdisp_release(dispex);
00849 
00850     return hres;
00851 }
00852 
00853 DispatchEx *iface_to_jsdisp(IUnknown *iface)
00854 {
00855     DispatchEx *ret;
00856     HRESULT hres;
00857 
00858     hres = IUnknown_QueryInterface(iface, &IID_IDispatchJS, (void**)&ret);
00859     if(FAILED(hres))
00860         return NULL;
00861 
00862     return ret;
00863 }
00864 
00865 HRESULT jsdisp_get_id(DispatchEx *jsdisp, const WCHAR *name, DWORD flags, DISPID *id)
00866 {
00867     dispex_prop_t *prop;
00868     HRESULT hres;
00869 
00870     if(flags & fdexNameEnsure)
00871         hres = ensure_prop_name(jsdisp, name, TRUE, PROPF_ENUM, &prop);
00872     else
00873         hres = find_prop_name_prot(jsdisp, name, &prop);
00874     if(FAILED(hres))
00875         return hres;
00876 
00877     if(prop) {
00878         *id = prop_to_id(jsdisp, prop);
00879         return S_OK;
00880     }
00881 
00882     TRACE("not found %s\n", debugstr_w(name));
00883     return DISP_E_UNKNOWNNAME;
00884 }
00885 
00886 HRESULT jsdisp_call_value(DispatchEx *jsthis, WORD flags, DISPPARAMS *dp, VARIANT *retv,
00887         jsexcept_t *ei, IServiceProvider *caller)
00888 {
00889     vdisp_t vdisp;
00890     HRESULT hres;
00891 
00892     set_jsdisp(&vdisp, jsthis);
00893     hres = jsthis->builtin_info->value_prop.invoke(jsthis->ctx, &vdisp, flags, dp, retv, ei, caller);
00894     vdisp_release(&vdisp);
00895     return hres;
00896 }
00897 
00898 HRESULT jsdisp_call(DispatchEx *disp, DISPID id, WORD flags, DISPPARAMS *dp, VARIANT *retv,
00899         jsexcept_t *ei, IServiceProvider *caller)
00900 {
00901     dispex_prop_t *prop;
00902 
00903     memset(ei, 0, sizeof(*ei));
00904     if(retv)
00905         V_VT(retv) = VT_EMPTY;
00906 
00907     prop = get_prop(disp, id);
00908     if(!prop)
00909         return DISP_E_MEMBERNOTFOUND;
00910 
00911     return invoke_prop_func(disp, disp, prop, flags, dp, retv, ei, caller);
00912 }
00913 
00914 HRESULT jsdisp_call_name(DispatchEx *disp, const WCHAR *name, WORD flags, DISPPARAMS *dp, VARIANT *retv,
00915         jsexcept_t *ei, IServiceProvider *caller)
00916 {
00917     dispex_prop_t *prop;
00918     HRESULT hres;
00919 
00920     hres = find_prop_name_prot(disp, name, &prop);
00921     if(FAILED(hres))
00922         return hres;
00923 
00924     memset(ei, 0, sizeof(*ei));
00925     if(retv)
00926         V_VT(retv) = VT_EMPTY;
00927 
00928     return invoke_prop_func(disp, disp, prop, flags, dp, retv, ei, caller);
00929 }
00930 
00931 HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *dp, VARIANT *retv,
00932         jsexcept_t *ei, IServiceProvider *caller)
00933 {
00934     DispatchEx *jsdisp;
00935     IDispatchEx *dispex;
00936     HRESULT hres;
00937 
00938     jsdisp = iface_to_jsdisp((IUnknown*)disp);
00939     if(jsdisp) {
00940         hres = jsdisp_call(jsdisp, id, flags, dp, retv, ei, caller);
00941         jsdisp_release(jsdisp);
00942         return hres;
00943     }
00944 
00945     memset(ei, 0, sizeof(*ei));
00946 
00947     if(retv)
00948         V_VT(retv) = VT_EMPTY;
00949     hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
00950     if(FAILED(hres)) {
00951         UINT err = 0;
00952 
00953         if(flags == DISPATCH_CONSTRUCT) {
00954             WARN("IDispatch cannot be constructor\n");
00955             return DISP_E_MEMBERNOTFOUND;
00956         }
00957 
00958         TRACE("using IDispatch\n");
00959         return IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, dp, retv, &ei->ei, &err);
00960     }
00961 
00962     hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, retv, &ei->ei, caller);
00963     IDispatchEx_Release(dispex);
00964 
00965     return hres;
00966 }
00967 
00968 HRESULT jsdisp_propput_name(DispatchEx *obj, const WCHAR *name, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller)
00969 {
00970     dispex_prop_t *prop;
00971     HRESULT hres;
00972 
00973     hres = ensure_prop_name(obj, name, FALSE, PROPF_ENUM, &prop);
00974     if(FAILED(hres))
00975         return hres;
00976 
00977     return prop_put(obj, prop, val, ei, caller);
00978 }
00979 
00980 HRESULT jsdisp_propput_const(DispatchEx *obj, const WCHAR *name, VARIANT *val)
00981 {
00982     dispex_prop_t *prop;
00983     HRESULT hres;
00984 
00985     hres = ensure_prop_name(obj, name, FALSE, PROPF_ENUM|PROPF_CONST, &prop);
00986     if(FAILED(hres))
00987         return hres;
00988 
00989     return VariantCopy(&prop->u.var, val);
00990 }
00991 
00992 HRESULT jsdisp_propput_idx(DispatchEx *obj, DWORD idx, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller)
00993 {
00994     WCHAR buf[12];
00995 
00996     static const WCHAR formatW[] = {'%','d',0};
00997 
00998     sprintfW(buf, formatW, idx);
00999     return jsdisp_propput_name(obj, buf, val, ei, caller);
01000 }
01001 
01002 HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller)
01003 {
01004     DispatchEx *jsdisp;
01005     HRESULT hres;
01006 
01007     jsdisp = iface_to_jsdisp((IUnknown*)disp);
01008     if(jsdisp) {
01009         dispex_prop_t *prop;
01010 
01011         prop = get_prop(jsdisp, id);
01012         if(prop)
01013             hres = prop_put(jsdisp, prop, val, ei, caller);
01014         else
01015             hres = DISP_E_MEMBERNOTFOUND;
01016 
01017         jsdisp_release(jsdisp);
01018     }else {
01019         DISPID dispid = DISPID_PROPERTYPUT;
01020         DISPPARAMS dp  = {val, &dispid, 1, 1};
01021         IDispatchEx *dispex;
01022 
01023         hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
01024         if(SUCCEEDED(hres)) {
01025             hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, DISPATCH_PROPERTYPUT, &dp, NULL, &ei->ei, caller);
01026             IDispatchEx_Release(dispex);
01027         }else {
01028             ULONG err = 0;
01029 
01030             TRACE("using IDispatch\n");
01031             hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, DISPATCH_PROPERTYPUT, &dp, NULL, &ei->ei, &err);
01032         }
01033     }
01034 
01035     return hres;
01036 }
01037 
01038 HRESULT jsdisp_propget_name(DispatchEx *obj, const WCHAR *name, VARIANT *var, jsexcept_t *ei, IServiceProvider *caller)
01039 {
01040     DISPPARAMS dp = {NULL, NULL, 0, 0};
01041     dispex_prop_t *prop;
01042     HRESULT hres;
01043 
01044     hres = find_prop_name_prot(obj, name, &prop);
01045     if(FAILED(hres))
01046         return hres;
01047 
01048     V_VT(var) = VT_EMPTY;
01049     if(!prop)
01050         return S_OK;
01051 
01052     return prop_get(obj, prop, &dp, var, ei, caller);
01053 }
01054 
01055 HRESULT jsdisp_get_idx(DispatchEx *obj, DWORD idx, VARIANT *var, jsexcept_t *ei, IServiceProvider *caller)
01056 {
01057     WCHAR name[12];
01058     DISPPARAMS dp = {NULL, NULL, 0, 0};
01059     dispex_prop_t *prop;
01060     HRESULT hres;
01061 
01062     static const WCHAR formatW[] = {'%','d',0};
01063 
01064     sprintfW(name, formatW, idx);
01065 
01066     hres = find_prop_name_prot(obj, name, &prop);
01067     if(FAILED(hres))
01068         return hres;
01069 
01070     V_VT(var) = VT_EMPTY;
01071     if(!prop)
01072         return DISP_E_UNKNOWNNAME;
01073 
01074     return prop_get(obj, prop, &dp, var, ei, caller);
01075 }
01076 
01077 HRESULT jsdisp_propget(DispatchEx *jsdisp, DISPID id, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller)
01078 {
01079     DISPPARAMS dp  = {NULL,NULL,0,0};
01080     dispex_prop_t *prop;
01081 
01082     prop = get_prop(jsdisp, id);
01083     if(!prop)
01084         return DISP_E_MEMBERNOTFOUND;
01085 
01086     V_VT(val) = VT_EMPTY;
01087     return prop_get(jsdisp, prop, &dp, val, ei, caller);
01088 }
01089 
01090 HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, VARIANT *val, jsexcept_t *ei, IServiceProvider *caller)
01091 {
01092     DISPPARAMS dp  = {NULL,NULL,0,0};
01093     IDispatchEx *dispex;
01094     DispatchEx *jsdisp;
01095     HRESULT hres;
01096 
01097     jsdisp = iface_to_jsdisp((IUnknown*)disp);
01098     if(jsdisp) {
01099         hres = jsdisp_propget(jsdisp, id, val, ei, caller);
01100         jsdisp_release(jsdisp);
01101         return hres;
01102     }
01103 
01104     hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
01105     if(FAILED(hres)) {
01106         ULONG err = 0;
01107 
01108         TRACE("using IDispatch\n");
01109         return IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, INVOKE_PROPERTYGET, &dp, val, &ei->ei, &err);
01110     }
01111 
01112     hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, INVOKE_PROPERTYGET, &dp, val, &ei->ei, caller);
01113     IDispatchEx_Release(dispex);
01114 
01115     return hres;
01116 }
01117 
01118 HRESULT jsdisp_delete_idx(DispatchEx *obj, DWORD idx)
01119 {
01120     static const WCHAR formatW[] = {'%','d',0};
01121     WCHAR buf[12];
01122     dispex_prop_t *prop;
01123     HRESULT hres;
01124 
01125     sprintfW(buf, formatW, idx);
01126 
01127     hres = find_prop_name(obj, buf, &prop);
01128     if(FAILED(hres) || !prop)
01129         return hres;
01130 
01131     return delete_prop(prop);
01132 }

Generated on Sun May 27 2012 04:24:19 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.