jscript: Store more data in DispatchEx object.
[wine] / dlls / jscript / dispex.c
1 /*
2  * Copyright 2008 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 "jscript.h"
20
21 #include "wine/unicode.h"
22 #include "wine/debug.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
25
26 typedef enum {
27     PROP_VARIANT,
28     PROP_BUILTIN,
29     PROP_PROTREF,
30     PROP_DELETED
31 } prop_type_t;
32
33 struct _dispex_prop_t {
34     WCHAR *name;
35     prop_type_t type;
36     DWORD flags;
37
38     union {
39         VARIANT var;
40         const builtin_prop_t *p;
41         DWORD ref;
42     } u;
43 };
44
45 #define DISPATCHEX_THIS(iface) DEFINE_THIS(DispatchEx, IDispatchEx, iface)
46
47 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
48 {
49     DispatchEx *This = DISPATCHEX_THIS(iface);
50
51     if(IsEqualGUID(&IID_IUnknown, riid)) {
52         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
53         *ppv = _IDispatchEx_(This);
54     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
55         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
56         *ppv = _IDispatchEx_(This);
57     }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
58         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
59         *ppv = _IDispatchEx_(This);
60     }else {
61         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
62         *ppv = NULL;
63         return E_NOINTERFACE;
64     }
65
66     IUnknown_AddRef((IUnknown*)*ppv);
67     return S_OK;
68 }
69
70 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
71 {
72     DispatchEx *This = DISPATCHEX_THIS(iface);
73     LONG ref = InterlockedIncrement(&This->ref);
74
75     TRACE("(%p) ref=%d\n", This, ref);
76
77     return ref;
78 }
79
80 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
81 {
82     DispatchEx *This = DISPATCHEX_THIS(iface);
83     LONG ref = InterlockedDecrement(&This->ref);
84
85     TRACE("(%p) ref=%d\n", This, ref);
86
87     if(!ref) {
88         dispex_prop_t *prop;
89
90         for(prop = This->props; prop < This->props+This->prop_cnt; prop++) {
91             if(prop->type == PROP_VARIANT)
92                 VariantClear(&prop->u.var);
93             heap_free(prop->name);
94         }
95         heap_free(This->props);
96         script_release(This->ctx);
97
98         if(This->builtin_info->destructor)
99             This->builtin_info->destructor(This);
100         else
101             heap_free(This);
102     }
103
104     return ref;
105 }
106
107 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
108 {
109     DispatchEx *This = DISPATCHEX_THIS(iface);
110
111     TRACE("(%p)->(%p)\n", This, pctinfo);
112
113     *pctinfo = 1;
114     return S_OK;
115 }
116
117 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
118                                               LCID lcid, ITypeInfo **ppTInfo)
119 {
120     DispatchEx *This = DISPATCHEX_THIS(iface);
121     FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
122     return E_NOTIMPL;
123 }
124
125 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
126                                                 LPOLESTR *rgszNames, UINT cNames,
127                                                 LCID lcid, DISPID *rgDispId)
128 {
129     DispatchEx *This = DISPATCHEX_THIS(iface);
130     UINT i;
131     HRESULT hres;
132
133     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
134           lcid, rgDispId);
135
136     for(i=0; i < cNames; i++) {
137         hres = IDispatchEx_GetDispID(_IDispatchEx_(This), rgszNames[i], 0, rgDispId+i);
138         if(FAILED(hres))
139             return hres;
140     }
141
142     return S_OK;
143 }
144
145 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
146                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
147                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
148 {
149     DispatchEx *This = DISPATCHEX_THIS(iface);
150
151     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
152           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
153
154     return IDispatchEx_InvokeEx(_IDispatchEx_(This), dispIdMember, lcid, wFlags,
155             pDispParams, pVarResult, pExcepInfo, NULL);
156 }
157
158 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
159 {
160     DispatchEx *This = DISPATCHEX_THIS(iface);
161     FIXME("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
162     return E_NOTIMPL;
163 }
164
165 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
166         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
167 {
168     DispatchEx *This = DISPATCHEX_THIS(iface);
169     FIXME("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
170     return E_NOTIMPL;
171 }
172
173 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
174 {
175     DispatchEx *This = DISPATCHEX_THIS(iface);
176     FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
177     return E_NOTIMPL;
178 }
179
180 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
181 {
182     DispatchEx *This = DISPATCHEX_THIS(iface);
183     FIXME("(%p)->(%x)\n", This, id);
184     return E_NOTIMPL;
185 }
186
187 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
188 {
189     DispatchEx *This = DISPATCHEX_THIS(iface);
190     FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
191     return E_NOTIMPL;
192 }
193
194 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
195 {
196     DispatchEx *This = DISPATCHEX_THIS(iface);
197     FIXME("(%p)->(%x %p)\n", This, id, pbstrName);
198     return E_NOTIMPL;
199 }
200
201 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
202 {
203     DispatchEx *This = DISPATCHEX_THIS(iface);
204     FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
205     return E_NOTIMPL;
206 }
207
208 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
209 {
210     DispatchEx *This = DISPATCHEX_THIS(iface);
211     FIXME("(%p)->(%p)\n", This, ppunk);
212     return E_NOTIMPL;
213 }
214
215 #undef DISPATCHEX_THIS
216
217 static IDispatchExVtbl DispatchExVtbl = {
218     DispatchEx_QueryInterface,
219     DispatchEx_AddRef,
220     DispatchEx_Release,
221     DispatchEx_GetTypeInfoCount,
222     DispatchEx_GetTypeInfo,
223     DispatchEx_GetIDsOfNames,
224     DispatchEx_Invoke,
225     DispatchEx_GetDispID,
226     DispatchEx_InvokeEx,
227     DispatchEx_DeleteMemberByName,
228     DispatchEx_DeleteMemberByDispID,
229     DispatchEx_GetMemberProperties,
230     DispatchEx_GetMemberName,
231     DispatchEx_GetNextDispID,
232     DispatchEx_GetNameSpaceParent
233 };
234
235 static HRESULT jsdisp_set_prot_prop(DispatchEx *dispex, DispatchEx *prototype)
236 {
237     VARIANT *var;
238
239     if(!dispex->props[1].name)
240         return E_OUTOFMEMORY;
241
242     dispex->props[1].type = PROP_VARIANT;
243     dispex->props[1].flags = 0;
244
245     var = &dispex->props[1].u.var;
246     V_VT(var) = VT_DISPATCH;
247     V_DISPATCH(var) = (IDispatch*)_IDispatchEx_(prototype);
248
249     return S_OK;
250 }
251
252 static HRESULT init_dispex(DispatchEx *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, DispatchEx *prototype)
253 {
254     static const WCHAR prototypeW[] = {'p','r','o','t','o','t','y','p','e',0};
255
256     TRACE("%p (%p)\n", dispex, prototype);
257
258     dispex->lpIDispatchExVtbl = &DispatchExVtbl;
259     dispex->ref = 1;
260     dispex->builtin_info = builtin_info;
261
262     dispex->props = heap_alloc((dispex->buf_size=4) * sizeof(dispex_prop_t));
263     if(!dispex->props)
264         return E_OUTOFMEMORY;
265
266     dispex->prototype = prototype;
267     if(prototype)
268         IDispatchEx_AddRef(_IDispatchEx_(prototype));
269
270     dispex->prop_cnt = 2;
271     dispex->props[0].name = NULL;
272     dispex->props[0].flags = 0;
273     if(builtin_info->value_prop.invoke) {
274         dispex->props[0].type = PROP_BUILTIN;
275         dispex->props[0].u.p = &builtin_info->value_prop;
276     }else {
277         dispex->props[0].type = PROP_DELETED;
278     }
279
280     dispex->props[1].type = PROP_DELETED;
281     dispex->props[1].name = SysAllocString(prototypeW);
282     dispex->props[1].flags = 0;
283
284     if(prototype) {
285         HRESULT hres;
286
287         hres = jsdisp_set_prot_prop(dispex, prototype);
288         if(FAILED(hres)) {
289             IDispatchEx_Release(_IDispatchEx_(dispex));
290             return hres;
291         }
292     }
293
294     script_addref(ctx);
295     dispex->ctx = ctx;
296
297     return S_OK;
298 }
299
300 static const builtin_info_t dispex_info = {
301     JSCLASS_NONE,
302     {NULL, NULL, 0},
303     0, NULL,
304     NULL,
305     NULL
306 };
307
308 HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, DispatchEx *prototype, DispatchEx **dispex)
309 {
310     DispatchEx *ret;
311     HRESULT hres;
312
313     ret = heap_alloc_zero(sizeof(DispatchEx));
314     if(!ret)
315         return E_OUTOFMEMORY;
316
317     hres = init_dispex(ret, ctx, builtin_info ? builtin_info : &dispex_info, prototype);
318     if(FAILED(hres))
319         return hres;
320
321     *dispex = ret;
322     return S_OK;
323 }