2 * Copyright 2011 Jacek Caban for CodeWeavers
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.
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.
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
21 #include "wine/debug.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(vbscript
);
25 static inline BOOL
is_func_id(vbdisp_t
*This
, DISPID id
)
27 return id
< This
->desc
->func_cnt
;
30 static BOOL
get_func_id(vbdisp_t
*This
, const WCHAR
*name
, vbdisp_invoke_type_t invoke_type
, BOOL search_private
, DISPID
*id
)
34 for(i
= invoke_type
== VBDISP_ANY
? 0 : 1; i
< This
->desc
->func_cnt
; i
++) {
35 if(invoke_type
== VBDISP_ANY
) {
36 if(!search_private
&& !This
->desc
->funcs
[i
].is_public
)
38 if(!i
&& !This
->desc
->funcs
[0].name
) /* default value may not exist */
41 if(!This
->desc
->funcs
[i
].entries
[invoke_type
]
42 || (!search_private
&& !This
->desc
->funcs
[i
].entries
[invoke_type
]->is_public
))
46 if(!strcmpiW(This
->desc
->funcs
[i
].name
, name
)) {
55 HRESULT
vbdisp_get_id(vbdisp_t
*This
, BSTR name
, vbdisp_invoke_type_t invoke_type
, BOOL search_private
, DISPID
*id
)
59 if(get_func_id(This
, name
, invoke_type
, search_private
, id
))
62 for(i
=0; i
< This
->desc
->prop_cnt
; i
++) {
63 if(!search_private
&& !This
->desc
->props
[i
].is_public
)
66 if(!strcmpiW(This
->desc
->props
[i
].name
, name
)) {
67 *id
= i
+ This
->desc
->func_cnt
;
72 if(This
->desc
->typeinfo
) {
75 hres
= ITypeInfo_GetIDsOfNames(This
->desc
->typeinfo
, &name
, 1, id
);
81 return DISP_E_UNKNOWNNAME
;
84 static VARIANT
*get_propput_arg(const DISPPARAMS
*dp
)
88 for(i
=0; i
< dp
->cNamedArgs
; i
++) {
89 if(dp
->rgdispidNamedArgs
[i
] == DISPID_PROPERTYPUT
)
96 static HRESULT
invoke_variant_prop(vbdisp_t
*This
, VARIANT
*v
, WORD flags
, DISPPARAMS
*dp
, VARIANT
*res
)
101 case DISPATCH_PROPERTYGET
|DISPATCH_METHOD
:
103 WARN("called with arguments\n");
104 return DISP_E_MEMBERNOTFOUND
; /* That's what tests show */
107 hres
= VariantCopy(res
, v
);
110 case DISPATCH_PROPERTYPUT
: {
113 put_val
= get_propput_arg(dp
);
115 WARN("no value to set\n");
116 return DISP_E_PARAMNOTOPTIONAL
;
120 V_VT(res
) = VT_EMPTY
;
122 hres
= VariantCopy(v
, put_val
);
127 FIXME("unimplemented flags %x\n", flags
);
134 static HRESULT
invoke_builtin(vbdisp_t
*This
, const builtin_prop_t
*prop
, WORD flags
, DISPPARAMS
*dp
, VARIANT
*res
)
139 case DISPATCH_PROPERTYGET
:
140 if(!(prop
->flags
& (BP_GET
|BP_GETPUT
))) {
141 FIXME("property does not support DISPATCH_PROPERTYGET\n");
145 case DISPATCH_PROPERTYGET
|DISPATCH_METHOD
:
147 case DISPATCH_METHOD
:
148 if(prop
->flags
& (BP_GET
|BP_GETPUT
)) {
149 FIXME("Call on property\n");
153 case DISPATCH_PROPERTYPUT
:
154 if(!(prop
->flags
& (BP_GET
|BP_GETPUT
))) {
155 FIXME("property does not support DISPATCH_PROPERTYPUT\n");
162 FIXME("unsupported flags %x\n", flags
);
166 if(arg_cnt(dp
) < prop
->min_args
|| arg_cnt(dp
) > (prop
->max_args
? prop
->max_args
: prop
->min_args
)) {
167 FIXME("invalid number of arguments\n");
171 if(arg_cnt(dp
) == 1 && V_VT(dp
->rgvarg
) == (VT_BYREF
|VT_VARIANT
))
172 args
= V_VARIANTREF(dp
->rgvarg
);
176 return prop
->proc(This
, args
, dp
->cArgs
, res
);
179 static BOOL
run_terminator(vbdisp_t
*This
)
183 if(This
->terminator_ran
)
185 This
->terminator_ran
= TRUE
;
187 if(!This
->desc
->class_terminate_id
)
191 exec_script(This
->desc
->ctx
, This
->desc
->funcs
[This
->desc
->class_terminate_id
].entries
[VBDISP_CALLGET
],
192 (IDispatch
*)&This
->IDispatchEx_iface
, &dp
, NULL
);
196 static void clean_props(vbdisp_t
*This
)
203 for(i
=0; i
< This
->desc
->prop_cnt
; i
++)
204 VariantClear(This
->props
+i
);
207 static inline vbdisp_t
*impl_from_IDispatchEx(IDispatchEx
*iface
)
209 return CONTAINING_RECORD(iface
, vbdisp_t
, IDispatchEx_iface
);
212 static HRESULT WINAPI
DispatchEx_QueryInterface(IDispatchEx
*iface
, REFIID riid
, void **ppv
)
214 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
216 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
217 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
218 *ppv
= &This
->IDispatchEx_iface
;
219 }else if(IsEqualGUID(&IID_IDispatch
, riid
)) {
220 TRACE("(%p)->(IID_IDispatch %p)\n", This
, ppv
);
221 *ppv
= &This
->IDispatchEx_iface
;
222 }else if(IsEqualGUID(&IID_IDispatchEx
, riid
)) {
223 TRACE("(%p)->(IID_IDispatchEx %p)\n", This
, ppv
);
224 *ppv
= &This
->IDispatchEx_iface
;
226 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
228 return E_NOINTERFACE
;
231 IUnknown_AddRef((IUnknown
*)*ppv
);
235 static ULONG WINAPI
DispatchEx_AddRef(IDispatchEx
*iface
)
237 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
238 LONG ref
= InterlockedIncrement(&This
->ref
);
240 TRACE("(%p) ref=%d\n", This
, ref
);
245 static ULONG WINAPI
DispatchEx_Release(IDispatchEx
*iface
)
247 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
248 LONG ref
= InterlockedDecrement(&This
->ref
);
250 TRACE("(%p) ref=%d\n", This
, ref
);
252 if(!ref
&& run_terminator(This
)) {
254 list_remove(&This
->entry
);
261 static HRESULT WINAPI
DispatchEx_GetTypeInfoCount(IDispatchEx
*iface
, UINT
*pctinfo
)
263 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
265 TRACE("(%p)->(%p)\n", This
, pctinfo
);
271 static HRESULT WINAPI
DispatchEx_GetTypeInfo(IDispatchEx
*iface
, UINT iTInfo
, LCID lcid
,
274 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
275 FIXME("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
279 static HRESULT WINAPI
DispatchEx_GetIDsOfNames(IDispatchEx
*iface
, REFIID riid
,
280 LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
,
283 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
284 FIXME("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
289 static HRESULT WINAPI
DispatchEx_Invoke(IDispatchEx
*iface
, DISPID dispIdMember
,
290 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
291 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
293 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
294 FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
295 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
299 static HRESULT WINAPI
DispatchEx_GetDispID(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
, DISPID
*pid
)
301 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
303 TRACE("(%p)->(%s %x %p)\n", This
, debugstr_w(bstrName
), grfdex
, pid
);
308 if(grfdex
& ~(fdexNameEnsure
|fdexNameCaseInsensitive
)) {
309 FIXME("unsupported flags %x\n", grfdex
);
313 return vbdisp_get_id(This
, bstrName
, VBDISP_ANY
, FALSE
, pid
);
316 static HRESULT WINAPI
DispatchEx_InvokeEx(IDispatchEx
*iface
, DISPID id
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pdp
,
317 VARIANT
*pvarRes
, EXCEPINFO
*pei
, IServiceProvider
*pspCaller
)
319 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
321 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This
, id
, lcid
, wFlags
, pdp
, pvarRes
, pei
, pspCaller
);
327 V_VT(pvarRes
) = VT_EMPTY
;
330 return DISP_E_MEMBERNOTFOUND
;
332 if(is_func_id(This
, id
)) {
336 case DISPATCH_METHOD
:
337 case DISPATCH_METHOD
|DISPATCH_PROPERTYGET
:
338 func
= This
->desc
->funcs
[id
].entries
[VBDISP_CALLGET
];
340 FIXME("no invoke/getter\n");
341 return DISP_E_MEMBERNOTFOUND
;
344 return exec_script(This
->desc
->ctx
, func
, (IDispatch
*)&This
->IDispatchEx_iface
, pdp
, pvarRes
);
345 case DISPATCH_PROPERTYPUT
: {
347 DISPPARAMS dp
= {NULL
, NULL
, 1, 0};
350 FIXME("arguments not implemented\n");
354 put_val
= get_propput_arg(pdp
);
356 WARN("no value to set\n");
357 return DISP_E_PARAMNOTOPTIONAL
;
361 func
= This
->desc
->funcs
[id
].entries
[V_VT(put_val
) == VT_DISPATCH
? VBDISP_SET
: VBDISP_LET
];
363 FIXME("no letter/setter\n");
364 return DISP_E_MEMBERNOTFOUND
;
367 return exec_script(This
->desc
->ctx
, func
, (IDispatch
*)&This
->IDispatchEx_iface
, &dp
, NULL
);
370 FIXME("flags %x\n", wFlags
);
371 return DISP_E_MEMBERNOTFOUND
;
375 if(id
< This
->desc
->prop_cnt
+ This
->desc
->func_cnt
)
376 return invoke_variant_prop(This
, This
->props
+(id
-This
->desc
->func_cnt
), wFlags
, pdp
, pvarRes
);
378 if(This
->desc
->builtin_prop_cnt
) {
379 unsigned min
= 0, max
= This
->desc
->builtin_prop_cnt
-1, i
;
383 if(This
->desc
->builtin_props
[i
].id
== id
)
384 return invoke_builtin(This
, This
->desc
->builtin_props
+i
, wFlags
, pdp
, pvarRes
);
385 if(This
->desc
->builtin_props
[i
].id
< id
)
392 return DISP_E_MEMBERNOTFOUND
;
395 static HRESULT WINAPI
DispatchEx_DeleteMemberByName(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
)
397 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
398 FIXME("(%p)->(%s %x)\n", This
, debugstr_w(bstrName
), grfdex
);
402 static HRESULT WINAPI
DispatchEx_DeleteMemberByDispID(IDispatchEx
*iface
, DISPID id
)
404 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
405 FIXME("(%p)->(%x)\n", This
, id
);
409 static HRESULT WINAPI
DispatchEx_GetMemberProperties(IDispatchEx
*iface
, DISPID id
, DWORD grfdexFetch
, DWORD
*pgrfdex
)
411 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
412 FIXME("(%p)->(%x %x %p)\n", This
, id
, grfdexFetch
, pgrfdex
);
416 static HRESULT WINAPI
DispatchEx_GetMemberName(IDispatchEx
*iface
, DISPID id
, BSTR
*pbstrName
)
418 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
419 FIXME("(%p)->(%x %p)\n", This
, id
, pbstrName
);
423 static HRESULT WINAPI
DispatchEx_GetNextDispID(IDispatchEx
*iface
, DWORD grfdex
, DISPID id
, DISPID
*pid
)
425 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
426 FIXME("(%p)->(%x %x %p)\n", This
, grfdex
, id
, pid
);
430 static HRESULT WINAPI
DispatchEx_GetNameSpaceParent(IDispatchEx
*iface
, IUnknown
**ppunk
)
432 vbdisp_t
*This
= impl_from_IDispatchEx(iface
);
433 FIXME("(%p)->(%p)\n", This
, ppunk
);
437 static IDispatchExVtbl DispatchExVtbl
= {
438 DispatchEx_QueryInterface
,
441 DispatchEx_GetTypeInfoCount
,
442 DispatchEx_GetTypeInfo
,
443 DispatchEx_GetIDsOfNames
,
445 DispatchEx_GetDispID
,
447 DispatchEx_DeleteMemberByName
,
448 DispatchEx_DeleteMemberByDispID
,
449 DispatchEx_GetMemberProperties
,
450 DispatchEx_GetMemberName
,
451 DispatchEx_GetNextDispID
,
452 DispatchEx_GetNameSpaceParent
455 static inline vbdisp_t
*unsafe_impl_from_IDispatch(IDispatch
*iface
)
457 return iface
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
458 ? CONTAINING_RECORD(iface
, vbdisp_t
, IDispatchEx_iface
)
462 HRESULT
create_vbdisp(const class_desc_t
*desc
, vbdisp_t
**ret
)
466 vbdisp
= heap_alloc_zero( FIELD_OFFSET( vbdisp_t
, props
[desc
->prop_cnt
] ));
468 return E_OUTOFMEMORY
;
470 vbdisp
->IDispatchEx_iface
.lpVtbl
= &DispatchExVtbl
;
474 if(desc
->class_initialize_id
) {
478 hres
= exec_script(desc
->ctx
, desc
->funcs
[desc
->class_initialize_id
].entries
[VBDISP_CALLGET
],
479 (IDispatch
*)&vbdisp
->IDispatchEx_iface
, &dp
, NULL
);
481 IDispatchEx_Release(&vbdisp
->IDispatchEx_iface
);
486 list_add_tail(&desc
->ctx
->objects
, &vbdisp
->entry
);
491 void collect_objects(script_ctx_t
*ctx
)
493 vbdisp_t
*iter
, *iter2
;
495 LIST_FOR_EACH_ENTRY_SAFE(iter
, iter2
, &ctx
->objects
, vbdisp_t
, entry
)
496 run_terminator(iter
);
498 while(!list_empty(&ctx
->objects
)) {
499 iter
= LIST_ENTRY(list_head(&ctx
->objects
), vbdisp_t
, entry
);
501 IDispatchEx_AddRef(&iter
->IDispatchEx_iface
);
504 list_remove(&iter
->entry
);
505 list_init(&iter
->entry
);
506 IDispatchEx_Release(&iter
->IDispatchEx_iface
);
510 HRESULT
disp_get_id(IDispatch
*disp
, BSTR name
, vbdisp_invoke_type_t invoke_type
, BOOL search_private
, DISPID
*id
)
516 vbdisp
= unsafe_impl_from_IDispatch(disp
);
518 return vbdisp_get_id(vbdisp
, name
, invoke_type
, search_private
, id
);
520 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
522 TRACE("unsing IDispatch\n");
523 return IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &name
, 1, 0, id
);
526 hres
= IDispatchEx_GetDispID(dispex
, name
, fdexNameCaseInsensitive
, id
);
527 IDispatchEx_Release(dispex
);
531 HRESULT
disp_call(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, DISPPARAMS
*dp
, VARIANT
*retv
)
533 const WORD flags
= DISPATCH_METHOD
|(retv
? DISPATCH_PROPERTYGET
: 0);
538 memset(&ei
, 0, sizeof(ei
));
540 V_VT(retv
) = VT_EMPTY
;
542 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
546 TRACE("using IDispatch\n");
547 return IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, flags
, dp
, retv
, &ei
, &err
);
550 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, flags
, dp
, retv
, &ei
, NULL
/* CALLER_FIXME */);
551 IDispatchEx_Release(dispex
);
555 HRESULT
disp_propput(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, VARIANT
*val
)
557 DISPID propput_dispid
= DISPID_PROPERTYPUT
;
558 DISPPARAMS dp
= {val
, &propput_dispid
, 1, 1};
563 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
564 if(SUCCEEDED(hres
)) {
565 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, DISPATCH_PROPERTYPUT
, &dp
, NULL
, &ei
, NULL
/* FIXME! */);
566 IDispatchEx_Release(dispex
);
570 TRACE("using IDispatch\n");
571 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, DISPATCH_PROPERTYPUT
, &dp
, NULL
, &ei
, &err
);