vbscript: Added support for variable assignment statements.
[wine] / dlls / vbscript / vbscript.c
1 /*
2  * Copyright 2011 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
20 #include <assert.h>
21
22 #include "vbscript.h"
23 #include "objsafe.h"
24
25 #include "wine/debug.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
28
29 #ifdef _WIN64
30
31 #define CTXARG_T DWORDLONG
32 #define IActiveScriptParseVtbl IActiveScriptParse64Vtbl
33
34 #else
35
36 #define CTXARG_T DWORD
37 #define IActiveScriptParseVtbl IActiveScriptParse32Vtbl
38
39 #endif
40
41 struct VBScript {
42     IActiveScript IActiveScript_iface;
43     IActiveScriptParse IActiveScriptParse_iface;
44     IObjectSafety IObjectSafety_iface;
45
46     LONG ref;
47
48     DWORD safeopt;
49     SCRIPTSTATE state;
50     IActiveScriptSite *site;
51     script_ctx_t *ctx;
52     LONG thread_id;
53     LCID lcid;
54 };
55
56 static void change_state(VBScript *This, SCRIPTSTATE state)
57 {
58     if(This->state == state)
59         return;
60
61     This->state = state;
62     if(This->site)
63         IActiveScriptSite_OnStateChange(This->site, state);
64 }
65
66 static inline BOOL is_started(VBScript *This)
67 {
68     return This->state == SCRIPTSTATE_STARTED
69         || This->state == SCRIPTSTATE_CONNECTED
70         || This->state == SCRIPTSTATE_DISCONNECTED;
71 }
72
73 static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code)
74 {
75     HRESULT hres;
76
77     code->global_executed = TRUE;
78
79     IActiveScriptSite_OnEnterScript(ctx->site);
80     hres = exec_script(ctx, &code->global_code);
81     IActiveScriptSite_OnLeaveScript(ctx->site);
82
83     return hres;
84 }
85
86 static void exec_queued_code(script_ctx_t *ctx)
87 {
88     vbscode_t *iter;
89
90     LIST_FOR_EACH_ENTRY(iter, &ctx->code_list, vbscode_t, entry) {
91         if(!iter->global_executed)
92             exec_global_code(ctx, iter);
93     }
94 }
95
96 static HRESULT set_ctx_site(VBScript *This)
97 {
98     HRESULT hres;
99
100     This->ctx->lcid = This->lcid;
101
102     hres = init_global(This->ctx);
103     if(FAILED(hres))
104         return hres;
105
106     IActiveScriptSite_AddRef(This->site);
107     This->ctx->site = This->site;
108
109     change_state(This, SCRIPTSTATE_INITIALIZED);
110     return S_OK;
111 }
112
113 static void destroy_script(script_ctx_t *ctx)
114 {
115     while(!list_empty(&ctx->code_list))
116         release_vbscode(LIST_ENTRY(list_head(&ctx->code_list), vbscode_t, entry));
117
118     while(!list_empty(&ctx->named_items)) {
119         named_item_t *iter = LIST_ENTRY(list_head(&ctx->named_items), named_item_t, entry);
120
121         list_remove(&iter->entry);
122         if(iter->disp)
123             IDispatch_Release(iter->disp);
124         heap_free(iter->name);
125         heap_free(iter);
126     }
127
128     if(ctx->host_global)
129         IDispatch_Release(ctx->host_global);
130     if(ctx->site)
131         IActiveScriptSite_Release(ctx->site);
132     if(ctx->script_obj)
133         IDispatchEx_Release(&ctx->script_obj->IDispatchEx_iface);
134     heap_free(ctx);
135 }
136
137 static void decrease_state(VBScript *This, SCRIPTSTATE state)
138 {
139     switch(This->state) {
140     case SCRIPTSTATE_CONNECTED:
141         change_state(This, SCRIPTSTATE_DISCONNECTED);
142         if(state == SCRIPTSTATE_DISCONNECTED)
143             return;
144         /* FALLTHROUGH */
145     case SCRIPTSTATE_STARTED:
146     case SCRIPTSTATE_DISCONNECTED:
147         if(This->state == SCRIPTSTATE_DISCONNECTED)
148             change_state(This, SCRIPTSTATE_INITIALIZED);
149         if(state == SCRIPTSTATE_INITIALIZED)
150             break;
151         /* FALLTHROUGH */
152     case SCRIPTSTATE_INITIALIZED:
153     case SCRIPTSTATE_UNINITIALIZED:
154         change_state(This, state);
155
156         if(This->site) {
157             IActiveScriptSite_Release(This->site);
158             This->site = NULL;
159         }
160
161         This->thread_id = 0;
162
163         if(state == SCRIPTSTATE_CLOSED) {
164             destroy_script(This->ctx);
165             This->ctx = NULL;
166         }
167
168         break;
169     default:
170         assert(0);
171     }
172 }
173
174 static inline VBScript *impl_from_IActiveScript(IActiveScript *iface)
175 {
176     return CONTAINING_RECORD(iface, VBScript, IActiveScript_iface);
177 }
178
179 static HRESULT WINAPI VBScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
180 {
181     VBScript *This = impl_from_IActiveScript(iface);
182
183     if(IsEqualGUID(riid, &IID_IUnknown)) {
184         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
185         *ppv = &This->IActiveScript_iface;
186     }else if(IsEqualGUID(riid, &IID_IActiveScript)) {
187         TRACE("(%p)->(IID_IActiveScript %p)\n", This, ppv);
188         *ppv = &This->IActiveScript_iface;
189     }else if(IsEqualGUID(riid, &IID_IActiveScriptParse)) {
190         TRACE("(%p)->(IID_IActiveScriptParse %p)\n", This, ppv);
191         *ppv = &This->IActiveScriptParse_iface;
192     }else if(IsEqualGUID(riid, &IID_IObjectSafety)) {
193         TRACE("(%p)->(IID_IObjectSafety %p)\n", This, ppv);
194         *ppv = &This->IObjectSafety_iface;
195     }else {
196         FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
197         *ppv = NULL;
198         return E_NOINTERFACE;
199     }
200
201     IUnknown_AddRef((IUnknown*)*ppv);
202     return S_OK;
203 }
204
205 static ULONG WINAPI VBScript_AddRef(IActiveScript *iface)
206 {
207     VBScript *This = impl_from_IActiveScript(iface);
208     LONG ref = InterlockedIncrement(&This->ref);
209
210     TRACE("(%p) ref=%d\n", This, ref);
211
212     return ref;
213 }
214
215 static ULONG WINAPI VBScript_Release(IActiveScript *iface)
216 {
217     VBScript *This = impl_from_IActiveScript(iface);
218     LONG ref = InterlockedDecrement(&This->ref);
219
220     TRACE("(%p) ref=%d\n", iface, ref);
221
222     if(!ref) {
223         if(This->site)
224             IActiveScriptSite_Release(This->site);
225         heap_free(This);
226     }
227
228     return ref;
229 }
230
231 static HRESULT WINAPI VBScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass)
232 {
233     VBScript *This = impl_from_IActiveScript(iface);
234     LCID lcid;
235     HRESULT hres;
236
237     TRACE("(%p)->(%p)\n", This, pass);
238
239     if(!pass)
240         return E_POINTER;
241
242     if(This->site)
243         return E_UNEXPECTED;
244
245     if(InterlockedCompareExchange(&This->thread_id, GetCurrentThreadId(), 0))
246         return E_UNEXPECTED;
247
248     This->site = pass;
249     IActiveScriptSite_AddRef(This->site);
250
251     hres = IActiveScriptSite_GetLCID(This->site, &lcid);
252     if(hres == S_OK)
253         This->lcid = lcid;
254
255     return This->ctx ? set_ctx_site(This) : S_OK;
256 }
257
258 static HRESULT WINAPI VBScript_GetScriptSite(IActiveScript *iface, REFIID riid,
259                                             void **ppvObject)
260 {
261     VBScript *This = impl_from_IActiveScript(iface);
262     FIXME("(%p)->()\n", This);
263     return E_NOTIMPL;
264 }
265
266 static HRESULT WINAPI VBScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
267 {
268     VBScript *This = impl_from_IActiveScript(iface);
269
270     TRACE("(%p)->(%d)\n", This, ss);
271
272     if(This->thread_id && GetCurrentThreadId() != This->thread_id)
273         return E_UNEXPECTED;
274
275     if(ss == SCRIPTSTATE_UNINITIALIZED) {
276         if(This->state == SCRIPTSTATE_CLOSED)
277             return E_UNEXPECTED;
278
279         decrease_state(This, SCRIPTSTATE_UNINITIALIZED);
280         return S_OK;
281     }
282
283     if(!This->ctx)
284         return E_UNEXPECTED;
285
286     switch(ss) {
287     case SCRIPTSTATE_STARTED:
288     case SCRIPTSTATE_CONNECTED: /* FIXME */
289         if(This->state == SCRIPTSTATE_CLOSED)
290             return E_UNEXPECTED;
291
292         exec_queued_code(This->ctx);
293         break;
294     case SCRIPTSTATE_INITIALIZED:
295         FIXME("unimplemented SCRIPTSTATE_INITIALIZED\n");
296         return S_OK;
297     default:
298         FIXME("unimplemented state %d\n", ss);
299         return E_NOTIMPL;
300     }
301
302     change_state(This, ss);
303     return S_OK;
304 }
305
306 static HRESULT WINAPI VBScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
307 {
308     VBScript *This = impl_from_IActiveScript(iface);
309
310     TRACE("(%p)->(%p)\n", This, pssState);
311
312     if(!pssState)
313         return E_POINTER;
314
315     if(This->thread_id && This->thread_id != GetCurrentThreadId())
316         return E_UNEXPECTED;
317
318     *pssState = This->state;
319     return S_OK;
320 }
321
322 static HRESULT WINAPI VBScript_Close(IActiveScript *iface)
323 {
324     VBScript *This = impl_from_IActiveScript(iface);
325
326     TRACE("(%p)->()\n", This);
327
328     if(This->thread_id && This->thread_id != GetCurrentThreadId())
329         return E_UNEXPECTED;
330
331     decrease_state(This, SCRIPTSTATE_CLOSED);
332     return S_OK;
333 }
334
335 static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstrName, DWORD dwFlags)
336 {
337     VBScript *This = impl_from_IActiveScript(iface);
338     named_item_t *item;
339     IDispatch *disp = NULL;
340     HRESULT hres;
341
342     TRACE("(%p)->(%s %x)\n", This, debugstr_w(pstrName), dwFlags);
343
344     if(This->thread_id != GetCurrentThreadId() || !This->ctx || This->state == SCRIPTSTATE_CLOSED)
345         return E_UNEXPECTED;
346
347     if(dwFlags & SCRIPTITEM_GLOBALMEMBERS) {
348         IUnknown *unk;
349
350         hres = IActiveScriptSite_GetItemInfo(This->site, pstrName, SCRIPTINFO_IUNKNOWN, &unk, NULL);
351         if(FAILED(hres)) {
352             WARN("GetItemInfo failed: %08x\n", hres);
353             return hres;
354         }
355
356         hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp);
357         IUnknown_Release(unk);
358         if(FAILED(hres)) {
359             WARN("object does not implement IDispatch\n");
360             return hres;
361         }
362
363         if(This->ctx->host_global)
364             IDispatch_Release(This->ctx->host_global);
365         IDispatch_AddRef(disp);
366         This->ctx->host_global = disp;
367     }
368
369     item = heap_alloc(sizeof(*item));
370     if(!item) {
371         if(disp)
372             IDispatch_Release(disp);
373         return E_OUTOFMEMORY;
374     }
375
376     item->disp = disp;
377     item->flags = dwFlags;
378     item->name = heap_strdupW(pstrName);
379     if(!item->name) {
380         if(disp)
381             IDispatch_Release(disp);
382         heap_free(item);
383         return E_OUTOFMEMORY;
384     }
385
386     list_add_tail(&This->ctx->named_items, &item->entry);
387     return S_OK;
388 }
389
390 static HRESULT WINAPI VBScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
391         DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
392 {
393     VBScript *This = impl_from_IActiveScript(iface);
394     FIXME("(%p)->()\n", This);
395     return E_NOTIMPL;
396 }
397
398 static HRESULT WINAPI VBScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName, IDispatch **ppdisp)
399 {
400     VBScript *This = impl_from_IActiveScript(iface);
401
402     TRACE("(%p)->(%p)\n", This, ppdisp);
403
404     if(!ppdisp)
405         return E_POINTER;
406
407     if(This->thread_id != GetCurrentThreadId() || !This->ctx->script_obj) {
408         *ppdisp = NULL;
409         return E_UNEXPECTED;
410     }
411
412     *ppdisp = (IDispatch*)&This->ctx->script_obj->IDispatchEx_iface;
413     IDispatch_AddRef(*ppdisp);
414     return S_OK;
415 }
416
417 static HRESULT WINAPI VBScript_GetCurrentScriptThreadID(IActiveScript *iface,
418                                                        SCRIPTTHREADID *pstridThread)
419 {
420     VBScript *This = impl_from_IActiveScript(iface);
421     FIXME("(%p)->()\n", This);
422     return E_NOTIMPL;
423 }
424
425 static HRESULT WINAPI VBScript_GetScriptThreadID(IActiveScript *iface,
426                                                 DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
427 {
428     VBScript *This = impl_from_IActiveScript(iface);
429     FIXME("(%p)->()\n", This);
430     return E_NOTIMPL;
431 }
432
433 static HRESULT WINAPI VBScript_GetScriptThreadState(IActiveScript *iface,
434         SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
435 {
436     VBScript *This = impl_from_IActiveScript(iface);
437     FIXME("(%p)->()\n", This);
438     return E_NOTIMPL;
439 }
440
441 static HRESULT WINAPI VBScript_InterruptScriptThread(IActiveScript *iface,
442         SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
443 {
444     VBScript *This = impl_from_IActiveScript(iface);
445     FIXME("(%p)->()\n", This);
446     return E_NOTIMPL;
447 }
448
449 static HRESULT WINAPI VBScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
450 {
451     VBScript *This = impl_from_IActiveScript(iface);
452     FIXME("(%p)->()\n", This);
453     return E_NOTIMPL;
454 }
455
456 static const IActiveScriptVtbl VBScriptVtbl = {
457     VBScript_QueryInterface,
458     VBScript_AddRef,
459     VBScript_Release,
460     VBScript_SetScriptSite,
461     VBScript_GetScriptSite,
462     VBScript_SetScriptState,
463     VBScript_GetScriptState,
464     VBScript_Close,
465     VBScript_AddNamedItem,
466     VBScript_AddTypeLib,
467     VBScript_GetScriptDispatch,
468     VBScript_GetCurrentScriptThreadID,
469     VBScript_GetScriptThreadID,
470     VBScript_GetScriptThreadState,
471     VBScript_InterruptScriptThread,
472     VBScript_Clone
473 };
474
475 static inline VBScript *impl_from_IActiveScriptParse(IActiveScriptParse *iface)
476 {
477     return CONTAINING_RECORD(iface, VBScript, IActiveScriptParse_iface);
478 }
479
480 static HRESULT WINAPI VBScriptParse_QueryInterface(IActiveScriptParse *iface, REFIID riid, void **ppv)
481 {
482     VBScript *This = impl_from_IActiveScriptParse(iface);
483     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
484 }
485
486 static ULONG WINAPI VBScriptParse_AddRef(IActiveScriptParse *iface)
487 {
488     VBScript *This = impl_from_IActiveScriptParse(iface);
489     return IActiveScript_AddRef(&This->IActiveScript_iface);
490 }
491
492 static ULONG WINAPI VBScriptParse_Release(IActiveScriptParse *iface)
493 {
494     VBScript *This = impl_from_IActiveScriptParse(iface);
495     return IActiveScript_Release(&This->IActiveScript_iface);
496 }
497
498 static HRESULT WINAPI VBScriptParse_InitNew(IActiveScriptParse *iface)
499 {
500     VBScript *This = impl_from_IActiveScriptParse(iface);
501     script_ctx_t *ctx, *old_ctx;
502
503     TRACE("(%p)\n", This);
504
505     if(This->ctx)
506         return E_UNEXPECTED;
507
508     ctx = heap_alloc_zero(sizeof(script_ctx_t));
509     if(!ctx)
510         return E_OUTOFMEMORY;
511
512     list_init(&ctx->code_list);
513     list_init(&ctx->named_items);
514
515     old_ctx = InterlockedCompareExchangePointer((void**)&This->ctx, ctx, NULL);
516     if(old_ctx) {
517         destroy_script(ctx);
518         return E_UNEXPECTED;
519     }
520
521     return This->site ? set_ctx_site(This) : S_OK;
522 }
523
524 static HRESULT WINAPI VBScriptParse_AddScriptlet(IActiveScriptParse *iface,
525         LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName,
526         LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName, LPCOLESTR pstrDelimiter,
527         CTXARG_T dwSourceContextCookie, ULONG ulStartingLineNumber, DWORD dwFlags,
528         BSTR *pbstrName, EXCEPINFO *pexcepinfo)
529 {
530     VBScript *This = impl_from_IActiveScriptParse(iface);
531     FIXME("(%p)->(%s %s %s %s %s %s %s %u %x %p %p)\n", This, debugstr_w(pstrDefaultName),
532           debugstr_w(pstrCode), debugstr_w(pstrItemName), debugstr_w(pstrSubItemName),
533           debugstr_w(pstrEventName), debugstr_w(pstrDelimiter), wine_dbgstr_longlong(dwSourceContextCookie),
534           ulStartingLineNumber, dwFlags, pbstrName, pexcepinfo);
535     return E_NOTIMPL;
536 }
537
538 static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface,
539         LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext,
540         LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, ULONG ulStartingLine,
541         DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo)
542 {
543     VBScript *This = impl_from_IActiveScriptParse(iface);
544     vbscode_t *code;
545     HRESULT hres;
546
547     TRACE("(%p)->(%s %s %p %s %s %u %x %p %p)\n", This, debugstr_w(pstrCode),
548           debugstr_w(pstrItemName), punkContext, debugstr_w(pstrDelimiter),
549           wine_dbgstr_longlong(dwSourceContextCookie), ulStartingLine, dwFlags, pvarResult, pexcepinfo);
550
551     if(This->thread_id != GetCurrentThreadId() || This->state == SCRIPTSTATE_CLOSED)
552         return E_UNEXPECTED;
553
554     hres = compile_script(This->ctx, pstrCode, &code);
555     if(FAILED(hres))
556         return hres;
557
558     return is_started(This) ? exec_global_code(This->ctx, code) : S_OK;
559 }
560
561 static const IActiveScriptParseVtbl VBScriptParseVtbl = {
562     VBScriptParse_QueryInterface,
563     VBScriptParse_AddRef,
564     VBScriptParse_Release,
565     VBScriptParse_InitNew,
566     VBScriptParse_AddScriptlet,
567     VBScriptParse_ParseScriptText
568 };
569
570 static inline VBScript *impl_from_IObjectSafety(IObjectSafety *iface)
571 {
572     return CONTAINING_RECORD(iface, VBScript, IObjectSafety_iface);
573 }
574
575 static HRESULT WINAPI VBScriptSafety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
576 {
577     VBScript *This = impl_from_IObjectSafety(iface);
578     return IActiveScript_QueryInterface(&This->IActiveScript_iface, riid, ppv);
579 }
580
581 static ULONG WINAPI VBScriptSafety_AddRef(IObjectSafety *iface)
582 {
583     VBScript *This = impl_from_IObjectSafety(iface);
584     return IActiveScript_AddRef(&This->IActiveScript_iface);
585 }
586
587 static ULONG WINAPI VBScriptSafety_Release(IObjectSafety *iface)
588 {
589     VBScript *This = impl_from_IObjectSafety(iface);
590     return IActiveScript_Release(&This->IActiveScript_iface);
591 }
592
593 #define SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_DISPEX|INTERFACE_USES_SECURITY_MANAGER)
594
595 static HRESULT WINAPI VBScriptSafety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
596         DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
597 {
598     VBScript *This = impl_from_IObjectSafety(iface);
599
600     TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), pdwSupportedOptions, pdwEnabledOptions);
601
602     if(!pdwSupportedOptions || !pdwEnabledOptions)
603         return E_POINTER;
604
605     *pdwSupportedOptions = SUPPORTED_OPTIONS;
606     *pdwEnabledOptions = This->safeopt;
607     return S_OK;
608 }
609
610 static HRESULT WINAPI VBScriptSafety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
611         DWORD dwOptionSetMask, DWORD dwEnabledOptions)
612 {
613     VBScript *This = impl_from_IObjectSafety(iface);
614
615     TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), dwOptionSetMask, dwEnabledOptions);
616
617     if(dwOptionSetMask & ~SUPPORTED_OPTIONS)
618         return E_FAIL;
619
620     This->safeopt = (dwEnabledOptions & dwOptionSetMask) | (This->safeopt & ~dwOptionSetMask) | INTERFACE_USES_DISPEX;
621     return S_OK;
622 }
623
624 static const IObjectSafetyVtbl VBScriptSafetyVtbl = {
625     VBScriptSafety_QueryInterface,
626     VBScriptSafety_AddRef,
627     VBScriptSafety_Release,
628     VBScriptSafety_GetInterfaceSafetyOptions,
629     VBScriptSafety_SetInterfaceSafetyOptions
630 };
631
632 HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv)
633 {
634     VBScript *ret;
635     HRESULT hres;
636
637     TRACE("(%p %s %p)\n", pUnkOuter, debugstr_guid(riid), ppv);
638
639     ret = heap_alloc_zero(sizeof(*ret));
640     if(!ret)
641         return E_OUTOFMEMORY;
642
643     ret->IActiveScript_iface.lpVtbl = &VBScriptVtbl;
644     ret->IActiveScriptParse_iface.lpVtbl = &VBScriptParseVtbl;
645     ret->IObjectSafety_iface.lpVtbl = &VBScriptSafetyVtbl;
646
647     ret->ref = 1;
648     ret->state = SCRIPTSTATE_UNINITIALIZED;
649     ret->safeopt = INTERFACE_USES_DISPEX;
650
651     hres = IActiveScript_QueryInterface(&ret->IActiveScript_iface, riid, ppv);
652     IActiveScript_Release(&ret->IActiveScript_iface);
653     return hres;
654 }