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