1 /* 2 * Copyright 2008-2009 Jacek Caban for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include "mshtml_private.h" 20 21 #define MAX_ARGS 16 22 23 static CRITICAL_SECTION cs_dispex_static_data; 24 static CRITICAL_SECTION_DEBUG cs_dispex_static_data_dbg = 25 { 26 0, 0, &cs_dispex_static_data, 27 { &cs_dispex_static_data_dbg.ProcessLocksList, &cs_dispex_static_data_dbg.ProcessLocksList }, 28 0, 0, { (DWORD_PTR)(__FILE__ ": dispex_static_data") } 29 }; 30 static CRITICAL_SECTION cs_dispex_static_data = { &cs_dispex_static_data_dbg, -1, 0, 0, 0, 0 }; 31 32 33 static const WCHAR objectW[] = {'[','o','b','j','e','c','t',']',0}; 34 35 typedef struct { 36 DISPID id; 37 BSTR name; 38 tid_t tid; 39 SHORT call_vtbl_off; 40 SHORT put_vtbl_off; 41 SHORT get_vtbl_off; 42 SHORT func_disp_idx; 43 USHORT argc; 44 VARTYPE prop_vt; 45 VARTYPE *arg_types; 46 } func_info_t; 47 48 struct dispex_data_t { 49 DWORD func_cnt; 50 func_info_t *funcs; 51 func_info_t **name_table; 52 DWORD func_disp_cnt; 53 54 struct list entry; 55 }; 56 57 typedef struct { 58 VARIANT var; 59 LPWSTR name; 60 DWORD flags; 61 } dynamic_prop_t; 62 63 #define DYNPROP_DELETED 0x01 64 65 typedef struct { 66 DispatchEx dispex; 67 IUnknown IUnknown_iface; 68 LONG ref; 69 DispatchEx *obj; 70 func_info_t *info; 71 } func_disp_t; 72 73 typedef struct { 74 func_disp_t *func_obj; 75 VARIANT val; 76 } func_obj_entry_t; 77 78 struct dispex_dynamic_data_t { 79 DWORD buf_size; 80 DWORD prop_cnt; 81 dynamic_prop_t *props; 82 func_obj_entry_t *func_disps; 83 }; 84 85 #define DISPID_DYNPROP_0 0x50000000 86 #define DISPID_DYNPROP_MAX 0x5fffffff 87 88 #define FDEX_VERSION_MASK 0xf0000000 89 90 static ITypeLib *typelib; 91 static ITypeInfo *typeinfos[LAST_tid]; 92 static struct list dispex_data_list = LIST_INIT(dispex_data_list); 93 94 static REFIID tid_ids[] = { 95 #define XIID(iface) &IID_ ## iface, 96 #define XDIID(iface) &DIID_ ## iface, 97 TID_LIST 98 #undef XIID 99 #undef XDIID 100 }; 101 102 static HRESULT load_typelib(void) 103 { 104 HRESULT hres; 105 ITypeLib *tl; 106 107 hres = LoadRegTypeLib(&LIBID_MSHTML, 4, 0, LOCALE_SYSTEM_DEFAULT, &tl); 108 if(FAILED(hres)) { 109 ERR("LoadRegTypeLib failed: %08x\n", hres); 110 return hres; 111 } 112 113 if(InterlockedCompareExchangePointer((void**)&typelib, tl, NULL)) 114 ITypeLib_Release(tl); 115 return hres; 116 } 117 118 static HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo) 119 { 120 HRESULT hres; 121 122 if (!typelib) 123 hres = load_typelib(); 124 if (!typelib) 125 return hres; 126 127 if(!typeinfos[tid]) { 128 ITypeInfo *ti; 129 130 hres = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &ti); 131 if(FAILED(hres)) { 132 ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_mshtml_guid(tid_ids[tid]), hres); 133 return hres; 134 } 135 136 if(InterlockedCompareExchangePointer((void**)(typeinfos+tid), ti, NULL)) 137 ITypeInfo_Release(ti); 138 } 139 140 *typeinfo = typeinfos[tid]; 141 return S_OK; 142 } 143 144 void release_typelib(void) 145 { 146 dispex_data_t *iter; 147 unsigned i; 148 149 while(!list_empty(&dispex_data_list)) { 150 iter = LIST_ENTRY(list_head(&dispex_data_list), dispex_data_t, entry); 151 list_remove(&iter->entry); 152 153 for(i=0; i < iter->func_cnt; i++) 154 SysFreeString(iter->funcs[i].name); 155 156 heap_free(iter->funcs); 157 heap_free(iter->name_table); 158 heap_free(iter); 159 } 160 161 if(!typelib) 162 return; 163 164 for(i=0; i < sizeof(typeinfos)/sizeof(*typeinfos); i++) 165 if(typeinfos[i]) 166 ITypeInfo_Release(typeinfos[i]); 167 168 ITypeLib_Release(typelib); 169 DeleteCriticalSection(&cs_dispex_static_data); 170 } 171 172 HRESULT get_htmldoc_classinfo(ITypeInfo **typeinfo) 173 { 174 HRESULT hres; 175 176 if (!typelib) 177 hres = load_typelib(); 178 if (!typelib) 179 return hres; 180 181 hres = ITypeLib_GetTypeInfoOfGuid(typelib, &CLSID_HTMLDocument, typeinfo); 182 if(FAILED(hres)) 183 ERR("GetTypeInfoOfGuid failed: %08x\n", hres); 184 return hres; 185 } 186 187 /* Not all argument types are supported yet */ 188 #define BUILTIN_ARG_TYPES_SWITCH \ 189 CASE_VT(VT_I2, INT16, V_I2); \ 190 CASE_VT(VT_I4, INT32, V_I4); \ 191 CASE_VT(VT_R4, float, V_R4); \ 192 CASE_VT(VT_BSTR, BSTR, V_BSTR); \ 193 CASE_VT(VT_BOOL, VARIANT_BOOL, V_BOOL) 194 195 /* List all types used by IDispatchEx-based properties */ 196 #define BUILTIN_TYPES_SWITCH \ 197 BUILTIN_ARG_TYPES_SWITCH; \ 198 CASE_VT(VT_VARIANT, VARIANT, *); \ 199 CASE_VT(VT_PTR, void*, V_BYREF); \ 200 CASE_VT(VT_UNKNOWN, IUnknown*, V_UNKNOWN); \ 201 CASE_VT(VT_DISPATCH, IDispatch*, V_DISPATCH) 202 203 static BOOL is_arg_type_supported(VARTYPE vt) 204 { 205 switch(vt) { 206 #define CASE_VT(x,a,b) case x: return TRUE 207 BUILTIN_ARG_TYPES_SWITCH; 208 #undef CASE_VT 209 } 210 return FALSE; 211 } 212 213 static void add_func_info(dispex_data_t *data, DWORD *size, tid_t tid, const FUNCDESC *desc, ITypeInfo *dti) 214 { 215 func_info_t *info; 216 HRESULT hres; 217 218 for(info = data->funcs; info < data->funcs+data->func_cnt; info++) { 219 if(info->id == desc->memid) { 220 if(info->tid != tid) 221 return; /* Duplicated in other interface */ 222 break; 223 } 224 } 225 226 if(info == data->funcs+data->func_cnt) { 227 if(data->func_cnt == *size) 228 data->funcs = heap_realloc_zero(data->funcs, (*size <<= 1)*sizeof(func_info_t)); 229 230 info = data->funcs+data->func_cnt; 231 hres = ITypeInfo_GetDocumentation(dti, desc->memid, &info->name, NULL, NULL, NULL); 232 if(FAILED(hres)) 233 return; 234 235 data->func_cnt++; 236 237 info->id = desc->memid; 238 info->tid = tid; 239 info->func_disp_idx = -1; 240 info->prop_vt = VT_EMPTY; 241 } 242 243 if(desc->invkind & DISPATCH_METHOD) { 244 unsigned i; 245 246 info->func_disp_idx = data->func_disp_cnt++; 247 info->argc = desc->cParams; 248 249 assert(info->argc < MAX_ARGS); 250 assert(desc->funckind == FUNC_DISPATCH); 251 252 info->arg_types = heap_alloc(sizeof(*info->arg_types) * info->argc); 253 if(!info->arg_types) 254 return; /* FIXME: real error instead of fallback */ 255 256 for(i=0; i < info->argc; i++) 257 info->arg_types[i] = desc->lprgelemdescParam[i].tdesc.vt; 258 259 info->prop_vt = desc->elemdescFunc.tdesc.vt; 260 if(info->prop_vt != VT_VOID && !is_arg_type_supported(info->prop_vt)) { 261 TRACE("%s: return type %d\n", debugstr_w(info->name), info->prop_vt); 262 return; /* Fallback to ITypeInfo::Invoke */ 263 } 264 265 if(desc->cParamsOpt) { 266 TRACE("%s: optional params\n", debugstr_w(info->name)); 267 return; /* Fallback to ITypeInfo::Invoke */ 268 } 269 270 for(i=0; i < info->argc; i++) { 271 if(!is_arg_type_supported(info->arg_types[i])) { 272 return; /* Fallback to ITypeInfo for unsupported arg types */ 273 } 274 275 if(desc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) { 276 TRACE("%s param %d: default value\n", debugstr_w(info->name), i); 277 return; /* Fallback to ITypeInfo::Invoke */ 278 } 279 } 280 281 assert(info->argc <= MAX_ARGS); 282 assert(desc->callconv == CC_STDCALL); 283 284 info->call_vtbl_off = desc->oVft/sizeof(void*); 285 }else if(desc->invkind & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYGET)) { 286 VARTYPE vt = VT_EMPTY; 287 288 if(desc->invkind & DISPATCH_PROPERTYGET) { 289 vt = desc->elemdescFunc.tdesc.vt; 290 info->get_vtbl_off = desc->oVft/sizeof(void*); 291 } 292 if(desc->invkind & DISPATCH_PROPERTYPUT) { 293 assert(desc->cParams == 1); 294 vt = desc->lprgelemdescParam->tdesc.vt; 295 info->put_vtbl_off = desc->oVft/sizeof(void*); 296 } 297 298 assert(info->prop_vt == VT_EMPTY || vt == info->prop_vt); 299 info->prop_vt = vt; 300 } 301 } 302 303 static int dispid_cmp(const void *p1, const void *p2) 304 { 305 return ((const func_info_t*)p1)->id - ((const func_info_t*)p2)->id; 306 } 307 308 static int func_name_cmp(const void *p1, const void *p2) 309 { 310 return strcmpiW((*(func_info_t* const*)p1)->name, (*(func_info_t* const*)p2)->name); 311 } 312 313 static dispex_data_t *preprocess_dispex_data(DispatchEx *This) 314 { 315 const tid_t *tid = This->data->iface_tids; 316 FUNCDESC *funcdesc; 317 dispex_data_t *data; 318 DWORD size = 16, i; 319 ITypeInfo *ti, *dti; 320 HRESULT hres; 321 322 TRACE("(%p)\n", This); 323 324 if(This->data->disp_tid) { 325 hres = get_typeinfo(This->data->disp_tid, &dti); 326 if(FAILED(hres)) { 327 ERR("Could not get disp type info: %08x\n", hres); 328 return NULL; 329 } 330 } 331 332 data = heap_alloc(sizeof(dispex_data_t)); 333 if (!data) { 334 ERR("Out of memory\n"); 335 return NULL; 336 } 337 data->func_cnt = 0; 338 data->func_disp_cnt = 0; 339 data->funcs = heap_alloc_zero(size*sizeof(func_info_t)); 340 if (!data->funcs) { 341 heap_free (data); 342 ERR("Out of memory\n"); 343 return NULL; 344 } 345 list_add_tail(&dispex_data_list, &data->entry); 346 347 while(*tid) { 348 hres = get_typeinfo(*tid, &ti); 349 if(FAILED(hres)) 350 break; 351 352 i=7; 353 while(1) { 354 hres = ITypeInfo_GetFuncDesc(ti, i++, &funcdesc); 355 if(FAILED(hres)) 356 break; 357 358 add_func_info(data, &size, *tid, funcdesc, dti); 359 ITypeInfo_ReleaseFuncDesc(ti, funcdesc); 360 } 361 362 tid++; 363 } 364 365 if(!data->func_cnt) { 366 heap_free(data->funcs); 367 data->name_table = NULL; 368 data->funcs = NULL; 369 return data; 370 } 371 372 373 data->funcs = heap_realloc(data->funcs, data->func_cnt * sizeof(func_info_t)); 374 qsort(data->funcs, data->func_cnt, sizeof(func_info_t), dispid_cmp); 375 376 data->name_table = heap_alloc(data->func_cnt * sizeof(func_info_t*)); 377 for(i=0; i < data->func_cnt; i++) 378 data->name_table[i] = data->funcs+i; 379 qsort(data->name_table, data->func_cnt, sizeof(func_info_t*), func_name_cmp); 380 381 return data; 382 } 383 384 static int id_cmp(const void *p1, const void *p2) 385 { 386 return *(const DISPID*)p1 - *(const DISPID*)p2; 387 } 388 389 HRESULT get_dispids(tid_t tid, DWORD *ret_size, DISPID **ret) 390 { 391 unsigned i, func_cnt; 392 FUNCDESC *funcdesc; 393 ITypeInfo *ti; 394 TYPEATTR *attr; 395 DISPID *ids; 396 HRESULT hres; 397 398 hres = get_typeinfo(tid, &ti); 399 if(FAILED(hres)) 400 return hres; 401 402 hres = ITypeInfo_GetTypeAttr(ti, &attr); 403 if(FAILED(hres)) { 404 ITypeInfo_Release(ti); 405 return hres; 406 } 407 408 func_cnt = attr->cFuncs; 409 ITypeInfo_ReleaseTypeAttr(ti, attr); 410 411 ids = heap_alloc(func_cnt*sizeof(DISPID)); 412 if(!ids) { 413 ITypeInfo_Release(ti); 414 return E_OUTOFMEMORY; 415 } 416 417 for(i=0; i < func_cnt; i++) { 418 hres = ITypeInfo_GetFuncDesc(ti, i, &funcdesc); 419 if(FAILED(hres)) 420 break; 421 422 ids[i] = funcdesc->memid; 423 ITypeInfo_ReleaseFuncDesc(ti, funcdesc); 424 } 425 426 ITypeInfo_Release(ti); 427 if(FAILED(hres)) { 428 heap_free(ids); 429 return hres; 430 } 431 432 qsort(ids, func_cnt, sizeof(DISPID), id_cmp); 433 434 *ret_size = func_cnt; 435 *ret = ids; 436 return S_OK; 437 } 438 439 static dispex_data_t *get_dispex_data(DispatchEx *This) 440 { 441 if(This->data->data) 442 return This->data->data; 443 444 EnterCriticalSection(&cs_dispex_static_data); 445 446 if(!This->data->data) 447 This->data->data = preprocess_dispex_data(This); 448 449 LeaveCriticalSection(&cs_dispex_static_data); 450 451 return This->data->data; 452 } 453 454 static inline BOOL is_custom_dispid(DISPID id) 455 { 456 return MSHTML_DISPID_CUSTOM_MIN <= id && id <= MSHTML_DISPID_CUSTOM_MAX; 457 } 458 459 static inline BOOL is_dynamic_dispid(DISPID id) 460 { 461 return DISPID_DYNPROP_0 <= id && id <= DISPID_DYNPROP_MAX; 462 } 463 464 dispex_prop_type_t get_dispid_type(DISPID id) 465 { 466 if(is_dynamic_dispid(id)) 467 return DISPEXPROP_DYNAMIC; 468 if(is_custom_dispid(id)) 469 return DISPEXPROP_CUSTOM; 470 return DISPEXPROP_BUILTIN; 471 } 472 473 static HRESULT variant_copy(VARIANT *dest, VARIANT *src) 474 { 475 if(V_VT(src) == VT_BSTR && !V_BSTR(src)) { 476 V_VT(dest) = VT_BSTR; 477 V_BSTR(dest) = NULL; 478 return S_OK; 479 } 480 481 return VariantCopy(dest, src); 482 } 483 484 static inline dispex_dynamic_data_t *get_dynamic_data(DispatchEx *This) 485 { 486 if(This->dynamic_data) 487 return This->dynamic_data; 488 489 This->dynamic_data = heap_alloc_zero(sizeof(dispex_dynamic_data_t)); 490 if(!This->dynamic_data) 491 return NULL; 492 493 if(This->data->vtbl && This->data->vtbl->populate_props) 494 This->data->vtbl->populate_props(This); 495 496 return This->dynamic_data; 497 } 498 499 static HRESULT get_dynamic_prop(DispatchEx *This, const WCHAR *name, DWORD flags, dynamic_prop_t **ret) 500 { 501 const BOOL alloc = flags & fdexNameEnsure; 502 dispex_dynamic_data_t *data; 503 dynamic_prop_t *prop; 504 505 data = get_dynamic_data(This); 506 if(!data) 507 return E_OUTOFMEMORY; 508 509 for(prop = data->props; prop < data->props+data->prop_cnt; prop++) { 510 if(flags & fdexNameCaseInsensitive ? !strcmpiW(prop->name, name) : !strcmpW(prop->name, name)) { 511 if(prop->flags & DYNPROP_DELETED) { 512 if(!alloc) 513 return DISP_E_UNKNOWNNAME; 514 prop->flags &= ~DYNPROP_DELETED; 515 } 516 *ret = prop; 517 return S_OK; 518 } 519 } 520 521 if(!alloc) 522 return DISP_E_UNKNOWNNAME; 523 524 TRACE("creating dynamic prop %s\n", debugstr_w(name)); 525 526 if(!data->buf_size) { 527 data->props = heap_alloc(sizeof(dynamic_prop_t)*4); 528 if(!data->props) 529 return E_OUTOFMEMORY; 530 data->buf_size = 4; 531 }else if(data->buf_size == data->prop_cnt) { 532 dynamic_prop_t *new_props; 533 534 new_props = heap_realloc(data->props, sizeof(dynamic_prop_t)*(data->buf_size<<1)); 535 if(!new_props) 536 return E_OUTOFMEMORY; 537 538 data->props = new_props; 539 data->buf_size <<= 1; 540 } 541 542 prop = data->props + data->prop_cnt; 543 544 prop->name = heap_strdupW(name); 545 if(!prop->name) 546 return E_OUTOFMEMORY; 547 548 VariantInit(&prop->var); 549 prop->flags = 0; 550 data->prop_cnt++; 551 *ret = prop; 552 return S_OK; 553 } 554 555 HRESULT dispex_get_dprop_ref(DispatchEx *This, const WCHAR *name, BOOL alloc, VARIANT **ret) 556 { 557 dynamic_prop_t *prop; 558 HRESULT hres; 559 560 hres = get_dynamic_prop(This, name, alloc ? fdexNameEnsure : 0, &prop); 561 if(FAILED(hres)) 562 return hres; 563 564 *ret = &prop->var; 565 return S_OK; 566 } 567 568 HRESULT dispex_get_dynid(DispatchEx *This, const WCHAR *name, DISPID *id) 569 { 570 dynamic_prop_t *prop; 571 HRESULT hres; 572 573 hres = get_dynamic_prop(This, name, fdexNameEnsure, &prop); 574 if(FAILED(hres)) 575 return hres; 576 577 *id = DISPID_DYNPROP_0 + (prop - This->dynamic_data->props); 578 return S_OK; 579 } 580 581 static HRESULT dispex_value(DispatchEx *This, LCID lcid, WORD flags, DISPPARAMS *params, 582 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) 583 { 584 if(This->data->vtbl && This->data->vtbl->value) 585 return This->data->vtbl->value(This, lcid, flags, params, res, ei, caller); 586 587 switch(flags) { 588 case DISPATCH_PROPERTYGET: 589 V_VT(res) = VT_BSTR; 590 V_BSTR(res) = SysAllocString(objectW); 591 if(!V_BSTR(res)) 592 return E_OUTOFMEMORY; 593 break; 594 default: 595 FIXME("Unimplemented flags %x\n", flags); 596 return E_NOTIMPL; 597 } 598 599 return S_OK; 600 } 601 602 static HRESULT typeinfo_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res, 603 EXCEPINFO *ei) 604 { 605 ITypeInfo *ti; 606 IUnknown *unk; 607 UINT argerr=0; 608 HRESULT hres; 609 610 hres = get_typeinfo(func->tid, &ti); 611 if(FAILED(hres)) { 612 ERR("Could not get type info: %08x\n", hres); 613 return hres; 614 } 615 616 hres = IUnknown_QueryInterface(This->outer, tid_ids[func->tid], (void**)&unk); 617 if(FAILED(hres)) { 618 ERR("Could not get iface %s: %08x\n", debugstr_mshtml_guid(tid_ids[func->tid]), hres); 619 return E_FAIL; 620 } 621 622 hres = ITypeInfo_Invoke(ti, unk, func->id, flags, dp, res, ei, &argerr); 623 624 IUnknown_Release(unk); 625 return hres; 626 } 627 628 static inline func_disp_t *impl_from_IUnknown(IUnknown *iface) 629 { 630 return CONTAINING_RECORD(iface, func_disp_t, IUnknown_iface); 631 } 632 633 static HRESULT WINAPI Function_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) 634 { 635 func_disp_t *This = impl_from_IUnknown(iface); 636 637 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); 638 639 if(IsEqualGUID(&IID_IUnknown, riid)) { 640 *ppv = &This->IUnknown_iface; 641 }else if(dispex_query_interface(&This->dispex, riid, ppv)) { 642 return *ppv ? S_OK : E_NOINTERFACE; 643 }else { 644 *ppv = NULL; 645 return E_NOINTERFACE; 646 } 647 648 IUnknown_AddRef((IUnknown*)*ppv); 649 return S_OK; 650 } 651 652 static ULONG WINAPI Function_AddRef(IUnknown *iface) 653 { 654 func_disp_t *This = impl_from_IUnknown(iface); 655 LONG ref = InterlockedIncrement(&This->ref); 656 657 TRACE("(%p) ref=%d\n", This, ref); 658 659 return ref; 660 } 661 662 static ULONG WINAPI Function_Release(IUnknown *iface) 663 { 664 func_disp_t *This = impl_from_IUnknown(iface); 665 LONG ref = InterlockedDecrement(&This->ref); 666 667 TRACE("(%p) ref=%d\n", This, ref); 668 669 if(!ref) { 670 assert(!This->obj); 671 release_dispex(&This->dispex); 672 heap_free(This); 673 } 674 675 return ref; 676 } 677 678 static const IUnknownVtbl FunctionUnkVtbl = { 679 Function_QueryInterface, 680 Function_AddRef, 681 Function_Release 682 }; 683 684 static inline func_disp_t *impl_from_DispatchEx(DispatchEx *iface) 685 { 686 return CONTAINING_RECORD(iface, func_disp_t, dispex); 687 } 688 689 static HRESULT function_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *params, 690 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) 691 { 692 func_disp_t *This = impl_from_DispatchEx(dispex); 693 HRESULT hres; 694 695 switch(flags) { 696 case DISPATCH_METHOD|DISPATCH_PROPERTYGET: 697 if(!res) 698 return E_INVALIDARG; 699 /* fall through */ 700 case DISPATCH_METHOD: 701 if(!This->obj) 702 return E_UNEXPECTED; 703 hres = typeinfo_invoke(This->obj, This->info, flags, params, res, ei); 704 break; 705 case DISPATCH_PROPERTYGET: { 706 unsigned name_len; 707 WCHAR *ptr; 708 BSTR str; 709 710 static const WCHAR func_prefixW[] = 711 {'\n','f','u','n','c','t','i','o','n',' '}; 712 static const WCHAR func_suffixW[] = 713 {'(',')',' ','{','\n',' ',' ',' ',' ','[','n','a','t','i','v','e',' ','c','o','d','e',']','\n','}','\n'}; 714 715 /* FIXME: This probably should be more generic. Also we should try to get IID_IActiveScriptSite and SID_GetCaller. */ 716 if(!caller) 717 return E_ACCESSDENIED; 718 719 name_len = SysStringLen(This->info->name); 720 ptr = str = SysAllocStringLen(NULL, name_len + (sizeof(func_prefixW)+sizeof(func_suffixW))/sizeof(WCHAR)); 721 if(!str) 722 return E_OUTOFMEMORY; 723 724 memcpy(ptr, func_prefixW, sizeof(func_prefixW)); 725 ptr += sizeof(func_prefixW)/sizeof(WCHAR); 726 727 memcpy(ptr, This->info->name, name_len*sizeof(WCHAR)); 728 ptr += name_len; 729 730 memcpy(ptr, func_suffixW, sizeof(func_suffixW)); 731 732 V_VT(res) = VT_BSTR; 733 V_BSTR(res) = str; 734 return S_OK; 735 } 736 default: 737 FIXME("Unimplemented flags %x\n", flags); 738 hres = E_NOTIMPL; 739 } 740 741 return hres; 742 } 743 744 static const dispex_static_data_vtbl_t function_dispex_vtbl = { 745 function_value, 746 NULL, 747 NULL, 748 NULL 749 }; 750 751 static const tid_t function_iface_tids[] = {0}; 752 753 static dispex_static_data_t function_dispex = { 754 &function_dispex_vtbl, 755 NULL_tid, 756 NULL, 757 function_iface_tids 758 }; 759 760 static func_disp_t *create_func_disp(DispatchEx *obj, func_info_t *info) 761 { 762 func_disp_t *ret; 763 764 ret = heap_alloc_zero(sizeof(func_disp_t)); 765 if(!ret) 766 return NULL; 767 768 ret->IUnknown_iface.lpVtbl = &FunctionUnkVtbl; 769 init_dispex(&ret->dispex, &ret->IUnknown_iface, &function_dispex); 770 ret->ref = 1; 771 ret->obj = obj; 772 ret->info = info; 773 774 return ret; 775 } 776 777 static HRESULT invoke_disp_value(DispatchEx *This, IDispatch *func_disp, LCID lcid, WORD flags, DISPPARAMS *dp, 778 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) 779 { 780 DISPID named_arg = DISPID_THIS; 781 DISPPARAMS new_dp = {NULL, &named_arg, 0, 1}; 782 IDispatchEx *dispex; 783 HRESULT hres; 784 785 if(dp->cNamedArgs) { 786 FIXME("named args not supported\n"); 787 return E_NOTIMPL; 788 } 789 790 new_dp.rgvarg = heap_alloc((dp->cArgs+1)*sizeof(VARIANTARG)); 791 if(!new_dp.rgvarg) 792 return E_OUTOFMEMORY; 793 794 new_dp.cArgs = dp->cArgs+1; 795 memcpy(new_dp.rgvarg+1, dp->rgvarg, dp->cArgs*sizeof(VARIANTARG)); 796 797 V_VT(new_dp.rgvarg) = VT_DISPATCH; 798 V_DISPATCH(new_dp.rgvarg) = (IDispatch*)&This->IDispatchEx_iface; 799 800 hres = IDispatch_QueryInterface(func_disp, &IID_IDispatchEx, (void**)&dispex); 801 TRACE(">>>\n"); 802 if(SUCCEEDED(hres)) { 803 hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, lcid, flags, &new_dp, res, ei, caller); 804 IDispatchEx_Release(dispex); 805 }else { 806 ULONG err = 0; 807 hres = IDispatch_Invoke(func_disp, DISPID_VALUE, &IID_NULL, lcid, flags, &new_dp, res, ei, &err); 808 } 809 if(SUCCEEDED(hres)) 810 TRACE("<<< %s\n", debugstr_variant(res)); 811 else 812 WARN("<<< %08x\n", hres); 813 814 heap_free(new_dp.rgvarg); 815 return hres; 816 } 817 818 static HRESULT get_func_obj_entry(DispatchEx *This, func_info_t *func, func_obj_entry_t **ret) 819 { 820 dispex_dynamic_data_t *dynamic_data; 821 func_obj_entry_t *entry; 822 823 dynamic_data = get_dynamic_data(This); 824 if(!dynamic_data) 825 return E_OUTOFMEMORY; 826 827 if(!dynamic_data->func_disps) { 828 dynamic_data->func_disps = heap_alloc_zero(This->data->data->func_disp_cnt * sizeof(*dynamic_data->func_disps)); 829 if(!dynamic_data->func_disps) 830 return E_OUTOFMEMORY; 831 } 832 833 entry = dynamic_data->func_disps + func->func_disp_idx; 834 if(!entry->func_obj) { 835 entry->func_obj = create_func_disp(This, func); 836 if(!entry->func_obj) 837 return E_OUTOFMEMORY; 838 839 IDispatchEx_AddRef(&entry->func_obj->dispex.IDispatchEx_iface); 840 V_VT(&entry->val) = VT_DISPATCH; 841 V_DISPATCH(&entry->val) = (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface; 842 } 843 844 *ret = entry; 845 return S_OK; 846 } 847 848 static HRESULT get_builtin_func(dispex_data_t *data, DISPID id, func_info_t **ret) 849 { 850 int min, max, n; 851 852 min = 0; 853 max = data->func_cnt-1; 854 855 while(min <= max) { 856 n = (min+max)/2; 857 858 if(data->funcs[n].id == id) { 859 *ret = data->funcs+n; 860 return S_OK; 861 } 862 863 if(data->funcs[n].id < id) 864 min = n+1; 865 else 866 max = n-1; 867 } 868 869 WARN("invalid id %x\n", id); 870 return DISP_E_UNKNOWNNAME; 871 } 872 873 static HRESULT get_builtin_id(DispatchEx *This, BSTR name, DWORD grfdex, DISPID *ret) 874 { 875 dispex_data_t *data; 876 int min, max, n, c; 877 878 data = get_dispex_data(This); 879 if(!data) 880 return E_FAIL; 881 882 min = 0; 883 max = data->func_cnt-1; 884 885 while(min <= max) { 886 n = (min+max)/2; 887 888 c = strcmpiW(data->name_table[n]->name, name); 889 if(!c) { 890 if((grfdex & fdexNameCaseSensitive) && strcmpW(data->name_table[n]->name, name)) 891 break; 892 893 *ret = data->name_table[n]->id; 894 return S_OK; 895 } 896 897 if(c > 0) 898 max = n-1; 899 else 900 min = n+1; 901 } 902 903 if(This->data->vtbl && This->data->vtbl->get_dispid) { 904 HRESULT hres; 905 906 hres = This->data->vtbl->get_dispid(This, name, grfdex, ret); 907 if(hres != DISP_E_UNKNOWNNAME) 908 return hres; 909 } 910 911 return DISP_E_UNKNOWNNAME; 912 } 913 914 static HRESULT change_type(VARIANT *dst, VARIANT *src, VARTYPE vt, IServiceProvider *caller) 915 { 916 V_VT(dst) = VT_EMPTY; 917 918 if(caller) { 919 IVariantChangeType *change_type = NULL; 920 HRESULT hres; 921 922 hres = IServiceProvider_QueryService(caller, &SID_VariantConversion, &IID_IVariantChangeType, (void**)&change_type); 923 if(SUCCEEDED(hres)) { 924 hres = IVariantChangeType_ChangeType(change_type, dst, src, LOCALE_NEUTRAL, vt); 925 IVariantChangeType_Release(change_type); 926 return hres; 927 } 928 } 929 930 switch(vt) { 931 case VT_BOOL: 932 if(V_VT(src) == VT_BSTR) { 933 V_VT(dst) = VT_BOOL; 934 V_BOOL(dst) = V_BSTR(src) && *V_BSTR(src) ? VARIANT_TRUE : VARIANT_FALSE; 935 return S_OK; 936 } 937 break; 938 } 939 940 return VariantChangeType(dst, src, 0, vt); 941 } 942 943 static HRESULT builtin_propget(DispatchEx *This, func_info_t *func, DISPPARAMS *dp, VARIANT *res) 944 { 945 IUnknown *iface; 946 HRESULT hres; 947 948 if(dp && dp->cArgs) { 949 FIXME("cArgs %d\n", dp->cArgs); 950 return E_NOTIMPL; 951 } 952 953 assert(func->get_vtbl_off); 954 955 hres = IUnknown_QueryInterface(This->outer, tid_ids[func->tid], (void**)&iface); 956 if(SUCCEEDED(hres)) { 957 switch(func->prop_vt) { 958 #define CASE_VT(vt,type,access) \ 959 case vt: { \ 960 type val; \ 961 hres = ((HRESULT (WINAPI*)(IUnknown*,type*))((void**)iface->lpVtbl)[func->get_vtbl_off])(iface,&val); \ 962 if(SUCCEEDED(hres)) \ 963 access(res) = val; \ 964 } \ 965 break 966 BUILTIN_TYPES_SWITCH; 967 #undef CASE_VT 968 default: 969 FIXME("Unhandled vt %d\n", func->prop_vt); 970 hres = E_NOTIMPL; 971 } 972 IUnknown_Release(iface); 973 } 974 975 if(FAILED(hres)) 976 return hres; 977 978 if(func->prop_vt != VT_VARIANT) 979 V_VT(res) = func->prop_vt == VT_PTR ? VT_DISPATCH : func->prop_vt; 980 return S_OK; 981 } 982 983 static HRESULT builtin_propput(DispatchEx *This, func_info_t *func, DISPPARAMS *dp, IServiceProvider *caller) 984 { 985 VARIANT *v, tmpv; 986 IUnknown *iface; 987 HRESULT hres; 988 989 if(dp->cArgs != 1 || (dp->cNamedArgs == 1 && *dp->rgdispidNamedArgs != DISPID_PROPERTYPUT) 990 || dp->cNamedArgs > 1) { 991 FIXME("invalid args\n"); 992 return E_INVALIDARG; 993 } 994 995 if(!func->put_vtbl_off) { 996 FIXME("No setter\n"); 997 return E_FAIL; 998 } 999 1000 v = dp->rgvarg; 1001 if(func->prop_vt != VT_VARIANT && V_VT(v) != func->prop_vt) { 1002 hres = change_type(&tmpv, v, func->prop_vt, caller); 1003 if(FAILED(hres)) 1004 return hres; 1005 v = &tmpv; 1006 } 1007 1008 hres = IUnknown_QueryInterface(This->outer, tid_ids[func->tid], (void**)&iface); 1009 if(SUCCEEDED(hres)) { 1010 switch(func->prop_vt) { 1011 #define CASE_VT(vt,type,access) \ 1012 case vt: \ 1013 hres = ((HRESULT (WINAPI*)(IUnknown*,type))((void**)iface->lpVtbl)[func->put_vtbl_off])(iface,access(v)); \ 1014 break 1015 BUILTIN_TYPES_SWITCH; 1016 #undef CASE_VT 1017 default: 1018 FIXME("Unimplemented vt %d\n", func->prop_vt); 1019 hres = E_NOTIMPL; 1020 } 1021 1022 IUnknown_Release(iface); 1023 } 1024 1025 if(v == &tmpv) 1026 VariantClear(v); 1027 return hres; 1028 } 1029 1030 static HRESULT invoke_builtin_function(DispatchEx *This, func_info_t *func, DISPPARAMS *dp, VARIANT *res, IServiceProvider *caller) 1031 { 1032 VARIANT arg_buf[MAX_ARGS], *arg_ptrs[MAX_ARGS], *arg, retv, ret_ref, vhres; 1033 unsigned i, nconv = 0; 1034 IUnknown *iface; 1035 HRESULT hres; 1036 1037 if(dp->cNamedArgs) { 1038 FIXME("Named arguments not supported\n"); 1039 return E_NOTIMPL; 1040 } 1041 1042 if(dp->cArgs != func->argc) { 1043 FIXME("Invalid argument count (expected %u, got %u)\n", func->argc, dp->cArgs); 1044 return E_INVALIDARG; 1045 } 1046 1047 hres = IUnknown_QueryInterface(This->outer, tid_ids[func->tid], (void**)&iface); 1048 if(FAILED(hres)) 1049 return hres; 1050 1051 for(i=0; i < func->argc; i++) { 1052 arg = dp->rgvarg+dp->cArgs-i-1; 1053 if(func->arg_types[i] == V_VT(arg)) { 1054 arg_ptrs[i] = arg; 1055 }else { 1056 hres = change_type(arg_buf+nconv, arg, func->arg_types[i], caller); 1057 if(FAILED(hres)) 1058 break; 1059 arg_ptrs[i] = arg_buf + nconv++; 1060 } 1061 } 1062 1063 if(SUCCEEDED(hres)) { 1064 if(func->prop_vt == VT_VOID) { 1065 V_VT(&retv) = VT_EMPTY; 1066 }else { 1067 V_VT(&retv) = func->prop_vt; 1068 arg_ptrs[func->argc] = &ret_ref; 1069 V_VT(&ret_ref) = VT_BYREF|func->prop_vt; 1070 1071 switch(func->prop_vt) { 1072 #define CASE_VT(vt,type,access) \ 1073 case vt: \ 1074 V_BYREF(&ret_ref) = &access(&retv); \ 1075 break 1076 BUILTIN_TYPES_SWITCH; 1077 #undef CASE_VT 1078 default: 1079 assert(0); 1080 } 1081 } 1082 1083 V_VT(&vhres) = VT_ERROR; 1084 hres = DispCallFunc(iface, func->call_vtbl_off*sizeof(void*), CC_STDCALL, VT_ERROR, 1085 func->argc + (func->prop_vt == VT_VOID ? 0 : 1), func->arg_types, arg_ptrs, &vhres); 1086 } 1087 1088 while(nconv--) 1089 VariantClear(arg_buf+nconv); 1090 IUnknown_Release(iface); 1091 if(FAILED(hres)) 1092 return hres; 1093 if(FAILED(V_ERROR(&vhres))) 1094 return V_ERROR(&vhres); 1095 1096 if(res) 1097 *res = retv; 1098 else 1099 VariantClear(&retv); 1100 return V_ERROR(&vhres); 1101 } 1102 1103 static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res, 1104 EXCEPINFO *ei, IServiceProvider *caller) 1105 { 1106 HRESULT hres; 1107 1108 switch(flags) { 1109 case DISPATCH_METHOD|DISPATCH_PROPERTYGET: 1110 if(!res) 1111 return E_INVALIDARG; 1112 /* fall through */ 1113 case DISPATCH_METHOD: 1114 if(This->dynamic_data && This->dynamic_data->func_disps 1115 && This->dynamic_data->func_disps[func->func_disp_idx].func_obj) { 1116 func_obj_entry_t *entry = This->dynamic_data->func_disps + func->func_disp_idx; 1117 1118 if(V_VT(&entry->val) != VT_DISPATCH) { 1119 FIXME("calling %s not supported\n", debugstr_variant(&entry->val)); 1120 return E_NOTIMPL; 1121 } 1122 1123 if((IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface != V_DISPATCH(&entry->val)) { 1124 if(!V_DISPATCH(&entry->val)) { 1125 FIXME("Calling null\n"); 1126 return E_FAIL; 1127 } 1128 1129 hres = invoke_disp_value(This, V_DISPATCH(&entry->val), 0, flags, dp, res, ei, NULL); 1130 break; 1131 } 1132 } 1133 1134 if(func->call_vtbl_off) 1135 hres = invoke_builtin_function(This, func, dp, res, caller); 1136 else 1137 hres = typeinfo_invoke(This, func, flags, dp, res, ei); 1138 break; 1139 case DISPATCH_PROPERTYGET: { 1140 func_obj_entry_t *entry; 1141 1142 if(func->id == DISPID_VALUE) { 1143 BSTR ret; 1144 1145 ret = SysAllocString(objectW); 1146 if(!ret) 1147 return E_OUTOFMEMORY; 1148 1149 V_VT(res) = VT_BSTR; 1150 V_BSTR(res) = ret; 1151 return S_OK; 1152 } 1153 1154 hres = get_func_obj_entry(This, func, &entry); 1155 if(FAILED(hres)) 1156 return hres; 1157 1158 V_VT(res) = VT_EMPTY; 1159 return VariantCopy(res, &entry->val); 1160 } 1161 case DISPATCH_PROPERTYPUT: { 1162 func_obj_entry_t *entry; 1163 1164 if(dp->cArgs != 1 || (dp->cNamedArgs == 1 && *dp->rgdispidNamedArgs != DISPID_PROPERTYPUT) 1165 || dp->cNamedArgs > 1) { 1166 FIXME("invalid args\n"); 1167 return E_INVALIDARG; 1168 } 1169 1170 /* 1171 * NOTE: Although we have IDispatchEx tests showing, that it's not allowed to set 1172 * function property using InvokeEx, it's possible to do that from jscript. 1173 * Native probably uses some undocumented interface in this case, but it should 1174 * be fine for us to allow IDispatchEx handle that. 1175 */ 1176 hres = get_func_obj_entry(This, func, &entry); 1177 if(FAILED(hres)) 1178 return hres; 1179 1180 return VariantCopy(&entry->val, dp->rgvarg); 1181 } 1182 default: 1183 FIXME("Unimplemented flags %x\n", flags); 1184 hres = E_NOTIMPL; 1185 } 1186 1187 return hres; 1188 } 1189 1190 static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD flags, DISPPARAMS *dp, 1191 VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) 1192 { 1193 dispex_data_t *data; 1194 func_info_t *func; 1195 HRESULT hres; 1196 1197 data = get_dispex_data(This); 1198 if(!data) 1199 return E_FAIL; 1200 1201 hres = get_builtin_func(data, id, &func); 1202 if(id == DISPID_VALUE && hres == DISP_E_UNKNOWNNAME) 1203 return dispex_value(This, lcid, flags, dp, res, ei, caller); 1204 if(FAILED(hres)) 1205 return hres; 1206 1207 if(func->func_disp_idx != -1) 1208 return function_invoke(This, func, flags, dp, res, ei, caller); 1209 1210 switch(flags) { 1211 case DISPATCH_PROPERTYPUT: 1212 if(res) 1213 V_VT(res) = VT_EMPTY; 1214 hres = builtin_propput(This, func, dp, caller); 1215 break; 1216 case DISPATCH_PROPERTYGET: 1217 hres = builtin_propget(This, func, dp, res); 1218 break; 1219 default: 1220 if(!func->get_vtbl_off) { 1221 hres = typeinfo_invoke(This, func, flags, dp, res, ei); 1222 }else { 1223 VARIANT v; 1224 1225 hres = builtin_propget(This, func, NULL, &v); 1226 if(FAILED(hres)) 1227 return hres; 1228 1229 if(flags != (DISPATCH_PROPERTYGET|DISPATCH_METHOD) || dp->cArgs) { 1230 if(V_VT(&v) != VT_DISPATCH) { 1231 FIXME("Not a function %s flags %08x\n", debugstr_variant(&v), flags); 1232 VariantClear(&v); 1233 return E_FAIL; 1234 } 1235 1236 hres = invoke_disp_value(This, V_DISPATCH(&v), lcid, flags, dp, res, ei, caller); 1237 IDispatch_Release(V_DISPATCH(&v)); 1238 }else if(res) { 1239 *res = v; 1240 }else { 1241 VariantClear(&v); 1242 } 1243 } 1244 } 1245 1246 return hres; 1247 } 1248 1249 HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) 1250 { 1251 switch(get_dispid_type(id)) { 1252 case DISPEXPROP_CUSTOM: 1253 FIXME("DISPEXPROP_CUSTOM not supported\n"); 1254 return E_NOTIMPL; 1255 1256 case DISPEXPROP_DYNAMIC: { 1257 DWORD idx = id - DISPID_DYNPROP_0; 1258 dynamic_prop_t *prop; 1259 1260 prop = This->dynamic_data->props+idx; 1261 VariantClear(&prop->var); 1262 prop->flags |= DYNPROP_DELETED; 1263 *success = VARIANT_TRUE; 1264 return S_OK; 1265 } 1266 case DISPEXPROP_BUILTIN: { 1267 VARIANT var; 1268 DISPPARAMS dp = {&var,NULL,1,0}; 1269 dispex_data_t *data; 1270 func_info_t *func; 1271 HRESULT hres; 1272 1273 data = get_dispex_data(This); 1274 if(!data) 1275 return E_FAIL; 1276 1277 hres = get_builtin_func(data, id, &func); 1278 if(FAILED(hres)) 1279 return hres; 1280 1281 /* For builtin functions, we set their value to the original function. */ 1282 if(func->func_disp_idx != -1) { 1283 func_obj_entry_t *entry; 1284 1285 if(!This->dynamic_data || !This->dynamic_data->func_disps 1286 || !This->dynamic_data->func_disps[func->func_disp_idx].func_obj) { 1287 *success = VARIANT_FALSE; 1288 return S_OK; 1289 } 1290 1291 entry = This->dynamic_data->func_disps + func->func_disp_idx; 1292 if(V_VT(&entry->val) == VT_DISPATCH 1293 && V_DISPATCH(&entry->val) == (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface) { 1294 *success = VARIANT_FALSE; 1295 return S_OK; 1296 } 1297 1298 VariantClear(&entry->val); 1299 V_VT(&entry->val) = VT_DISPATCH; 1300 V_DISPATCH(&entry->val) = (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface; 1301 IDispatch_AddRef(V_DISPATCH(&entry->val)); 1302 *success = VARIANT_TRUE; 1303 return S_OK; 1304 } 1305 1306 V_VT(&var) = VT_EMPTY; 1307 hres = builtin_propput(This, func, &dp, NULL); 1308 if(FAILED(hres)) 1309 return hres; 1310 1311 *success = VARIANT_TRUE; 1312 return S_OK; 1313 } 1314 default: 1315 assert(0); 1316 return E_FAIL; 1317 } 1318 } 1319 1320 static inline DispatchEx *impl_from_IDispatchEx(IDispatchEx *iface) 1321 { 1322 return CONTAINING_RECORD(iface, DispatchEx, IDispatchEx_iface); 1323 } 1324 1325 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) 1326 { 1327 DispatchEx *This = impl_from_IDispatchEx(iface); 1328 1329 return IUnknown_QueryInterface(This->outer, riid, ppv); 1330 } 1331 1332 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface) 1333 { 1334 DispatchEx *This = impl_from_IDispatchEx(iface); 1335 1336 return IUnknown_AddRef(This->outer); 1337 } 1338 1339 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) 1340 { 1341 DispatchEx *This = impl_from_IDispatchEx(iface); 1342 1343 return IUnknown_Release(This->outer); 1344 } 1345 1346 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo) 1347 { 1348 DispatchEx *This = impl_from_IDispatchEx(iface); 1349 1350 TRACE("(%p)->(%p)\n", This, pctinfo); 1351 1352 *pctinfo = 1; 1353 return S_OK; 1354 } 1355 1356 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, 1357 LCID lcid, ITypeInfo **ppTInfo) 1358 { 1359 DispatchEx *This = impl_from_IDispatchEx(iface); 1360 HRESULT hres; 1361 1362 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); 1363 1364 hres = get_typeinfo(This->data->disp_tid, ppTInfo); 1365 if(FAILED(hres)) 1366 return hres; 1367 1368 ITypeInfo_AddRef(*ppTInfo); 1369 return S_OK; 1370 } 1371 1372 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, 1373 LPOLESTR *rgszNames, UINT cNames, 1374 LCID lcid, DISPID *rgDispId) 1375 { 1376 DispatchEx *This = impl_from_IDispatchEx(iface); 1377 UINT i; 1378 HRESULT hres; 1379 1380 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames, 1381 lcid, rgDispId); 1382 1383 for(i=0; i < cNames; i++) { 1384 hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i); 1385 if(FAILED(hres)) 1386 return hres; 1387 } 1388 1389 return S_OK; 1390 } 1391 1392 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, 1393 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, 1394 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) 1395 { 1396 DispatchEx *This = impl_from_IDispatchEx(iface); 1397 1398 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), 1399 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); 1400 1401 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags, pDispParams, 1402 pVarResult, pExcepInfo, NULL); 1403 } 1404 1405 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) 1406 { 1407 DispatchEx *This = impl_from_IDispatchEx(iface); 1408 dynamic_prop_t *dprop; 1409 HRESULT hres; 1410 1411 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid); 1412 1413 if(grfdex & ~(fdexNameCaseSensitive|fdexNameCaseInsensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) 1414 FIXME("Unsupported grfdex %x\n", grfdex); 1415 1416 hres = get_builtin_id(This, bstrName, grfdex, pid); 1417 if(hres != DISP_E_UNKNOWNNAME) 1418 return hres; 1419 1420 hres = get_dynamic_prop(This, bstrName, grfdex, &dprop); 1421 if(FAILED(hres)) 1422 return hres; 1423 1424 *pid = DISPID_DYNPROP_0 + (dprop - This->dynamic_data->props); 1425 return S_OK; 1426 } 1427 1428 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, 1429 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) 1430 { 1431 DispatchEx *This = impl_from_IDispatchEx(iface); 1432 HRESULT hres; 1433 1434 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); 1435 1436 if(wFlags == (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF)) 1437 wFlags = DISPATCH_PROPERTYPUT; 1438 1439 switch(get_dispid_type(id)) { 1440 case DISPEXPROP_CUSTOM: 1441 if(!This->data->vtbl || !This->data->vtbl->invoke) 1442 return DISP_E_UNKNOWNNAME; 1443 return This->data->vtbl->invoke(This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); 1444 1445 case DISPEXPROP_DYNAMIC: { 1446 DWORD idx = id - DISPID_DYNPROP_0; 1447 dynamic_prop_t *prop; 1448 1449 if(!get_dynamic_data(This) || This->dynamic_data->prop_cnt <= idx) 1450 return DISP_E_UNKNOWNNAME; 1451 1452 prop = This->dynamic_data->props+idx; 1453 1454 switch(wFlags) { 1455 case DISPATCH_METHOD|DISPATCH_PROPERTYGET: 1456 if(!pvarRes) 1457 return E_INVALIDARG; 1458 /* fall through */ 1459 case DISPATCH_METHOD: 1460 if(V_VT(&prop->var) != VT_DISPATCH) { 1461 FIXME("invoke %s\n", debugstr_variant(&prop->var)); 1462 return E_NOTIMPL; 1463 } 1464 1465 return invoke_disp_value(This, V_DISPATCH(&prop->var), lcid, wFlags, pdp, pvarRes, pei, pspCaller); 1466 case DISPATCH_PROPERTYGET: 1467 if(prop->flags & DYNPROP_DELETED) 1468 return DISP_E_UNKNOWNNAME; 1469 V_VT(pvarRes) = VT_EMPTY; 1470 return variant_copy(pvarRes, &prop->var); 1471 case DISPATCH_PROPERTYPUT: 1472 if(pdp->cArgs != 1 || (pdp->cNamedArgs == 1 && *pdp->rgdispidNamedArgs != DISPID_PROPERTYPUT) 1473 || pdp->cNamedArgs > 1) { 1474 FIXME("invalid args\n"); 1475 return E_INVALIDARG; 1476 } 1477 1478 TRACE("put %s\n", debugstr_variant(pdp->rgvarg)); 1479 VariantClear(&prop->var); 1480 hres = variant_copy(&prop->var, pdp->rgvarg); 1481 if(FAILED(hres)) 1482 return hres; 1483 1484 prop->flags &= ~DYNPROP_DELETED; 1485 return S_OK; 1486 default: 1487 FIXME("unhandled wFlags %x\n", wFlags); 1488 return E_NOTIMPL; 1489 } 1490 } 1491 case DISPEXPROP_BUILTIN: 1492 if(wFlags == DISPATCH_CONSTRUCT) { 1493 if(id == DISPID_VALUE) { 1494 if(This->data->vtbl && This->data->vtbl->value) { 1495 return This->data->vtbl->value(This, lcid, wFlags, pdp, pvarRes, pei, pspCaller); 1496 } 1497 FIXME("DISPATCH_CONSTRUCT flag but missing value function\n"); 1498 return E_FAIL; 1499 } 1500 FIXME("DISPATCH_CONSTRUCT flag without DISPID_VALUE\n"); 1501 return E_FAIL; 1502 } 1503 1504 return invoke_builtin_prop(This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); 1505 default: 1506 assert(0); 1507 return E_FAIL; 1508 } 1509 } 1510 1511 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) 1512 { 1513 DispatchEx *This = impl_from_IDispatchEx(iface); 1514 1515 TRACE("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex); 1516 1517 /* Not implemented by IE */ 1518 return E_NOTIMPL; 1519 } 1520 1521 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) 1522 { 1523 DispatchEx *This = impl_from_IDispatchEx(iface); 1524 1525 TRACE("(%p)->(%x)\n", This, id); 1526 1527 /* Not implemented by IE */ 1528 return E_NOTIMPL; 1529 } 1530 1531 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) 1532 { 1533 DispatchEx *This = impl_from_IDispatchEx(iface); 1534 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex); 1535 return E_NOTIMPL; 1536 } 1537 1538 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) 1539 { 1540 DispatchEx *This = impl_from_IDispatchEx(iface); 1541 dispex_data_t *data; 1542 func_info_t *func; 1543 HRESULT hres; 1544 1545 TRACE("(%p)->(%x %p)\n", This, id, pbstrName); 1546 1547 if(is_dynamic_dispid(id)) { 1548 DWORD idx = id - DISPID_DYNPROP_0; 1549 1550 if(!get_dynamic_data(This) || This->dynamic_data->prop_cnt <= idx) 1551 return DISP_E_UNKNOWNNAME; 1552 1553 *pbstrName = SysAllocString(This->dynamic_data->props[idx].name); 1554 if(!*pbstrName) 1555 return E_OUTOFMEMORY; 1556 1557 return S_OK; 1558 } 1559 1560 data = get_dispex_data(This); 1561 if(!data) 1562 return E_FAIL; 1563 1564 hres = get_builtin_func(data, id, &func); 1565 if(FAILED(hres)) 1566 return hres; 1567 1568 *pbstrName = SysAllocString(func->name); 1569 if(!*pbstrName) 1570 return E_OUTOFMEMORY; 1571 return S_OK; 1572 } 1573 1574 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) 1575 { 1576 DispatchEx *This = impl_from_IDispatchEx(iface); 1577 dispex_data_t *data; 1578 func_info_t *func; 1579 HRESULT hres; 1580 1581 TRACE("(%p)->(%x %x %p)\n", This, grfdex, id, pid); 1582 1583 if(is_dynamic_dispid(id)) { 1584 DWORD idx = id - DISPID_DYNPROP_0; 1585 1586 if(!get_dynamic_data(This) || This->dynamic_data->prop_cnt <= idx) 1587 return DISP_E_UNKNOWNNAME; 1588 1589 while(++idx < This->dynamic_data->prop_cnt && This->dynamic_data->props[idx].flags & DYNPROP_DELETED); 1590 1591 if(idx == This->dynamic_data->prop_cnt) { 1592 *pid = DISPID_STARTENUM; 1593 return S_FALSE; 1594 } 1595 1596 *pid = DISPID_DYNPROP_0+idx; 1597 return S_OK; 1598 } 1599 1600 data = get_dispex_data(This); 1601 if(!data) 1602 return E_FAIL; 1603 1604 if(id == DISPID_STARTENUM) { 1605 func = data->funcs; 1606 }else { 1607 hres = get_builtin_func(data, id, &func); 1608 if(FAILED(hres)) 1609 return hres; 1610 func++; 1611 } 1612 1613 while(func < data->funcs+data->func_cnt) { 1614 /* FIXME: Skip hidden properties */ 1615 if(func->func_disp_idx == -1) { 1616 *pid = func->id; 1617 return S_OK; 1618 } 1619 func++; 1620 } 1621 1622 if(get_dynamic_data(This) && This->dynamic_data->prop_cnt) { 1623 *pid = DISPID_DYNPROP_0; 1624 return S_OK; 1625 } 1626 1627 *pid = DISPID_STARTENUM; 1628 return S_FALSE; 1629 } 1630 1631 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk) 1632 { 1633 DispatchEx *This = impl_from_IDispatchEx(iface); 1634 FIXME("(%p)->(%p)\n", This, ppunk); 1635 return E_NOTIMPL; 1636 } 1637 1638 static IDispatchExVtbl DispatchExVtbl = { 1639 DispatchEx_QueryInterface, 1640 DispatchEx_AddRef, 1641 DispatchEx_Release, 1642 DispatchEx_GetTypeInfoCount, 1643 DispatchEx_GetTypeInfo, 1644 DispatchEx_GetIDsOfNames, 1645 DispatchEx_Invoke, 1646 DispatchEx_GetDispID, 1647 DispatchEx_InvokeEx, 1648 DispatchEx_DeleteMemberByName, 1649 DispatchEx_DeleteMemberByDispID, 1650 DispatchEx_GetMemberProperties, 1651 DispatchEx_GetMemberName, 1652 DispatchEx_GetNextDispID, 1653 DispatchEx_GetNameSpaceParent 1654 }; 1655 1656 BOOL dispex_query_interface(DispatchEx *This, REFIID riid, void **ppv) 1657 { 1658 if(IsEqualGUID(&IID_IDispatch, riid)) 1659 *ppv = &This->IDispatchEx_iface; 1660 else if(IsEqualGUID(&IID_IDispatchEx, riid)) 1661 *ppv = &This->IDispatchEx_iface; 1662 else if(IsEqualGUID(&IID_IDispatchJS, riid)) 1663 *ppv = NULL; 1664 else if(IsEqualGUID(&IID_UndocumentedScriptIface, riid)) 1665 *ppv = NULL; 1666 else 1667 return FALSE; 1668 1669 if(*ppv) 1670 IUnknown_AddRef((IUnknown*)*ppv); 1671 return TRUE; 1672 } 1673 1674 void dispex_traverse(DispatchEx *This, nsCycleCollectionTraversalCallback *cb) 1675 { 1676 dynamic_prop_t *prop; 1677 1678 if(!This->dynamic_data) 1679 return; 1680 1681 for(prop = This->dynamic_data->props; prop < This->dynamic_data->props + This->dynamic_data->prop_cnt; prop++) { 1682 if(V_VT(&prop->var) == VT_DISPATCH) 1683 note_cc_edge((nsISupports*)V_DISPATCH(&prop->var), "dispex_data", cb); 1684 } 1685 1686 /* FIXME: Traverse func_disps */ 1687 } 1688 1689 void dispex_unlink(DispatchEx *This) 1690 { 1691 dynamic_prop_t *prop; 1692 1693 if(!This->dynamic_data) 1694 return; 1695 1696 for(prop = This->dynamic_data->props; prop < This->dynamic_data->props + This->dynamic_data->prop_cnt; prop++) { 1697 if(V_VT(&prop->var) == VT_DISPATCH) { 1698 V_VT(&prop->var) = VT_EMPTY; 1699 IDispatch_Release(V_DISPATCH(&prop->var)); 1700 }else { 1701 VariantClear(&prop->var); 1702 } 1703 } 1704 } 1705 1706 void release_dispex(DispatchEx *This) 1707 { 1708 dynamic_prop_t *prop; 1709 1710 if(!This->dynamic_data) 1711 return; 1712 1713 for(prop = This->dynamic_data->props; prop < This->dynamic_data->props + This->dynamic_data->prop_cnt; prop++) { 1714 VariantClear(&prop->var); 1715 heap_free(prop->name); 1716 } 1717 1718 heap_free(This->dynamic_data->props); 1719 1720 if(This->dynamic_data->func_disps) { 1721 func_obj_entry_t *iter; 1722 1723 for(iter = This->dynamic_data->func_disps; iter < This->dynamic_data->func_disps+This->data->data->func_disp_cnt; iter++) { 1724 if(iter->func_obj) { 1725 iter->func_obj->obj = NULL; 1726 IDispatchEx_Release(&iter->func_obj->dispex.IDispatchEx_iface); 1727 } 1728 VariantClear(&iter->val); 1729 } 1730 1731 heap_free(This->dynamic_data->func_disps); 1732 } 1733 1734 heap_free(This->dynamic_data); 1735 } 1736 1737 void init_dispex(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *data) 1738 { 1739 dispex->IDispatchEx_iface.lpVtbl = &DispatchExVtbl; 1740 dispex->outer = outer; 1741 dispex->data = data; 1742 dispex->dynamic_data = NULL; 1743 } 1744