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