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