Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendispex.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
1.7.6.1
|