push 0e6205f14485faf726c13701981a3210b06d24f6
[wine/hacks.git] / dlls / jscript / dispex.c
blobd2af5f821493a1738d5f1fb2ce835d5e60a71b48
1 /*
2 * Copyright 2008 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
19 #include "jscript.h"
21 #include "wine/unicode.h"
22 #include "wine/debug.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
26 typedef enum {
27 PROP_VARIANT,
28 PROP_BUILTIN,
29 PROP_PROTREF,
30 PROP_DELETED
31 } prop_type_t;
33 struct _dispex_prop_t {
34 WCHAR *name;
35 prop_type_t type;
36 DWORD flags;
38 union {
39 VARIANT var;
40 const builtin_prop_t *p;
41 DWORD ref;
42 } u;
45 static inline DISPID prop_to_id(DispatchEx *This, dispex_prop_t *prop)
47 return prop - This->props;
50 static const builtin_prop_t *find_builtin_prop(DispatchEx *This, const WCHAR *name)
52 int min = 0, max, i, r;
54 max = This->builtin_info->props_cnt-1;
55 while(min <= max) {
56 i = (min+max)/2;
58 r = strcmpW(name, This->builtin_info->props[i].name);
59 if(!r)
60 return This->builtin_info->props + i;
62 if(r < 0)
63 max = i-1;
64 else
65 min = i+1;
68 return NULL;
71 static dispex_prop_t *alloc_prop(DispatchEx *This, const WCHAR *name, prop_type_t type, DWORD flags)
73 dispex_prop_t *ret;
75 if(This->buf_size == This->prop_cnt) {
76 dispex_prop_t *tmp = heap_realloc(This->props, (This->buf_size<<=1)*sizeof(*This->props));
77 if(!tmp)
78 return NULL;
79 This->props = tmp;
82 ret = This->props + This->prop_cnt++;
83 ret->type = type;
84 ret->flags = flags;
85 ret->name = heap_strdupW(name);
86 if(!ret->name)
87 return NULL;
89 return ret;
92 static dispex_prop_t *alloc_protref(DispatchEx *This, const WCHAR *name, DWORD ref)
94 dispex_prop_t *ret;
96 ret = alloc_prop(This, name, PROP_PROTREF, 0);
97 if(!ret)
98 return NULL;
100 ret->u.ref = ref;
101 return ret;
104 static HRESULT find_prop_name(DispatchEx *This, const WCHAR *name, dispex_prop_t **ret)
106 const builtin_prop_t *builtin;
107 dispex_prop_t *prop;
109 for(prop = This->props; prop < This->props+This->prop_cnt; prop++) {
110 if(prop->name && !strcmpW(prop->name, name)) {
111 *ret = prop;
112 return S_OK;
116 builtin = find_builtin_prop(This, name);
117 if(builtin) {
118 prop = alloc_prop(This, name, PROP_BUILTIN, builtin->flags);
119 if(!prop)
120 return E_OUTOFMEMORY;
122 prop->u.p = builtin;
123 *ret = prop;
124 return S_OK;
127 *ret = NULL;
128 return S_OK;
131 static HRESULT find_prop_name_prot(DispatchEx *This, const WCHAR *name, BOOL alloc, dispex_prop_t **ret)
133 dispex_prop_t *prop;
134 HRESULT hres;
136 hres = find_prop_name(This, name, &prop);
137 if(FAILED(hres))
138 return hres;
139 if(prop) {
140 *ret = prop;
141 return S_OK;
144 if(This->prototype) {
145 hres = find_prop_name_prot(This->prototype, name, FALSE, &prop);
146 if(FAILED(hres))
147 return hres;
148 if(prop) {
149 prop = alloc_protref(This, prop->name, prop - This->prototype->props);
150 if(!prop)
151 return E_OUTOFMEMORY;
152 *ret = prop;
153 return S_OK;
157 if(alloc) {
158 TRACE("creating prop %s\n", debugstr_w(name));
160 prop = alloc_prop(This, name, PROP_VARIANT, PROPF_ENUM);
161 if(!prop)
162 return E_OUTOFMEMORY;
163 VariantInit(&prop->u.var);
166 *ret = prop;
167 return S_OK;
170 #define DISPATCHEX_THIS(iface) DEFINE_THIS(DispatchEx, IDispatchEx, iface)
172 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
174 DispatchEx *This = DISPATCHEX_THIS(iface);
176 if(IsEqualGUID(&IID_IUnknown, riid)) {
177 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
178 *ppv = _IDispatchEx_(This);
179 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
180 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
181 *ppv = _IDispatchEx_(This);
182 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
183 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
184 *ppv = _IDispatchEx_(This);
185 }else {
186 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
187 *ppv = NULL;
188 return E_NOINTERFACE;
191 IUnknown_AddRef((IUnknown*)*ppv);
192 return S_OK;
195 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
197 DispatchEx *This = DISPATCHEX_THIS(iface);
198 LONG ref = InterlockedIncrement(&This->ref);
200 TRACE("(%p) ref=%d\n", This, ref);
202 return ref;
205 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
207 DispatchEx *This = DISPATCHEX_THIS(iface);
208 LONG ref = InterlockedDecrement(&This->ref);
210 TRACE("(%p) ref=%d\n", This, ref);
212 if(!ref) {
213 dispex_prop_t *prop;
215 for(prop = This->props; prop < This->props+This->prop_cnt; prop++) {
216 if(prop->type == PROP_VARIANT)
217 VariantClear(&prop->u.var);
218 heap_free(prop->name);
220 heap_free(This->props);
221 script_release(This->ctx);
223 if(This->builtin_info->destructor)
224 This->builtin_info->destructor(This);
225 else
226 heap_free(This);
229 return ref;
232 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
234 DispatchEx *This = DISPATCHEX_THIS(iface);
236 TRACE("(%p)->(%p)\n", This, pctinfo);
238 *pctinfo = 1;
239 return S_OK;
242 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
243 LCID lcid, ITypeInfo **ppTInfo)
245 DispatchEx *This = DISPATCHEX_THIS(iface);
246 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
247 return E_NOTIMPL;
250 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
251 LPOLESTR *rgszNames, UINT cNames,
252 LCID lcid, DISPID *rgDispId)
254 DispatchEx *This = DISPATCHEX_THIS(iface);
255 UINT i;
256 HRESULT hres;
258 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
259 lcid, rgDispId);
261 for(i=0; i < cNames; i++) {
262 hres = IDispatchEx_GetDispID(_IDispatchEx_(This), rgszNames[i], 0, rgDispId+i);
263 if(FAILED(hres))
264 return hres;
267 return S_OK;
270 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
271 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
272 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
274 DispatchEx *This = DISPATCHEX_THIS(iface);
276 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
277 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
279 return IDispatchEx_InvokeEx(_IDispatchEx_(This), dispIdMember, lcid, wFlags,
280 pDispParams, pVarResult, pExcepInfo, NULL);
283 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
285 DispatchEx *This = DISPATCHEX_THIS(iface);
286 dispex_prop_t *prop;
287 HRESULT hres;
289 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
291 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit)) {
292 FIXME("Unsupported grfdex %x\n", grfdex);
293 return E_NOTIMPL;
296 hres = find_prop_name_prot(This, bstrName, (grfdex&fdexNameEnsure) != 0, &prop);
297 if(FAILED(hres))
298 return hres;
299 if(prop) {
300 *pid = prop_to_id(This, prop);
301 return S_OK;
304 TRACE("not found %s\n", debugstr_w(bstrName));
305 return DISP_E_UNKNOWNNAME;
308 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
309 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
311 DispatchEx *This = DISPATCHEX_THIS(iface);
312 FIXME("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
313 return E_NOTIMPL;
316 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
318 DispatchEx *This = DISPATCHEX_THIS(iface);
319 FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
320 return E_NOTIMPL;
323 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
325 DispatchEx *This = DISPATCHEX_THIS(iface);
326 FIXME("(%p)->(%x)\n", This, id);
327 return E_NOTIMPL;
330 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
332 DispatchEx *This = DISPATCHEX_THIS(iface);
333 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
334 return E_NOTIMPL;
337 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
339 DispatchEx *This = DISPATCHEX_THIS(iface);
340 FIXME("(%p)->(%x %p)\n", This, id, pbstrName);
341 return E_NOTIMPL;
344 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
346 DispatchEx *This = DISPATCHEX_THIS(iface);
347 FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
348 return E_NOTIMPL;
351 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
353 DispatchEx *This = DISPATCHEX_THIS(iface);
354 FIXME("(%p)->(%p)\n", This, ppunk);
355 return E_NOTIMPL;
358 #undef DISPATCHEX_THIS
360 static IDispatchExVtbl DispatchExVtbl = {
361 DispatchEx_QueryInterface,
362 DispatchEx_AddRef,
363 DispatchEx_Release,
364 DispatchEx_GetTypeInfoCount,
365 DispatchEx_GetTypeInfo,
366 DispatchEx_GetIDsOfNames,
367 DispatchEx_Invoke,
368 DispatchEx_GetDispID,
369 DispatchEx_InvokeEx,
370 DispatchEx_DeleteMemberByName,
371 DispatchEx_DeleteMemberByDispID,
372 DispatchEx_GetMemberProperties,
373 DispatchEx_GetMemberName,
374 DispatchEx_GetNextDispID,
375 DispatchEx_GetNameSpaceParent
378 static HRESULT jsdisp_set_prot_prop(DispatchEx *dispex, DispatchEx *prototype)
380 VARIANT *var;
382 if(!dispex->props[1].name)
383 return E_OUTOFMEMORY;
385 dispex->props[1].type = PROP_VARIANT;
386 dispex->props[1].flags = 0;
388 var = &dispex->props[1].u.var;
389 V_VT(var) = VT_DISPATCH;
390 V_DISPATCH(var) = (IDispatch*)_IDispatchEx_(prototype);
392 return S_OK;
395 static HRESULT init_dispex(DispatchEx *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, DispatchEx *prototype)
397 static const WCHAR prototypeW[] = {'p','r','o','t','o','t','y','p','e',0};
399 TRACE("%p (%p)\n", dispex, prototype);
401 dispex->lpIDispatchExVtbl = &DispatchExVtbl;
402 dispex->ref = 1;
403 dispex->builtin_info = builtin_info;
405 dispex->props = heap_alloc((dispex->buf_size=4) * sizeof(dispex_prop_t));
406 if(!dispex->props)
407 return E_OUTOFMEMORY;
409 dispex->prototype = prototype;
410 if(prototype)
411 IDispatchEx_AddRef(_IDispatchEx_(prototype));
413 dispex->prop_cnt = 2;
414 dispex->props[0].name = NULL;
415 dispex->props[0].flags = 0;
416 if(builtin_info->value_prop.invoke) {
417 dispex->props[0].type = PROP_BUILTIN;
418 dispex->props[0].u.p = &builtin_info->value_prop;
419 }else {
420 dispex->props[0].type = PROP_DELETED;
423 dispex->props[1].type = PROP_DELETED;
424 dispex->props[1].name = SysAllocString(prototypeW);
425 dispex->props[1].flags = 0;
427 if(prototype) {
428 HRESULT hres;
430 hres = jsdisp_set_prot_prop(dispex, prototype);
431 if(FAILED(hres)) {
432 IDispatchEx_Release(_IDispatchEx_(dispex));
433 return hres;
437 script_addref(ctx);
438 dispex->ctx = ctx;
440 return S_OK;
443 static const builtin_info_t dispex_info = {
444 JSCLASS_NONE,
445 {NULL, NULL, 0},
446 0, NULL,
447 NULL,
448 NULL
451 HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, DispatchEx *prototype, DispatchEx **dispex)
453 DispatchEx *ret;
454 HRESULT hres;
456 ret = heap_alloc_zero(sizeof(DispatchEx));
457 if(!ret)
458 return E_OUTOFMEMORY;
460 hres = init_dispex(ret, ctx, builtin_info ? builtin_info : &dispex_info, prototype);
461 if(FAILED(hres))
462 return hres;
464 *dispex = ret;
465 return S_OK;