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